##// END OF EJS Templates
debugignore: use getattr instead of hasattr
Augie Fackler -
r14949:a4435770 default
parent child Browse files
Show More
@@ -1,5187 +1,5188 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, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
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, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 Valid types are:
310 Valid types are:
311
311
312 :``files``: a directory full of files (default)
312 :``files``: a directory full of files (default)
313 :``tar``: tar archive, uncompressed
313 :``tar``: tar archive, uncompressed
314 :``tbz2``: tar archive, compressed using bzip2
314 :``tbz2``: tar archive, compressed using bzip2
315 :``tgz``: tar archive, compressed using gzip
315 :``tgz``: tar archive, compressed using gzip
316 :``uzip``: zip archive, uncompressed
316 :``uzip``: zip archive, uncompressed
317 :``zip``: zip archive, compressed using deflate
317 :``zip``: zip archive, compressed using deflate
318
318
319 The exact name of the destination archive or directory is given
319 The exact name of the destination archive or directory is given
320 using a format string; see :hg:`help export` for details.
320 using a format string; see :hg:`help export` for details.
321
321
322 Each member added to an archive file has a directory prefix
322 Each member added to an archive file has a directory prefix
323 prepended. Use -p/--prefix to specify a format string for the
323 prepended. Use -p/--prefix to specify a format string for the
324 prefix. The default is the basename of the archive, with suffixes
324 prefix. The default is the basename of the archive, with suffixes
325 removed.
325 removed.
326
326
327 Returns 0 on success.
327 Returns 0 on success.
328 '''
328 '''
329
329
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
331 if not ctx:
331 if not ctx:
332 raise util.Abort(_('no working directory: please specify a revision'))
332 raise util.Abort(_('no working directory: please specify a revision'))
333 node = ctx.node()
333 node = ctx.node()
334 dest = cmdutil.makefilename(repo, dest, node)
334 dest = cmdutil.makefilename(repo, dest, node)
335 if os.path.realpath(dest) == repo.root:
335 if os.path.realpath(dest) == repo.root:
336 raise util.Abort(_('repository root cannot be destination'))
336 raise util.Abort(_('repository root cannot be destination'))
337
337
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
339 prefix = opts.get('prefix')
339 prefix = opts.get('prefix')
340
340
341 if dest == '-':
341 if dest == '-':
342 if kind == 'files':
342 if kind == 'files':
343 raise util.Abort(_('cannot archive plain files to stdout'))
343 raise util.Abort(_('cannot archive plain files to stdout'))
344 dest = cmdutil.makefileobj(repo, dest)
344 dest = cmdutil.makefileobj(repo, dest)
345 if not prefix:
345 if not prefix:
346 prefix = os.path.basename(repo.root) + '-%h'
346 prefix = os.path.basename(repo.root) + '-%h'
347
347
348 prefix = cmdutil.makefilename(repo, prefix, node)
348 prefix = cmdutil.makefilename(repo, prefix, node)
349 matchfn = scmutil.match(ctx, [], opts)
349 matchfn = scmutil.match(ctx, [], opts)
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
351 matchfn, prefix, subrepos=opts.get('subrepos'))
351 matchfn, prefix, subrepos=opts.get('subrepos'))
352
352
353 @command('backout',
353 @command('backout',
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
358 _('[OPTION]... [-r] REV'))
358 _('[OPTION]... [-r] REV'))
359 def backout(ui, repo, node=None, rev=None, **opts):
359 def backout(ui, repo, node=None, rev=None, **opts):
360 '''reverse effect of earlier changeset
360 '''reverse effect of earlier changeset
361
361
362 Prepare a new changeset with the effect of REV undone in the
362 Prepare a new changeset with the effect of REV undone in the
363 current working directory.
363 current working directory.
364
364
365 If REV is the parent of the working directory, then this new changeset
365 If REV is the parent of the working directory, then this new changeset
366 is committed automatically. Otherwise, hg needs to merge the
366 is committed automatically. Otherwise, hg needs to merge the
367 changes and the merged result is left uncommitted.
367 changes and the merged result is left uncommitted.
368
368
369 By default, the pending changeset will have one parent,
369 By default, the pending changeset will have one parent,
370 maintaining a linear history. With --merge, the pending changeset
370 maintaining a linear history. With --merge, the pending changeset
371 will instead have two parents: the old parent of the working
371 will instead have two parents: the old parent of the working
372 directory and a new child of REV that simply undoes REV.
372 directory and a new child of REV that simply undoes REV.
373
373
374 Before version 1.7, the behavior without --merge was equivalent to
374 Before version 1.7, the behavior without --merge was equivalent to
375 specifying --merge followed by :hg:`update --clean .` to cancel
375 specifying --merge followed by :hg:`update --clean .` to cancel
376 the merge and leave the child of REV as a head to be merged
376 the merge and leave the child of REV as a head to be merged
377 separately.
377 separately.
378
378
379 See :hg:`help dates` for a list of formats valid for -d/--date.
379 See :hg:`help dates` for a list of formats valid for -d/--date.
380
380
381 Returns 0 on success.
381 Returns 0 on success.
382 '''
382 '''
383 if rev and node:
383 if rev and node:
384 raise util.Abort(_("please specify just one revision"))
384 raise util.Abort(_("please specify just one revision"))
385
385
386 if not rev:
386 if not rev:
387 rev = node
387 rev = node
388
388
389 if not rev:
389 if not rev:
390 raise util.Abort(_("please specify a revision to backout"))
390 raise util.Abort(_("please specify a revision to backout"))
391
391
392 date = opts.get('date')
392 date = opts.get('date')
393 if date:
393 if date:
394 opts['date'] = util.parsedate(date)
394 opts['date'] = util.parsedate(date)
395
395
396 cmdutil.bailifchanged(repo)
396 cmdutil.bailifchanged(repo)
397 node = scmutil.revsingle(repo, rev).node()
397 node = scmutil.revsingle(repo, rev).node()
398
398
399 op1, op2 = repo.dirstate.parents()
399 op1, op2 = repo.dirstate.parents()
400 a = repo.changelog.ancestor(op1, node)
400 a = repo.changelog.ancestor(op1, node)
401 if a != node:
401 if a != node:
402 raise util.Abort(_('cannot backout change on a different branch'))
402 raise util.Abort(_('cannot backout change on a different branch'))
403
403
404 p1, p2 = repo.changelog.parents(node)
404 p1, p2 = repo.changelog.parents(node)
405 if p1 == nullid:
405 if p1 == nullid:
406 raise util.Abort(_('cannot backout a change with no parents'))
406 raise util.Abort(_('cannot backout a change with no parents'))
407 if p2 != nullid:
407 if p2 != nullid:
408 if not opts.get('parent'):
408 if not opts.get('parent'):
409 raise util.Abort(_('cannot backout a merge changeset without '
409 raise util.Abort(_('cannot backout a merge changeset without '
410 '--parent'))
410 '--parent'))
411 p = repo.lookup(opts['parent'])
411 p = repo.lookup(opts['parent'])
412 if p not in (p1, p2):
412 if p not in (p1, p2):
413 raise util.Abort(_('%s is not a parent of %s') %
413 raise util.Abort(_('%s is not a parent of %s') %
414 (short(p), short(node)))
414 (short(p), short(node)))
415 parent = p
415 parent = p
416 else:
416 else:
417 if opts.get('parent'):
417 if opts.get('parent'):
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
419 parent = p1
419 parent = p1
420
420
421 # the backout should appear on the same branch
421 # the backout should appear on the same branch
422 branch = repo.dirstate.branch()
422 branch = repo.dirstate.branch()
423 hg.clean(repo, node, show_stats=False)
423 hg.clean(repo, node, show_stats=False)
424 repo.dirstate.setbranch(branch)
424 repo.dirstate.setbranch(branch)
425 revert_opts = opts.copy()
425 revert_opts = opts.copy()
426 revert_opts['date'] = None
426 revert_opts['date'] = None
427 revert_opts['all'] = True
427 revert_opts['all'] = True
428 revert_opts['rev'] = hex(parent)
428 revert_opts['rev'] = hex(parent)
429 revert_opts['no_backup'] = None
429 revert_opts['no_backup'] = None
430 revert(ui, repo, **revert_opts)
430 revert(ui, repo, **revert_opts)
431 if not opts.get('merge') and op1 != node:
431 if not opts.get('merge') and op1 != node:
432 try:
432 try:
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
434 return hg.update(repo, op1)
434 return hg.update(repo, op1)
435 finally:
435 finally:
436 ui.setconfig('ui', 'forcemerge', '')
436 ui.setconfig('ui', 'forcemerge', '')
437
437
438 commit_opts = opts.copy()
438 commit_opts = opts.copy()
439 commit_opts['addremove'] = False
439 commit_opts['addremove'] = False
440 if not commit_opts['message'] and not commit_opts['logfile']:
440 if not commit_opts['message'] and not commit_opts['logfile']:
441 # we don't translate commit messages
441 # we don't translate commit messages
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
443 commit_opts['force_editor'] = True
443 commit_opts['force_editor'] = True
444 commit(ui, repo, **commit_opts)
444 commit(ui, repo, **commit_opts)
445 def nice(node):
445 def nice(node):
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
447 ui.status(_('changeset %s backs out changeset %s\n') %
447 ui.status(_('changeset %s backs out changeset %s\n') %
448 (nice(repo.changelog.tip()), nice(node)))
448 (nice(repo.changelog.tip()), nice(node)))
449 if opts.get('merge') and op1 != node:
449 if opts.get('merge') and op1 != node:
450 hg.clean(repo, op1, show_stats=False)
450 hg.clean(repo, op1, show_stats=False)
451 ui.status(_('merging with changeset %s\n')
451 ui.status(_('merging with changeset %s\n')
452 % nice(repo.changelog.tip()))
452 % nice(repo.changelog.tip()))
453 try:
453 try:
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
455 return hg.merge(repo, hex(repo.changelog.tip()))
455 return hg.merge(repo, hex(repo.changelog.tip()))
456 finally:
456 finally:
457 ui.setconfig('ui', 'forcemerge', '')
457 ui.setconfig('ui', 'forcemerge', '')
458 return 0
458 return 0
459
459
460 @command('bisect',
460 @command('bisect',
461 [('r', 'reset', False, _('reset bisect state')),
461 [('r', 'reset', False, _('reset bisect state')),
462 ('g', 'good', False, _('mark changeset good')),
462 ('g', 'good', False, _('mark changeset good')),
463 ('b', 'bad', False, _('mark changeset bad')),
463 ('b', 'bad', False, _('mark changeset bad')),
464 ('s', 'skip', False, _('skip testing changeset')),
464 ('s', 'skip', False, _('skip testing changeset')),
465 ('e', 'extend', False, _('extend the bisect range')),
465 ('e', 'extend', False, _('extend the bisect range')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
467 ('U', 'noupdate', False, _('do not update to target'))],
467 ('U', 'noupdate', False, _('do not update to target'))],
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
469 def bisect(ui, repo, rev=None, extra=None, command=None,
469 def bisect(ui, repo, rev=None, extra=None, command=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
471 noupdate=None):
471 noupdate=None):
472 """subdivision search of changesets
472 """subdivision search of changesets
473
473
474 This command helps to find changesets which introduce problems. To
474 This command helps to find changesets which introduce problems. To
475 use, mark the earliest changeset you know exhibits the problem as
475 use, mark the earliest changeset you know exhibits the problem as
476 bad, then mark the latest changeset which is free from the problem
476 bad, then mark the latest changeset which is free from the problem
477 as good. Bisect will update your working directory to a revision
477 as good. Bisect will update your working directory to a revision
478 for testing (unless the -U/--noupdate option is specified). Once
478 for testing (unless the -U/--noupdate option is specified). Once
479 you have performed tests, mark the working directory as good or
479 you have performed tests, mark the working directory as good or
480 bad, and bisect will either update to another candidate changeset
480 bad, and bisect will either update to another candidate changeset
481 or announce that it has found the bad revision.
481 or announce that it has found the bad revision.
482
482
483 As a shortcut, you can also use the revision argument to mark a
483 As a shortcut, you can also use the revision argument to mark a
484 revision as good or bad without checking it out first.
484 revision as good or bad without checking it out first.
485
485
486 If you supply a command, it will be used for automatic bisection.
486 If you supply a command, it will be used for automatic bisection.
487 Its exit status will be used to mark revisions as good or bad:
487 Its exit status will be used to mark revisions as good or bad:
488 status 0 means good, 125 means to skip the revision, 127
488 status 0 means good, 125 means to skip the revision, 127
489 (command not found) will abort the bisection, and any other
489 (command not found) will abort the bisection, and any other
490 non-zero exit status means the revision is bad.
490 non-zero exit status means the revision is bad.
491
491
492 Returns 0 on success.
492 Returns 0 on success.
493 """
493 """
494 def extendbisectrange(nodes, good):
494 def extendbisectrange(nodes, good):
495 # bisect is incomplete when it ends on a merge node and
495 # bisect is incomplete when it ends on a merge node and
496 # one of the parent was not checked.
496 # one of the parent was not checked.
497 parents = repo[nodes[0]].parents()
497 parents = repo[nodes[0]].parents()
498 if len(parents) > 1:
498 if len(parents) > 1:
499 side = good and state['bad'] or state['good']
499 side = good and state['bad'] or state['good']
500 num = len(set(i.node() for i in parents) & set(side))
500 num = len(set(i.node() for i in parents) & set(side))
501 if num == 1:
501 if num == 1:
502 return parents[0].ancestor(parents[1])
502 return parents[0].ancestor(parents[1])
503 return None
503 return None
504
504
505 def print_result(nodes, good):
505 def print_result(nodes, good):
506 displayer = cmdutil.show_changeset(ui, repo, {})
506 displayer = cmdutil.show_changeset(ui, repo, {})
507 if len(nodes) == 1:
507 if len(nodes) == 1:
508 # narrowed it down to a single revision
508 # narrowed it down to a single revision
509 if good:
509 if good:
510 ui.write(_("The first good revision is:\n"))
510 ui.write(_("The first good revision is:\n"))
511 else:
511 else:
512 ui.write(_("The first bad revision is:\n"))
512 ui.write(_("The first bad revision is:\n"))
513 displayer.show(repo[nodes[0]])
513 displayer.show(repo[nodes[0]])
514 extendnode = extendbisectrange(nodes, good)
514 extendnode = extendbisectrange(nodes, good)
515 if extendnode is not None:
515 if extendnode is not None:
516 ui.write(_('Not all ancestors of this changeset have been'
516 ui.write(_('Not all ancestors of this changeset have been'
517 ' checked.\nUse bisect --extend to continue the '
517 ' checked.\nUse bisect --extend to continue the '
518 'bisection from\nthe common ancestor, %s.\n')
518 'bisection from\nthe common ancestor, %s.\n')
519 % extendnode)
519 % extendnode)
520 else:
520 else:
521 # multiple possible revisions
521 # multiple possible revisions
522 if good:
522 if good:
523 ui.write(_("Due to skipped revisions, the first "
523 ui.write(_("Due to skipped revisions, the first "
524 "good revision could be any of:\n"))
524 "good revision could be any of:\n"))
525 else:
525 else:
526 ui.write(_("Due to skipped revisions, the first "
526 ui.write(_("Due to skipped revisions, the first "
527 "bad revision could be any of:\n"))
527 "bad revision could be any of:\n"))
528 for n in nodes:
528 for n in nodes:
529 displayer.show(repo[n])
529 displayer.show(repo[n])
530 displayer.close()
530 displayer.close()
531
531
532 def check_state(state, interactive=True):
532 def check_state(state, interactive=True):
533 if not state['good'] or not state['bad']:
533 if not state['good'] or not state['bad']:
534 if (good or bad or skip or reset) and interactive:
534 if (good or bad or skip or reset) and interactive:
535 return
535 return
536 if not state['good']:
536 if not state['good']:
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
538 else:
538 else:
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
540 return True
540 return True
541
541
542 # backward compatibility
542 # backward compatibility
543 if rev in "good bad reset init".split():
543 if rev in "good bad reset init".split():
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
545 cmd, rev, extra = rev, extra, None
545 cmd, rev, extra = rev, extra, None
546 if cmd == "good":
546 if cmd == "good":
547 good = True
547 good = True
548 elif cmd == "bad":
548 elif cmd == "bad":
549 bad = True
549 bad = True
550 else:
550 else:
551 reset = True
551 reset = True
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
553 raise util.Abort(_('incompatible arguments'))
553 raise util.Abort(_('incompatible arguments'))
554
554
555 if reset:
555 if reset:
556 p = repo.join("bisect.state")
556 p = repo.join("bisect.state")
557 if os.path.exists(p):
557 if os.path.exists(p):
558 os.unlink(p)
558 os.unlink(p)
559 return
559 return
560
560
561 state = hbisect.load_state(repo)
561 state = hbisect.load_state(repo)
562
562
563 if command:
563 if command:
564 changesets = 1
564 changesets = 1
565 try:
565 try:
566 while changesets:
566 while changesets:
567 # update state
567 # update state
568 status = util.system(command, out=ui.fout)
568 status = util.system(command, out=ui.fout)
569 if status == 125:
569 if status == 125:
570 transition = "skip"
570 transition = "skip"
571 elif status == 0:
571 elif status == 0:
572 transition = "good"
572 transition = "good"
573 # status < 0 means process was killed
573 # status < 0 means process was killed
574 elif status == 127:
574 elif status == 127:
575 raise util.Abort(_("failed to execute %s") % command)
575 raise util.Abort(_("failed to execute %s") % command)
576 elif status < 0:
576 elif status < 0:
577 raise util.Abort(_("%s killed") % command)
577 raise util.Abort(_("%s killed") % command)
578 else:
578 else:
579 transition = "bad"
579 transition = "bad"
580 ctx = scmutil.revsingle(repo, rev)
580 ctx = scmutil.revsingle(repo, rev)
581 rev = None # clear for future iterations
581 rev = None # clear for future iterations
582 state[transition].append(ctx.node())
582 state[transition].append(ctx.node())
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
584 check_state(state, interactive=False)
584 check_state(state, interactive=False)
585 # bisect
585 # bisect
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
587 # update to next check
587 # update to next check
588 cmdutil.bailifchanged(repo)
588 cmdutil.bailifchanged(repo)
589 hg.clean(repo, nodes[0], show_stats=False)
589 hg.clean(repo, nodes[0], show_stats=False)
590 finally:
590 finally:
591 hbisect.save_state(repo, state)
591 hbisect.save_state(repo, state)
592 print_result(nodes, good)
592 print_result(nodes, good)
593 return
593 return
594
594
595 # update state
595 # update state
596
596
597 if rev:
597 if rev:
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
599 else:
599 else:
600 nodes = [repo.lookup('.')]
600 nodes = [repo.lookup('.')]
601
601
602 if good or bad or skip:
602 if good or bad or skip:
603 if good:
603 if good:
604 state['good'] += nodes
604 state['good'] += nodes
605 elif bad:
605 elif bad:
606 state['bad'] += nodes
606 state['bad'] += nodes
607 elif skip:
607 elif skip:
608 state['skip'] += nodes
608 state['skip'] += nodes
609 hbisect.save_state(repo, state)
609 hbisect.save_state(repo, state)
610
610
611 if not check_state(state):
611 if not check_state(state):
612 return
612 return
613
613
614 # actually bisect
614 # actually bisect
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
616 if extend:
616 if extend:
617 if not changesets:
617 if not changesets:
618 extendnode = extendbisectrange(nodes, good)
618 extendnode = extendbisectrange(nodes, good)
619 if extendnode is not None:
619 if extendnode is not None:
620 ui.write(_("Extending search to changeset %d:%s\n"
620 ui.write(_("Extending search to changeset %d:%s\n"
621 % (extendnode.rev(), extendnode)))
621 % (extendnode.rev(), extendnode)))
622 if noupdate:
622 if noupdate:
623 return
623 return
624 cmdutil.bailifchanged(repo)
624 cmdutil.bailifchanged(repo)
625 return hg.clean(repo, extendnode.node())
625 return hg.clean(repo, extendnode.node())
626 raise util.Abort(_("nothing to extend"))
626 raise util.Abort(_("nothing to extend"))
627
627
628 if changesets == 0:
628 if changesets == 0:
629 print_result(nodes, good)
629 print_result(nodes, good)
630 else:
630 else:
631 assert len(nodes) == 1 # only a single node can be tested next
631 assert len(nodes) == 1 # only a single node can be tested next
632 node = nodes[0]
632 node = nodes[0]
633 # compute the approximate number of remaining tests
633 # compute the approximate number of remaining tests
634 tests, size = 0, 2
634 tests, size = 0, 2
635 while size <= changesets:
635 while size <= changesets:
636 tests, size = tests + 1, size * 2
636 tests, size = tests + 1, size * 2
637 rev = repo.changelog.rev(node)
637 rev = repo.changelog.rev(node)
638 ui.write(_("Testing changeset %d:%s "
638 ui.write(_("Testing changeset %d:%s "
639 "(%d changesets remaining, ~%d tests)\n")
639 "(%d changesets remaining, ~%d tests)\n")
640 % (rev, short(node), changesets, tests))
640 % (rev, short(node), changesets, tests))
641 if not noupdate:
641 if not noupdate:
642 cmdutil.bailifchanged(repo)
642 cmdutil.bailifchanged(repo)
643 return hg.clean(repo, node)
643 return hg.clean(repo, node)
644
644
645 @command('bookmarks',
645 @command('bookmarks',
646 [('f', 'force', False, _('force')),
646 [('f', 'force', False, _('force')),
647 ('r', 'rev', '', _('revision'), _('REV')),
647 ('r', 'rev', '', _('revision'), _('REV')),
648 ('d', 'delete', False, _('delete a given bookmark')),
648 ('d', 'delete', False, _('delete a given bookmark')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
653 rename=None, inactive=False):
653 rename=None, inactive=False):
654 '''track a line of development with movable markers
654 '''track a line of development with movable markers
655
655
656 Bookmarks are pointers to certain commits that move when
656 Bookmarks are pointers to certain commits that move when
657 committing. Bookmarks are local. They can be renamed, copied and
657 committing. Bookmarks are local. They can be renamed, copied and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
659 :hg:`update` to merge and update respectively to a given bookmark.
659 :hg:`update` to merge and update respectively to a given bookmark.
660
660
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
662 directory's parent revision with the given name. If you specify
662 directory's parent revision with the given name. If you specify
663 a revision using -r REV (where REV may be an existing bookmark),
663 a revision using -r REV (where REV may be an existing bookmark),
664 the bookmark is assigned to that revision.
664 the bookmark is assigned to that revision.
665
665
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
667 push` and :hg:`help pull`). This requires both the local and remote
667 push` and :hg:`help pull`). This requires both the local and remote
668 repositories to support bookmarks. For versions prior to 1.8, this means
668 repositories to support bookmarks. For versions prior to 1.8, this means
669 the bookmarks extension must be enabled.
669 the bookmarks extension must be enabled.
670 '''
670 '''
671 hexfn = ui.debugflag and hex or short
671 hexfn = ui.debugflag and hex or short
672 marks = repo._bookmarks
672 marks = repo._bookmarks
673 cur = repo.changectx('.').node()
673 cur = repo.changectx('.').node()
674
674
675 if rename:
675 if rename:
676 if rename not in marks:
676 if rename not in marks:
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
678 if mark in marks and not force:
678 if mark in marks and not force:
679 raise util.Abort(_("bookmark '%s' already exists "
679 raise util.Abort(_("bookmark '%s' already exists "
680 "(use -f to force)") % mark)
680 "(use -f to force)") % mark)
681 if mark is None:
681 if mark is None:
682 raise util.Abort(_("new bookmark name required"))
682 raise util.Abort(_("new bookmark name required"))
683 marks[mark] = marks[rename]
683 marks[mark] = marks[rename]
684 if repo._bookmarkcurrent == rename and not inactive:
684 if repo._bookmarkcurrent == rename and not inactive:
685 bookmarks.setcurrent(repo, mark)
685 bookmarks.setcurrent(repo, mark)
686 del marks[rename]
686 del marks[rename]
687 bookmarks.write(repo)
687 bookmarks.write(repo)
688 return
688 return
689
689
690 if delete:
690 if delete:
691 if mark is None:
691 if mark is None:
692 raise util.Abort(_("bookmark name required"))
692 raise util.Abort(_("bookmark name required"))
693 if mark not in marks:
693 if mark not in marks:
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
695 if mark == repo._bookmarkcurrent:
695 if mark == repo._bookmarkcurrent:
696 bookmarks.setcurrent(repo, None)
696 bookmarks.setcurrent(repo, None)
697 del marks[mark]
697 del marks[mark]
698 bookmarks.write(repo)
698 bookmarks.write(repo)
699 return
699 return
700
700
701 if mark is not None:
701 if mark is not None:
702 if "\n" in mark:
702 if "\n" in mark:
703 raise util.Abort(_("bookmark name cannot contain newlines"))
703 raise util.Abort(_("bookmark name cannot contain newlines"))
704 mark = mark.strip()
704 mark = mark.strip()
705 if not mark:
705 if not mark:
706 raise util.Abort(_("bookmark names cannot consist entirely of "
706 raise util.Abort(_("bookmark names cannot consist entirely of "
707 "whitespace"))
707 "whitespace"))
708 if inactive and mark == repo._bookmarkcurrent:
708 if inactive and mark == repo._bookmarkcurrent:
709 bookmarks.setcurrent(repo, None)
709 bookmarks.setcurrent(repo, None)
710 return
710 return
711 if mark in marks and not force:
711 if mark in marks and not force:
712 raise util.Abort(_("bookmark '%s' already exists "
712 raise util.Abort(_("bookmark '%s' already exists "
713 "(use -f to force)") % mark)
713 "(use -f to force)") % mark)
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
715 and not force):
715 and not force):
716 raise util.Abort(
716 raise util.Abort(
717 _("a bookmark cannot have the name of an existing branch"))
717 _("a bookmark cannot have the name of an existing branch"))
718 if rev:
718 if rev:
719 marks[mark] = repo.lookup(rev)
719 marks[mark] = repo.lookup(rev)
720 else:
720 else:
721 marks[mark] = repo.changectx('.').node()
721 marks[mark] = repo.changectx('.').node()
722 if not inactive and repo.changectx('.').node() == marks[mark]:
722 if not inactive and repo.changectx('.').node() == marks[mark]:
723 bookmarks.setcurrent(repo, mark)
723 bookmarks.setcurrent(repo, mark)
724 bookmarks.write(repo)
724 bookmarks.write(repo)
725 return
725 return
726
726
727 if mark is None:
727 if mark is None:
728 if rev:
728 if rev:
729 raise util.Abort(_("bookmark name required"))
729 raise util.Abort(_("bookmark name required"))
730 if len(marks) == 0:
730 if len(marks) == 0:
731 ui.status(_("no bookmarks set\n"))
731 ui.status(_("no bookmarks set\n"))
732 else:
732 else:
733 for bmark, n in sorted(marks.iteritems()):
733 for bmark, n in sorted(marks.iteritems()):
734 current = repo._bookmarkcurrent
734 current = repo._bookmarkcurrent
735 if bmark == current and n == cur:
735 if bmark == current and n == cur:
736 prefix, label = '*', 'bookmarks.current'
736 prefix, label = '*', 'bookmarks.current'
737 else:
737 else:
738 prefix, label = ' ', ''
738 prefix, label = ' ', ''
739
739
740 if ui.quiet:
740 if ui.quiet:
741 ui.write("%s\n" % bmark, label=label)
741 ui.write("%s\n" % bmark, label=label)
742 else:
742 else:
743 ui.write(" %s %-25s %d:%s\n" % (
743 ui.write(" %s %-25s %d:%s\n" % (
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
745 label=label)
745 label=label)
746 return
746 return
747
747
748 @command('branch',
748 @command('branch',
749 [('f', 'force', None,
749 [('f', 'force', None,
750 _('set branch name even if it shadows an existing branch')),
750 _('set branch name even if it shadows an existing branch')),
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
752 _('[-fC] [NAME]'))
752 _('[-fC] [NAME]'))
753 def branch(ui, repo, label=None, **opts):
753 def branch(ui, repo, label=None, **opts):
754 """set or show the current branch name
754 """set or show the current branch name
755
755
756 With no argument, show the current branch name. With one argument,
756 With no argument, show the current branch name. With one argument,
757 set the working directory branch name (the branch will not exist
757 set the working directory branch name (the branch will not exist
758 in the repository until the next commit). Standard practice
758 in the repository until the next commit). Standard practice
759 recommends that primary development take place on the 'default'
759 recommends that primary development take place on the 'default'
760 branch.
760 branch.
761
761
762 Unless -f/--force is specified, branch will not let you set a
762 Unless -f/--force is specified, branch will not let you set a
763 branch name that already exists, even if it's inactive.
763 branch name that already exists, even if it's inactive.
764
764
765 Use -C/--clean to reset the working directory branch to that of
765 Use -C/--clean to reset the working directory branch to that of
766 the parent of the working directory, negating a previous branch
766 the parent of the working directory, negating a previous branch
767 change.
767 change.
768
768
769 Use the command :hg:`update` to switch to an existing branch. Use
769 Use the command :hg:`update` to switch to an existing branch. Use
770 :hg:`commit --close-branch` to mark this branch as closed.
770 :hg:`commit --close-branch` to mark this branch as closed.
771
771
772 .. note::
772 .. note::
773
773
774 Branch names are permanent. Use :hg:`bookmark` to create a
774 Branch names are permanent. Use :hg:`bookmark` to create a
775 light-weight bookmark instead. See :hg:`help glossary` for more
775 light-weight bookmark instead. See :hg:`help glossary` for more
776 information about named branches and bookmarks.
776 information about named branches and bookmarks.
777
777
778 Returns 0 on success.
778 Returns 0 on success.
779 """
779 """
780
780
781 if opts.get('clean'):
781 if opts.get('clean'):
782 label = repo[None].p1().branch()
782 label = repo[None].p1().branch()
783 repo.dirstate.setbranch(label)
783 repo.dirstate.setbranch(label)
784 ui.status(_('reset working directory to branch %s\n') % label)
784 ui.status(_('reset working directory to branch %s\n') % label)
785 elif label:
785 elif label:
786 if not opts.get('force') and label in repo.branchtags():
786 if not opts.get('force') and label in repo.branchtags():
787 if label not in [p.branch() for p in repo.parents()]:
787 if label not in [p.branch() for p in repo.parents()]:
788 raise util.Abort(_('a branch of the same name already exists'),
788 raise util.Abort(_('a branch of the same name already exists'),
789 # i18n: "it" refers to an existing branch
789 # i18n: "it" refers to an existing branch
790 hint=_("use 'hg update' to switch to it"))
790 hint=_("use 'hg update' to switch to it"))
791 repo.dirstate.setbranch(label)
791 repo.dirstate.setbranch(label)
792 ui.status(_('marked working directory as branch %s\n') % label)
792 ui.status(_('marked working directory as branch %s\n') % label)
793 else:
793 else:
794 ui.write("%s\n" % repo.dirstate.branch())
794 ui.write("%s\n" % repo.dirstate.branch())
795
795
796 @command('branches',
796 @command('branches',
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
798 ('c', 'closed', False, _('show normal and closed branches'))],
798 ('c', 'closed', False, _('show normal and closed branches'))],
799 _('[-ac]'))
799 _('[-ac]'))
800 def branches(ui, repo, active=False, closed=False):
800 def branches(ui, repo, active=False, closed=False):
801 """list repository named branches
801 """list repository named branches
802
802
803 List the repository's named branches, indicating which ones are
803 List the repository's named branches, indicating which ones are
804 inactive. If -c/--closed is specified, also list branches which have
804 inactive. If -c/--closed is specified, also list branches which have
805 been marked closed (see :hg:`commit --close-branch`).
805 been marked closed (see :hg:`commit --close-branch`).
806
806
807 If -a/--active is specified, only show active branches. A branch
807 If -a/--active is specified, only show active branches. A branch
808 is considered active if it contains repository heads.
808 is considered active if it contains repository heads.
809
809
810 Use the command :hg:`update` to switch to an existing branch.
810 Use the command :hg:`update` to switch to an existing branch.
811
811
812 Returns 0.
812 Returns 0.
813 """
813 """
814
814
815 hexfunc = ui.debugflag and hex or short
815 hexfunc = ui.debugflag and hex or short
816 activebranches = [repo[n].branch() for n in repo.heads()]
816 activebranches = [repo[n].branch() for n in repo.heads()]
817 def testactive(tag, node):
817 def testactive(tag, node):
818 realhead = tag in activebranches
818 realhead = tag in activebranches
819 open = node in repo.branchheads(tag, closed=False)
819 open = node in repo.branchheads(tag, closed=False)
820 return realhead and open
820 return realhead and open
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
822 for tag, node in repo.branchtags().items()],
822 for tag, node in repo.branchtags().items()],
823 reverse=True)
823 reverse=True)
824
824
825 for isactive, node, tag in branches:
825 for isactive, node, tag in branches:
826 if (not active) or isactive:
826 if (not active) or isactive:
827 if ui.quiet:
827 if ui.quiet:
828 ui.write("%s\n" % tag)
828 ui.write("%s\n" % tag)
829 else:
829 else:
830 hn = repo.lookup(node)
830 hn = repo.lookup(node)
831 if isactive:
831 if isactive:
832 label = 'branches.active'
832 label = 'branches.active'
833 notice = ''
833 notice = ''
834 elif hn not in repo.branchheads(tag, closed=False):
834 elif hn not in repo.branchheads(tag, closed=False):
835 if not closed:
835 if not closed:
836 continue
836 continue
837 label = 'branches.closed'
837 label = 'branches.closed'
838 notice = _(' (closed)')
838 notice = _(' (closed)')
839 else:
839 else:
840 label = 'branches.inactive'
840 label = 'branches.inactive'
841 notice = _(' (inactive)')
841 notice = _(' (inactive)')
842 if tag == repo.dirstate.branch():
842 if tag == repo.dirstate.branch():
843 label = 'branches.current'
843 label = 'branches.current'
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
846 tag = ui.label(tag, label)
846 tag = ui.label(tag, label)
847 ui.write("%s %s%s\n" % (tag, rev, notice))
847 ui.write("%s %s%s\n" % (tag, rev, notice))
848
848
849 @command('bundle',
849 @command('bundle',
850 [('f', 'force', None, _('run even when the destination is unrelated')),
850 [('f', 'force', None, _('run even when the destination is unrelated')),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
852 _('REV')),
852 _('REV')),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
854 _('BRANCH')),
854 _('BRANCH')),
855 ('', 'base', [],
855 ('', 'base', [],
856 _('a base changeset assumed to be available at the destination'),
856 _('a base changeset assumed to be available at the destination'),
857 _('REV')),
857 _('REV')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
860 ] + remoteopts,
860 ] + remoteopts,
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
862 def bundle(ui, repo, fname, dest=None, **opts):
862 def bundle(ui, repo, fname, dest=None, **opts):
863 """create a changegroup file
863 """create a changegroup file
864
864
865 Generate a compressed changegroup file collecting changesets not
865 Generate a compressed changegroup file collecting changesets not
866 known to be in another repository.
866 known to be in another repository.
867
867
868 If you omit the destination repository, then hg assumes the
868 If you omit the destination repository, then hg assumes the
869 destination will have all the nodes you specify with --base
869 destination will have all the nodes you specify with --base
870 parameters. To create a bundle containing all changesets, use
870 parameters. To create a bundle containing all changesets, use
871 -a/--all (or --base null).
871 -a/--all (or --base null).
872
872
873 You can change compression method with the -t/--type option.
873 You can change compression method with the -t/--type option.
874 The available compression methods are: none, bzip2, and
874 The available compression methods are: none, bzip2, and
875 gzip (by default, bundles are compressed using bzip2).
875 gzip (by default, bundles are compressed using bzip2).
876
876
877 The bundle file can then be transferred using conventional means
877 The bundle file can then be transferred using conventional means
878 and applied to another repository with the unbundle or pull
878 and applied to another repository with the unbundle or pull
879 command. This is useful when direct push and pull are not
879 command. This is useful when direct push and pull are not
880 available or when exporting an entire repository is undesirable.
880 available or when exporting an entire repository is undesirable.
881
881
882 Applying bundles preserves all changeset contents including
882 Applying bundles preserves all changeset contents including
883 permissions, copy/rename information, and revision history.
883 permissions, copy/rename information, and revision history.
884
884
885 Returns 0 on success, 1 if no changes found.
885 Returns 0 on success, 1 if no changes found.
886 """
886 """
887 revs = None
887 revs = None
888 if 'rev' in opts:
888 if 'rev' in opts:
889 revs = scmutil.revrange(repo, opts['rev'])
889 revs = scmutil.revrange(repo, opts['rev'])
890
890
891 if opts.get('all'):
891 if opts.get('all'):
892 base = ['null']
892 base = ['null']
893 else:
893 else:
894 base = scmutil.revrange(repo, opts.get('base'))
894 base = scmutil.revrange(repo, opts.get('base'))
895 if base:
895 if base:
896 if dest:
896 if dest:
897 raise util.Abort(_("--base is incompatible with specifying "
897 raise util.Abort(_("--base is incompatible with specifying "
898 "a destination"))
898 "a destination"))
899 common = [repo.lookup(rev) for rev in base]
899 common = [repo.lookup(rev) for rev in base]
900 heads = revs and map(repo.lookup, revs) or revs
900 heads = revs and map(repo.lookup, revs) or revs
901 else:
901 else:
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
904 other = hg.peer(repo, opts, dest)
904 other = hg.peer(repo, opts, dest)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
906 heads = revs and map(repo.lookup, revs) or revs
906 heads = revs and map(repo.lookup, revs) or revs
907 common, outheads = discovery.findcommonoutgoing(repo, other,
907 common, outheads = discovery.findcommonoutgoing(repo, other,
908 onlyheads=heads,
908 onlyheads=heads,
909 force=opts.get('force'))
909 force=opts.get('force'))
910
910
911 cg = repo.getbundle('bundle', common=common, heads=heads)
911 cg = repo.getbundle('bundle', common=common, heads=heads)
912 if not cg:
912 if not cg:
913 ui.status(_("no changes found\n"))
913 ui.status(_("no changes found\n"))
914 return 1
914 return 1
915
915
916 bundletype = opts.get('type', 'bzip2').lower()
916 bundletype = opts.get('type', 'bzip2').lower()
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
918 bundletype = btypes.get(bundletype)
918 bundletype = btypes.get(bundletype)
919 if bundletype not in changegroup.bundletypes:
919 if bundletype not in changegroup.bundletypes:
920 raise util.Abort(_('unknown bundle type specified with --type'))
920 raise util.Abort(_('unknown bundle type specified with --type'))
921
921
922 changegroup.writebundle(cg, fname, bundletype)
922 changegroup.writebundle(cg, fname, bundletype)
923
923
924 @command('cat',
924 @command('cat',
925 [('o', 'output', '',
925 [('o', 'output', '',
926 _('print output to file with formatted name'), _('FORMAT')),
926 _('print output to file with formatted name'), _('FORMAT')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
928 ('', 'decode', None, _('apply any matching decode filter')),
928 ('', 'decode', None, _('apply any matching decode filter')),
929 ] + walkopts,
929 ] + walkopts,
930 _('[OPTION]... FILE...'))
930 _('[OPTION]... FILE...'))
931 def cat(ui, repo, file1, *pats, **opts):
931 def cat(ui, repo, file1, *pats, **opts):
932 """output the current or given revision of files
932 """output the current or given revision of files
933
933
934 Print the specified files as they were at the given revision. If
934 Print the specified files as they were at the given revision. If
935 no revision is given, the parent of the working directory is used,
935 no revision is given, the parent of the working directory is used,
936 or tip if no revision is checked out.
936 or tip if no revision is checked out.
937
937
938 Output may be to a file, in which case the name of the file is
938 Output may be to a file, in which case the name of the file is
939 given using a format string. The formatting rules are the same as
939 given using a format string. The formatting rules are the same as
940 for the export command, with the following additions:
940 for the export command, with the following additions:
941
941
942 :``%s``: basename of file being printed
942 :``%s``: basename of file being printed
943 :``%d``: dirname of file being printed, or '.' if in repository root
943 :``%d``: dirname of file being printed, or '.' if in repository root
944 :``%p``: root-relative path name of file being printed
944 :``%p``: root-relative path name of file being printed
945
945
946 Returns 0 on success.
946 Returns 0 on success.
947 """
947 """
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
949 err = 1
949 err = 1
950 m = scmutil.match(ctx, (file1,) + pats, opts)
950 m = scmutil.match(ctx, (file1,) + pats, opts)
951 for abs in ctx.walk(m):
951 for abs in ctx.walk(m):
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
953 pathname=abs)
953 pathname=abs)
954 data = ctx[abs].data()
954 data = ctx[abs].data()
955 if opts.get('decode'):
955 if opts.get('decode'):
956 data = repo.wwritedata(abs, data)
956 data = repo.wwritedata(abs, data)
957 fp.write(data)
957 fp.write(data)
958 fp.close()
958 fp.close()
959 err = 0
959 err = 0
960 return err
960 return err
961
961
962 @command('^clone',
962 @command('^clone',
963 [('U', 'noupdate', None,
963 [('U', 'noupdate', None,
964 _('the clone will include an empty working copy (only a repository)')),
964 _('the clone will include an empty working copy (only a repository)')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
970 ] + remoteopts,
970 ] + remoteopts,
971 _('[OPTION]... SOURCE [DEST]'))
971 _('[OPTION]... SOURCE [DEST]'))
972 def clone(ui, source, dest=None, **opts):
972 def clone(ui, source, dest=None, **opts):
973 """make a copy of an existing repository
973 """make a copy of an existing repository
974
974
975 Create a copy of an existing repository in a new directory.
975 Create a copy of an existing repository in a new directory.
976
976
977 If no destination directory name is specified, it defaults to the
977 If no destination directory name is specified, it defaults to the
978 basename of the source.
978 basename of the source.
979
979
980 The location of the source is added to the new repository's
980 The location of the source is added to the new repository's
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
982
982
983 See :hg:`help urls` for valid source format details.
983 See :hg:`help urls` for valid source format details.
984
984
985 It is possible to specify an ``ssh://`` URL as the destination, but no
985 It is possible to specify an ``ssh://`` URL as the destination, but no
986 ``.hg/hgrc`` and working directory will be created on the remote side.
986 ``.hg/hgrc`` and working directory will be created on the remote side.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
988
988
989 A set of changesets (tags, or branch names) to pull may be specified
989 A set of changesets (tags, or branch names) to pull may be specified
990 by listing each changeset (tag, or branch name) with -r/--rev.
990 by listing each changeset (tag, or branch name) with -r/--rev.
991 If -r/--rev is used, the cloned repository will contain only a subset
991 If -r/--rev is used, the cloned repository will contain only a subset
992 of the changesets of the source repository. Only the set of changesets
992 of the changesets of the source repository. Only the set of changesets
993 defined by all -r/--rev options (including all their ancestors)
993 defined by all -r/--rev options (including all their ancestors)
994 will be pulled into the destination repository.
994 will be pulled into the destination repository.
995 No subsequent changesets (including subsequent tags) will be present
995 No subsequent changesets (including subsequent tags) will be present
996 in the destination.
996 in the destination.
997
997
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
999 local source repositories.
999 local source repositories.
1000
1000
1001 For efficiency, hardlinks are used for cloning whenever the source
1001 For efficiency, hardlinks are used for cloning whenever the source
1002 and destination are on the same filesystem (note this applies only
1002 and destination are on the same filesystem (note this applies only
1003 to the repository data, not to the working directory). Some
1003 to the repository data, not to the working directory). Some
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1005 do not report errors. In these cases, use the --pull option to
1005 do not report errors. In these cases, use the --pull option to
1006 avoid hardlinking.
1006 avoid hardlinking.
1007
1007
1008 In some cases, you can clone repositories and the working directory
1008 In some cases, you can clone repositories and the working directory
1009 using full hardlinks with ::
1009 using full hardlinks with ::
1010
1010
1011 $ cp -al REPO REPOCLONE
1011 $ cp -al REPO REPOCLONE
1012
1012
1013 This is the fastest way to clone, but it is not always safe. The
1013 This is the fastest way to clone, but it is not always safe. The
1014 operation is not atomic (making sure REPO is not modified during
1014 operation is not atomic (making sure REPO is not modified during
1015 the operation is up to you) and you have to make sure your editor
1015 the operation is up to you) and you have to make sure your editor
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1017 this is not compatible with certain extensions that place their
1017 this is not compatible with certain extensions that place their
1018 metadata under the .hg directory, such as mq.
1018 metadata under the .hg directory, such as mq.
1019
1019
1020 Mercurial will update the working directory to the first applicable
1020 Mercurial will update the working directory to the first applicable
1021 revision from this list:
1021 revision from this list:
1022
1022
1023 a) null if -U or the source repository has no changesets
1023 a) null if -U or the source repository has no changesets
1024 b) if -u . and the source repository is local, the first parent of
1024 b) if -u . and the source repository is local, the first parent of
1025 the source repository's working directory
1025 the source repository's working directory
1026 c) the changeset specified with -u (if a branch name, this means the
1026 c) the changeset specified with -u (if a branch name, this means the
1027 latest head of that branch)
1027 latest head of that branch)
1028 d) the changeset specified with -r
1028 d) the changeset specified with -r
1029 e) the tipmost head specified with -b
1029 e) the tipmost head specified with -b
1030 f) the tipmost head specified with the url#branch source syntax
1030 f) the tipmost head specified with the url#branch source syntax
1031 g) the tipmost head of the default branch
1031 g) the tipmost head of the default branch
1032 h) tip
1032 h) tip
1033
1033
1034 Returns 0 on success.
1034 Returns 0 on success.
1035 """
1035 """
1036 if opts.get('noupdate') and opts.get('updaterev'):
1036 if opts.get('noupdate') and opts.get('updaterev'):
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1038
1038
1039 r = hg.clone(ui, opts, source, dest,
1039 r = hg.clone(ui, opts, source, dest,
1040 pull=opts.get('pull'),
1040 pull=opts.get('pull'),
1041 stream=opts.get('uncompressed'),
1041 stream=opts.get('uncompressed'),
1042 rev=opts.get('rev'),
1042 rev=opts.get('rev'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1044 branch=opts.get('branch'))
1044 branch=opts.get('branch'))
1045
1045
1046 return r is None
1046 return r is None
1047
1047
1048 @command('^commit|ci',
1048 @command('^commit|ci',
1049 [('A', 'addremove', None,
1049 [('A', 'addremove', None,
1050 _('mark new/missing files as added/removed before committing')),
1050 _('mark new/missing files as added/removed before committing')),
1051 ('', 'close-branch', None,
1051 ('', 'close-branch', None,
1052 _('mark a branch as closed, hiding it from the branch list')),
1052 _('mark a branch as closed, hiding it from the branch list')),
1053 ] + walkopts + commitopts + commitopts2,
1053 ] + walkopts + commitopts + commitopts2,
1054 _('[OPTION]... [FILE]...'))
1054 _('[OPTION]... [FILE]...'))
1055 def commit(ui, repo, *pats, **opts):
1055 def commit(ui, repo, *pats, **opts):
1056 """commit the specified files or all outstanding changes
1056 """commit the specified files or all outstanding changes
1057
1057
1058 Commit changes to the given files into the repository. Unlike a
1058 Commit changes to the given files into the repository. Unlike a
1059 centralized SCM, this operation is a local operation. See
1059 centralized SCM, this operation is a local operation. See
1060 :hg:`push` for a way to actively distribute your changes.
1060 :hg:`push` for a way to actively distribute your changes.
1061
1061
1062 If a list of files is omitted, all changes reported by :hg:`status`
1062 If a list of files is omitted, all changes reported by :hg:`status`
1063 will be committed.
1063 will be committed.
1064
1064
1065 If you are committing the result of a merge, do not provide any
1065 If you are committing the result of a merge, do not provide any
1066 filenames or -I/-X filters.
1066 filenames or -I/-X filters.
1067
1067
1068 If no commit message is specified, Mercurial starts your
1068 If no commit message is specified, Mercurial starts your
1069 configured editor where you can enter a message. In case your
1069 configured editor where you can enter a message. In case your
1070 commit fails, you will find a backup of your message in
1070 commit fails, you will find a backup of your message in
1071 ``.hg/last-message.txt``.
1071 ``.hg/last-message.txt``.
1072
1072
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1074
1074
1075 Returns 0 on success, 1 if nothing changed.
1075 Returns 0 on success, 1 if nothing changed.
1076 """
1076 """
1077 extra = {}
1077 extra = {}
1078 if opts.get('close_branch'):
1078 if opts.get('close_branch'):
1079 if repo['.'].node() not in repo.branchheads():
1079 if repo['.'].node() not in repo.branchheads():
1080 # The topo heads set is included in the branch heads set of the
1080 # The topo heads set is included in the branch heads set of the
1081 # current branch, so it's sufficient to test branchheads
1081 # current branch, so it's sufficient to test branchheads
1082 raise util.Abort(_('can only close branch heads'))
1082 raise util.Abort(_('can only close branch heads'))
1083 extra['close'] = 1
1083 extra['close'] = 1
1084 e = cmdutil.commiteditor
1084 e = cmdutil.commiteditor
1085 if opts.get('force_editor'):
1085 if opts.get('force_editor'):
1086 e = cmdutil.commitforceeditor
1086 e = cmdutil.commitforceeditor
1087
1087
1088 def commitfunc(ui, repo, message, match, opts):
1088 def commitfunc(ui, repo, message, match, opts):
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1090 editor=e, extra=extra)
1090 editor=e, extra=extra)
1091
1091
1092 branch = repo[None].branch()
1092 branch = repo[None].branch()
1093 bheads = repo.branchheads(branch)
1093 bheads = repo.branchheads(branch)
1094
1094
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1096 if not node:
1096 if not node:
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1098 if stat[3]:
1098 if stat[3]:
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1100 % len(stat[3]))
1100 % len(stat[3]))
1101 else:
1101 else:
1102 ui.status(_("nothing changed\n"))
1102 ui.status(_("nothing changed\n"))
1103 return 1
1103 return 1
1104
1104
1105 ctx = repo[node]
1105 ctx = repo[node]
1106 parents = ctx.parents()
1106 parents = ctx.parents()
1107
1107
1108 if (bheads and node not in bheads and not
1108 if (bheads and node not in bheads and not
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1110 ui.status(_('created new head\n'))
1110 ui.status(_('created new head\n'))
1111 # The message is not printed for initial roots. For the other
1111 # The message is not printed for initial roots. For the other
1112 # changesets, it is printed in the following situations:
1112 # changesets, it is printed in the following situations:
1113 #
1113 #
1114 # Par column: for the 2 parents with ...
1114 # Par column: for the 2 parents with ...
1115 # N: null or no parent
1115 # N: null or no parent
1116 # B: parent is on another named branch
1116 # B: parent is on another named branch
1117 # C: parent is a regular non head changeset
1117 # C: parent is a regular non head changeset
1118 # H: parent was a branch head of the current branch
1118 # H: parent was a branch head of the current branch
1119 # Msg column: whether we print "created new head" message
1119 # Msg column: whether we print "created new head" message
1120 # In the following, it is assumed that there already exists some
1120 # In the following, it is assumed that there already exists some
1121 # initial branch heads of the current branch, otherwise nothing is
1121 # initial branch heads of the current branch, otherwise nothing is
1122 # printed anyway.
1122 # printed anyway.
1123 #
1123 #
1124 # Par Msg Comment
1124 # Par Msg Comment
1125 # NN y additional topo root
1125 # NN y additional topo root
1126 #
1126 #
1127 # BN y additional branch root
1127 # BN y additional branch root
1128 # CN y additional topo head
1128 # CN y additional topo head
1129 # HN n usual case
1129 # HN n usual case
1130 #
1130 #
1131 # BB y weird additional branch root
1131 # BB y weird additional branch root
1132 # CB y branch merge
1132 # CB y branch merge
1133 # HB n merge with named branch
1133 # HB n merge with named branch
1134 #
1134 #
1135 # CC y additional head from merge
1135 # CC y additional head from merge
1136 # CH n merge with a head
1136 # CH n merge with a head
1137 #
1137 #
1138 # HH n head merge: head count decreases
1138 # HH n head merge: head count decreases
1139
1139
1140 if not opts.get('close_branch'):
1140 if not opts.get('close_branch'):
1141 for r in parents:
1141 for r in parents:
1142 if r.extra().get('close') and r.branch() == branch:
1142 if r.extra().get('close') and r.branch() == branch:
1143 ui.status(_('reopening closed branch head %d\n') % r)
1143 ui.status(_('reopening closed branch head %d\n') % r)
1144
1144
1145 if ui.debugflag:
1145 if ui.debugflag:
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1147 elif ui.verbose:
1147 elif ui.verbose:
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1149
1149
1150 @command('copy|cp',
1150 @command('copy|cp',
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1153 ] + walkopts + dryrunopts,
1153 ] + walkopts + dryrunopts,
1154 _('[OPTION]... [SOURCE]... DEST'))
1154 _('[OPTION]... [SOURCE]... DEST'))
1155 def copy(ui, repo, *pats, **opts):
1155 def copy(ui, repo, *pats, **opts):
1156 """mark files as copied for the next commit
1156 """mark files as copied for the next commit
1157
1157
1158 Mark dest as having copies of source files. If dest is a
1158 Mark dest as having copies of source files. If dest is a
1159 directory, copies are put in that directory. If dest is a file,
1159 directory, copies are put in that directory. If dest is a file,
1160 the source must be a single file.
1160 the source must be a single file.
1161
1161
1162 By default, this command copies the contents of files as they
1162 By default, this command copies the contents of files as they
1163 exist in the working directory. If invoked with -A/--after, the
1163 exist in the working directory. If invoked with -A/--after, the
1164 operation is recorded, but no copying is performed.
1164 operation is recorded, but no copying is performed.
1165
1165
1166 This command takes effect with the next commit. To undo a copy
1166 This command takes effect with the next commit. To undo a copy
1167 before that, see :hg:`revert`.
1167 before that, see :hg:`revert`.
1168
1168
1169 Returns 0 on success, 1 if errors are encountered.
1169 Returns 0 on success, 1 if errors are encountered.
1170 """
1170 """
1171 wlock = repo.wlock(False)
1171 wlock = repo.wlock(False)
1172 try:
1172 try:
1173 return cmdutil.copy(ui, repo, pats, opts)
1173 return cmdutil.copy(ui, repo, pats, opts)
1174 finally:
1174 finally:
1175 wlock.release()
1175 wlock.release()
1176
1176
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1178 def debugancestor(ui, repo, *args):
1178 def debugancestor(ui, repo, *args):
1179 """find the ancestor revision of two revisions in a given index"""
1179 """find the ancestor revision of two revisions in a given index"""
1180 if len(args) == 3:
1180 if len(args) == 3:
1181 index, rev1, rev2 = args
1181 index, rev1, rev2 = args
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1183 lookup = r.lookup
1183 lookup = r.lookup
1184 elif len(args) == 2:
1184 elif len(args) == 2:
1185 if not repo:
1185 if not repo:
1186 raise util.Abort(_("there is no Mercurial repository here "
1186 raise util.Abort(_("there is no Mercurial repository here "
1187 "(.hg not found)"))
1187 "(.hg not found)"))
1188 rev1, rev2 = args
1188 rev1, rev2 = args
1189 r = repo.changelog
1189 r = repo.changelog
1190 lookup = repo.lookup
1190 lookup = repo.lookup
1191 else:
1191 else:
1192 raise util.Abort(_('either two or three arguments required'))
1192 raise util.Abort(_('either two or three arguments required'))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1195
1195
1196 @command('debugbuilddag',
1196 @command('debugbuilddag',
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1200 _('[OPTION]... [TEXT]'))
1200 _('[OPTION]... [TEXT]'))
1201 def debugbuilddag(ui, repo, text=None,
1201 def debugbuilddag(ui, repo, text=None,
1202 mergeable_file=False,
1202 mergeable_file=False,
1203 overwritten_file=False,
1203 overwritten_file=False,
1204 new_file=False):
1204 new_file=False):
1205 """builds a repo with a given DAG from scratch in the current empty repo
1205 """builds a repo with a given DAG from scratch in the current empty repo
1206
1206
1207 The description of the DAG is read from stdin if not given on the
1207 The description of the DAG is read from stdin if not given on the
1208 command line.
1208 command line.
1209
1209
1210 Elements:
1210 Elements:
1211
1211
1212 - "+n" is a linear run of n nodes based on the current default parent
1212 - "+n" is a linear run of n nodes based on the current default parent
1213 - "." is a single node based on the current default parent
1213 - "." is a single node based on the current default parent
1214 - "$" resets the default parent to null (implied at the start);
1214 - "$" resets the default parent to null (implied at the start);
1215 otherwise the default parent is always the last node created
1215 otherwise the default parent is always the last node created
1216 - "<p" sets the default parent to the backref p
1216 - "<p" sets the default parent to the backref p
1217 - "*p" is a fork at parent p, which is a backref
1217 - "*p" is a fork at parent p, which is a backref
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1219 - "/p2" is a merge of the preceding node and p2
1219 - "/p2" is a merge of the preceding node and p2
1220 - ":tag" defines a local tag for the preceding node
1220 - ":tag" defines a local tag for the preceding node
1221 - "@branch" sets the named branch for subsequent nodes
1221 - "@branch" sets the named branch for subsequent nodes
1222 - "#...\\n" is a comment up to the end of the line
1222 - "#...\\n" is a comment up to the end of the line
1223
1223
1224 Whitespace between the above elements is ignored.
1224 Whitespace between the above elements is ignored.
1225
1225
1226 A backref is either
1226 A backref is either
1227
1227
1228 - a number n, which references the node curr-n, where curr is the current
1228 - a number n, which references the node curr-n, where curr is the current
1229 node, or
1229 node, or
1230 - the name of a local tag you placed earlier using ":tag", or
1230 - the name of a local tag you placed earlier using ":tag", or
1231 - empty to denote the default parent.
1231 - empty to denote the default parent.
1232
1232
1233 All string valued-elements are either strictly alphanumeric, or must
1233 All string valued-elements are either strictly alphanumeric, or must
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1235 """
1235 """
1236
1236
1237 if text is None:
1237 if text is None:
1238 ui.status(_("reading DAG from stdin\n"))
1238 ui.status(_("reading DAG from stdin\n"))
1239 text = ui.fin.read()
1239 text = ui.fin.read()
1240
1240
1241 cl = repo.changelog
1241 cl = repo.changelog
1242 if len(cl) > 0:
1242 if len(cl) > 0:
1243 raise util.Abort(_('repository is not empty'))
1243 raise util.Abort(_('repository is not empty'))
1244
1244
1245 # determine number of revs in DAG
1245 # determine number of revs in DAG
1246 total = 0
1246 total = 0
1247 for type, data in dagparser.parsedag(text):
1247 for type, data in dagparser.parsedag(text):
1248 if type == 'n':
1248 if type == 'n':
1249 total += 1
1249 total += 1
1250
1250
1251 if mergeable_file:
1251 if mergeable_file:
1252 linesperrev = 2
1252 linesperrev = 2
1253 # make a file with k lines per rev
1253 # make a file with k lines per rev
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1255 initialmergedlines.append("")
1255 initialmergedlines.append("")
1256
1256
1257 tags = []
1257 tags = []
1258
1258
1259 tr = repo.transaction("builddag")
1259 tr = repo.transaction("builddag")
1260 try:
1260 try:
1261
1261
1262 at = -1
1262 at = -1
1263 atbranch = 'default'
1263 atbranch = 'default'
1264 nodeids = []
1264 nodeids = []
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1266 for type, data in dagparser.parsedag(text):
1266 for type, data in dagparser.parsedag(text):
1267 if type == 'n':
1267 if type == 'n':
1268 ui.note('node %s\n' % str(data))
1268 ui.note('node %s\n' % str(data))
1269 id, ps = data
1269 id, ps = data
1270
1270
1271 files = []
1271 files = []
1272 fctxs = {}
1272 fctxs = {}
1273
1273
1274 p2 = None
1274 p2 = None
1275 if mergeable_file:
1275 if mergeable_file:
1276 fn = "mf"
1276 fn = "mf"
1277 p1 = repo[ps[0]]
1277 p1 = repo[ps[0]]
1278 if len(ps) > 1:
1278 if len(ps) > 1:
1279 p2 = repo[ps[1]]
1279 p2 = repo[ps[1]]
1280 pa = p1.ancestor(p2)
1280 pa = p1.ancestor(p2)
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1282 m3 = simplemerge.Merge3Text(base, local, other)
1282 m3 = simplemerge.Merge3Text(base, local, other)
1283 ml = [l.strip() for l in m3.merge_lines()]
1283 ml = [l.strip() for l in m3.merge_lines()]
1284 ml.append("")
1284 ml.append("")
1285 elif at > 0:
1285 elif at > 0:
1286 ml = p1[fn].data().split("\n")
1286 ml = p1[fn].data().split("\n")
1287 else:
1287 else:
1288 ml = initialmergedlines
1288 ml = initialmergedlines
1289 ml[id * linesperrev] += " r%i" % id
1289 ml[id * linesperrev] += " r%i" % id
1290 mergedtext = "\n".join(ml)
1290 mergedtext = "\n".join(ml)
1291 files.append(fn)
1291 files.append(fn)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1293
1293
1294 if overwritten_file:
1294 if overwritten_file:
1295 fn = "of"
1295 fn = "of"
1296 files.append(fn)
1296 files.append(fn)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1298
1298
1299 if new_file:
1299 if new_file:
1300 fn = "nf%i" % id
1300 fn = "nf%i" % id
1301 files.append(fn)
1301 files.append(fn)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1303 if len(ps) > 1:
1303 if len(ps) > 1:
1304 if not p2:
1304 if not p2:
1305 p2 = repo[ps[1]]
1305 p2 = repo[ps[1]]
1306 for fn in p2:
1306 for fn in p2:
1307 if fn.startswith("nf"):
1307 if fn.startswith("nf"):
1308 files.append(fn)
1308 files.append(fn)
1309 fctxs[fn] = p2[fn]
1309 fctxs[fn] = p2[fn]
1310
1310
1311 def fctxfn(repo, cx, path):
1311 def fctxfn(repo, cx, path):
1312 return fctxs.get(path)
1312 return fctxs.get(path)
1313
1313
1314 if len(ps) == 0 or ps[0] < 0:
1314 if len(ps) == 0 or ps[0] < 0:
1315 pars = [None, None]
1315 pars = [None, None]
1316 elif len(ps) == 1:
1316 elif len(ps) == 1:
1317 pars = [nodeids[ps[0]], None]
1317 pars = [nodeids[ps[0]], None]
1318 else:
1318 else:
1319 pars = [nodeids[p] for p in ps]
1319 pars = [nodeids[p] for p in ps]
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1321 date=(id, 0),
1321 date=(id, 0),
1322 user="debugbuilddag",
1322 user="debugbuilddag",
1323 extra={'branch': atbranch})
1323 extra={'branch': atbranch})
1324 nodeid = repo.commitctx(cx)
1324 nodeid = repo.commitctx(cx)
1325 nodeids.append(nodeid)
1325 nodeids.append(nodeid)
1326 at = id
1326 at = id
1327 elif type == 'l':
1327 elif type == 'l':
1328 id, name = data
1328 id, name = data
1329 ui.note('tag %s\n' % name)
1329 ui.note('tag %s\n' % name)
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1331 elif type == 'a':
1331 elif type == 'a':
1332 ui.note('branch %s\n' % data)
1332 ui.note('branch %s\n' % data)
1333 atbranch = data
1333 atbranch = data
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1335 tr.close()
1335 tr.close()
1336 finally:
1336 finally:
1337 ui.progress(_('building'), None)
1337 ui.progress(_('building'), None)
1338 tr.release()
1338 tr.release()
1339
1339
1340 if tags:
1340 if tags:
1341 repo.opener.write("localtags", "".join(tags))
1341 repo.opener.write("localtags", "".join(tags))
1342
1342
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1345 """lists the contents of a bundle"""
1345 """lists the contents of a bundle"""
1346 f = url.open(ui, bundlepath)
1346 f = url.open(ui, bundlepath)
1347 try:
1347 try:
1348 gen = changegroup.readbundle(f, bundlepath)
1348 gen = changegroup.readbundle(f, bundlepath)
1349 if all:
1349 if all:
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1351
1351
1352 def showchunks(named):
1352 def showchunks(named):
1353 ui.write("\n%s\n" % named)
1353 ui.write("\n%s\n" % named)
1354 chain = None
1354 chain = None
1355 while True:
1355 while True:
1356 chunkdata = gen.deltachunk(chain)
1356 chunkdata = gen.deltachunk(chain)
1357 if not chunkdata:
1357 if not chunkdata:
1358 break
1358 break
1359 node = chunkdata['node']
1359 node = chunkdata['node']
1360 p1 = chunkdata['p1']
1360 p1 = chunkdata['p1']
1361 p2 = chunkdata['p2']
1361 p2 = chunkdata['p2']
1362 cs = chunkdata['cs']
1362 cs = chunkdata['cs']
1363 deltabase = chunkdata['deltabase']
1363 deltabase = chunkdata['deltabase']
1364 delta = chunkdata['delta']
1364 delta = chunkdata['delta']
1365 ui.write("%s %s %s %s %s %s\n" %
1365 ui.write("%s %s %s %s %s %s\n" %
1366 (hex(node), hex(p1), hex(p2),
1366 (hex(node), hex(p1), hex(p2),
1367 hex(cs), hex(deltabase), len(delta)))
1367 hex(cs), hex(deltabase), len(delta)))
1368 chain = node
1368 chain = node
1369
1369
1370 chunkdata = gen.changelogheader()
1370 chunkdata = gen.changelogheader()
1371 showchunks("changelog")
1371 showchunks("changelog")
1372 chunkdata = gen.manifestheader()
1372 chunkdata = gen.manifestheader()
1373 showchunks("manifest")
1373 showchunks("manifest")
1374 while True:
1374 while True:
1375 chunkdata = gen.filelogheader()
1375 chunkdata = gen.filelogheader()
1376 if not chunkdata:
1376 if not chunkdata:
1377 break
1377 break
1378 fname = chunkdata['filename']
1378 fname = chunkdata['filename']
1379 showchunks(fname)
1379 showchunks(fname)
1380 else:
1380 else:
1381 chunkdata = gen.changelogheader()
1381 chunkdata = gen.changelogheader()
1382 chain = None
1382 chain = None
1383 while True:
1383 while True:
1384 chunkdata = gen.deltachunk(chain)
1384 chunkdata = gen.deltachunk(chain)
1385 if not chunkdata:
1385 if not chunkdata:
1386 break
1386 break
1387 node = chunkdata['node']
1387 node = chunkdata['node']
1388 ui.write("%s\n" % hex(node))
1388 ui.write("%s\n" % hex(node))
1389 chain = node
1389 chain = node
1390 finally:
1390 finally:
1391 f.close()
1391 f.close()
1392
1392
1393 @command('debugcheckstate', [], '')
1393 @command('debugcheckstate', [], '')
1394 def debugcheckstate(ui, repo):
1394 def debugcheckstate(ui, repo):
1395 """validate the correctness of the current dirstate"""
1395 """validate the correctness of the current dirstate"""
1396 parent1, parent2 = repo.dirstate.parents()
1396 parent1, parent2 = repo.dirstate.parents()
1397 m1 = repo[parent1].manifest()
1397 m1 = repo[parent1].manifest()
1398 m2 = repo[parent2].manifest()
1398 m2 = repo[parent2].manifest()
1399 errors = 0
1399 errors = 0
1400 for f in repo.dirstate:
1400 for f in repo.dirstate:
1401 state = repo.dirstate[f]
1401 state = repo.dirstate[f]
1402 if state in "nr" and f not in m1:
1402 if state in "nr" and f not in m1:
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1404 errors += 1
1404 errors += 1
1405 if state in "a" and f in m1:
1405 if state in "a" and f in m1:
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1407 errors += 1
1407 errors += 1
1408 if state in "m" and f not in m1 and f not in m2:
1408 if state in "m" and f not in m1 and f not in m2:
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1410 (f, state))
1410 (f, state))
1411 errors += 1
1411 errors += 1
1412 for f in m1:
1412 for f in m1:
1413 state = repo.dirstate[f]
1413 state = repo.dirstate[f]
1414 if state not in "nrm":
1414 if state not in "nrm":
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1416 errors += 1
1416 errors += 1
1417 if errors:
1417 if errors:
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1419 raise util.Abort(error)
1419 raise util.Abort(error)
1420
1420
1421 @command('debugcommands', [], _('[COMMAND]'))
1421 @command('debugcommands', [], _('[COMMAND]'))
1422 def debugcommands(ui, cmd='', *args):
1422 def debugcommands(ui, cmd='', *args):
1423 """list all available commands and options"""
1423 """list all available commands and options"""
1424 for cmd, vals in sorted(table.iteritems()):
1424 for cmd, vals in sorted(table.iteritems()):
1425 cmd = cmd.split('|')[0].strip('^')
1425 cmd = cmd.split('|')[0].strip('^')
1426 opts = ', '.join([i[1] for i in vals[1]])
1426 opts = ', '.join([i[1] for i in vals[1]])
1427 ui.write('%s: %s\n' % (cmd, opts))
1427 ui.write('%s: %s\n' % (cmd, opts))
1428
1428
1429 @command('debugcomplete',
1429 @command('debugcomplete',
1430 [('o', 'options', None, _('show the command options'))],
1430 [('o', 'options', None, _('show the command options'))],
1431 _('[-o] CMD'))
1431 _('[-o] CMD'))
1432 def debugcomplete(ui, cmd='', **opts):
1432 def debugcomplete(ui, cmd='', **opts):
1433 """returns the completion list associated with the given command"""
1433 """returns the completion list associated with the given command"""
1434
1434
1435 if opts.get('options'):
1435 if opts.get('options'):
1436 options = []
1436 options = []
1437 otables = [globalopts]
1437 otables = [globalopts]
1438 if cmd:
1438 if cmd:
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1440 otables.append(entry[1])
1440 otables.append(entry[1])
1441 for t in otables:
1441 for t in otables:
1442 for o in t:
1442 for o in t:
1443 if "(DEPRECATED)" in o[3]:
1443 if "(DEPRECATED)" in o[3]:
1444 continue
1444 continue
1445 if o[0]:
1445 if o[0]:
1446 options.append('-%s' % o[0])
1446 options.append('-%s' % o[0])
1447 options.append('--%s' % o[1])
1447 options.append('--%s' % o[1])
1448 ui.write("%s\n" % "\n".join(options))
1448 ui.write("%s\n" % "\n".join(options))
1449 return
1449 return
1450
1450
1451 cmdlist = cmdutil.findpossible(cmd, table)
1451 cmdlist = cmdutil.findpossible(cmd, table)
1452 if ui.verbose:
1452 if ui.verbose:
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1455
1455
1456 @command('debugdag',
1456 @command('debugdag',
1457 [('t', 'tags', None, _('use tags as labels')),
1457 [('t', 'tags', None, _('use tags as labels')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1459 ('', 'dots', None, _('use dots for runs')),
1459 ('', 'dots', None, _('use dots for runs')),
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1461 _('[OPTION]... [FILE [REV]...]'))
1461 _('[OPTION]... [FILE [REV]...]'))
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1463 """format the changelog or an index DAG as a concise textual description
1463 """format the changelog or an index DAG as a concise textual description
1464
1464
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1466 revision numbers, they get labelled in the output as rN.
1466 revision numbers, they get labelled in the output as rN.
1467
1467
1468 Otherwise, the changelog DAG of the current repo is emitted.
1468 Otherwise, the changelog DAG of the current repo is emitted.
1469 """
1469 """
1470 spaces = opts.get('spaces')
1470 spaces = opts.get('spaces')
1471 dots = opts.get('dots')
1471 dots = opts.get('dots')
1472 if file_:
1472 if file_:
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1474 revs = set((int(r) for r in revs))
1474 revs = set((int(r) for r in revs))
1475 def events():
1475 def events():
1476 for r in rlog:
1476 for r in rlog:
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1478 if r in revs:
1478 if r in revs:
1479 yield 'l', (r, "r%i" % r)
1479 yield 'l', (r, "r%i" % r)
1480 elif repo:
1480 elif repo:
1481 cl = repo.changelog
1481 cl = repo.changelog
1482 tags = opts.get('tags')
1482 tags = opts.get('tags')
1483 branches = opts.get('branches')
1483 branches = opts.get('branches')
1484 if tags:
1484 if tags:
1485 labels = {}
1485 labels = {}
1486 for l, n in repo.tags().items():
1486 for l, n in repo.tags().items():
1487 labels.setdefault(cl.rev(n), []).append(l)
1487 labels.setdefault(cl.rev(n), []).append(l)
1488 def events():
1488 def events():
1489 b = "default"
1489 b = "default"
1490 for r in cl:
1490 for r in cl:
1491 if branches:
1491 if branches:
1492 newb = cl.read(cl.node(r))[5]['branch']
1492 newb = cl.read(cl.node(r))[5]['branch']
1493 if newb != b:
1493 if newb != b:
1494 yield 'a', newb
1494 yield 'a', newb
1495 b = newb
1495 b = newb
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1497 if tags:
1497 if tags:
1498 ls = labels.get(r)
1498 ls = labels.get(r)
1499 if ls:
1499 if ls:
1500 for l in ls:
1500 for l in ls:
1501 yield 'l', (r, l)
1501 yield 'l', (r, l)
1502 else:
1502 else:
1503 raise util.Abort(_('need repo for changelog dag'))
1503 raise util.Abort(_('need repo for changelog dag'))
1504
1504
1505 for line in dagparser.dagtextlines(events(),
1505 for line in dagparser.dagtextlines(events(),
1506 addspaces=spaces,
1506 addspaces=spaces,
1507 wraplabels=True,
1507 wraplabels=True,
1508 wrapannotations=True,
1508 wrapannotations=True,
1509 wrapnonlinear=dots,
1509 wrapnonlinear=dots,
1510 usedots=dots,
1510 usedots=dots,
1511 maxlinewidth=70):
1511 maxlinewidth=70):
1512 ui.write(line)
1512 ui.write(line)
1513 ui.write("\n")
1513 ui.write("\n")
1514
1514
1515 @command('debugdata',
1515 @command('debugdata',
1516 [('c', 'changelog', False, _('open changelog')),
1516 [('c', 'changelog', False, _('open changelog')),
1517 ('m', 'manifest', False, _('open manifest'))],
1517 ('m', 'manifest', False, _('open manifest'))],
1518 _('-c|-m|FILE REV'))
1518 _('-c|-m|FILE REV'))
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1520 """dump the contents of a data file revision"""
1520 """dump the contents of a data file revision"""
1521 if opts.get('changelog') or opts.get('manifest'):
1521 if opts.get('changelog') or opts.get('manifest'):
1522 file_, rev = None, file_
1522 file_, rev = None, file_
1523 elif rev is None:
1523 elif rev is None:
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1526 try:
1526 try:
1527 ui.write(r.revision(r.lookup(rev)))
1527 ui.write(r.revision(r.lookup(rev)))
1528 except KeyError:
1528 except KeyError:
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1530
1530
1531 @command('debugdate',
1531 @command('debugdate',
1532 [('e', 'extended', None, _('try extended date formats'))],
1532 [('e', 'extended', None, _('try extended date formats'))],
1533 _('[-e] DATE [RANGE]'))
1533 _('[-e] DATE [RANGE]'))
1534 def debugdate(ui, date, range=None, **opts):
1534 def debugdate(ui, date, range=None, **opts):
1535 """parse and display a date"""
1535 """parse and display a date"""
1536 if opts["extended"]:
1536 if opts["extended"]:
1537 d = util.parsedate(date, util.extendeddateformats)
1537 d = util.parsedate(date, util.extendeddateformats)
1538 else:
1538 else:
1539 d = util.parsedate(date)
1539 d = util.parsedate(date)
1540 ui.write("internal: %s %s\n" % d)
1540 ui.write("internal: %s %s\n" % d)
1541 ui.write("standard: %s\n" % util.datestr(d))
1541 ui.write("standard: %s\n" % util.datestr(d))
1542 if range:
1542 if range:
1543 m = util.matchdate(range)
1543 m = util.matchdate(range)
1544 ui.write("match: %s\n" % m(d[0]))
1544 ui.write("match: %s\n" % m(d[0]))
1545
1545
1546 @command('debugdiscovery',
1546 @command('debugdiscovery',
1547 [('', 'old', None, _('use old-style discovery')),
1547 [('', 'old', None, _('use old-style discovery')),
1548 ('', 'nonheads', None,
1548 ('', 'nonheads', None,
1549 _('use old-style discovery with non-heads included')),
1549 _('use old-style discovery with non-heads included')),
1550 ] + remoteopts,
1550 ] + remoteopts,
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1553 """runs the changeset discovery protocol in isolation"""
1553 """runs the changeset discovery protocol in isolation"""
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1555 remote = hg.peer(repo, opts, remoteurl)
1555 remote = hg.peer(repo, opts, remoteurl)
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1557
1557
1558 # make sure tests are repeatable
1558 # make sure tests are repeatable
1559 random.seed(12323)
1559 random.seed(12323)
1560
1560
1561 def doit(localheads, remoteheads):
1561 def doit(localheads, remoteheads):
1562 if opts.get('old'):
1562 if opts.get('old'):
1563 if localheads:
1563 if localheads:
1564 raise util.Abort('cannot use localheads with old style discovery')
1564 raise util.Abort('cannot use localheads with old style discovery')
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1566 force=True)
1566 force=True)
1567 common = set(common)
1567 common = set(common)
1568 if not opts.get('nonheads'):
1568 if not opts.get('nonheads'):
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1570 for n in common]))
1570 for n in common]))
1571 dag = dagutil.revlogdag(repo.changelog)
1571 dag = dagutil.revlogdag(repo.changelog)
1572 all = dag.ancestorset(dag.internalizeall(common))
1572 all = dag.ancestorset(dag.internalizeall(common))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1574 else:
1574 else:
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1576 common = set(common)
1576 common = set(common)
1577 rheads = set(hds)
1577 rheads = set(hds)
1578 lheads = set(repo.heads())
1578 lheads = set(repo.heads())
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1580 if lheads <= common:
1580 if lheads <= common:
1581 ui.write("local is subset\n")
1581 ui.write("local is subset\n")
1582 elif rheads <= common:
1582 elif rheads <= common:
1583 ui.write("remote is subset\n")
1583 ui.write("remote is subset\n")
1584
1584
1585 serverlogs = opts.get('serverlog')
1585 serverlogs = opts.get('serverlog')
1586 if serverlogs:
1586 if serverlogs:
1587 for filename in serverlogs:
1587 for filename in serverlogs:
1588 logfile = open(filename, 'r')
1588 logfile = open(filename, 'r')
1589 try:
1589 try:
1590 line = logfile.readline()
1590 line = logfile.readline()
1591 while line:
1591 while line:
1592 parts = line.strip().split(';')
1592 parts = line.strip().split(';')
1593 op = parts[1]
1593 op = parts[1]
1594 if op == 'cg':
1594 if op == 'cg':
1595 pass
1595 pass
1596 elif op == 'cgss':
1596 elif op == 'cgss':
1597 doit(parts[2].split(' '), parts[3].split(' '))
1597 doit(parts[2].split(' '), parts[3].split(' '))
1598 elif op == 'unb':
1598 elif op == 'unb':
1599 doit(parts[3].split(' '), parts[2].split(' '))
1599 doit(parts[3].split(' '), parts[2].split(' '))
1600 line = logfile.readline()
1600 line = logfile.readline()
1601 finally:
1601 finally:
1602 logfile.close()
1602 logfile.close()
1603
1603
1604 else:
1604 else:
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1606 opts.get('remote_head'))
1606 opts.get('remote_head'))
1607 localrevs = opts.get('local_head')
1607 localrevs = opts.get('local_head')
1608 doit(localrevs, remoterevs)
1608 doit(localrevs, remoterevs)
1609
1609
1610 @command('debugfileset', [], ('REVSPEC'))
1610 @command('debugfileset', [], ('REVSPEC'))
1611 def debugfileset(ui, repo, expr):
1611 def debugfileset(ui, repo, expr):
1612 '''parse and apply a fileset specification'''
1612 '''parse and apply a fileset specification'''
1613 if ui.verbose:
1613 if ui.verbose:
1614 tree = fileset.parse(expr)[0]
1614 tree = fileset.parse(expr)[0]
1615 ui.note(tree, "\n")
1615 ui.note(tree, "\n")
1616
1616
1617 for f in fileset.getfileset(repo[None], expr):
1617 for f in fileset.getfileset(repo[None], expr):
1618 ui.write("%s\n" % f)
1618 ui.write("%s\n" % f)
1619
1619
1620 @command('debugfsinfo', [], _('[PATH]'))
1620 @command('debugfsinfo', [], _('[PATH]'))
1621 def debugfsinfo(ui, path = "."):
1621 def debugfsinfo(ui, path = "."):
1622 """show information detected about current filesystem"""
1622 """show information detected about current filesystem"""
1623 util.writefile('.debugfsinfo', '')
1623 util.writefile('.debugfsinfo', '')
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1627 and 'yes' or 'no'))
1627 and 'yes' or 'no'))
1628 os.unlink('.debugfsinfo')
1628 os.unlink('.debugfsinfo')
1629
1629
1630 @command('debuggetbundle',
1630 @command('debuggetbundle',
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1634 _('REPO FILE [-H|-C ID]...'))
1634 _('REPO FILE [-H|-C ID]...'))
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1636 """retrieves a bundle from a repo
1636 """retrieves a bundle from a repo
1637
1637
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1639 given file.
1639 given file.
1640 """
1640 """
1641 repo = hg.peer(ui, opts, repopath)
1641 repo = hg.peer(ui, opts, repopath)
1642 if not repo.capable('getbundle'):
1642 if not repo.capable('getbundle'):
1643 raise util.Abort("getbundle() not supported by target repository")
1643 raise util.Abort("getbundle() not supported by target repository")
1644 args = {}
1644 args = {}
1645 if common:
1645 if common:
1646 args['common'] = [bin(s) for s in common]
1646 args['common'] = [bin(s) for s in common]
1647 if head:
1647 if head:
1648 args['heads'] = [bin(s) for s in head]
1648 args['heads'] = [bin(s) for s in head]
1649 bundle = repo.getbundle('debug', **args)
1649 bundle = repo.getbundle('debug', **args)
1650
1650
1651 bundletype = opts.get('type', 'bzip2').lower()
1651 bundletype = opts.get('type', 'bzip2').lower()
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1653 bundletype = btypes.get(bundletype)
1653 bundletype = btypes.get(bundletype)
1654 if bundletype not in changegroup.bundletypes:
1654 if bundletype not in changegroup.bundletypes:
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1657
1657
1658 @command('debugignore', [], '')
1658 @command('debugignore', [], '')
1659 def debugignore(ui, repo, *values, **opts):
1659 def debugignore(ui, repo, *values, **opts):
1660 """display the combined ignore pattern"""
1660 """display the combined ignore pattern"""
1661 ignore = repo.dirstate._ignore
1661 ignore = repo.dirstate._ignore
1662 if hasattr(ignore, 'includepat'):
1662 includepat = getattr(ignore, 'includepat', None)
1663 ui.write("%s\n" % ignore.includepat)
1663 if includepat is not None:
1664 ui.write("%s\n" % includepat)
1664 else:
1665 else:
1665 raise util.Abort(_("no ignore patterns found"))
1666 raise util.Abort(_("no ignore patterns found"))
1666
1667
1667 @command('debugindex',
1668 @command('debugindex',
1668 [('c', 'changelog', False, _('open changelog')),
1669 [('c', 'changelog', False, _('open changelog')),
1669 ('m', 'manifest', False, _('open manifest')),
1670 ('m', 'manifest', False, _('open manifest')),
1670 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1671 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1671 _('[-f FORMAT] -c|-m|FILE'))
1672 _('[-f FORMAT] -c|-m|FILE'))
1672 def debugindex(ui, repo, file_ = None, **opts):
1673 def debugindex(ui, repo, file_ = None, **opts):
1673 """dump the contents of an index file"""
1674 """dump the contents of an index file"""
1674 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1675 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1675 format = opts.get('format', 0)
1676 format = opts.get('format', 0)
1676 if format not in (0, 1):
1677 if format not in (0, 1):
1677 raise util.Abort(_("unknown format %d") % format)
1678 raise util.Abort(_("unknown format %d") % format)
1678
1679
1679 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1680 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1680 if generaldelta:
1681 if generaldelta:
1681 basehdr = ' delta'
1682 basehdr = ' delta'
1682 else:
1683 else:
1683 basehdr = ' base'
1684 basehdr = ' base'
1684
1685
1685 if format == 0:
1686 if format == 0:
1686 ui.write(" rev offset length " + basehdr + " linkrev"
1687 ui.write(" rev offset length " + basehdr + " linkrev"
1687 " nodeid p1 p2\n")
1688 " nodeid p1 p2\n")
1688 elif format == 1:
1689 elif format == 1:
1689 ui.write(" rev flag offset length"
1690 ui.write(" rev flag offset length"
1690 " size " + basehdr + " link p1 p2 nodeid\n")
1691 " size " + basehdr + " link p1 p2 nodeid\n")
1691
1692
1692 for i in r:
1693 for i in r:
1693 node = r.node(i)
1694 node = r.node(i)
1694 if generaldelta:
1695 if generaldelta:
1695 base = r.deltaparent(i)
1696 base = r.deltaparent(i)
1696 else:
1697 else:
1697 base = r.chainbase(i)
1698 base = r.chainbase(i)
1698 if format == 0:
1699 if format == 0:
1699 try:
1700 try:
1700 pp = r.parents(node)
1701 pp = r.parents(node)
1701 except:
1702 except:
1702 pp = [nullid, nullid]
1703 pp = [nullid, nullid]
1703 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1704 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1704 i, r.start(i), r.length(i), base, r.linkrev(i),
1705 i, r.start(i), r.length(i), base, r.linkrev(i),
1705 short(node), short(pp[0]), short(pp[1])))
1706 short(node), short(pp[0]), short(pp[1])))
1706 elif format == 1:
1707 elif format == 1:
1707 pr = r.parentrevs(i)
1708 pr = r.parentrevs(i)
1708 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1709 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1709 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1710 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1710 base, r.linkrev(i), pr[0], pr[1], short(node)))
1711 base, r.linkrev(i), pr[0], pr[1], short(node)))
1711
1712
1712 @command('debugindexdot', [], _('FILE'))
1713 @command('debugindexdot', [], _('FILE'))
1713 def debugindexdot(ui, repo, file_):
1714 def debugindexdot(ui, repo, file_):
1714 """dump an index DAG as a graphviz dot file"""
1715 """dump an index DAG as a graphviz dot file"""
1715 r = None
1716 r = None
1716 if repo:
1717 if repo:
1717 filelog = repo.file(file_)
1718 filelog = repo.file(file_)
1718 if len(filelog):
1719 if len(filelog):
1719 r = filelog
1720 r = filelog
1720 if not r:
1721 if not r:
1721 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1722 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1722 ui.write("digraph G {\n")
1723 ui.write("digraph G {\n")
1723 for i in r:
1724 for i in r:
1724 node = r.node(i)
1725 node = r.node(i)
1725 pp = r.parents(node)
1726 pp = r.parents(node)
1726 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1727 if pp[1] != nullid:
1728 if pp[1] != nullid:
1728 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1729 ui.write("}\n")
1730 ui.write("}\n")
1730
1731
1731 @command('debuginstall', [], '')
1732 @command('debuginstall', [], '')
1732 def debuginstall(ui):
1733 def debuginstall(ui):
1733 '''test Mercurial installation
1734 '''test Mercurial installation
1734
1735
1735 Returns 0 on success.
1736 Returns 0 on success.
1736 '''
1737 '''
1737
1738
1738 def writetemp(contents):
1739 def writetemp(contents):
1739 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1740 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1740 f = os.fdopen(fd, "wb")
1741 f = os.fdopen(fd, "wb")
1741 f.write(contents)
1742 f.write(contents)
1742 f.close()
1743 f.close()
1743 return name
1744 return name
1744
1745
1745 problems = 0
1746 problems = 0
1746
1747
1747 # encoding
1748 # encoding
1748 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1749 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1749 try:
1750 try:
1750 encoding.fromlocal("test")
1751 encoding.fromlocal("test")
1751 except util.Abort, inst:
1752 except util.Abort, inst:
1752 ui.write(" %s\n" % inst)
1753 ui.write(" %s\n" % inst)
1753 ui.write(_(" (check that your locale is properly set)\n"))
1754 ui.write(_(" (check that your locale is properly set)\n"))
1754 problems += 1
1755 problems += 1
1755
1756
1756 # compiled modules
1757 # compiled modules
1757 ui.status(_("Checking installed modules (%s)...\n")
1758 ui.status(_("Checking installed modules (%s)...\n")
1758 % os.path.dirname(__file__))
1759 % os.path.dirname(__file__))
1759 try:
1760 try:
1760 import bdiff, mpatch, base85, osutil
1761 import bdiff, mpatch, base85, osutil
1761 except Exception, inst:
1762 except Exception, inst:
1762 ui.write(" %s\n" % inst)
1763 ui.write(" %s\n" % inst)
1763 ui.write(_(" One or more extensions could not be found"))
1764 ui.write(_(" One or more extensions could not be found"))
1764 ui.write(_(" (check that you compiled the extensions)\n"))
1765 ui.write(_(" (check that you compiled the extensions)\n"))
1765 problems += 1
1766 problems += 1
1766
1767
1767 # templates
1768 # templates
1768 ui.status(_("Checking templates...\n"))
1769 ui.status(_("Checking templates...\n"))
1769 try:
1770 try:
1770 import templater
1771 import templater
1771 templater.templater(templater.templatepath("map-cmdline.default"))
1772 templater.templater(templater.templatepath("map-cmdline.default"))
1772 except Exception, inst:
1773 except Exception, inst:
1773 ui.write(" %s\n" % inst)
1774 ui.write(" %s\n" % inst)
1774 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1775 problems += 1
1776 problems += 1
1776
1777
1777 # editor
1778 # editor
1778 ui.status(_("Checking commit editor...\n"))
1779 ui.status(_("Checking commit editor...\n"))
1779 editor = ui.geteditor()
1780 editor = ui.geteditor()
1780 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1781 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1781 if not cmdpath:
1782 if not cmdpath:
1782 if editor == 'vi':
1783 if editor == 'vi':
1783 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1784 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1784 ui.write(_(" (specify a commit editor in your configuration"
1785 ui.write(_(" (specify a commit editor in your configuration"
1785 " file)\n"))
1786 " file)\n"))
1786 else:
1787 else:
1787 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1788 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1788 ui.write(_(" (specify a commit editor in your configuration"
1789 ui.write(_(" (specify a commit editor in your configuration"
1789 " file)\n"))
1790 " file)\n"))
1790 problems += 1
1791 problems += 1
1791
1792
1792 # check username
1793 # check username
1793 ui.status(_("Checking username...\n"))
1794 ui.status(_("Checking username...\n"))
1794 try:
1795 try:
1795 ui.username()
1796 ui.username()
1796 except util.Abort, e:
1797 except util.Abort, e:
1797 ui.write(" %s\n" % e)
1798 ui.write(" %s\n" % e)
1798 ui.write(_(" (specify a username in your configuration file)\n"))
1799 ui.write(_(" (specify a username in your configuration file)\n"))
1799 problems += 1
1800 problems += 1
1800
1801
1801 if not problems:
1802 if not problems:
1802 ui.status(_("No problems detected\n"))
1803 ui.status(_("No problems detected\n"))
1803 else:
1804 else:
1804 ui.write(_("%s problems detected,"
1805 ui.write(_("%s problems detected,"
1805 " please check your install!\n") % problems)
1806 " please check your install!\n") % problems)
1806
1807
1807 return problems
1808 return problems
1808
1809
1809 @command('debugknown', [], _('REPO ID...'))
1810 @command('debugknown', [], _('REPO ID...'))
1810 def debugknown(ui, repopath, *ids, **opts):
1811 def debugknown(ui, repopath, *ids, **opts):
1811 """test whether node ids are known to a repo
1812 """test whether node ids are known to a repo
1812
1813
1813 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1814 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1814 indicating unknown/known.
1815 indicating unknown/known.
1815 """
1816 """
1816 repo = hg.peer(ui, opts, repopath)
1817 repo = hg.peer(ui, opts, repopath)
1817 if not repo.capable('known'):
1818 if not repo.capable('known'):
1818 raise util.Abort("known() not supported by target repository")
1819 raise util.Abort("known() not supported by target repository")
1819 flags = repo.known([bin(s) for s in ids])
1820 flags = repo.known([bin(s) for s in ids])
1820 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1821 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1821
1822
1822 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1823 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1823 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1824 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1824 '''access the pushkey key/value protocol
1825 '''access the pushkey key/value protocol
1825
1826
1826 With two args, list the keys in the given namespace.
1827 With two args, list the keys in the given namespace.
1827
1828
1828 With five args, set a key to new if it currently is set to old.
1829 With five args, set a key to new if it currently is set to old.
1829 Reports success or failure.
1830 Reports success or failure.
1830 '''
1831 '''
1831
1832
1832 target = hg.peer(ui, {}, repopath)
1833 target = hg.peer(ui, {}, repopath)
1833 if keyinfo:
1834 if keyinfo:
1834 key, old, new = keyinfo
1835 key, old, new = keyinfo
1835 r = target.pushkey(namespace, key, old, new)
1836 r = target.pushkey(namespace, key, old, new)
1836 ui.status(str(r) + '\n')
1837 ui.status(str(r) + '\n')
1837 return not r
1838 return not r
1838 else:
1839 else:
1839 for k, v in target.listkeys(namespace).iteritems():
1840 for k, v in target.listkeys(namespace).iteritems():
1840 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1841 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1841 v.encode('string-escape')))
1842 v.encode('string-escape')))
1842
1843
1843 @command('debugrebuildstate',
1844 @command('debugrebuildstate',
1844 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1845 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1845 _('[-r REV] [REV]'))
1846 _('[-r REV] [REV]'))
1846 def debugrebuildstate(ui, repo, rev="tip"):
1847 def debugrebuildstate(ui, repo, rev="tip"):
1847 """rebuild the dirstate as it would look like for the given revision"""
1848 """rebuild the dirstate as it would look like for the given revision"""
1848 ctx = scmutil.revsingle(repo, rev)
1849 ctx = scmutil.revsingle(repo, rev)
1849 wlock = repo.wlock()
1850 wlock = repo.wlock()
1850 try:
1851 try:
1851 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1852 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1852 finally:
1853 finally:
1853 wlock.release()
1854 wlock.release()
1854
1855
1855 @command('debugrename',
1856 @command('debugrename',
1856 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1857 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1857 _('[-r REV] FILE'))
1858 _('[-r REV] FILE'))
1858 def debugrename(ui, repo, file1, *pats, **opts):
1859 def debugrename(ui, repo, file1, *pats, **opts):
1859 """dump rename information"""
1860 """dump rename information"""
1860
1861
1861 ctx = scmutil.revsingle(repo, opts.get('rev'))
1862 ctx = scmutil.revsingle(repo, opts.get('rev'))
1862 m = scmutil.match(ctx, (file1,) + pats, opts)
1863 m = scmutil.match(ctx, (file1,) + pats, opts)
1863 for abs in ctx.walk(m):
1864 for abs in ctx.walk(m):
1864 fctx = ctx[abs]
1865 fctx = ctx[abs]
1865 o = fctx.filelog().renamed(fctx.filenode())
1866 o = fctx.filelog().renamed(fctx.filenode())
1866 rel = m.rel(abs)
1867 rel = m.rel(abs)
1867 if o:
1868 if o:
1868 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1869 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1869 else:
1870 else:
1870 ui.write(_("%s not renamed\n") % rel)
1871 ui.write(_("%s not renamed\n") % rel)
1871
1872
1872 @command('debugrevlog',
1873 @command('debugrevlog',
1873 [('c', 'changelog', False, _('open changelog')),
1874 [('c', 'changelog', False, _('open changelog')),
1874 ('m', 'manifest', False, _('open manifest')),
1875 ('m', 'manifest', False, _('open manifest')),
1875 ('d', 'dump', False, _('dump index data'))],
1876 ('d', 'dump', False, _('dump index data'))],
1876 _('-c|-m|FILE'))
1877 _('-c|-m|FILE'))
1877 def debugrevlog(ui, repo, file_ = None, **opts):
1878 def debugrevlog(ui, repo, file_ = None, **opts):
1878 """show data and statistics about a revlog"""
1879 """show data and statistics about a revlog"""
1879 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1880 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1880
1881
1881 if opts.get("dump"):
1882 if opts.get("dump"):
1882 numrevs = len(r)
1883 numrevs = len(r)
1883 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1884 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1884 " rawsize totalsize compression heads\n")
1885 " rawsize totalsize compression heads\n")
1885 ts = 0
1886 ts = 0
1886 heads = set()
1887 heads = set()
1887 for rev in xrange(numrevs):
1888 for rev in xrange(numrevs):
1888 dbase = r.deltaparent(rev)
1889 dbase = r.deltaparent(rev)
1889 if dbase == -1:
1890 if dbase == -1:
1890 dbase = rev
1891 dbase = rev
1891 cbase = r.chainbase(rev)
1892 cbase = r.chainbase(rev)
1892 p1, p2 = r.parentrevs(rev)
1893 p1, p2 = r.parentrevs(rev)
1893 rs = r.rawsize(rev)
1894 rs = r.rawsize(rev)
1894 ts = ts + rs
1895 ts = ts + rs
1895 heads -= set(r.parentrevs(rev))
1896 heads -= set(r.parentrevs(rev))
1896 heads.add(rev)
1897 heads.add(rev)
1897 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1898 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1898 (rev, p1, p2, r.start(rev), r.end(rev),
1899 (rev, p1, p2, r.start(rev), r.end(rev),
1899 r.start(dbase), r.start(cbase),
1900 r.start(dbase), r.start(cbase),
1900 r.start(p1), r.start(p2),
1901 r.start(p1), r.start(p2),
1901 rs, ts, ts / r.end(rev), len(heads)))
1902 rs, ts, ts / r.end(rev), len(heads)))
1902 return 0
1903 return 0
1903
1904
1904 v = r.version
1905 v = r.version
1905 format = v & 0xFFFF
1906 format = v & 0xFFFF
1906 flags = []
1907 flags = []
1907 gdelta = False
1908 gdelta = False
1908 if v & revlog.REVLOGNGINLINEDATA:
1909 if v & revlog.REVLOGNGINLINEDATA:
1909 flags.append('inline')
1910 flags.append('inline')
1910 if v & revlog.REVLOGGENERALDELTA:
1911 if v & revlog.REVLOGGENERALDELTA:
1911 gdelta = True
1912 gdelta = True
1912 flags.append('generaldelta')
1913 flags.append('generaldelta')
1913 if not flags:
1914 if not flags:
1914 flags = ['(none)']
1915 flags = ['(none)']
1915
1916
1916 nummerges = 0
1917 nummerges = 0
1917 numfull = 0
1918 numfull = 0
1918 numprev = 0
1919 numprev = 0
1919 nump1 = 0
1920 nump1 = 0
1920 nump2 = 0
1921 nump2 = 0
1921 numother = 0
1922 numother = 0
1922 nump1prev = 0
1923 nump1prev = 0
1923 nump2prev = 0
1924 nump2prev = 0
1924 chainlengths = []
1925 chainlengths = []
1925
1926
1926 datasize = [None, 0, 0L]
1927 datasize = [None, 0, 0L]
1927 fullsize = [None, 0, 0L]
1928 fullsize = [None, 0, 0L]
1928 deltasize = [None, 0, 0L]
1929 deltasize = [None, 0, 0L]
1929
1930
1930 def addsize(size, l):
1931 def addsize(size, l):
1931 if l[0] is None or size < l[0]:
1932 if l[0] is None or size < l[0]:
1932 l[0] = size
1933 l[0] = size
1933 if size > l[1]:
1934 if size > l[1]:
1934 l[1] = size
1935 l[1] = size
1935 l[2] += size
1936 l[2] += size
1936
1937
1937 numrevs = len(r)
1938 numrevs = len(r)
1938 for rev in xrange(numrevs):
1939 for rev in xrange(numrevs):
1939 p1, p2 = r.parentrevs(rev)
1940 p1, p2 = r.parentrevs(rev)
1940 delta = r.deltaparent(rev)
1941 delta = r.deltaparent(rev)
1941 if format > 0:
1942 if format > 0:
1942 addsize(r.rawsize(rev), datasize)
1943 addsize(r.rawsize(rev), datasize)
1943 if p2 != nullrev:
1944 if p2 != nullrev:
1944 nummerges += 1
1945 nummerges += 1
1945 size = r.length(rev)
1946 size = r.length(rev)
1946 if delta == nullrev:
1947 if delta == nullrev:
1947 chainlengths.append(0)
1948 chainlengths.append(0)
1948 numfull += 1
1949 numfull += 1
1949 addsize(size, fullsize)
1950 addsize(size, fullsize)
1950 else:
1951 else:
1951 chainlengths.append(chainlengths[delta] + 1)
1952 chainlengths.append(chainlengths[delta] + 1)
1952 addsize(size, deltasize)
1953 addsize(size, deltasize)
1953 if delta == rev - 1:
1954 if delta == rev - 1:
1954 numprev += 1
1955 numprev += 1
1955 if delta == p1:
1956 if delta == p1:
1956 nump1prev += 1
1957 nump1prev += 1
1957 elif delta == p2:
1958 elif delta == p2:
1958 nump2prev += 1
1959 nump2prev += 1
1959 elif delta == p1:
1960 elif delta == p1:
1960 nump1 += 1
1961 nump1 += 1
1961 elif delta == p2:
1962 elif delta == p2:
1962 nump2 += 1
1963 nump2 += 1
1963 elif delta != nullrev:
1964 elif delta != nullrev:
1964 numother += 1
1965 numother += 1
1965
1966
1966 numdeltas = numrevs - numfull
1967 numdeltas = numrevs - numfull
1967 numoprev = numprev - nump1prev - nump2prev
1968 numoprev = numprev - nump1prev - nump2prev
1968 totalrawsize = datasize[2]
1969 totalrawsize = datasize[2]
1969 datasize[2] /= numrevs
1970 datasize[2] /= numrevs
1970 fulltotal = fullsize[2]
1971 fulltotal = fullsize[2]
1971 fullsize[2] /= numfull
1972 fullsize[2] /= numfull
1972 deltatotal = deltasize[2]
1973 deltatotal = deltasize[2]
1973 deltasize[2] /= numrevs - numfull
1974 deltasize[2] /= numrevs - numfull
1974 totalsize = fulltotal + deltatotal
1975 totalsize = fulltotal + deltatotal
1975 avgchainlen = sum(chainlengths) / numrevs
1976 avgchainlen = sum(chainlengths) / numrevs
1976 compratio = totalrawsize / totalsize
1977 compratio = totalrawsize / totalsize
1977
1978
1978 basedfmtstr = '%%%dd\n'
1979 basedfmtstr = '%%%dd\n'
1979 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1980 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1980
1981
1981 def dfmtstr(max):
1982 def dfmtstr(max):
1982 return basedfmtstr % len(str(max))
1983 return basedfmtstr % len(str(max))
1983 def pcfmtstr(max, padding=0):
1984 def pcfmtstr(max, padding=0):
1984 return basepcfmtstr % (len(str(max)), ' ' * padding)
1985 return basepcfmtstr % (len(str(max)), ' ' * padding)
1985
1986
1986 def pcfmt(value, total):
1987 def pcfmt(value, total):
1987 return (value, 100 * float(value) / total)
1988 return (value, 100 * float(value) / total)
1988
1989
1989 ui.write('format : %d\n' % format)
1990 ui.write('format : %d\n' % format)
1990 ui.write('flags : %s\n' % ', '.join(flags))
1991 ui.write('flags : %s\n' % ', '.join(flags))
1991
1992
1992 ui.write('\n')
1993 ui.write('\n')
1993 fmt = pcfmtstr(totalsize)
1994 fmt = pcfmtstr(totalsize)
1994 fmt2 = dfmtstr(totalsize)
1995 fmt2 = dfmtstr(totalsize)
1995 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1997 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1997 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1998 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1998 ui.write('revisions : ' + fmt2 % numrevs)
1999 ui.write('revisions : ' + fmt2 % numrevs)
1999 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2000 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2000 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2001 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2001 ui.write('revision size : ' + fmt2 % totalsize)
2002 ui.write('revision size : ' + fmt2 % totalsize)
2002 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2003 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2003 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2004 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2004
2005
2005 ui.write('\n')
2006 ui.write('\n')
2006 fmt = dfmtstr(max(avgchainlen, compratio))
2007 fmt = dfmtstr(max(avgchainlen, compratio))
2007 ui.write('avg chain length : ' + fmt % avgchainlen)
2008 ui.write('avg chain length : ' + fmt % avgchainlen)
2008 ui.write('compression ratio : ' + fmt % compratio)
2009 ui.write('compression ratio : ' + fmt % compratio)
2009
2010
2010 if format > 0:
2011 if format > 0:
2011 ui.write('\n')
2012 ui.write('\n')
2012 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2013 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2013 % tuple(datasize))
2014 % tuple(datasize))
2014 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2015 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2015 % tuple(fullsize))
2016 % tuple(fullsize))
2016 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2017 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2017 % tuple(deltasize))
2018 % tuple(deltasize))
2018
2019
2019 if numdeltas > 0:
2020 if numdeltas > 0:
2020 ui.write('\n')
2021 ui.write('\n')
2021 fmt = pcfmtstr(numdeltas)
2022 fmt = pcfmtstr(numdeltas)
2022 fmt2 = pcfmtstr(numdeltas, 4)
2023 fmt2 = pcfmtstr(numdeltas, 4)
2023 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2024 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2024 if numprev > 0:
2025 if numprev > 0:
2025 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2026 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2026 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2027 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2027 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2028 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2028 if gdelta:
2029 if gdelta:
2029 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2030 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2030 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2031 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2031 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2032 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2032
2033
2033 @command('debugrevspec', [], ('REVSPEC'))
2034 @command('debugrevspec', [], ('REVSPEC'))
2034 def debugrevspec(ui, repo, expr):
2035 def debugrevspec(ui, repo, expr):
2035 '''parse and apply a revision specification'''
2036 '''parse and apply a revision specification'''
2036 if ui.verbose:
2037 if ui.verbose:
2037 tree = revset.parse(expr)[0]
2038 tree = revset.parse(expr)[0]
2038 ui.note(tree, "\n")
2039 ui.note(tree, "\n")
2039 newtree = revset.findaliases(ui, tree)
2040 newtree = revset.findaliases(ui, tree)
2040 if newtree != tree:
2041 if newtree != tree:
2041 ui.note(newtree, "\n")
2042 ui.note(newtree, "\n")
2042 func = revset.match(ui, expr)
2043 func = revset.match(ui, expr)
2043 for c in func(repo, range(len(repo))):
2044 for c in func(repo, range(len(repo))):
2044 ui.write("%s\n" % c)
2045 ui.write("%s\n" % c)
2045
2046
2046 @command('debugsetparents', [], _('REV1 [REV2]'))
2047 @command('debugsetparents', [], _('REV1 [REV2]'))
2047 def debugsetparents(ui, repo, rev1, rev2=None):
2048 def debugsetparents(ui, repo, rev1, rev2=None):
2048 """manually set the parents of the current working directory
2049 """manually set the parents of the current working directory
2049
2050
2050 This is useful for writing repository conversion tools, but should
2051 This is useful for writing repository conversion tools, but should
2051 be used with care.
2052 be used with care.
2052
2053
2053 Returns 0 on success.
2054 Returns 0 on success.
2054 """
2055 """
2055
2056
2056 r1 = scmutil.revsingle(repo, rev1).node()
2057 r1 = scmutil.revsingle(repo, rev1).node()
2057 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2058 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2058
2059
2059 wlock = repo.wlock()
2060 wlock = repo.wlock()
2060 try:
2061 try:
2061 repo.dirstate.setparents(r1, r2)
2062 repo.dirstate.setparents(r1, r2)
2062 finally:
2063 finally:
2063 wlock.release()
2064 wlock.release()
2064
2065
2065 @command('debugstate',
2066 @command('debugstate',
2066 [('', 'nodates', None, _('do not display the saved mtime')),
2067 [('', 'nodates', None, _('do not display the saved mtime')),
2067 ('', 'datesort', None, _('sort by saved mtime'))],
2068 ('', 'datesort', None, _('sort by saved mtime'))],
2068 _('[OPTION]...'))
2069 _('[OPTION]...'))
2069 def debugstate(ui, repo, nodates=None, datesort=None):
2070 def debugstate(ui, repo, nodates=None, datesort=None):
2070 """show the contents of the current dirstate"""
2071 """show the contents of the current dirstate"""
2071 timestr = ""
2072 timestr = ""
2072 showdate = not nodates
2073 showdate = not nodates
2073 if datesort:
2074 if datesort:
2074 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2075 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2075 else:
2076 else:
2076 keyfunc = None # sort by filename
2077 keyfunc = None # sort by filename
2077 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2078 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2078 if showdate:
2079 if showdate:
2079 if ent[3] == -1:
2080 if ent[3] == -1:
2080 # Pad or slice to locale representation
2081 # Pad or slice to locale representation
2081 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2082 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2082 time.localtime(0)))
2083 time.localtime(0)))
2083 timestr = 'unset'
2084 timestr = 'unset'
2084 timestr = (timestr[:locale_len] +
2085 timestr = (timestr[:locale_len] +
2085 ' ' * (locale_len - len(timestr)))
2086 ' ' * (locale_len - len(timestr)))
2086 else:
2087 else:
2087 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2088 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2088 time.localtime(ent[3]))
2089 time.localtime(ent[3]))
2089 if ent[1] & 020000:
2090 if ent[1] & 020000:
2090 mode = 'lnk'
2091 mode = 'lnk'
2091 else:
2092 else:
2092 mode = '%3o' % (ent[1] & 0777)
2093 mode = '%3o' % (ent[1] & 0777)
2093 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2094 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2094 for f in repo.dirstate.copies():
2095 for f in repo.dirstate.copies():
2095 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2096 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2096
2097
2097 @command('debugsub',
2098 @command('debugsub',
2098 [('r', 'rev', '',
2099 [('r', 'rev', '',
2099 _('revision to check'), _('REV'))],
2100 _('revision to check'), _('REV'))],
2100 _('[-r REV] [REV]'))
2101 _('[-r REV] [REV]'))
2101 def debugsub(ui, repo, rev=None):
2102 def debugsub(ui, repo, rev=None):
2102 ctx = scmutil.revsingle(repo, rev, None)
2103 ctx = scmutil.revsingle(repo, rev, None)
2103 for k, v in sorted(ctx.substate.items()):
2104 for k, v in sorted(ctx.substate.items()):
2104 ui.write('path %s\n' % k)
2105 ui.write('path %s\n' % k)
2105 ui.write(' source %s\n' % v[0])
2106 ui.write(' source %s\n' % v[0])
2106 ui.write(' revision %s\n' % v[1])
2107 ui.write(' revision %s\n' % v[1])
2107
2108
2108 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2109 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2109 def debugwalk(ui, repo, *pats, **opts):
2110 def debugwalk(ui, repo, *pats, **opts):
2110 """show how files match on given patterns"""
2111 """show how files match on given patterns"""
2111 m = scmutil.match(repo[None], pats, opts)
2112 m = scmutil.match(repo[None], pats, opts)
2112 items = list(repo.walk(m))
2113 items = list(repo.walk(m))
2113 if not items:
2114 if not items:
2114 return
2115 return
2115 fmt = 'f %%-%ds %%-%ds %%s' % (
2116 fmt = 'f %%-%ds %%-%ds %%s' % (
2116 max([len(abs) for abs in items]),
2117 max([len(abs) for abs in items]),
2117 max([len(m.rel(abs)) for abs in items]))
2118 max([len(m.rel(abs)) for abs in items]))
2118 for abs in items:
2119 for abs in items:
2119 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2120 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2120 ui.write("%s\n" % line.rstrip())
2121 ui.write("%s\n" % line.rstrip())
2121
2122
2122 @command('debugwireargs',
2123 @command('debugwireargs',
2123 [('', 'three', '', 'three'),
2124 [('', 'three', '', 'three'),
2124 ('', 'four', '', 'four'),
2125 ('', 'four', '', 'four'),
2125 ('', 'five', '', 'five'),
2126 ('', 'five', '', 'five'),
2126 ] + remoteopts,
2127 ] + remoteopts,
2127 _('REPO [OPTIONS]... [ONE [TWO]]'))
2128 _('REPO [OPTIONS]... [ONE [TWO]]'))
2128 def debugwireargs(ui, repopath, *vals, **opts):
2129 def debugwireargs(ui, repopath, *vals, **opts):
2129 repo = hg.peer(ui, opts, repopath)
2130 repo = hg.peer(ui, opts, repopath)
2130 for opt in remoteopts:
2131 for opt in remoteopts:
2131 del opts[opt[1]]
2132 del opts[opt[1]]
2132 args = {}
2133 args = {}
2133 for k, v in opts.iteritems():
2134 for k, v in opts.iteritems():
2134 if v:
2135 if v:
2135 args[k] = v
2136 args[k] = v
2136 # run twice to check that we don't mess up the stream for the next command
2137 # run twice to check that we don't mess up the stream for the next command
2137 res1 = repo.debugwireargs(*vals, **args)
2138 res1 = repo.debugwireargs(*vals, **args)
2138 res2 = repo.debugwireargs(*vals, **args)
2139 res2 = repo.debugwireargs(*vals, **args)
2139 ui.write("%s\n" % res1)
2140 ui.write("%s\n" % res1)
2140 if res1 != res2:
2141 if res1 != res2:
2141 ui.warn("%s\n" % res2)
2142 ui.warn("%s\n" % res2)
2142
2143
2143 @command('^diff',
2144 @command('^diff',
2144 [('r', 'rev', [], _('revision'), _('REV')),
2145 [('r', 'rev', [], _('revision'), _('REV')),
2145 ('c', 'change', '', _('change made by revision'), _('REV'))
2146 ('c', 'change', '', _('change made by revision'), _('REV'))
2146 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2147 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2147 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2148 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2148 def diff(ui, repo, *pats, **opts):
2149 def diff(ui, repo, *pats, **opts):
2149 """diff repository (or selected files)
2150 """diff repository (or selected files)
2150
2151
2151 Show differences between revisions for the specified files.
2152 Show differences between revisions for the specified files.
2152
2153
2153 Differences between files are shown using the unified diff format.
2154 Differences between files are shown using the unified diff format.
2154
2155
2155 .. note::
2156 .. note::
2156 diff may generate unexpected results for merges, as it will
2157 diff may generate unexpected results for merges, as it will
2157 default to comparing against the working directory's first
2158 default to comparing against the working directory's first
2158 parent changeset if no revisions are specified.
2159 parent changeset if no revisions are specified.
2159
2160
2160 When two revision arguments are given, then changes are shown
2161 When two revision arguments are given, then changes are shown
2161 between those revisions. If only one revision is specified then
2162 between those revisions. If only one revision is specified then
2162 that revision is compared to the working directory, and, when no
2163 that revision is compared to the working directory, and, when no
2163 revisions are specified, the working directory files are compared
2164 revisions are specified, the working directory files are compared
2164 to its parent.
2165 to its parent.
2165
2166
2166 Alternatively you can specify -c/--change with a revision to see
2167 Alternatively you can specify -c/--change with a revision to see
2167 the changes in that changeset relative to its first parent.
2168 the changes in that changeset relative to its first parent.
2168
2169
2169 Without the -a/--text option, diff will avoid generating diffs of
2170 Without the -a/--text option, diff will avoid generating diffs of
2170 files it detects as binary. With -a, diff will generate a diff
2171 files it detects as binary. With -a, diff will generate a diff
2171 anyway, probably with undesirable results.
2172 anyway, probably with undesirable results.
2172
2173
2173 Use the -g/--git option to generate diffs in the git extended diff
2174 Use the -g/--git option to generate diffs in the git extended diff
2174 format. For more information, read :hg:`help diffs`.
2175 format. For more information, read :hg:`help diffs`.
2175
2176
2176 Returns 0 on success.
2177 Returns 0 on success.
2177 """
2178 """
2178
2179
2179 revs = opts.get('rev')
2180 revs = opts.get('rev')
2180 change = opts.get('change')
2181 change = opts.get('change')
2181 stat = opts.get('stat')
2182 stat = opts.get('stat')
2182 reverse = opts.get('reverse')
2183 reverse = opts.get('reverse')
2183
2184
2184 if revs and change:
2185 if revs and change:
2185 msg = _('cannot specify --rev and --change at the same time')
2186 msg = _('cannot specify --rev and --change at the same time')
2186 raise util.Abort(msg)
2187 raise util.Abort(msg)
2187 elif change:
2188 elif change:
2188 node2 = scmutil.revsingle(repo, change, None).node()
2189 node2 = scmutil.revsingle(repo, change, None).node()
2189 node1 = repo[node2].p1().node()
2190 node1 = repo[node2].p1().node()
2190 else:
2191 else:
2191 node1, node2 = scmutil.revpair(repo, revs)
2192 node1, node2 = scmutil.revpair(repo, revs)
2192
2193
2193 if reverse:
2194 if reverse:
2194 node1, node2 = node2, node1
2195 node1, node2 = node2, node1
2195
2196
2196 diffopts = patch.diffopts(ui, opts)
2197 diffopts = patch.diffopts(ui, opts)
2197 m = scmutil.match(repo[node2], pats, opts)
2198 m = scmutil.match(repo[node2], pats, opts)
2198 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2199 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2199 listsubrepos=opts.get('subrepos'))
2200 listsubrepos=opts.get('subrepos'))
2200
2201
2201 @command('^export',
2202 @command('^export',
2202 [('o', 'output', '',
2203 [('o', 'output', '',
2203 _('print output to file with formatted name'), _('FORMAT')),
2204 _('print output to file with formatted name'), _('FORMAT')),
2204 ('', 'switch-parent', None, _('diff against the second parent')),
2205 ('', 'switch-parent', None, _('diff against the second parent')),
2205 ('r', 'rev', [], _('revisions to export'), _('REV')),
2206 ('r', 'rev', [], _('revisions to export'), _('REV')),
2206 ] + diffopts,
2207 ] + diffopts,
2207 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2208 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2208 def export(ui, repo, *changesets, **opts):
2209 def export(ui, repo, *changesets, **opts):
2209 """dump the header and diffs for one or more changesets
2210 """dump the header and diffs for one or more changesets
2210
2211
2211 Print the changeset header and diffs for one or more revisions.
2212 Print the changeset header and diffs for one or more revisions.
2212
2213
2213 The information shown in the changeset header is: author, date,
2214 The information shown in the changeset header is: author, date,
2214 branch name (if non-default), changeset hash, parent(s) and commit
2215 branch name (if non-default), changeset hash, parent(s) and commit
2215 comment.
2216 comment.
2216
2217
2217 .. note::
2218 .. note::
2218 export may generate unexpected diff output for merge
2219 export may generate unexpected diff output for merge
2219 changesets, as it will compare the merge changeset against its
2220 changesets, as it will compare the merge changeset against its
2220 first parent only.
2221 first parent only.
2221
2222
2222 Output may be to a file, in which case the name of the file is
2223 Output may be to a file, in which case the name of the file is
2223 given using a format string. The formatting rules are as follows:
2224 given using a format string. The formatting rules are as follows:
2224
2225
2225 :``%%``: literal "%" character
2226 :``%%``: literal "%" character
2226 :``%H``: changeset hash (40 hexadecimal digits)
2227 :``%H``: changeset hash (40 hexadecimal digits)
2227 :``%N``: number of patches being generated
2228 :``%N``: number of patches being generated
2228 :``%R``: changeset revision number
2229 :``%R``: changeset revision number
2229 :``%b``: basename of the exporting repository
2230 :``%b``: basename of the exporting repository
2230 :``%h``: short-form changeset hash (12 hexadecimal digits)
2231 :``%h``: short-form changeset hash (12 hexadecimal digits)
2231 :``%n``: zero-padded sequence number, starting at 1
2232 :``%n``: zero-padded sequence number, starting at 1
2232 :``%r``: zero-padded changeset revision number
2233 :``%r``: zero-padded changeset revision number
2233
2234
2234 Without the -a/--text option, export will avoid generating diffs
2235 Without the -a/--text option, export will avoid generating diffs
2235 of files it detects as binary. With -a, export will generate a
2236 of files it detects as binary. With -a, export will generate a
2236 diff anyway, probably with undesirable results.
2237 diff anyway, probably with undesirable results.
2237
2238
2238 Use the -g/--git option to generate diffs in the git extended diff
2239 Use the -g/--git option to generate diffs in the git extended diff
2239 format. See :hg:`help diffs` for more information.
2240 format. See :hg:`help diffs` for more information.
2240
2241
2241 With the --switch-parent option, the diff will be against the
2242 With the --switch-parent option, the diff will be against the
2242 second parent. It can be useful to review a merge.
2243 second parent. It can be useful to review a merge.
2243
2244
2244 Returns 0 on success.
2245 Returns 0 on success.
2245 """
2246 """
2246 changesets += tuple(opts.get('rev', []))
2247 changesets += tuple(opts.get('rev', []))
2247 if not changesets:
2248 if not changesets:
2248 raise util.Abort(_("export requires at least one changeset"))
2249 raise util.Abort(_("export requires at least one changeset"))
2249 revs = scmutil.revrange(repo, changesets)
2250 revs = scmutil.revrange(repo, changesets)
2250 if len(revs) > 1:
2251 if len(revs) > 1:
2251 ui.note(_('exporting patches:\n'))
2252 ui.note(_('exporting patches:\n'))
2252 else:
2253 else:
2253 ui.note(_('exporting patch:\n'))
2254 ui.note(_('exporting patch:\n'))
2254 cmdutil.export(repo, revs, template=opts.get('output'),
2255 cmdutil.export(repo, revs, template=opts.get('output'),
2255 switch_parent=opts.get('switch_parent'),
2256 switch_parent=opts.get('switch_parent'),
2256 opts=patch.diffopts(ui, opts))
2257 opts=patch.diffopts(ui, opts))
2257
2258
2258 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2259 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2259 def forget(ui, repo, *pats, **opts):
2260 def forget(ui, repo, *pats, **opts):
2260 """forget the specified files on the next commit
2261 """forget the specified files on the next commit
2261
2262
2262 Mark the specified files so they will no longer be tracked
2263 Mark the specified files so they will no longer be tracked
2263 after the next commit.
2264 after the next commit.
2264
2265
2265 This only removes files from the current branch, not from the
2266 This only removes files from the current branch, not from the
2266 entire project history, and it does not delete them from the
2267 entire project history, and it does not delete them from the
2267 working directory.
2268 working directory.
2268
2269
2269 To undo a forget before the next commit, see :hg:`add`.
2270 To undo a forget before the next commit, see :hg:`add`.
2270
2271
2271 Returns 0 on success.
2272 Returns 0 on success.
2272 """
2273 """
2273
2274
2274 if not pats:
2275 if not pats:
2275 raise util.Abort(_('no files specified'))
2276 raise util.Abort(_('no files specified'))
2276
2277
2277 m = scmutil.match(repo[None], pats, opts)
2278 m = scmutil.match(repo[None], pats, opts)
2278 s = repo.status(match=m, clean=True)
2279 s = repo.status(match=m, clean=True)
2279 forget = sorted(s[0] + s[1] + s[3] + s[6])
2280 forget = sorted(s[0] + s[1] + s[3] + s[6])
2280 errs = 0
2281 errs = 0
2281
2282
2282 for f in m.files():
2283 for f in m.files():
2283 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2284 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2284 if os.path.exists(m.rel(f)):
2285 if os.path.exists(m.rel(f)):
2285 ui.warn(_('not removing %s: file is already untracked\n')
2286 ui.warn(_('not removing %s: file is already untracked\n')
2286 % m.rel(f))
2287 % m.rel(f))
2287 errs = 1
2288 errs = 1
2288
2289
2289 for f in forget:
2290 for f in forget:
2290 if ui.verbose or not m.exact(f):
2291 if ui.verbose or not m.exact(f):
2291 ui.status(_('removing %s\n') % m.rel(f))
2292 ui.status(_('removing %s\n') % m.rel(f))
2292
2293
2293 repo[None].forget(forget)
2294 repo[None].forget(forget)
2294 return errs
2295 return errs
2295
2296
2296 @command('grep',
2297 @command('grep',
2297 [('0', 'print0', None, _('end fields with NUL')),
2298 [('0', 'print0', None, _('end fields with NUL')),
2298 ('', 'all', None, _('print all revisions that match')),
2299 ('', 'all', None, _('print all revisions that match')),
2299 ('a', 'text', None, _('treat all files as text')),
2300 ('a', 'text', None, _('treat all files as text')),
2300 ('f', 'follow', None,
2301 ('f', 'follow', None,
2301 _('follow changeset history,'
2302 _('follow changeset history,'
2302 ' or file history across copies and renames')),
2303 ' or file history across copies and renames')),
2303 ('i', 'ignore-case', None, _('ignore case when matching')),
2304 ('i', 'ignore-case', None, _('ignore case when matching')),
2304 ('l', 'files-with-matches', None,
2305 ('l', 'files-with-matches', None,
2305 _('print only filenames and revisions that match')),
2306 _('print only filenames and revisions that match')),
2306 ('n', 'line-number', None, _('print matching line numbers')),
2307 ('n', 'line-number', None, _('print matching line numbers')),
2307 ('r', 'rev', [],
2308 ('r', 'rev', [],
2308 _('only search files changed within revision range'), _('REV')),
2309 _('only search files changed within revision range'), _('REV')),
2309 ('u', 'user', None, _('list the author (long with -v)')),
2310 ('u', 'user', None, _('list the author (long with -v)')),
2310 ('d', 'date', None, _('list the date (short with -q)')),
2311 ('d', 'date', None, _('list the date (short with -q)')),
2311 ] + walkopts,
2312 ] + walkopts,
2312 _('[OPTION]... PATTERN [FILE]...'))
2313 _('[OPTION]... PATTERN [FILE]...'))
2313 def grep(ui, repo, pattern, *pats, **opts):
2314 def grep(ui, repo, pattern, *pats, **opts):
2314 """search for a pattern in specified files and revisions
2315 """search for a pattern in specified files and revisions
2315
2316
2316 Search revisions of files for a regular expression.
2317 Search revisions of files for a regular expression.
2317
2318
2318 This command behaves differently than Unix grep. It only accepts
2319 This command behaves differently than Unix grep. It only accepts
2319 Python/Perl regexps. It searches repository history, not the
2320 Python/Perl regexps. It searches repository history, not the
2320 working directory. It always prints the revision number in which a
2321 working directory. It always prints the revision number in which a
2321 match appears.
2322 match appears.
2322
2323
2323 By default, grep only prints output for the first revision of a
2324 By default, grep only prints output for the first revision of a
2324 file in which it finds a match. To get it to print every revision
2325 file in which it finds a match. To get it to print every revision
2325 that contains a change in match status ("-" for a match that
2326 that contains a change in match status ("-" for a match that
2326 becomes a non-match, or "+" for a non-match that becomes a match),
2327 becomes a non-match, or "+" for a non-match that becomes a match),
2327 use the --all flag.
2328 use the --all flag.
2328
2329
2329 Returns 0 if a match is found, 1 otherwise.
2330 Returns 0 if a match is found, 1 otherwise.
2330 """
2331 """
2331 reflags = 0
2332 reflags = 0
2332 if opts.get('ignore_case'):
2333 if opts.get('ignore_case'):
2333 reflags |= re.I
2334 reflags |= re.I
2334 try:
2335 try:
2335 regexp = re.compile(pattern, reflags)
2336 regexp = re.compile(pattern, reflags)
2336 except re.error, inst:
2337 except re.error, inst:
2337 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2338 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2338 return 1
2339 return 1
2339 sep, eol = ':', '\n'
2340 sep, eol = ':', '\n'
2340 if opts.get('print0'):
2341 if opts.get('print0'):
2341 sep = eol = '\0'
2342 sep = eol = '\0'
2342
2343
2343 getfile = util.lrucachefunc(repo.file)
2344 getfile = util.lrucachefunc(repo.file)
2344
2345
2345 def matchlines(body):
2346 def matchlines(body):
2346 begin = 0
2347 begin = 0
2347 linenum = 0
2348 linenum = 0
2348 while True:
2349 while True:
2349 match = regexp.search(body, begin)
2350 match = regexp.search(body, begin)
2350 if not match:
2351 if not match:
2351 break
2352 break
2352 mstart, mend = match.span()
2353 mstart, mend = match.span()
2353 linenum += body.count('\n', begin, mstart) + 1
2354 linenum += body.count('\n', begin, mstart) + 1
2354 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2355 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2355 begin = body.find('\n', mend) + 1 or len(body)
2356 begin = body.find('\n', mend) + 1 or len(body)
2356 lend = begin - 1
2357 lend = begin - 1
2357 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2358 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2358
2359
2359 class linestate(object):
2360 class linestate(object):
2360 def __init__(self, line, linenum, colstart, colend):
2361 def __init__(self, line, linenum, colstart, colend):
2361 self.line = line
2362 self.line = line
2362 self.linenum = linenum
2363 self.linenum = linenum
2363 self.colstart = colstart
2364 self.colstart = colstart
2364 self.colend = colend
2365 self.colend = colend
2365
2366
2366 def __hash__(self):
2367 def __hash__(self):
2367 return hash((self.linenum, self.line))
2368 return hash((self.linenum, self.line))
2368
2369
2369 def __eq__(self, other):
2370 def __eq__(self, other):
2370 return self.line == other.line
2371 return self.line == other.line
2371
2372
2372 matches = {}
2373 matches = {}
2373 copies = {}
2374 copies = {}
2374 def grepbody(fn, rev, body):
2375 def grepbody(fn, rev, body):
2375 matches[rev].setdefault(fn, [])
2376 matches[rev].setdefault(fn, [])
2376 m = matches[rev][fn]
2377 m = matches[rev][fn]
2377 for lnum, cstart, cend, line in matchlines(body):
2378 for lnum, cstart, cend, line in matchlines(body):
2378 s = linestate(line, lnum, cstart, cend)
2379 s = linestate(line, lnum, cstart, cend)
2379 m.append(s)
2380 m.append(s)
2380
2381
2381 def difflinestates(a, b):
2382 def difflinestates(a, b):
2382 sm = difflib.SequenceMatcher(None, a, b)
2383 sm = difflib.SequenceMatcher(None, a, b)
2383 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2384 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2384 if tag == 'insert':
2385 if tag == 'insert':
2385 for i in xrange(blo, bhi):
2386 for i in xrange(blo, bhi):
2386 yield ('+', b[i])
2387 yield ('+', b[i])
2387 elif tag == 'delete':
2388 elif tag == 'delete':
2388 for i in xrange(alo, ahi):
2389 for i in xrange(alo, ahi):
2389 yield ('-', a[i])
2390 yield ('-', a[i])
2390 elif tag == 'replace':
2391 elif tag == 'replace':
2391 for i in xrange(alo, ahi):
2392 for i in xrange(alo, ahi):
2392 yield ('-', a[i])
2393 yield ('-', a[i])
2393 for i in xrange(blo, bhi):
2394 for i in xrange(blo, bhi):
2394 yield ('+', b[i])
2395 yield ('+', b[i])
2395
2396
2396 def display(fn, ctx, pstates, states):
2397 def display(fn, ctx, pstates, states):
2397 rev = ctx.rev()
2398 rev = ctx.rev()
2398 datefunc = ui.quiet and util.shortdate or util.datestr
2399 datefunc = ui.quiet and util.shortdate or util.datestr
2399 found = False
2400 found = False
2400 filerevmatches = {}
2401 filerevmatches = {}
2401 def binary():
2402 def binary():
2402 flog = getfile(fn)
2403 flog = getfile(fn)
2403 return util.binary(flog.read(ctx.filenode(fn)))
2404 return util.binary(flog.read(ctx.filenode(fn)))
2404
2405
2405 if opts.get('all'):
2406 if opts.get('all'):
2406 iter = difflinestates(pstates, states)
2407 iter = difflinestates(pstates, states)
2407 else:
2408 else:
2408 iter = [('', l) for l in states]
2409 iter = [('', l) for l in states]
2409 for change, l in iter:
2410 for change, l in iter:
2410 cols = [fn, str(rev)]
2411 cols = [fn, str(rev)]
2411 before, match, after = None, None, None
2412 before, match, after = None, None, None
2412 if opts.get('line_number'):
2413 if opts.get('line_number'):
2413 cols.append(str(l.linenum))
2414 cols.append(str(l.linenum))
2414 if opts.get('all'):
2415 if opts.get('all'):
2415 cols.append(change)
2416 cols.append(change)
2416 if opts.get('user'):
2417 if opts.get('user'):
2417 cols.append(ui.shortuser(ctx.user()))
2418 cols.append(ui.shortuser(ctx.user()))
2418 if opts.get('date'):
2419 if opts.get('date'):
2419 cols.append(datefunc(ctx.date()))
2420 cols.append(datefunc(ctx.date()))
2420 if opts.get('files_with_matches'):
2421 if opts.get('files_with_matches'):
2421 c = (fn, rev)
2422 c = (fn, rev)
2422 if c in filerevmatches:
2423 if c in filerevmatches:
2423 continue
2424 continue
2424 filerevmatches[c] = 1
2425 filerevmatches[c] = 1
2425 else:
2426 else:
2426 before = l.line[:l.colstart]
2427 before = l.line[:l.colstart]
2427 match = l.line[l.colstart:l.colend]
2428 match = l.line[l.colstart:l.colend]
2428 after = l.line[l.colend:]
2429 after = l.line[l.colend:]
2429 ui.write(sep.join(cols))
2430 ui.write(sep.join(cols))
2430 if before is not None:
2431 if before is not None:
2431 if not opts.get('text') and binary():
2432 if not opts.get('text') and binary():
2432 ui.write(sep + " Binary file matches")
2433 ui.write(sep + " Binary file matches")
2433 else:
2434 else:
2434 ui.write(sep + before)
2435 ui.write(sep + before)
2435 ui.write(match, label='grep.match')
2436 ui.write(match, label='grep.match')
2436 ui.write(after)
2437 ui.write(after)
2437 ui.write(eol)
2438 ui.write(eol)
2438 found = True
2439 found = True
2439 return found
2440 return found
2440
2441
2441 skip = {}
2442 skip = {}
2442 revfiles = {}
2443 revfiles = {}
2443 matchfn = scmutil.match(repo[None], pats, opts)
2444 matchfn = scmutil.match(repo[None], pats, opts)
2444 found = False
2445 found = False
2445 follow = opts.get('follow')
2446 follow = opts.get('follow')
2446
2447
2447 def prep(ctx, fns):
2448 def prep(ctx, fns):
2448 rev = ctx.rev()
2449 rev = ctx.rev()
2449 pctx = ctx.p1()
2450 pctx = ctx.p1()
2450 parent = pctx.rev()
2451 parent = pctx.rev()
2451 matches.setdefault(rev, {})
2452 matches.setdefault(rev, {})
2452 matches.setdefault(parent, {})
2453 matches.setdefault(parent, {})
2453 files = revfiles.setdefault(rev, [])
2454 files = revfiles.setdefault(rev, [])
2454 for fn in fns:
2455 for fn in fns:
2455 flog = getfile(fn)
2456 flog = getfile(fn)
2456 try:
2457 try:
2457 fnode = ctx.filenode(fn)
2458 fnode = ctx.filenode(fn)
2458 except error.LookupError:
2459 except error.LookupError:
2459 continue
2460 continue
2460
2461
2461 copied = flog.renamed(fnode)
2462 copied = flog.renamed(fnode)
2462 copy = follow and copied and copied[0]
2463 copy = follow and copied and copied[0]
2463 if copy:
2464 if copy:
2464 copies.setdefault(rev, {})[fn] = copy
2465 copies.setdefault(rev, {})[fn] = copy
2465 if fn in skip:
2466 if fn in skip:
2466 if copy:
2467 if copy:
2467 skip[copy] = True
2468 skip[copy] = True
2468 continue
2469 continue
2469 files.append(fn)
2470 files.append(fn)
2470
2471
2471 if fn not in matches[rev]:
2472 if fn not in matches[rev]:
2472 grepbody(fn, rev, flog.read(fnode))
2473 grepbody(fn, rev, flog.read(fnode))
2473
2474
2474 pfn = copy or fn
2475 pfn = copy or fn
2475 if pfn not in matches[parent]:
2476 if pfn not in matches[parent]:
2476 try:
2477 try:
2477 fnode = pctx.filenode(pfn)
2478 fnode = pctx.filenode(pfn)
2478 grepbody(pfn, parent, flog.read(fnode))
2479 grepbody(pfn, parent, flog.read(fnode))
2479 except error.LookupError:
2480 except error.LookupError:
2480 pass
2481 pass
2481
2482
2482 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2483 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2483 rev = ctx.rev()
2484 rev = ctx.rev()
2484 parent = ctx.p1().rev()
2485 parent = ctx.p1().rev()
2485 for fn in sorted(revfiles.get(rev, [])):
2486 for fn in sorted(revfiles.get(rev, [])):
2486 states = matches[rev][fn]
2487 states = matches[rev][fn]
2487 copy = copies.get(rev, {}).get(fn)
2488 copy = copies.get(rev, {}).get(fn)
2488 if fn in skip:
2489 if fn in skip:
2489 if copy:
2490 if copy:
2490 skip[copy] = True
2491 skip[copy] = True
2491 continue
2492 continue
2492 pstates = matches.get(parent, {}).get(copy or fn, [])
2493 pstates = matches.get(parent, {}).get(copy or fn, [])
2493 if pstates or states:
2494 if pstates or states:
2494 r = display(fn, ctx, pstates, states)
2495 r = display(fn, ctx, pstates, states)
2495 found = found or r
2496 found = found or r
2496 if r and not opts.get('all'):
2497 if r and not opts.get('all'):
2497 skip[fn] = True
2498 skip[fn] = True
2498 if copy:
2499 if copy:
2499 skip[copy] = True
2500 skip[copy] = True
2500 del matches[rev]
2501 del matches[rev]
2501 del revfiles[rev]
2502 del revfiles[rev]
2502
2503
2503 return not found
2504 return not found
2504
2505
2505 @command('heads',
2506 @command('heads',
2506 [('r', 'rev', '',
2507 [('r', 'rev', '',
2507 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2508 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2508 ('t', 'topo', False, _('show topological heads only')),
2509 ('t', 'topo', False, _('show topological heads only')),
2509 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2510 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2510 ('c', 'closed', False, _('show normal and closed branch heads')),
2511 ('c', 'closed', False, _('show normal and closed branch heads')),
2511 ] + templateopts,
2512 ] + templateopts,
2512 _('[-ac] [-r STARTREV] [REV]...'))
2513 _('[-ac] [-r STARTREV] [REV]...'))
2513 def heads(ui, repo, *branchrevs, **opts):
2514 def heads(ui, repo, *branchrevs, **opts):
2514 """show current repository heads or show branch heads
2515 """show current repository heads or show branch heads
2515
2516
2516 With no arguments, show all repository branch heads.
2517 With no arguments, show all repository branch heads.
2517
2518
2518 Repository "heads" are changesets with no child changesets. They are
2519 Repository "heads" are changesets with no child changesets. They are
2519 where development generally takes place and are the usual targets
2520 where development generally takes place and are the usual targets
2520 for update and merge operations. Branch heads are changesets that have
2521 for update and merge operations. Branch heads are changesets that have
2521 no child changeset on the same branch.
2522 no child changeset on the same branch.
2522
2523
2523 If one or more REVs are given, only branch heads on the branches
2524 If one or more REVs are given, only branch heads on the branches
2524 associated with the specified changesets are shown.
2525 associated with the specified changesets are shown.
2525
2526
2526 If -c/--closed is specified, also show branch heads marked closed
2527 If -c/--closed is specified, also show branch heads marked closed
2527 (see :hg:`commit --close-branch`).
2528 (see :hg:`commit --close-branch`).
2528
2529
2529 If STARTREV is specified, only those heads that are descendants of
2530 If STARTREV is specified, only those heads that are descendants of
2530 STARTREV will be displayed.
2531 STARTREV will be displayed.
2531
2532
2532 If -t/--topo is specified, named branch mechanics will be ignored and only
2533 If -t/--topo is specified, named branch mechanics will be ignored and only
2533 changesets without children will be shown.
2534 changesets without children will be shown.
2534
2535
2535 Returns 0 if matching heads are found, 1 if not.
2536 Returns 0 if matching heads are found, 1 if not.
2536 """
2537 """
2537
2538
2538 start = None
2539 start = None
2539 if 'rev' in opts:
2540 if 'rev' in opts:
2540 start = scmutil.revsingle(repo, opts['rev'], None).node()
2541 start = scmutil.revsingle(repo, opts['rev'], None).node()
2541
2542
2542 if opts.get('topo'):
2543 if opts.get('topo'):
2543 heads = [repo[h] for h in repo.heads(start)]
2544 heads = [repo[h] for h in repo.heads(start)]
2544 else:
2545 else:
2545 heads = []
2546 heads = []
2546 for branch in repo.branchmap():
2547 for branch in repo.branchmap():
2547 heads += repo.branchheads(branch, start, opts.get('closed'))
2548 heads += repo.branchheads(branch, start, opts.get('closed'))
2548 heads = [repo[h] for h in heads]
2549 heads = [repo[h] for h in heads]
2549
2550
2550 if branchrevs:
2551 if branchrevs:
2551 branches = set(repo[br].branch() for br in branchrevs)
2552 branches = set(repo[br].branch() for br in branchrevs)
2552 heads = [h for h in heads if h.branch() in branches]
2553 heads = [h for h in heads if h.branch() in branches]
2553
2554
2554 if opts.get('active') and branchrevs:
2555 if opts.get('active') and branchrevs:
2555 dagheads = repo.heads(start)
2556 dagheads = repo.heads(start)
2556 heads = [h for h in heads if h.node() in dagheads]
2557 heads = [h for h in heads if h.node() in dagheads]
2557
2558
2558 if branchrevs:
2559 if branchrevs:
2559 haveheads = set(h.branch() for h in heads)
2560 haveheads = set(h.branch() for h in heads)
2560 if branches - haveheads:
2561 if branches - haveheads:
2561 headless = ', '.join(b for b in branches - haveheads)
2562 headless = ', '.join(b for b in branches - haveheads)
2562 msg = _('no open branch heads found on branches %s')
2563 msg = _('no open branch heads found on branches %s')
2563 if opts.get('rev'):
2564 if opts.get('rev'):
2564 msg += _(' (started at %s)' % opts['rev'])
2565 msg += _(' (started at %s)' % opts['rev'])
2565 ui.warn((msg + '\n') % headless)
2566 ui.warn((msg + '\n') % headless)
2566
2567
2567 if not heads:
2568 if not heads:
2568 return 1
2569 return 1
2569
2570
2570 heads = sorted(heads, key=lambda x: -x.rev())
2571 heads = sorted(heads, key=lambda x: -x.rev())
2571 displayer = cmdutil.show_changeset(ui, repo, opts)
2572 displayer = cmdutil.show_changeset(ui, repo, opts)
2572 for ctx in heads:
2573 for ctx in heads:
2573 displayer.show(ctx)
2574 displayer.show(ctx)
2574 displayer.close()
2575 displayer.close()
2575
2576
2576 @command('help',
2577 @command('help',
2577 [('e', 'extension', None, _('show only help for extensions')),
2578 [('e', 'extension', None, _('show only help for extensions')),
2578 ('c', 'command', None, _('show only help for commands'))],
2579 ('c', 'command', None, _('show only help for commands'))],
2579 _('[-ec] [TOPIC]'))
2580 _('[-ec] [TOPIC]'))
2580 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2581 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2581 """show help for a given topic or a help overview
2582 """show help for a given topic or a help overview
2582
2583
2583 With no arguments, print a list of commands with short help messages.
2584 With no arguments, print a list of commands with short help messages.
2584
2585
2585 Given a topic, extension, or command name, print help for that
2586 Given a topic, extension, or command name, print help for that
2586 topic.
2587 topic.
2587
2588
2588 Returns 0 if successful.
2589 Returns 0 if successful.
2589 """
2590 """
2590 option_lists = []
2591 option_lists = []
2591 textwidth = min(ui.termwidth(), 80) - 2
2592 textwidth = min(ui.termwidth(), 80) - 2
2592
2593
2593 def addglobalopts(aliases):
2594 def addglobalopts(aliases):
2594 if ui.verbose:
2595 if ui.verbose:
2595 option_lists.append((_("global options:"), globalopts))
2596 option_lists.append((_("global options:"), globalopts))
2596 if name == 'shortlist':
2597 if name == 'shortlist':
2597 option_lists.append((_('use "hg help" for the full list '
2598 option_lists.append((_('use "hg help" for the full list '
2598 'of commands'), ()))
2599 'of commands'), ()))
2599 else:
2600 else:
2600 if name == 'shortlist':
2601 if name == 'shortlist':
2601 msg = _('use "hg help" for the full list of commands '
2602 msg = _('use "hg help" for the full list of commands '
2602 'or "hg -v" for details')
2603 'or "hg -v" for details')
2603 elif name and not full:
2604 elif name and not full:
2604 msg = _('use "hg help %s" to show the full help text' % name)
2605 msg = _('use "hg help %s" to show the full help text' % name)
2605 elif aliases:
2606 elif aliases:
2606 msg = _('use "hg -v help%s" to show builtin aliases and '
2607 msg = _('use "hg -v help%s" to show builtin aliases and '
2607 'global options') % (name and " " + name or "")
2608 'global options') % (name and " " + name or "")
2608 else:
2609 else:
2609 msg = _('use "hg -v help %s" to show global options') % name
2610 msg = _('use "hg -v help %s" to show global options') % name
2610 option_lists.append((msg, ()))
2611 option_lists.append((msg, ()))
2611
2612
2612 def helpcmd(name):
2613 def helpcmd(name):
2613 if with_version:
2614 if with_version:
2614 version_(ui)
2615 version_(ui)
2615 ui.write('\n')
2616 ui.write('\n')
2616
2617
2617 try:
2618 try:
2618 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2619 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2619 except error.AmbiguousCommand, inst:
2620 except error.AmbiguousCommand, inst:
2620 # py3k fix: except vars can't be used outside the scope of the
2621 # py3k fix: except vars can't be used outside the scope of the
2621 # except block, nor can be used inside a lambda. python issue4617
2622 # except block, nor can be used inside a lambda. python issue4617
2622 prefix = inst.args[0]
2623 prefix = inst.args[0]
2623 select = lambda c: c.lstrip('^').startswith(prefix)
2624 select = lambda c: c.lstrip('^').startswith(prefix)
2624 helplist(_('list of commands:\n\n'), select)
2625 helplist(_('list of commands:\n\n'), select)
2625 return
2626 return
2626
2627
2627 # check if it's an invalid alias and display its error if it is
2628 # check if it's an invalid alias and display its error if it is
2628 if getattr(entry[0], 'badalias', False):
2629 if getattr(entry[0], 'badalias', False):
2629 if not unknowncmd:
2630 if not unknowncmd:
2630 entry[0](ui)
2631 entry[0](ui)
2631 return
2632 return
2632
2633
2633 # synopsis
2634 # synopsis
2634 if len(entry) > 2:
2635 if len(entry) > 2:
2635 if entry[2].startswith('hg'):
2636 if entry[2].startswith('hg'):
2636 ui.write("%s\n" % entry[2])
2637 ui.write("%s\n" % entry[2])
2637 else:
2638 else:
2638 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2639 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2639 else:
2640 else:
2640 ui.write('hg %s\n' % aliases[0])
2641 ui.write('hg %s\n' % aliases[0])
2641
2642
2642 # aliases
2643 # aliases
2643 if full and not ui.quiet and len(aliases) > 1:
2644 if full and not ui.quiet and len(aliases) > 1:
2644 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2645 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2645
2646
2646 # description
2647 # description
2647 doc = gettext(entry[0].__doc__)
2648 doc = gettext(entry[0].__doc__)
2648 if not doc:
2649 if not doc:
2649 doc = _("(no help text available)")
2650 doc = _("(no help text available)")
2650 if hasattr(entry[0], 'definition'): # aliased command
2651 if hasattr(entry[0], 'definition'): # aliased command
2651 if entry[0].definition.startswith('!'): # shell alias
2652 if entry[0].definition.startswith('!'): # shell alias
2652 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2653 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2653 else:
2654 else:
2654 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2655 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2655 if ui.quiet or not full:
2656 if ui.quiet or not full:
2656 doc = doc.splitlines()[0]
2657 doc = doc.splitlines()[0]
2657 keep = ui.verbose and ['verbose'] or []
2658 keep = ui.verbose and ['verbose'] or []
2658 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2659 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2659 ui.write("\n%s\n" % formatted)
2660 ui.write("\n%s\n" % formatted)
2660 if pruned:
2661 if pruned:
2661 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2662 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2662
2663
2663 if not ui.quiet:
2664 if not ui.quiet:
2664 # options
2665 # options
2665 if entry[1]:
2666 if entry[1]:
2666 option_lists.append((_("options:\n"), entry[1]))
2667 option_lists.append((_("options:\n"), entry[1]))
2667
2668
2668 addglobalopts(False)
2669 addglobalopts(False)
2669
2670
2670 # check if this command shadows a non-trivial (multi-line)
2671 # check if this command shadows a non-trivial (multi-line)
2671 # extension help text
2672 # extension help text
2672 try:
2673 try:
2673 mod = extensions.find(name)
2674 mod = extensions.find(name)
2674 doc = gettext(mod.__doc__) or ''
2675 doc = gettext(mod.__doc__) or ''
2675 if '\n' in doc.strip():
2676 if '\n' in doc.strip():
2676 msg = _('use "hg help -e %s" to show help for '
2677 msg = _('use "hg help -e %s" to show help for '
2677 'the %s extension') % (name, name)
2678 'the %s extension') % (name, name)
2678 ui.write('\n%s\n' % msg)
2679 ui.write('\n%s\n' % msg)
2679 except KeyError:
2680 except KeyError:
2680 pass
2681 pass
2681
2682
2682 def helplist(header, select=None):
2683 def helplist(header, select=None):
2683 h = {}
2684 h = {}
2684 cmds = {}
2685 cmds = {}
2685 for c, e in table.iteritems():
2686 for c, e in table.iteritems():
2686 f = c.split("|", 1)[0]
2687 f = c.split("|", 1)[0]
2687 if select and not select(f):
2688 if select and not select(f):
2688 continue
2689 continue
2689 if (not select and name != 'shortlist' and
2690 if (not select and name != 'shortlist' and
2690 e[0].__module__ != __name__):
2691 e[0].__module__ != __name__):
2691 continue
2692 continue
2692 if name == "shortlist" and not f.startswith("^"):
2693 if name == "shortlist" and not f.startswith("^"):
2693 continue
2694 continue
2694 f = f.lstrip("^")
2695 f = f.lstrip("^")
2695 if not ui.debugflag and f.startswith("debug"):
2696 if not ui.debugflag and f.startswith("debug"):
2696 continue
2697 continue
2697 doc = e[0].__doc__
2698 doc = e[0].__doc__
2698 if doc and 'DEPRECATED' in doc and not ui.verbose:
2699 if doc and 'DEPRECATED' in doc and not ui.verbose:
2699 continue
2700 continue
2700 doc = gettext(doc)
2701 doc = gettext(doc)
2701 if not doc:
2702 if not doc:
2702 doc = _("(no help text available)")
2703 doc = _("(no help text available)")
2703 h[f] = doc.splitlines()[0].rstrip()
2704 h[f] = doc.splitlines()[0].rstrip()
2704 cmds[f] = c.lstrip("^")
2705 cmds[f] = c.lstrip("^")
2705
2706
2706 if not h:
2707 if not h:
2707 ui.status(_('no commands defined\n'))
2708 ui.status(_('no commands defined\n'))
2708 return
2709 return
2709
2710
2710 ui.status(header)
2711 ui.status(header)
2711 fns = sorted(h)
2712 fns = sorted(h)
2712 m = max(map(len, fns))
2713 m = max(map(len, fns))
2713 for f in fns:
2714 for f in fns:
2714 if ui.verbose:
2715 if ui.verbose:
2715 commands = cmds[f].replace("|",", ")
2716 commands = cmds[f].replace("|",", ")
2716 ui.write(" %s:\n %s\n"%(commands, h[f]))
2717 ui.write(" %s:\n %s\n"%(commands, h[f]))
2717 else:
2718 else:
2718 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2719 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2719 initindent=' %-*s ' % (m, f),
2720 initindent=' %-*s ' % (m, f),
2720 hangindent=' ' * (m + 4))))
2721 hangindent=' ' * (m + 4))))
2721
2722
2722 if not ui.quiet:
2723 if not ui.quiet:
2723 addglobalopts(True)
2724 addglobalopts(True)
2724
2725
2725 def helptopic(name):
2726 def helptopic(name):
2726 for names, header, doc in help.helptable:
2727 for names, header, doc in help.helptable:
2727 if name in names:
2728 if name in names:
2728 break
2729 break
2729 else:
2730 else:
2730 raise error.UnknownCommand(name)
2731 raise error.UnknownCommand(name)
2731
2732
2732 # description
2733 # description
2733 if not doc:
2734 if not doc:
2734 doc = _("(no help text available)")
2735 doc = _("(no help text available)")
2735 if util.safehasattr(doc, '__call__'):
2736 if util.safehasattr(doc, '__call__'):
2736 doc = doc()
2737 doc = doc()
2737
2738
2738 ui.write("%s\n\n" % header)
2739 ui.write("%s\n\n" % header)
2739 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2740 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2740 try:
2741 try:
2741 cmdutil.findcmd(name, table)
2742 cmdutil.findcmd(name, table)
2742 ui.write(_('\nuse "hg help -c %s" to see help for '
2743 ui.write(_('\nuse "hg help -c %s" to see help for '
2743 'the %s command\n') % (name, name))
2744 'the %s command\n') % (name, name))
2744 except error.UnknownCommand:
2745 except error.UnknownCommand:
2745 pass
2746 pass
2746
2747
2747 def helpext(name):
2748 def helpext(name):
2748 try:
2749 try:
2749 mod = extensions.find(name)
2750 mod = extensions.find(name)
2750 doc = gettext(mod.__doc__) or _('no help text available')
2751 doc = gettext(mod.__doc__) or _('no help text available')
2751 except KeyError:
2752 except KeyError:
2752 mod = None
2753 mod = None
2753 doc = extensions.disabledext(name)
2754 doc = extensions.disabledext(name)
2754 if not doc:
2755 if not doc:
2755 raise error.UnknownCommand(name)
2756 raise error.UnknownCommand(name)
2756
2757
2757 if '\n' not in doc:
2758 if '\n' not in doc:
2758 head, tail = doc, ""
2759 head, tail = doc, ""
2759 else:
2760 else:
2760 head, tail = doc.split('\n', 1)
2761 head, tail = doc.split('\n', 1)
2761 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2762 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2762 if tail:
2763 if tail:
2763 ui.write(minirst.format(tail, textwidth))
2764 ui.write(minirst.format(tail, textwidth))
2764 ui.status('\n\n')
2765 ui.status('\n\n')
2765
2766
2766 if mod:
2767 if mod:
2767 try:
2768 try:
2768 ct = mod.cmdtable
2769 ct = mod.cmdtable
2769 except AttributeError:
2770 except AttributeError:
2770 ct = {}
2771 ct = {}
2771 modcmds = set([c.split('|', 1)[0] for c in ct])
2772 modcmds = set([c.split('|', 1)[0] for c in ct])
2772 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2773 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2773 else:
2774 else:
2774 ui.write(_('use "hg help extensions" for information on enabling '
2775 ui.write(_('use "hg help extensions" for information on enabling '
2775 'extensions\n'))
2776 'extensions\n'))
2776
2777
2777 def helpextcmd(name):
2778 def helpextcmd(name):
2778 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2779 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2779 doc = gettext(mod.__doc__).splitlines()[0]
2780 doc = gettext(mod.__doc__).splitlines()[0]
2780
2781
2781 msg = help.listexts(_("'%s' is provided by the following "
2782 msg = help.listexts(_("'%s' is provided by the following "
2782 "extension:") % cmd, {ext: doc}, indent=4)
2783 "extension:") % cmd, {ext: doc}, indent=4)
2783 ui.write(minirst.format(msg, textwidth))
2784 ui.write(minirst.format(msg, textwidth))
2784 ui.write('\n\n')
2785 ui.write('\n\n')
2785 ui.write(_('use "hg help extensions" for information on enabling '
2786 ui.write(_('use "hg help extensions" for information on enabling '
2786 'extensions\n'))
2787 'extensions\n'))
2787
2788
2788 if name and name != 'shortlist':
2789 if name and name != 'shortlist':
2789 i = None
2790 i = None
2790 if unknowncmd:
2791 if unknowncmd:
2791 queries = (helpextcmd,)
2792 queries = (helpextcmd,)
2792 elif opts.get('extension'):
2793 elif opts.get('extension'):
2793 queries = (helpext,)
2794 queries = (helpext,)
2794 elif opts.get('command'):
2795 elif opts.get('command'):
2795 queries = (helpcmd,)
2796 queries = (helpcmd,)
2796 else:
2797 else:
2797 queries = (helptopic, helpcmd, helpext, helpextcmd)
2798 queries = (helptopic, helpcmd, helpext, helpextcmd)
2798 for f in queries:
2799 for f in queries:
2799 try:
2800 try:
2800 f(name)
2801 f(name)
2801 i = None
2802 i = None
2802 break
2803 break
2803 except error.UnknownCommand, inst:
2804 except error.UnknownCommand, inst:
2804 i = inst
2805 i = inst
2805 if i:
2806 if i:
2806 raise i
2807 raise i
2807
2808
2808 else:
2809 else:
2809 # program name
2810 # program name
2810 if ui.verbose or with_version:
2811 if ui.verbose or with_version:
2811 version_(ui)
2812 version_(ui)
2812 else:
2813 else:
2813 ui.status(_("Mercurial Distributed SCM\n"))
2814 ui.status(_("Mercurial Distributed SCM\n"))
2814 ui.status('\n')
2815 ui.status('\n')
2815
2816
2816 # list of commands
2817 # list of commands
2817 if name == "shortlist":
2818 if name == "shortlist":
2818 header = _('basic commands:\n\n')
2819 header = _('basic commands:\n\n')
2819 else:
2820 else:
2820 header = _('list of commands:\n\n')
2821 header = _('list of commands:\n\n')
2821
2822
2822 helplist(header)
2823 helplist(header)
2823 if name != 'shortlist':
2824 if name != 'shortlist':
2824 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2825 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2825 if text:
2826 if text:
2826 ui.write("\n%s\n" % minirst.format(text, textwidth))
2827 ui.write("\n%s\n" % minirst.format(text, textwidth))
2827
2828
2828 # list all option lists
2829 # list all option lists
2829 opt_output = []
2830 opt_output = []
2830 multioccur = False
2831 multioccur = False
2831 for title, options in option_lists:
2832 for title, options in option_lists:
2832 opt_output.append(("\n%s" % title, None))
2833 opt_output.append(("\n%s" % title, None))
2833 for option in options:
2834 for option in options:
2834 if len(option) == 5:
2835 if len(option) == 5:
2835 shortopt, longopt, default, desc, optlabel = option
2836 shortopt, longopt, default, desc, optlabel = option
2836 else:
2837 else:
2837 shortopt, longopt, default, desc = option
2838 shortopt, longopt, default, desc = option
2838 optlabel = _("VALUE") # default label
2839 optlabel = _("VALUE") # default label
2839
2840
2840 if _("DEPRECATED") in desc and not ui.verbose:
2841 if _("DEPRECATED") in desc and not ui.verbose:
2841 continue
2842 continue
2842 if isinstance(default, list):
2843 if isinstance(default, list):
2843 numqualifier = " %s [+]" % optlabel
2844 numqualifier = " %s [+]" % optlabel
2844 multioccur = True
2845 multioccur = True
2845 elif (default is not None) and not isinstance(default, bool):
2846 elif (default is not None) and not isinstance(default, bool):
2846 numqualifier = " %s" % optlabel
2847 numqualifier = " %s" % optlabel
2847 else:
2848 else:
2848 numqualifier = ""
2849 numqualifier = ""
2849 opt_output.append(("%2s%s" %
2850 opt_output.append(("%2s%s" %
2850 (shortopt and "-%s" % shortopt,
2851 (shortopt and "-%s" % shortopt,
2851 longopt and " --%s%s" %
2852 longopt and " --%s%s" %
2852 (longopt, numqualifier)),
2853 (longopt, numqualifier)),
2853 "%s%s" % (desc,
2854 "%s%s" % (desc,
2854 default
2855 default
2855 and _(" (default: %s)") % default
2856 and _(" (default: %s)") % default
2856 or "")))
2857 or "")))
2857 if multioccur:
2858 if multioccur:
2858 msg = _("\n[+] marked option can be specified multiple times")
2859 msg = _("\n[+] marked option can be specified multiple times")
2859 if ui.verbose and name != 'shortlist':
2860 if ui.verbose and name != 'shortlist':
2860 opt_output.append((msg, None))
2861 opt_output.append((msg, None))
2861 else:
2862 else:
2862 opt_output.insert(-1, (msg, None))
2863 opt_output.insert(-1, (msg, None))
2863
2864
2864 if not name:
2865 if not name:
2865 ui.write(_("\nadditional help topics:\n\n"))
2866 ui.write(_("\nadditional help topics:\n\n"))
2866 topics = []
2867 topics = []
2867 for names, header, doc in help.helptable:
2868 for names, header, doc in help.helptable:
2868 topics.append((sorted(names, key=len, reverse=True)[0], header))
2869 topics.append((sorted(names, key=len, reverse=True)[0], header))
2869 topics_len = max([len(s[0]) for s in topics])
2870 topics_len = max([len(s[0]) for s in topics])
2870 for t, desc in topics:
2871 for t, desc in topics:
2871 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2872 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2872
2873
2873 if opt_output:
2874 if opt_output:
2874 colwidth = encoding.colwidth
2875 colwidth = encoding.colwidth
2875 # normalize: (opt or message, desc or None, width of opt)
2876 # normalize: (opt or message, desc or None, width of opt)
2876 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2877 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2877 for opt, desc in opt_output]
2878 for opt, desc in opt_output]
2878 hanging = max([e[2] for e in entries])
2879 hanging = max([e[2] for e in entries])
2879 for opt, desc, width in entries:
2880 for opt, desc, width in entries:
2880 if desc:
2881 if desc:
2881 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2882 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2882 hangindent = ' ' * (hanging + 3)
2883 hangindent = ' ' * (hanging + 3)
2883 ui.write('%s\n' % (util.wrap(desc, textwidth,
2884 ui.write('%s\n' % (util.wrap(desc, textwidth,
2884 initindent=initindent,
2885 initindent=initindent,
2885 hangindent=hangindent)))
2886 hangindent=hangindent)))
2886 else:
2887 else:
2887 ui.write("%s\n" % opt)
2888 ui.write("%s\n" % opt)
2888
2889
2889 @command('identify|id',
2890 @command('identify|id',
2890 [('r', 'rev', '',
2891 [('r', 'rev', '',
2891 _('identify the specified revision'), _('REV')),
2892 _('identify the specified revision'), _('REV')),
2892 ('n', 'num', None, _('show local revision number')),
2893 ('n', 'num', None, _('show local revision number')),
2893 ('i', 'id', None, _('show global revision id')),
2894 ('i', 'id', None, _('show global revision id')),
2894 ('b', 'branch', None, _('show branch')),
2895 ('b', 'branch', None, _('show branch')),
2895 ('t', 'tags', None, _('show tags')),
2896 ('t', 'tags', None, _('show tags')),
2896 ('B', 'bookmarks', None, _('show bookmarks'))],
2897 ('B', 'bookmarks', None, _('show bookmarks'))],
2897 _('[-nibtB] [-r REV] [SOURCE]'))
2898 _('[-nibtB] [-r REV] [SOURCE]'))
2898 def identify(ui, repo, source=None, rev=None,
2899 def identify(ui, repo, source=None, rev=None,
2899 num=None, id=None, branch=None, tags=None, bookmarks=None):
2900 num=None, id=None, branch=None, tags=None, bookmarks=None):
2900 """identify the working copy or specified revision
2901 """identify the working copy or specified revision
2901
2902
2902 Print a summary identifying the repository state at REV using one or
2903 Print a summary identifying the repository state at REV using one or
2903 two parent hash identifiers, followed by a "+" if the working
2904 two parent hash identifiers, followed by a "+" if the working
2904 directory has uncommitted changes, the branch name (if not default),
2905 directory has uncommitted changes, the branch name (if not default),
2905 a list of tags, and a list of bookmarks.
2906 a list of tags, and a list of bookmarks.
2906
2907
2907 When REV is not given, print a summary of the current state of the
2908 When REV is not given, print a summary of the current state of the
2908 repository.
2909 repository.
2909
2910
2910 Specifying a path to a repository root or Mercurial bundle will
2911 Specifying a path to a repository root or Mercurial bundle will
2911 cause lookup to operate on that repository/bundle.
2912 cause lookup to operate on that repository/bundle.
2912
2913
2913 Returns 0 if successful.
2914 Returns 0 if successful.
2914 """
2915 """
2915
2916
2916 if not repo and not source:
2917 if not repo and not source:
2917 raise util.Abort(_("there is no Mercurial repository here "
2918 raise util.Abort(_("there is no Mercurial repository here "
2918 "(.hg not found)"))
2919 "(.hg not found)"))
2919
2920
2920 hexfunc = ui.debugflag and hex or short
2921 hexfunc = ui.debugflag and hex or short
2921 default = not (num or id or branch or tags or bookmarks)
2922 default = not (num or id or branch or tags or bookmarks)
2922 output = []
2923 output = []
2923 revs = []
2924 revs = []
2924
2925
2925 if source:
2926 if source:
2926 source, branches = hg.parseurl(ui.expandpath(source))
2927 source, branches = hg.parseurl(ui.expandpath(source))
2927 repo = hg.peer(ui, {}, source)
2928 repo = hg.peer(ui, {}, source)
2928 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2929 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2929
2930
2930 if not repo.local():
2931 if not repo.local():
2931 if num or branch or tags:
2932 if num or branch or tags:
2932 raise util.Abort(
2933 raise util.Abort(
2933 _("can't query remote revision number, branch, or tags"))
2934 _("can't query remote revision number, branch, or tags"))
2934 if not rev and revs:
2935 if not rev and revs:
2935 rev = revs[0]
2936 rev = revs[0]
2936 if not rev:
2937 if not rev:
2937 rev = "tip"
2938 rev = "tip"
2938
2939
2939 remoterev = repo.lookup(rev)
2940 remoterev = repo.lookup(rev)
2940 if default or id:
2941 if default or id:
2941 output = [hexfunc(remoterev)]
2942 output = [hexfunc(remoterev)]
2942
2943
2943 def getbms():
2944 def getbms():
2944 bms = []
2945 bms = []
2945
2946
2946 if 'bookmarks' in repo.listkeys('namespaces'):
2947 if 'bookmarks' in repo.listkeys('namespaces'):
2947 hexremoterev = hex(remoterev)
2948 hexremoterev = hex(remoterev)
2948 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2949 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2949 if bmr == hexremoterev]
2950 if bmr == hexremoterev]
2950
2951
2951 return bms
2952 return bms
2952
2953
2953 if bookmarks:
2954 if bookmarks:
2954 output.extend(getbms())
2955 output.extend(getbms())
2955 elif default and not ui.quiet:
2956 elif default and not ui.quiet:
2956 # multiple bookmarks for a single parent separated by '/'
2957 # multiple bookmarks for a single parent separated by '/'
2957 bm = '/'.join(getbms())
2958 bm = '/'.join(getbms())
2958 if bm:
2959 if bm:
2959 output.append(bm)
2960 output.append(bm)
2960 else:
2961 else:
2961 if not rev:
2962 if not rev:
2962 ctx = repo[None]
2963 ctx = repo[None]
2963 parents = ctx.parents()
2964 parents = ctx.parents()
2964 changed = ""
2965 changed = ""
2965 if default or id or num:
2966 if default or id or num:
2966 changed = util.any(repo.status()) and "+" or ""
2967 changed = util.any(repo.status()) and "+" or ""
2967 if default or id:
2968 if default or id:
2968 output = ["%s%s" %
2969 output = ["%s%s" %
2969 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2970 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2970 if num:
2971 if num:
2971 output.append("%s%s" %
2972 output.append("%s%s" %
2972 ('+'.join([str(p.rev()) for p in parents]), changed))
2973 ('+'.join([str(p.rev()) for p in parents]), changed))
2973 else:
2974 else:
2974 ctx = scmutil.revsingle(repo, rev)
2975 ctx = scmutil.revsingle(repo, rev)
2975 if default or id:
2976 if default or id:
2976 output = [hexfunc(ctx.node())]
2977 output = [hexfunc(ctx.node())]
2977 if num:
2978 if num:
2978 output.append(str(ctx.rev()))
2979 output.append(str(ctx.rev()))
2979
2980
2980 if default and not ui.quiet:
2981 if default and not ui.quiet:
2981 b = ctx.branch()
2982 b = ctx.branch()
2982 if b != 'default':
2983 if b != 'default':
2983 output.append("(%s)" % b)
2984 output.append("(%s)" % b)
2984
2985
2985 # multiple tags for a single parent separated by '/'
2986 # multiple tags for a single parent separated by '/'
2986 t = '/'.join(ctx.tags())
2987 t = '/'.join(ctx.tags())
2987 if t:
2988 if t:
2988 output.append(t)
2989 output.append(t)
2989
2990
2990 # multiple bookmarks for a single parent separated by '/'
2991 # multiple bookmarks for a single parent separated by '/'
2991 bm = '/'.join(ctx.bookmarks())
2992 bm = '/'.join(ctx.bookmarks())
2992 if bm:
2993 if bm:
2993 output.append(bm)
2994 output.append(bm)
2994 else:
2995 else:
2995 if branch:
2996 if branch:
2996 output.append(ctx.branch())
2997 output.append(ctx.branch())
2997
2998
2998 if tags:
2999 if tags:
2999 output.extend(ctx.tags())
3000 output.extend(ctx.tags())
3000
3001
3001 if bookmarks:
3002 if bookmarks:
3002 output.extend(ctx.bookmarks())
3003 output.extend(ctx.bookmarks())
3003
3004
3004 ui.write("%s\n" % ' '.join(output))
3005 ui.write("%s\n" % ' '.join(output))
3005
3006
3006 @command('import|patch',
3007 @command('import|patch',
3007 [('p', 'strip', 1,
3008 [('p', 'strip', 1,
3008 _('directory strip option for patch. This has the same '
3009 _('directory strip option for patch. This has the same '
3009 'meaning as the corresponding patch option'), _('NUM')),
3010 'meaning as the corresponding patch option'), _('NUM')),
3010 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3011 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3011 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3012 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3012 ('', 'no-commit', None,
3013 ('', 'no-commit', None,
3013 _("don't commit, just update the working directory")),
3014 _("don't commit, just update the working directory")),
3014 ('', 'bypass', None,
3015 ('', 'bypass', None,
3015 _("apply patch without touching the working directory")),
3016 _("apply patch without touching the working directory")),
3016 ('', 'exact', None,
3017 ('', 'exact', None,
3017 _('apply patch to the nodes from which it was generated')),
3018 _('apply patch to the nodes from which it was generated')),
3018 ('', 'import-branch', None,
3019 ('', 'import-branch', None,
3019 _('use any branch information in patch (implied by --exact)'))] +
3020 _('use any branch information in patch (implied by --exact)'))] +
3020 commitopts + commitopts2 + similarityopts,
3021 commitopts + commitopts2 + similarityopts,
3021 _('[OPTION]... PATCH...'))
3022 _('[OPTION]... PATCH...'))
3022 def import_(ui, repo, patch1, *patches, **opts):
3023 def import_(ui, repo, patch1, *patches, **opts):
3023 """import an ordered set of patches
3024 """import an ordered set of patches
3024
3025
3025 Import a list of patches and commit them individually (unless
3026 Import a list of patches and commit them individually (unless
3026 --no-commit is specified).
3027 --no-commit is specified).
3027
3028
3028 If there are outstanding changes in the working directory, import
3029 If there are outstanding changes in the working directory, import
3029 will abort unless given the -f/--force flag.
3030 will abort unless given the -f/--force flag.
3030
3031
3031 You can import a patch straight from a mail message. Even patches
3032 You can import a patch straight from a mail message. Even patches
3032 as attachments work (to use the body part, it must have type
3033 as attachments work (to use the body part, it must have type
3033 text/plain or text/x-patch). From and Subject headers of email
3034 text/plain or text/x-patch). From and Subject headers of email
3034 message are used as default committer and commit message. All
3035 message are used as default committer and commit message. All
3035 text/plain body parts before first diff are added to commit
3036 text/plain body parts before first diff are added to commit
3036 message.
3037 message.
3037
3038
3038 If the imported patch was generated by :hg:`export`, user and
3039 If the imported patch was generated by :hg:`export`, user and
3039 description from patch override values from message headers and
3040 description from patch override values from message headers and
3040 body. Values given on command line with -m/--message and -u/--user
3041 body. Values given on command line with -m/--message and -u/--user
3041 override these.
3042 override these.
3042
3043
3043 If --exact is specified, import will set the working directory to
3044 If --exact is specified, import will set the working directory to
3044 the parent of each patch before applying it, and will abort if the
3045 the parent of each patch before applying it, and will abort if the
3045 resulting changeset has a different ID than the one recorded in
3046 resulting changeset has a different ID than the one recorded in
3046 the patch. This may happen due to character set problems or other
3047 the patch. This may happen due to character set problems or other
3047 deficiencies in the text patch format.
3048 deficiencies in the text patch format.
3048
3049
3049 Use --bypass to apply and commit patches directly to the
3050 Use --bypass to apply and commit patches directly to the
3050 repository, not touching the working directory. Without --exact,
3051 repository, not touching the working directory. Without --exact,
3051 patches will be applied on top of the working directory parent
3052 patches will be applied on top of the working directory parent
3052 revision.
3053 revision.
3053
3054
3054 With -s/--similarity, hg will attempt to discover renames and
3055 With -s/--similarity, hg will attempt to discover renames and
3055 copies in the patch in the same way as 'addremove'.
3056 copies in the patch in the same way as 'addremove'.
3056
3057
3057 To read a patch from standard input, use "-" as the patch name. If
3058 To read a patch from standard input, use "-" as the patch name. If
3058 a URL is specified, the patch will be downloaded from it.
3059 a URL is specified, the patch will be downloaded from it.
3059 See :hg:`help dates` for a list of formats valid for -d/--date.
3060 See :hg:`help dates` for a list of formats valid for -d/--date.
3060
3061
3061 Returns 0 on success.
3062 Returns 0 on success.
3062 """
3063 """
3063 patches = (patch1,) + patches
3064 patches = (patch1,) + patches
3064
3065
3065 date = opts.get('date')
3066 date = opts.get('date')
3066 if date:
3067 if date:
3067 opts['date'] = util.parsedate(date)
3068 opts['date'] = util.parsedate(date)
3068
3069
3069 update = not opts.get('bypass')
3070 update = not opts.get('bypass')
3070 if not update and opts.get('no_commit'):
3071 if not update and opts.get('no_commit'):
3071 raise util.Abort(_('cannot use --no-commit with --bypass'))
3072 raise util.Abort(_('cannot use --no-commit with --bypass'))
3072 try:
3073 try:
3073 sim = float(opts.get('similarity') or 0)
3074 sim = float(opts.get('similarity') or 0)
3074 except ValueError:
3075 except ValueError:
3075 raise util.Abort(_('similarity must be a number'))
3076 raise util.Abort(_('similarity must be a number'))
3076 if sim < 0 or sim > 100:
3077 if sim < 0 or sim > 100:
3077 raise util.Abort(_('similarity must be between 0 and 100'))
3078 raise util.Abort(_('similarity must be between 0 and 100'))
3078 if sim and not update:
3079 if sim and not update:
3079 raise util.Abort(_('cannot use --similarity with --bypass'))
3080 raise util.Abort(_('cannot use --similarity with --bypass'))
3080
3081
3081 if (opts.get('exact') or not opts.get('force')) and update:
3082 if (opts.get('exact') or not opts.get('force')) and update:
3082 cmdutil.bailifchanged(repo)
3083 cmdutil.bailifchanged(repo)
3083
3084
3084 d = opts["base"]
3085 d = opts["base"]
3085 strip = opts["strip"]
3086 strip = opts["strip"]
3086 wlock = lock = None
3087 wlock = lock = None
3087 msgs = []
3088 msgs = []
3088
3089
3089 def checkexact(repo, n, nodeid):
3090 def checkexact(repo, n, nodeid):
3090 if opts.get('exact') and hex(n) != nodeid:
3091 if opts.get('exact') and hex(n) != nodeid:
3091 repo.rollback()
3092 repo.rollback()
3092 raise util.Abort(_('patch is damaged or loses information'))
3093 raise util.Abort(_('patch is damaged or loses information'))
3093
3094
3094 def tryone(ui, hunk, parents):
3095 def tryone(ui, hunk, parents):
3095 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3096 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3096 patch.extract(ui, hunk)
3097 patch.extract(ui, hunk)
3097
3098
3098 if not tmpname:
3099 if not tmpname:
3099 return None
3100 return None
3100 commitid = _('to working directory')
3101 commitid = _('to working directory')
3101
3102
3102 try:
3103 try:
3103 cmdline_message = cmdutil.logmessage(ui, opts)
3104 cmdline_message = cmdutil.logmessage(ui, opts)
3104 if cmdline_message:
3105 if cmdline_message:
3105 # pickup the cmdline msg
3106 # pickup the cmdline msg
3106 message = cmdline_message
3107 message = cmdline_message
3107 elif message:
3108 elif message:
3108 # pickup the patch msg
3109 # pickup the patch msg
3109 message = message.strip()
3110 message = message.strip()
3110 else:
3111 else:
3111 # launch the editor
3112 # launch the editor
3112 message = None
3113 message = None
3113 ui.debug('message:\n%s\n' % message)
3114 ui.debug('message:\n%s\n' % message)
3114
3115
3115 if len(parents) == 1:
3116 if len(parents) == 1:
3116 parents.append(repo[nullid])
3117 parents.append(repo[nullid])
3117 if opts.get('exact'):
3118 if opts.get('exact'):
3118 if not nodeid or not p1:
3119 if not nodeid or not p1:
3119 raise util.Abort(_('not a Mercurial patch'))
3120 raise util.Abort(_('not a Mercurial patch'))
3120 p1 = repo[p1]
3121 p1 = repo[p1]
3121 p2 = repo[p2 or nullid]
3122 p2 = repo[p2 or nullid]
3122 elif p2:
3123 elif p2:
3123 try:
3124 try:
3124 p1 = repo[p1]
3125 p1 = repo[p1]
3125 p2 = repo[p2]
3126 p2 = repo[p2]
3126 except error.RepoError:
3127 except error.RepoError:
3127 p1, p2 = parents
3128 p1, p2 = parents
3128 else:
3129 else:
3129 p1, p2 = parents
3130 p1, p2 = parents
3130
3131
3131 n = None
3132 n = None
3132 if update:
3133 if update:
3133 if opts.get('exact') and p1 != parents[0]:
3134 if opts.get('exact') and p1 != parents[0]:
3134 hg.clean(repo, p1.node())
3135 hg.clean(repo, p1.node())
3135 if p1 != parents[0] and p2 != parents[1]:
3136 if p1 != parents[0] and p2 != parents[1]:
3136 repo.dirstate.setparents(p1.node(), p2.node())
3137 repo.dirstate.setparents(p1.node(), p2.node())
3137
3138
3138 if opts.get('exact') or opts.get('import_branch'):
3139 if opts.get('exact') or opts.get('import_branch'):
3139 repo.dirstate.setbranch(branch or 'default')
3140 repo.dirstate.setbranch(branch or 'default')
3140
3141
3141 files = set()
3142 files = set()
3142 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3143 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3143 eolmode=None, similarity=sim / 100.0)
3144 eolmode=None, similarity=sim / 100.0)
3144 files = list(files)
3145 files = list(files)
3145 if opts.get('no_commit'):
3146 if opts.get('no_commit'):
3146 if message:
3147 if message:
3147 msgs.append(message)
3148 msgs.append(message)
3148 else:
3149 else:
3149 if opts.get('exact'):
3150 if opts.get('exact'):
3150 m = None
3151 m = None
3151 else:
3152 else:
3152 m = scmutil.matchfiles(repo, files or [])
3153 m = scmutil.matchfiles(repo, files or [])
3153 n = repo.commit(message, opts.get('user') or user,
3154 n = repo.commit(message, opts.get('user') or user,
3154 opts.get('date') or date, match=m,
3155 opts.get('date') or date, match=m,
3155 editor=cmdutil.commiteditor)
3156 editor=cmdutil.commiteditor)
3156 checkexact(repo, n, nodeid)
3157 checkexact(repo, n, nodeid)
3157 # Force a dirstate write so that the next transaction
3158 # Force a dirstate write so that the next transaction
3158 # backups an up-to-date file.
3159 # backups an up-to-date file.
3159 repo.dirstate.write()
3160 repo.dirstate.write()
3160 else:
3161 else:
3161 if opts.get('exact') or opts.get('import_branch'):
3162 if opts.get('exact') or opts.get('import_branch'):
3162 branch = branch or 'default'
3163 branch = branch or 'default'
3163 else:
3164 else:
3164 branch = p1.branch()
3165 branch = p1.branch()
3165 store = patch.filestore()
3166 store = patch.filestore()
3166 try:
3167 try:
3167 files = set()
3168 files = set()
3168 try:
3169 try:
3169 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3170 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3170 files, eolmode=None)
3171 files, eolmode=None)
3171 except patch.PatchError, e:
3172 except patch.PatchError, e:
3172 raise util.Abort(str(e))
3173 raise util.Abort(str(e))
3173 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3174 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3174 message,
3175 message,
3175 opts.get('user') or user,
3176 opts.get('user') or user,
3176 opts.get('date') or date,
3177 opts.get('date') or date,
3177 branch, files, store,
3178 branch, files, store,
3178 editor=cmdutil.commiteditor)
3179 editor=cmdutil.commiteditor)
3179 repo.savecommitmessage(memctx.description())
3180 repo.savecommitmessage(memctx.description())
3180 n = memctx.commit()
3181 n = memctx.commit()
3181 checkexact(repo, n, nodeid)
3182 checkexact(repo, n, nodeid)
3182 finally:
3183 finally:
3183 store.close()
3184 store.close()
3184 if n:
3185 if n:
3185 commitid = short(n)
3186 commitid = short(n)
3186 return commitid
3187 return commitid
3187 finally:
3188 finally:
3188 os.unlink(tmpname)
3189 os.unlink(tmpname)
3189
3190
3190 try:
3191 try:
3191 wlock = repo.wlock()
3192 wlock = repo.wlock()
3192 lock = repo.lock()
3193 lock = repo.lock()
3193 parents = repo.parents()
3194 parents = repo.parents()
3194 lastcommit = None
3195 lastcommit = None
3195 for p in patches:
3196 for p in patches:
3196 pf = os.path.join(d, p)
3197 pf = os.path.join(d, p)
3197
3198
3198 if pf == '-':
3199 if pf == '-':
3199 ui.status(_("applying patch from stdin\n"))
3200 ui.status(_("applying patch from stdin\n"))
3200 pf = ui.fin
3201 pf = ui.fin
3201 else:
3202 else:
3202 ui.status(_("applying %s\n") % p)
3203 ui.status(_("applying %s\n") % p)
3203 pf = url.open(ui, pf)
3204 pf = url.open(ui, pf)
3204
3205
3205 haspatch = False
3206 haspatch = False
3206 for hunk in patch.split(pf):
3207 for hunk in patch.split(pf):
3207 commitid = tryone(ui, hunk, parents)
3208 commitid = tryone(ui, hunk, parents)
3208 if commitid:
3209 if commitid:
3209 haspatch = True
3210 haspatch = True
3210 if lastcommit:
3211 if lastcommit:
3211 ui.status(_('applied %s\n') % lastcommit)
3212 ui.status(_('applied %s\n') % lastcommit)
3212 lastcommit = commitid
3213 lastcommit = commitid
3213 if update or opts.get('exact'):
3214 if update or opts.get('exact'):
3214 parents = repo.parents()
3215 parents = repo.parents()
3215 else:
3216 else:
3216 parents = [repo[commitid]]
3217 parents = [repo[commitid]]
3217
3218
3218 if not haspatch:
3219 if not haspatch:
3219 raise util.Abort(_('no diffs found'))
3220 raise util.Abort(_('no diffs found'))
3220
3221
3221 if msgs:
3222 if msgs:
3222 repo.savecommitmessage('\n* * *\n'.join(msgs))
3223 repo.savecommitmessage('\n* * *\n'.join(msgs))
3223 finally:
3224 finally:
3224 release(lock, wlock)
3225 release(lock, wlock)
3225
3226
3226 @command('incoming|in',
3227 @command('incoming|in',
3227 [('f', 'force', None,
3228 [('f', 'force', None,
3228 _('run even if remote repository is unrelated')),
3229 _('run even if remote repository is unrelated')),
3229 ('n', 'newest-first', None, _('show newest record first')),
3230 ('n', 'newest-first', None, _('show newest record first')),
3230 ('', 'bundle', '',
3231 ('', 'bundle', '',
3231 _('file to store the bundles into'), _('FILE')),
3232 _('file to store the bundles into'), _('FILE')),
3232 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3233 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3233 ('B', 'bookmarks', False, _("compare bookmarks")),
3234 ('B', 'bookmarks', False, _("compare bookmarks")),
3234 ('b', 'branch', [],
3235 ('b', 'branch', [],
3235 _('a specific branch you would like to pull'), _('BRANCH')),
3236 _('a specific branch you would like to pull'), _('BRANCH')),
3236 ] + logopts + remoteopts + subrepoopts,
3237 ] + logopts + remoteopts + subrepoopts,
3237 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3238 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3238 def incoming(ui, repo, source="default", **opts):
3239 def incoming(ui, repo, source="default", **opts):
3239 """show new changesets found in source
3240 """show new changesets found in source
3240
3241
3241 Show new changesets found in the specified path/URL or the default
3242 Show new changesets found in the specified path/URL or the default
3242 pull location. These are the changesets that would have been pulled
3243 pull location. These are the changesets that would have been pulled
3243 if a pull at the time you issued this command.
3244 if a pull at the time you issued this command.
3244
3245
3245 For remote repository, using --bundle avoids downloading the
3246 For remote repository, using --bundle avoids downloading the
3246 changesets twice if the incoming is followed by a pull.
3247 changesets twice if the incoming is followed by a pull.
3247
3248
3248 See pull for valid source format details.
3249 See pull for valid source format details.
3249
3250
3250 Returns 0 if there are incoming changes, 1 otherwise.
3251 Returns 0 if there are incoming changes, 1 otherwise.
3251 """
3252 """
3252 if opts.get('bundle') and opts.get('subrepos'):
3253 if opts.get('bundle') and opts.get('subrepos'):
3253 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3254 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3254
3255
3255 if opts.get('bookmarks'):
3256 if opts.get('bookmarks'):
3256 source, branches = hg.parseurl(ui.expandpath(source),
3257 source, branches = hg.parseurl(ui.expandpath(source),
3257 opts.get('branch'))
3258 opts.get('branch'))
3258 other = hg.peer(repo, opts, source)
3259 other = hg.peer(repo, opts, source)
3259 if 'bookmarks' not in other.listkeys('namespaces'):
3260 if 'bookmarks' not in other.listkeys('namespaces'):
3260 ui.warn(_("remote doesn't support bookmarks\n"))
3261 ui.warn(_("remote doesn't support bookmarks\n"))
3261 return 0
3262 return 0
3262 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3263 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3263 return bookmarks.diff(ui, repo, other)
3264 return bookmarks.diff(ui, repo, other)
3264
3265
3265 repo._subtoppath = ui.expandpath(source)
3266 repo._subtoppath = ui.expandpath(source)
3266 try:
3267 try:
3267 return hg.incoming(ui, repo, source, opts)
3268 return hg.incoming(ui, repo, source, opts)
3268 finally:
3269 finally:
3269 del repo._subtoppath
3270 del repo._subtoppath
3270
3271
3271
3272
3272 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3273 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3273 def init(ui, dest=".", **opts):
3274 def init(ui, dest=".", **opts):
3274 """create a new repository in the given directory
3275 """create a new repository in the given directory
3275
3276
3276 Initialize a new repository in the given directory. If the given
3277 Initialize a new repository in the given directory. If the given
3277 directory does not exist, it will be created.
3278 directory does not exist, it will be created.
3278
3279
3279 If no directory is given, the current directory is used.
3280 If no directory is given, the current directory is used.
3280
3281
3281 It is possible to specify an ``ssh://`` URL as the destination.
3282 It is possible to specify an ``ssh://`` URL as the destination.
3282 See :hg:`help urls` for more information.
3283 See :hg:`help urls` for more information.
3283
3284
3284 Returns 0 on success.
3285 Returns 0 on success.
3285 """
3286 """
3286 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3287 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3287
3288
3288 @command('locate',
3289 @command('locate',
3289 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3290 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3290 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3291 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3291 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3292 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3292 ] + walkopts,
3293 ] + walkopts,
3293 _('[OPTION]... [PATTERN]...'))
3294 _('[OPTION]... [PATTERN]...'))
3294 def locate(ui, repo, *pats, **opts):
3295 def locate(ui, repo, *pats, **opts):
3295 """locate files matching specific patterns
3296 """locate files matching specific patterns
3296
3297
3297 Print files under Mercurial control in the working directory whose
3298 Print files under Mercurial control in the working directory whose
3298 names match the given patterns.
3299 names match the given patterns.
3299
3300
3300 By default, this command searches all directories in the working
3301 By default, this command searches all directories in the working
3301 directory. To search just the current directory and its
3302 directory. To search just the current directory and its
3302 subdirectories, use "--include .".
3303 subdirectories, use "--include .".
3303
3304
3304 If no patterns are given to match, this command prints the names
3305 If no patterns are given to match, this command prints the names
3305 of all files under Mercurial control in the working directory.
3306 of all files under Mercurial control in the working directory.
3306
3307
3307 If you want to feed the output of this command into the "xargs"
3308 If you want to feed the output of this command into the "xargs"
3308 command, use the -0 option to both this command and "xargs". This
3309 command, use the -0 option to both this command and "xargs". This
3309 will avoid the problem of "xargs" treating single filenames that
3310 will avoid the problem of "xargs" treating single filenames that
3310 contain whitespace as multiple filenames.
3311 contain whitespace as multiple filenames.
3311
3312
3312 Returns 0 if a match is found, 1 otherwise.
3313 Returns 0 if a match is found, 1 otherwise.
3313 """
3314 """
3314 end = opts.get('print0') and '\0' or '\n'
3315 end = opts.get('print0') and '\0' or '\n'
3315 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3316 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3316
3317
3317 ret = 1
3318 ret = 1
3318 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3319 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3319 m.bad = lambda x, y: False
3320 m.bad = lambda x, y: False
3320 for abs in repo[rev].walk(m):
3321 for abs in repo[rev].walk(m):
3321 if not rev and abs not in repo.dirstate:
3322 if not rev and abs not in repo.dirstate:
3322 continue
3323 continue
3323 if opts.get('fullpath'):
3324 if opts.get('fullpath'):
3324 ui.write(repo.wjoin(abs), end)
3325 ui.write(repo.wjoin(abs), end)
3325 else:
3326 else:
3326 ui.write(((pats and m.rel(abs)) or abs), end)
3327 ui.write(((pats and m.rel(abs)) or abs), end)
3327 ret = 0
3328 ret = 0
3328
3329
3329 return ret
3330 return ret
3330
3331
3331 @command('^log|history',
3332 @command('^log|history',
3332 [('f', 'follow', None,
3333 [('f', 'follow', None,
3333 _('follow changeset history, or file history across copies and renames')),
3334 _('follow changeset history, or file history across copies and renames')),
3334 ('', 'follow-first', None,
3335 ('', 'follow-first', None,
3335 _('only follow the first parent of merge changesets')),
3336 _('only follow the first parent of merge changesets')),
3336 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3337 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3337 ('C', 'copies', None, _('show copied files')),
3338 ('C', 'copies', None, _('show copied files')),
3338 ('k', 'keyword', [],
3339 ('k', 'keyword', [],
3339 _('do case-insensitive search for a given text'), _('TEXT')),
3340 _('do case-insensitive search for a given text'), _('TEXT')),
3340 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3341 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3341 ('', 'removed', None, _('include revisions where files were removed')),
3342 ('', 'removed', None, _('include revisions where files were removed')),
3342 ('m', 'only-merges', None, _('show only merges')),
3343 ('m', 'only-merges', None, _('show only merges')),
3343 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3344 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3344 ('', 'only-branch', [],
3345 ('', 'only-branch', [],
3345 _('show only changesets within the given named branch (DEPRECATED)'),
3346 _('show only changesets within the given named branch (DEPRECATED)'),
3346 _('BRANCH')),
3347 _('BRANCH')),
3347 ('b', 'branch', [],
3348 ('b', 'branch', [],
3348 _('show changesets within the given named branch'), _('BRANCH')),
3349 _('show changesets within the given named branch'), _('BRANCH')),
3349 ('P', 'prune', [],
3350 ('P', 'prune', [],
3350 _('do not display revision or any of its ancestors'), _('REV')),
3351 _('do not display revision or any of its ancestors'), _('REV')),
3351 ('h', 'hidden', False, _('show hidden changesets')),
3352 ('h', 'hidden', False, _('show hidden changesets')),
3352 ] + logopts + walkopts,
3353 ] + logopts + walkopts,
3353 _('[OPTION]... [FILE]'))
3354 _('[OPTION]... [FILE]'))
3354 def log(ui, repo, *pats, **opts):
3355 def log(ui, repo, *pats, **opts):
3355 """show revision history of entire repository or files
3356 """show revision history of entire repository or files
3356
3357
3357 Print the revision history of the specified files or the entire
3358 Print the revision history of the specified files or the entire
3358 project.
3359 project.
3359
3360
3360 File history is shown without following rename or copy history of
3361 File history is shown without following rename or copy history of
3361 files. Use -f/--follow with a filename to follow history across
3362 files. Use -f/--follow with a filename to follow history across
3362 renames and copies. --follow without a filename will only show
3363 renames and copies. --follow without a filename will only show
3363 ancestors or descendants of the starting revision. --follow-first
3364 ancestors or descendants of the starting revision. --follow-first
3364 only follows the first parent of merge revisions.
3365 only follows the first parent of merge revisions.
3365
3366
3366 If no revision range is specified, the default is ``tip:0`` unless
3367 If no revision range is specified, the default is ``tip:0`` unless
3367 --follow is set, in which case the working directory parent is
3368 --follow is set, in which case the working directory parent is
3368 used as the starting revision. You can specify a revision set for
3369 used as the starting revision. You can specify a revision set for
3369 log, see :hg:`help revsets` for more information.
3370 log, see :hg:`help revsets` for more information.
3370
3371
3371 See :hg:`help dates` for a list of formats valid for -d/--date.
3372 See :hg:`help dates` for a list of formats valid for -d/--date.
3372
3373
3373 By default this command prints revision number and changeset id,
3374 By default this command prints revision number and changeset id,
3374 tags, non-trivial parents, user, date and time, and a summary for
3375 tags, non-trivial parents, user, date and time, and a summary for
3375 each commit. When the -v/--verbose switch is used, the list of
3376 each commit. When the -v/--verbose switch is used, the list of
3376 changed files and full commit message are shown.
3377 changed files and full commit message are shown.
3377
3378
3378 .. note::
3379 .. note::
3379 log -p/--patch may generate unexpected diff output for merge
3380 log -p/--patch may generate unexpected diff output for merge
3380 changesets, as it will only compare the merge changeset against
3381 changesets, as it will only compare the merge changeset against
3381 its first parent. Also, only files different from BOTH parents
3382 its first parent. Also, only files different from BOTH parents
3382 will appear in files:.
3383 will appear in files:.
3383
3384
3384 Returns 0 on success.
3385 Returns 0 on success.
3385 """
3386 """
3386
3387
3387 matchfn = scmutil.match(repo[None], pats, opts)
3388 matchfn = scmutil.match(repo[None], pats, opts)
3388 limit = cmdutil.loglimit(opts)
3389 limit = cmdutil.loglimit(opts)
3389 count = 0
3390 count = 0
3390
3391
3391 endrev = None
3392 endrev = None
3392 if opts.get('copies') and opts.get('rev'):
3393 if opts.get('copies') and opts.get('rev'):
3393 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3394 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3394
3395
3395 df = False
3396 df = False
3396 if opts["date"]:
3397 if opts["date"]:
3397 df = util.matchdate(opts["date"])
3398 df = util.matchdate(opts["date"])
3398
3399
3399 branches = opts.get('branch', []) + opts.get('only_branch', [])
3400 branches = opts.get('branch', []) + opts.get('only_branch', [])
3400 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3401 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3401
3402
3402 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3403 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3403 def prep(ctx, fns):
3404 def prep(ctx, fns):
3404 rev = ctx.rev()
3405 rev = ctx.rev()
3405 parents = [p for p in repo.changelog.parentrevs(rev)
3406 parents = [p for p in repo.changelog.parentrevs(rev)
3406 if p != nullrev]
3407 if p != nullrev]
3407 if opts.get('no_merges') and len(parents) == 2:
3408 if opts.get('no_merges') and len(parents) == 2:
3408 return
3409 return
3409 if opts.get('only_merges') and len(parents) != 2:
3410 if opts.get('only_merges') and len(parents) != 2:
3410 return
3411 return
3411 if opts.get('branch') and ctx.branch() not in opts['branch']:
3412 if opts.get('branch') and ctx.branch() not in opts['branch']:
3412 return
3413 return
3413 if not opts.get('hidden') and ctx.hidden():
3414 if not opts.get('hidden') and ctx.hidden():
3414 return
3415 return
3415 if df and not df(ctx.date()[0]):
3416 if df and not df(ctx.date()[0]):
3416 return
3417 return
3417 if opts['user'] and not [k for k in opts['user']
3418 if opts['user'] and not [k for k in opts['user']
3418 if k.lower() in ctx.user().lower()]:
3419 if k.lower() in ctx.user().lower()]:
3419 return
3420 return
3420 if opts.get('keyword'):
3421 if opts.get('keyword'):
3421 for k in [kw.lower() for kw in opts['keyword']]:
3422 for k in [kw.lower() for kw in opts['keyword']]:
3422 if (k in ctx.user().lower() or
3423 if (k in ctx.user().lower() or
3423 k in ctx.description().lower() or
3424 k in ctx.description().lower() or
3424 k in " ".join(ctx.files()).lower()):
3425 k in " ".join(ctx.files()).lower()):
3425 break
3426 break
3426 else:
3427 else:
3427 return
3428 return
3428
3429
3429 copies = None
3430 copies = None
3430 if opts.get('copies') and rev:
3431 if opts.get('copies') and rev:
3431 copies = []
3432 copies = []
3432 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3433 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3433 for fn in ctx.files():
3434 for fn in ctx.files():
3434 rename = getrenamed(fn, rev)
3435 rename = getrenamed(fn, rev)
3435 if rename:
3436 if rename:
3436 copies.append((fn, rename[0]))
3437 copies.append((fn, rename[0]))
3437
3438
3438 revmatchfn = None
3439 revmatchfn = None
3439 if opts.get('patch') or opts.get('stat'):
3440 if opts.get('patch') or opts.get('stat'):
3440 if opts.get('follow') or opts.get('follow_first'):
3441 if opts.get('follow') or opts.get('follow_first'):
3441 # note: this might be wrong when following through merges
3442 # note: this might be wrong when following through merges
3442 revmatchfn = scmutil.match(repo[None], fns, default='path')
3443 revmatchfn = scmutil.match(repo[None], fns, default='path')
3443 else:
3444 else:
3444 revmatchfn = matchfn
3445 revmatchfn = matchfn
3445
3446
3446 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3447 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3447
3448
3448 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3449 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3449 if count == limit:
3450 if count == limit:
3450 break
3451 break
3451 if displayer.flush(ctx.rev()):
3452 if displayer.flush(ctx.rev()):
3452 count += 1
3453 count += 1
3453 displayer.close()
3454 displayer.close()
3454
3455
3455 @command('manifest',
3456 @command('manifest',
3456 [('r', 'rev', '', _('revision to display'), _('REV')),
3457 [('r', 'rev', '', _('revision to display'), _('REV')),
3457 ('', 'all', False, _("list files from all revisions"))],
3458 ('', 'all', False, _("list files from all revisions"))],
3458 _('[-r REV]'))
3459 _('[-r REV]'))
3459 def manifest(ui, repo, node=None, rev=None, **opts):
3460 def manifest(ui, repo, node=None, rev=None, **opts):
3460 """output the current or given revision of the project manifest
3461 """output the current or given revision of the project manifest
3461
3462
3462 Print a list of version controlled files for the given revision.
3463 Print a list of version controlled files for the given revision.
3463 If no revision is given, the first parent of the working directory
3464 If no revision is given, the first parent of the working directory
3464 is used, or the null revision if no revision is checked out.
3465 is used, or the null revision if no revision is checked out.
3465
3466
3466 With -v, print file permissions, symlink and executable bits.
3467 With -v, print file permissions, symlink and executable bits.
3467 With --debug, print file revision hashes.
3468 With --debug, print file revision hashes.
3468
3469
3469 If option --all is specified, the list of all files from all revisions
3470 If option --all is specified, the list of all files from all revisions
3470 is printed. This includes deleted and renamed files.
3471 is printed. This includes deleted and renamed files.
3471
3472
3472 Returns 0 on success.
3473 Returns 0 on success.
3473 """
3474 """
3474 if opts.get('all'):
3475 if opts.get('all'):
3475 if rev or node:
3476 if rev or node:
3476 raise util.Abort(_("can't specify a revision with --all"))
3477 raise util.Abort(_("can't specify a revision with --all"))
3477
3478
3478 res = []
3479 res = []
3479 prefix = "data/"
3480 prefix = "data/"
3480 suffix = ".i"
3481 suffix = ".i"
3481 plen = len(prefix)
3482 plen = len(prefix)
3482 slen = len(suffix)
3483 slen = len(suffix)
3483 lock = repo.lock()
3484 lock = repo.lock()
3484 try:
3485 try:
3485 for fn, b, size in repo.store.datafiles():
3486 for fn, b, size in repo.store.datafiles():
3486 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3487 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3487 res.append(fn[plen:-slen])
3488 res.append(fn[plen:-slen])
3488 finally:
3489 finally:
3489 lock.release()
3490 lock.release()
3490 for f in sorted(res):
3491 for f in sorted(res):
3491 ui.write("%s\n" % f)
3492 ui.write("%s\n" % f)
3492 return
3493 return
3493
3494
3494 if rev and node:
3495 if rev and node:
3495 raise util.Abort(_("please specify just one revision"))
3496 raise util.Abort(_("please specify just one revision"))
3496
3497
3497 if not node:
3498 if not node:
3498 node = rev
3499 node = rev
3499
3500
3500 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3501 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3501 ctx = scmutil.revsingle(repo, node)
3502 ctx = scmutil.revsingle(repo, node)
3502 for f in ctx:
3503 for f in ctx:
3503 if ui.debugflag:
3504 if ui.debugflag:
3504 ui.write("%40s " % hex(ctx.manifest()[f]))
3505 ui.write("%40s " % hex(ctx.manifest()[f]))
3505 if ui.verbose:
3506 if ui.verbose:
3506 ui.write(decor[ctx.flags(f)])
3507 ui.write(decor[ctx.flags(f)])
3507 ui.write("%s\n" % f)
3508 ui.write("%s\n" % f)
3508
3509
3509 @command('^merge',
3510 @command('^merge',
3510 [('f', 'force', None, _('force a merge with outstanding changes')),
3511 [('f', 'force', None, _('force a merge with outstanding changes')),
3511 ('r', 'rev', '', _('revision to merge'), _('REV')),
3512 ('r', 'rev', '', _('revision to merge'), _('REV')),
3512 ('P', 'preview', None,
3513 ('P', 'preview', None,
3513 _('review revisions to merge (no merge is performed)'))
3514 _('review revisions to merge (no merge is performed)'))
3514 ] + mergetoolopts,
3515 ] + mergetoolopts,
3515 _('[-P] [-f] [[-r] REV]'))
3516 _('[-P] [-f] [[-r] REV]'))
3516 def merge(ui, repo, node=None, **opts):
3517 def merge(ui, repo, node=None, **opts):
3517 """merge working directory with another revision
3518 """merge working directory with another revision
3518
3519
3519 The current working directory is updated with all changes made in
3520 The current working directory is updated with all changes made in
3520 the requested revision since the last common predecessor revision.
3521 the requested revision since the last common predecessor revision.
3521
3522
3522 Files that changed between either parent are marked as changed for
3523 Files that changed between either parent are marked as changed for
3523 the next commit and a commit must be performed before any further
3524 the next commit and a commit must be performed before any further
3524 updates to the repository are allowed. The next commit will have
3525 updates to the repository are allowed. The next commit will have
3525 two parents.
3526 two parents.
3526
3527
3527 ``--tool`` can be used to specify the merge tool used for file
3528 ``--tool`` can be used to specify the merge tool used for file
3528 merges. It overrides the HGMERGE environment variable and your
3529 merges. It overrides the HGMERGE environment variable and your
3529 configuration files. See :hg:`help merge-tools` for options.
3530 configuration files. See :hg:`help merge-tools` for options.
3530
3531
3531 If no revision is specified, the working directory's parent is a
3532 If no revision is specified, the working directory's parent is a
3532 head revision, and the current branch contains exactly one other
3533 head revision, and the current branch contains exactly one other
3533 head, the other head is merged with by default. Otherwise, an
3534 head, the other head is merged with by default. Otherwise, an
3534 explicit revision with which to merge with must be provided.
3535 explicit revision with which to merge with must be provided.
3535
3536
3536 :hg:`resolve` must be used to resolve unresolved files.
3537 :hg:`resolve` must be used to resolve unresolved files.
3537
3538
3538 To undo an uncommitted merge, use :hg:`update --clean .` which
3539 To undo an uncommitted merge, use :hg:`update --clean .` which
3539 will check out a clean copy of the original merge parent, losing
3540 will check out a clean copy of the original merge parent, losing
3540 all changes.
3541 all changes.
3541
3542
3542 Returns 0 on success, 1 if there are unresolved files.
3543 Returns 0 on success, 1 if there are unresolved files.
3543 """
3544 """
3544
3545
3545 if opts.get('rev') and node:
3546 if opts.get('rev') and node:
3546 raise util.Abort(_("please specify just one revision"))
3547 raise util.Abort(_("please specify just one revision"))
3547 if not node:
3548 if not node:
3548 node = opts.get('rev')
3549 node = opts.get('rev')
3549
3550
3550 if not node:
3551 if not node:
3551 branch = repo[None].branch()
3552 branch = repo[None].branch()
3552 bheads = repo.branchheads(branch)
3553 bheads = repo.branchheads(branch)
3553 if len(bheads) > 2:
3554 if len(bheads) > 2:
3554 raise util.Abort(_("branch '%s' has %d heads - "
3555 raise util.Abort(_("branch '%s' has %d heads - "
3555 "please merge with an explicit rev")
3556 "please merge with an explicit rev")
3556 % (branch, len(bheads)),
3557 % (branch, len(bheads)),
3557 hint=_("run 'hg heads .' to see heads"))
3558 hint=_("run 'hg heads .' to see heads"))
3558
3559
3559 parent = repo.dirstate.p1()
3560 parent = repo.dirstate.p1()
3560 if len(bheads) == 1:
3561 if len(bheads) == 1:
3561 if len(repo.heads()) > 1:
3562 if len(repo.heads()) > 1:
3562 raise util.Abort(_("branch '%s' has one head - "
3563 raise util.Abort(_("branch '%s' has one head - "
3563 "please merge with an explicit rev")
3564 "please merge with an explicit rev")
3564 % branch,
3565 % branch,
3565 hint=_("run 'hg heads' to see all heads"))
3566 hint=_("run 'hg heads' to see all heads"))
3566 msg = _('there is nothing to merge')
3567 msg = _('there is nothing to merge')
3567 if parent != repo.lookup(repo[None].branch()):
3568 if parent != repo.lookup(repo[None].branch()):
3568 msg = _('%s - use "hg update" instead') % msg
3569 msg = _('%s - use "hg update" instead') % msg
3569 raise util.Abort(msg)
3570 raise util.Abort(msg)
3570
3571
3571 if parent not in bheads:
3572 if parent not in bheads:
3572 raise util.Abort(_('working directory not at a head revision'),
3573 raise util.Abort(_('working directory not at a head revision'),
3573 hint=_("use 'hg update' or merge with an "
3574 hint=_("use 'hg update' or merge with an "
3574 "explicit revision"))
3575 "explicit revision"))
3575 node = parent == bheads[0] and bheads[-1] or bheads[0]
3576 node = parent == bheads[0] and bheads[-1] or bheads[0]
3576 else:
3577 else:
3577 node = scmutil.revsingle(repo, node).node()
3578 node = scmutil.revsingle(repo, node).node()
3578
3579
3579 if opts.get('preview'):
3580 if opts.get('preview'):
3580 # find nodes that are ancestors of p2 but not of p1
3581 # find nodes that are ancestors of p2 but not of p1
3581 p1 = repo.lookup('.')
3582 p1 = repo.lookup('.')
3582 p2 = repo.lookup(node)
3583 p2 = repo.lookup(node)
3583 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3584 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3584
3585
3585 displayer = cmdutil.show_changeset(ui, repo, opts)
3586 displayer = cmdutil.show_changeset(ui, repo, opts)
3586 for node in nodes:
3587 for node in nodes:
3587 displayer.show(repo[node])
3588 displayer.show(repo[node])
3588 displayer.close()
3589 displayer.close()
3589 return 0
3590 return 0
3590
3591
3591 try:
3592 try:
3592 # ui.forcemerge is an internal variable, do not document
3593 # ui.forcemerge is an internal variable, do not document
3593 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3594 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3594 return hg.merge(repo, node, force=opts.get('force'))
3595 return hg.merge(repo, node, force=opts.get('force'))
3595 finally:
3596 finally:
3596 ui.setconfig('ui', 'forcemerge', '')
3597 ui.setconfig('ui', 'forcemerge', '')
3597
3598
3598 @command('outgoing|out',
3599 @command('outgoing|out',
3599 [('f', 'force', None, _('run even when the destination is unrelated')),
3600 [('f', 'force', None, _('run even when the destination is unrelated')),
3600 ('r', 'rev', [],
3601 ('r', 'rev', [],
3601 _('a changeset intended to be included in the destination'), _('REV')),
3602 _('a changeset intended to be included in the destination'), _('REV')),
3602 ('n', 'newest-first', None, _('show newest record first')),
3603 ('n', 'newest-first', None, _('show newest record first')),
3603 ('B', 'bookmarks', False, _('compare bookmarks')),
3604 ('B', 'bookmarks', False, _('compare bookmarks')),
3604 ('b', 'branch', [], _('a specific branch you would like to push'),
3605 ('b', 'branch', [], _('a specific branch you would like to push'),
3605 _('BRANCH')),
3606 _('BRANCH')),
3606 ] + logopts + remoteopts + subrepoopts,
3607 ] + logopts + remoteopts + subrepoopts,
3607 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3608 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3608 def outgoing(ui, repo, dest=None, **opts):
3609 def outgoing(ui, repo, dest=None, **opts):
3609 """show changesets not found in the destination
3610 """show changesets not found in the destination
3610
3611
3611 Show changesets not found in the specified destination repository
3612 Show changesets not found in the specified destination repository
3612 or the default push location. These are the changesets that would
3613 or the default push location. These are the changesets that would
3613 be pushed if a push was requested.
3614 be pushed if a push was requested.
3614
3615
3615 See pull for details of valid destination formats.
3616 See pull for details of valid destination formats.
3616
3617
3617 Returns 0 if there are outgoing changes, 1 otherwise.
3618 Returns 0 if there are outgoing changes, 1 otherwise.
3618 """
3619 """
3619
3620
3620 if opts.get('bookmarks'):
3621 if opts.get('bookmarks'):
3621 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3622 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3622 dest, branches = hg.parseurl(dest, opts.get('branch'))
3623 dest, branches = hg.parseurl(dest, opts.get('branch'))
3623 other = hg.peer(repo, opts, dest)
3624 other = hg.peer(repo, opts, dest)
3624 if 'bookmarks' not in other.listkeys('namespaces'):
3625 if 'bookmarks' not in other.listkeys('namespaces'):
3625 ui.warn(_("remote doesn't support bookmarks\n"))
3626 ui.warn(_("remote doesn't support bookmarks\n"))
3626 return 0
3627 return 0
3627 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3628 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3628 return bookmarks.diff(ui, other, repo)
3629 return bookmarks.diff(ui, other, repo)
3629
3630
3630 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3631 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3631 try:
3632 try:
3632 return hg.outgoing(ui, repo, dest, opts)
3633 return hg.outgoing(ui, repo, dest, opts)
3633 finally:
3634 finally:
3634 del repo._subtoppath
3635 del repo._subtoppath
3635
3636
3636 @command('parents',
3637 @command('parents',
3637 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3638 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3638 ] + templateopts,
3639 ] + templateopts,
3639 _('[-r REV] [FILE]'))
3640 _('[-r REV] [FILE]'))
3640 def parents(ui, repo, file_=None, **opts):
3641 def parents(ui, repo, file_=None, **opts):
3641 """show the parents of the working directory or revision
3642 """show the parents of the working directory or revision
3642
3643
3643 Print the working directory's parent revisions. If a revision is
3644 Print the working directory's parent revisions. If a revision is
3644 given via -r/--rev, the parent of that revision will be printed.
3645 given via -r/--rev, the parent of that revision will be printed.
3645 If a file argument is given, the revision in which the file was
3646 If a file argument is given, the revision in which the file was
3646 last changed (before the working directory revision or the
3647 last changed (before the working directory revision or the
3647 argument to --rev if given) is printed.
3648 argument to --rev if given) is printed.
3648
3649
3649 Returns 0 on success.
3650 Returns 0 on success.
3650 """
3651 """
3651
3652
3652 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3653 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3653
3654
3654 if file_:
3655 if file_:
3655 m = scmutil.match(ctx, (file_,), opts)
3656 m = scmutil.match(ctx, (file_,), opts)
3656 if m.anypats() or len(m.files()) != 1:
3657 if m.anypats() or len(m.files()) != 1:
3657 raise util.Abort(_('can only specify an explicit filename'))
3658 raise util.Abort(_('can only specify an explicit filename'))
3658 file_ = m.files()[0]
3659 file_ = m.files()[0]
3659 filenodes = []
3660 filenodes = []
3660 for cp in ctx.parents():
3661 for cp in ctx.parents():
3661 if not cp:
3662 if not cp:
3662 continue
3663 continue
3663 try:
3664 try:
3664 filenodes.append(cp.filenode(file_))
3665 filenodes.append(cp.filenode(file_))
3665 except error.LookupError:
3666 except error.LookupError:
3666 pass
3667 pass
3667 if not filenodes:
3668 if not filenodes:
3668 raise util.Abort(_("'%s' not found in manifest!") % file_)
3669 raise util.Abort(_("'%s' not found in manifest!") % file_)
3669 fl = repo.file(file_)
3670 fl = repo.file(file_)
3670 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3671 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3671 else:
3672 else:
3672 p = [cp.node() for cp in ctx.parents()]
3673 p = [cp.node() for cp in ctx.parents()]
3673
3674
3674 displayer = cmdutil.show_changeset(ui, repo, opts)
3675 displayer = cmdutil.show_changeset(ui, repo, opts)
3675 for n in p:
3676 for n in p:
3676 if n != nullid:
3677 if n != nullid:
3677 displayer.show(repo[n])
3678 displayer.show(repo[n])
3678 displayer.close()
3679 displayer.close()
3679
3680
3680 @command('paths', [], _('[NAME]'))
3681 @command('paths', [], _('[NAME]'))
3681 def paths(ui, repo, search=None):
3682 def paths(ui, repo, search=None):
3682 """show aliases for remote repositories
3683 """show aliases for remote repositories
3683
3684
3684 Show definition of symbolic path name NAME. If no name is given,
3685 Show definition of symbolic path name NAME. If no name is given,
3685 show definition of all available names.
3686 show definition of all available names.
3686
3687
3687 Option -q/--quiet suppresses all output when searching for NAME
3688 Option -q/--quiet suppresses all output when searching for NAME
3688 and shows only the path names when listing all definitions.
3689 and shows only the path names when listing all definitions.
3689
3690
3690 Path names are defined in the [paths] section of your
3691 Path names are defined in the [paths] section of your
3691 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3692 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3692 repository, ``.hg/hgrc`` is used, too.
3693 repository, ``.hg/hgrc`` is used, too.
3693
3694
3694 The path names ``default`` and ``default-push`` have a special
3695 The path names ``default`` and ``default-push`` have a special
3695 meaning. When performing a push or pull operation, they are used
3696 meaning. When performing a push or pull operation, they are used
3696 as fallbacks if no location is specified on the command-line.
3697 as fallbacks if no location is specified on the command-line.
3697 When ``default-push`` is set, it will be used for push and
3698 When ``default-push`` is set, it will be used for push and
3698 ``default`` will be used for pull; otherwise ``default`` is used
3699 ``default`` will be used for pull; otherwise ``default`` is used
3699 as the fallback for both. When cloning a repository, the clone
3700 as the fallback for both. When cloning a repository, the clone
3700 source is written as ``default`` in ``.hg/hgrc``. Note that
3701 source is written as ``default`` in ``.hg/hgrc``. Note that
3701 ``default`` and ``default-push`` apply to all inbound (e.g.
3702 ``default`` and ``default-push`` apply to all inbound (e.g.
3702 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3703 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3703 :hg:`bundle`) operations.
3704 :hg:`bundle`) operations.
3704
3705
3705 See :hg:`help urls` for more information.
3706 See :hg:`help urls` for more information.
3706
3707
3707 Returns 0 on success.
3708 Returns 0 on success.
3708 """
3709 """
3709 if search:
3710 if search:
3710 for name, path in ui.configitems("paths"):
3711 for name, path in ui.configitems("paths"):
3711 if name == search:
3712 if name == search:
3712 ui.status("%s\n" % util.hidepassword(path))
3713 ui.status("%s\n" % util.hidepassword(path))
3713 return
3714 return
3714 if not ui.quiet:
3715 if not ui.quiet:
3715 ui.warn(_("not found!\n"))
3716 ui.warn(_("not found!\n"))
3716 return 1
3717 return 1
3717 else:
3718 else:
3718 for name, path in ui.configitems("paths"):
3719 for name, path in ui.configitems("paths"):
3719 if ui.quiet:
3720 if ui.quiet:
3720 ui.write("%s\n" % name)
3721 ui.write("%s\n" % name)
3721 else:
3722 else:
3722 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3723 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3723
3724
3724 def postincoming(ui, repo, modheads, optupdate, checkout):
3725 def postincoming(ui, repo, modheads, optupdate, checkout):
3725 if modheads == 0:
3726 if modheads == 0:
3726 return
3727 return
3727 if optupdate:
3728 if optupdate:
3728 try:
3729 try:
3729 return hg.update(repo, checkout)
3730 return hg.update(repo, checkout)
3730 except util.Abort, inst:
3731 except util.Abort, inst:
3731 ui.warn(_("not updating: %s\n" % str(inst)))
3732 ui.warn(_("not updating: %s\n" % str(inst)))
3732 return 0
3733 return 0
3733 if modheads > 1:
3734 if modheads > 1:
3734 currentbranchheads = len(repo.branchheads())
3735 currentbranchheads = len(repo.branchheads())
3735 if currentbranchheads == modheads:
3736 if currentbranchheads == modheads:
3736 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3737 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3737 elif currentbranchheads > 1:
3738 elif currentbranchheads > 1:
3738 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3739 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3739 else:
3740 else:
3740 ui.status(_("(run 'hg heads' to see heads)\n"))
3741 ui.status(_("(run 'hg heads' to see heads)\n"))
3741 else:
3742 else:
3742 ui.status(_("(run 'hg update' to get a working copy)\n"))
3743 ui.status(_("(run 'hg update' to get a working copy)\n"))
3743
3744
3744 @command('^pull',
3745 @command('^pull',
3745 [('u', 'update', None,
3746 [('u', 'update', None,
3746 _('update to new branch head if changesets were pulled')),
3747 _('update to new branch head if changesets were pulled')),
3747 ('f', 'force', None, _('run even when remote repository is unrelated')),
3748 ('f', 'force', None, _('run even when remote repository is unrelated')),
3748 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3749 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3749 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3750 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3750 ('b', 'branch', [], _('a specific branch you would like to pull'),
3751 ('b', 'branch', [], _('a specific branch you would like to pull'),
3751 _('BRANCH')),
3752 _('BRANCH')),
3752 ] + remoteopts,
3753 ] + remoteopts,
3753 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3754 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3754 def pull(ui, repo, source="default", **opts):
3755 def pull(ui, repo, source="default", **opts):
3755 """pull changes from the specified source
3756 """pull changes from the specified source
3756
3757
3757 Pull changes from a remote repository to a local one.
3758 Pull changes from a remote repository to a local one.
3758
3759
3759 This finds all changes from the repository at the specified path
3760 This finds all changes from the repository at the specified path
3760 or URL and adds them to a local repository (the current one unless
3761 or URL and adds them to a local repository (the current one unless
3761 -R is specified). By default, this does not update the copy of the
3762 -R is specified). By default, this does not update the copy of the
3762 project in the working directory.
3763 project in the working directory.
3763
3764
3764 Use :hg:`incoming` if you want to see what would have been added
3765 Use :hg:`incoming` if you want to see what would have been added
3765 by a pull at the time you issued this command. If you then decide
3766 by a pull at the time you issued this command. If you then decide
3766 to add those changes to the repository, you should use :hg:`pull
3767 to add those changes to the repository, you should use :hg:`pull
3767 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3768 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3768
3769
3769 If SOURCE is omitted, the 'default' path will be used.
3770 If SOURCE is omitted, the 'default' path will be used.
3770 See :hg:`help urls` for more information.
3771 See :hg:`help urls` for more information.
3771
3772
3772 Returns 0 on success, 1 if an update had unresolved files.
3773 Returns 0 on success, 1 if an update had unresolved files.
3773 """
3774 """
3774 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3775 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3775 other = hg.peer(repo, opts, source)
3776 other = hg.peer(repo, opts, source)
3776 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3777 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3777 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3778 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3778
3779
3779 if opts.get('bookmark'):
3780 if opts.get('bookmark'):
3780 if not revs:
3781 if not revs:
3781 revs = []
3782 revs = []
3782 rb = other.listkeys('bookmarks')
3783 rb = other.listkeys('bookmarks')
3783 for b in opts['bookmark']:
3784 for b in opts['bookmark']:
3784 if b not in rb:
3785 if b not in rb:
3785 raise util.Abort(_('remote bookmark %s not found!') % b)
3786 raise util.Abort(_('remote bookmark %s not found!') % b)
3786 revs.append(rb[b])
3787 revs.append(rb[b])
3787
3788
3788 if revs:
3789 if revs:
3789 try:
3790 try:
3790 revs = [other.lookup(rev) for rev in revs]
3791 revs = [other.lookup(rev) for rev in revs]
3791 except error.CapabilityError:
3792 except error.CapabilityError:
3792 err = _("other repository doesn't support revision lookup, "
3793 err = _("other repository doesn't support revision lookup, "
3793 "so a rev cannot be specified.")
3794 "so a rev cannot be specified.")
3794 raise util.Abort(err)
3795 raise util.Abort(err)
3795
3796
3796 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3797 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3797 bookmarks.updatefromremote(ui, repo, other)
3798 bookmarks.updatefromremote(ui, repo, other)
3798 if checkout:
3799 if checkout:
3799 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3800 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3800 repo._subtoppath = source
3801 repo._subtoppath = source
3801 try:
3802 try:
3802 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3803 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3803
3804
3804 finally:
3805 finally:
3805 del repo._subtoppath
3806 del repo._subtoppath
3806
3807
3807 # update specified bookmarks
3808 # update specified bookmarks
3808 if opts.get('bookmark'):
3809 if opts.get('bookmark'):
3809 for b in opts['bookmark']:
3810 for b in opts['bookmark']:
3810 # explicit pull overrides local bookmark if any
3811 # explicit pull overrides local bookmark if any
3811 ui.status(_("importing bookmark %s\n") % b)
3812 ui.status(_("importing bookmark %s\n") % b)
3812 repo._bookmarks[b] = repo[rb[b]].node()
3813 repo._bookmarks[b] = repo[rb[b]].node()
3813 bookmarks.write(repo)
3814 bookmarks.write(repo)
3814
3815
3815 return ret
3816 return ret
3816
3817
3817 @command('^push',
3818 @command('^push',
3818 [('f', 'force', None, _('force push')),
3819 [('f', 'force', None, _('force push')),
3819 ('r', 'rev', [],
3820 ('r', 'rev', [],
3820 _('a changeset intended to be included in the destination'),
3821 _('a changeset intended to be included in the destination'),
3821 _('REV')),
3822 _('REV')),
3822 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3823 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3823 ('b', 'branch', [],
3824 ('b', 'branch', [],
3824 _('a specific branch you would like to push'), _('BRANCH')),
3825 _('a specific branch you would like to push'), _('BRANCH')),
3825 ('', 'new-branch', False, _('allow pushing a new branch')),
3826 ('', 'new-branch', False, _('allow pushing a new branch')),
3826 ] + remoteopts,
3827 ] + remoteopts,
3827 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3828 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3828 def push(ui, repo, dest=None, **opts):
3829 def push(ui, repo, dest=None, **opts):
3829 """push changes to the specified destination
3830 """push changes to the specified destination
3830
3831
3831 Push changesets from the local repository to the specified
3832 Push changesets from the local repository to the specified
3832 destination.
3833 destination.
3833
3834
3834 This operation is symmetrical to pull: it is identical to a pull
3835 This operation is symmetrical to pull: it is identical to a pull
3835 in the destination repository from the current one.
3836 in the destination repository from the current one.
3836
3837
3837 By default, push will not allow creation of new heads at the
3838 By default, push will not allow creation of new heads at the
3838 destination, since multiple heads would make it unclear which head
3839 destination, since multiple heads would make it unclear which head
3839 to use. In this situation, it is recommended to pull and merge
3840 to use. In this situation, it is recommended to pull and merge
3840 before pushing.
3841 before pushing.
3841
3842
3842 Use --new-branch if you want to allow push to create a new named
3843 Use --new-branch if you want to allow push to create a new named
3843 branch that is not present at the destination. This allows you to
3844 branch that is not present at the destination. This allows you to
3844 only create a new branch without forcing other changes.
3845 only create a new branch without forcing other changes.
3845
3846
3846 Use -f/--force to override the default behavior and push all
3847 Use -f/--force to override the default behavior and push all
3847 changesets on all branches.
3848 changesets on all branches.
3848
3849
3849 If -r/--rev is used, the specified revision and all its ancestors
3850 If -r/--rev is used, the specified revision and all its ancestors
3850 will be pushed to the remote repository.
3851 will be pushed to the remote repository.
3851
3852
3852 Please see :hg:`help urls` for important details about ``ssh://``
3853 Please see :hg:`help urls` for important details about ``ssh://``
3853 URLs. If DESTINATION is omitted, a default path will be used.
3854 URLs. If DESTINATION is omitted, a default path will be used.
3854
3855
3855 Returns 0 if push was successful, 1 if nothing to push.
3856 Returns 0 if push was successful, 1 if nothing to push.
3856 """
3857 """
3857
3858
3858 if opts.get('bookmark'):
3859 if opts.get('bookmark'):
3859 for b in opts['bookmark']:
3860 for b in opts['bookmark']:
3860 # translate -B options to -r so changesets get pushed
3861 # translate -B options to -r so changesets get pushed
3861 if b in repo._bookmarks:
3862 if b in repo._bookmarks:
3862 opts.setdefault('rev', []).append(b)
3863 opts.setdefault('rev', []).append(b)
3863 else:
3864 else:
3864 # if we try to push a deleted bookmark, translate it to null
3865 # if we try to push a deleted bookmark, translate it to null
3865 # this lets simultaneous -r, -b options continue working
3866 # this lets simultaneous -r, -b options continue working
3866 opts.setdefault('rev', []).append("null")
3867 opts.setdefault('rev', []).append("null")
3867
3868
3868 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3869 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3869 dest, branches = hg.parseurl(dest, opts.get('branch'))
3870 dest, branches = hg.parseurl(dest, opts.get('branch'))
3870 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3871 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3871 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3872 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3872 other = hg.peer(repo, opts, dest)
3873 other = hg.peer(repo, opts, dest)
3873 if revs:
3874 if revs:
3874 revs = [repo.lookup(rev) for rev in revs]
3875 revs = [repo.lookup(rev) for rev in revs]
3875
3876
3876 repo._subtoppath = dest
3877 repo._subtoppath = dest
3877 try:
3878 try:
3878 # push subrepos depth-first for coherent ordering
3879 # push subrepos depth-first for coherent ordering
3879 c = repo['']
3880 c = repo['']
3880 subs = c.substate # only repos that are committed
3881 subs = c.substate # only repos that are committed
3881 for s in sorted(subs):
3882 for s in sorted(subs):
3882 if not c.sub(s).push(opts.get('force')):
3883 if not c.sub(s).push(opts.get('force')):
3883 return False
3884 return False
3884 finally:
3885 finally:
3885 del repo._subtoppath
3886 del repo._subtoppath
3886 result = repo.push(other, opts.get('force'), revs=revs,
3887 result = repo.push(other, opts.get('force'), revs=revs,
3887 newbranch=opts.get('new_branch'))
3888 newbranch=opts.get('new_branch'))
3888
3889
3889 result = (result == 0)
3890 result = (result == 0)
3890
3891
3891 if opts.get('bookmark'):
3892 if opts.get('bookmark'):
3892 rb = other.listkeys('bookmarks')
3893 rb = other.listkeys('bookmarks')
3893 for b in opts['bookmark']:
3894 for b in opts['bookmark']:
3894 # explicit push overrides remote bookmark if any
3895 # explicit push overrides remote bookmark if any
3895 if b in repo._bookmarks:
3896 if b in repo._bookmarks:
3896 ui.status(_("exporting bookmark %s\n") % b)
3897 ui.status(_("exporting bookmark %s\n") % b)
3897 new = repo[b].hex()
3898 new = repo[b].hex()
3898 elif b in rb:
3899 elif b in rb:
3899 ui.status(_("deleting remote bookmark %s\n") % b)
3900 ui.status(_("deleting remote bookmark %s\n") % b)
3900 new = '' # delete
3901 new = '' # delete
3901 else:
3902 else:
3902 ui.warn(_('bookmark %s does not exist on the local '
3903 ui.warn(_('bookmark %s does not exist on the local '
3903 'or remote repository!\n') % b)
3904 'or remote repository!\n') % b)
3904 return 2
3905 return 2
3905 old = rb.get(b, '')
3906 old = rb.get(b, '')
3906 r = other.pushkey('bookmarks', b, old, new)
3907 r = other.pushkey('bookmarks', b, old, new)
3907 if not r:
3908 if not r:
3908 ui.warn(_('updating bookmark %s failed!\n') % b)
3909 ui.warn(_('updating bookmark %s failed!\n') % b)
3909 if not result:
3910 if not result:
3910 result = 2
3911 result = 2
3911
3912
3912 return result
3913 return result
3913
3914
3914 @command('recover', [])
3915 @command('recover', [])
3915 def recover(ui, repo):
3916 def recover(ui, repo):
3916 """roll back an interrupted transaction
3917 """roll back an interrupted transaction
3917
3918
3918 Recover from an interrupted commit or pull.
3919 Recover from an interrupted commit or pull.
3919
3920
3920 This command tries to fix the repository status after an
3921 This command tries to fix the repository status after an
3921 interrupted operation. It should only be necessary when Mercurial
3922 interrupted operation. It should only be necessary when Mercurial
3922 suggests it.
3923 suggests it.
3923
3924
3924 Returns 0 if successful, 1 if nothing to recover or verify fails.
3925 Returns 0 if successful, 1 if nothing to recover or verify fails.
3925 """
3926 """
3926 if repo.recover():
3927 if repo.recover():
3927 return hg.verify(repo)
3928 return hg.verify(repo)
3928 return 1
3929 return 1
3929
3930
3930 @command('^remove|rm',
3931 @command('^remove|rm',
3931 [('A', 'after', None, _('record delete for missing files')),
3932 [('A', 'after', None, _('record delete for missing files')),
3932 ('f', 'force', None,
3933 ('f', 'force', None,
3933 _('remove (and delete) file even if added or modified')),
3934 _('remove (and delete) file even if added or modified')),
3934 ] + walkopts,
3935 ] + walkopts,
3935 _('[OPTION]... FILE...'))
3936 _('[OPTION]... FILE...'))
3936 def remove(ui, repo, *pats, **opts):
3937 def remove(ui, repo, *pats, **opts):
3937 """remove the specified files on the next commit
3938 """remove the specified files on the next commit
3938
3939
3939 Schedule the indicated files for removal from the repository.
3940 Schedule the indicated files for removal from the repository.
3940
3941
3941 This only removes files from the current branch, not from the
3942 This only removes files from the current branch, not from the
3942 entire project history. -A/--after can be used to remove only
3943 entire project history. -A/--after can be used to remove only
3943 files that have already been deleted, -f/--force can be used to
3944 files that have already been deleted, -f/--force can be used to
3944 force deletion, and -Af can be used to remove files from the next
3945 force deletion, and -Af can be used to remove files from the next
3945 revision without deleting them from the working directory.
3946 revision without deleting them from the working directory.
3946
3947
3947 The following table details the behavior of remove for different
3948 The following table details the behavior of remove for different
3948 file states (columns) and option combinations (rows). The file
3949 file states (columns) and option combinations (rows). The file
3949 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3950 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3950 reported by :hg:`status`). The actions are Warn, Remove (from
3951 reported by :hg:`status`). The actions are Warn, Remove (from
3951 branch) and Delete (from disk)::
3952 branch) and Delete (from disk)::
3952
3953
3953 A C M !
3954 A C M !
3954 none W RD W R
3955 none W RD W R
3955 -f R RD RD R
3956 -f R RD RD R
3956 -A W W W R
3957 -A W W W R
3957 -Af R R R R
3958 -Af R R R R
3958
3959
3959 Note that remove never deletes files in Added [A] state from the
3960 Note that remove never deletes files in Added [A] state from the
3960 working directory, not even if option --force is specified.
3961 working directory, not even if option --force is specified.
3961
3962
3962 This command schedules the files to be removed at the next commit.
3963 This command schedules the files to be removed at the next commit.
3963 To undo a remove before that, see :hg:`revert`.
3964 To undo a remove before that, see :hg:`revert`.
3964
3965
3965 Returns 0 on success, 1 if any warnings encountered.
3966 Returns 0 on success, 1 if any warnings encountered.
3966 """
3967 """
3967
3968
3968 ret = 0
3969 ret = 0
3969 after, force = opts.get('after'), opts.get('force')
3970 after, force = opts.get('after'), opts.get('force')
3970 if not pats and not after:
3971 if not pats and not after:
3971 raise util.Abort(_('no files specified'))
3972 raise util.Abort(_('no files specified'))
3972
3973
3973 m = scmutil.match(repo[None], pats, opts)
3974 m = scmutil.match(repo[None], pats, opts)
3974 s = repo.status(match=m, clean=True)
3975 s = repo.status(match=m, clean=True)
3975 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3976 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3976
3977
3977 for f in m.files():
3978 for f in m.files():
3978 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3979 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3979 if os.path.exists(m.rel(f)):
3980 if os.path.exists(m.rel(f)):
3980 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3981 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3981 ret = 1
3982 ret = 1
3982
3983
3983 if force:
3984 if force:
3984 list = modified + deleted + clean + added
3985 list = modified + deleted + clean + added
3985 elif after:
3986 elif after:
3986 list = deleted
3987 list = deleted
3987 for f in modified + added + clean:
3988 for f in modified + added + clean:
3988 ui.warn(_('not removing %s: file still exists (use -f'
3989 ui.warn(_('not removing %s: file still exists (use -f'
3989 ' to force removal)\n') % m.rel(f))
3990 ' to force removal)\n') % m.rel(f))
3990 ret = 1
3991 ret = 1
3991 else:
3992 else:
3992 list = deleted + clean
3993 list = deleted + clean
3993 for f in modified:
3994 for f in modified:
3994 ui.warn(_('not removing %s: file is modified (use -f'
3995 ui.warn(_('not removing %s: file is modified (use -f'
3995 ' to force removal)\n') % m.rel(f))
3996 ' to force removal)\n') % m.rel(f))
3996 ret = 1
3997 ret = 1
3997 for f in added:
3998 for f in added:
3998 ui.warn(_('not removing %s: file has been marked for add (use -f'
3999 ui.warn(_('not removing %s: file has been marked for add (use -f'
3999 ' to force removal)\n') % m.rel(f))
4000 ' to force removal)\n') % m.rel(f))
4000 ret = 1
4001 ret = 1
4001
4002
4002 for f in sorted(list):
4003 for f in sorted(list):
4003 if ui.verbose or not m.exact(f):
4004 if ui.verbose or not m.exact(f):
4004 ui.status(_('removing %s\n') % m.rel(f))
4005 ui.status(_('removing %s\n') % m.rel(f))
4005
4006
4006 wlock = repo.wlock()
4007 wlock = repo.wlock()
4007 try:
4008 try:
4008 if not after:
4009 if not after:
4009 for f in list:
4010 for f in list:
4010 if f in added:
4011 if f in added:
4011 continue # we never unlink added files on remove
4012 continue # we never unlink added files on remove
4012 try:
4013 try:
4013 util.unlinkpath(repo.wjoin(f))
4014 util.unlinkpath(repo.wjoin(f))
4014 except OSError, inst:
4015 except OSError, inst:
4015 if inst.errno != errno.ENOENT:
4016 if inst.errno != errno.ENOENT:
4016 raise
4017 raise
4017 repo[None].forget(list)
4018 repo[None].forget(list)
4018 finally:
4019 finally:
4019 wlock.release()
4020 wlock.release()
4020
4021
4021 return ret
4022 return ret
4022
4023
4023 @command('rename|move|mv',
4024 @command('rename|move|mv',
4024 [('A', 'after', None, _('record a rename that has already occurred')),
4025 [('A', 'after', None, _('record a rename that has already occurred')),
4025 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4026 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4026 ] + walkopts + dryrunopts,
4027 ] + walkopts + dryrunopts,
4027 _('[OPTION]... SOURCE... DEST'))
4028 _('[OPTION]... SOURCE... DEST'))
4028 def rename(ui, repo, *pats, **opts):
4029 def rename(ui, repo, *pats, **opts):
4029 """rename files; equivalent of copy + remove
4030 """rename files; equivalent of copy + remove
4030
4031
4031 Mark dest as copies of sources; mark sources for deletion. If dest
4032 Mark dest as copies of sources; mark sources for deletion. If dest
4032 is a directory, copies are put in that directory. If dest is a
4033 is a directory, copies are put in that directory. If dest is a
4033 file, there can only be one source.
4034 file, there can only be one source.
4034
4035
4035 By default, this command copies the contents of files as they
4036 By default, this command copies the contents of files as they
4036 exist in the working directory. If invoked with -A/--after, the
4037 exist in the working directory. If invoked with -A/--after, the
4037 operation is recorded, but no copying is performed.
4038 operation is recorded, but no copying is performed.
4038
4039
4039 This command takes effect at the next commit. To undo a rename
4040 This command takes effect at the next commit. To undo a rename
4040 before that, see :hg:`revert`.
4041 before that, see :hg:`revert`.
4041
4042
4042 Returns 0 on success, 1 if errors are encountered.
4043 Returns 0 on success, 1 if errors are encountered.
4043 """
4044 """
4044 wlock = repo.wlock(False)
4045 wlock = repo.wlock(False)
4045 try:
4046 try:
4046 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4047 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4047 finally:
4048 finally:
4048 wlock.release()
4049 wlock.release()
4049
4050
4050 @command('resolve',
4051 @command('resolve',
4051 [('a', 'all', None, _('select all unresolved files')),
4052 [('a', 'all', None, _('select all unresolved files')),
4052 ('l', 'list', None, _('list state of files needing merge')),
4053 ('l', 'list', None, _('list state of files needing merge')),
4053 ('m', 'mark', None, _('mark files as resolved')),
4054 ('m', 'mark', None, _('mark files as resolved')),
4054 ('u', 'unmark', None, _('mark files as unresolved')),
4055 ('u', 'unmark', None, _('mark files as unresolved')),
4055 ('n', 'no-status', None, _('hide status prefix'))]
4056 ('n', 'no-status', None, _('hide status prefix'))]
4056 + mergetoolopts + walkopts,
4057 + mergetoolopts + walkopts,
4057 _('[OPTION]... [FILE]...'))
4058 _('[OPTION]... [FILE]...'))
4058 def resolve(ui, repo, *pats, **opts):
4059 def resolve(ui, repo, *pats, **opts):
4059 """redo merges or set/view the merge status of files
4060 """redo merges or set/view the merge status of files
4060
4061
4061 Merges with unresolved conflicts are often the result of
4062 Merges with unresolved conflicts are often the result of
4062 non-interactive merging using the ``internal:merge`` configuration
4063 non-interactive merging using the ``internal:merge`` configuration
4063 setting, or a command-line merge tool like ``diff3``. The resolve
4064 setting, or a command-line merge tool like ``diff3``. The resolve
4064 command is used to manage the files involved in a merge, after
4065 command is used to manage the files involved in a merge, after
4065 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4066 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4066 working directory must have two parents).
4067 working directory must have two parents).
4067
4068
4068 The resolve command can be used in the following ways:
4069 The resolve command can be used in the following ways:
4069
4070
4070 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4071 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4071 files, discarding any previous merge attempts. Re-merging is not
4072 files, discarding any previous merge attempts. Re-merging is not
4072 performed for files already marked as resolved. Use ``--all/-a``
4073 performed for files already marked as resolved. Use ``--all/-a``
4073 to selects all unresolved files. ``--tool`` can be used to specify
4074 to selects all unresolved files. ``--tool`` can be used to specify
4074 the merge tool used for the given files. It overrides the HGMERGE
4075 the merge tool used for the given files. It overrides the HGMERGE
4075 environment variable and your configuration files.
4076 environment variable and your configuration files.
4076
4077
4077 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4078 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4078 (e.g. after having manually fixed-up the files). The default is
4079 (e.g. after having manually fixed-up the files). The default is
4079 to mark all unresolved files.
4080 to mark all unresolved files.
4080
4081
4081 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4082 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4082 default is to mark all resolved files.
4083 default is to mark all resolved files.
4083
4084
4084 - :hg:`resolve -l`: list files which had or still have conflicts.
4085 - :hg:`resolve -l`: list files which had or still have conflicts.
4085 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4086 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4086
4087
4087 Note that Mercurial will not let you commit files with unresolved
4088 Note that Mercurial will not let you commit files with unresolved
4088 merge conflicts. You must use :hg:`resolve -m ...` before you can
4089 merge conflicts. You must use :hg:`resolve -m ...` before you can
4089 commit after a conflicting merge.
4090 commit after a conflicting merge.
4090
4091
4091 Returns 0 on success, 1 if any files fail a resolve attempt.
4092 Returns 0 on success, 1 if any files fail a resolve attempt.
4092 """
4093 """
4093
4094
4094 all, mark, unmark, show, nostatus = \
4095 all, mark, unmark, show, nostatus = \
4095 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4096 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4096
4097
4097 if (show and (mark or unmark)) or (mark and unmark):
4098 if (show and (mark or unmark)) or (mark and unmark):
4098 raise util.Abort(_("too many options specified"))
4099 raise util.Abort(_("too many options specified"))
4099 if pats and all:
4100 if pats and all:
4100 raise util.Abort(_("can't specify --all and patterns"))
4101 raise util.Abort(_("can't specify --all and patterns"))
4101 if not (all or pats or show or mark or unmark):
4102 if not (all or pats or show or mark or unmark):
4102 raise util.Abort(_('no files or directories specified; '
4103 raise util.Abort(_('no files or directories specified; '
4103 'use --all to remerge all files'))
4104 'use --all to remerge all files'))
4104
4105
4105 ms = mergemod.mergestate(repo)
4106 ms = mergemod.mergestate(repo)
4106 m = scmutil.match(repo[None], pats, opts)
4107 m = scmutil.match(repo[None], pats, opts)
4107 ret = 0
4108 ret = 0
4108
4109
4109 for f in ms:
4110 for f in ms:
4110 if m(f):
4111 if m(f):
4111 if show:
4112 if show:
4112 if nostatus:
4113 if nostatus:
4113 ui.write("%s\n" % f)
4114 ui.write("%s\n" % f)
4114 else:
4115 else:
4115 ui.write("%s %s\n" % (ms[f].upper(), f),
4116 ui.write("%s %s\n" % (ms[f].upper(), f),
4116 label='resolve.' +
4117 label='resolve.' +
4117 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4118 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4118 elif mark:
4119 elif mark:
4119 ms.mark(f, "r")
4120 ms.mark(f, "r")
4120 elif unmark:
4121 elif unmark:
4121 ms.mark(f, "u")
4122 ms.mark(f, "u")
4122 else:
4123 else:
4123 wctx = repo[None]
4124 wctx = repo[None]
4124 mctx = wctx.parents()[-1]
4125 mctx = wctx.parents()[-1]
4125
4126
4126 # backup pre-resolve (merge uses .orig for its own purposes)
4127 # backup pre-resolve (merge uses .orig for its own purposes)
4127 a = repo.wjoin(f)
4128 a = repo.wjoin(f)
4128 util.copyfile(a, a + ".resolve")
4129 util.copyfile(a, a + ".resolve")
4129
4130
4130 try:
4131 try:
4131 # resolve file
4132 # resolve file
4132 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4133 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4133 if ms.resolve(f, wctx, mctx):
4134 if ms.resolve(f, wctx, mctx):
4134 ret = 1
4135 ret = 1
4135 finally:
4136 finally:
4136 ui.setconfig('ui', 'forcemerge', '')
4137 ui.setconfig('ui', 'forcemerge', '')
4137
4138
4138 # replace filemerge's .orig file with our resolve file
4139 # replace filemerge's .orig file with our resolve file
4139 util.rename(a + ".resolve", a + ".orig")
4140 util.rename(a + ".resolve", a + ".orig")
4140
4141
4141 ms.commit()
4142 ms.commit()
4142 return ret
4143 return ret
4143
4144
4144 @command('revert',
4145 @command('revert',
4145 [('a', 'all', None, _('revert all changes when no arguments given')),
4146 [('a', 'all', None, _('revert all changes when no arguments given')),
4146 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4147 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4147 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4148 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4148 ('', 'no-backup', None, _('do not save backup copies of files')),
4149 ('', 'no-backup', None, _('do not save backup copies of files')),
4149 ] + walkopts + dryrunopts,
4150 ] + walkopts + dryrunopts,
4150 _('[OPTION]... [-r REV] [NAME]...'))
4151 _('[OPTION]... [-r REV] [NAME]...'))
4151 def revert(ui, repo, *pats, **opts):
4152 def revert(ui, repo, *pats, **opts):
4152 """restore files to their checkout state
4153 """restore files to their checkout state
4153
4154
4154 .. note::
4155 .. note::
4155 To check out earlier revisions, you should use :hg:`update REV`.
4156 To check out earlier revisions, you should use :hg:`update REV`.
4156 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4157 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4157
4158
4158 With no revision specified, revert the specified files or directories
4159 With no revision specified, revert the specified files or directories
4159 to the contents they had in the parent of the working directory.
4160 to the contents they had in the parent of the working directory.
4160 This restores the contents of files to an unmodified
4161 This restores the contents of files to an unmodified
4161 state and unschedules adds, removes, copies, and renames. If the
4162 state and unschedules adds, removes, copies, and renames. If the
4162 working directory has two parents, you must explicitly specify a
4163 working directory has two parents, you must explicitly specify a
4163 revision.
4164 revision.
4164
4165
4165 Using the -r/--rev or -d/--date options, revert the given files or
4166 Using the -r/--rev or -d/--date options, revert the given files or
4166 directories to their states as of a specific revision. Because
4167 directories to their states as of a specific revision. Because
4167 revert does not change the working directory parents, this will
4168 revert does not change the working directory parents, this will
4168 cause these files to appear modified. This can be helpful to "back
4169 cause these files to appear modified. This can be helpful to "back
4169 out" some or all of an earlier change. See :hg:`backout` for a
4170 out" some or all of an earlier change. See :hg:`backout` for a
4170 related method.
4171 related method.
4171
4172
4172 Modified files are saved with a .orig suffix before reverting.
4173 Modified files are saved with a .orig suffix before reverting.
4173 To disable these backups, use --no-backup.
4174 To disable these backups, use --no-backup.
4174
4175
4175 See :hg:`help dates` for a list of formats valid for -d/--date.
4176 See :hg:`help dates` for a list of formats valid for -d/--date.
4176
4177
4177 Returns 0 on success.
4178 Returns 0 on success.
4178 """
4179 """
4179
4180
4180 if opts.get("date"):
4181 if opts.get("date"):
4181 if opts.get("rev"):
4182 if opts.get("rev"):
4182 raise util.Abort(_("you can't specify a revision and a date"))
4183 raise util.Abort(_("you can't specify a revision and a date"))
4183 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4184 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4184
4185
4185 parent, p2 = repo.dirstate.parents()
4186 parent, p2 = repo.dirstate.parents()
4186 if not opts.get('rev') and p2 != nullid:
4187 if not opts.get('rev') and p2 != nullid:
4187 # revert after merge is a trap for new users (issue2915)
4188 # revert after merge is a trap for new users (issue2915)
4188 raise util.Abort(_('uncommitted merge with no revision specified'),
4189 raise util.Abort(_('uncommitted merge with no revision specified'),
4189 hint=_('use "hg update" or see "hg help revert"'))
4190 hint=_('use "hg update" or see "hg help revert"'))
4190
4191
4191 ctx = scmutil.revsingle(repo, opts.get('rev'))
4192 ctx = scmutil.revsingle(repo, opts.get('rev'))
4192 node = ctx.node()
4193 node = ctx.node()
4193
4194
4194 if not pats and not opts.get('all'):
4195 if not pats and not opts.get('all'):
4195 msg = _("no files or directories specified")
4196 msg = _("no files or directories specified")
4196 if p2 != nullid:
4197 if p2 != nullid:
4197 hint = _("uncommitted merge, use --all to discard all changes,"
4198 hint = _("uncommitted merge, use --all to discard all changes,"
4198 " or 'hg update -C .' to abort the merge")
4199 " or 'hg update -C .' to abort the merge")
4199 raise util.Abort(msg, hint=hint)
4200 raise util.Abort(msg, hint=hint)
4200 dirty = util.any(repo.status())
4201 dirty = util.any(repo.status())
4201 if node != parent:
4202 if node != parent:
4202 if dirty:
4203 if dirty:
4203 hint = _("uncommitted changes, use --all to discard all"
4204 hint = _("uncommitted changes, use --all to discard all"
4204 " changes, or 'hg update %s' to update") % ctx.rev()
4205 " changes, or 'hg update %s' to update") % ctx.rev()
4205 else:
4206 else:
4206 hint = _("use --all to revert all files,"
4207 hint = _("use --all to revert all files,"
4207 " or 'hg update %s' to update") % ctx.rev()
4208 " or 'hg update %s' to update") % ctx.rev()
4208 elif dirty:
4209 elif dirty:
4209 hint = _("uncommitted changes, use --all to discard all changes")
4210 hint = _("uncommitted changes, use --all to discard all changes")
4210 else:
4211 else:
4211 hint = _("use --all to revert all files")
4212 hint = _("use --all to revert all files")
4212 raise util.Abort(msg, hint=hint)
4213 raise util.Abort(msg, hint=hint)
4213
4214
4214 mf = ctx.manifest()
4215 mf = ctx.manifest()
4215 if node == parent:
4216 if node == parent:
4216 pmf = mf
4217 pmf = mf
4217 else:
4218 else:
4218 pmf = None
4219 pmf = None
4219
4220
4220 # need all matching names in dirstate and manifest of target rev,
4221 # need all matching names in dirstate and manifest of target rev,
4221 # so have to walk both. do not print errors if files exist in one
4222 # so have to walk both. do not print errors if files exist in one
4222 # but not other.
4223 # but not other.
4223
4224
4224 names = {}
4225 names = {}
4225
4226
4226 wlock = repo.wlock()
4227 wlock = repo.wlock()
4227 try:
4228 try:
4228 # walk dirstate.
4229 # walk dirstate.
4229
4230
4230 m = scmutil.match(repo[None], pats, opts)
4231 m = scmutil.match(repo[None], pats, opts)
4231 m.bad = lambda x, y: False
4232 m.bad = lambda x, y: False
4232 for abs in repo.walk(m):
4233 for abs in repo.walk(m):
4233 names[abs] = m.rel(abs), m.exact(abs)
4234 names[abs] = m.rel(abs), m.exact(abs)
4234
4235
4235 # walk target manifest.
4236 # walk target manifest.
4236
4237
4237 def badfn(path, msg):
4238 def badfn(path, msg):
4238 if path in names:
4239 if path in names:
4239 return
4240 return
4240 path_ = path + '/'
4241 path_ = path + '/'
4241 for f in names:
4242 for f in names:
4242 if f.startswith(path_):
4243 if f.startswith(path_):
4243 return
4244 return
4244 ui.warn("%s: %s\n" % (m.rel(path), msg))
4245 ui.warn("%s: %s\n" % (m.rel(path), msg))
4245
4246
4246 m = scmutil.match(repo[node], pats, opts)
4247 m = scmutil.match(repo[node], pats, opts)
4247 m.bad = badfn
4248 m.bad = badfn
4248 for abs in repo[node].walk(m):
4249 for abs in repo[node].walk(m):
4249 if abs not in names:
4250 if abs not in names:
4250 names[abs] = m.rel(abs), m.exact(abs)
4251 names[abs] = m.rel(abs), m.exact(abs)
4251
4252
4252 m = scmutil.matchfiles(repo, names)
4253 m = scmutil.matchfiles(repo, names)
4253 changes = repo.status(match=m)[:4]
4254 changes = repo.status(match=m)[:4]
4254 modified, added, removed, deleted = map(set, changes)
4255 modified, added, removed, deleted = map(set, changes)
4255
4256
4256 # if f is a rename, also revert the source
4257 # if f is a rename, also revert the source
4257 cwd = repo.getcwd()
4258 cwd = repo.getcwd()
4258 for f in added:
4259 for f in added:
4259 src = repo.dirstate.copied(f)
4260 src = repo.dirstate.copied(f)
4260 if src and src not in names and repo.dirstate[src] == 'r':
4261 if src and src not in names and repo.dirstate[src] == 'r':
4261 removed.add(src)
4262 removed.add(src)
4262 names[src] = (repo.pathto(src, cwd), True)
4263 names[src] = (repo.pathto(src, cwd), True)
4263
4264
4264 def removeforget(abs):
4265 def removeforget(abs):
4265 if repo.dirstate[abs] == 'a':
4266 if repo.dirstate[abs] == 'a':
4266 return _('forgetting %s\n')
4267 return _('forgetting %s\n')
4267 return _('removing %s\n')
4268 return _('removing %s\n')
4268
4269
4269 revert = ([], _('reverting %s\n'))
4270 revert = ([], _('reverting %s\n'))
4270 add = ([], _('adding %s\n'))
4271 add = ([], _('adding %s\n'))
4271 remove = ([], removeforget)
4272 remove = ([], removeforget)
4272 undelete = ([], _('undeleting %s\n'))
4273 undelete = ([], _('undeleting %s\n'))
4273
4274
4274 disptable = (
4275 disptable = (
4275 # dispatch table:
4276 # dispatch table:
4276 # file state
4277 # file state
4277 # action if in target manifest
4278 # action if in target manifest
4278 # action if not in target manifest
4279 # action if not in target manifest
4279 # make backup if in target manifest
4280 # make backup if in target manifest
4280 # make backup if not in target manifest
4281 # make backup if not in target manifest
4281 (modified, revert, remove, True, True),
4282 (modified, revert, remove, True, True),
4282 (added, revert, remove, True, False),
4283 (added, revert, remove, True, False),
4283 (removed, undelete, None, False, False),
4284 (removed, undelete, None, False, False),
4284 (deleted, revert, remove, False, False),
4285 (deleted, revert, remove, False, False),
4285 )
4286 )
4286
4287
4287 for abs, (rel, exact) in sorted(names.items()):
4288 for abs, (rel, exact) in sorted(names.items()):
4288 mfentry = mf.get(abs)
4289 mfentry = mf.get(abs)
4289 target = repo.wjoin(abs)
4290 target = repo.wjoin(abs)
4290 def handle(xlist, dobackup):
4291 def handle(xlist, dobackup):
4291 xlist[0].append(abs)
4292 xlist[0].append(abs)
4292 if (dobackup and not opts.get('no_backup') and
4293 if (dobackup and not opts.get('no_backup') and
4293 os.path.lexists(target)):
4294 os.path.lexists(target)):
4294 bakname = "%s.orig" % rel
4295 bakname = "%s.orig" % rel
4295 ui.note(_('saving current version of %s as %s\n') %
4296 ui.note(_('saving current version of %s as %s\n') %
4296 (rel, bakname))
4297 (rel, bakname))
4297 if not opts.get('dry_run'):
4298 if not opts.get('dry_run'):
4298 util.rename(target, bakname)
4299 util.rename(target, bakname)
4299 if ui.verbose or not exact:
4300 if ui.verbose or not exact:
4300 msg = xlist[1]
4301 msg = xlist[1]
4301 if not isinstance(msg, basestring):
4302 if not isinstance(msg, basestring):
4302 msg = msg(abs)
4303 msg = msg(abs)
4303 ui.status(msg % rel)
4304 ui.status(msg % rel)
4304 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4305 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4305 if abs not in table:
4306 if abs not in table:
4306 continue
4307 continue
4307 # file has changed in dirstate
4308 # file has changed in dirstate
4308 if mfentry:
4309 if mfentry:
4309 handle(hitlist, backuphit)
4310 handle(hitlist, backuphit)
4310 elif misslist is not None:
4311 elif misslist is not None:
4311 handle(misslist, backupmiss)
4312 handle(misslist, backupmiss)
4312 break
4313 break
4313 else:
4314 else:
4314 if abs not in repo.dirstate:
4315 if abs not in repo.dirstate:
4315 if mfentry:
4316 if mfentry:
4316 handle(add, True)
4317 handle(add, True)
4317 elif exact:
4318 elif exact:
4318 ui.warn(_('file not managed: %s\n') % rel)
4319 ui.warn(_('file not managed: %s\n') % rel)
4319 continue
4320 continue
4320 # file has not changed in dirstate
4321 # file has not changed in dirstate
4321 if node == parent:
4322 if node == parent:
4322 if exact:
4323 if exact:
4323 ui.warn(_('no changes needed to %s\n') % rel)
4324 ui.warn(_('no changes needed to %s\n') % rel)
4324 continue
4325 continue
4325 if pmf is None:
4326 if pmf is None:
4326 # only need parent manifest in this unlikely case,
4327 # only need parent manifest in this unlikely case,
4327 # so do not read by default
4328 # so do not read by default
4328 pmf = repo[parent].manifest()
4329 pmf = repo[parent].manifest()
4329 if abs in pmf:
4330 if abs in pmf:
4330 if mfentry:
4331 if mfentry:
4331 # if version of file is same in parent and target
4332 # if version of file is same in parent and target
4332 # manifests, do nothing
4333 # manifests, do nothing
4333 if (pmf[abs] != mfentry or
4334 if (pmf[abs] != mfentry or
4334 pmf.flags(abs) != mf.flags(abs)):
4335 pmf.flags(abs) != mf.flags(abs)):
4335 handle(revert, False)
4336 handle(revert, False)
4336 else:
4337 else:
4337 handle(remove, False)
4338 handle(remove, False)
4338
4339
4339 if not opts.get('dry_run'):
4340 if not opts.get('dry_run'):
4340 def checkout(f):
4341 def checkout(f):
4341 fc = ctx[f]
4342 fc = ctx[f]
4342 repo.wwrite(f, fc.data(), fc.flags())
4343 repo.wwrite(f, fc.data(), fc.flags())
4343
4344
4344 audit_path = scmutil.pathauditor(repo.root)
4345 audit_path = scmutil.pathauditor(repo.root)
4345 for f in remove[0]:
4346 for f in remove[0]:
4346 if repo.dirstate[f] == 'a':
4347 if repo.dirstate[f] == 'a':
4347 repo.dirstate.drop(f)
4348 repo.dirstate.drop(f)
4348 continue
4349 continue
4349 audit_path(f)
4350 audit_path(f)
4350 try:
4351 try:
4351 util.unlinkpath(repo.wjoin(f))
4352 util.unlinkpath(repo.wjoin(f))
4352 except OSError:
4353 except OSError:
4353 pass
4354 pass
4354 repo.dirstate.remove(f)
4355 repo.dirstate.remove(f)
4355
4356
4356 normal = None
4357 normal = None
4357 if node == parent:
4358 if node == parent:
4358 # We're reverting to our parent. If possible, we'd like status
4359 # We're reverting to our parent. If possible, we'd like status
4359 # to report the file as clean. We have to use normallookup for
4360 # to report the file as clean. We have to use normallookup for
4360 # merges to avoid losing information about merged/dirty files.
4361 # merges to avoid losing information about merged/dirty files.
4361 if p2 != nullid:
4362 if p2 != nullid:
4362 normal = repo.dirstate.normallookup
4363 normal = repo.dirstate.normallookup
4363 else:
4364 else:
4364 normal = repo.dirstate.normal
4365 normal = repo.dirstate.normal
4365 for f in revert[0]:
4366 for f in revert[0]:
4366 checkout(f)
4367 checkout(f)
4367 if normal:
4368 if normal:
4368 normal(f)
4369 normal(f)
4369
4370
4370 for f in add[0]:
4371 for f in add[0]:
4371 checkout(f)
4372 checkout(f)
4372 repo.dirstate.add(f)
4373 repo.dirstate.add(f)
4373
4374
4374 normal = repo.dirstate.normallookup
4375 normal = repo.dirstate.normallookup
4375 if node == parent and p2 == nullid:
4376 if node == parent and p2 == nullid:
4376 normal = repo.dirstate.normal
4377 normal = repo.dirstate.normal
4377 for f in undelete[0]:
4378 for f in undelete[0]:
4378 checkout(f)
4379 checkout(f)
4379 normal(f)
4380 normal(f)
4380
4381
4381 finally:
4382 finally:
4382 wlock.release()
4383 wlock.release()
4383
4384
4384 @command('rollback', dryrunopts)
4385 @command('rollback', dryrunopts)
4385 def rollback(ui, repo, **opts):
4386 def rollback(ui, repo, **opts):
4386 """roll back the last transaction (dangerous)
4387 """roll back the last transaction (dangerous)
4387
4388
4388 This command should be used with care. There is only one level of
4389 This command should be used with care. There is only one level of
4389 rollback, and there is no way to undo a rollback. It will also
4390 rollback, and there is no way to undo a rollback. It will also
4390 restore the dirstate at the time of the last transaction, losing
4391 restore the dirstate at the time of the last transaction, losing
4391 any dirstate changes since that time. This command does not alter
4392 any dirstate changes since that time. This command does not alter
4392 the working directory.
4393 the working directory.
4393
4394
4394 Transactions are used to encapsulate the effects of all commands
4395 Transactions are used to encapsulate the effects of all commands
4395 that create new changesets or propagate existing changesets into a
4396 that create new changesets or propagate existing changesets into a
4396 repository. For example, the following commands are transactional,
4397 repository. For example, the following commands are transactional,
4397 and their effects can be rolled back:
4398 and their effects can be rolled back:
4398
4399
4399 - commit
4400 - commit
4400 - import
4401 - import
4401 - pull
4402 - pull
4402 - push (with this repository as the destination)
4403 - push (with this repository as the destination)
4403 - unbundle
4404 - unbundle
4404
4405
4405 This command is not intended for use on public repositories. Once
4406 This command is not intended for use on public repositories. Once
4406 changes are visible for pull by other users, rolling a transaction
4407 changes are visible for pull by other users, rolling a transaction
4407 back locally is ineffective (someone else may already have pulled
4408 back locally is ineffective (someone else may already have pulled
4408 the changes). Furthermore, a race is possible with readers of the
4409 the changes). Furthermore, a race is possible with readers of the
4409 repository; for example an in-progress pull from the repository
4410 repository; for example an in-progress pull from the repository
4410 may fail if a rollback is performed.
4411 may fail if a rollback is performed.
4411
4412
4412 Returns 0 on success, 1 if no rollback data is available.
4413 Returns 0 on success, 1 if no rollback data is available.
4413 """
4414 """
4414 return repo.rollback(opts.get('dry_run'))
4415 return repo.rollback(opts.get('dry_run'))
4415
4416
4416 @command('root', [])
4417 @command('root', [])
4417 def root(ui, repo):
4418 def root(ui, repo):
4418 """print the root (top) of the current working directory
4419 """print the root (top) of the current working directory
4419
4420
4420 Print the root directory of the current repository.
4421 Print the root directory of the current repository.
4421
4422
4422 Returns 0 on success.
4423 Returns 0 on success.
4423 """
4424 """
4424 ui.write(repo.root + "\n")
4425 ui.write(repo.root + "\n")
4425
4426
4426 @command('^serve',
4427 @command('^serve',
4427 [('A', 'accesslog', '', _('name of access log file to write to'),
4428 [('A', 'accesslog', '', _('name of access log file to write to'),
4428 _('FILE')),
4429 _('FILE')),
4429 ('d', 'daemon', None, _('run server in background')),
4430 ('d', 'daemon', None, _('run server in background')),
4430 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4431 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4431 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4432 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4432 # use string type, then we can check if something was passed
4433 # use string type, then we can check if something was passed
4433 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4434 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4434 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4435 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4435 _('ADDR')),
4436 _('ADDR')),
4436 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4437 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4437 _('PREFIX')),
4438 _('PREFIX')),
4438 ('n', 'name', '',
4439 ('n', 'name', '',
4439 _('name to show in web pages (default: working directory)'), _('NAME')),
4440 _('name to show in web pages (default: working directory)'), _('NAME')),
4440 ('', 'web-conf', '',
4441 ('', 'web-conf', '',
4441 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4442 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4442 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4443 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4443 _('FILE')),
4444 _('FILE')),
4444 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4445 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4445 ('', 'stdio', None, _('for remote clients')),
4446 ('', 'stdio', None, _('for remote clients')),
4446 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4447 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4447 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4448 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4448 ('', 'style', '', _('template style to use'), _('STYLE')),
4449 ('', 'style', '', _('template style to use'), _('STYLE')),
4449 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4450 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4450 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4451 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4451 _('[OPTION]...'))
4452 _('[OPTION]...'))
4452 def serve(ui, repo, **opts):
4453 def serve(ui, repo, **opts):
4453 """start stand-alone webserver
4454 """start stand-alone webserver
4454
4455
4455 Start a local HTTP repository browser and pull server. You can use
4456 Start a local HTTP repository browser and pull server. You can use
4456 this for ad-hoc sharing and browsing of repositories. It is
4457 this for ad-hoc sharing and browsing of repositories. It is
4457 recommended to use a real web server to serve a repository for
4458 recommended to use a real web server to serve a repository for
4458 longer periods of time.
4459 longer periods of time.
4459
4460
4460 Please note that the server does not implement access control.
4461 Please note that the server does not implement access control.
4461 This means that, by default, anybody can read from the server and
4462 This means that, by default, anybody can read from the server and
4462 nobody can write to it by default. Set the ``web.allow_push``
4463 nobody can write to it by default. Set the ``web.allow_push``
4463 option to ``*`` to allow everybody to push to the server. You
4464 option to ``*`` to allow everybody to push to the server. You
4464 should use a real web server if you need to authenticate users.
4465 should use a real web server if you need to authenticate users.
4465
4466
4466 By default, the server logs accesses to stdout and errors to
4467 By default, the server logs accesses to stdout and errors to
4467 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4468 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4468 files.
4469 files.
4469
4470
4470 To have the server choose a free port number to listen on, specify
4471 To have the server choose a free port number to listen on, specify
4471 a port number of 0; in this case, the server will print the port
4472 a port number of 0; in this case, the server will print the port
4472 number it uses.
4473 number it uses.
4473
4474
4474 Returns 0 on success.
4475 Returns 0 on success.
4475 """
4476 """
4476
4477
4477 if opts["stdio"] and opts["cmdserver"]:
4478 if opts["stdio"] and opts["cmdserver"]:
4478 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4479 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4479
4480
4480 def checkrepo():
4481 def checkrepo():
4481 if repo is None:
4482 if repo is None:
4482 raise error.RepoError(_("There is no Mercurial repository here"
4483 raise error.RepoError(_("There is no Mercurial repository here"
4483 " (.hg not found)"))
4484 " (.hg not found)"))
4484
4485
4485 if opts["stdio"]:
4486 if opts["stdio"]:
4486 checkrepo()
4487 checkrepo()
4487 s = sshserver.sshserver(ui, repo)
4488 s = sshserver.sshserver(ui, repo)
4488 s.serve_forever()
4489 s.serve_forever()
4489
4490
4490 if opts["cmdserver"]:
4491 if opts["cmdserver"]:
4491 checkrepo()
4492 checkrepo()
4492 s = commandserver.server(ui, repo, opts["cmdserver"])
4493 s = commandserver.server(ui, repo, opts["cmdserver"])
4493 return s.serve()
4494 return s.serve()
4494
4495
4495 # this way we can check if something was given in the command-line
4496 # this way we can check if something was given in the command-line
4496 if opts.get('port'):
4497 if opts.get('port'):
4497 opts['port'] = util.getport(opts.get('port'))
4498 opts['port'] = util.getport(opts.get('port'))
4498
4499
4499 baseui = repo and repo.baseui or ui
4500 baseui = repo and repo.baseui or ui
4500 optlist = ("name templates style address port prefix ipv6"
4501 optlist = ("name templates style address port prefix ipv6"
4501 " accesslog errorlog certificate encoding")
4502 " accesslog errorlog certificate encoding")
4502 for o in optlist.split():
4503 for o in optlist.split():
4503 val = opts.get(o, '')
4504 val = opts.get(o, '')
4504 if val in (None, ''): # should check against default options instead
4505 if val in (None, ''): # should check against default options instead
4505 continue
4506 continue
4506 baseui.setconfig("web", o, val)
4507 baseui.setconfig("web", o, val)
4507 if repo and repo.ui != baseui:
4508 if repo and repo.ui != baseui:
4508 repo.ui.setconfig("web", o, val)
4509 repo.ui.setconfig("web", o, val)
4509
4510
4510 o = opts.get('web_conf') or opts.get('webdir_conf')
4511 o = opts.get('web_conf') or opts.get('webdir_conf')
4511 if not o:
4512 if not o:
4512 if not repo:
4513 if not repo:
4513 raise error.RepoError(_("There is no Mercurial repository"
4514 raise error.RepoError(_("There is no Mercurial repository"
4514 " here (.hg not found)"))
4515 " here (.hg not found)"))
4515 o = repo.root
4516 o = repo.root
4516
4517
4517 app = hgweb.hgweb(o, baseui=ui)
4518 app = hgweb.hgweb(o, baseui=ui)
4518
4519
4519 class service(object):
4520 class service(object):
4520 def init(self):
4521 def init(self):
4521 util.setsignalhandler()
4522 util.setsignalhandler()
4522 self.httpd = hgweb.server.create_server(ui, app)
4523 self.httpd = hgweb.server.create_server(ui, app)
4523
4524
4524 if opts['port'] and not ui.verbose:
4525 if opts['port'] and not ui.verbose:
4525 return
4526 return
4526
4527
4527 if self.httpd.prefix:
4528 if self.httpd.prefix:
4528 prefix = self.httpd.prefix.strip('/') + '/'
4529 prefix = self.httpd.prefix.strip('/') + '/'
4529 else:
4530 else:
4530 prefix = ''
4531 prefix = ''
4531
4532
4532 port = ':%d' % self.httpd.port
4533 port = ':%d' % self.httpd.port
4533 if port == ':80':
4534 if port == ':80':
4534 port = ''
4535 port = ''
4535
4536
4536 bindaddr = self.httpd.addr
4537 bindaddr = self.httpd.addr
4537 if bindaddr == '0.0.0.0':
4538 if bindaddr == '0.0.0.0':
4538 bindaddr = '*'
4539 bindaddr = '*'
4539 elif ':' in bindaddr: # IPv6
4540 elif ':' in bindaddr: # IPv6
4540 bindaddr = '[%s]' % bindaddr
4541 bindaddr = '[%s]' % bindaddr
4541
4542
4542 fqaddr = self.httpd.fqaddr
4543 fqaddr = self.httpd.fqaddr
4543 if ':' in fqaddr:
4544 if ':' in fqaddr:
4544 fqaddr = '[%s]' % fqaddr
4545 fqaddr = '[%s]' % fqaddr
4545 if opts['port']:
4546 if opts['port']:
4546 write = ui.status
4547 write = ui.status
4547 else:
4548 else:
4548 write = ui.write
4549 write = ui.write
4549 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4550 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4550 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4551 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4551
4552
4552 def run(self):
4553 def run(self):
4553 self.httpd.serve_forever()
4554 self.httpd.serve_forever()
4554
4555
4555 service = service()
4556 service = service()
4556
4557
4557 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4558 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4558
4559
4559 @command('showconfig|debugconfig',
4560 @command('showconfig|debugconfig',
4560 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4561 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4561 _('[-u] [NAME]...'))
4562 _('[-u] [NAME]...'))
4562 def showconfig(ui, repo, *values, **opts):
4563 def showconfig(ui, repo, *values, **opts):
4563 """show combined config settings from all hgrc files
4564 """show combined config settings from all hgrc files
4564
4565
4565 With no arguments, print names and values of all config items.
4566 With no arguments, print names and values of all config items.
4566
4567
4567 With one argument of the form section.name, print just the value
4568 With one argument of the form section.name, print just the value
4568 of that config item.
4569 of that config item.
4569
4570
4570 With multiple arguments, print names and values of all config
4571 With multiple arguments, print names and values of all config
4571 items with matching section names.
4572 items with matching section names.
4572
4573
4573 With --debug, the source (filename and line number) is printed
4574 With --debug, the source (filename and line number) is printed
4574 for each config item.
4575 for each config item.
4575
4576
4576 Returns 0 on success.
4577 Returns 0 on success.
4577 """
4578 """
4578
4579
4579 for f in scmutil.rcpath():
4580 for f in scmutil.rcpath():
4580 ui.debug('read config from: %s\n' % f)
4581 ui.debug('read config from: %s\n' % f)
4581 untrusted = bool(opts.get('untrusted'))
4582 untrusted = bool(opts.get('untrusted'))
4582 if values:
4583 if values:
4583 sections = [v for v in values if '.' not in v]
4584 sections = [v for v in values if '.' not in v]
4584 items = [v for v in values if '.' in v]
4585 items = [v for v in values if '.' in v]
4585 if len(items) > 1 or items and sections:
4586 if len(items) > 1 or items and sections:
4586 raise util.Abort(_('only one config item permitted'))
4587 raise util.Abort(_('only one config item permitted'))
4587 for section, name, value in ui.walkconfig(untrusted=untrusted):
4588 for section, name, value in ui.walkconfig(untrusted=untrusted):
4588 value = str(value).replace('\n', '\\n')
4589 value = str(value).replace('\n', '\\n')
4589 sectname = section + '.' + name
4590 sectname = section + '.' + name
4590 if values:
4591 if values:
4591 for v in values:
4592 for v in values:
4592 if v == section:
4593 if v == section:
4593 ui.debug('%s: ' %
4594 ui.debug('%s: ' %
4594 ui.configsource(section, name, untrusted))
4595 ui.configsource(section, name, untrusted))
4595 ui.write('%s=%s\n' % (sectname, value))
4596 ui.write('%s=%s\n' % (sectname, value))
4596 elif v == sectname:
4597 elif v == sectname:
4597 ui.debug('%s: ' %
4598 ui.debug('%s: ' %
4598 ui.configsource(section, name, untrusted))
4599 ui.configsource(section, name, untrusted))
4599 ui.write(value, '\n')
4600 ui.write(value, '\n')
4600 else:
4601 else:
4601 ui.debug('%s: ' %
4602 ui.debug('%s: ' %
4602 ui.configsource(section, name, untrusted))
4603 ui.configsource(section, name, untrusted))
4603 ui.write('%s=%s\n' % (sectname, value))
4604 ui.write('%s=%s\n' % (sectname, value))
4604
4605
4605 @command('^status|st',
4606 @command('^status|st',
4606 [('A', 'all', None, _('show status of all files')),
4607 [('A', 'all', None, _('show status of all files')),
4607 ('m', 'modified', None, _('show only modified files')),
4608 ('m', 'modified', None, _('show only modified files')),
4608 ('a', 'added', None, _('show only added files')),
4609 ('a', 'added', None, _('show only added files')),
4609 ('r', 'removed', None, _('show only removed files')),
4610 ('r', 'removed', None, _('show only removed files')),
4610 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4611 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4611 ('c', 'clean', None, _('show only files without changes')),
4612 ('c', 'clean', None, _('show only files without changes')),
4612 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4613 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4613 ('i', 'ignored', None, _('show only ignored files')),
4614 ('i', 'ignored', None, _('show only ignored files')),
4614 ('n', 'no-status', None, _('hide status prefix')),
4615 ('n', 'no-status', None, _('hide status prefix')),
4615 ('C', 'copies', None, _('show source of copied files')),
4616 ('C', 'copies', None, _('show source of copied files')),
4616 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4617 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4617 ('', 'rev', [], _('show difference from revision'), _('REV')),
4618 ('', 'rev', [], _('show difference from revision'), _('REV')),
4618 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4619 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4619 ] + walkopts + subrepoopts,
4620 ] + walkopts + subrepoopts,
4620 _('[OPTION]... [FILE]...'))
4621 _('[OPTION]... [FILE]...'))
4621 def status(ui, repo, *pats, **opts):
4622 def status(ui, repo, *pats, **opts):
4622 """show changed files in the working directory
4623 """show changed files in the working directory
4623
4624
4624 Show status of files in the repository. If names are given, only
4625 Show status of files in the repository. If names are given, only
4625 files that match are shown. Files that are clean or ignored or
4626 files that match are shown. Files that are clean or ignored or
4626 the source of a copy/move operation, are not listed unless
4627 the source of a copy/move operation, are not listed unless
4627 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4628 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4628 Unless options described with "show only ..." are given, the
4629 Unless options described with "show only ..." are given, the
4629 options -mardu are used.
4630 options -mardu are used.
4630
4631
4631 Option -q/--quiet hides untracked (unknown and ignored) files
4632 Option -q/--quiet hides untracked (unknown and ignored) files
4632 unless explicitly requested with -u/--unknown or -i/--ignored.
4633 unless explicitly requested with -u/--unknown or -i/--ignored.
4633
4634
4634 .. note::
4635 .. note::
4635 status may appear to disagree with diff if permissions have
4636 status may appear to disagree with diff if permissions have
4636 changed or a merge has occurred. The standard diff format does
4637 changed or a merge has occurred. The standard diff format does
4637 not report permission changes and diff only reports changes
4638 not report permission changes and diff only reports changes
4638 relative to one merge parent.
4639 relative to one merge parent.
4639
4640
4640 If one revision is given, it is used as the base revision.
4641 If one revision is given, it is used as the base revision.
4641 If two revisions are given, the differences between them are
4642 If two revisions are given, the differences between them are
4642 shown. The --change option can also be used as a shortcut to list
4643 shown. The --change option can also be used as a shortcut to list
4643 the changed files of a revision from its first parent.
4644 the changed files of a revision from its first parent.
4644
4645
4645 The codes used to show the status of files are::
4646 The codes used to show the status of files are::
4646
4647
4647 M = modified
4648 M = modified
4648 A = added
4649 A = added
4649 R = removed
4650 R = removed
4650 C = clean
4651 C = clean
4651 ! = missing (deleted by non-hg command, but still tracked)
4652 ! = missing (deleted by non-hg command, but still tracked)
4652 ? = not tracked
4653 ? = not tracked
4653 I = ignored
4654 I = ignored
4654 = origin of the previous file listed as A (added)
4655 = origin of the previous file listed as A (added)
4655
4656
4656 Returns 0 on success.
4657 Returns 0 on success.
4657 """
4658 """
4658
4659
4659 revs = opts.get('rev')
4660 revs = opts.get('rev')
4660 change = opts.get('change')
4661 change = opts.get('change')
4661
4662
4662 if revs and change:
4663 if revs and change:
4663 msg = _('cannot specify --rev and --change at the same time')
4664 msg = _('cannot specify --rev and --change at the same time')
4664 raise util.Abort(msg)
4665 raise util.Abort(msg)
4665 elif change:
4666 elif change:
4666 node2 = repo.lookup(change)
4667 node2 = repo.lookup(change)
4667 node1 = repo[node2].p1().node()
4668 node1 = repo[node2].p1().node()
4668 else:
4669 else:
4669 node1, node2 = scmutil.revpair(repo, revs)
4670 node1, node2 = scmutil.revpair(repo, revs)
4670
4671
4671 cwd = (pats and repo.getcwd()) or ''
4672 cwd = (pats and repo.getcwd()) or ''
4672 end = opts.get('print0') and '\0' or '\n'
4673 end = opts.get('print0') and '\0' or '\n'
4673 copy = {}
4674 copy = {}
4674 states = 'modified added removed deleted unknown ignored clean'.split()
4675 states = 'modified added removed deleted unknown ignored clean'.split()
4675 show = [k for k in states if opts.get(k)]
4676 show = [k for k in states if opts.get(k)]
4676 if opts.get('all'):
4677 if opts.get('all'):
4677 show += ui.quiet and (states[:4] + ['clean']) or states
4678 show += ui.quiet and (states[:4] + ['clean']) or states
4678 if not show:
4679 if not show:
4679 show = ui.quiet and states[:4] or states[:5]
4680 show = ui.quiet and states[:4] or states[:5]
4680
4681
4681 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4682 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4682 'ignored' in show, 'clean' in show, 'unknown' in show,
4683 'ignored' in show, 'clean' in show, 'unknown' in show,
4683 opts.get('subrepos'))
4684 opts.get('subrepos'))
4684 changestates = zip(states, 'MAR!?IC', stat)
4685 changestates = zip(states, 'MAR!?IC', stat)
4685
4686
4686 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4687 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4687 ctxn = repo[nullid]
4688 ctxn = repo[nullid]
4688 ctx1 = repo[node1]
4689 ctx1 = repo[node1]
4689 ctx2 = repo[node2]
4690 ctx2 = repo[node2]
4690 added = stat[1]
4691 added = stat[1]
4691 if node2 is None:
4692 if node2 is None:
4692 added = stat[0] + stat[1] # merged?
4693 added = stat[0] + stat[1] # merged?
4693
4694
4694 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4695 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4695 if k in added:
4696 if k in added:
4696 copy[k] = v
4697 copy[k] = v
4697 elif v in added:
4698 elif v in added:
4698 copy[v] = k
4699 copy[v] = k
4699
4700
4700 for state, char, files in changestates:
4701 for state, char, files in changestates:
4701 if state in show:
4702 if state in show:
4702 format = "%s %%s%s" % (char, end)
4703 format = "%s %%s%s" % (char, end)
4703 if opts.get('no_status'):
4704 if opts.get('no_status'):
4704 format = "%%s%s" % end
4705 format = "%%s%s" % end
4705
4706
4706 for f in files:
4707 for f in files:
4707 ui.write(format % repo.pathto(f, cwd),
4708 ui.write(format % repo.pathto(f, cwd),
4708 label='status.' + state)
4709 label='status.' + state)
4709 if f in copy:
4710 if f in copy:
4710 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4711 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4711 label='status.copied')
4712 label='status.copied')
4712
4713
4713 @command('^summary|sum',
4714 @command('^summary|sum',
4714 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4715 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4715 def summary(ui, repo, **opts):
4716 def summary(ui, repo, **opts):
4716 """summarize working directory state
4717 """summarize working directory state
4717
4718
4718 This generates a brief summary of the working directory state,
4719 This generates a brief summary of the working directory state,
4719 including parents, branch, commit status, and available updates.
4720 including parents, branch, commit status, and available updates.
4720
4721
4721 With the --remote option, this will check the default paths for
4722 With the --remote option, this will check the default paths for
4722 incoming and outgoing changes. This can be time-consuming.
4723 incoming and outgoing changes. This can be time-consuming.
4723
4724
4724 Returns 0 on success.
4725 Returns 0 on success.
4725 """
4726 """
4726
4727
4727 ctx = repo[None]
4728 ctx = repo[None]
4728 parents = ctx.parents()
4729 parents = ctx.parents()
4729 pnode = parents[0].node()
4730 pnode = parents[0].node()
4730 marks = []
4731 marks = []
4731
4732
4732 for p in parents:
4733 for p in parents:
4733 # label with log.changeset (instead of log.parent) since this
4734 # label with log.changeset (instead of log.parent) since this
4734 # shows a working directory parent *changeset*:
4735 # shows a working directory parent *changeset*:
4735 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4736 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4736 label='log.changeset')
4737 label='log.changeset')
4737 ui.write(' '.join(p.tags()), label='log.tag')
4738 ui.write(' '.join(p.tags()), label='log.tag')
4738 if p.bookmarks():
4739 if p.bookmarks():
4739 marks.extend(p.bookmarks())
4740 marks.extend(p.bookmarks())
4740 if p.rev() == -1:
4741 if p.rev() == -1:
4741 if not len(repo):
4742 if not len(repo):
4742 ui.write(_(' (empty repository)'))
4743 ui.write(_(' (empty repository)'))
4743 else:
4744 else:
4744 ui.write(_(' (no revision checked out)'))
4745 ui.write(_(' (no revision checked out)'))
4745 ui.write('\n')
4746 ui.write('\n')
4746 if p.description():
4747 if p.description():
4747 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4748 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4748 label='log.summary')
4749 label='log.summary')
4749
4750
4750 branch = ctx.branch()
4751 branch = ctx.branch()
4751 bheads = repo.branchheads(branch)
4752 bheads = repo.branchheads(branch)
4752 m = _('branch: %s\n') % branch
4753 m = _('branch: %s\n') % branch
4753 if branch != 'default':
4754 if branch != 'default':
4754 ui.write(m, label='log.branch')
4755 ui.write(m, label='log.branch')
4755 else:
4756 else:
4756 ui.status(m, label='log.branch')
4757 ui.status(m, label='log.branch')
4757
4758
4758 if marks:
4759 if marks:
4759 current = repo._bookmarkcurrent
4760 current = repo._bookmarkcurrent
4760 ui.write(_('bookmarks:'), label='log.bookmark')
4761 ui.write(_('bookmarks:'), label='log.bookmark')
4761 if current is not None:
4762 if current is not None:
4762 try:
4763 try:
4763 marks.remove(current)
4764 marks.remove(current)
4764 ui.write(' *' + current, label='bookmarks.current')
4765 ui.write(' *' + current, label='bookmarks.current')
4765 except ValueError:
4766 except ValueError:
4766 # current bookmark not in parent ctx marks
4767 # current bookmark not in parent ctx marks
4767 pass
4768 pass
4768 for m in marks:
4769 for m in marks:
4769 ui.write(' ' + m, label='log.bookmark')
4770 ui.write(' ' + m, label='log.bookmark')
4770 ui.write('\n', label='log.bookmark')
4771 ui.write('\n', label='log.bookmark')
4771
4772
4772 st = list(repo.status(unknown=True))[:6]
4773 st = list(repo.status(unknown=True))[:6]
4773
4774
4774 c = repo.dirstate.copies()
4775 c = repo.dirstate.copies()
4775 copied, renamed = [], []
4776 copied, renamed = [], []
4776 for d, s in c.iteritems():
4777 for d, s in c.iteritems():
4777 if s in st[2]:
4778 if s in st[2]:
4778 st[2].remove(s)
4779 st[2].remove(s)
4779 renamed.append(d)
4780 renamed.append(d)
4780 else:
4781 else:
4781 copied.append(d)
4782 copied.append(d)
4782 if d in st[1]:
4783 if d in st[1]:
4783 st[1].remove(d)
4784 st[1].remove(d)
4784 st.insert(3, renamed)
4785 st.insert(3, renamed)
4785 st.insert(4, copied)
4786 st.insert(4, copied)
4786
4787
4787 ms = mergemod.mergestate(repo)
4788 ms = mergemod.mergestate(repo)
4788 st.append([f for f in ms if ms[f] == 'u'])
4789 st.append([f for f in ms if ms[f] == 'u'])
4789
4790
4790 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4791 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4791 st.append(subs)
4792 st.append(subs)
4792
4793
4793 labels = [ui.label(_('%d modified'), 'status.modified'),
4794 labels = [ui.label(_('%d modified'), 'status.modified'),
4794 ui.label(_('%d added'), 'status.added'),
4795 ui.label(_('%d added'), 'status.added'),
4795 ui.label(_('%d removed'), 'status.removed'),
4796 ui.label(_('%d removed'), 'status.removed'),
4796 ui.label(_('%d renamed'), 'status.copied'),
4797 ui.label(_('%d renamed'), 'status.copied'),
4797 ui.label(_('%d copied'), 'status.copied'),
4798 ui.label(_('%d copied'), 'status.copied'),
4798 ui.label(_('%d deleted'), 'status.deleted'),
4799 ui.label(_('%d deleted'), 'status.deleted'),
4799 ui.label(_('%d unknown'), 'status.unknown'),
4800 ui.label(_('%d unknown'), 'status.unknown'),
4800 ui.label(_('%d ignored'), 'status.ignored'),
4801 ui.label(_('%d ignored'), 'status.ignored'),
4801 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4802 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4802 ui.label(_('%d subrepos'), 'status.modified')]
4803 ui.label(_('%d subrepos'), 'status.modified')]
4803 t = []
4804 t = []
4804 for s, l in zip(st, labels):
4805 for s, l in zip(st, labels):
4805 if s:
4806 if s:
4806 t.append(l % len(s))
4807 t.append(l % len(s))
4807
4808
4808 t = ', '.join(t)
4809 t = ', '.join(t)
4809 cleanworkdir = False
4810 cleanworkdir = False
4810
4811
4811 if len(parents) > 1:
4812 if len(parents) > 1:
4812 t += _(' (merge)')
4813 t += _(' (merge)')
4813 elif branch != parents[0].branch():
4814 elif branch != parents[0].branch():
4814 t += _(' (new branch)')
4815 t += _(' (new branch)')
4815 elif (parents[0].extra().get('close') and
4816 elif (parents[0].extra().get('close') and
4816 pnode in repo.branchheads(branch, closed=True)):
4817 pnode in repo.branchheads(branch, closed=True)):
4817 t += _(' (head closed)')
4818 t += _(' (head closed)')
4818 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4819 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4819 t += _(' (clean)')
4820 t += _(' (clean)')
4820 cleanworkdir = True
4821 cleanworkdir = True
4821 elif pnode not in bheads:
4822 elif pnode not in bheads:
4822 t += _(' (new branch head)')
4823 t += _(' (new branch head)')
4823
4824
4824 if cleanworkdir:
4825 if cleanworkdir:
4825 ui.status(_('commit: %s\n') % t.strip())
4826 ui.status(_('commit: %s\n') % t.strip())
4826 else:
4827 else:
4827 ui.write(_('commit: %s\n') % t.strip())
4828 ui.write(_('commit: %s\n') % t.strip())
4828
4829
4829 # all ancestors of branch heads - all ancestors of parent = new csets
4830 # all ancestors of branch heads - all ancestors of parent = new csets
4830 new = [0] * len(repo)
4831 new = [0] * len(repo)
4831 cl = repo.changelog
4832 cl = repo.changelog
4832 for a in [cl.rev(n) for n in bheads]:
4833 for a in [cl.rev(n) for n in bheads]:
4833 new[a] = 1
4834 new[a] = 1
4834 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4835 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4835 new[a] = 1
4836 new[a] = 1
4836 for a in [p.rev() for p in parents]:
4837 for a in [p.rev() for p in parents]:
4837 if a >= 0:
4838 if a >= 0:
4838 new[a] = 0
4839 new[a] = 0
4839 for a in cl.ancestors(*[p.rev() for p in parents]):
4840 for a in cl.ancestors(*[p.rev() for p in parents]):
4840 new[a] = 0
4841 new[a] = 0
4841 new = sum(new)
4842 new = sum(new)
4842
4843
4843 if new == 0:
4844 if new == 0:
4844 ui.status(_('update: (current)\n'))
4845 ui.status(_('update: (current)\n'))
4845 elif pnode not in bheads:
4846 elif pnode not in bheads:
4846 ui.write(_('update: %d new changesets (update)\n') % new)
4847 ui.write(_('update: %d new changesets (update)\n') % new)
4847 else:
4848 else:
4848 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4849 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4849 (new, len(bheads)))
4850 (new, len(bheads)))
4850
4851
4851 if opts.get('remote'):
4852 if opts.get('remote'):
4852 t = []
4853 t = []
4853 source, branches = hg.parseurl(ui.expandpath('default'))
4854 source, branches = hg.parseurl(ui.expandpath('default'))
4854 other = hg.peer(repo, {}, source)
4855 other = hg.peer(repo, {}, source)
4855 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4856 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4856 ui.debug('comparing with %s\n' % util.hidepassword(source))
4857 ui.debug('comparing with %s\n' % util.hidepassword(source))
4857 repo.ui.pushbuffer()
4858 repo.ui.pushbuffer()
4858 commoninc = discovery.findcommonincoming(repo, other)
4859 commoninc = discovery.findcommonincoming(repo, other)
4859 _common, incoming, _rheads = commoninc
4860 _common, incoming, _rheads = commoninc
4860 repo.ui.popbuffer()
4861 repo.ui.popbuffer()
4861 if incoming:
4862 if incoming:
4862 t.append(_('1 or more incoming'))
4863 t.append(_('1 or more incoming'))
4863
4864
4864 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4865 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4865 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4866 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4866 if source != dest:
4867 if source != dest:
4867 other = hg.peer(repo, {}, dest)
4868 other = hg.peer(repo, {}, dest)
4868 commoninc = None
4869 commoninc = None
4869 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4870 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4870 repo.ui.pushbuffer()
4871 repo.ui.pushbuffer()
4871 common, outheads = discovery.findcommonoutgoing(repo, other,
4872 common, outheads = discovery.findcommonoutgoing(repo, other,
4872 commoninc=commoninc)
4873 commoninc=commoninc)
4873 repo.ui.popbuffer()
4874 repo.ui.popbuffer()
4874 o = repo.changelog.findmissing(common=common, heads=outheads)
4875 o = repo.changelog.findmissing(common=common, heads=outheads)
4875 if o:
4876 if o:
4876 t.append(_('%d outgoing') % len(o))
4877 t.append(_('%d outgoing') % len(o))
4877 if 'bookmarks' in other.listkeys('namespaces'):
4878 if 'bookmarks' in other.listkeys('namespaces'):
4878 lmarks = repo.listkeys('bookmarks')
4879 lmarks = repo.listkeys('bookmarks')
4879 rmarks = other.listkeys('bookmarks')
4880 rmarks = other.listkeys('bookmarks')
4880 diff = set(rmarks) - set(lmarks)
4881 diff = set(rmarks) - set(lmarks)
4881 if len(diff) > 0:
4882 if len(diff) > 0:
4882 t.append(_('%d incoming bookmarks') % len(diff))
4883 t.append(_('%d incoming bookmarks') % len(diff))
4883 diff = set(lmarks) - set(rmarks)
4884 diff = set(lmarks) - set(rmarks)
4884 if len(diff) > 0:
4885 if len(diff) > 0:
4885 t.append(_('%d outgoing bookmarks') % len(diff))
4886 t.append(_('%d outgoing bookmarks') % len(diff))
4886
4887
4887 if t:
4888 if t:
4888 ui.write(_('remote: %s\n') % (', '.join(t)))
4889 ui.write(_('remote: %s\n') % (', '.join(t)))
4889 else:
4890 else:
4890 ui.status(_('remote: (synced)\n'))
4891 ui.status(_('remote: (synced)\n'))
4891
4892
4892 @command('tag',
4893 @command('tag',
4893 [('f', 'force', None, _('force tag')),
4894 [('f', 'force', None, _('force tag')),
4894 ('l', 'local', None, _('make the tag local')),
4895 ('l', 'local', None, _('make the tag local')),
4895 ('r', 'rev', '', _('revision to tag'), _('REV')),
4896 ('r', 'rev', '', _('revision to tag'), _('REV')),
4896 ('', 'remove', None, _('remove a tag')),
4897 ('', 'remove', None, _('remove a tag')),
4897 # -l/--local is already there, commitopts cannot be used
4898 # -l/--local is already there, commitopts cannot be used
4898 ('e', 'edit', None, _('edit commit message')),
4899 ('e', 'edit', None, _('edit commit message')),
4899 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4900 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4900 ] + commitopts2,
4901 ] + commitopts2,
4901 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4902 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4902 def tag(ui, repo, name1, *names, **opts):
4903 def tag(ui, repo, name1, *names, **opts):
4903 """add one or more tags for the current or given revision
4904 """add one or more tags for the current or given revision
4904
4905
4905 Name a particular revision using <name>.
4906 Name a particular revision using <name>.
4906
4907
4907 Tags are used to name particular revisions of the repository and are
4908 Tags are used to name particular revisions of the repository and are
4908 very useful to compare different revisions, to go back to significant
4909 very useful to compare different revisions, to go back to significant
4909 earlier versions or to mark branch points as releases, etc. Changing
4910 earlier versions or to mark branch points as releases, etc. Changing
4910 an existing tag is normally disallowed; use -f/--force to override.
4911 an existing tag is normally disallowed; use -f/--force to override.
4911
4912
4912 If no revision is given, the parent of the working directory is
4913 If no revision is given, the parent of the working directory is
4913 used, or tip if no revision is checked out.
4914 used, or tip if no revision is checked out.
4914
4915
4915 To facilitate version control, distribution, and merging of tags,
4916 To facilitate version control, distribution, and merging of tags,
4916 they are stored as a file named ".hgtags" which is managed similarly
4917 they are stored as a file named ".hgtags" which is managed similarly
4917 to other project files and can be hand-edited if necessary. This
4918 to other project files and can be hand-edited if necessary. This
4918 also means that tagging creates a new commit. The file
4919 also means that tagging creates a new commit. The file
4919 ".hg/localtags" is used for local tags (not shared among
4920 ".hg/localtags" is used for local tags (not shared among
4920 repositories).
4921 repositories).
4921
4922
4922 Tag commits are usually made at the head of a branch. If the parent
4923 Tag commits are usually made at the head of a branch. If the parent
4923 of the working directory is not a branch head, :hg:`tag` aborts; use
4924 of the working directory is not a branch head, :hg:`tag` aborts; use
4924 -f/--force to force the tag commit to be based on a non-head
4925 -f/--force to force the tag commit to be based on a non-head
4925 changeset.
4926 changeset.
4926
4927
4927 See :hg:`help dates` for a list of formats valid for -d/--date.
4928 See :hg:`help dates` for a list of formats valid for -d/--date.
4928
4929
4929 Since tag names have priority over branch names during revision
4930 Since tag names have priority over branch names during revision
4930 lookup, using an existing branch name as a tag name is discouraged.
4931 lookup, using an existing branch name as a tag name is discouraged.
4931
4932
4932 Returns 0 on success.
4933 Returns 0 on success.
4933 """
4934 """
4934
4935
4935 rev_ = "."
4936 rev_ = "."
4936 names = [t.strip() for t in (name1,) + names]
4937 names = [t.strip() for t in (name1,) + names]
4937 if len(names) != len(set(names)):
4938 if len(names) != len(set(names)):
4938 raise util.Abort(_('tag names must be unique'))
4939 raise util.Abort(_('tag names must be unique'))
4939 for n in names:
4940 for n in names:
4940 if n in ['tip', '.', 'null']:
4941 if n in ['tip', '.', 'null']:
4941 raise util.Abort(_("the name '%s' is reserved") % n)
4942 raise util.Abort(_("the name '%s' is reserved") % n)
4942 if not n:
4943 if not n:
4943 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4944 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4944 if opts.get('rev') and opts.get('remove'):
4945 if opts.get('rev') and opts.get('remove'):
4945 raise util.Abort(_("--rev and --remove are incompatible"))
4946 raise util.Abort(_("--rev and --remove are incompatible"))
4946 if opts.get('rev'):
4947 if opts.get('rev'):
4947 rev_ = opts['rev']
4948 rev_ = opts['rev']
4948 message = opts.get('message')
4949 message = opts.get('message')
4949 if opts.get('remove'):
4950 if opts.get('remove'):
4950 expectedtype = opts.get('local') and 'local' or 'global'
4951 expectedtype = opts.get('local') and 'local' or 'global'
4951 for n in names:
4952 for n in names:
4952 if not repo.tagtype(n):
4953 if not repo.tagtype(n):
4953 raise util.Abort(_("tag '%s' does not exist") % n)
4954 raise util.Abort(_("tag '%s' does not exist") % n)
4954 if repo.tagtype(n) != expectedtype:
4955 if repo.tagtype(n) != expectedtype:
4955 if expectedtype == 'global':
4956 if expectedtype == 'global':
4956 raise util.Abort(_("tag '%s' is not a global tag") % n)
4957 raise util.Abort(_("tag '%s' is not a global tag") % n)
4957 else:
4958 else:
4958 raise util.Abort(_("tag '%s' is not a local tag") % n)
4959 raise util.Abort(_("tag '%s' is not a local tag") % n)
4959 rev_ = nullid
4960 rev_ = nullid
4960 if not message:
4961 if not message:
4961 # we don't translate commit messages
4962 # we don't translate commit messages
4962 message = 'Removed tag %s' % ', '.join(names)
4963 message = 'Removed tag %s' % ', '.join(names)
4963 elif not opts.get('force'):
4964 elif not opts.get('force'):
4964 for n in names:
4965 for n in names:
4965 if n in repo.tags():
4966 if n in repo.tags():
4966 raise util.Abort(_("tag '%s' already exists "
4967 raise util.Abort(_("tag '%s' already exists "
4967 "(use -f to force)") % n)
4968 "(use -f to force)") % n)
4968 if not opts.get('local'):
4969 if not opts.get('local'):
4969 p1, p2 = repo.dirstate.parents()
4970 p1, p2 = repo.dirstate.parents()
4970 if p2 != nullid:
4971 if p2 != nullid:
4971 raise util.Abort(_('uncommitted merge'))
4972 raise util.Abort(_('uncommitted merge'))
4972 bheads = repo.branchheads()
4973 bheads = repo.branchheads()
4973 if not opts.get('force') and bheads and p1 not in bheads:
4974 if not opts.get('force') and bheads and p1 not in bheads:
4974 raise util.Abort(_('not at a branch head (use -f to force)'))
4975 raise util.Abort(_('not at a branch head (use -f to force)'))
4975 r = scmutil.revsingle(repo, rev_).node()
4976 r = scmutil.revsingle(repo, rev_).node()
4976
4977
4977 if not message:
4978 if not message:
4978 # we don't translate commit messages
4979 # we don't translate commit messages
4979 message = ('Added tag %s for changeset %s' %
4980 message = ('Added tag %s for changeset %s' %
4980 (', '.join(names), short(r)))
4981 (', '.join(names), short(r)))
4981
4982
4982 date = opts.get('date')
4983 date = opts.get('date')
4983 if date:
4984 if date:
4984 date = util.parsedate(date)
4985 date = util.parsedate(date)
4985
4986
4986 if opts.get('edit'):
4987 if opts.get('edit'):
4987 message = ui.edit(message, ui.username())
4988 message = ui.edit(message, ui.username())
4988
4989
4989 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4990 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4990
4991
4991 @command('tags', [], '')
4992 @command('tags', [], '')
4992 def tags(ui, repo):
4993 def tags(ui, repo):
4993 """list repository tags
4994 """list repository tags
4994
4995
4995 This lists both regular and local tags. When the -v/--verbose
4996 This lists both regular and local tags. When the -v/--verbose
4996 switch is used, a third column "local" is printed for local tags.
4997 switch is used, a third column "local" is printed for local tags.
4997
4998
4998 Returns 0 on success.
4999 Returns 0 on success.
4999 """
5000 """
5000
5001
5001 hexfunc = ui.debugflag and hex or short
5002 hexfunc = ui.debugflag and hex or short
5002 tagtype = ""
5003 tagtype = ""
5003
5004
5004 for t, n in reversed(repo.tagslist()):
5005 for t, n in reversed(repo.tagslist()):
5005 if ui.quiet:
5006 if ui.quiet:
5006 ui.write("%s\n" % t)
5007 ui.write("%s\n" % t)
5007 continue
5008 continue
5008
5009
5009 hn = hexfunc(n)
5010 hn = hexfunc(n)
5010 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5011 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5011 spaces = " " * (30 - encoding.colwidth(t))
5012 spaces = " " * (30 - encoding.colwidth(t))
5012
5013
5013 if ui.verbose:
5014 if ui.verbose:
5014 if repo.tagtype(t) == 'local':
5015 if repo.tagtype(t) == 'local':
5015 tagtype = " local"
5016 tagtype = " local"
5016 else:
5017 else:
5017 tagtype = ""
5018 tagtype = ""
5018 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5019 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5019
5020
5020 @command('tip',
5021 @command('tip',
5021 [('p', 'patch', None, _('show patch')),
5022 [('p', 'patch', None, _('show patch')),
5022 ('g', 'git', None, _('use git extended diff format')),
5023 ('g', 'git', None, _('use git extended diff format')),
5023 ] + templateopts,
5024 ] + templateopts,
5024 _('[-p] [-g]'))
5025 _('[-p] [-g]'))
5025 def tip(ui, repo, **opts):
5026 def tip(ui, repo, **opts):
5026 """show the tip revision
5027 """show the tip revision
5027
5028
5028 The tip revision (usually just called the tip) is the changeset
5029 The tip revision (usually just called the tip) is the changeset
5029 most recently added to the repository (and therefore the most
5030 most recently added to the repository (and therefore the most
5030 recently changed head).
5031 recently changed head).
5031
5032
5032 If you have just made a commit, that commit will be the tip. If
5033 If you have just made a commit, that commit will be the tip. If
5033 you have just pulled changes from another repository, the tip of
5034 you have just pulled changes from another repository, the tip of
5034 that repository becomes the current tip. The "tip" tag is special
5035 that repository becomes the current tip. The "tip" tag is special
5035 and cannot be renamed or assigned to a different changeset.
5036 and cannot be renamed or assigned to a different changeset.
5036
5037
5037 Returns 0 on success.
5038 Returns 0 on success.
5038 """
5039 """
5039 displayer = cmdutil.show_changeset(ui, repo, opts)
5040 displayer = cmdutil.show_changeset(ui, repo, opts)
5040 displayer.show(repo[len(repo) - 1])
5041 displayer.show(repo[len(repo) - 1])
5041 displayer.close()
5042 displayer.close()
5042
5043
5043 @command('unbundle',
5044 @command('unbundle',
5044 [('u', 'update', None,
5045 [('u', 'update', None,
5045 _('update to new branch head if changesets were unbundled'))],
5046 _('update to new branch head if changesets were unbundled'))],
5046 _('[-u] FILE...'))
5047 _('[-u] FILE...'))
5047 def unbundle(ui, repo, fname1, *fnames, **opts):
5048 def unbundle(ui, repo, fname1, *fnames, **opts):
5048 """apply one or more changegroup files
5049 """apply one or more changegroup files
5049
5050
5050 Apply one or more compressed changegroup files generated by the
5051 Apply one or more compressed changegroup files generated by the
5051 bundle command.
5052 bundle command.
5052
5053
5053 Returns 0 on success, 1 if an update has unresolved files.
5054 Returns 0 on success, 1 if an update has unresolved files.
5054 """
5055 """
5055 fnames = (fname1,) + fnames
5056 fnames = (fname1,) + fnames
5056
5057
5057 lock = repo.lock()
5058 lock = repo.lock()
5058 wc = repo['.']
5059 wc = repo['.']
5059 try:
5060 try:
5060 for fname in fnames:
5061 for fname in fnames:
5061 f = url.open(ui, fname)
5062 f = url.open(ui, fname)
5062 gen = changegroup.readbundle(f, fname)
5063 gen = changegroup.readbundle(f, fname)
5063 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5064 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5064 lock=lock)
5065 lock=lock)
5065 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5066 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5066 finally:
5067 finally:
5067 lock.release()
5068 lock.release()
5068 return postincoming(ui, repo, modheads, opts.get('update'), None)
5069 return postincoming(ui, repo, modheads, opts.get('update'), None)
5069
5070
5070 @command('^update|up|checkout|co',
5071 @command('^update|up|checkout|co',
5071 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5072 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5072 ('c', 'check', None,
5073 ('c', 'check', None,
5073 _('update across branches if no uncommitted changes')),
5074 _('update across branches if no uncommitted changes')),
5074 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5075 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5075 ('r', 'rev', '', _('revision'), _('REV'))],
5076 ('r', 'rev', '', _('revision'), _('REV'))],
5076 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5077 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5077 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5078 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5078 """update working directory (or switch revisions)
5079 """update working directory (or switch revisions)
5079
5080
5080 Update the repository's working directory to the specified
5081 Update the repository's working directory to the specified
5081 changeset. If no changeset is specified, update to the tip of the
5082 changeset. If no changeset is specified, update to the tip of the
5082 current named branch.
5083 current named branch.
5083
5084
5084 If the changeset is not a descendant of the working directory's
5085 If the changeset is not a descendant of the working directory's
5085 parent, the update is aborted. With the -c/--check option, the
5086 parent, the update is aborted. With the -c/--check option, the
5086 working directory is checked for uncommitted changes; if none are
5087 working directory is checked for uncommitted changes; if none are
5087 found, the working directory is updated to the specified
5088 found, the working directory is updated to the specified
5088 changeset.
5089 changeset.
5089
5090
5090 Update sets the working directory's parent revison to the specified
5091 Update sets the working directory's parent revison to the specified
5091 changeset (see :hg:`help parents`).
5092 changeset (see :hg:`help parents`).
5092
5093
5093 The following rules apply when the working directory contains
5094 The following rules apply when the working directory contains
5094 uncommitted changes:
5095 uncommitted changes:
5095
5096
5096 1. If neither -c/--check nor -C/--clean is specified, and if
5097 1. If neither -c/--check nor -C/--clean is specified, and if
5097 the requested changeset is an ancestor or descendant of
5098 the requested changeset is an ancestor or descendant of
5098 the working directory's parent, the uncommitted changes
5099 the working directory's parent, the uncommitted changes
5099 are merged into the requested changeset and the merged
5100 are merged into the requested changeset and the merged
5100 result is left uncommitted. If the requested changeset is
5101 result is left uncommitted. If the requested changeset is
5101 not an ancestor or descendant (that is, it is on another
5102 not an ancestor or descendant (that is, it is on another
5102 branch), the update is aborted and the uncommitted changes
5103 branch), the update is aborted and the uncommitted changes
5103 are preserved.
5104 are preserved.
5104
5105
5105 2. With the -c/--check option, the update is aborted and the
5106 2. With the -c/--check option, the update is aborted and the
5106 uncommitted changes are preserved.
5107 uncommitted changes are preserved.
5107
5108
5108 3. With the -C/--clean option, uncommitted changes are discarded and
5109 3. With the -C/--clean option, uncommitted changes are discarded and
5109 the working directory is updated to the requested changeset.
5110 the working directory is updated to the requested changeset.
5110
5111
5111 Use null as the changeset to remove the working directory (like
5112 Use null as the changeset to remove the working directory (like
5112 :hg:`clone -U`).
5113 :hg:`clone -U`).
5113
5114
5114 If you want to revert just one file to an older revision, use
5115 If you want to revert just one file to an older revision, use
5115 :hg:`revert [-r REV] NAME`.
5116 :hg:`revert [-r REV] NAME`.
5116
5117
5117 See :hg:`help dates` for a list of formats valid for -d/--date.
5118 See :hg:`help dates` for a list of formats valid for -d/--date.
5118
5119
5119 Returns 0 on success, 1 if there are unresolved files.
5120 Returns 0 on success, 1 if there are unresolved files.
5120 """
5121 """
5121 if rev and node:
5122 if rev and node:
5122 raise util.Abort(_("please specify just one revision"))
5123 raise util.Abort(_("please specify just one revision"))
5123
5124
5124 if rev is None or rev == '':
5125 if rev is None or rev == '':
5125 rev = node
5126 rev = node
5126
5127
5127 # if we defined a bookmark, we have to remember the original bookmark name
5128 # if we defined a bookmark, we have to remember the original bookmark name
5128 brev = rev
5129 brev = rev
5129 rev = scmutil.revsingle(repo, rev, rev).rev()
5130 rev = scmutil.revsingle(repo, rev, rev).rev()
5130
5131
5131 if check and clean:
5132 if check and clean:
5132 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5133 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5133
5134
5134 if check:
5135 if check:
5135 # we could use dirty() but we can ignore merge and branch trivia
5136 # we could use dirty() but we can ignore merge and branch trivia
5136 c = repo[None]
5137 c = repo[None]
5137 if c.modified() or c.added() or c.removed():
5138 if c.modified() or c.added() or c.removed():
5138 raise util.Abort(_("uncommitted local changes"))
5139 raise util.Abort(_("uncommitted local changes"))
5139
5140
5140 if date:
5141 if date:
5141 if rev is not None:
5142 if rev is not None:
5142 raise util.Abort(_("you can't specify a revision and a date"))
5143 raise util.Abort(_("you can't specify a revision and a date"))
5143 rev = cmdutil.finddate(ui, repo, date)
5144 rev = cmdutil.finddate(ui, repo, date)
5144
5145
5145 if clean or check:
5146 if clean or check:
5146 ret = hg.clean(repo, rev)
5147 ret = hg.clean(repo, rev)
5147 else:
5148 else:
5148 ret = hg.update(repo, rev)
5149 ret = hg.update(repo, rev)
5149
5150
5150 if brev in repo._bookmarks:
5151 if brev in repo._bookmarks:
5151 bookmarks.setcurrent(repo, brev)
5152 bookmarks.setcurrent(repo, brev)
5152
5153
5153 return ret
5154 return ret
5154
5155
5155 @command('verify', [])
5156 @command('verify', [])
5156 def verify(ui, repo):
5157 def verify(ui, repo):
5157 """verify the integrity of the repository
5158 """verify the integrity of the repository
5158
5159
5159 Verify the integrity of the current repository.
5160 Verify the integrity of the current repository.
5160
5161
5161 This will perform an extensive check of the repository's
5162 This will perform an extensive check of the repository's
5162 integrity, validating the hashes and checksums of each entry in
5163 integrity, validating the hashes and checksums of each entry in
5163 the changelog, manifest, and tracked files, as well as the
5164 the changelog, manifest, and tracked files, as well as the
5164 integrity of their crosslinks and indices.
5165 integrity of their crosslinks and indices.
5165
5166
5166 Returns 0 on success, 1 if errors are encountered.
5167 Returns 0 on success, 1 if errors are encountered.
5167 """
5168 """
5168 return hg.verify(repo)
5169 return hg.verify(repo)
5169
5170
5170 @command('version', [])
5171 @command('version', [])
5171 def version_(ui):
5172 def version_(ui):
5172 """output version and copyright information"""
5173 """output version and copyright information"""
5173 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5174 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5174 % util.version())
5175 % util.version())
5175 ui.status(_(
5176 ui.status(_(
5176 "(see http://mercurial.selenic.com for more information)\n"
5177 "(see http://mercurial.selenic.com for more information)\n"
5177 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5178 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5178 "This is free software; see the source for copying conditions. "
5179 "This is free software; see the source for copying conditions. "
5179 "There is NO\nwarranty; "
5180 "There is NO\nwarranty; "
5180 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5181 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5181 ))
5182 ))
5182
5183
5183 norepo = ("clone init version help debugcommands debugcomplete"
5184 norepo = ("clone init version help debugcommands debugcomplete"
5184 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5185 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5185 " debugknown debuggetbundle debugbundle")
5186 " debugknown debuggetbundle debugbundle")
5186 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5187 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5187 " debugdata debugindex debugindexdot debugrevlog")
5188 " debugdata debugindex debugindexdot debugrevlog")
General Comments 0
You need to be logged in to leave comments. Login now