##// END OF EJS Templates
update: do not use the term 'update' when mentioning reverting one file...
Adrian Buehlmann -
r14729:94eea58d stable
parent child Browse files
Show More
@@ -1,5158 +1,5158 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, assume \'yes\' for any required answers')),
34 _('do not prompt, assume \'yes\' for any required answers')),
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 similarityopts = [
122 similarityopts = [
123 ('s', 'similarity', '',
123 ('s', 'similarity', '',
124 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
124 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
125 ]
125 ]
126
126
127 subrepoopts = [
127 subrepoopts = [
128 ('S', 'subrepos', None,
128 ('S', 'subrepos', None,
129 _('recurse into subrepositories'))
129 _('recurse into subrepositories'))
130 ]
130 ]
131
131
132 # Commands start here, listed alphabetically
132 # Commands start here, listed alphabetically
133
133
134 @command('^add',
134 @command('^add',
135 walkopts + subrepoopts + dryrunopts,
135 walkopts + subrepoopts + dryrunopts,
136 _('[OPTION]... [FILE]...'))
136 _('[OPTION]... [FILE]...'))
137 def add(ui, repo, *pats, **opts):
137 def add(ui, repo, *pats, **opts):
138 """add the specified files on the next commit
138 """add the specified files on the next commit
139
139
140 Schedule files to be version controlled and added to the
140 Schedule files to be version controlled and added to the
141 repository.
141 repository.
142
142
143 The files will be added to the repository at the next commit. To
143 The files will be added to the repository at the next commit. To
144 undo an add before that, see :hg:`forget`.
144 undo an add before that, see :hg:`forget`.
145
145
146 If no names are given, add all files to the repository.
146 If no names are given, add all files to the repository.
147
147
148 .. container:: verbose
148 .. container:: verbose
149
149
150 An example showing how new (unknown) files are added
150 An example showing how new (unknown) files are added
151 automatically by :hg:`add`::
151 automatically by :hg:`add`::
152
152
153 $ ls
153 $ ls
154 foo.c
154 foo.c
155 $ hg status
155 $ hg status
156 ? foo.c
156 ? foo.c
157 $ hg add
157 $ hg add
158 adding foo.c
158 adding foo.c
159 $ hg status
159 $ hg status
160 A foo.c
160 A foo.c
161
161
162 Returns 0 if all files are successfully added.
162 Returns 0 if all files are successfully added.
163 """
163 """
164
164
165 m = scmutil.match(repo[None], pats, opts)
165 m = scmutil.match(repo[None], pats, opts)
166 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
166 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
167 opts.get('subrepos'), prefix="")
167 opts.get('subrepos'), prefix="")
168 return rejected and 1 or 0
168 return rejected and 1 or 0
169
169
170 @command('addremove',
170 @command('addremove',
171 similarityopts + walkopts + dryrunopts,
171 similarityopts + walkopts + dryrunopts,
172 _('[OPTION]... [FILE]...'))
172 _('[OPTION]... [FILE]...'))
173 def addremove(ui, repo, *pats, **opts):
173 def addremove(ui, repo, *pats, **opts):
174 """add all new files, delete all missing files
174 """add all new files, delete all missing files
175
175
176 Add all new files and remove all missing files from the
176 Add all new files and remove all missing files from the
177 repository.
177 repository.
178
178
179 New files are ignored if they match any of the patterns in
179 New files are ignored if they match any of the patterns in
180 ``.hgignore``. As with add, these changes take effect at the next
180 ``.hgignore``. As with add, these changes take effect at the next
181 commit.
181 commit.
182
182
183 Use the -s/--similarity option to detect renamed files. With a
183 Use the -s/--similarity option to detect renamed files. With a
184 parameter greater than 0, this compares every removed file with
184 parameter greater than 0, this compares every removed file with
185 every added file and records those similar enough as renames. This
185 every added file and records those similar enough as renames. This
186 option takes a percentage between 0 (disabled) and 100 (files must
186 option takes a percentage between 0 (disabled) and 100 (files must
187 be identical) as its parameter. Detecting renamed files this way
187 be identical) as its parameter. Detecting renamed files this way
188 can be expensive. After using this option, :hg:`status -C` can be
188 can be expensive. After using this option, :hg:`status -C` can be
189 used to check which files were identified as moved or renamed.
189 used to check which files were identified as moved or renamed.
190
190
191 Returns 0 if all files are successfully added.
191 Returns 0 if all files are successfully added.
192 """
192 """
193 try:
193 try:
194 sim = float(opts.get('similarity') or 100)
194 sim = float(opts.get('similarity') or 100)
195 except ValueError:
195 except ValueError:
196 raise util.Abort(_('similarity must be a number'))
196 raise util.Abort(_('similarity must be a number'))
197 if sim < 0 or sim > 100:
197 if sim < 0 or sim > 100:
198 raise util.Abort(_('similarity must be between 0 and 100'))
198 raise util.Abort(_('similarity must be between 0 and 100'))
199 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
199 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
200
200
201 @command('^annotate|blame',
201 @command('^annotate|blame',
202 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
202 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
203 ('', 'follow', None,
203 ('', 'follow', None,
204 _('follow copies/renames and list the filename (DEPRECATED)')),
204 _('follow copies/renames and list the filename (DEPRECATED)')),
205 ('', 'no-follow', None, _("don't follow copies and renames")),
205 ('', 'no-follow', None, _("don't follow copies and renames")),
206 ('a', 'text', None, _('treat all files as text')),
206 ('a', 'text', None, _('treat all files as text')),
207 ('u', 'user', None, _('list the author (long with -v)')),
207 ('u', 'user', None, _('list the author (long with -v)')),
208 ('f', 'file', None, _('list the filename')),
208 ('f', 'file', None, _('list the filename')),
209 ('d', 'date', None, _('list the date (short with -q)')),
209 ('d', 'date', None, _('list the date (short with -q)')),
210 ('n', 'number', None, _('list the revision number (default)')),
210 ('n', 'number', None, _('list the revision number (default)')),
211 ('c', 'changeset', None, _('list the changeset')),
211 ('c', 'changeset', None, _('list the changeset')),
212 ('l', 'line-number', None, _('show line number at the first appearance'))
212 ('l', 'line-number', None, _('show line number at the first appearance'))
213 ] + walkopts,
213 ] + walkopts,
214 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
214 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
215 def annotate(ui, repo, *pats, **opts):
215 def annotate(ui, repo, *pats, **opts):
216 """show changeset information by line for each file
216 """show changeset information by line for each file
217
217
218 List changes in files, showing the revision id responsible for
218 List changes in files, showing the revision id responsible for
219 each line
219 each line
220
220
221 This command is useful for discovering when a change was made and
221 This command is useful for discovering when a change was made and
222 by whom.
222 by whom.
223
223
224 Without the -a/--text option, annotate will avoid processing files
224 Without the -a/--text option, annotate will avoid processing files
225 it detects as binary. With -a, annotate will annotate the file
225 it detects as binary. With -a, annotate will annotate the file
226 anyway, although the results will probably be neither useful
226 anyway, although the results will probably be neither useful
227 nor desirable.
227 nor desirable.
228
228
229 Returns 0 on success.
229 Returns 0 on success.
230 """
230 """
231 if opts.get('follow'):
231 if opts.get('follow'):
232 # --follow is deprecated and now just an alias for -f/--file
232 # --follow is deprecated and now just an alias for -f/--file
233 # to mimic the behavior of Mercurial before version 1.5
233 # to mimic the behavior of Mercurial before version 1.5
234 opts['file'] = True
234 opts['file'] = True
235
235
236 datefunc = ui.quiet and util.shortdate or util.datestr
236 datefunc = ui.quiet and util.shortdate or util.datestr
237 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
237 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
238
238
239 if not pats:
239 if not pats:
240 raise util.Abort(_('at least one filename or pattern is required'))
240 raise util.Abort(_('at least one filename or pattern is required'))
241
241
242 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
242 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
243 ('number', ' ', lambda x: str(x[0].rev())),
243 ('number', ' ', lambda x: str(x[0].rev())),
244 ('changeset', ' ', lambda x: short(x[0].node())),
244 ('changeset', ' ', lambda x: short(x[0].node())),
245 ('date', ' ', getdate),
245 ('date', ' ', getdate),
246 ('file', ' ', lambda x: x[0].path()),
246 ('file', ' ', lambda x: x[0].path()),
247 ('line_number', ':', lambda x: str(x[1])),
247 ('line_number', ':', lambda x: str(x[1])),
248 ]
248 ]
249
249
250 if (not opts.get('user') and not opts.get('changeset')
250 if (not opts.get('user') and not opts.get('changeset')
251 and not opts.get('date') and not opts.get('file')):
251 and not opts.get('date') and not opts.get('file')):
252 opts['number'] = True
252 opts['number'] = True
253
253
254 linenumber = opts.get('line_number') is not None
254 linenumber = opts.get('line_number') is not None
255 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
255 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
256 raise util.Abort(_('at least one of -n/-c is required for -l'))
256 raise util.Abort(_('at least one of -n/-c is required for -l'))
257
257
258 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
258 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
259 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
259 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
260
260
261 def bad(x, y):
261 def bad(x, y):
262 raise util.Abort("%s: %s" % (x, y))
262 raise util.Abort("%s: %s" % (x, y))
263
263
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
265 m = scmutil.match(ctx, pats, opts)
265 m = scmutil.match(ctx, pats, opts)
266 m.bad = bad
266 m.bad = bad
267 follow = not opts.get('no_follow')
267 follow = not opts.get('no_follow')
268 for abs in ctx.walk(m):
268 for abs in ctx.walk(m):
269 fctx = ctx[abs]
269 fctx = ctx[abs]
270 if not opts.get('text') and util.binary(fctx.data()):
270 if not opts.get('text') and util.binary(fctx.data()):
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
272 continue
272 continue
273
273
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
275 pieces = []
275 pieces = []
276
276
277 for f, sep in funcmap:
277 for f, sep in funcmap:
278 l = [f(n) for n, dummy in lines]
278 l = [f(n) for n, dummy in lines]
279 if l:
279 if l:
280 sized = [(x, encoding.colwidth(x)) for x in l]
280 sized = [(x, encoding.colwidth(x)) for x in l]
281 ml = max([w for x, w in sized])
281 ml = max([w for x, w in sized])
282 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
282 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
283 for x, w in sized])
283 for x, w in sized])
284
284
285 if pieces:
285 if pieces:
286 for p, l in zip(zip(*pieces), lines):
286 for p, l in zip(zip(*pieces), lines):
287 ui.write("%s: %s" % ("".join(p), l[1]))
287 ui.write("%s: %s" % ("".join(p), l[1]))
288
288
289 @command('archive',
289 @command('archive',
290 [('', 'no-decode', None, _('do not pass files through decoders')),
290 [('', 'no-decode', None, _('do not pass files through decoders')),
291 ('p', 'prefix', '', _('directory prefix for files in archive'),
291 ('p', 'prefix', '', _('directory prefix for files in archive'),
292 _('PREFIX')),
292 _('PREFIX')),
293 ('r', 'rev', '', _('revision to distribute'), _('REV')),
293 ('r', 'rev', '', _('revision to distribute'), _('REV')),
294 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
294 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
295 ] + subrepoopts + walkopts,
295 ] + subrepoopts + walkopts,
296 _('[OPTION]... DEST'))
296 _('[OPTION]... DEST'))
297 def archive(ui, repo, dest, **opts):
297 def archive(ui, repo, dest, **opts):
298 '''create an unversioned archive of a repository revision
298 '''create an unversioned archive of a repository revision
299
299
300 By default, the revision used is the parent of the working
300 By default, the revision used is the parent of the working
301 directory; use -r/--rev to specify a different revision.
301 directory; use -r/--rev to specify a different revision.
302
302
303 The archive type is automatically detected based on file
303 The archive type is automatically detected based on file
304 extension (or override using -t/--type).
304 extension (or override using -t/--type).
305
305
306 Valid types are:
306 Valid types are:
307
307
308 :``files``: a directory full of files (default)
308 :``files``: a directory full of files (default)
309 :``tar``: tar archive, uncompressed
309 :``tar``: tar archive, uncompressed
310 :``tbz2``: tar archive, compressed using bzip2
310 :``tbz2``: tar archive, compressed using bzip2
311 :``tgz``: tar archive, compressed using gzip
311 :``tgz``: tar archive, compressed using gzip
312 :``uzip``: zip archive, uncompressed
312 :``uzip``: zip archive, uncompressed
313 :``zip``: zip archive, compressed using deflate
313 :``zip``: zip archive, compressed using deflate
314
314
315 The exact name of the destination archive or directory is given
315 The exact name of the destination archive or directory is given
316 using a format string; see :hg:`help export` for details.
316 using a format string; see :hg:`help export` for details.
317
317
318 Each member added to an archive file has a directory prefix
318 Each member added to an archive file has a directory prefix
319 prepended. Use -p/--prefix to specify a format string for the
319 prepended. Use -p/--prefix to specify a format string for the
320 prefix. The default is the basename of the archive, with suffixes
320 prefix. The default is the basename of the archive, with suffixes
321 removed.
321 removed.
322
322
323 Returns 0 on success.
323 Returns 0 on success.
324 '''
324 '''
325
325
326 ctx = scmutil.revsingle(repo, opts.get('rev'))
326 ctx = scmutil.revsingle(repo, opts.get('rev'))
327 if not ctx:
327 if not ctx:
328 raise util.Abort(_('no working directory: please specify a revision'))
328 raise util.Abort(_('no working directory: please specify a revision'))
329 node = ctx.node()
329 node = ctx.node()
330 dest = cmdutil.makefilename(repo, dest, node)
330 dest = cmdutil.makefilename(repo, dest, node)
331 if os.path.realpath(dest) == repo.root:
331 if os.path.realpath(dest) == repo.root:
332 raise util.Abort(_('repository root cannot be destination'))
332 raise util.Abort(_('repository root cannot be destination'))
333
333
334 kind = opts.get('type') or archival.guesskind(dest) or 'files'
334 kind = opts.get('type') or archival.guesskind(dest) or 'files'
335 prefix = opts.get('prefix')
335 prefix = opts.get('prefix')
336
336
337 if dest == '-':
337 if dest == '-':
338 if kind == 'files':
338 if kind == 'files':
339 raise util.Abort(_('cannot archive plain files to stdout'))
339 raise util.Abort(_('cannot archive plain files to stdout'))
340 dest = ui.fout
340 dest = ui.fout
341 if not prefix:
341 if not prefix:
342 prefix = os.path.basename(repo.root) + '-%h'
342 prefix = os.path.basename(repo.root) + '-%h'
343
343
344 prefix = cmdutil.makefilename(repo, prefix, node)
344 prefix = cmdutil.makefilename(repo, prefix, node)
345 matchfn = scmutil.match(ctx, [], opts)
345 matchfn = scmutil.match(ctx, [], opts)
346 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
346 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
347 matchfn, prefix, subrepos=opts.get('subrepos'))
347 matchfn, prefix, subrepos=opts.get('subrepos'))
348
348
349 @command('backout',
349 @command('backout',
350 [('', 'merge', None, _('merge with old dirstate parent after backout')),
350 [('', 'merge', None, _('merge with old dirstate parent after backout')),
351 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
351 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
352 ('t', 'tool', '', _('specify merge tool')),
352 ('t', 'tool', '', _('specify merge tool')),
353 ('r', 'rev', '', _('revision to backout'), _('REV')),
353 ('r', 'rev', '', _('revision to backout'), _('REV')),
354 ] + walkopts + commitopts + commitopts2,
354 ] + walkopts + commitopts + commitopts2,
355 _('[OPTION]... [-r] REV'))
355 _('[OPTION]... [-r] REV'))
356 def backout(ui, repo, node=None, rev=None, **opts):
356 def backout(ui, repo, node=None, rev=None, **opts):
357 '''reverse effect of earlier changeset
357 '''reverse effect of earlier changeset
358
358
359 Prepare a new changeset with the effect of REV undone in the
359 Prepare a new changeset with the effect of REV undone in the
360 current working directory.
360 current working directory.
361
361
362 If REV is the parent of the working directory, then this new changeset
362 If REV is the parent of the working directory, then this new changeset
363 is committed automatically. Otherwise, hg needs to merge the
363 is committed automatically. Otherwise, hg needs to merge the
364 changes and the merged result is left uncommitted.
364 changes and the merged result is left uncommitted.
365
365
366 By default, the pending changeset will have one parent,
366 By default, the pending changeset will have one parent,
367 maintaining a linear history. With --merge, the pending changeset
367 maintaining a linear history. With --merge, the pending changeset
368 will instead have two parents: the old parent of the working
368 will instead have two parents: the old parent of the working
369 directory and a new child of REV that simply undoes REV.
369 directory and a new child of REV that simply undoes REV.
370
370
371 Before version 1.7, the behavior without --merge was equivalent to
371 Before version 1.7, the behavior without --merge was equivalent to
372 specifying --merge followed by :hg:`update --clean .` to cancel
372 specifying --merge followed by :hg:`update --clean .` to cancel
373 the merge and leave the child of REV as a head to be merged
373 the merge and leave the child of REV as a head to be merged
374 separately.
374 separately.
375
375
376 See :hg:`help dates` for a list of formats valid for -d/--date.
376 See :hg:`help dates` for a list of formats valid for -d/--date.
377
377
378 Returns 0 on success.
378 Returns 0 on success.
379 '''
379 '''
380 if rev and node:
380 if rev and node:
381 raise util.Abort(_("please specify just one revision"))
381 raise util.Abort(_("please specify just one revision"))
382
382
383 if not rev:
383 if not rev:
384 rev = node
384 rev = node
385
385
386 if not rev:
386 if not rev:
387 raise util.Abort(_("please specify a revision to backout"))
387 raise util.Abort(_("please specify a revision to backout"))
388
388
389 date = opts.get('date')
389 date = opts.get('date')
390 if date:
390 if date:
391 opts['date'] = util.parsedate(date)
391 opts['date'] = util.parsedate(date)
392
392
393 cmdutil.bailifchanged(repo)
393 cmdutil.bailifchanged(repo)
394 node = scmutil.revsingle(repo, rev).node()
394 node = scmutil.revsingle(repo, rev).node()
395
395
396 op1, op2 = repo.dirstate.parents()
396 op1, op2 = repo.dirstate.parents()
397 a = repo.changelog.ancestor(op1, node)
397 a = repo.changelog.ancestor(op1, node)
398 if a != node:
398 if a != node:
399 raise util.Abort(_('cannot backout change on a different branch'))
399 raise util.Abort(_('cannot backout change on a different branch'))
400
400
401 p1, p2 = repo.changelog.parents(node)
401 p1, p2 = repo.changelog.parents(node)
402 if p1 == nullid:
402 if p1 == nullid:
403 raise util.Abort(_('cannot backout a change with no parents'))
403 raise util.Abort(_('cannot backout a change with no parents'))
404 if p2 != nullid:
404 if p2 != nullid:
405 if not opts.get('parent'):
405 if not opts.get('parent'):
406 raise util.Abort(_('cannot backout a merge changeset without '
406 raise util.Abort(_('cannot backout a merge changeset without '
407 '--parent'))
407 '--parent'))
408 p = repo.lookup(opts['parent'])
408 p = repo.lookup(opts['parent'])
409 if p not in (p1, p2):
409 if p not in (p1, p2):
410 raise util.Abort(_('%s is not a parent of %s') %
410 raise util.Abort(_('%s is not a parent of %s') %
411 (short(p), short(node)))
411 (short(p), short(node)))
412 parent = p
412 parent = p
413 else:
413 else:
414 if opts.get('parent'):
414 if opts.get('parent'):
415 raise util.Abort(_('cannot use --parent on non-merge changeset'))
415 raise util.Abort(_('cannot use --parent on non-merge changeset'))
416 parent = p1
416 parent = p1
417
417
418 # the backout should appear on the same branch
418 # the backout should appear on the same branch
419 branch = repo.dirstate.branch()
419 branch = repo.dirstate.branch()
420 hg.clean(repo, node, show_stats=False)
420 hg.clean(repo, node, show_stats=False)
421 repo.dirstate.setbranch(branch)
421 repo.dirstate.setbranch(branch)
422 revert_opts = opts.copy()
422 revert_opts = opts.copy()
423 revert_opts['date'] = None
423 revert_opts['date'] = None
424 revert_opts['all'] = True
424 revert_opts['all'] = True
425 revert_opts['rev'] = hex(parent)
425 revert_opts['rev'] = hex(parent)
426 revert_opts['no_backup'] = None
426 revert_opts['no_backup'] = None
427 revert(ui, repo, **revert_opts)
427 revert(ui, repo, **revert_opts)
428 if not opts.get('merge') and op1 != node:
428 if not opts.get('merge') and op1 != node:
429 try:
429 try:
430 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
430 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
431 return hg.update(repo, op1)
431 return hg.update(repo, op1)
432 finally:
432 finally:
433 ui.setconfig('ui', 'forcemerge', '')
433 ui.setconfig('ui', 'forcemerge', '')
434
434
435 commit_opts = opts.copy()
435 commit_opts = opts.copy()
436 commit_opts['addremove'] = False
436 commit_opts['addremove'] = False
437 if not commit_opts['message'] and not commit_opts['logfile']:
437 if not commit_opts['message'] and not commit_opts['logfile']:
438 # we don't translate commit messages
438 # we don't translate commit messages
439 commit_opts['message'] = "Backed out changeset %s" % short(node)
439 commit_opts['message'] = "Backed out changeset %s" % short(node)
440 commit_opts['force_editor'] = True
440 commit_opts['force_editor'] = True
441 commit(ui, repo, **commit_opts)
441 commit(ui, repo, **commit_opts)
442 def nice(node):
442 def nice(node):
443 return '%d:%s' % (repo.changelog.rev(node), short(node))
443 return '%d:%s' % (repo.changelog.rev(node), short(node))
444 ui.status(_('changeset %s backs out changeset %s\n') %
444 ui.status(_('changeset %s backs out changeset %s\n') %
445 (nice(repo.changelog.tip()), nice(node)))
445 (nice(repo.changelog.tip()), nice(node)))
446 if opts.get('merge') and op1 != node:
446 if opts.get('merge') and op1 != node:
447 hg.clean(repo, op1, show_stats=False)
447 hg.clean(repo, op1, show_stats=False)
448 ui.status(_('merging with changeset %s\n')
448 ui.status(_('merging with changeset %s\n')
449 % nice(repo.changelog.tip()))
449 % nice(repo.changelog.tip()))
450 try:
450 try:
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 return hg.merge(repo, hex(repo.changelog.tip()))
452 return hg.merge(repo, hex(repo.changelog.tip()))
453 finally:
453 finally:
454 ui.setconfig('ui', 'forcemerge', '')
454 ui.setconfig('ui', 'forcemerge', '')
455 return 0
455 return 0
456
456
457 @command('bisect',
457 @command('bisect',
458 [('r', 'reset', False, _('reset bisect state')),
458 [('r', 'reset', False, _('reset bisect state')),
459 ('g', 'good', False, _('mark changeset good')),
459 ('g', 'good', False, _('mark changeset good')),
460 ('b', 'bad', False, _('mark changeset bad')),
460 ('b', 'bad', False, _('mark changeset bad')),
461 ('s', 'skip', False, _('skip testing changeset')),
461 ('s', 'skip', False, _('skip testing changeset')),
462 ('e', 'extend', False, _('extend the bisect range')),
462 ('e', 'extend', False, _('extend the bisect range')),
463 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
463 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
464 ('U', 'noupdate', False, _('do not update to target'))],
464 ('U', 'noupdate', False, _('do not update to target'))],
465 _("[-gbsr] [-U] [-c CMD] [REV]"))
465 _("[-gbsr] [-U] [-c CMD] [REV]"))
466 def bisect(ui, repo, rev=None, extra=None, command=None,
466 def bisect(ui, repo, rev=None, extra=None, command=None,
467 reset=None, good=None, bad=None, skip=None, extend=None,
467 reset=None, good=None, bad=None, skip=None, extend=None,
468 noupdate=None):
468 noupdate=None):
469 """subdivision search of changesets
469 """subdivision search of changesets
470
470
471 This command helps to find changesets which introduce problems. To
471 This command helps to find changesets which introduce problems. To
472 use, mark the earliest changeset you know exhibits the problem as
472 use, mark the earliest changeset you know exhibits the problem as
473 bad, then mark the latest changeset which is free from the problem
473 bad, then mark the latest changeset which is free from the problem
474 as good. Bisect will update your working directory to a revision
474 as good. Bisect will update your working directory to a revision
475 for testing (unless the -U/--noupdate option is specified). Once
475 for testing (unless the -U/--noupdate option is specified). Once
476 you have performed tests, mark the working directory as good or
476 you have performed tests, mark the working directory as good or
477 bad, and bisect will either update to another candidate changeset
477 bad, and bisect will either update to another candidate changeset
478 or announce that it has found the bad revision.
478 or announce that it has found the bad revision.
479
479
480 As a shortcut, you can also use the revision argument to mark a
480 As a shortcut, you can also use the revision argument to mark a
481 revision as good or bad without checking it out first.
481 revision as good or bad without checking it out first.
482
482
483 If you supply a command, it will be used for automatic bisection.
483 If you supply a command, it will be used for automatic bisection.
484 Its exit status will be used to mark revisions as good or bad:
484 Its exit status will be used to mark revisions as good or bad:
485 status 0 means good, 125 means to skip the revision, 127
485 status 0 means good, 125 means to skip the revision, 127
486 (command not found) will abort the bisection, and any other
486 (command not found) will abort the bisection, and any other
487 non-zero exit status means the revision is bad.
487 non-zero exit status means the revision is bad.
488
488
489 Returns 0 on success.
489 Returns 0 on success.
490 """
490 """
491 def extendbisectrange(nodes, good):
491 def extendbisectrange(nodes, good):
492 # bisect is incomplete when it ends on a merge node and
492 # bisect is incomplete when it ends on a merge node and
493 # one of the parent was not checked.
493 # one of the parent was not checked.
494 parents = repo[nodes[0]].parents()
494 parents = repo[nodes[0]].parents()
495 if len(parents) > 1:
495 if len(parents) > 1:
496 side = good and state['bad'] or state['good']
496 side = good and state['bad'] or state['good']
497 num = len(set(i.node() for i in parents) & set(side))
497 num = len(set(i.node() for i in parents) & set(side))
498 if num == 1:
498 if num == 1:
499 return parents[0].ancestor(parents[1])
499 return parents[0].ancestor(parents[1])
500 return None
500 return None
501
501
502 def print_result(nodes, good):
502 def print_result(nodes, good):
503 displayer = cmdutil.show_changeset(ui, repo, {})
503 displayer = cmdutil.show_changeset(ui, repo, {})
504 if len(nodes) == 1:
504 if len(nodes) == 1:
505 # narrowed it down to a single revision
505 # narrowed it down to a single revision
506 if good:
506 if good:
507 ui.write(_("The first good revision is:\n"))
507 ui.write(_("The first good revision is:\n"))
508 else:
508 else:
509 ui.write(_("The first bad revision is:\n"))
509 ui.write(_("The first bad revision is:\n"))
510 displayer.show(repo[nodes[0]])
510 displayer.show(repo[nodes[0]])
511 extendnode = extendbisectrange(nodes, good)
511 extendnode = extendbisectrange(nodes, good)
512 if extendnode is not None:
512 if extendnode is not None:
513 ui.write(_('Not all ancestors of this changeset have been'
513 ui.write(_('Not all ancestors of this changeset have been'
514 ' checked.\nUse bisect --extend to continue the '
514 ' checked.\nUse bisect --extend to continue the '
515 'bisection from\nthe common ancestor, %s.\n')
515 'bisection from\nthe common ancestor, %s.\n')
516 % extendnode)
516 % extendnode)
517 else:
517 else:
518 # multiple possible revisions
518 # multiple possible revisions
519 if good:
519 if good:
520 ui.write(_("Due to skipped revisions, the first "
520 ui.write(_("Due to skipped revisions, the first "
521 "good revision could be any of:\n"))
521 "good revision could be any of:\n"))
522 else:
522 else:
523 ui.write(_("Due to skipped revisions, the first "
523 ui.write(_("Due to skipped revisions, the first "
524 "bad revision could be any of:\n"))
524 "bad revision could be any of:\n"))
525 for n in nodes:
525 for n in nodes:
526 displayer.show(repo[n])
526 displayer.show(repo[n])
527 displayer.close()
527 displayer.close()
528
528
529 def check_state(state, interactive=True):
529 def check_state(state, interactive=True):
530 if not state['good'] or not state['bad']:
530 if not state['good'] or not state['bad']:
531 if (good or bad or skip or reset) and interactive:
531 if (good or bad or skip or reset) and interactive:
532 return
532 return
533 if not state['good']:
533 if not state['good']:
534 raise util.Abort(_('cannot bisect (no known good revisions)'))
534 raise util.Abort(_('cannot bisect (no known good revisions)'))
535 else:
535 else:
536 raise util.Abort(_('cannot bisect (no known bad revisions)'))
536 raise util.Abort(_('cannot bisect (no known bad revisions)'))
537 return True
537 return True
538
538
539 # backward compatibility
539 # backward compatibility
540 if rev in "good bad reset init".split():
540 if rev in "good bad reset init".split():
541 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
541 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
542 cmd, rev, extra = rev, extra, None
542 cmd, rev, extra = rev, extra, None
543 if cmd == "good":
543 if cmd == "good":
544 good = True
544 good = True
545 elif cmd == "bad":
545 elif cmd == "bad":
546 bad = True
546 bad = True
547 else:
547 else:
548 reset = True
548 reset = True
549 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
549 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
550 raise util.Abort(_('incompatible arguments'))
550 raise util.Abort(_('incompatible arguments'))
551
551
552 if reset:
552 if reset:
553 p = repo.join("bisect.state")
553 p = repo.join("bisect.state")
554 if os.path.exists(p):
554 if os.path.exists(p):
555 os.unlink(p)
555 os.unlink(p)
556 return
556 return
557
557
558 state = hbisect.load_state(repo)
558 state = hbisect.load_state(repo)
559
559
560 if command:
560 if command:
561 changesets = 1
561 changesets = 1
562 try:
562 try:
563 while changesets:
563 while changesets:
564 # update state
564 # update state
565 status = util.system(command)
565 status = util.system(command)
566 if status == 125:
566 if status == 125:
567 transition = "skip"
567 transition = "skip"
568 elif status == 0:
568 elif status == 0:
569 transition = "good"
569 transition = "good"
570 # status < 0 means process was killed
570 # status < 0 means process was killed
571 elif status == 127:
571 elif status == 127:
572 raise util.Abort(_("failed to execute %s") % command)
572 raise util.Abort(_("failed to execute %s") % command)
573 elif status < 0:
573 elif status < 0:
574 raise util.Abort(_("%s killed") % command)
574 raise util.Abort(_("%s killed") % command)
575 else:
575 else:
576 transition = "bad"
576 transition = "bad"
577 ctx = scmutil.revsingle(repo, rev)
577 ctx = scmutil.revsingle(repo, rev)
578 rev = None # clear for future iterations
578 rev = None # clear for future iterations
579 state[transition].append(ctx.node())
579 state[transition].append(ctx.node())
580 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
580 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
581 check_state(state, interactive=False)
581 check_state(state, interactive=False)
582 # bisect
582 # bisect
583 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
583 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
584 # update to next check
584 # update to next check
585 cmdutil.bailifchanged(repo)
585 cmdutil.bailifchanged(repo)
586 hg.clean(repo, nodes[0], show_stats=False)
586 hg.clean(repo, nodes[0], show_stats=False)
587 finally:
587 finally:
588 hbisect.save_state(repo, state)
588 hbisect.save_state(repo, state)
589 print_result(nodes, good)
589 print_result(nodes, good)
590 return
590 return
591
591
592 # update state
592 # update state
593
593
594 if rev:
594 if rev:
595 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
595 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
596 else:
596 else:
597 nodes = [repo.lookup('.')]
597 nodes = [repo.lookup('.')]
598
598
599 if good or bad or skip:
599 if good or bad or skip:
600 if good:
600 if good:
601 state['good'] += nodes
601 state['good'] += nodes
602 elif bad:
602 elif bad:
603 state['bad'] += nodes
603 state['bad'] += nodes
604 elif skip:
604 elif skip:
605 state['skip'] += nodes
605 state['skip'] += nodes
606 hbisect.save_state(repo, state)
606 hbisect.save_state(repo, state)
607
607
608 if not check_state(state):
608 if not check_state(state):
609 return
609 return
610
610
611 # actually bisect
611 # actually bisect
612 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
612 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
613 if extend:
613 if extend:
614 if not changesets:
614 if not changesets:
615 extendnode = extendbisectrange(nodes, good)
615 extendnode = extendbisectrange(nodes, good)
616 if extendnode is not None:
616 if extendnode is not None:
617 ui.write(_("Extending search to changeset %d:%s\n"
617 ui.write(_("Extending search to changeset %d:%s\n"
618 % (extendnode.rev(), extendnode)))
618 % (extendnode.rev(), extendnode)))
619 if noupdate:
619 if noupdate:
620 return
620 return
621 cmdutil.bailifchanged(repo)
621 cmdutil.bailifchanged(repo)
622 return hg.clean(repo, extendnode.node())
622 return hg.clean(repo, extendnode.node())
623 raise util.Abort(_("nothing to extend"))
623 raise util.Abort(_("nothing to extend"))
624
624
625 if changesets == 0:
625 if changesets == 0:
626 print_result(nodes, good)
626 print_result(nodes, good)
627 else:
627 else:
628 assert len(nodes) == 1 # only a single node can be tested next
628 assert len(nodes) == 1 # only a single node can be tested next
629 node = nodes[0]
629 node = nodes[0]
630 # compute the approximate number of remaining tests
630 # compute the approximate number of remaining tests
631 tests, size = 0, 2
631 tests, size = 0, 2
632 while size <= changesets:
632 while size <= changesets:
633 tests, size = tests + 1, size * 2
633 tests, size = tests + 1, size * 2
634 rev = repo.changelog.rev(node)
634 rev = repo.changelog.rev(node)
635 ui.write(_("Testing changeset %d:%s "
635 ui.write(_("Testing changeset %d:%s "
636 "(%d changesets remaining, ~%d tests)\n")
636 "(%d changesets remaining, ~%d tests)\n")
637 % (rev, short(node), changesets, tests))
637 % (rev, short(node), changesets, tests))
638 if not noupdate:
638 if not noupdate:
639 cmdutil.bailifchanged(repo)
639 cmdutil.bailifchanged(repo)
640 return hg.clean(repo, node)
640 return hg.clean(repo, node)
641
641
642 @command('bookmarks',
642 @command('bookmarks',
643 [('f', 'force', False, _('force')),
643 [('f', 'force', False, _('force')),
644 ('r', 'rev', '', _('revision'), _('REV')),
644 ('r', 'rev', '', _('revision'), _('REV')),
645 ('d', 'delete', False, _('delete a given bookmark')),
645 ('d', 'delete', False, _('delete a given bookmark')),
646 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
646 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
647 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
647 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
648 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
648 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
649 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
649 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
650 rename=None, inactive=False):
650 rename=None, inactive=False):
651 '''track a line of development with movable markers
651 '''track a line of development with movable markers
652
652
653 Bookmarks are pointers to certain commits that move when
653 Bookmarks are pointers to certain commits that move when
654 committing. Bookmarks are local. They can be renamed, copied and
654 committing. Bookmarks are local. They can be renamed, copied and
655 deleted. It is possible to use bookmark names in :hg:`merge` and
655 deleted. It is possible to use bookmark names in :hg:`merge` and
656 :hg:`update` to merge and update respectively to a given bookmark.
656 :hg:`update` to merge and update respectively to a given bookmark.
657
657
658 You can use :hg:`bookmark NAME` to set a bookmark on the working
658 You can use :hg:`bookmark NAME` to set a bookmark on the working
659 directory's parent revision with the given name. If you specify
659 directory's parent revision with the given name. If you specify
660 a revision using -r REV (where REV may be an existing bookmark),
660 a revision using -r REV (where REV may be an existing bookmark),
661 the bookmark is assigned to that revision.
661 the bookmark is assigned to that revision.
662
662
663 Bookmarks can be pushed and pulled between repositories (see :hg:`help
663 Bookmarks can be pushed and pulled between repositories (see :hg:`help
664 push` and :hg:`help pull`). This requires both the local and remote
664 push` and :hg:`help pull`). This requires both the local and remote
665 repositories to support bookmarks. For versions prior to 1.8, this means
665 repositories to support bookmarks. For versions prior to 1.8, this means
666 the bookmarks extension must be enabled.
666 the bookmarks extension must be enabled.
667 '''
667 '''
668 hexfn = ui.debugflag and hex or short
668 hexfn = ui.debugflag and hex or short
669 marks = repo._bookmarks
669 marks = repo._bookmarks
670 cur = repo.changectx('.').node()
670 cur = repo.changectx('.').node()
671
671
672 if rename:
672 if rename:
673 if rename not in marks:
673 if rename not in marks:
674 raise util.Abort(_("bookmark '%s' does not exist") % rename)
674 raise util.Abort(_("bookmark '%s' does not exist") % rename)
675 if mark in marks and not force:
675 if mark in marks and not force:
676 raise util.Abort(_("bookmark '%s' already exists "
676 raise util.Abort(_("bookmark '%s' already exists "
677 "(use -f to force)") % mark)
677 "(use -f to force)") % mark)
678 if mark is None:
678 if mark is None:
679 raise util.Abort(_("new bookmark name required"))
679 raise util.Abort(_("new bookmark name required"))
680 marks[mark] = marks[rename]
680 marks[mark] = marks[rename]
681 if repo._bookmarkcurrent == rename and not inactive:
681 if repo._bookmarkcurrent == rename and not inactive:
682 bookmarks.setcurrent(repo, mark)
682 bookmarks.setcurrent(repo, mark)
683 del marks[rename]
683 del marks[rename]
684 bookmarks.write(repo)
684 bookmarks.write(repo)
685 return
685 return
686
686
687 if delete:
687 if delete:
688 if mark is None:
688 if mark is None:
689 raise util.Abort(_("bookmark name required"))
689 raise util.Abort(_("bookmark name required"))
690 if mark not in marks:
690 if mark not in marks:
691 raise util.Abort(_("bookmark '%s' does not exist") % mark)
691 raise util.Abort(_("bookmark '%s' does not exist") % mark)
692 if mark == repo._bookmarkcurrent:
692 if mark == repo._bookmarkcurrent:
693 bookmarks.setcurrent(repo, None)
693 bookmarks.setcurrent(repo, None)
694 del marks[mark]
694 del marks[mark]
695 bookmarks.write(repo)
695 bookmarks.write(repo)
696 return
696 return
697
697
698 if mark is not None:
698 if mark is not None:
699 if "\n" in mark:
699 if "\n" in mark:
700 raise util.Abort(_("bookmark name cannot contain newlines"))
700 raise util.Abort(_("bookmark name cannot contain newlines"))
701 mark = mark.strip()
701 mark = mark.strip()
702 if not mark:
702 if not mark:
703 raise util.Abort(_("bookmark names cannot consist entirely of "
703 raise util.Abort(_("bookmark names cannot consist entirely of "
704 "whitespace"))
704 "whitespace"))
705 if inactive and mark == repo._bookmarkcurrent:
705 if inactive and mark == repo._bookmarkcurrent:
706 bookmarks.setcurrent(repo, None)
706 bookmarks.setcurrent(repo, None)
707 return
707 return
708 if mark in marks and not force:
708 if mark in marks and not force:
709 raise util.Abort(_("bookmark '%s' already exists "
709 raise util.Abort(_("bookmark '%s' already exists "
710 "(use -f to force)") % mark)
710 "(use -f to force)") % mark)
711 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
711 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
712 and not force):
712 and not force):
713 raise util.Abort(
713 raise util.Abort(
714 _("a bookmark cannot have the name of an existing branch"))
714 _("a bookmark cannot have the name of an existing branch"))
715 if rev:
715 if rev:
716 marks[mark] = repo.lookup(rev)
716 marks[mark] = repo.lookup(rev)
717 else:
717 else:
718 marks[mark] = repo.changectx('.').node()
718 marks[mark] = repo.changectx('.').node()
719 if not inactive and repo.changectx('.').node() == marks[mark]:
719 if not inactive and repo.changectx('.').node() == marks[mark]:
720 bookmarks.setcurrent(repo, mark)
720 bookmarks.setcurrent(repo, mark)
721 bookmarks.write(repo)
721 bookmarks.write(repo)
722 return
722 return
723
723
724 if mark is None:
724 if mark is None:
725 if rev:
725 if rev:
726 raise util.Abort(_("bookmark name required"))
726 raise util.Abort(_("bookmark name required"))
727 if len(marks) == 0:
727 if len(marks) == 0:
728 ui.status(_("no bookmarks set\n"))
728 ui.status(_("no bookmarks set\n"))
729 else:
729 else:
730 for bmark, n in sorted(marks.iteritems()):
730 for bmark, n in sorted(marks.iteritems()):
731 current = repo._bookmarkcurrent
731 current = repo._bookmarkcurrent
732 if bmark == current and n == cur:
732 if bmark == current and n == cur:
733 prefix, label = '*', 'bookmarks.current'
733 prefix, label = '*', 'bookmarks.current'
734 else:
734 else:
735 prefix, label = ' ', ''
735 prefix, label = ' ', ''
736
736
737 if ui.quiet:
737 if ui.quiet:
738 ui.write("%s\n" % bmark, label=label)
738 ui.write("%s\n" % bmark, label=label)
739 else:
739 else:
740 ui.write(" %s %-25s %d:%s\n" % (
740 ui.write(" %s %-25s %d:%s\n" % (
741 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
741 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
742 label=label)
742 label=label)
743 return
743 return
744
744
745 @command('branch',
745 @command('branch',
746 [('f', 'force', None,
746 [('f', 'force', None,
747 _('set branch name even if it shadows an existing branch')),
747 _('set branch name even if it shadows an existing branch')),
748 ('C', 'clean', None, _('reset branch name to parent branch name'))],
748 ('C', 'clean', None, _('reset branch name to parent branch name'))],
749 _('[-fC] [NAME]'))
749 _('[-fC] [NAME]'))
750 def branch(ui, repo, label=None, **opts):
750 def branch(ui, repo, label=None, **opts):
751 """set or show the current branch name
751 """set or show the current branch name
752
752
753 With no argument, show the current branch name. With one argument,
753 With no argument, show the current branch name. With one argument,
754 set the working directory branch name (the branch will not exist
754 set the working directory branch name (the branch will not exist
755 in the repository until the next commit). Standard practice
755 in the repository until the next commit). Standard practice
756 recommends that primary development take place on the 'default'
756 recommends that primary development take place on the 'default'
757 branch.
757 branch.
758
758
759 Unless -f/--force is specified, branch will not let you set a
759 Unless -f/--force is specified, branch will not let you set a
760 branch name that already exists, even if it's inactive.
760 branch name that already exists, even if it's inactive.
761
761
762 Use -C/--clean to reset the working directory branch to that of
762 Use -C/--clean to reset the working directory branch to that of
763 the parent of the working directory, negating a previous branch
763 the parent of the working directory, negating a previous branch
764 change.
764 change.
765
765
766 Use the command :hg:`update` to switch to an existing branch. Use
766 Use the command :hg:`update` to switch to an existing branch. Use
767 :hg:`commit --close-branch` to mark this branch as closed.
767 :hg:`commit --close-branch` to mark this branch as closed.
768
768
769 .. note::
769 .. note::
770
770
771 Branch names are permanent. Use :hg:`bookmark` to create a
771 Branch names are permanent. Use :hg:`bookmark` to create a
772 light-weight bookmark instead. See :hg:`help glossary` for more
772 light-weight bookmark instead. See :hg:`help glossary` for more
773 information about named branches and bookmarks.
773 information about named branches and bookmarks.
774
774
775 Returns 0 on success.
775 Returns 0 on success.
776 """
776 """
777
777
778 if opts.get('clean'):
778 if opts.get('clean'):
779 label = repo[None].p1().branch()
779 label = repo[None].p1().branch()
780 repo.dirstate.setbranch(label)
780 repo.dirstate.setbranch(label)
781 ui.status(_('reset working directory to branch %s\n') % label)
781 ui.status(_('reset working directory to branch %s\n') % label)
782 elif label:
782 elif label:
783 if not opts.get('force') and label in repo.branchtags():
783 if not opts.get('force') and label in repo.branchtags():
784 if label not in [p.branch() for p in repo.parents()]:
784 if label not in [p.branch() for p in repo.parents()]:
785 raise util.Abort(_('a branch of the same name already exists'),
785 raise util.Abort(_('a branch of the same name already exists'),
786 # i18n: "it" refers to an existing branch
786 # i18n: "it" refers to an existing branch
787 hint=_("use 'hg update' to switch to it"))
787 hint=_("use 'hg update' to switch to it"))
788 repo.dirstate.setbranch(label)
788 repo.dirstate.setbranch(label)
789 ui.status(_('marked working directory as branch %s\n') % label)
789 ui.status(_('marked working directory as branch %s\n') % label)
790 else:
790 else:
791 ui.write("%s\n" % repo.dirstate.branch())
791 ui.write("%s\n" % repo.dirstate.branch())
792
792
793 @command('branches',
793 @command('branches',
794 [('a', 'active', False, _('show only branches that have unmerged heads')),
794 [('a', 'active', False, _('show only branches that have unmerged heads')),
795 ('c', 'closed', False, _('show normal and closed branches'))],
795 ('c', 'closed', False, _('show normal and closed branches'))],
796 _('[-ac]'))
796 _('[-ac]'))
797 def branches(ui, repo, active=False, closed=False):
797 def branches(ui, repo, active=False, closed=False):
798 """list repository named branches
798 """list repository named branches
799
799
800 List the repository's named branches, indicating which ones are
800 List the repository's named branches, indicating which ones are
801 inactive. If -c/--closed is specified, also list branches which have
801 inactive. If -c/--closed is specified, also list branches which have
802 been marked closed (see :hg:`commit --close-branch`).
802 been marked closed (see :hg:`commit --close-branch`).
803
803
804 If -a/--active is specified, only show active branches. A branch
804 If -a/--active is specified, only show active branches. A branch
805 is considered active if it contains repository heads.
805 is considered active if it contains repository heads.
806
806
807 Use the command :hg:`update` to switch to an existing branch.
807 Use the command :hg:`update` to switch to an existing branch.
808
808
809 Returns 0.
809 Returns 0.
810 """
810 """
811
811
812 hexfunc = ui.debugflag and hex or short
812 hexfunc = ui.debugflag and hex or short
813 activebranches = [repo[n].branch() for n in repo.heads()]
813 activebranches = [repo[n].branch() for n in repo.heads()]
814 def testactive(tag, node):
814 def testactive(tag, node):
815 realhead = tag in activebranches
815 realhead = tag in activebranches
816 open = node in repo.branchheads(tag, closed=False)
816 open = node in repo.branchheads(tag, closed=False)
817 return realhead and open
817 return realhead and open
818 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
818 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
819 for tag, node in repo.branchtags().items()],
819 for tag, node in repo.branchtags().items()],
820 reverse=True)
820 reverse=True)
821
821
822 for isactive, node, tag in branches:
822 for isactive, node, tag in branches:
823 if (not active) or isactive:
823 if (not active) or isactive:
824 if ui.quiet:
824 if ui.quiet:
825 ui.write("%s\n" % tag)
825 ui.write("%s\n" % tag)
826 else:
826 else:
827 hn = repo.lookup(node)
827 hn = repo.lookup(node)
828 if isactive:
828 if isactive:
829 label = 'branches.active'
829 label = 'branches.active'
830 notice = ''
830 notice = ''
831 elif hn not in repo.branchheads(tag, closed=False):
831 elif hn not in repo.branchheads(tag, closed=False):
832 if not closed:
832 if not closed:
833 continue
833 continue
834 label = 'branches.closed'
834 label = 'branches.closed'
835 notice = _(' (closed)')
835 notice = _(' (closed)')
836 else:
836 else:
837 label = 'branches.inactive'
837 label = 'branches.inactive'
838 notice = _(' (inactive)')
838 notice = _(' (inactive)')
839 if tag == repo.dirstate.branch():
839 if tag == repo.dirstate.branch():
840 label = 'branches.current'
840 label = 'branches.current'
841 rev = str(node).rjust(31 - encoding.colwidth(tag))
841 rev = str(node).rjust(31 - encoding.colwidth(tag))
842 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
842 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
843 tag = ui.label(tag, label)
843 tag = ui.label(tag, label)
844 ui.write("%s %s%s\n" % (tag, rev, notice))
844 ui.write("%s %s%s\n" % (tag, rev, notice))
845
845
846 @command('bundle',
846 @command('bundle',
847 [('f', 'force', None, _('run even when the destination is unrelated')),
847 [('f', 'force', None, _('run even when the destination is unrelated')),
848 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
848 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
849 _('REV')),
849 _('REV')),
850 ('b', 'branch', [], _('a specific branch you would like to bundle'),
850 ('b', 'branch', [], _('a specific branch you would like to bundle'),
851 _('BRANCH')),
851 _('BRANCH')),
852 ('', 'base', [],
852 ('', 'base', [],
853 _('a base changeset assumed to be available at the destination'),
853 _('a base changeset assumed to be available at the destination'),
854 _('REV')),
854 _('REV')),
855 ('a', 'all', None, _('bundle all changesets in the repository')),
855 ('a', 'all', None, _('bundle all changesets in the repository')),
856 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
856 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
857 ] + remoteopts,
857 ] + remoteopts,
858 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
858 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
859 def bundle(ui, repo, fname, dest=None, **opts):
859 def bundle(ui, repo, fname, dest=None, **opts):
860 """create a changegroup file
860 """create a changegroup file
861
861
862 Generate a compressed changegroup file collecting changesets not
862 Generate a compressed changegroup file collecting changesets not
863 known to be in another repository.
863 known to be in another repository.
864
864
865 If you omit the destination repository, then hg assumes the
865 If you omit the destination repository, then hg assumes the
866 destination will have all the nodes you specify with --base
866 destination will have all the nodes you specify with --base
867 parameters. To create a bundle containing all changesets, use
867 parameters. To create a bundle containing all changesets, use
868 -a/--all (or --base null).
868 -a/--all (or --base null).
869
869
870 You can change compression method with the -t/--type option.
870 You can change compression method with the -t/--type option.
871 The available compression methods are: none, bzip2, and
871 The available compression methods are: none, bzip2, and
872 gzip (by default, bundles are compressed using bzip2).
872 gzip (by default, bundles are compressed using bzip2).
873
873
874 The bundle file can then be transferred using conventional means
874 The bundle file can then be transferred using conventional means
875 and applied to another repository with the unbundle or pull
875 and applied to another repository with the unbundle or pull
876 command. This is useful when direct push and pull are not
876 command. This is useful when direct push and pull are not
877 available or when exporting an entire repository is undesirable.
877 available or when exporting an entire repository is undesirable.
878
878
879 Applying bundles preserves all changeset contents including
879 Applying bundles preserves all changeset contents including
880 permissions, copy/rename information, and revision history.
880 permissions, copy/rename information, and revision history.
881
881
882 Returns 0 on success, 1 if no changes found.
882 Returns 0 on success, 1 if no changes found.
883 """
883 """
884 revs = None
884 revs = None
885 if 'rev' in opts:
885 if 'rev' in opts:
886 revs = scmutil.revrange(repo, opts['rev'])
886 revs = scmutil.revrange(repo, opts['rev'])
887
887
888 if opts.get('all'):
888 if opts.get('all'):
889 base = ['null']
889 base = ['null']
890 else:
890 else:
891 base = scmutil.revrange(repo, opts.get('base'))
891 base = scmutil.revrange(repo, opts.get('base'))
892 if base:
892 if base:
893 if dest:
893 if dest:
894 raise util.Abort(_("--base is incompatible with specifying "
894 raise util.Abort(_("--base is incompatible with specifying "
895 "a destination"))
895 "a destination"))
896 common = [repo.lookup(rev) for rev in base]
896 common = [repo.lookup(rev) for rev in base]
897 heads = revs and map(repo.lookup, revs) or revs
897 heads = revs and map(repo.lookup, revs) or revs
898 else:
898 else:
899 dest = ui.expandpath(dest or 'default-push', dest or 'default')
899 dest = ui.expandpath(dest or 'default-push', dest or 'default')
900 dest, branches = hg.parseurl(dest, opts.get('branch'))
900 dest, branches = hg.parseurl(dest, opts.get('branch'))
901 other = hg.peer(repo, opts, dest)
901 other = hg.peer(repo, opts, dest)
902 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
902 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
903 heads = revs and map(repo.lookup, revs) or revs
903 heads = revs and map(repo.lookup, revs) or revs
904 common, outheads = discovery.findcommonoutgoing(repo, other,
904 common, outheads = discovery.findcommonoutgoing(repo, other,
905 onlyheads=heads,
905 onlyheads=heads,
906 force=opts.get('force'))
906 force=opts.get('force'))
907
907
908 cg = repo.getbundle('bundle', common=common, heads=heads)
908 cg = repo.getbundle('bundle', common=common, heads=heads)
909 if not cg:
909 if not cg:
910 ui.status(_("no changes found\n"))
910 ui.status(_("no changes found\n"))
911 return 1
911 return 1
912
912
913 bundletype = opts.get('type', 'bzip2').lower()
913 bundletype = opts.get('type', 'bzip2').lower()
914 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
914 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
915 bundletype = btypes.get(bundletype)
915 bundletype = btypes.get(bundletype)
916 if bundletype not in changegroup.bundletypes:
916 if bundletype not in changegroup.bundletypes:
917 raise util.Abort(_('unknown bundle type specified with --type'))
917 raise util.Abort(_('unknown bundle type specified with --type'))
918
918
919 changegroup.writebundle(cg, fname, bundletype)
919 changegroup.writebundle(cg, fname, bundletype)
920
920
921 @command('cat',
921 @command('cat',
922 [('o', 'output', '',
922 [('o', 'output', '',
923 _('print output to file with formatted name'), _('FORMAT')),
923 _('print output to file with formatted name'), _('FORMAT')),
924 ('r', 'rev', '', _('print the given revision'), _('REV')),
924 ('r', 'rev', '', _('print the given revision'), _('REV')),
925 ('', 'decode', None, _('apply any matching decode filter')),
925 ('', 'decode', None, _('apply any matching decode filter')),
926 ] + walkopts,
926 ] + walkopts,
927 _('[OPTION]... FILE...'))
927 _('[OPTION]... FILE...'))
928 def cat(ui, repo, file1, *pats, **opts):
928 def cat(ui, repo, file1, *pats, **opts):
929 """output the current or given revision of files
929 """output the current or given revision of files
930
930
931 Print the specified files as they were at the given revision. If
931 Print the specified files as they were at the given revision. If
932 no revision is given, the parent of the working directory is used,
932 no revision is given, the parent of the working directory is used,
933 or tip if no revision is checked out.
933 or tip if no revision is checked out.
934
934
935 Output may be to a file, in which case the name of the file is
935 Output may be to a file, in which case the name of the file is
936 given using a format string. The formatting rules are the same as
936 given using a format string. The formatting rules are the same as
937 for the export command, with the following additions:
937 for the export command, with the following additions:
938
938
939 :``%s``: basename of file being printed
939 :``%s``: basename of file being printed
940 :``%d``: dirname of file being printed, or '.' if in repository root
940 :``%d``: dirname of file being printed, or '.' if in repository root
941 :``%p``: root-relative path name of file being printed
941 :``%p``: root-relative path name of file being printed
942
942
943 Returns 0 on success.
943 Returns 0 on success.
944 """
944 """
945 ctx = scmutil.revsingle(repo, opts.get('rev'))
945 ctx = scmutil.revsingle(repo, opts.get('rev'))
946 err = 1
946 err = 1
947 m = scmutil.match(ctx, (file1,) + pats, opts)
947 m = scmutil.match(ctx, (file1,) + pats, opts)
948 for abs in ctx.walk(m):
948 for abs in ctx.walk(m):
949 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
949 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
950 pathname=abs)
950 pathname=abs)
951 data = ctx[abs].data()
951 data = ctx[abs].data()
952 if opts.get('decode'):
952 if opts.get('decode'):
953 data = repo.wwritedata(abs, data)
953 data = repo.wwritedata(abs, data)
954 fp.write(data)
954 fp.write(data)
955 fp.close()
955 fp.close()
956 err = 0
956 err = 0
957 return err
957 return err
958
958
959 @command('^clone',
959 @command('^clone',
960 [('U', 'noupdate', None,
960 [('U', 'noupdate', None,
961 _('the clone will include an empty working copy (only a repository)')),
961 _('the clone will include an empty working copy (only a repository)')),
962 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
962 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
963 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
963 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
964 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
964 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
965 ('', 'pull', None, _('use pull protocol to copy metadata')),
965 ('', 'pull', None, _('use pull protocol to copy metadata')),
966 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
966 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
967 ] + remoteopts,
967 ] + remoteopts,
968 _('[OPTION]... SOURCE [DEST]'))
968 _('[OPTION]... SOURCE [DEST]'))
969 def clone(ui, source, dest=None, **opts):
969 def clone(ui, source, dest=None, **opts):
970 """make a copy of an existing repository
970 """make a copy of an existing repository
971
971
972 Create a copy of an existing repository in a new directory.
972 Create a copy of an existing repository in a new directory.
973
973
974 If no destination directory name is specified, it defaults to the
974 If no destination directory name is specified, it defaults to the
975 basename of the source.
975 basename of the source.
976
976
977 The location of the source is added to the new repository's
977 The location of the source is added to the new repository's
978 ``.hg/hgrc`` file, as the default to be used for future pulls.
978 ``.hg/hgrc`` file, as the default to be used for future pulls.
979
979
980 See :hg:`help urls` for valid source format details.
980 See :hg:`help urls` for valid source format details.
981
981
982 It is possible to specify an ``ssh://`` URL as the destination, but no
982 It is possible to specify an ``ssh://`` URL as the destination, but no
983 ``.hg/hgrc`` and working directory will be created on the remote side.
983 ``.hg/hgrc`` and working directory will be created on the remote side.
984 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
984 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
985
985
986 A set of changesets (tags, or branch names) to pull may be specified
986 A set of changesets (tags, or branch names) to pull may be specified
987 by listing each changeset (tag, or branch name) with -r/--rev.
987 by listing each changeset (tag, or branch name) with -r/--rev.
988 If -r/--rev is used, the cloned repository will contain only a subset
988 If -r/--rev is used, the cloned repository will contain only a subset
989 of the changesets of the source repository. Only the set of changesets
989 of the changesets of the source repository. Only the set of changesets
990 defined by all -r/--rev options (including all their ancestors)
990 defined by all -r/--rev options (including all their ancestors)
991 will be pulled into the destination repository.
991 will be pulled into the destination repository.
992 No subsequent changesets (including subsequent tags) will be present
992 No subsequent changesets (including subsequent tags) will be present
993 in the destination.
993 in the destination.
994
994
995 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
995 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
996 local source repositories.
996 local source repositories.
997
997
998 For efficiency, hardlinks are used for cloning whenever the source
998 For efficiency, hardlinks are used for cloning whenever the source
999 and destination are on the same filesystem (note this applies only
999 and destination are on the same filesystem (note this applies only
1000 to the repository data, not to the working directory). Some
1000 to the repository data, not to the working directory). Some
1001 filesystems, such as AFS, implement hardlinking incorrectly, but
1001 filesystems, such as AFS, implement hardlinking incorrectly, but
1002 do not report errors. In these cases, use the --pull option to
1002 do not report errors. In these cases, use the --pull option to
1003 avoid hardlinking.
1003 avoid hardlinking.
1004
1004
1005 In some cases, you can clone repositories and the working directory
1005 In some cases, you can clone repositories and the working directory
1006 using full hardlinks with ::
1006 using full hardlinks with ::
1007
1007
1008 $ cp -al REPO REPOCLONE
1008 $ cp -al REPO REPOCLONE
1009
1009
1010 This is the fastest way to clone, but it is not always safe. The
1010 This is the fastest way to clone, but it is not always safe. The
1011 operation is not atomic (making sure REPO is not modified during
1011 operation is not atomic (making sure REPO is not modified during
1012 the operation is up to you) and you have to make sure your editor
1012 the operation is up to you) and you have to make sure your editor
1013 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1013 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1014 this is not compatible with certain extensions that place their
1014 this is not compatible with certain extensions that place their
1015 metadata under the .hg directory, such as mq.
1015 metadata under the .hg directory, such as mq.
1016
1016
1017 Mercurial will update the working directory to the first applicable
1017 Mercurial will update the working directory to the first applicable
1018 revision from this list:
1018 revision from this list:
1019
1019
1020 a) null if -U or the source repository has no changesets
1020 a) null if -U or the source repository has no changesets
1021 b) if -u . and the source repository is local, the first parent of
1021 b) if -u . and the source repository is local, the first parent of
1022 the source repository's working directory
1022 the source repository's working directory
1023 c) the changeset specified with -u (if a branch name, this means the
1023 c) the changeset specified with -u (if a branch name, this means the
1024 latest head of that branch)
1024 latest head of that branch)
1025 d) the changeset specified with -r
1025 d) the changeset specified with -r
1026 e) the tipmost head specified with -b
1026 e) the tipmost head specified with -b
1027 f) the tipmost head specified with the url#branch source syntax
1027 f) the tipmost head specified with the url#branch source syntax
1028 g) the tipmost head of the default branch
1028 g) the tipmost head of the default branch
1029 h) tip
1029 h) tip
1030
1030
1031 Returns 0 on success.
1031 Returns 0 on success.
1032 """
1032 """
1033 if opts.get('noupdate') and opts.get('updaterev'):
1033 if opts.get('noupdate') and opts.get('updaterev'):
1034 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1034 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1035
1035
1036 r = hg.clone(ui, opts, source, dest,
1036 r = hg.clone(ui, opts, source, dest,
1037 pull=opts.get('pull'),
1037 pull=opts.get('pull'),
1038 stream=opts.get('uncompressed'),
1038 stream=opts.get('uncompressed'),
1039 rev=opts.get('rev'),
1039 rev=opts.get('rev'),
1040 update=opts.get('updaterev') or not opts.get('noupdate'),
1040 update=opts.get('updaterev') or not opts.get('noupdate'),
1041 branch=opts.get('branch'))
1041 branch=opts.get('branch'))
1042
1042
1043 return r is None
1043 return r is None
1044
1044
1045 @command('^commit|ci',
1045 @command('^commit|ci',
1046 [('A', 'addremove', None,
1046 [('A', 'addremove', None,
1047 _('mark new/missing files as added/removed before committing')),
1047 _('mark new/missing files as added/removed before committing')),
1048 ('', 'close-branch', None,
1048 ('', 'close-branch', None,
1049 _('mark a branch as closed, hiding it from the branch list')),
1049 _('mark a branch as closed, hiding it from the branch list')),
1050 ] + walkopts + commitopts + commitopts2,
1050 ] + walkopts + commitopts + commitopts2,
1051 _('[OPTION]... [FILE]...'))
1051 _('[OPTION]... [FILE]...'))
1052 def commit(ui, repo, *pats, **opts):
1052 def commit(ui, repo, *pats, **opts):
1053 """commit the specified files or all outstanding changes
1053 """commit the specified files or all outstanding changes
1054
1054
1055 Commit changes to the given files into the repository. Unlike a
1055 Commit changes to the given files into the repository. Unlike a
1056 centralized SCM, this operation is a local operation. See
1056 centralized SCM, this operation is a local operation. See
1057 :hg:`push` for a way to actively distribute your changes.
1057 :hg:`push` for a way to actively distribute your changes.
1058
1058
1059 If a list of files is omitted, all changes reported by :hg:`status`
1059 If a list of files is omitted, all changes reported by :hg:`status`
1060 will be committed.
1060 will be committed.
1061
1061
1062 If you are committing the result of a merge, do not provide any
1062 If you are committing the result of a merge, do not provide any
1063 filenames or -I/-X filters.
1063 filenames or -I/-X filters.
1064
1064
1065 If no commit message is specified, Mercurial starts your
1065 If no commit message is specified, Mercurial starts your
1066 configured editor where you can enter a message. In case your
1066 configured editor where you can enter a message. In case your
1067 commit fails, you will find a backup of your message in
1067 commit fails, you will find a backup of your message in
1068 ``.hg/last-message.txt``.
1068 ``.hg/last-message.txt``.
1069
1069
1070 See :hg:`help dates` for a list of formats valid for -d/--date.
1070 See :hg:`help dates` for a list of formats valid for -d/--date.
1071
1071
1072 Returns 0 on success, 1 if nothing changed.
1072 Returns 0 on success, 1 if nothing changed.
1073 """
1073 """
1074 extra = {}
1074 extra = {}
1075 if opts.get('close_branch'):
1075 if opts.get('close_branch'):
1076 if repo['.'].node() not in repo.branchheads():
1076 if repo['.'].node() not in repo.branchheads():
1077 # The topo heads set is included in the branch heads set of the
1077 # The topo heads set is included in the branch heads set of the
1078 # current branch, so it's sufficient to test branchheads
1078 # current branch, so it's sufficient to test branchheads
1079 raise util.Abort(_('can only close branch heads'))
1079 raise util.Abort(_('can only close branch heads'))
1080 extra['close'] = 1
1080 extra['close'] = 1
1081 e = cmdutil.commiteditor
1081 e = cmdutil.commiteditor
1082 if opts.get('force_editor'):
1082 if opts.get('force_editor'):
1083 e = cmdutil.commitforceeditor
1083 e = cmdutil.commitforceeditor
1084
1084
1085 def commitfunc(ui, repo, message, match, opts):
1085 def commitfunc(ui, repo, message, match, opts):
1086 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1086 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1087 editor=e, extra=extra)
1087 editor=e, extra=extra)
1088
1088
1089 branch = repo[None].branch()
1089 branch = repo[None].branch()
1090 bheads = repo.branchheads(branch)
1090 bheads = repo.branchheads(branch)
1091
1091
1092 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1092 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1093 if not node:
1093 if not node:
1094 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1094 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1095 if stat[3]:
1095 if stat[3]:
1096 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1096 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1097 % len(stat[3]))
1097 % len(stat[3]))
1098 else:
1098 else:
1099 ui.status(_("nothing changed\n"))
1099 ui.status(_("nothing changed\n"))
1100 return 1
1100 return 1
1101
1101
1102 ctx = repo[node]
1102 ctx = repo[node]
1103 parents = ctx.parents()
1103 parents = ctx.parents()
1104
1104
1105 if bheads and not [x for x in parents
1105 if bheads and not [x for x in parents
1106 if x.node() in bheads and x.branch() == branch]:
1106 if x.node() in bheads and x.branch() == branch]:
1107 ui.status(_('created new head\n'))
1107 ui.status(_('created new head\n'))
1108 # The message is not printed for initial roots. For the other
1108 # The message is not printed for initial roots. For the other
1109 # changesets, it is printed in the following situations:
1109 # changesets, it is printed in the following situations:
1110 #
1110 #
1111 # Par column: for the 2 parents with ...
1111 # Par column: for the 2 parents with ...
1112 # N: null or no parent
1112 # N: null or no parent
1113 # B: parent is on another named branch
1113 # B: parent is on another named branch
1114 # C: parent is a regular non head changeset
1114 # C: parent is a regular non head changeset
1115 # H: parent was a branch head of the current branch
1115 # H: parent was a branch head of the current branch
1116 # Msg column: whether we print "created new head" message
1116 # Msg column: whether we print "created new head" message
1117 # In the following, it is assumed that there already exists some
1117 # In the following, it is assumed that there already exists some
1118 # initial branch heads of the current branch, otherwise nothing is
1118 # initial branch heads of the current branch, otherwise nothing is
1119 # printed anyway.
1119 # printed anyway.
1120 #
1120 #
1121 # Par Msg Comment
1121 # Par Msg Comment
1122 # NN y additional topo root
1122 # NN y additional topo root
1123 #
1123 #
1124 # BN y additional branch root
1124 # BN y additional branch root
1125 # CN y additional topo head
1125 # CN y additional topo head
1126 # HN n usual case
1126 # HN n usual case
1127 #
1127 #
1128 # BB y weird additional branch root
1128 # BB y weird additional branch root
1129 # CB y branch merge
1129 # CB y branch merge
1130 # HB n merge with named branch
1130 # HB n merge with named branch
1131 #
1131 #
1132 # CC y additional head from merge
1132 # CC y additional head from merge
1133 # CH n merge with a head
1133 # CH n merge with a head
1134 #
1134 #
1135 # HH n head merge: head count decreases
1135 # HH n head merge: head count decreases
1136
1136
1137 if not opts.get('close_branch'):
1137 if not opts.get('close_branch'):
1138 for r in parents:
1138 for r in parents:
1139 if r.extra().get('close') and r.branch() == branch:
1139 if r.extra().get('close') and r.branch() == branch:
1140 ui.status(_('reopening closed branch head %d\n') % r)
1140 ui.status(_('reopening closed branch head %d\n') % r)
1141
1141
1142 if ui.debugflag:
1142 if ui.debugflag:
1143 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1143 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1144 elif ui.verbose:
1144 elif ui.verbose:
1145 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1145 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1146
1146
1147 @command('copy|cp',
1147 @command('copy|cp',
1148 [('A', 'after', None, _('record a copy that has already occurred')),
1148 [('A', 'after', None, _('record a copy that has already occurred')),
1149 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1149 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1150 ] + walkopts + dryrunopts,
1150 ] + walkopts + dryrunopts,
1151 _('[OPTION]... [SOURCE]... DEST'))
1151 _('[OPTION]... [SOURCE]... DEST'))
1152 def copy(ui, repo, *pats, **opts):
1152 def copy(ui, repo, *pats, **opts):
1153 """mark files as copied for the next commit
1153 """mark files as copied for the next commit
1154
1154
1155 Mark dest as having copies of source files. If dest is a
1155 Mark dest as having copies of source files. If dest is a
1156 directory, copies are put in that directory. If dest is a file,
1156 directory, copies are put in that directory. If dest is a file,
1157 the source must be a single file.
1157 the source must be a single file.
1158
1158
1159 By default, this command copies the contents of files as they
1159 By default, this command copies the contents of files as they
1160 exist in the working directory. If invoked with -A/--after, the
1160 exist in the working directory. If invoked with -A/--after, the
1161 operation is recorded, but no copying is performed.
1161 operation is recorded, but no copying is performed.
1162
1162
1163 This command takes effect with the next commit. To undo a copy
1163 This command takes effect with the next commit. To undo a copy
1164 before that, see :hg:`revert`.
1164 before that, see :hg:`revert`.
1165
1165
1166 Returns 0 on success, 1 if errors are encountered.
1166 Returns 0 on success, 1 if errors are encountered.
1167 """
1167 """
1168 wlock = repo.wlock(False)
1168 wlock = repo.wlock(False)
1169 try:
1169 try:
1170 return cmdutil.copy(ui, repo, pats, opts)
1170 return cmdutil.copy(ui, repo, pats, opts)
1171 finally:
1171 finally:
1172 wlock.release()
1172 wlock.release()
1173
1173
1174 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1174 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1175 def debugancestor(ui, repo, *args):
1175 def debugancestor(ui, repo, *args):
1176 """find the ancestor revision of two revisions in a given index"""
1176 """find the ancestor revision of two revisions in a given index"""
1177 if len(args) == 3:
1177 if len(args) == 3:
1178 index, rev1, rev2 = args
1178 index, rev1, rev2 = args
1179 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1179 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1180 lookup = r.lookup
1180 lookup = r.lookup
1181 elif len(args) == 2:
1181 elif len(args) == 2:
1182 if not repo:
1182 if not repo:
1183 raise util.Abort(_("there is no Mercurial repository here "
1183 raise util.Abort(_("there is no Mercurial repository here "
1184 "(.hg not found)"))
1184 "(.hg not found)"))
1185 rev1, rev2 = args
1185 rev1, rev2 = args
1186 r = repo.changelog
1186 r = repo.changelog
1187 lookup = repo.lookup
1187 lookup = repo.lookup
1188 else:
1188 else:
1189 raise util.Abort(_('either two or three arguments required'))
1189 raise util.Abort(_('either two or three arguments required'))
1190 a = r.ancestor(lookup(rev1), lookup(rev2))
1190 a = r.ancestor(lookup(rev1), lookup(rev2))
1191 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1191 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1192
1192
1193 @command('debugbuilddag',
1193 @command('debugbuilddag',
1194 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1194 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1195 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1195 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1196 ('n', 'new-file', None, _('add new file at each rev'))],
1196 ('n', 'new-file', None, _('add new file at each rev'))],
1197 _('[OPTION]... [TEXT]'))
1197 _('[OPTION]... [TEXT]'))
1198 def debugbuilddag(ui, repo, text=None,
1198 def debugbuilddag(ui, repo, text=None,
1199 mergeable_file=False,
1199 mergeable_file=False,
1200 overwritten_file=False,
1200 overwritten_file=False,
1201 new_file=False):
1201 new_file=False):
1202 """builds a repo with a given DAG from scratch in the current empty repo
1202 """builds a repo with a given DAG from scratch in the current empty repo
1203
1203
1204 The description of the DAG is read from stdin if not given on the
1204 The description of the DAG is read from stdin if not given on the
1205 command line.
1205 command line.
1206
1206
1207 Elements:
1207 Elements:
1208
1208
1209 - "+n" is a linear run of n nodes based on the current default parent
1209 - "+n" is a linear run of n nodes based on the current default parent
1210 - "." is a single node based on the current default parent
1210 - "." is a single node based on the current default parent
1211 - "$" resets the default parent to null (implied at the start);
1211 - "$" resets the default parent to null (implied at the start);
1212 otherwise the default parent is always the last node created
1212 otherwise the default parent is always the last node created
1213 - "<p" sets the default parent to the backref p
1213 - "<p" sets the default parent to the backref p
1214 - "*p" is a fork at parent p, which is a backref
1214 - "*p" is a fork at parent p, which is a backref
1215 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1215 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1216 - "/p2" is a merge of the preceding node and p2
1216 - "/p2" is a merge of the preceding node and p2
1217 - ":tag" defines a local tag for the preceding node
1217 - ":tag" defines a local tag for the preceding node
1218 - "@branch" sets the named branch for subsequent nodes
1218 - "@branch" sets the named branch for subsequent nodes
1219 - "#...\\n" is a comment up to the end of the line
1219 - "#...\\n" is a comment up to the end of the line
1220
1220
1221 Whitespace between the above elements is ignored.
1221 Whitespace between the above elements is ignored.
1222
1222
1223 A backref is either
1223 A backref is either
1224
1224
1225 - a number n, which references the node curr-n, where curr is the current
1225 - a number n, which references the node curr-n, where curr is the current
1226 node, or
1226 node, or
1227 - the name of a local tag you placed earlier using ":tag", or
1227 - the name of a local tag you placed earlier using ":tag", or
1228 - empty to denote the default parent.
1228 - empty to denote the default parent.
1229
1229
1230 All string valued-elements are either strictly alphanumeric, or must
1230 All string valued-elements are either strictly alphanumeric, or must
1231 be enclosed in double quotes ("..."), with "\\" as escape character.
1231 be enclosed in double quotes ("..."), with "\\" as escape character.
1232 """
1232 """
1233
1233
1234 if text is None:
1234 if text is None:
1235 ui.status(_("reading DAG from stdin\n"))
1235 ui.status(_("reading DAG from stdin\n"))
1236 text = ui.fin.read()
1236 text = ui.fin.read()
1237
1237
1238 cl = repo.changelog
1238 cl = repo.changelog
1239 if len(cl) > 0:
1239 if len(cl) > 0:
1240 raise util.Abort(_('repository is not empty'))
1240 raise util.Abort(_('repository is not empty'))
1241
1241
1242 # determine number of revs in DAG
1242 # determine number of revs in DAG
1243 total = 0
1243 total = 0
1244 for type, data in dagparser.parsedag(text):
1244 for type, data in dagparser.parsedag(text):
1245 if type == 'n':
1245 if type == 'n':
1246 total += 1
1246 total += 1
1247
1247
1248 if mergeable_file:
1248 if mergeable_file:
1249 linesperrev = 2
1249 linesperrev = 2
1250 # make a file with k lines per rev
1250 # make a file with k lines per rev
1251 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1251 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1252 initialmergedlines.append("")
1252 initialmergedlines.append("")
1253
1253
1254 tags = []
1254 tags = []
1255
1255
1256 tr = repo.transaction("builddag")
1256 tr = repo.transaction("builddag")
1257 try:
1257 try:
1258
1258
1259 at = -1
1259 at = -1
1260 atbranch = 'default'
1260 atbranch = 'default'
1261 nodeids = []
1261 nodeids = []
1262 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1262 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1263 for type, data in dagparser.parsedag(text):
1263 for type, data in dagparser.parsedag(text):
1264 if type == 'n':
1264 if type == 'n':
1265 ui.note('node %s\n' % str(data))
1265 ui.note('node %s\n' % str(data))
1266 id, ps = data
1266 id, ps = data
1267
1267
1268 files = []
1268 files = []
1269 fctxs = {}
1269 fctxs = {}
1270
1270
1271 p2 = None
1271 p2 = None
1272 if mergeable_file:
1272 if mergeable_file:
1273 fn = "mf"
1273 fn = "mf"
1274 p1 = repo[ps[0]]
1274 p1 = repo[ps[0]]
1275 if len(ps) > 1:
1275 if len(ps) > 1:
1276 p2 = repo[ps[1]]
1276 p2 = repo[ps[1]]
1277 pa = p1.ancestor(p2)
1277 pa = p1.ancestor(p2)
1278 base, local, other = [x[fn].data() for x in pa, p1, p2]
1278 base, local, other = [x[fn].data() for x in pa, p1, p2]
1279 m3 = simplemerge.Merge3Text(base, local, other)
1279 m3 = simplemerge.Merge3Text(base, local, other)
1280 ml = [l.strip() for l in m3.merge_lines()]
1280 ml = [l.strip() for l in m3.merge_lines()]
1281 ml.append("")
1281 ml.append("")
1282 elif at > 0:
1282 elif at > 0:
1283 ml = p1[fn].data().split("\n")
1283 ml = p1[fn].data().split("\n")
1284 else:
1284 else:
1285 ml = initialmergedlines
1285 ml = initialmergedlines
1286 ml[id * linesperrev] += " r%i" % id
1286 ml[id * linesperrev] += " r%i" % id
1287 mergedtext = "\n".join(ml)
1287 mergedtext = "\n".join(ml)
1288 files.append(fn)
1288 files.append(fn)
1289 fctxs[fn] = context.memfilectx(fn, mergedtext)
1289 fctxs[fn] = context.memfilectx(fn, mergedtext)
1290
1290
1291 if overwritten_file:
1291 if overwritten_file:
1292 fn = "of"
1292 fn = "of"
1293 files.append(fn)
1293 files.append(fn)
1294 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1294 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1295
1295
1296 if new_file:
1296 if new_file:
1297 fn = "nf%i" % id
1297 fn = "nf%i" % id
1298 files.append(fn)
1298 files.append(fn)
1299 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1299 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1300 if len(ps) > 1:
1300 if len(ps) > 1:
1301 if not p2:
1301 if not p2:
1302 p2 = repo[ps[1]]
1302 p2 = repo[ps[1]]
1303 for fn in p2:
1303 for fn in p2:
1304 if fn.startswith("nf"):
1304 if fn.startswith("nf"):
1305 files.append(fn)
1305 files.append(fn)
1306 fctxs[fn] = p2[fn]
1306 fctxs[fn] = p2[fn]
1307
1307
1308 def fctxfn(repo, cx, path):
1308 def fctxfn(repo, cx, path):
1309 return fctxs.get(path)
1309 return fctxs.get(path)
1310
1310
1311 if len(ps) == 0 or ps[0] < 0:
1311 if len(ps) == 0 or ps[0] < 0:
1312 pars = [None, None]
1312 pars = [None, None]
1313 elif len(ps) == 1:
1313 elif len(ps) == 1:
1314 pars = [nodeids[ps[0]], None]
1314 pars = [nodeids[ps[0]], None]
1315 else:
1315 else:
1316 pars = [nodeids[p] for p in ps]
1316 pars = [nodeids[p] for p in ps]
1317 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1317 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1318 date=(id, 0),
1318 date=(id, 0),
1319 user="debugbuilddag",
1319 user="debugbuilddag",
1320 extra={'branch': atbranch})
1320 extra={'branch': atbranch})
1321 nodeid = repo.commitctx(cx)
1321 nodeid = repo.commitctx(cx)
1322 nodeids.append(nodeid)
1322 nodeids.append(nodeid)
1323 at = id
1323 at = id
1324 elif type == 'l':
1324 elif type == 'l':
1325 id, name = data
1325 id, name = data
1326 ui.note('tag %s\n' % name)
1326 ui.note('tag %s\n' % name)
1327 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1327 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1328 elif type == 'a':
1328 elif type == 'a':
1329 ui.note('branch %s\n' % data)
1329 ui.note('branch %s\n' % data)
1330 atbranch = data
1330 atbranch = data
1331 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1331 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1332 tr.close()
1332 tr.close()
1333 finally:
1333 finally:
1334 ui.progress(_('building'), None)
1334 ui.progress(_('building'), None)
1335 tr.release()
1335 tr.release()
1336
1336
1337 if tags:
1337 if tags:
1338 repo.opener.write("localtags", "".join(tags))
1338 repo.opener.write("localtags", "".join(tags))
1339
1339
1340 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1340 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1341 def debugbundle(ui, bundlepath, all=None, **opts):
1341 def debugbundle(ui, bundlepath, all=None, **opts):
1342 """lists the contents of a bundle"""
1342 """lists the contents of a bundle"""
1343 f = url.open(ui, bundlepath)
1343 f = url.open(ui, bundlepath)
1344 try:
1344 try:
1345 gen = changegroup.readbundle(f, bundlepath)
1345 gen = changegroup.readbundle(f, bundlepath)
1346 if all:
1346 if all:
1347 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1347 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1348
1348
1349 def showchunks(named):
1349 def showchunks(named):
1350 ui.write("\n%s\n" % named)
1350 ui.write("\n%s\n" % named)
1351 chain = None
1351 chain = None
1352 while True:
1352 while True:
1353 chunkdata = gen.deltachunk(chain)
1353 chunkdata = gen.deltachunk(chain)
1354 if not chunkdata:
1354 if not chunkdata:
1355 break
1355 break
1356 node = chunkdata['node']
1356 node = chunkdata['node']
1357 p1 = chunkdata['p1']
1357 p1 = chunkdata['p1']
1358 p2 = chunkdata['p2']
1358 p2 = chunkdata['p2']
1359 cs = chunkdata['cs']
1359 cs = chunkdata['cs']
1360 deltabase = chunkdata['deltabase']
1360 deltabase = chunkdata['deltabase']
1361 delta = chunkdata['delta']
1361 delta = chunkdata['delta']
1362 ui.write("%s %s %s %s %s %s\n" %
1362 ui.write("%s %s %s %s %s %s\n" %
1363 (hex(node), hex(p1), hex(p2),
1363 (hex(node), hex(p1), hex(p2),
1364 hex(cs), hex(deltabase), len(delta)))
1364 hex(cs), hex(deltabase), len(delta)))
1365 chain = node
1365 chain = node
1366
1366
1367 chunkdata = gen.changelogheader()
1367 chunkdata = gen.changelogheader()
1368 showchunks("changelog")
1368 showchunks("changelog")
1369 chunkdata = gen.manifestheader()
1369 chunkdata = gen.manifestheader()
1370 showchunks("manifest")
1370 showchunks("manifest")
1371 while True:
1371 while True:
1372 chunkdata = gen.filelogheader()
1372 chunkdata = gen.filelogheader()
1373 if not chunkdata:
1373 if not chunkdata:
1374 break
1374 break
1375 fname = chunkdata['filename']
1375 fname = chunkdata['filename']
1376 showchunks(fname)
1376 showchunks(fname)
1377 else:
1377 else:
1378 chunkdata = gen.changelogheader()
1378 chunkdata = gen.changelogheader()
1379 chain = None
1379 chain = None
1380 while True:
1380 while True:
1381 chunkdata = gen.deltachunk(chain)
1381 chunkdata = gen.deltachunk(chain)
1382 if not chunkdata:
1382 if not chunkdata:
1383 break
1383 break
1384 node = chunkdata['node']
1384 node = chunkdata['node']
1385 ui.write("%s\n" % hex(node))
1385 ui.write("%s\n" % hex(node))
1386 chain = node
1386 chain = node
1387 finally:
1387 finally:
1388 f.close()
1388 f.close()
1389
1389
1390 @command('debugcheckstate', [], '')
1390 @command('debugcheckstate', [], '')
1391 def debugcheckstate(ui, repo):
1391 def debugcheckstate(ui, repo):
1392 """validate the correctness of the current dirstate"""
1392 """validate the correctness of the current dirstate"""
1393 parent1, parent2 = repo.dirstate.parents()
1393 parent1, parent2 = repo.dirstate.parents()
1394 m1 = repo[parent1].manifest()
1394 m1 = repo[parent1].manifest()
1395 m2 = repo[parent2].manifest()
1395 m2 = repo[parent2].manifest()
1396 errors = 0
1396 errors = 0
1397 for f in repo.dirstate:
1397 for f in repo.dirstate:
1398 state = repo.dirstate[f]
1398 state = repo.dirstate[f]
1399 if state in "nr" and f not in m1:
1399 if state in "nr" and f not in m1:
1400 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1400 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1401 errors += 1
1401 errors += 1
1402 if state in "a" and f in m1:
1402 if state in "a" and f in m1:
1403 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1403 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1404 errors += 1
1404 errors += 1
1405 if state in "m" and f not in m1 and f not in m2:
1405 if state in "m" and f not in m1 and f not in m2:
1406 ui.warn(_("%s in state %s, but not in either manifest\n") %
1406 ui.warn(_("%s in state %s, but not in either manifest\n") %
1407 (f, state))
1407 (f, state))
1408 errors += 1
1408 errors += 1
1409 for f in m1:
1409 for f in m1:
1410 state = repo.dirstate[f]
1410 state = repo.dirstate[f]
1411 if state not in "nrm":
1411 if state not in "nrm":
1412 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1412 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1413 errors += 1
1413 errors += 1
1414 if errors:
1414 if errors:
1415 error = _(".hg/dirstate inconsistent with current parent's manifest")
1415 error = _(".hg/dirstate inconsistent with current parent's manifest")
1416 raise util.Abort(error)
1416 raise util.Abort(error)
1417
1417
1418 @command('debugcommands', [], _('[COMMAND]'))
1418 @command('debugcommands', [], _('[COMMAND]'))
1419 def debugcommands(ui, cmd='', *args):
1419 def debugcommands(ui, cmd='', *args):
1420 """list all available commands and options"""
1420 """list all available commands and options"""
1421 for cmd, vals in sorted(table.iteritems()):
1421 for cmd, vals in sorted(table.iteritems()):
1422 cmd = cmd.split('|')[0].strip('^')
1422 cmd = cmd.split('|')[0].strip('^')
1423 opts = ', '.join([i[1] for i in vals[1]])
1423 opts = ', '.join([i[1] for i in vals[1]])
1424 ui.write('%s: %s\n' % (cmd, opts))
1424 ui.write('%s: %s\n' % (cmd, opts))
1425
1425
1426 @command('debugcomplete',
1426 @command('debugcomplete',
1427 [('o', 'options', None, _('show the command options'))],
1427 [('o', 'options', None, _('show the command options'))],
1428 _('[-o] CMD'))
1428 _('[-o] CMD'))
1429 def debugcomplete(ui, cmd='', **opts):
1429 def debugcomplete(ui, cmd='', **opts):
1430 """returns the completion list associated with the given command"""
1430 """returns the completion list associated with the given command"""
1431
1431
1432 if opts.get('options'):
1432 if opts.get('options'):
1433 options = []
1433 options = []
1434 otables = [globalopts]
1434 otables = [globalopts]
1435 if cmd:
1435 if cmd:
1436 aliases, entry = cmdutil.findcmd(cmd, table, False)
1436 aliases, entry = cmdutil.findcmd(cmd, table, False)
1437 otables.append(entry[1])
1437 otables.append(entry[1])
1438 for t in otables:
1438 for t in otables:
1439 for o in t:
1439 for o in t:
1440 if "(DEPRECATED)" in o[3]:
1440 if "(DEPRECATED)" in o[3]:
1441 continue
1441 continue
1442 if o[0]:
1442 if o[0]:
1443 options.append('-%s' % o[0])
1443 options.append('-%s' % o[0])
1444 options.append('--%s' % o[1])
1444 options.append('--%s' % o[1])
1445 ui.write("%s\n" % "\n".join(options))
1445 ui.write("%s\n" % "\n".join(options))
1446 return
1446 return
1447
1447
1448 cmdlist = cmdutil.findpossible(cmd, table)
1448 cmdlist = cmdutil.findpossible(cmd, table)
1449 if ui.verbose:
1449 if ui.verbose:
1450 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1450 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1451 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1451 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1452
1452
1453 @command('debugdag',
1453 @command('debugdag',
1454 [('t', 'tags', None, _('use tags as labels')),
1454 [('t', 'tags', None, _('use tags as labels')),
1455 ('b', 'branches', None, _('annotate with branch names')),
1455 ('b', 'branches', None, _('annotate with branch names')),
1456 ('', 'dots', None, _('use dots for runs')),
1456 ('', 'dots', None, _('use dots for runs')),
1457 ('s', 'spaces', None, _('separate elements by spaces'))],
1457 ('s', 'spaces', None, _('separate elements by spaces'))],
1458 _('[OPTION]... [FILE [REV]...]'))
1458 _('[OPTION]... [FILE [REV]...]'))
1459 def debugdag(ui, repo, file_=None, *revs, **opts):
1459 def debugdag(ui, repo, file_=None, *revs, **opts):
1460 """format the changelog or an index DAG as a concise textual description
1460 """format the changelog or an index DAG as a concise textual description
1461
1461
1462 If you pass a revlog index, the revlog's DAG is emitted. If you list
1462 If you pass a revlog index, the revlog's DAG is emitted. If you list
1463 revision numbers, they get labelled in the output as rN.
1463 revision numbers, they get labelled in the output as rN.
1464
1464
1465 Otherwise, the changelog DAG of the current repo is emitted.
1465 Otherwise, the changelog DAG of the current repo is emitted.
1466 """
1466 """
1467 spaces = opts.get('spaces')
1467 spaces = opts.get('spaces')
1468 dots = opts.get('dots')
1468 dots = opts.get('dots')
1469 if file_:
1469 if file_:
1470 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1470 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1471 revs = set((int(r) for r in revs))
1471 revs = set((int(r) for r in revs))
1472 def events():
1472 def events():
1473 for r in rlog:
1473 for r in rlog:
1474 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1474 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1475 if r in revs:
1475 if r in revs:
1476 yield 'l', (r, "r%i" % r)
1476 yield 'l', (r, "r%i" % r)
1477 elif repo:
1477 elif repo:
1478 cl = repo.changelog
1478 cl = repo.changelog
1479 tags = opts.get('tags')
1479 tags = opts.get('tags')
1480 branches = opts.get('branches')
1480 branches = opts.get('branches')
1481 if tags:
1481 if tags:
1482 labels = {}
1482 labels = {}
1483 for l, n in repo.tags().items():
1483 for l, n in repo.tags().items():
1484 labels.setdefault(cl.rev(n), []).append(l)
1484 labels.setdefault(cl.rev(n), []).append(l)
1485 def events():
1485 def events():
1486 b = "default"
1486 b = "default"
1487 for r in cl:
1487 for r in cl:
1488 if branches:
1488 if branches:
1489 newb = cl.read(cl.node(r))[5]['branch']
1489 newb = cl.read(cl.node(r))[5]['branch']
1490 if newb != b:
1490 if newb != b:
1491 yield 'a', newb
1491 yield 'a', newb
1492 b = newb
1492 b = newb
1493 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1493 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1494 if tags:
1494 if tags:
1495 ls = labels.get(r)
1495 ls = labels.get(r)
1496 if ls:
1496 if ls:
1497 for l in ls:
1497 for l in ls:
1498 yield 'l', (r, l)
1498 yield 'l', (r, l)
1499 else:
1499 else:
1500 raise util.Abort(_('need repo for changelog dag'))
1500 raise util.Abort(_('need repo for changelog dag'))
1501
1501
1502 for line in dagparser.dagtextlines(events(),
1502 for line in dagparser.dagtextlines(events(),
1503 addspaces=spaces,
1503 addspaces=spaces,
1504 wraplabels=True,
1504 wraplabels=True,
1505 wrapannotations=True,
1505 wrapannotations=True,
1506 wrapnonlinear=dots,
1506 wrapnonlinear=dots,
1507 usedots=dots,
1507 usedots=dots,
1508 maxlinewidth=70):
1508 maxlinewidth=70):
1509 ui.write(line)
1509 ui.write(line)
1510 ui.write("\n")
1510 ui.write("\n")
1511
1511
1512 @command('debugdata',
1512 @command('debugdata',
1513 [('c', 'changelog', False, _('open changelog')),
1513 [('c', 'changelog', False, _('open changelog')),
1514 ('m', 'manifest', False, _('open manifest'))],
1514 ('m', 'manifest', False, _('open manifest'))],
1515 _('-c|-m|FILE REV'))
1515 _('-c|-m|FILE REV'))
1516 def debugdata(ui, repo, file_, rev = None, **opts):
1516 def debugdata(ui, repo, file_, rev = None, **opts):
1517 """dump the contents of a data file revision"""
1517 """dump the contents of a data file revision"""
1518 if opts.get('changelog') or opts.get('manifest'):
1518 if opts.get('changelog') or opts.get('manifest'):
1519 file_, rev = None, file_
1519 file_, rev = None, file_
1520 elif rev is None:
1520 elif rev is None:
1521 raise error.CommandError('debugdata', _('invalid arguments'))
1521 raise error.CommandError('debugdata', _('invalid arguments'))
1522 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1522 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1523 try:
1523 try:
1524 ui.write(r.revision(r.lookup(rev)))
1524 ui.write(r.revision(r.lookup(rev)))
1525 except KeyError:
1525 except KeyError:
1526 raise util.Abort(_('invalid revision identifier %s') % rev)
1526 raise util.Abort(_('invalid revision identifier %s') % rev)
1527
1527
1528 @command('debugdate',
1528 @command('debugdate',
1529 [('e', 'extended', None, _('try extended date formats'))],
1529 [('e', 'extended', None, _('try extended date formats'))],
1530 _('[-e] DATE [RANGE]'))
1530 _('[-e] DATE [RANGE]'))
1531 def debugdate(ui, date, range=None, **opts):
1531 def debugdate(ui, date, range=None, **opts):
1532 """parse and display a date"""
1532 """parse and display a date"""
1533 if opts["extended"]:
1533 if opts["extended"]:
1534 d = util.parsedate(date, util.extendeddateformats)
1534 d = util.parsedate(date, util.extendeddateformats)
1535 else:
1535 else:
1536 d = util.parsedate(date)
1536 d = util.parsedate(date)
1537 ui.write("internal: %s %s\n" % d)
1537 ui.write("internal: %s %s\n" % d)
1538 ui.write("standard: %s\n" % util.datestr(d))
1538 ui.write("standard: %s\n" % util.datestr(d))
1539 if range:
1539 if range:
1540 m = util.matchdate(range)
1540 m = util.matchdate(range)
1541 ui.write("match: %s\n" % m(d[0]))
1541 ui.write("match: %s\n" % m(d[0]))
1542
1542
1543 @command('debugdiscovery',
1543 @command('debugdiscovery',
1544 [('', 'old', None, _('use old-style discovery')),
1544 [('', 'old', None, _('use old-style discovery')),
1545 ('', 'nonheads', None,
1545 ('', 'nonheads', None,
1546 _('use old-style discovery with non-heads included')),
1546 _('use old-style discovery with non-heads included')),
1547 ] + remoteopts,
1547 ] + remoteopts,
1548 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1548 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1549 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1549 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1550 """runs the changeset discovery protocol in isolation"""
1550 """runs the changeset discovery protocol in isolation"""
1551 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1551 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1552 remote = hg.peer(repo, opts, remoteurl)
1552 remote = hg.peer(repo, opts, remoteurl)
1553 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1553 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1554
1554
1555 # make sure tests are repeatable
1555 # make sure tests are repeatable
1556 random.seed(12323)
1556 random.seed(12323)
1557
1557
1558 def doit(localheads, remoteheads):
1558 def doit(localheads, remoteheads):
1559 if opts.get('old'):
1559 if opts.get('old'):
1560 if localheads:
1560 if localheads:
1561 raise util.Abort('cannot use localheads with old style discovery')
1561 raise util.Abort('cannot use localheads with old style discovery')
1562 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1562 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1563 force=True)
1563 force=True)
1564 common = set(common)
1564 common = set(common)
1565 if not opts.get('nonheads'):
1565 if not opts.get('nonheads'):
1566 ui.write("unpruned common: %s\n" % " ".join([short(n)
1566 ui.write("unpruned common: %s\n" % " ".join([short(n)
1567 for n in common]))
1567 for n in common]))
1568 dag = dagutil.revlogdag(repo.changelog)
1568 dag = dagutil.revlogdag(repo.changelog)
1569 all = dag.ancestorset(dag.internalizeall(common))
1569 all = dag.ancestorset(dag.internalizeall(common))
1570 common = dag.externalizeall(dag.headsetofconnecteds(all))
1570 common = dag.externalizeall(dag.headsetofconnecteds(all))
1571 else:
1571 else:
1572 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1572 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1573 common = set(common)
1573 common = set(common)
1574 rheads = set(hds)
1574 rheads = set(hds)
1575 lheads = set(repo.heads())
1575 lheads = set(repo.heads())
1576 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1576 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1577 if lheads <= common:
1577 if lheads <= common:
1578 ui.write("local is subset\n")
1578 ui.write("local is subset\n")
1579 elif rheads <= common:
1579 elif rheads <= common:
1580 ui.write("remote is subset\n")
1580 ui.write("remote is subset\n")
1581
1581
1582 serverlogs = opts.get('serverlog')
1582 serverlogs = opts.get('serverlog')
1583 if serverlogs:
1583 if serverlogs:
1584 for filename in serverlogs:
1584 for filename in serverlogs:
1585 logfile = open(filename, 'r')
1585 logfile = open(filename, 'r')
1586 try:
1586 try:
1587 line = logfile.readline()
1587 line = logfile.readline()
1588 while line:
1588 while line:
1589 parts = line.strip().split(';')
1589 parts = line.strip().split(';')
1590 op = parts[1]
1590 op = parts[1]
1591 if op == 'cg':
1591 if op == 'cg':
1592 pass
1592 pass
1593 elif op == 'cgss':
1593 elif op == 'cgss':
1594 doit(parts[2].split(' '), parts[3].split(' '))
1594 doit(parts[2].split(' '), parts[3].split(' '))
1595 elif op == 'unb':
1595 elif op == 'unb':
1596 doit(parts[3].split(' '), parts[2].split(' '))
1596 doit(parts[3].split(' '), parts[2].split(' '))
1597 line = logfile.readline()
1597 line = logfile.readline()
1598 finally:
1598 finally:
1599 logfile.close()
1599 logfile.close()
1600
1600
1601 else:
1601 else:
1602 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1602 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1603 opts.get('remote_head'))
1603 opts.get('remote_head'))
1604 localrevs = opts.get('local_head')
1604 localrevs = opts.get('local_head')
1605 doit(localrevs, remoterevs)
1605 doit(localrevs, remoterevs)
1606
1606
1607 @command('debugfileset', [], ('REVSPEC'))
1607 @command('debugfileset', [], ('REVSPEC'))
1608 def debugfileset(ui, repo, expr):
1608 def debugfileset(ui, repo, expr):
1609 '''parse and apply a fileset specification'''
1609 '''parse and apply a fileset specification'''
1610 if ui.verbose:
1610 if ui.verbose:
1611 tree = fileset.parse(expr)[0]
1611 tree = fileset.parse(expr)[0]
1612 ui.note(tree, "\n")
1612 ui.note(tree, "\n")
1613
1613
1614 for f in fileset.getfileset(repo[None], expr):
1614 for f in fileset.getfileset(repo[None], expr):
1615 ui.write("%s\n" % f)
1615 ui.write("%s\n" % f)
1616
1616
1617 @command('debugfsinfo', [], _('[PATH]'))
1617 @command('debugfsinfo', [], _('[PATH]'))
1618 def debugfsinfo(ui, path = "."):
1618 def debugfsinfo(ui, path = "."):
1619 """show information detected about current filesystem"""
1619 """show information detected about current filesystem"""
1620 util.writefile('.debugfsinfo', '')
1620 util.writefile('.debugfsinfo', '')
1621 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1621 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1622 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1622 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1623 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1623 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1624 and 'yes' or 'no'))
1624 and 'yes' or 'no'))
1625 os.unlink('.debugfsinfo')
1625 os.unlink('.debugfsinfo')
1626
1626
1627 @command('debuggetbundle',
1627 @command('debuggetbundle',
1628 [('H', 'head', [], _('id of head node'), _('ID')),
1628 [('H', 'head', [], _('id of head node'), _('ID')),
1629 ('C', 'common', [], _('id of common node'), _('ID')),
1629 ('C', 'common', [], _('id of common node'), _('ID')),
1630 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1630 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1631 _('REPO FILE [-H|-C ID]...'))
1631 _('REPO FILE [-H|-C ID]...'))
1632 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1632 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1633 """retrieves a bundle from a repo
1633 """retrieves a bundle from a repo
1634
1634
1635 Every ID must be a full-length hex node id string. Saves the bundle to the
1635 Every ID must be a full-length hex node id string. Saves the bundle to the
1636 given file.
1636 given file.
1637 """
1637 """
1638 repo = hg.peer(ui, opts, repopath)
1638 repo = hg.peer(ui, opts, repopath)
1639 if not repo.capable('getbundle'):
1639 if not repo.capable('getbundle'):
1640 raise util.Abort("getbundle() not supported by target repository")
1640 raise util.Abort("getbundle() not supported by target repository")
1641 args = {}
1641 args = {}
1642 if common:
1642 if common:
1643 args['common'] = [bin(s) for s in common]
1643 args['common'] = [bin(s) for s in common]
1644 if head:
1644 if head:
1645 args['heads'] = [bin(s) for s in head]
1645 args['heads'] = [bin(s) for s in head]
1646 bundle = repo.getbundle('debug', **args)
1646 bundle = repo.getbundle('debug', **args)
1647
1647
1648 bundletype = opts.get('type', 'bzip2').lower()
1648 bundletype = opts.get('type', 'bzip2').lower()
1649 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1649 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1650 bundletype = btypes.get(bundletype)
1650 bundletype = btypes.get(bundletype)
1651 if bundletype not in changegroup.bundletypes:
1651 if bundletype not in changegroup.bundletypes:
1652 raise util.Abort(_('unknown bundle type specified with --type'))
1652 raise util.Abort(_('unknown bundle type specified with --type'))
1653 changegroup.writebundle(bundle, bundlepath, bundletype)
1653 changegroup.writebundle(bundle, bundlepath, bundletype)
1654
1654
1655 @command('debugignore', [], '')
1655 @command('debugignore', [], '')
1656 def debugignore(ui, repo, *values, **opts):
1656 def debugignore(ui, repo, *values, **opts):
1657 """display the combined ignore pattern"""
1657 """display the combined ignore pattern"""
1658 ignore = repo.dirstate._ignore
1658 ignore = repo.dirstate._ignore
1659 if hasattr(ignore, 'includepat'):
1659 if hasattr(ignore, 'includepat'):
1660 ui.write("%s\n" % ignore.includepat)
1660 ui.write("%s\n" % ignore.includepat)
1661 else:
1661 else:
1662 raise util.Abort(_("no ignore patterns found"))
1662 raise util.Abort(_("no ignore patterns found"))
1663
1663
1664 @command('debugindex',
1664 @command('debugindex',
1665 [('c', 'changelog', False, _('open changelog')),
1665 [('c', 'changelog', False, _('open changelog')),
1666 ('m', 'manifest', False, _('open manifest')),
1666 ('m', 'manifest', False, _('open manifest')),
1667 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1667 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1668 _('[-f FORMAT] -c|-m|FILE'))
1668 _('[-f FORMAT] -c|-m|FILE'))
1669 def debugindex(ui, repo, file_ = None, **opts):
1669 def debugindex(ui, repo, file_ = None, **opts):
1670 """dump the contents of an index file"""
1670 """dump the contents of an index file"""
1671 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1671 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1672 format = opts.get('format', 0)
1672 format = opts.get('format', 0)
1673 if format not in (0, 1):
1673 if format not in (0, 1):
1674 raise util.Abort(_("unknown format %d") % format)
1674 raise util.Abort(_("unknown format %d") % format)
1675
1675
1676 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1676 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1677 if generaldelta:
1677 if generaldelta:
1678 basehdr = ' delta'
1678 basehdr = ' delta'
1679 else:
1679 else:
1680 basehdr = ' base'
1680 basehdr = ' base'
1681
1681
1682 if format == 0:
1682 if format == 0:
1683 ui.write(" rev offset length " + basehdr + " linkrev"
1683 ui.write(" rev offset length " + basehdr + " linkrev"
1684 " nodeid p1 p2\n")
1684 " nodeid p1 p2\n")
1685 elif format == 1:
1685 elif format == 1:
1686 ui.write(" rev flag offset length"
1686 ui.write(" rev flag offset length"
1687 " size " + basehdr + " link p1 p2 nodeid\n")
1687 " size " + basehdr + " link p1 p2 nodeid\n")
1688
1688
1689 for i in r:
1689 for i in r:
1690 node = r.node(i)
1690 node = r.node(i)
1691 if generaldelta:
1691 if generaldelta:
1692 base = r.deltaparent(i)
1692 base = r.deltaparent(i)
1693 else:
1693 else:
1694 base = r.chainbase(i)
1694 base = r.chainbase(i)
1695 if format == 0:
1695 if format == 0:
1696 try:
1696 try:
1697 pp = r.parents(node)
1697 pp = r.parents(node)
1698 except:
1698 except:
1699 pp = [nullid, nullid]
1699 pp = [nullid, nullid]
1700 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1700 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1701 i, r.start(i), r.length(i), base, r.linkrev(i),
1701 i, r.start(i), r.length(i), base, r.linkrev(i),
1702 short(node), short(pp[0]), short(pp[1])))
1702 short(node), short(pp[0]), short(pp[1])))
1703 elif format == 1:
1703 elif format == 1:
1704 pr = r.parentrevs(i)
1704 pr = r.parentrevs(i)
1705 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1705 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1706 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1706 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1707 base, r.linkrev(i), pr[0], pr[1], short(node)))
1707 base, r.linkrev(i), pr[0], pr[1], short(node)))
1708
1708
1709 @command('debugindexdot', [], _('FILE'))
1709 @command('debugindexdot', [], _('FILE'))
1710 def debugindexdot(ui, repo, file_):
1710 def debugindexdot(ui, repo, file_):
1711 """dump an index DAG as a graphviz dot file"""
1711 """dump an index DAG as a graphviz dot file"""
1712 r = None
1712 r = None
1713 if repo:
1713 if repo:
1714 filelog = repo.file(file_)
1714 filelog = repo.file(file_)
1715 if len(filelog):
1715 if len(filelog):
1716 r = filelog
1716 r = filelog
1717 if not r:
1717 if not r:
1718 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1718 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1719 ui.write("digraph G {\n")
1719 ui.write("digraph G {\n")
1720 for i in r:
1720 for i in r:
1721 node = r.node(i)
1721 node = r.node(i)
1722 pp = r.parents(node)
1722 pp = r.parents(node)
1723 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1723 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1724 if pp[1] != nullid:
1724 if pp[1] != nullid:
1725 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1725 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1726 ui.write("}\n")
1726 ui.write("}\n")
1727
1727
1728 @command('debuginstall', [], '')
1728 @command('debuginstall', [], '')
1729 def debuginstall(ui):
1729 def debuginstall(ui):
1730 '''test Mercurial installation
1730 '''test Mercurial installation
1731
1731
1732 Returns 0 on success.
1732 Returns 0 on success.
1733 '''
1733 '''
1734
1734
1735 def writetemp(contents):
1735 def writetemp(contents):
1736 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1736 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1737 f = os.fdopen(fd, "wb")
1737 f = os.fdopen(fd, "wb")
1738 f.write(contents)
1738 f.write(contents)
1739 f.close()
1739 f.close()
1740 return name
1740 return name
1741
1741
1742 problems = 0
1742 problems = 0
1743
1743
1744 # encoding
1744 # encoding
1745 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1745 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1746 try:
1746 try:
1747 encoding.fromlocal("test")
1747 encoding.fromlocal("test")
1748 except util.Abort, inst:
1748 except util.Abort, inst:
1749 ui.write(" %s\n" % inst)
1749 ui.write(" %s\n" % inst)
1750 ui.write(_(" (check that your locale is properly set)\n"))
1750 ui.write(_(" (check that your locale is properly set)\n"))
1751 problems += 1
1751 problems += 1
1752
1752
1753 # compiled modules
1753 # compiled modules
1754 ui.status(_("Checking installed modules (%s)...\n")
1754 ui.status(_("Checking installed modules (%s)...\n")
1755 % os.path.dirname(__file__))
1755 % os.path.dirname(__file__))
1756 try:
1756 try:
1757 import bdiff, mpatch, base85, osutil
1757 import bdiff, mpatch, base85, osutil
1758 except Exception, inst:
1758 except Exception, inst:
1759 ui.write(" %s\n" % inst)
1759 ui.write(" %s\n" % inst)
1760 ui.write(_(" One or more extensions could not be found"))
1760 ui.write(_(" One or more extensions could not be found"))
1761 ui.write(_(" (check that you compiled the extensions)\n"))
1761 ui.write(_(" (check that you compiled the extensions)\n"))
1762 problems += 1
1762 problems += 1
1763
1763
1764 # templates
1764 # templates
1765 ui.status(_("Checking templates...\n"))
1765 ui.status(_("Checking templates...\n"))
1766 try:
1766 try:
1767 import templater
1767 import templater
1768 templater.templater(templater.templatepath("map-cmdline.default"))
1768 templater.templater(templater.templatepath("map-cmdline.default"))
1769 except Exception, inst:
1769 except Exception, inst:
1770 ui.write(" %s\n" % inst)
1770 ui.write(" %s\n" % inst)
1771 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1771 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1772 problems += 1
1772 problems += 1
1773
1773
1774 # editor
1774 # editor
1775 ui.status(_("Checking commit editor...\n"))
1775 ui.status(_("Checking commit editor...\n"))
1776 editor = ui.geteditor()
1776 editor = ui.geteditor()
1777 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1777 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1778 if not cmdpath:
1778 if not cmdpath:
1779 if editor == 'vi':
1779 if editor == 'vi':
1780 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1780 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1781 ui.write(_(" (specify a commit editor in your configuration"
1781 ui.write(_(" (specify a commit editor in your configuration"
1782 " file)\n"))
1782 " file)\n"))
1783 else:
1783 else:
1784 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1784 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1785 ui.write(_(" (specify a commit editor in your configuration"
1785 ui.write(_(" (specify a commit editor in your configuration"
1786 " file)\n"))
1786 " file)\n"))
1787 problems += 1
1787 problems += 1
1788
1788
1789 # check username
1789 # check username
1790 ui.status(_("Checking username...\n"))
1790 ui.status(_("Checking username...\n"))
1791 try:
1791 try:
1792 ui.username()
1792 ui.username()
1793 except util.Abort, e:
1793 except util.Abort, e:
1794 ui.write(" %s\n" % e)
1794 ui.write(" %s\n" % e)
1795 ui.write(_(" (specify a username in your configuration file)\n"))
1795 ui.write(_(" (specify a username in your configuration file)\n"))
1796 problems += 1
1796 problems += 1
1797
1797
1798 if not problems:
1798 if not problems:
1799 ui.status(_("No problems detected\n"))
1799 ui.status(_("No problems detected\n"))
1800 else:
1800 else:
1801 ui.write(_("%s problems detected,"
1801 ui.write(_("%s problems detected,"
1802 " please check your install!\n") % problems)
1802 " please check your install!\n") % problems)
1803
1803
1804 return problems
1804 return problems
1805
1805
1806 @command('debugknown', [], _('REPO ID...'))
1806 @command('debugknown', [], _('REPO ID...'))
1807 def debugknown(ui, repopath, *ids, **opts):
1807 def debugknown(ui, repopath, *ids, **opts):
1808 """test whether node ids are known to a repo
1808 """test whether node ids are known to a repo
1809
1809
1810 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1810 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1811 indicating unknown/known.
1811 indicating unknown/known.
1812 """
1812 """
1813 repo = hg.peer(ui, opts, repopath)
1813 repo = hg.peer(ui, opts, repopath)
1814 if not repo.capable('known'):
1814 if not repo.capable('known'):
1815 raise util.Abort("known() not supported by target repository")
1815 raise util.Abort("known() not supported by target repository")
1816 flags = repo.known([bin(s) for s in ids])
1816 flags = repo.known([bin(s) for s in ids])
1817 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1817 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1818
1818
1819 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1819 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1820 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1820 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1821 '''access the pushkey key/value protocol
1821 '''access the pushkey key/value protocol
1822
1822
1823 With two args, list the keys in the given namespace.
1823 With two args, list the keys in the given namespace.
1824
1824
1825 With five args, set a key to new if it currently is set to old.
1825 With five args, set a key to new if it currently is set to old.
1826 Reports success or failure.
1826 Reports success or failure.
1827 '''
1827 '''
1828
1828
1829 target = hg.peer(ui, {}, repopath)
1829 target = hg.peer(ui, {}, repopath)
1830 if keyinfo:
1830 if keyinfo:
1831 key, old, new = keyinfo
1831 key, old, new = keyinfo
1832 r = target.pushkey(namespace, key, old, new)
1832 r = target.pushkey(namespace, key, old, new)
1833 ui.status(str(r) + '\n')
1833 ui.status(str(r) + '\n')
1834 return not r
1834 return not r
1835 else:
1835 else:
1836 for k, v in target.listkeys(namespace).iteritems():
1836 for k, v in target.listkeys(namespace).iteritems():
1837 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1837 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1838 v.encode('string-escape')))
1838 v.encode('string-escape')))
1839
1839
1840 @command('debugrebuildstate',
1840 @command('debugrebuildstate',
1841 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1841 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1842 _('[-r REV] [REV]'))
1842 _('[-r REV] [REV]'))
1843 def debugrebuildstate(ui, repo, rev="tip"):
1843 def debugrebuildstate(ui, repo, rev="tip"):
1844 """rebuild the dirstate as it would look like for the given revision"""
1844 """rebuild the dirstate as it would look like for the given revision"""
1845 ctx = scmutil.revsingle(repo, rev)
1845 ctx = scmutil.revsingle(repo, rev)
1846 wlock = repo.wlock()
1846 wlock = repo.wlock()
1847 try:
1847 try:
1848 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1848 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1849 finally:
1849 finally:
1850 wlock.release()
1850 wlock.release()
1851
1851
1852 @command('debugrename',
1852 @command('debugrename',
1853 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1853 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1854 _('[-r REV] FILE'))
1854 _('[-r REV] FILE'))
1855 def debugrename(ui, repo, file1, *pats, **opts):
1855 def debugrename(ui, repo, file1, *pats, **opts):
1856 """dump rename information"""
1856 """dump rename information"""
1857
1857
1858 ctx = scmutil.revsingle(repo, opts.get('rev'))
1858 ctx = scmutil.revsingle(repo, opts.get('rev'))
1859 m = scmutil.match(ctx, (file1,) + pats, opts)
1859 m = scmutil.match(ctx, (file1,) + pats, opts)
1860 for abs in ctx.walk(m):
1860 for abs in ctx.walk(m):
1861 fctx = ctx[abs]
1861 fctx = ctx[abs]
1862 o = fctx.filelog().renamed(fctx.filenode())
1862 o = fctx.filelog().renamed(fctx.filenode())
1863 rel = m.rel(abs)
1863 rel = m.rel(abs)
1864 if o:
1864 if o:
1865 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1865 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1866 else:
1866 else:
1867 ui.write(_("%s not renamed\n") % rel)
1867 ui.write(_("%s not renamed\n") % rel)
1868
1868
1869 @command('debugrevlog',
1869 @command('debugrevlog',
1870 [('c', 'changelog', False, _('open changelog')),
1870 [('c', 'changelog', False, _('open changelog')),
1871 ('m', 'manifest', False, _('open manifest')),
1871 ('m', 'manifest', False, _('open manifest')),
1872 ('d', 'dump', False, _('dump index data'))],
1872 ('d', 'dump', False, _('dump index data'))],
1873 _('-c|-m|FILE'))
1873 _('-c|-m|FILE'))
1874 def debugrevlog(ui, repo, file_ = None, **opts):
1874 def debugrevlog(ui, repo, file_ = None, **opts):
1875 """show data and statistics about a revlog"""
1875 """show data and statistics about a revlog"""
1876 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1876 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1877
1877
1878 if opts.get("dump"):
1878 if opts.get("dump"):
1879 numrevs = len(r)
1879 numrevs = len(r)
1880 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1880 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1881 " rawsize totalsize compression heads\n")
1881 " rawsize totalsize compression heads\n")
1882 ts = 0
1882 ts = 0
1883 heads = set()
1883 heads = set()
1884 for rev in xrange(numrevs):
1884 for rev in xrange(numrevs):
1885 dbase = r.deltaparent(rev)
1885 dbase = r.deltaparent(rev)
1886 if dbase == -1:
1886 if dbase == -1:
1887 dbase = rev
1887 dbase = rev
1888 cbase = r.chainbase(rev)
1888 cbase = r.chainbase(rev)
1889 p1, p2 = r.parentrevs(rev)
1889 p1, p2 = r.parentrevs(rev)
1890 rs = r.rawsize(rev)
1890 rs = r.rawsize(rev)
1891 ts = ts + rs
1891 ts = ts + rs
1892 heads -= set(r.parentrevs(rev))
1892 heads -= set(r.parentrevs(rev))
1893 heads.add(rev)
1893 heads.add(rev)
1894 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1894 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1895 (rev, p1, p2, r.start(rev), r.end(rev),
1895 (rev, p1, p2, r.start(rev), r.end(rev),
1896 r.start(dbase), r.start(cbase),
1896 r.start(dbase), r.start(cbase),
1897 r.start(p1), r.start(p2),
1897 r.start(p1), r.start(p2),
1898 rs, ts, ts / r.end(rev), len(heads)))
1898 rs, ts, ts / r.end(rev), len(heads)))
1899 return 0
1899 return 0
1900
1900
1901 v = r.version
1901 v = r.version
1902 format = v & 0xFFFF
1902 format = v & 0xFFFF
1903 flags = []
1903 flags = []
1904 gdelta = False
1904 gdelta = False
1905 if v & revlog.REVLOGNGINLINEDATA:
1905 if v & revlog.REVLOGNGINLINEDATA:
1906 flags.append('inline')
1906 flags.append('inline')
1907 if v & revlog.REVLOGGENERALDELTA:
1907 if v & revlog.REVLOGGENERALDELTA:
1908 gdelta = True
1908 gdelta = True
1909 flags.append('generaldelta')
1909 flags.append('generaldelta')
1910 if not flags:
1910 if not flags:
1911 flags = ['(none)']
1911 flags = ['(none)']
1912
1912
1913 nummerges = 0
1913 nummerges = 0
1914 numfull = 0
1914 numfull = 0
1915 numprev = 0
1915 numprev = 0
1916 nump1 = 0
1916 nump1 = 0
1917 nump2 = 0
1917 nump2 = 0
1918 numother = 0
1918 numother = 0
1919 nump1prev = 0
1919 nump1prev = 0
1920 nump2prev = 0
1920 nump2prev = 0
1921 chainlengths = []
1921 chainlengths = []
1922
1922
1923 datasize = [None, 0, 0L]
1923 datasize = [None, 0, 0L]
1924 fullsize = [None, 0, 0L]
1924 fullsize = [None, 0, 0L]
1925 deltasize = [None, 0, 0L]
1925 deltasize = [None, 0, 0L]
1926
1926
1927 def addsize(size, l):
1927 def addsize(size, l):
1928 if l[0] is None or size < l[0]:
1928 if l[0] is None or size < l[0]:
1929 l[0] = size
1929 l[0] = size
1930 if size > l[1]:
1930 if size > l[1]:
1931 l[1] = size
1931 l[1] = size
1932 l[2] += size
1932 l[2] += size
1933
1933
1934 numrevs = len(r)
1934 numrevs = len(r)
1935 for rev in xrange(numrevs):
1935 for rev in xrange(numrevs):
1936 p1, p2 = r.parentrevs(rev)
1936 p1, p2 = r.parentrevs(rev)
1937 delta = r.deltaparent(rev)
1937 delta = r.deltaparent(rev)
1938 if format > 0:
1938 if format > 0:
1939 addsize(r.rawsize(rev), datasize)
1939 addsize(r.rawsize(rev), datasize)
1940 if p2 != nullrev:
1940 if p2 != nullrev:
1941 nummerges += 1
1941 nummerges += 1
1942 size = r.length(rev)
1942 size = r.length(rev)
1943 if delta == nullrev:
1943 if delta == nullrev:
1944 chainlengths.append(0)
1944 chainlengths.append(0)
1945 numfull += 1
1945 numfull += 1
1946 addsize(size, fullsize)
1946 addsize(size, fullsize)
1947 else:
1947 else:
1948 chainlengths.append(chainlengths[delta] + 1)
1948 chainlengths.append(chainlengths[delta] + 1)
1949 addsize(size, deltasize)
1949 addsize(size, deltasize)
1950 if delta == rev - 1:
1950 if delta == rev - 1:
1951 numprev += 1
1951 numprev += 1
1952 if delta == p1:
1952 if delta == p1:
1953 nump1prev += 1
1953 nump1prev += 1
1954 elif delta == p2:
1954 elif delta == p2:
1955 nump2prev += 1
1955 nump2prev += 1
1956 elif delta == p1:
1956 elif delta == p1:
1957 nump1 += 1
1957 nump1 += 1
1958 elif delta == p2:
1958 elif delta == p2:
1959 nump2 += 1
1959 nump2 += 1
1960 elif delta != nullrev:
1960 elif delta != nullrev:
1961 numother += 1
1961 numother += 1
1962
1962
1963 numdeltas = numrevs - numfull
1963 numdeltas = numrevs - numfull
1964 numoprev = numprev - nump1prev - nump2prev
1964 numoprev = numprev - nump1prev - nump2prev
1965 totalrawsize = datasize[2]
1965 totalrawsize = datasize[2]
1966 datasize[2] /= numrevs
1966 datasize[2] /= numrevs
1967 fulltotal = fullsize[2]
1967 fulltotal = fullsize[2]
1968 fullsize[2] /= numfull
1968 fullsize[2] /= numfull
1969 deltatotal = deltasize[2]
1969 deltatotal = deltasize[2]
1970 deltasize[2] /= numrevs - numfull
1970 deltasize[2] /= numrevs - numfull
1971 totalsize = fulltotal + deltatotal
1971 totalsize = fulltotal + deltatotal
1972 avgchainlen = sum(chainlengths) / numrevs
1972 avgchainlen = sum(chainlengths) / numrevs
1973 compratio = totalrawsize / totalsize
1973 compratio = totalrawsize / totalsize
1974
1974
1975 basedfmtstr = '%%%dd\n'
1975 basedfmtstr = '%%%dd\n'
1976 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1976 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1977
1977
1978 def dfmtstr(max):
1978 def dfmtstr(max):
1979 return basedfmtstr % len(str(max))
1979 return basedfmtstr % len(str(max))
1980 def pcfmtstr(max, padding=0):
1980 def pcfmtstr(max, padding=0):
1981 return basepcfmtstr % (len(str(max)), ' ' * padding)
1981 return basepcfmtstr % (len(str(max)), ' ' * padding)
1982
1982
1983 def pcfmt(value, total):
1983 def pcfmt(value, total):
1984 return (value, 100 * float(value) / total)
1984 return (value, 100 * float(value) / total)
1985
1985
1986 ui.write('format : %d\n' % format)
1986 ui.write('format : %d\n' % format)
1987 ui.write('flags : %s\n' % ', '.join(flags))
1987 ui.write('flags : %s\n' % ', '.join(flags))
1988
1988
1989 ui.write('\n')
1989 ui.write('\n')
1990 fmt = pcfmtstr(totalsize)
1990 fmt = pcfmtstr(totalsize)
1991 fmt2 = dfmtstr(totalsize)
1991 fmt2 = dfmtstr(totalsize)
1992 ui.write('revisions : ' + fmt2 % numrevs)
1992 ui.write('revisions : ' + fmt2 % numrevs)
1993 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1993 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1994 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1994 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1995 ui.write('revisions : ' + fmt2 % numrevs)
1995 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1996 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1997 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1997 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1998 ui.write('revision size : ' + fmt2 % totalsize)
1998 ui.write('revision size : ' + fmt2 % totalsize)
1999 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
1999 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2000 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2000 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2001
2001
2002 ui.write('\n')
2002 ui.write('\n')
2003 fmt = dfmtstr(max(avgchainlen, compratio))
2003 fmt = dfmtstr(max(avgchainlen, compratio))
2004 ui.write('avg chain length : ' + fmt % avgchainlen)
2004 ui.write('avg chain length : ' + fmt % avgchainlen)
2005 ui.write('compression ratio : ' + fmt % compratio)
2005 ui.write('compression ratio : ' + fmt % compratio)
2006
2006
2007 if format > 0:
2007 if format > 0:
2008 ui.write('\n')
2008 ui.write('\n')
2009 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2009 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2010 % tuple(datasize))
2010 % tuple(datasize))
2011 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2011 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2012 % tuple(fullsize))
2012 % tuple(fullsize))
2013 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2013 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2014 % tuple(deltasize))
2014 % tuple(deltasize))
2015
2015
2016 if numdeltas > 0:
2016 if numdeltas > 0:
2017 ui.write('\n')
2017 ui.write('\n')
2018 fmt = pcfmtstr(numdeltas)
2018 fmt = pcfmtstr(numdeltas)
2019 fmt2 = pcfmtstr(numdeltas, 4)
2019 fmt2 = pcfmtstr(numdeltas, 4)
2020 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2020 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2021 if numprev > 0:
2021 if numprev > 0:
2022 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2022 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2023 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2023 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2024 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2024 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2025 if gdelta:
2025 if gdelta:
2026 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2026 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2027 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2027 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2028 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2028 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2029
2029
2030 @command('debugrevspec', [], ('REVSPEC'))
2030 @command('debugrevspec', [], ('REVSPEC'))
2031 def debugrevspec(ui, repo, expr):
2031 def debugrevspec(ui, repo, expr):
2032 '''parse and apply a revision specification'''
2032 '''parse and apply a revision specification'''
2033 if ui.verbose:
2033 if ui.verbose:
2034 tree = revset.parse(expr)[0]
2034 tree = revset.parse(expr)[0]
2035 ui.note(tree, "\n")
2035 ui.note(tree, "\n")
2036 newtree = revset.findaliases(ui, tree)
2036 newtree = revset.findaliases(ui, tree)
2037 if newtree != tree:
2037 if newtree != tree:
2038 ui.note(newtree, "\n")
2038 ui.note(newtree, "\n")
2039 func = revset.match(ui, expr)
2039 func = revset.match(ui, expr)
2040 for c in func(repo, range(len(repo))):
2040 for c in func(repo, range(len(repo))):
2041 ui.write("%s\n" % c)
2041 ui.write("%s\n" % c)
2042
2042
2043 @command('debugsetparents', [], _('REV1 [REV2]'))
2043 @command('debugsetparents', [], _('REV1 [REV2]'))
2044 def debugsetparents(ui, repo, rev1, rev2=None):
2044 def debugsetparents(ui, repo, rev1, rev2=None):
2045 """manually set the parents of the current working directory
2045 """manually set the parents of the current working directory
2046
2046
2047 This is useful for writing repository conversion tools, but should
2047 This is useful for writing repository conversion tools, but should
2048 be used with care.
2048 be used with care.
2049
2049
2050 Returns 0 on success.
2050 Returns 0 on success.
2051 """
2051 """
2052
2052
2053 r1 = scmutil.revsingle(repo, rev1).node()
2053 r1 = scmutil.revsingle(repo, rev1).node()
2054 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2054 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2055
2055
2056 wlock = repo.wlock()
2056 wlock = repo.wlock()
2057 try:
2057 try:
2058 repo.dirstate.setparents(r1, r2)
2058 repo.dirstate.setparents(r1, r2)
2059 finally:
2059 finally:
2060 wlock.release()
2060 wlock.release()
2061
2061
2062 @command('debugstate',
2062 @command('debugstate',
2063 [('', 'nodates', None, _('do not display the saved mtime')),
2063 [('', 'nodates', None, _('do not display the saved mtime')),
2064 ('', 'datesort', None, _('sort by saved mtime'))],
2064 ('', 'datesort', None, _('sort by saved mtime'))],
2065 _('[OPTION]...'))
2065 _('[OPTION]...'))
2066 def debugstate(ui, repo, nodates=None, datesort=None):
2066 def debugstate(ui, repo, nodates=None, datesort=None):
2067 """show the contents of the current dirstate"""
2067 """show the contents of the current dirstate"""
2068 timestr = ""
2068 timestr = ""
2069 showdate = not nodates
2069 showdate = not nodates
2070 if datesort:
2070 if datesort:
2071 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2071 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2072 else:
2072 else:
2073 keyfunc = None # sort by filename
2073 keyfunc = None # sort by filename
2074 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2074 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2075 if showdate:
2075 if showdate:
2076 if ent[3] == -1:
2076 if ent[3] == -1:
2077 # Pad or slice to locale representation
2077 # Pad or slice to locale representation
2078 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2078 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2079 time.localtime(0)))
2079 time.localtime(0)))
2080 timestr = 'unset'
2080 timestr = 'unset'
2081 timestr = (timestr[:locale_len] +
2081 timestr = (timestr[:locale_len] +
2082 ' ' * (locale_len - len(timestr)))
2082 ' ' * (locale_len - len(timestr)))
2083 else:
2083 else:
2084 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2084 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2085 time.localtime(ent[3]))
2085 time.localtime(ent[3]))
2086 if ent[1] & 020000:
2086 if ent[1] & 020000:
2087 mode = 'lnk'
2087 mode = 'lnk'
2088 else:
2088 else:
2089 mode = '%3o' % (ent[1] & 0777)
2089 mode = '%3o' % (ent[1] & 0777)
2090 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2090 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2091 for f in repo.dirstate.copies():
2091 for f in repo.dirstate.copies():
2092 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2092 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2093
2093
2094 @command('debugsub',
2094 @command('debugsub',
2095 [('r', 'rev', '',
2095 [('r', 'rev', '',
2096 _('revision to check'), _('REV'))],
2096 _('revision to check'), _('REV'))],
2097 _('[-r REV] [REV]'))
2097 _('[-r REV] [REV]'))
2098 def debugsub(ui, repo, rev=None):
2098 def debugsub(ui, repo, rev=None):
2099 ctx = scmutil.revsingle(repo, rev, None)
2099 ctx = scmutil.revsingle(repo, rev, None)
2100 for k, v in sorted(ctx.substate.items()):
2100 for k, v in sorted(ctx.substate.items()):
2101 ui.write('path %s\n' % k)
2101 ui.write('path %s\n' % k)
2102 ui.write(' source %s\n' % v[0])
2102 ui.write(' source %s\n' % v[0])
2103 ui.write(' revision %s\n' % v[1])
2103 ui.write(' revision %s\n' % v[1])
2104
2104
2105 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2105 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2106 def debugwalk(ui, repo, *pats, **opts):
2106 def debugwalk(ui, repo, *pats, **opts):
2107 """show how files match on given patterns"""
2107 """show how files match on given patterns"""
2108 m = scmutil.match(repo[None], pats, opts)
2108 m = scmutil.match(repo[None], pats, opts)
2109 items = list(repo.walk(m))
2109 items = list(repo.walk(m))
2110 if not items:
2110 if not items:
2111 return
2111 return
2112 fmt = 'f %%-%ds %%-%ds %%s' % (
2112 fmt = 'f %%-%ds %%-%ds %%s' % (
2113 max([len(abs) for abs in items]),
2113 max([len(abs) for abs in items]),
2114 max([len(m.rel(abs)) for abs in items]))
2114 max([len(m.rel(abs)) for abs in items]))
2115 for abs in items:
2115 for abs in items:
2116 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2116 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2117 ui.write("%s\n" % line.rstrip())
2117 ui.write("%s\n" % line.rstrip())
2118
2118
2119 @command('debugwireargs',
2119 @command('debugwireargs',
2120 [('', 'three', '', 'three'),
2120 [('', 'three', '', 'three'),
2121 ('', 'four', '', 'four'),
2121 ('', 'four', '', 'four'),
2122 ('', 'five', '', 'five'),
2122 ('', 'five', '', 'five'),
2123 ] + remoteopts,
2123 ] + remoteopts,
2124 _('REPO [OPTIONS]... [ONE [TWO]]'))
2124 _('REPO [OPTIONS]... [ONE [TWO]]'))
2125 def debugwireargs(ui, repopath, *vals, **opts):
2125 def debugwireargs(ui, repopath, *vals, **opts):
2126 repo = hg.peer(ui, opts, repopath)
2126 repo = hg.peer(ui, opts, repopath)
2127 for opt in remoteopts:
2127 for opt in remoteopts:
2128 del opts[opt[1]]
2128 del opts[opt[1]]
2129 args = {}
2129 args = {}
2130 for k, v in opts.iteritems():
2130 for k, v in opts.iteritems():
2131 if v:
2131 if v:
2132 args[k] = v
2132 args[k] = v
2133 # run twice to check that we don't mess up the stream for the next command
2133 # run twice to check that we don't mess up the stream for the next command
2134 res1 = repo.debugwireargs(*vals, **args)
2134 res1 = repo.debugwireargs(*vals, **args)
2135 res2 = repo.debugwireargs(*vals, **args)
2135 res2 = repo.debugwireargs(*vals, **args)
2136 ui.write("%s\n" % res1)
2136 ui.write("%s\n" % res1)
2137 if res1 != res2:
2137 if res1 != res2:
2138 ui.warn("%s\n" % res2)
2138 ui.warn("%s\n" % res2)
2139
2139
2140 @command('^diff',
2140 @command('^diff',
2141 [('r', 'rev', [], _('revision'), _('REV')),
2141 [('r', 'rev', [], _('revision'), _('REV')),
2142 ('c', 'change', '', _('change made by revision'), _('REV'))
2142 ('c', 'change', '', _('change made by revision'), _('REV'))
2143 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2143 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2144 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2144 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2145 def diff(ui, repo, *pats, **opts):
2145 def diff(ui, repo, *pats, **opts):
2146 """diff repository (or selected files)
2146 """diff repository (or selected files)
2147
2147
2148 Show differences between revisions for the specified files.
2148 Show differences between revisions for the specified files.
2149
2149
2150 Differences between files are shown using the unified diff format.
2150 Differences between files are shown using the unified diff format.
2151
2151
2152 .. note::
2152 .. note::
2153 diff may generate unexpected results for merges, as it will
2153 diff may generate unexpected results for merges, as it will
2154 default to comparing against the working directory's first
2154 default to comparing against the working directory's first
2155 parent changeset if no revisions are specified.
2155 parent changeset if no revisions are specified.
2156
2156
2157 When two revision arguments are given, then changes are shown
2157 When two revision arguments are given, then changes are shown
2158 between those revisions. If only one revision is specified then
2158 between those revisions. If only one revision is specified then
2159 that revision is compared to the working directory, and, when no
2159 that revision is compared to the working directory, and, when no
2160 revisions are specified, the working directory files are compared
2160 revisions are specified, the working directory files are compared
2161 to its parent.
2161 to its parent.
2162
2162
2163 Alternatively you can specify -c/--change with a revision to see
2163 Alternatively you can specify -c/--change with a revision to see
2164 the changes in that changeset relative to its first parent.
2164 the changes in that changeset relative to its first parent.
2165
2165
2166 Without the -a/--text option, diff will avoid generating diffs of
2166 Without the -a/--text option, diff will avoid generating diffs of
2167 files it detects as binary. With -a, diff will generate a diff
2167 files it detects as binary. With -a, diff will generate a diff
2168 anyway, probably with undesirable results.
2168 anyway, probably with undesirable results.
2169
2169
2170 Use the -g/--git option to generate diffs in the git extended diff
2170 Use the -g/--git option to generate diffs in the git extended diff
2171 format. For more information, read :hg:`help diffs`.
2171 format. For more information, read :hg:`help diffs`.
2172
2172
2173 Returns 0 on success.
2173 Returns 0 on success.
2174 """
2174 """
2175
2175
2176 revs = opts.get('rev')
2176 revs = opts.get('rev')
2177 change = opts.get('change')
2177 change = opts.get('change')
2178 stat = opts.get('stat')
2178 stat = opts.get('stat')
2179 reverse = opts.get('reverse')
2179 reverse = opts.get('reverse')
2180
2180
2181 if revs and change:
2181 if revs and change:
2182 msg = _('cannot specify --rev and --change at the same time')
2182 msg = _('cannot specify --rev and --change at the same time')
2183 raise util.Abort(msg)
2183 raise util.Abort(msg)
2184 elif change:
2184 elif change:
2185 node2 = scmutil.revsingle(repo, change, None).node()
2185 node2 = scmutil.revsingle(repo, change, None).node()
2186 node1 = repo[node2].p1().node()
2186 node1 = repo[node2].p1().node()
2187 else:
2187 else:
2188 node1, node2 = scmutil.revpair(repo, revs)
2188 node1, node2 = scmutil.revpair(repo, revs)
2189
2189
2190 if reverse:
2190 if reverse:
2191 node1, node2 = node2, node1
2191 node1, node2 = node2, node1
2192
2192
2193 diffopts = patch.diffopts(ui, opts)
2193 diffopts = patch.diffopts(ui, opts)
2194 m = scmutil.match(repo[node2], pats, opts)
2194 m = scmutil.match(repo[node2], pats, opts)
2195 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2195 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2196 listsubrepos=opts.get('subrepos'))
2196 listsubrepos=opts.get('subrepos'))
2197
2197
2198 @command('^export',
2198 @command('^export',
2199 [('o', 'output', '',
2199 [('o', 'output', '',
2200 _('print output to file with formatted name'), _('FORMAT')),
2200 _('print output to file with formatted name'), _('FORMAT')),
2201 ('', 'switch-parent', None, _('diff against the second parent')),
2201 ('', 'switch-parent', None, _('diff against the second parent')),
2202 ('r', 'rev', [], _('revisions to export'), _('REV')),
2202 ('r', 'rev', [], _('revisions to export'), _('REV')),
2203 ] + diffopts,
2203 ] + diffopts,
2204 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2204 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2205 def export(ui, repo, *changesets, **opts):
2205 def export(ui, repo, *changesets, **opts):
2206 """dump the header and diffs for one or more changesets
2206 """dump the header and diffs for one or more changesets
2207
2207
2208 Print the changeset header and diffs for one or more revisions.
2208 Print the changeset header and diffs for one or more revisions.
2209
2209
2210 The information shown in the changeset header is: author, date,
2210 The information shown in the changeset header is: author, date,
2211 branch name (if non-default), changeset hash, parent(s) and commit
2211 branch name (if non-default), changeset hash, parent(s) and commit
2212 comment.
2212 comment.
2213
2213
2214 .. note::
2214 .. note::
2215 export may generate unexpected diff output for merge
2215 export may generate unexpected diff output for merge
2216 changesets, as it will compare the merge changeset against its
2216 changesets, as it will compare the merge changeset against its
2217 first parent only.
2217 first parent only.
2218
2218
2219 Output may be to a file, in which case the name of the file is
2219 Output may be to a file, in which case the name of the file is
2220 given using a format string. The formatting rules are as follows:
2220 given using a format string. The formatting rules are as follows:
2221
2221
2222 :``%%``: literal "%" character
2222 :``%%``: literal "%" character
2223 :``%H``: changeset hash (40 hexadecimal digits)
2223 :``%H``: changeset hash (40 hexadecimal digits)
2224 :``%N``: number of patches being generated
2224 :``%N``: number of patches being generated
2225 :``%R``: changeset revision number
2225 :``%R``: changeset revision number
2226 :``%b``: basename of the exporting repository
2226 :``%b``: basename of the exporting repository
2227 :``%h``: short-form changeset hash (12 hexadecimal digits)
2227 :``%h``: short-form changeset hash (12 hexadecimal digits)
2228 :``%n``: zero-padded sequence number, starting at 1
2228 :``%n``: zero-padded sequence number, starting at 1
2229 :``%r``: zero-padded changeset revision number
2229 :``%r``: zero-padded changeset revision number
2230
2230
2231 Without the -a/--text option, export will avoid generating diffs
2231 Without the -a/--text option, export will avoid generating diffs
2232 of files it detects as binary. With -a, export will generate a
2232 of files it detects as binary. With -a, export will generate a
2233 diff anyway, probably with undesirable results.
2233 diff anyway, probably with undesirable results.
2234
2234
2235 Use the -g/--git option to generate diffs in the git extended diff
2235 Use the -g/--git option to generate diffs in the git extended diff
2236 format. See :hg:`help diffs` for more information.
2236 format. See :hg:`help diffs` for more information.
2237
2237
2238 With the --switch-parent option, the diff will be against the
2238 With the --switch-parent option, the diff will be against the
2239 second parent. It can be useful to review a merge.
2239 second parent. It can be useful to review a merge.
2240
2240
2241 Returns 0 on success.
2241 Returns 0 on success.
2242 """
2242 """
2243 changesets += tuple(opts.get('rev', []))
2243 changesets += tuple(opts.get('rev', []))
2244 if not changesets:
2244 if not changesets:
2245 raise util.Abort(_("export requires at least one changeset"))
2245 raise util.Abort(_("export requires at least one changeset"))
2246 revs = scmutil.revrange(repo, changesets)
2246 revs = scmutil.revrange(repo, changesets)
2247 if len(revs) > 1:
2247 if len(revs) > 1:
2248 ui.note(_('exporting patches:\n'))
2248 ui.note(_('exporting patches:\n'))
2249 else:
2249 else:
2250 ui.note(_('exporting patch:\n'))
2250 ui.note(_('exporting patch:\n'))
2251 cmdutil.export(repo, revs, template=opts.get('output'),
2251 cmdutil.export(repo, revs, template=opts.get('output'),
2252 switch_parent=opts.get('switch_parent'),
2252 switch_parent=opts.get('switch_parent'),
2253 opts=patch.diffopts(ui, opts))
2253 opts=patch.diffopts(ui, opts))
2254
2254
2255 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2255 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2256 def forget(ui, repo, *pats, **opts):
2256 def forget(ui, repo, *pats, **opts):
2257 """forget the specified files on the next commit
2257 """forget the specified files on the next commit
2258
2258
2259 Mark the specified files so they will no longer be tracked
2259 Mark the specified files so they will no longer be tracked
2260 after the next commit.
2260 after the next commit.
2261
2261
2262 This only removes files from the current branch, not from the
2262 This only removes files from the current branch, not from the
2263 entire project history, and it does not delete them from the
2263 entire project history, and it does not delete them from the
2264 working directory.
2264 working directory.
2265
2265
2266 To undo a forget before the next commit, see :hg:`add`.
2266 To undo a forget before the next commit, see :hg:`add`.
2267
2267
2268 Returns 0 on success.
2268 Returns 0 on success.
2269 """
2269 """
2270
2270
2271 if not pats:
2271 if not pats:
2272 raise util.Abort(_('no files specified'))
2272 raise util.Abort(_('no files specified'))
2273
2273
2274 m = scmutil.match(repo[None], pats, opts)
2274 m = scmutil.match(repo[None], pats, opts)
2275 s = repo.status(match=m, clean=True)
2275 s = repo.status(match=m, clean=True)
2276 forget = sorted(s[0] + s[1] + s[3] + s[6])
2276 forget = sorted(s[0] + s[1] + s[3] + s[6])
2277 errs = 0
2277 errs = 0
2278
2278
2279 for f in m.files():
2279 for f in m.files():
2280 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2280 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2281 if os.path.exists(m.rel(f)):
2281 if os.path.exists(m.rel(f)):
2282 ui.warn(_('not removing %s: file is already untracked\n')
2282 ui.warn(_('not removing %s: file is already untracked\n')
2283 % m.rel(f))
2283 % m.rel(f))
2284 errs = 1
2284 errs = 1
2285
2285
2286 for f in forget:
2286 for f in forget:
2287 if ui.verbose or not m.exact(f):
2287 if ui.verbose or not m.exact(f):
2288 ui.status(_('removing %s\n') % m.rel(f))
2288 ui.status(_('removing %s\n') % m.rel(f))
2289
2289
2290 repo[None].forget(forget)
2290 repo[None].forget(forget)
2291 return errs
2291 return errs
2292
2292
2293 @command('grep',
2293 @command('grep',
2294 [('0', 'print0', None, _('end fields with NUL')),
2294 [('0', 'print0', None, _('end fields with NUL')),
2295 ('', 'all', None, _('print all revisions that match')),
2295 ('', 'all', None, _('print all revisions that match')),
2296 ('a', 'text', None, _('treat all files as text')),
2296 ('a', 'text', None, _('treat all files as text')),
2297 ('f', 'follow', None,
2297 ('f', 'follow', None,
2298 _('follow changeset history,'
2298 _('follow changeset history,'
2299 ' or file history across copies and renames')),
2299 ' or file history across copies and renames')),
2300 ('i', 'ignore-case', None, _('ignore case when matching')),
2300 ('i', 'ignore-case', None, _('ignore case when matching')),
2301 ('l', 'files-with-matches', None,
2301 ('l', 'files-with-matches', None,
2302 _('print only filenames and revisions that match')),
2302 _('print only filenames and revisions that match')),
2303 ('n', 'line-number', None, _('print matching line numbers')),
2303 ('n', 'line-number', None, _('print matching line numbers')),
2304 ('r', 'rev', [],
2304 ('r', 'rev', [],
2305 _('only search files changed within revision range'), _('REV')),
2305 _('only search files changed within revision range'), _('REV')),
2306 ('u', 'user', None, _('list the author (long with -v)')),
2306 ('u', 'user', None, _('list the author (long with -v)')),
2307 ('d', 'date', None, _('list the date (short with -q)')),
2307 ('d', 'date', None, _('list the date (short with -q)')),
2308 ] + walkopts,
2308 ] + walkopts,
2309 _('[OPTION]... PATTERN [FILE]...'))
2309 _('[OPTION]... PATTERN [FILE]...'))
2310 def grep(ui, repo, pattern, *pats, **opts):
2310 def grep(ui, repo, pattern, *pats, **opts):
2311 """search for a pattern in specified files and revisions
2311 """search for a pattern in specified files and revisions
2312
2312
2313 Search revisions of files for a regular expression.
2313 Search revisions of files for a regular expression.
2314
2314
2315 This command behaves differently than Unix grep. It only accepts
2315 This command behaves differently than Unix grep. It only accepts
2316 Python/Perl regexps. It searches repository history, not the
2316 Python/Perl regexps. It searches repository history, not the
2317 working directory. It always prints the revision number in which a
2317 working directory. It always prints the revision number in which a
2318 match appears.
2318 match appears.
2319
2319
2320 By default, grep only prints output for the first revision of a
2320 By default, grep only prints output for the first revision of a
2321 file in which it finds a match. To get it to print every revision
2321 file in which it finds a match. To get it to print every revision
2322 that contains a change in match status ("-" for a match that
2322 that contains a change in match status ("-" for a match that
2323 becomes a non-match, or "+" for a non-match that becomes a match),
2323 becomes a non-match, or "+" for a non-match that becomes a match),
2324 use the --all flag.
2324 use the --all flag.
2325
2325
2326 Returns 0 if a match is found, 1 otherwise.
2326 Returns 0 if a match is found, 1 otherwise.
2327 """
2327 """
2328 reflags = 0
2328 reflags = 0
2329 if opts.get('ignore_case'):
2329 if opts.get('ignore_case'):
2330 reflags |= re.I
2330 reflags |= re.I
2331 try:
2331 try:
2332 regexp = re.compile(pattern, reflags)
2332 regexp = re.compile(pattern, reflags)
2333 except re.error, inst:
2333 except re.error, inst:
2334 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2334 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2335 return 1
2335 return 1
2336 sep, eol = ':', '\n'
2336 sep, eol = ':', '\n'
2337 if opts.get('print0'):
2337 if opts.get('print0'):
2338 sep = eol = '\0'
2338 sep = eol = '\0'
2339
2339
2340 getfile = util.lrucachefunc(repo.file)
2340 getfile = util.lrucachefunc(repo.file)
2341
2341
2342 def matchlines(body):
2342 def matchlines(body):
2343 begin = 0
2343 begin = 0
2344 linenum = 0
2344 linenum = 0
2345 while True:
2345 while True:
2346 match = regexp.search(body, begin)
2346 match = regexp.search(body, begin)
2347 if not match:
2347 if not match:
2348 break
2348 break
2349 mstart, mend = match.span()
2349 mstart, mend = match.span()
2350 linenum += body.count('\n', begin, mstart) + 1
2350 linenum += body.count('\n', begin, mstart) + 1
2351 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2351 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2352 begin = body.find('\n', mend) + 1 or len(body)
2352 begin = body.find('\n', mend) + 1 or len(body)
2353 lend = begin - 1
2353 lend = begin - 1
2354 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2354 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2355
2355
2356 class linestate(object):
2356 class linestate(object):
2357 def __init__(self, line, linenum, colstart, colend):
2357 def __init__(self, line, linenum, colstart, colend):
2358 self.line = line
2358 self.line = line
2359 self.linenum = linenum
2359 self.linenum = linenum
2360 self.colstart = colstart
2360 self.colstart = colstart
2361 self.colend = colend
2361 self.colend = colend
2362
2362
2363 def __hash__(self):
2363 def __hash__(self):
2364 return hash((self.linenum, self.line))
2364 return hash((self.linenum, self.line))
2365
2365
2366 def __eq__(self, other):
2366 def __eq__(self, other):
2367 return self.line == other.line
2367 return self.line == other.line
2368
2368
2369 matches = {}
2369 matches = {}
2370 copies = {}
2370 copies = {}
2371 def grepbody(fn, rev, body):
2371 def grepbody(fn, rev, body):
2372 matches[rev].setdefault(fn, [])
2372 matches[rev].setdefault(fn, [])
2373 m = matches[rev][fn]
2373 m = matches[rev][fn]
2374 for lnum, cstart, cend, line in matchlines(body):
2374 for lnum, cstart, cend, line in matchlines(body):
2375 s = linestate(line, lnum, cstart, cend)
2375 s = linestate(line, lnum, cstart, cend)
2376 m.append(s)
2376 m.append(s)
2377
2377
2378 def difflinestates(a, b):
2378 def difflinestates(a, b):
2379 sm = difflib.SequenceMatcher(None, a, b)
2379 sm = difflib.SequenceMatcher(None, a, b)
2380 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2380 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2381 if tag == 'insert':
2381 if tag == 'insert':
2382 for i in xrange(blo, bhi):
2382 for i in xrange(blo, bhi):
2383 yield ('+', b[i])
2383 yield ('+', b[i])
2384 elif tag == 'delete':
2384 elif tag == 'delete':
2385 for i in xrange(alo, ahi):
2385 for i in xrange(alo, ahi):
2386 yield ('-', a[i])
2386 yield ('-', a[i])
2387 elif tag == 'replace':
2387 elif tag == 'replace':
2388 for i in xrange(alo, ahi):
2388 for i in xrange(alo, ahi):
2389 yield ('-', a[i])
2389 yield ('-', a[i])
2390 for i in xrange(blo, bhi):
2390 for i in xrange(blo, bhi):
2391 yield ('+', b[i])
2391 yield ('+', b[i])
2392
2392
2393 def display(fn, ctx, pstates, states):
2393 def display(fn, ctx, pstates, states):
2394 rev = ctx.rev()
2394 rev = ctx.rev()
2395 datefunc = ui.quiet and util.shortdate or util.datestr
2395 datefunc = ui.quiet and util.shortdate or util.datestr
2396 found = False
2396 found = False
2397 filerevmatches = {}
2397 filerevmatches = {}
2398 def binary():
2398 def binary():
2399 flog = getfile(fn)
2399 flog = getfile(fn)
2400 return util.binary(flog.read(ctx.filenode(fn)))
2400 return util.binary(flog.read(ctx.filenode(fn)))
2401
2401
2402 if opts.get('all'):
2402 if opts.get('all'):
2403 iter = difflinestates(pstates, states)
2403 iter = difflinestates(pstates, states)
2404 else:
2404 else:
2405 iter = [('', l) for l in states]
2405 iter = [('', l) for l in states]
2406 for change, l in iter:
2406 for change, l in iter:
2407 cols = [fn, str(rev)]
2407 cols = [fn, str(rev)]
2408 before, match, after = None, None, None
2408 before, match, after = None, None, None
2409 if opts.get('line_number'):
2409 if opts.get('line_number'):
2410 cols.append(str(l.linenum))
2410 cols.append(str(l.linenum))
2411 if opts.get('all'):
2411 if opts.get('all'):
2412 cols.append(change)
2412 cols.append(change)
2413 if opts.get('user'):
2413 if opts.get('user'):
2414 cols.append(ui.shortuser(ctx.user()))
2414 cols.append(ui.shortuser(ctx.user()))
2415 if opts.get('date'):
2415 if opts.get('date'):
2416 cols.append(datefunc(ctx.date()))
2416 cols.append(datefunc(ctx.date()))
2417 if opts.get('files_with_matches'):
2417 if opts.get('files_with_matches'):
2418 c = (fn, rev)
2418 c = (fn, rev)
2419 if c in filerevmatches:
2419 if c in filerevmatches:
2420 continue
2420 continue
2421 filerevmatches[c] = 1
2421 filerevmatches[c] = 1
2422 else:
2422 else:
2423 before = l.line[:l.colstart]
2423 before = l.line[:l.colstart]
2424 match = l.line[l.colstart:l.colend]
2424 match = l.line[l.colstart:l.colend]
2425 after = l.line[l.colend:]
2425 after = l.line[l.colend:]
2426 ui.write(sep.join(cols))
2426 ui.write(sep.join(cols))
2427 if before is not None:
2427 if before is not None:
2428 if not opts.get('text') and binary():
2428 if not opts.get('text') and binary():
2429 ui.write(sep + " Binary file matches")
2429 ui.write(sep + " Binary file matches")
2430 else:
2430 else:
2431 ui.write(sep + before)
2431 ui.write(sep + before)
2432 ui.write(match, label='grep.match')
2432 ui.write(match, label='grep.match')
2433 ui.write(after)
2433 ui.write(after)
2434 ui.write(eol)
2434 ui.write(eol)
2435 found = True
2435 found = True
2436 return found
2436 return found
2437
2437
2438 skip = {}
2438 skip = {}
2439 revfiles = {}
2439 revfiles = {}
2440 matchfn = scmutil.match(repo[None], pats, opts)
2440 matchfn = scmutil.match(repo[None], pats, opts)
2441 found = False
2441 found = False
2442 follow = opts.get('follow')
2442 follow = opts.get('follow')
2443
2443
2444 def prep(ctx, fns):
2444 def prep(ctx, fns):
2445 rev = ctx.rev()
2445 rev = ctx.rev()
2446 pctx = ctx.p1()
2446 pctx = ctx.p1()
2447 parent = pctx.rev()
2447 parent = pctx.rev()
2448 matches.setdefault(rev, {})
2448 matches.setdefault(rev, {})
2449 matches.setdefault(parent, {})
2449 matches.setdefault(parent, {})
2450 files = revfiles.setdefault(rev, [])
2450 files = revfiles.setdefault(rev, [])
2451 for fn in fns:
2451 for fn in fns:
2452 flog = getfile(fn)
2452 flog = getfile(fn)
2453 try:
2453 try:
2454 fnode = ctx.filenode(fn)
2454 fnode = ctx.filenode(fn)
2455 except error.LookupError:
2455 except error.LookupError:
2456 continue
2456 continue
2457
2457
2458 copied = flog.renamed(fnode)
2458 copied = flog.renamed(fnode)
2459 copy = follow and copied and copied[0]
2459 copy = follow and copied and copied[0]
2460 if copy:
2460 if copy:
2461 copies.setdefault(rev, {})[fn] = copy
2461 copies.setdefault(rev, {})[fn] = copy
2462 if fn in skip:
2462 if fn in skip:
2463 if copy:
2463 if copy:
2464 skip[copy] = True
2464 skip[copy] = True
2465 continue
2465 continue
2466 files.append(fn)
2466 files.append(fn)
2467
2467
2468 if fn not in matches[rev]:
2468 if fn not in matches[rev]:
2469 grepbody(fn, rev, flog.read(fnode))
2469 grepbody(fn, rev, flog.read(fnode))
2470
2470
2471 pfn = copy or fn
2471 pfn = copy or fn
2472 if pfn not in matches[parent]:
2472 if pfn not in matches[parent]:
2473 try:
2473 try:
2474 fnode = pctx.filenode(pfn)
2474 fnode = pctx.filenode(pfn)
2475 grepbody(pfn, parent, flog.read(fnode))
2475 grepbody(pfn, parent, flog.read(fnode))
2476 except error.LookupError:
2476 except error.LookupError:
2477 pass
2477 pass
2478
2478
2479 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2479 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2480 rev = ctx.rev()
2480 rev = ctx.rev()
2481 parent = ctx.p1().rev()
2481 parent = ctx.p1().rev()
2482 for fn in sorted(revfiles.get(rev, [])):
2482 for fn in sorted(revfiles.get(rev, [])):
2483 states = matches[rev][fn]
2483 states = matches[rev][fn]
2484 copy = copies.get(rev, {}).get(fn)
2484 copy = copies.get(rev, {}).get(fn)
2485 if fn in skip:
2485 if fn in skip:
2486 if copy:
2486 if copy:
2487 skip[copy] = True
2487 skip[copy] = True
2488 continue
2488 continue
2489 pstates = matches.get(parent, {}).get(copy or fn, [])
2489 pstates = matches.get(parent, {}).get(copy or fn, [])
2490 if pstates or states:
2490 if pstates or states:
2491 r = display(fn, ctx, pstates, states)
2491 r = display(fn, ctx, pstates, states)
2492 found = found or r
2492 found = found or r
2493 if r and not opts.get('all'):
2493 if r and not opts.get('all'):
2494 skip[fn] = True
2494 skip[fn] = True
2495 if copy:
2495 if copy:
2496 skip[copy] = True
2496 skip[copy] = True
2497 del matches[rev]
2497 del matches[rev]
2498 del revfiles[rev]
2498 del revfiles[rev]
2499
2499
2500 return not found
2500 return not found
2501
2501
2502 @command('heads',
2502 @command('heads',
2503 [('r', 'rev', '',
2503 [('r', 'rev', '',
2504 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2504 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2505 ('t', 'topo', False, _('show topological heads only')),
2505 ('t', 'topo', False, _('show topological heads only')),
2506 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2506 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2507 ('c', 'closed', False, _('show normal and closed branch heads')),
2507 ('c', 'closed', False, _('show normal and closed branch heads')),
2508 ] + templateopts,
2508 ] + templateopts,
2509 _('[-ac] [-r STARTREV] [REV]...'))
2509 _('[-ac] [-r STARTREV] [REV]...'))
2510 def heads(ui, repo, *branchrevs, **opts):
2510 def heads(ui, repo, *branchrevs, **opts):
2511 """show current repository heads or show branch heads
2511 """show current repository heads or show branch heads
2512
2512
2513 With no arguments, show all repository branch heads.
2513 With no arguments, show all repository branch heads.
2514
2514
2515 Repository "heads" are changesets with no child changesets. They are
2515 Repository "heads" are changesets with no child changesets. They are
2516 where development generally takes place and are the usual targets
2516 where development generally takes place and are the usual targets
2517 for update and merge operations. Branch heads are changesets that have
2517 for update and merge operations. Branch heads are changesets that have
2518 no child changeset on the same branch.
2518 no child changeset on the same branch.
2519
2519
2520 If one or more REVs are given, only branch heads on the branches
2520 If one or more REVs are given, only branch heads on the branches
2521 associated with the specified changesets are shown.
2521 associated with the specified changesets are shown.
2522
2522
2523 If -c/--closed is specified, also show branch heads marked closed
2523 If -c/--closed is specified, also show branch heads marked closed
2524 (see :hg:`commit --close-branch`).
2524 (see :hg:`commit --close-branch`).
2525
2525
2526 If STARTREV is specified, only those heads that are descendants of
2526 If STARTREV is specified, only those heads that are descendants of
2527 STARTREV will be displayed.
2527 STARTREV will be displayed.
2528
2528
2529 If -t/--topo is specified, named branch mechanics will be ignored and only
2529 If -t/--topo is specified, named branch mechanics will be ignored and only
2530 changesets without children will be shown.
2530 changesets without children will be shown.
2531
2531
2532 Returns 0 if matching heads are found, 1 if not.
2532 Returns 0 if matching heads are found, 1 if not.
2533 """
2533 """
2534
2534
2535 start = None
2535 start = None
2536 if 'rev' in opts:
2536 if 'rev' in opts:
2537 start = scmutil.revsingle(repo, opts['rev'], None).node()
2537 start = scmutil.revsingle(repo, opts['rev'], None).node()
2538
2538
2539 if opts.get('topo'):
2539 if opts.get('topo'):
2540 heads = [repo[h] for h in repo.heads(start)]
2540 heads = [repo[h] for h in repo.heads(start)]
2541 else:
2541 else:
2542 heads = []
2542 heads = []
2543 for branch in repo.branchmap():
2543 for branch in repo.branchmap():
2544 heads += repo.branchheads(branch, start, opts.get('closed'))
2544 heads += repo.branchheads(branch, start, opts.get('closed'))
2545 heads = [repo[h] for h in heads]
2545 heads = [repo[h] for h in heads]
2546
2546
2547 if branchrevs:
2547 if branchrevs:
2548 branches = set(repo[br].branch() for br in branchrevs)
2548 branches = set(repo[br].branch() for br in branchrevs)
2549 heads = [h for h in heads if h.branch() in branches]
2549 heads = [h for h in heads if h.branch() in branches]
2550
2550
2551 if opts.get('active') and branchrevs:
2551 if opts.get('active') and branchrevs:
2552 dagheads = repo.heads(start)
2552 dagheads = repo.heads(start)
2553 heads = [h for h in heads if h.node() in dagheads]
2553 heads = [h for h in heads if h.node() in dagheads]
2554
2554
2555 if branchrevs:
2555 if branchrevs:
2556 haveheads = set(h.branch() for h in heads)
2556 haveheads = set(h.branch() for h in heads)
2557 if branches - haveheads:
2557 if branches - haveheads:
2558 headless = ', '.join(b for b in branches - haveheads)
2558 headless = ', '.join(b for b in branches - haveheads)
2559 msg = _('no open branch heads found on branches %s')
2559 msg = _('no open branch heads found on branches %s')
2560 if opts.get('rev'):
2560 if opts.get('rev'):
2561 msg += _(' (started at %s)' % opts['rev'])
2561 msg += _(' (started at %s)' % opts['rev'])
2562 ui.warn((msg + '\n') % headless)
2562 ui.warn((msg + '\n') % headless)
2563
2563
2564 if not heads:
2564 if not heads:
2565 return 1
2565 return 1
2566
2566
2567 heads = sorted(heads, key=lambda x: -x.rev())
2567 heads = sorted(heads, key=lambda x: -x.rev())
2568 displayer = cmdutil.show_changeset(ui, repo, opts)
2568 displayer = cmdutil.show_changeset(ui, repo, opts)
2569 for ctx in heads:
2569 for ctx in heads:
2570 displayer.show(ctx)
2570 displayer.show(ctx)
2571 displayer.close()
2571 displayer.close()
2572
2572
2573 @command('help',
2573 @command('help',
2574 [('e', 'extension', None, _('show only help for extensions')),
2574 [('e', 'extension', None, _('show only help for extensions')),
2575 ('c', 'command', None, _('show only help for commands'))],
2575 ('c', 'command', None, _('show only help for commands'))],
2576 _('[-ec] [TOPIC]'))
2576 _('[-ec] [TOPIC]'))
2577 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2577 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2578 """show help for a given topic or a help overview
2578 """show help for a given topic or a help overview
2579
2579
2580 With no arguments, print a list of commands with short help messages.
2580 With no arguments, print a list of commands with short help messages.
2581
2581
2582 Given a topic, extension, or command name, print help for that
2582 Given a topic, extension, or command name, print help for that
2583 topic.
2583 topic.
2584
2584
2585 Returns 0 if successful.
2585 Returns 0 if successful.
2586 """
2586 """
2587 option_lists = []
2587 option_lists = []
2588 textwidth = min(ui.termwidth(), 80) - 2
2588 textwidth = min(ui.termwidth(), 80) - 2
2589
2589
2590 def addglobalopts(aliases):
2590 def addglobalopts(aliases):
2591 if ui.verbose:
2591 if ui.verbose:
2592 option_lists.append((_("global options:"), globalopts))
2592 option_lists.append((_("global options:"), globalopts))
2593 if name == 'shortlist':
2593 if name == 'shortlist':
2594 option_lists.append((_('use "hg help" for the full list '
2594 option_lists.append((_('use "hg help" for the full list '
2595 'of commands'), ()))
2595 'of commands'), ()))
2596 else:
2596 else:
2597 if name == 'shortlist':
2597 if name == 'shortlist':
2598 msg = _('use "hg help" for the full list of commands '
2598 msg = _('use "hg help" for the full list of commands '
2599 'or "hg -v" for details')
2599 'or "hg -v" for details')
2600 elif name and not full:
2600 elif name and not full:
2601 msg = _('use "hg help %s" to show the full help text' % name)
2601 msg = _('use "hg help %s" to show the full help text' % name)
2602 elif aliases:
2602 elif aliases:
2603 msg = _('use "hg -v help%s" to show builtin aliases and '
2603 msg = _('use "hg -v help%s" to show builtin aliases and '
2604 'global options') % (name and " " + name or "")
2604 'global options') % (name and " " + name or "")
2605 else:
2605 else:
2606 msg = _('use "hg -v help %s" to show global options') % name
2606 msg = _('use "hg -v help %s" to show global options') % name
2607 option_lists.append((msg, ()))
2607 option_lists.append((msg, ()))
2608
2608
2609 def helpcmd(name):
2609 def helpcmd(name):
2610 if with_version:
2610 if with_version:
2611 version_(ui)
2611 version_(ui)
2612 ui.write('\n')
2612 ui.write('\n')
2613
2613
2614 try:
2614 try:
2615 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2615 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2616 except error.AmbiguousCommand, inst:
2616 except error.AmbiguousCommand, inst:
2617 # py3k fix: except vars can't be used outside the scope of the
2617 # py3k fix: except vars can't be used outside the scope of the
2618 # except block, nor can be used inside a lambda. python issue4617
2618 # except block, nor can be used inside a lambda. python issue4617
2619 prefix = inst.args[0]
2619 prefix = inst.args[0]
2620 select = lambda c: c.lstrip('^').startswith(prefix)
2620 select = lambda c: c.lstrip('^').startswith(prefix)
2621 helplist(_('list of commands:\n\n'), select)
2621 helplist(_('list of commands:\n\n'), select)
2622 return
2622 return
2623
2623
2624 # check if it's an invalid alias and display its error if it is
2624 # check if it's an invalid alias and display its error if it is
2625 if getattr(entry[0], 'badalias', False):
2625 if getattr(entry[0], 'badalias', False):
2626 if not unknowncmd:
2626 if not unknowncmd:
2627 entry[0](ui)
2627 entry[0](ui)
2628 return
2628 return
2629
2629
2630 # synopsis
2630 # synopsis
2631 if len(entry) > 2:
2631 if len(entry) > 2:
2632 if entry[2].startswith('hg'):
2632 if entry[2].startswith('hg'):
2633 ui.write("%s\n" % entry[2])
2633 ui.write("%s\n" % entry[2])
2634 else:
2634 else:
2635 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2635 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2636 else:
2636 else:
2637 ui.write('hg %s\n' % aliases[0])
2637 ui.write('hg %s\n' % aliases[0])
2638
2638
2639 # aliases
2639 # aliases
2640 if full and not ui.quiet and len(aliases) > 1:
2640 if full and not ui.quiet and len(aliases) > 1:
2641 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2641 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2642
2642
2643 # description
2643 # description
2644 doc = gettext(entry[0].__doc__)
2644 doc = gettext(entry[0].__doc__)
2645 if not doc:
2645 if not doc:
2646 doc = _("(no help text available)")
2646 doc = _("(no help text available)")
2647 if hasattr(entry[0], 'definition'): # aliased command
2647 if hasattr(entry[0], 'definition'): # aliased command
2648 if entry[0].definition.startswith('!'): # shell alias
2648 if entry[0].definition.startswith('!'): # shell alias
2649 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2649 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2650 else:
2650 else:
2651 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2651 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2652 if ui.quiet or not full:
2652 if ui.quiet or not full:
2653 doc = doc.splitlines()[0]
2653 doc = doc.splitlines()[0]
2654 keep = ui.verbose and ['verbose'] or []
2654 keep = ui.verbose and ['verbose'] or []
2655 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2655 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2656 ui.write("\n%s\n" % formatted)
2656 ui.write("\n%s\n" % formatted)
2657 if pruned:
2657 if pruned:
2658 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2658 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2659
2659
2660 if not ui.quiet:
2660 if not ui.quiet:
2661 # options
2661 # options
2662 if entry[1]:
2662 if entry[1]:
2663 option_lists.append((_("options:\n"), entry[1]))
2663 option_lists.append((_("options:\n"), entry[1]))
2664
2664
2665 addglobalopts(False)
2665 addglobalopts(False)
2666
2666
2667 # check if this command shadows a non-trivial (multi-line)
2667 # check if this command shadows a non-trivial (multi-line)
2668 # extension help text
2668 # extension help text
2669 try:
2669 try:
2670 mod = extensions.find(name)
2670 mod = extensions.find(name)
2671 doc = gettext(mod.__doc__) or ''
2671 doc = gettext(mod.__doc__) or ''
2672 if '\n' in doc.strip():
2672 if '\n' in doc.strip():
2673 msg = _('use "hg help -e %s" to show help for '
2673 msg = _('use "hg help -e %s" to show help for '
2674 'the %s extension') % (name, name)
2674 'the %s extension') % (name, name)
2675 ui.write('\n%s\n' % msg)
2675 ui.write('\n%s\n' % msg)
2676 except KeyError:
2676 except KeyError:
2677 pass
2677 pass
2678
2678
2679 def helplist(header, select=None):
2679 def helplist(header, select=None):
2680 h = {}
2680 h = {}
2681 cmds = {}
2681 cmds = {}
2682 for c, e in table.iteritems():
2682 for c, e in table.iteritems():
2683 f = c.split("|", 1)[0]
2683 f = c.split("|", 1)[0]
2684 if select and not select(f):
2684 if select and not select(f):
2685 continue
2685 continue
2686 if (not select and name != 'shortlist' and
2686 if (not select and name != 'shortlist' and
2687 e[0].__module__ != __name__):
2687 e[0].__module__ != __name__):
2688 continue
2688 continue
2689 if name == "shortlist" and not f.startswith("^"):
2689 if name == "shortlist" and not f.startswith("^"):
2690 continue
2690 continue
2691 f = f.lstrip("^")
2691 f = f.lstrip("^")
2692 if not ui.debugflag and f.startswith("debug"):
2692 if not ui.debugflag and f.startswith("debug"):
2693 continue
2693 continue
2694 doc = e[0].__doc__
2694 doc = e[0].__doc__
2695 if doc and 'DEPRECATED' in doc and not ui.verbose:
2695 if doc and 'DEPRECATED' in doc and not ui.verbose:
2696 continue
2696 continue
2697 doc = gettext(doc)
2697 doc = gettext(doc)
2698 if not doc:
2698 if not doc:
2699 doc = _("(no help text available)")
2699 doc = _("(no help text available)")
2700 h[f] = doc.splitlines()[0].rstrip()
2700 h[f] = doc.splitlines()[0].rstrip()
2701 cmds[f] = c.lstrip("^")
2701 cmds[f] = c.lstrip("^")
2702
2702
2703 if not h:
2703 if not h:
2704 ui.status(_('no commands defined\n'))
2704 ui.status(_('no commands defined\n'))
2705 return
2705 return
2706
2706
2707 ui.status(header)
2707 ui.status(header)
2708 fns = sorted(h)
2708 fns = sorted(h)
2709 m = max(map(len, fns))
2709 m = max(map(len, fns))
2710 for f in fns:
2710 for f in fns:
2711 if ui.verbose:
2711 if ui.verbose:
2712 commands = cmds[f].replace("|",", ")
2712 commands = cmds[f].replace("|",", ")
2713 ui.write(" %s:\n %s\n"%(commands, h[f]))
2713 ui.write(" %s:\n %s\n"%(commands, h[f]))
2714 else:
2714 else:
2715 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2715 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2716 initindent=' %-*s ' % (m, f),
2716 initindent=' %-*s ' % (m, f),
2717 hangindent=' ' * (m + 4))))
2717 hangindent=' ' * (m + 4))))
2718
2718
2719 if not ui.quiet:
2719 if not ui.quiet:
2720 addglobalopts(True)
2720 addglobalopts(True)
2721
2721
2722 def helptopic(name):
2722 def helptopic(name):
2723 for names, header, doc in help.helptable:
2723 for names, header, doc in help.helptable:
2724 if name in names:
2724 if name in names:
2725 break
2725 break
2726 else:
2726 else:
2727 raise error.UnknownCommand(name)
2727 raise error.UnknownCommand(name)
2728
2728
2729 # description
2729 # description
2730 if not doc:
2730 if not doc:
2731 doc = _("(no help text available)")
2731 doc = _("(no help text available)")
2732 if hasattr(doc, '__call__'):
2732 if hasattr(doc, '__call__'):
2733 doc = doc()
2733 doc = doc()
2734
2734
2735 ui.write("%s\n\n" % header)
2735 ui.write("%s\n\n" % header)
2736 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2736 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2737 try:
2737 try:
2738 cmdutil.findcmd(name, table)
2738 cmdutil.findcmd(name, table)
2739 ui.write(_('\nuse "hg help -c %s" to see help for '
2739 ui.write(_('\nuse "hg help -c %s" to see help for '
2740 'the %s command\n') % (name, name))
2740 'the %s command\n') % (name, name))
2741 except error.UnknownCommand:
2741 except error.UnknownCommand:
2742 pass
2742 pass
2743
2743
2744 def helpext(name):
2744 def helpext(name):
2745 try:
2745 try:
2746 mod = extensions.find(name)
2746 mod = extensions.find(name)
2747 doc = gettext(mod.__doc__) or _('no help text available')
2747 doc = gettext(mod.__doc__) or _('no help text available')
2748 except KeyError:
2748 except KeyError:
2749 mod = None
2749 mod = None
2750 doc = extensions.disabledext(name)
2750 doc = extensions.disabledext(name)
2751 if not doc:
2751 if not doc:
2752 raise error.UnknownCommand(name)
2752 raise error.UnknownCommand(name)
2753
2753
2754 if '\n' not in doc:
2754 if '\n' not in doc:
2755 head, tail = doc, ""
2755 head, tail = doc, ""
2756 else:
2756 else:
2757 head, tail = doc.split('\n', 1)
2757 head, tail = doc.split('\n', 1)
2758 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2758 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2759 if tail:
2759 if tail:
2760 ui.write(minirst.format(tail, textwidth))
2760 ui.write(minirst.format(tail, textwidth))
2761 ui.status('\n\n')
2761 ui.status('\n\n')
2762
2762
2763 if mod:
2763 if mod:
2764 try:
2764 try:
2765 ct = mod.cmdtable
2765 ct = mod.cmdtable
2766 except AttributeError:
2766 except AttributeError:
2767 ct = {}
2767 ct = {}
2768 modcmds = set([c.split('|', 1)[0] for c in ct])
2768 modcmds = set([c.split('|', 1)[0] for c in ct])
2769 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2769 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2770 else:
2770 else:
2771 ui.write(_('use "hg help extensions" for information on enabling '
2771 ui.write(_('use "hg help extensions" for information on enabling '
2772 'extensions\n'))
2772 'extensions\n'))
2773
2773
2774 def helpextcmd(name):
2774 def helpextcmd(name):
2775 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2775 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2776 doc = gettext(mod.__doc__).splitlines()[0]
2776 doc = gettext(mod.__doc__).splitlines()[0]
2777
2777
2778 msg = help.listexts(_("'%s' is provided by the following "
2778 msg = help.listexts(_("'%s' is provided by the following "
2779 "extension:") % cmd, {ext: doc}, indent=4)
2779 "extension:") % cmd, {ext: doc}, indent=4)
2780 ui.write(minirst.format(msg, textwidth))
2780 ui.write(minirst.format(msg, textwidth))
2781 ui.write('\n\n')
2781 ui.write('\n\n')
2782 ui.write(_('use "hg help extensions" for information on enabling '
2782 ui.write(_('use "hg help extensions" for information on enabling '
2783 'extensions\n'))
2783 'extensions\n'))
2784
2784
2785 if name and name != 'shortlist':
2785 if name and name != 'shortlist':
2786 i = None
2786 i = None
2787 if unknowncmd:
2787 if unknowncmd:
2788 queries = (helpextcmd,)
2788 queries = (helpextcmd,)
2789 elif opts.get('extension'):
2789 elif opts.get('extension'):
2790 queries = (helpext,)
2790 queries = (helpext,)
2791 elif opts.get('command'):
2791 elif opts.get('command'):
2792 queries = (helpcmd,)
2792 queries = (helpcmd,)
2793 else:
2793 else:
2794 queries = (helptopic, helpcmd, helpext, helpextcmd)
2794 queries = (helptopic, helpcmd, helpext, helpextcmd)
2795 for f in queries:
2795 for f in queries:
2796 try:
2796 try:
2797 f(name)
2797 f(name)
2798 i = None
2798 i = None
2799 break
2799 break
2800 except error.UnknownCommand, inst:
2800 except error.UnknownCommand, inst:
2801 i = inst
2801 i = inst
2802 if i:
2802 if i:
2803 raise i
2803 raise i
2804
2804
2805 else:
2805 else:
2806 # program name
2806 # program name
2807 if ui.verbose or with_version:
2807 if ui.verbose or with_version:
2808 version_(ui)
2808 version_(ui)
2809 else:
2809 else:
2810 ui.status(_("Mercurial Distributed SCM\n"))
2810 ui.status(_("Mercurial Distributed SCM\n"))
2811 ui.status('\n')
2811 ui.status('\n')
2812
2812
2813 # list of commands
2813 # list of commands
2814 if name == "shortlist":
2814 if name == "shortlist":
2815 header = _('basic commands:\n\n')
2815 header = _('basic commands:\n\n')
2816 else:
2816 else:
2817 header = _('list of commands:\n\n')
2817 header = _('list of commands:\n\n')
2818
2818
2819 helplist(header)
2819 helplist(header)
2820 if name != 'shortlist':
2820 if name != 'shortlist':
2821 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2821 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2822 if text:
2822 if text:
2823 ui.write("\n%s\n" % minirst.format(text, textwidth))
2823 ui.write("\n%s\n" % minirst.format(text, textwidth))
2824
2824
2825 # list all option lists
2825 # list all option lists
2826 opt_output = []
2826 opt_output = []
2827 multioccur = False
2827 multioccur = False
2828 for title, options in option_lists:
2828 for title, options in option_lists:
2829 opt_output.append(("\n%s" % title, None))
2829 opt_output.append(("\n%s" % title, None))
2830 for option in options:
2830 for option in options:
2831 if len(option) == 5:
2831 if len(option) == 5:
2832 shortopt, longopt, default, desc, optlabel = option
2832 shortopt, longopt, default, desc, optlabel = option
2833 else:
2833 else:
2834 shortopt, longopt, default, desc = option
2834 shortopt, longopt, default, desc = option
2835 optlabel = _("VALUE") # default label
2835 optlabel = _("VALUE") # default label
2836
2836
2837 if _("DEPRECATED") in desc and not ui.verbose:
2837 if _("DEPRECATED") in desc and not ui.verbose:
2838 continue
2838 continue
2839 if isinstance(default, list):
2839 if isinstance(default, list):
2840 numqualifier = " %s [+]" % optlabel
2840 numqualifier = " %s [+]" % optlabel
2841 multioccur = True
2841 multioccur = True
2842 elif (default is not None) and not isinstance(default, bool):
2842 elif (default is not None) and not isinstance(default, bool):
2843 numqualifier = " %s" % optlabel
2843 numqualifier = " %s" % optlabel
2844 else:
2844 else:
2845 numqualifier = ""
2845 numqualifier = ""
2846 opt_output.append(("%2s%s" %
2846 opt_output.append(("%2s%s" %
2847 (shortopt and "-%s" % shortopt,
2847 (shortopt and "-%s" % shortopt,
2848 longopt and " --%s%s" %
2848 longopt and " --%s%s" %
2849 (longopt, numqualifier)),
2849 (longopt, numqualifier)),
2850 "%s%s" % (desc,
2850 "%s%s" % (desc,
2851 default
2851 default
2852 and _(" (default: %s)") % default
2852 and _(" (default: %s)") % default
2853 or "")))
2853 or "")))
2854 if multioccur:
2854 if multioccur:
2855 msg = _("\n[+] marked option can be specified multiple times")
2855 msg = _("\n[+] marked option can be specified multiple times")
2856 if ui.verbose and name != 'shortlist':
2856 if ui.verbose and name != 'shortlist':
2857 opt_output.append((msg, None))
2857 opt_output.append((msg, None))
2858 else:
2858 else:
2859 opt_output.insert(-1, (msg, None))
2859 opt_output.insert(-1, (msg, None))
2860
2860
2861 if not name:
2861 if not name:
2862 ui.write(_("\nadditional help topics:\n\n"))
2862 ui.write(_("\nadditional help topics:\n\n"))
2863 topics = []
2863 topics = []
2864 for names, header, doc in help.helptable:
2864 for names, header, doc in help.helptable:
2865 topics.append((sorted(names, key=len, reverse=True)[0], header))
2865 topics.append((sorted(names, key=len, reverse=True)[0], header))
2866 topics_len = max([len(s[0]) for s in topics])
2866 topics_len = max([len(s[0]) for s in topics])
2867 for t, desc in topics:
2867 for t, desc in topics:
2868 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2868 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2869
2869
2870 if opt_output:
2870 if opt_output:
2871 colwidth = encoding.colwidth
2871 colwidth = encoding.colwidth
2872 # normalize: (opt or message, desc or None, width of opt)
2872 # normalize: (opt or message, desc or None, width of opt)
2873 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2873 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2874 for opt, desc in opt_output]
2874 for opt, desc in opt_output]
2875 hanging = max([e[2] for e in entries])
2875 hanging = max([e[2] for e in entries])
2876 for opt, desc, width in entries:
2876 for opt, desc, width in entries:
2877 if desc:
2877 if desc:
2878 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2878 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2879 hangindent = ' ' * (hanging + 3)
2879 hangindent = ' ' * (hanging + 3)
2880 ui.write('%s\n' % (util.wrap(desc, textwidth,
2880 ui.write('%s\n' % (util.wrap(desc, textwidth,
2881 initindent=initindent,
2881 initindent=initindent,
2882 hangindent=hangindent)))
2882 hangindent=hangindent)))
2883 else:
2883 else:
2884 ui.write("%s\n" % opt)
2884 ui.write("%s\n" % opt)
2885
2885
2886 @command('identify|id',
2886 @command('identify|id',
2887 [('r', 'rev', '',
2887 [('r', 'rev', '',
2888 _('identify the specified revision'), _('REV')),
2888 _('identify the specified revision'), _('REV')),
2889 ('n', 'num', None, _('show local revision number')),
2889 ('n', 'num', None, _('show local revision number')),
2890 ('i', 'id', None, _('show global revision id')),
2890 ('i', 'id', None, _('show global revision id')),
2891 ('b', 'branch', None, _('show branch')),
2891 ('b', 'branch', None, _('show branch')),
2892 ('t', 'tags', None, _('show tags')),
2892 ('t', 'tags', None, _('show tags')),
2893 ('B', 'bookmarks', None, _('show bookmarks'))],
2893 ('B', 'bookmarks', None, _('show bookmarks'))],
2894 _('[-nibtB] [-r REV] [SOURCE]'))
2894 _('[-nibtB] [-r REV] [SOURCE]'))
2895 def identify(ui, repo, source=None, rev=None,
2895 def identify(ui, repo, source=None, rev=None,
2896 num=None, id=None, branch=None, tags=None, bookmarks=None):
2896 num=None, id=None, branch=None, tags=None, bookmarks=None):
2897 """identify the working copy or specified revision
2897 """identify the working copy or specified revision
2898
2898
2899 Print a summary identifying the repository state at REV using one or
2899 Print a summary identifying the repository state at REV using one or
2900 two parent hash identifiers, followed by a "+" if the working
2900 two parent hash identifiers, followed by a "+" if the working
2901 directory has uncommitted changes, the branch name (if not default),
2901 directory has uncommitted changes, the branch name (if not default),
2902 a list of tags, and a list of bookmarks.
2902 a list of tags, and a list of bookmarks.
2903
2903
2904 When REV is not given, print a summary of the current state of the
2904 When REV is not given, print a summary of the current state of the
2905 repository.
2905 repository.
2906
2906
2907 Specifying a path to a repository root or Mercurial bundle will
2907 Specifying a path to a repository root or Mercurial bundle will
2908 cause lookup to operate on that repository/bundle.
2908 cause lookup to operate on that repository/bundle.
2909
2909
2910 Returns 0 if successful.
2910 Returns 0 if successful.
2911 """
2911 """
2912
2912
2913 if not repo and not source:
2913 if not repo and not source:
2914 raise util.Abort(_("there is no Mercurial repository here "
2914 raise util.Abort(_("there is no Mercurial repository here "
2915 "(.hg not found)"))
2915 "(.hg not found)"))
2916
2916
2917 hexfunc = ui.debugflag and hex or short
2917 hexfunc = ui.debugflag and hex or short
2918 default = not (num or id or branch or tags or bookmarks)
2918 default = not (num or id or branch or tags or bookmarks)
2919 output = []
2919 output = []
2920 revs = []
2920 revs = []
2921
2921
2922 if source:
2922 if source:
2923 source, branches = hg.parseurl(ui.expandpath(source))
2923 source, branches = hg.parseurl(ui.expandpath(source))
2924 repo = hg.peer(ui, {}, source)
2924 repo = hg.peer(ui, {}, source)
2925 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2925 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2926
2926
2927 if not repo.local():
2927 if not repo.local():
2928 if num or branch or tags:
2928 if num or branch or tags:
2929 raise util.Abort(
2929 raise util.Abort(
2930 _("can't query remote revision number, branch, or tags"))
2930 _("can't query remote revision number, branch, or tags"))
2931 if not rev and revs:
2931 if not rev and revs:
2932 rev = revs[0]
2932 rev = revs[0]
2933 if not rev:
2933 if not rev:
2934 rev = "tip"
2934 rev = "tip"
2935
2935
2936 remoterev = repo.lookup(rev)
2936 remoterev = repo.lookup(rev)
2937 if default or id:
2937 if default or id:
2938 output = [hexfunc(remoterev)]
2938 output = [hexfunc(remoterev)]
2939
2939
2940 def getbms():
2940 def getbms():
2941 bms = []
2941 bms = []
2942
2942
2943 if 'bookmarks' in repo.listkeys('namespaces'):
2943 if 'bookmarks' in repo.listkeys('namespaces'):
2944 hexremoterev = hex(remoterev)
2944 hexremoterev = hex(remoterev)
2945 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2945 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2946 if bmr == hexremoterev]
2946 if bmr == hexremoterev]
2947
2947
2948 return bms
2948 return bms
2949
2949
2950 if bookmarks:
2950 if bookmarks:
2951 output.extend(getbms())
2951 output.extend(getbms())
2952 elif default and not ui.quiet:
2952 elif default and not ui.quiet:
2953 # multiple bookmarks for a single parent separated by '/'
2953 # multiple bookmarks for a single parent separated by '/'
2954 bm = '/'.join(getbms())
2954 bm = '/'.join(getbms())
2955 if bm:
2955 if bm:
2956 output.append(bm)
2956 output.append(bm)
2957 else:
2957 else:
2958 if not rev:
2958 if not rev:
2959 ctx = repo[None]
2959 ctx = repo[None]
2960 parents = ctx.parents()
2960 parents = ctx.parents()
2961 changed = ""
2961 changed = ""
2962 if default or id or num:
2962 if default or id or num:
2963 changed = util.any(repo.status()) and "+" or ""
2963 changed = util.any(repo.status()) and "+" or ""
2964 if default or id:
2964 if default or id:
2965 output = ["%s%s" %
2965 output = ["%s%s" %
2966 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2966 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2967 if num:
2967 if num:
2968 output.append("%s%s" %
2968 output.append("%s%s" %
2969 ('+'.join([str(p.rev()) for p in parents]), changed))
2969 ('+'.join([str(p.rev()) for p in parents]), changed))
2970 else:
2970 else:
2971 ctx = scmutil.revsingle(repo, rev)
2971 ctx = scmutil.revsingle(repo, rev)
2972 if default or id:
2972 if default or id:
2973 output = [hexfunc(ctx.node())]
2973 output = [hexfunc(ctx.node())]
2974 if num:
2974 if num:
2975 output.append(str(ctx.rev()))
2975 output.append(str(ctx.rev()))
2976
2976
2977 if default and not ui.quiet:
2977 if default and not ui.quiet:
2978 b = ctx.branch()
2978 b = ctx.branch()
2979 if b != 'default':
2979 if b != 'default':
2980 output.append("(%s)" % b)
2980 output.append("(%s)" % b)
2981
2981
2982 # multiple tags for a single parent separated by '/'
2982 # multiple tags for a single parent separated by '/'
2983 t = '/'.join(ctx.tags())
2983 t = '/'.join(ctx.tags())
2984 if t:
2984 if t:
2985 output.append(t)
2985 output.append(t)
2986
2986
2987 # multiple bookmarks for a single parent separated by '/'
2987 # multiple bookmarks for a single parent separated by '/'
2988 bm = '/'.join(ctx.bookmarks())
2988 bm = '/'.join(ctx.bookmarks())
2989 if bm:
2989 if bm:
2990 output.append(bm)
2990 output.append(bm)
2991 else:
2991 else:
2992 if branch:
2992 if branch:
2993 output.append(ctx.branch())
2993 output.append(ctx.branch())
2994
2994
2995 if tags:
2995 if tags:
2996 output.extend(ctx.tags())
2996 output.extend(ctx.tags())
2997
2997
2998 if bookmarks:
2998 if bookmarks:
2999 output.extend(ctx.bookmarks())
2999 output.extend(ctx.bookmarks())
3000
3000
3001 ui.write("%s\n" % ' '.join(output))
3001 ui.write("%s\n" % ' '.join(output))
3002
3002
3003 @command('import|patch',
3003 @command('import|patch',
3004 [('p', 'strip', 1,
3004 [('p', 'strip', 1,
3005 _('directory strip option for patch. This has the same '
3005 _('directory strip option for patch. This has the same '
3006 'meaning as the corresponding patch option'), _('NUM')),
3006 'meaning as the corresponding patch option'), _('NUM')),
3007 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3007 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3008 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3008 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3009 ('', 'no-commit', None,
3009 ('', 'no-commit', None,
3010 _("don't commit, just update the working directory")),
3010 _("don't commit, just update the working directory")),
3011 ('', 'bypass', None,
3011 ('', 'bypass', None,
3012 _("apply patch without touching the working directory")),
3012 _("apply patch without touching the working directory")),
3013 ('', 'exact', None,
3013 ('', 'exact', None,
3014 _('apply patch to the nodes from which it was generated')),
3014 _('apply patch to the nodes from which it was generated')),
3015 ('', 'import-branch', None,
3015 ('', 'import-branch', None,
3016 _('use any branch information in patch (implied by --exact)'))] +
3016 _('use any branch information in patch (implied by --exact)'))] +
3017 commitopts + commitopts2 + similarityopts,
3017 commitopts + commitopts2 + similarityopts,
3018 _('[OPTION]... PATCH...'))
3018 _('[OPTION]... PATCH...'))
3019 def import_(ui, repo, patch1, *patches, **opts):
3019 def import_(ui, repo, patch1, *patches, **opts):
3020 """import an ordered set of patches
3020 """import an ordered set of patches
3021
3021
3022 Import a list of patches and commit them individually (unless
3022 Import a list of patches and commit them individually (unless
3023 --no-commit is specified).
3023 --no-commit is specified).
3024
3024
3025 If there are outstanding changes in the working directory, import
3025 If there are outstanding changes in the working directory, import
3026 will abort unless given the -f/--force flag.
3026 will abort unless given the -f/--force flag.
3027
3027
3028 You can import a patch straight from a mail message. Even patches
3028 You can import a patch straight from a mail message. Even patches
3029 as attachments work (to use the body part, it must have type
3029 as attachments work (to use the body part, it must have type
3030 text/plain or text/x-patch). From and Subject headers of email
3030 text/plain or text/x-patch). From and Subject headers of email
3031 message are used as default committer and commit message. All
3031 message are used as default committer and commit message. All
3032 text/plain body parts before first diff are added to commit
3032 text/plain body parts before first diff are added to commit
3033 message.
3033 message.
3034
3034
3035 If the imported patch was generated by :hg:`export`, user and
3035 If the imported patch was generated by :hg:`export`, user and
3036 description from patch override values from message headers and
3036 description from patch override values from message headers and
3037 body. Values given on command line with -m/--message and -u/--user
3037 body. Values given on command line with -m/--message and -u/--user
3038 override these.
3038 override these.
3039
3039
3040 If --exact is specified, import will set the working directory to
3040 If --exact is specified, import will set the working directory to
3041 the parent of each patch before applying it, and will abort if the
3041 the parent of each patch before applying it, and will abort if the
3042 resulting changeset has a different ID than the one recorded in
3042 resulting changeset has a different ID than the one recorded in
3043 the patch. This may happen due to character set problems or other
3043 the patch. This may happen due to character set problems or other
3044 deficiencies in the text patch format.
3044 deficiencies in the text patch format.
3045
3045
3046 Use --bypass to apply and commit patches directly to the
3046 Use --bypass to apply and commit patches directly to the
3047 repository, not touching the working directory. Without --exact,
3047 repository, not touching the working directory. Without --exact,
3048 patches will be applied on top of the working directory parent
3048 patches will be applied on top of the working directory parent
3049 revision.
3049 revision.
3050
3050
3051 With -s/--similarity, hg will attempt to discover renames and
3051 With -s/--similarity, hg will attempt to discover renames and
3052 copies in the patch in the same way as 'addremove'.
3052 copies in the patch in the same way as 'addremove'.
3053
3053
3054 To read a patch from standard input, use "-" as the patch name. If
3054 To read a patch from standard input, use "-" as the patch name. If
3055 a URL is specified, the patch will be downloaded from it.
3055 a URL is specified, the patch will be downloaded from it.
3056 See :hg:`help dates` for a list of formats valid for -d/--date.
3056 See :hg:`help dates` for a list of formats valid for -d/--date.
3057
3057
3058 Returns 0 on success.
3058 Returns 0 on success.
3059 """
3059 """
3060 patches = (patch1,) + patches
3060 patches = (patch1,) + patches
3061
3061
3062 date = opts.get('date')
3062 date = opts.get('date')
3063 if date:
3063 if date:
3064 opts['date'] = util.parsedate(date)
3064 opts['date'] = util.parsedate(date)
3065
3065
3066 update = not opts.get('bypass')
3066 update = not opts.get('bypass')
3067 if not update and opts.get('no_commit'):
3067 if not update and opts.get('no_commit'):
3068 raise util.Abort(_('cannot use --no-commit with --bypass'))
3068 raise util.Abort(_('cannot use --no-commit with --bypass'))
3069 try:
3069 try:
3070 sim = float(opts.get('similarity') or 0)
3070 sim = float(opts.get('similarity') or 0)
3071 except ValueError:
3071 except ValueError:
3072 raise util.Abort(_('similarity must be a number'))
3072 raise util.Abort(_('similarity must be a number'))
3073 if sim < 0 or sim > 100:
3073 if sim < 0 or sim > 100:
3074 raise util.Abort(_('similarity must be between 0 and 100'))
3074 raise util.Abort(_('similarity must be between 0 and 100'))
3075 if sim and not update:
3075 if sim and not update:
3076 raise util.Abort(_('cannot use --similarity with --bypass'))
3076 raise util.Abort(_('cannot use --similarity with --bypass'))
3077
3077
3078 if (opts.get('exact') or not opts.get('force')) and update:
3078 if (opts.get('exact') or not opts.get('force')) and update:
3079 cmdutil.bailifchanged(repo)
3079 cmdutil.bailifchanged(repo)
3080
3080
3081 d = opts["base"]
3081 d = opts["base"]
3082 strip = opts["strip"]
3082 strip = opts["strip"]
3083 wlock = lock = None
3083 wlock = lock = None
3084 msgs = []
3084 msgs = []
3085
3085
3086 def checkexact(repo, n, nodeid):
3086 def checkexact(repo, n, nodeid):
3087 if opts.get('exact') and hex(n) != nodeid:
3087 if opts.get('exact') and hex(n) != nodeid:
3088 repo.rollback()
3088 repo.rollback()
3089 raise util.Abort(_('patch is damaged or loses information'))
3089 raise util.Abort(_('patch is damaged or loses information'))
3090
3090
3091 def tryone(ui, hunk, parents):
3091 def tryone(ui, hunk, parents):
3092 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3092 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3093 patch.extract(ui, hunk)
3093 patch.extract(ui, hunk)
3094
3094
3095 if not tmpname:
3095 if not tmpname:
3096 return None
3096 return None
3097 commitid = _('to working directory')
3097 commitid = _('to working directory')
3098
3098
3099 try:
3099 try:
3100 cmdline_message = cmdutil.logmessage(ui, opts)
3100 cmdline_message = cmdutil.logmessage(ui, opts)
3101 if cmdline_message:
3101 if cmdline_message:
3102 # pickup the cmdline msg
3102 # pickup the cmdline msg
3103 message = cmdline_message
3103 message = cmdline_message
3104 elif message:
3104 elif message:
3105 # pickup the patch msg
3105 # pickup the patch msg
3106 message = message.strip()
3106 message = message.strip()
3107 else:
3107 else:
3108 # launch the editor
3108 # launch the editor
3109 message = None
3109 message = None
3110 ui.debug('message:\n%s\n' % message)
3110 ui.debug('message:\n%s\n' % message)
3111
3111
3112 if len(parents) == 1:
3112 if len(parents) == 1:
3113 parents.append(repo[nullid])
3113 parents.append(repo[nullid])
3114 if opts.get('exact'):
3114 if opts.get('exact'):
3115 if not nodeid or not p1:
3115 if not nodeid or not p1:
3116 raise util.Abort(_('not a Mercurial patch'))
3116 raise util.Abort(_('not a Mercurial patch'))
3117 p1 = repo[p1]
3117 p1 = repo[p1]
3118 p2 = repo[p2 or nullid]
3118 p2 = repo[p2 or nullid]
3119 elif p2:
3119 elif p2:
3120 try:
3120 try:
3121 p1 = repo[p1]
3121 p1 = repo[p1]
3122 p2 = repo[p2]
3122 p2 = repo[p2]
3123 except error.RepoError:
3123 except error.RepoError:
3124 p1, p2 = parents
3124 p1, p2 = parents
3125 else:
3125 else:
3126 p1, p2 = parents
3126 p1, p2 = parents
3127
3127
3128 n = None
3128 n = None
3129 if update:
3129 if update:
3130 if opts.get('exact') and p1 != parents[0]:
3130 if opts.get('exact') and p1 != parents[0]:
3131 hg.clean(repo, p1.node())
3131 hg.clean(repo, p1.node())
3132 if p1 != parents[0] and p2 != parents[1]:
3132 if p1 != parents[0] and p2 != parents[1]:
3133 repo.dirstate.setparents(p1.node(), p2.node())
3133 repo.dirstate.setparents(p1.node(), p2.node())
3134
3134
3135 if opts.get('exact') or opts.get('import_branch'):
3135 if opts.get('exact') or opts.get('import_branch'):
3136 repo.dirstate.setbranch(branch or 'default')
3136 repo.dirstate.setbranch(branch or 'default')
3137
3137
3138 files = set()
3138 files = set()
3139 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3139 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3140 eolmode=None, similarity=sim / 100.0)
3140 eolmode=None, similarity=sim / 100.0)
3141 files = list(files)
3141 files = list(files)
3142 if opts.get('no_commit'):
3142 if opts.get('no_commit'):
3143 if message:
3143 if message:
3144 msgs.append(message)
3144 msgs.append(message)
3145 else:
3145 else:
3146 if opts.get('exact'):
3146 if opts.get('exact'):
3147 m = None
3147 m = None
3148 else:
3148 else:
3149 m = scmutil.matchfiles(repo, files or [])
3149 m = scmutil.matchfiles(repo, files or [])
3150 n = repo.commit(message, opts.get('user') or user,
3150 n = repo.commit(message, opts.get('user') or user,
3151 opts.get('date') or date, match=m,
3151 opts.get('date') or date, match=m,
3152 editor=cmdutil.commiteditor)
3152 editor=cmdutil.commiteditor)
3153 checkexact(repo, n, nodeid)
3153 checkexact(repo, n, nodeid)
3154 # Force a dirstate write so that the next transaction
3154 # Force a dirstate write so that the next transaction
3155 # backups an up-to-date file.
3155 # backups an up-to-date file.
3156 repo.dirstate.write()
3156 repo.dirstate.write()
3157 else:
3157 else:
3158 if opts.get('exact') or opts.get('import_branch'):
3158 if opts.get('exact') or opts.get('import_branch'):
3159 branch = branch or 'default'
3159 branch = branch or 'default'
3160 else:
3160 else:
3161 branch = p1.branch()
3161 branch = p1.branch()
3162 store = patch.filestore()
3162 store = patch.filestore()
3163 try:
3163 try:
3164 files = set()
3164 files = set()
3165 try:
3165 try:
3166 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3166 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3167 files, eolmode=None)
3167 files, eolmode=None)
3168 except patch.PatchError, e:
3168 except patch.PatchError, e:
3169 raise util.Abort(str(e))
3169 raise util.Abort(str(e))
3170 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3170 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3171 message,
3171 message,
3172 opts.get('user') or user,
3172 opts.get('user') or user,
3173 opts.get('date') or date,
3173 opts.get('date') or date,
3174 branch, files, store,
3174 branch, files, store,
3175 editor=cmdutil.commiteditor)
3175 editor=cmdutil.commiteditor)
3176 repo.savecommitmessage(memctx.description())
3176 repo.savecommitmessage(memctx.description())
3177 n = memctx.commit()
3177 n = memctx.commit()
3178 checkexact(repo, n, nodeid)
3178 checkexact(repo, n, nodeid)
3179 finally:
3179 finally:
3180 store.close()
3180 store.close()
3181 if n:
3181 if n:
3182 commitid = short(n)
3182 commitid = short(n)
3183 return commitid
3183 return commitid
3184 finally:
3184 finally:
3185 os.unlink(tmpname)
3185 os.unlink(tmpname)
3186
3186
3187 try:
3187 try:
3188 wlock = repo.wlock()
3188 wlock = repo.wlock()
3189 lock = repo.lock()
3189 lock = repo.lock()
3190 parents = repo.parents()
3190 parents = repo.parents()
3191 lastcommit = None
3191 lastcommit = None
3192 for p in patches:
3192 for p in patches:
3193 pf = os.path.join(d, p)
3193 pf = os.path.join(d, p)
3194
3194
3195 if pf == '-':
3195 if pf == '-':
3196 ui.status(_("applying patch from stdin\n"))
3196 ui.status(_("applying patch from stdin\n"))
3197 pf = ui.fin
3197 pf = ui.fin
3198 else:
3198 else:
3199 ui.status(_("applying %s\n") % p)
3199 ui.status(_("applying %s\n") % p)
3200 pf = url.open(ui, pf)
3200 pf = url.open(ui, pf)
3201
3201
3202 haspatch = False
3202 haspatch = False
3203 for hunk in patch.split(pf):
3203 for hunk in patch.split(pf):
3204 commitid = tryone(ui, hunk, parents)
3204 commitid = tryone(ui, hunk, parents)
3205 if commitid:
3205 if commitid:
3206 haspatch = True
3206 haspatch = True
3207 if lastcommit:
3207 if lastcommit:
3208 ui.status(_('applied %s\n') % lastcommit)
3208 ui.status(_('applied %s\n') % lastcommit)
3209 lastcommit = commitid
3209 lastcommit = commitid
3210 if update or opts.get('exact'):
3210 if update or opts.get('exact'):
3211 parents = repo.parents()
3211 parents = repo.parents()
3212 else:
3212 else:
3213 parents = [repo[commitid]]
3213 parents = [repo[commitid]]
3214
3214
3215 if not haspatch:
3215 if not haspatch:
3216 raise util.Abort(_('no diffs found'))
3216 raise util.Abort(_('no diffs found'))
3217
3217
3218 if msgs:
3218 if msgs:
3219 repo.savecommitmessage('\n* * *\n'.join(msgs))
3219 repo.savecommitmessage('\n* * *\n'.join(msgs))
3220 finally:
3220 finally:
3221 release(lock, wlock)
3221 release(lock, wlock)
3222
3222
3223 @command('incoming|in',
3223 @command('incoming|in',
3224 [('f', 'force', None,
3224 [('f', 'force', None,
3225 _('run even if remote repository is unrelated')),
3225 _('run even if remote repository is unrelated')),
3226 ('n', 'newest-first', None, _('show newest record first')),
3226 ('n', 'newest-first', None, _('show newest record first')),
3227 ('', 'bundle', '',
3227 ('', 'bundle', '',
3228 _('file to store the bundles into'), _('FILE')),
3228 _('file to store the bundles into'), _('FILE')),
3229 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3229 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3230 ('B', 'bookmarks', False, _("compare bookmarks")),
3230 ('B', 'bookmarks', False, _("compare bookmarks")),
3231 ('b', 'branch', [],
3231 ('b', 'branch', [],
3232 _('a specific branch you would like to pull'), _('BRANCH')),
3232 _('a specific branch you would like to pull'), _('BRANCH')),
3233 ] + logopts + remoteopts + subrepoopts,
3233 ] + logopts + remoteopts + subrepoopts,
3234 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3234 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3235 def incoming(ui, repo, source="default", **opts):
3235 def incoming(ui, repo, source="default", **opts):
3236 """show new changesets found in source
3236 """show new changesets found in source
3237
3237
3238 Show new changesets found in the specified path/URL or the default
3238 Show new changesets found in the specified path/URL or the default
3239 pull location. These are the changesets that would have been pulled
3239 pull location. These are the changesets that would have been pulled
3240 if a pull at the time you issued this command.
3240 if a pull at the time you issued this command.
3241
3241
3242 For remote repository, using --bundle avoids downloading the
3242 For remote repository, using --bundle avoids downloading the
3243 changesets twice if the incoming is followed by a pull.
3243 changesets twice if the incoming is followed by a pull.
3244
3244
3245 See pull for valid source format details.
3245 See pull for valid source format details.
3246
3246
3247 Returns 0 if there are incoming changes, 1 otherwise.
3247 Returns 0 if there are incoming changes, 1 otherwise.
3248 """
3248 """
3249 if opts.get('bundle') and opts.get('subrepos'):
3249 if opts.get('bundle') and opts.get('subrepos'):
3250 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3250 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3251
3251
3252 if opts.get('bookmarks'):
3252 if opts.get('bookmarks'):
3253 source, branches = hg.parseurl(ui.expandpath(source),
3253 source, branches = hg.parseurl(ui.expandpath(source),
3254 opts.get('branch'))
3254 opts.get('branch'))
3255 other = hg.peer(repo, opts, source)
3255 other = hg.peer(repo, opts, source)
3256 if 'bookmarks' not in other.listkeys('namespaces'):
3256 if 'bookmarks' not in other.listkeys('namespaces'):
3257 ui.warn(_("remote doesn't support bookmarks\n"))
3257 ui.warn(_("remote doesn't support bookmarks\n"))
3258 return 0
3258 return 0
3259 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3259 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3260 return bookmarks.diff(ui, repo, other)
3260 return bookmarks.diff(ui, repo, other)
3261
3261
3262 repo._subtoppath = ui.expandpath(source)
3262 repo._subtoppath = ui.expandpath(source)
3263 try:
3263 try:
3264 return hg.incoming(ui, repo, source, opts)
3264 return hg.incoming(ui, repo, source, opts)
3265 finally:
3265 finally:
3266 del repo._subtoppath
3266 del repo._subtoppath
3267
3267
3268
3268
3269 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3269 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3270 def init(ui, dest=".", **opts):
3270 def init(ui, dest=".", **opts):
3271 """create a new repository in the given directory
3271 """create a new repository in the given directory
3272
3272
3273 Initialize a new repository in the given directory. If the given
3273 Initialize a new repository in the given directory. If the given
3274 directory does not exist, it will be created.
3274 directory does not exist, it will be created.
3275
3275
3276 If no directory is given, the current directory is used.
3276 If no directory is given, the current directory is used.
3277
3277
3278 It is possible to specify an ``ssh://`` URL as the destination.
3278 It is possible to specify an ``ssh://`` URL as the destination.
3279 See :hg:`help urls` for more information.
3279 See :hg:`help urls` for more information.
3280
3280
3281 Returns 0 on success.
3281 Returns 0 on success.
3282 """
3282 """
3283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3284
3284
3285 @command('locate',
3285 @command('locate',
3286 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3286 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3287 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3287 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3288 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3288 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3289 ] + walkopts,
3289 ] + walkopts,
3290 _('[OPTION]... [PATTERN]...'))
3290 _('[OPTION]... [PATTERN]...'))
3291 def locate(ui, repo, *pats, **opts):
3291 def locate(ui, repo, *pats, **opts):
3292 """locate files matching specific patterns
3292 """locate files matching specific patterns
3293
3293
3294 Print files under Mercurial control in the working directory whose
3294 Print files under Mercurial control in the working directory whose
3295 names match the given patterns.
3295 names match the given patterns.
3296
3296
3297 By default, this command searches all directories in the working
3297 By default, this command searches all directories in the working
3298 directory. To search just the current directory and its
3298 directory. To search just the current directory and its
3299 subdirectories, use "--include .".
3299 subdirectories, use "--include .".
3300
3300
3301 If no patterns are given to match, this command prints the names
3301 If no patterns are given to match, this command prints the names
3302 of all files under Mercurial control in the working directory.
3302 of all files under Mercurial control in the working directory.
3303
3303
3304 If you want to feed the output of this command into the "xargs"
3304 If you want to feed the output of this command into the "xargs"
3305 command, use the -0 option to both this command and "xargs". This
3305 command, use the -0 option to both this command and "xargs". This
3306 will avoid the problem of "xargs" treating single filenames that
3306 will avoid the problem of "xargs" treating single filenames that
3307 contain whitespace as multiple filenames.
3307 contain whitespace as multiple filenames.
3308
3308
3309 Returns 0 if a match is found, 1 otherwise.
3309 Returns 0 if a match is found, 1 otherwise.
3310 """
3310 """
3311 end = opts.get('print0') and '\0' or '\n'
3311 end = opts.get('print0') and '\0' or '\n'
3312 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3312 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3313
3313
3314 ret = 1
3314 ret = 1
3315 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3315 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3316 m.bad = lambda x, y: False
3316 m.bad = lambda x, y: False
3317 for abs in repo[rev].walk(m):
3317 for abs in repo[rev].walk(m):
3318 if not rev and abs not in repo.dirstate:
3318 if not rev and abs not in repo.dirstate:
3319 continue
3319 continue
3320 if opts.get('fullpath'):
3320 if opts.get('fullpath'):
3321 ui.write(repo.wjoin(abs), end)
3321 ui.write(repo.wjoin(abs), end)
3322 else:
3322 else:
3323 ui.write(((pats and m.rel(abs)) or abs), end)
3323 ui.write(((pats and m.rel(abs)) or abs), end)
3324 ret = 0
3324 ret = 0
3325
3325
3326 return ret
3326 return ret
3327
3327
3328 @command('^log|history',
3328 @command('^log|history',
3329 [('f', 'follow', None,
3329 [('f', 'follow', None,
3330 _('follow changeset history, or file history across copies and renames')),
3330 _('follow changeset history, or file history across copies and renames')),
3331 ('', 'follow-first', None,
3331 ('', 'follow-first', None,
3332 _('only follow the first parent of merge changesets')),
3332 _('only follow the first parent of merge changesets')),
3333 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3333 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3334 ('C', 'copies', None, _('show copied files')),
3334 ('C', 'copies', None, _('show copied files')),
3335 ('k', 'keyword', [],
3335 ('k', 'keyword', [],
3336 _('do case-insensitive search for a given text'), _('TEXT')),
3336 _('do case-insensitive search for a given text'), _('TEXT')),
3337 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3337 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3338 ('', 'removed', None, _('include revisions where files were removed')),
3338 ('', 'removed', None, _('include revisions where files were removed')),
3339 ('m', 'only-merges', None, _('show only merges')),
3339 ('m', 'only-merges', None, _('show only merges')),
3340 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3340 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3341 ('', 'only-branch', [],
3341 ('', 'only-branch', [],
3342 _('show only changesets within the given named branch (DEPRECATED)'),
3342 _('show only changesets within the given named branch (DEPRECATED)'),
3343 _('BRANCH')),
3343 _('BRANCH')),
3344 ('b', 'branch', [],
3344 ('b', 'branch', [],
3345 _('show changesets within the given named branch'), _('BRANCH')),
3345 _('show changesets within the given named branch'), _('BRANCH')),
3346 ('P', 'prune', [],
3346 ('P', 'prune', [],
3347 _('do not display revision or any of its ancestors'), _('REV')),
3347 _('do not display revision or any of its ancestors'), _('REV')),
3348 ('h', 'hidden', False, _('show hidden changesets')),
3348 ('h', 'hidden', False, _('show hidden changesets')),
3349 ] + logopts + walkopts,
3349 ] + logopts + walkopts,
3350 _('[OPTION]... [FILE]'))
3350 _('[OPTION]... [FILE]'))
3351 def log(ui, repo, *pats, **opts):
3351 def log(ui, repo, *pats, **opts):
3352 """show revision history of entire repository or files
3352 """show revision history of entire repository or files
3353
3353
3354 Print the revision history of the specified files or the entire
3354 Print the revision history of the specified files or the entire
3355 project.
3355 project.
3356
3356
3357 File history is shown without following rename or copy history of
3357 File history is shown without following rename or copy history of
3358 files. Use -f/--follow with a filename to follow history across
3358 files. Use -f/--follow with a filename to follow history across
3359 renames and copies. --follow without a filename will only show
3359 renames and copies. --follow without a filename will only show
3360 ancestors or descendants of the starting revision. --follow-first
3360 ancestors or descendants of the starting revision. --follow-first
3361 only follows the first parent of merge revisions.
3361 only follows the first parent of merge revisions.
3362
3362
3363 If no revision range is specified, the default is ``tip:0`` unless
3363 If no revision range is specified, the default is ``tip:0`` unless
3364 --follow is set, in which case the working directory parent is
3364 --follow is set, in which case the working directory parent is
3365 used as the starting revision. You can specify a revision set for
3365 used as the starting revision. You can specify a revision set for
3366 log, see :hg:`help revsets` for more information.
3366 log, see :hg:`help revsets` for more information.
3367
3367
3368 See :hg:`help dates` for a list of formats valid for -d/--date.
3368 See :hg:`help dates` for a list of formats valid for -d/--date.
3369
3369
3370 By default this command prints revision number and changeset id,
3370 By default this command prints revision number and changeset id,
3371 tags, non-trivial parents, user, date and time, and a summary for
3371 tags, non-trivial parents, user, date and time, and a summary for
3372 each commit. When the -v/--verbose switch is used, the list of
3372 each commit. When the -v/--verbose switch is used, the list of
3373 changed files and full commit message are shown.
3373 changed files and full commit message are shown.
3374
3374
3375 .. note::
3375 .. note::
3376 log -p/--patch may generate unexpected diff output for merge
3376 log -p/--patch may generate unexpected diff output for merge
3377 changesets, as it will only compare the merge changeset against
3377 changesets, as it will only compare the merge changeset against
3378 its first parent. Also, only files different from BOTH parents
3378 its first parent. Also, only files different from BOTH parents
3379 will appear in files:.
3379 will appear in files:.
3380
3380
3381 Returns 0 on success.
3381 Returns 0 on success.
3382 """
3382 """
3383
3383
3384 matchfn = scmutil.match(repo[None], pats, opts)
3384 matchfn = scmutil.match(repo[None], pats, opts)
3385 limit = cmdutil.loglimit(opts)
3385 limit = cmdutil.loglimit(opts)
3386 count = 0
3386 count = 0
3387
3387
3388 endrev = None
3388 endrev = None
3389 if opts.get('copies') and opts.get('rev'):
3389 if opts.get('copies') and opts.get('rev'):
3390 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3390 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3391
3391
3392 df = False
3392 df = False
3393 if opts["date"]:
3393 if opts["date"]:
3394 df = util.matchdate(opts["date"])
3394 df = util.matchdate(opts["date"])
3395
3395
3396 branches = opts.get('branch', []) + opts.get('only_branch', [])
3396 branches = opts.get('branch', []) + opts.get('only_branch', [])
3397 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3397 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3398
3398
3399 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3399 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3400 def prep(ctx, fns):
3400 def prep(ctx, fns):
3401 rev = ctx.rev()
3401 rev = ctx.rev()
3402 parents = [p for p in repo.changelog.parentrevs(rev)
3402 parents = [p for p in repo.changelog.parentrevs(rev)
3403 if p != nullrev]
3403 if p != nullrev]
3404 if opts.get('no_merges') and len(parents) == 2:
3404 if opts.get('no_merges') and len(parents) == 2:
3405 return
3405 return
3406 if opts.get('only_merges') and len(parents) != 2:
3406 if opts.get('only_merges') and len(parents) != 2:
3407 return
3407 return
3408 if opts.get('branch') and ctx.branch() not in opts['branch']:
3408 if opts.get('branch') and ctx.branch() not in opts['branch']:
3409 return
3409 return
3410 if not opts.get('hidden') and ctx.hidden():
3410 if not opts.get('hidden') and ctx.hidden():
3411 return
3411 return
3412 if df and not df(ctx.date()[0]):
3412 if df and not df(ctx.date()[0]):
3413 return
3413 return
3414 if opts['user'] and not [k for k in opts['user']
3414 if opts['user'] and not [k for k in opts['user']
3415 if k.lower() in ctx.user().lower()]:
3415 if k.lower() in ctx.user().lower()]:
3416 return
3416 return
3417 if opts.get('keyword'):
3417 if opts.get('keyword'):
3418 for k in [kw.lower() for kw in opts['keyword']]:
3418 for k in [kw.lower() for kw in opts['keyword']]:
3419 if (k in ctx.user().lower() or
3419 if (k in ctx.user().lower() or
3420 k in ctx.description().lower() or
3420 k in ctx.description().lower() or
3421 k in " ".join(ctx.files()).lower()):
3421 k in " ".join(ctx.files()).lower()):
3422 break
3422 break
3423 else:
3423 else:
3424 return
3424 return
3425
3425
3426 copies = None
3426 copies = None
3427 if opts.get('copies') and rev:
3427 if opts.get('copies') and rev:
3428 copies = []
3428 copies = []
3429 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3429 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3430 for fn in ctx.files():
3430 for fn in ctx.files():
3431 rename = getrenamed(fn, rev)
3431 rename = getrenamed(fn, rev)
3432 if rename:
3432 if rename:
3433 copies.append((fn, rename[0]))
3433 copies.append((fn, rename[0]))
3434
3434
3435 revmatchfn = None
3435 revmatchfn = None
3436 if opts.get('patch') or opts.get('stat'):
3436 if opts.get('patch') or opts.get('stat'):
3437 if opts.get('follow') or opts.get('follow_first'):
3437 if opts.get('follow') or opts.get('follow_first'):
3438 # note: this might be wrong when following through merges
3438 # note: this might be wrong when following through merges
3439 revmatchfn = scmutil.match(repo[None], fns, default='path')
3439 revmatchfn = scmutil.match(repo[None], fns, default='path')
3440 else:
3440 else:
3441 revmatchfn = matchfn
3441 revmatchfn = matchfn
3442
3442
3443 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3443 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3444
3444
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3446 if count == limit:
3446 if count == limit:
3447 break
3447 break
3448 if displayer.flush(ctx.rev()):
3448 if displayer.flush(ctx.rev()):
3449 count += 1
3449 count += 1
3450 displayer.close()
3450 displayer.close()
3451
3451
3452 @command('manifest',
3452 @command('manifest',
3453 [('r', 'rev', '', _('revision to display'), _('REV')),
3453 [('r', 'rev', '', _('revision to display'), _('REV')),
3454 ('', 'all', False, _("list files from all revisions"))],
3454 ('', 'all', False, _("list files from all revisions"))],
3455 _('[-r REV]'))
3455 _('[-r REV]'))
3456 def manifest(ui, repo, node=None, rev=None, **opts):
3456 def manifest(ui, repo, node=None, rev=None, **opts):
3457 """output the current or given revision of the project manifest
3457 """output the current or given revision of the project manifest
3458
3458
3459 Print a list of version controlled files for the given revision.
3459 Print a list of version controlled files for the given revision.
3460 If no revision is given, the first parent of the working directory
3460 If no revision is given, the first parent of the working directory
3461 is used, or the null revision if no revision is checked out.
3461 is used, or the null revision if no revision is checked out.
3462
3462
3463 With -v, print file permissions, symlink and executable bits.
3463 With -v, print file permissions, symlink and executable bits.
3464 With --debug, print file revision hashes.
3464 With --debug, print file revision hashes.
3465
3465
3466 If option --all is specified, the list of all files from all revisions
3466 If option --all is specified, the list of all files from all revisions
3467 is printed. This includes deleted and renamed files.
3467 is printed. This includes deleted and renamed files.
3468
3468
3469 Returns 0 on success.
3469 Returns 0 on success.
3470 """
3470 """
3471 if opts.get('all'):
3471 if opts.get('all'):
3472 if rev or node:
3472 if rev or node:
3473 raise util.Abort(_("can't specify a revision with --all"))
3473 raise util.Abort(_("can't specify a revision with --all"))
3474
3474
3475 res = []
3475 res = []
3476 prefix = "data/"
3476 prefix = "data/"
3477 suffix = ".i"
3477 suffix = ".i"
3478 plen = len(prefix)
3478 plen = len(prefix)
3479 slen = len(suffix)
3479 slen = len(suffix)
3480 lock = repo.lock()
3480 lock = repo.lock()
3481 try:
3481 try:
3482 for fn, b, size in repo.store.datafiles():
3482 for fn, b, size in repo.store.datafiles():
3483 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3483 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3484 res.append(fn[plen:-slen])
3484 res.append(fn[plen:-slen])
3485 finally:
3485 finally:
3486 lock.release()
3486 lock.release()
3487 for f in sorted(res):
3487 for f in sorted(res):
3488 ui.write("%s\n" % f)
3488 ui.write("%s\n" % f)
3489 return
3489 return
3490
3490
3491 if rev and node:
3491 if rev and node:
3492 raise util.Abort(_("please specify just one revision"))
3492 raise util.Abort(_("please specify just one revision"))
3493
3493
3494 if not node:
3494 if not node:
3495 node = rev
3495 node = rev
3496
3496
3497 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3497 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3498 ctx = scmutil.revsingle(repo, node)
3498 ctx = scmutil.revsingle(repo, node)
3499 for f in ctx:
3499 for f in ctx:
3500 if ui.debugflag:
3500 if ui.debugflag:
3501 ui.write("%40s " % hex(ctx.manifest()[f]))
3501 ui.write("%40s " % hex(ctx.manifest()[f]))
3502 if ui.verbose:
3502 if ui.verbose:
3503 ui.write(decor[ctx.flags(f)])
3503 ui.write(decor[ctx.flags(f)])
3504 ui.write("%s\n" % f)
3504 ui.write("%s\n" % f)
3505
3505
3506 @command('^merge',
3506 @command('^merge',
3507 [('f', 'force', None, _('force a merge with outstanding changes')),
3507 [('f', 'force', None, _('force a merge with outstanding changes')),
3508 ('t', 'tool', '', _('specify merge tool')),
3508 ('t', 'tool', '', _('specify merge tool')),
3509 ('r', 'rev', '', _('revision to merge'), _('REV')),
3509 ('r', 'rev', '', _('revision to merge'), _('REV')),
3510 ('P', 'preview', None,
3510 ('P', 'preview', None,
3511 _('review revisions to merge (no merge is performed)'))],
3511 _('review revisions to merge (no merge is performed)'))],
3512 _('[-P] [-f] [[-r] REV]'))
3512 _('[-P] [-f] [[-r] REV]'))
3513 def merge(ui, repo, node=None, **opts):
3513 def merge(ui, repo, node=None, **opts):
3514 """merge working directory with another revision
3514 """merge working directory with another revision
3515
3515
3516 The current working directory is updated with all changes made in
3516 The current working directory is updated with all changes made in
3517 the requested revision since the last common predecessor revision.
3517 the requested revision since the last common predecessor revision.
3518
3518
3519 Files that changed between either parent are marked as changed for
3519 Files that changed between either parent are marked as changed for
3520 the next commit and a commit must be performed before any further
3520 the next commit and a commit must be performed before any further
3521 updates to the repository are allowed. The next commit will have
3521 updates to the repository are allowed. The next commit will have
3522 two parents.
3522 two parents.
3523
3523
3524 ``--tool`` can be used to specify the merge tool used for file
3524 ``--tool`` can be used to specify the merge tool used for file
3525 merges. It overrides the HGMERGE environment variable and your
3525 merges. It overrides the HGMERGE environment variable and your
3526 configuration files. See :hg:`help merge-tools` for options.
3526 configuration files. See :hg:`help merge-tools` for options.
3527
3527
3528 If no revision is specified, the working directory's parent is a
3528 If no revision is specified, the working directory's parent is a
3529 head revision, and the current branch contains exactly one other
3529 head revision, and the current branch contains exactly one other
3530 head, the other head is merged with by default. Otherwise, an
3530 head, the other head is merged with by default. Otherwise, an
3531 explicit revision with which to merge with must be provided.
3531 explicit revision with which to merge with must be provided.
3532
3532
3533 :hg:`resolve` must be used to resolve unresolved files.
3533 :hg:`resolve` must be used to resolve unresolved files.
3534
3534
3535 To undo an uncommitted merge, use :hg:`update --clean .` which
3535 To undo an uncommitted merge, use :hg:`update --clean .` which
3536 will check out a clean copy of the original merge parent, losing
3536 will check out a clean copy of the original merge parent, losing
3537 all changes.
3537 all changes.
3538
3538
3539 Returns 0 on success, 1 if there are unresolved files.
3539 Returns 0 on success, 1 if there are unresolved files.
3540 """
3540 """
3541
3541
3542 if opts.get('rev') and node:
3542 if opts.get('rev') and node:
3543 raise util.Abort(_("please specify just one revision"))
3543 raise util.Abort(_("please specify just one revision"))
3544 if not node:
3544 if not node:
3545 node = opts.get('rev')
3545 node = opts.get('rev')
3546
3546
3547 if not node:
3547 if not node:
3548 branch = repo[None].branch()
3548 branch = repo[None].branch()
3549 bheads = repo.branchheads(branch)
3549 bheads = repo.branchheads(branch)
3550 if len(bheads) > 2:
3550 if len(bheads) > 2:
3551 raise util.Abort(_("branch '%s' has %d heads - "
3551 raise util.Abort(_("branch '%s' has %d heads - "
3552 "please merge with an explicit rev")
3552 "please merge with an explicit rev")
3553 % (branch, len(bheads)),
3553 % (branch, len(bheads)),
3554 hint=_("run 'hg heads .' to see heads"))
3554 hint=_("run 'hg heads .' to see heads"))
3555
3555
3556 parent = repo.dirstate.p1()
3556 parent = repo.dirstate.p1()
3557 if len(bheads) == 1:
3557 if len(bheads) == 1:
3558 if len(repo.heads()) > 1:
3558 if len(repo.heads()) > 1:
3559 raise util.Abort(_("branch '%s' has one head - "
3559 raise util.Abort(_("branch '%s' has one head - "
3560 "please merge with an explicit rev")
3560 "please merge with an explicit rev")
3561 % branch,
3561 % branch,
3562 hint=_("run 'hg heads' to see all heads"))
3562 hint=_("run 'hg heads' to see all heads"))
3563 msg = _('there is nothing to merge')
3563 msg = _('there is nothing to merge')
3564 if parent != repo.lookup(repo[None].branch()):
3564 if parent != repo.lookup(repo[None].branch()):
3565 msg = _('%s - use "hg update" instead') % msg
3565 msg = _('%s - use "hg update" instead') % msg
3566 raise util.Abort(msg)
3566 raise util.Abort(msg)
3567
3567
3568 if parent not in bheads:
3568 if parent not in bheads:
3569 raise util.Abort(_('working directory not at a head revision'),
3569 raise util.Abort(_('working directory not at a head revision'),
3570 hint=_("use 'hg update' or merge with an "
3570 hint=_("use 'hg update' or merge with an "
3571 "explicit revision"))
3571 "explicit revision"))
3572 node = parent == bheads[0] and bheads[-1] or bheads[0]
3572 node = parent == bheads[0] and bheads[-1] or bheads[0]
3573 else:
3573 else:
3574 node = scmutil.revsingle(repo, node).node()
3574 node = scmutil.revsingle(repo, node).node()
3575
3575
3576 if opts.get('preview'):
3576 if opts.get('preview'):
3577 # find nodes that are ancestors of p2 but not of p1
3577 # find nodes that are ancestors of p2 but not of p1
3578 p1 = repo.lookup('.')
3578 p1 = repo.lookup('.')
3579 p2 = repo.lookup(node)
3579 p2 = repo.lookup(node)
3580 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3580 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3581
3581
3582 displayer = cmdutil.show_changeset(ui, repo, opts)
3582 displayer = cmdutil.show_changeset(ui, repo, opts)
3583 for node in nodes:
3583 for node in nodes:
3584 displayer.show(repo[node])
3584 displayer.show(repo[node])
3585 displayer.close()
3585 displayer.close()
3586 return 0
3586 return 0
3587
3587
3588 try:
3588 try:
3589 # ui.forcemerge is an internal variable, do not document
3589 # ui.forcemerge is an internal variable, do not document
3590 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3590 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3591 return hg.merge(repo, node, force=opts.get('force'))
3591 return hg.merge(repo, node, force=opts.get('force'))
3592 finally:
3592 finally:
3593 ui.setconfig('ui', 'forcemerge', '')
3593 ui.setconfig('ui', 'forcemerge', '')
3594
3594
3595 @command('outgoing|out',
3595 @command('outgoing|out',
3596 [('f', 'force', None, _('run even when the destination is unrelated')),
3596 [('f', 'force', None, _('run even when the destination is unrelated')),
3597 ('r', 'rev', [],
3597 ('r', 'rev', [],
3598 _('a changeset intended to be included in the destination'), _('REV')),
3598 _('a changeset intended to be included in the destination'), _('REV')),
3599 ('n', 'newest-first', None, _('show newest record first')),
3599 ('n', 'newest-first', None, _('show newest record first')),
3600 ('B', 'bookmarks', False, _('compare bookmarks')),
3600 ('B', 'bookmarks', False, _('compare bookmarks')),
3601 ('b', 'branch', [], _('a specific branch you would like to push'),
3601 ('b', 'branch', [], _('a specific branch you would like to push'),
3602 _('BRANCH')),
3602 _('BRANCH')),
3603 ] + logopts + remoteopts + subrepoopts,
3603 ] + logopts + remoteopts + subrepoopts,
3604 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3604 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3605 def outgoing(ui, repo, dest=None, **opts):
3605 def outgoing(ui, repo, dest=None, **opts):
3606 """show changesets not found in the destination
3606 """show changesets not found in the destination
3607
3607
3608 Show changesets not found in the specified destination repository
3608 Show changesets not found in the specified destination repository
3609 or the default push location. These are the changesets that would
3609 or the default push location. These are the changesets that would
3610 be pushed if a push was requested.
3610 be pushed if a push was requested.
3611
3611
3612 See pull for details of valid destination formats.
3612 See pull for details of valid destination formats.
3613
3613
3614 Returns 0 if there are outgoing changes, 1 otherwise.
3614 Returns 0 if there are outgoing changes, 1 otherwise.
3615 """
3615 """
3616
3616
3617 if opts.get('bookmarks'):
3617 if opts.get('bookmarks'):
3618 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3618 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3619 dest, branches = hg.parseurl(dest, opts.get('branch'))
3619 dest, branches = hg.parseurl(dest, opts.get('branch'))
3620 other = hg.peer(repo, opts, dest)
3620 other = hg.peer(repo, opts, dest)
3621 if 'bookmarks' not in other.listkeys('namespaces'):
3621 if 'bookmarks' not in other.listkeys('namespaces'):
3622 ui.warn(_("remote doesn't support bookmarks\n"))
3622 ui.warn(_("remote doesn't support bookmarks\n"))
3623 return 0
3623 return 0
3624 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3624 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3625 return bookmarks.diff(ui, other, repo)
3625 return bookmarks.diff(ui, other, repo)
3626
3626
3627 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3627 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3628 try:
3628 try:
3629 return hg.outgoing(ui, repo, dest, opts)
3629 return hg.outgoing(ui, repo, dest, opts)
3630 finally:
3630 finally:
3631 del repo._subtoppath
3631 del repo._subtoppath
3632
3632
3633 @command('parents',
3633 @command('parents',
3634 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3634 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3635 ] + templateopts,
3635 ] + templateopts,
3636 _('[-r REV] [FILE]'))
3636 _('[-r REV] [FILE]'))
3637 def parents(ui, repo, file_=None, **opts):
3637 def parents(ui, repo, file_=None, **opts):
3638 """show the parents of the working directory or revision
3638 """show the parents of the working directory or revision
3639
3639
3640 Print the working directory's parent revisions. If a revision is
3640 Print the working directory's parent revisions. If a revision is
3641 given via -r/--rev, the parent of that revision will be printed.
3641 given via -r/--rev, the parent of that revision will be printed.
3642 If a file argument is given, the revision in which the file was
3642 If a file argument is given, the revision in which the file was
3643 last changed (before the working directory revision or the
3643 last changed (before the working directory revision or the
3644 argument to --rev if given) is printed.
3644 argument to --rev if given) is printed.
3645
3645
3646 Returns 0 on success.
3646 Returns 0 on success.
3647 """
3647 """
3648
3648
3649 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3649 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3650
3650
3651 if file_:
3651 if file_:
3652 m = scmutil.match(ctx, (file_,), opts)
3652 m = scmutil.match(ctx, (file_,), opts)
3653 if m.anypats() or len(m.files()) != 1:
3653 if m.anypats() or len(m.files()) != 1:
3654 raise util.Abort(_('can only specify an explicit filename'))
3654 raise util.Abort(_('can only specify an explicit filename'))
3655 file_ = m.files()[0]
3655 file_ = m.files()[0]
3656 filenodes = []
3656 filenodes = []
3657 for cp in ctx.parents():
3657 for cp in ctx.parents():
3658 if not cp:
3658 if not cp:
3659 continue
3659 continue
3660 try:
3660 try:
3661 filenodes.append(cp.filenode(file_))
3661 filenodes.append(cp.filenode(file_))
3662 except error.LookupError:
3662 except error.LookupError:
3663 pass
3663 pass
3664 if not filenodes:
3664 if not filenodes:
3665 raise util.Abort(_("'%s' not found in manifest!") % file_)
3665 raise util.Abort(_("'%s' not found in manifest!") % file_)
3666 fl = repo.file(file_)
3666 fl = repo.file(file_)
3667 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3667 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3668 else:
3668 else:
3669 p = [cp.node() for cp in ctx.parents()]
3669 p = [cp.node() for cp in ctx.parents()]
3670
3670
3671 displayer = cmdutil.show_changeset(ui, repo, opts)
3671 displayer = cmdutil.show_changeset(ui, repo, opts)
3672 for n in p:
3672 for n in p:
3673 if n != nullid:
3673 if n != nullid:
3674 displayer.show(repo[n])
3674 displayer.show(repo[n])
3675 displayer.close()
3675 displayer.close()
3676
3676
3677 @command('paths', [], _('[NAME]'))
3677 @command('paths', [], _('[NAME]'))
3678 def paths(ui, repo, search=None):
3678 def paths(ui, repo, search=None):
3679 """show aliases for remote repositories
3679 """show aliases for remote repositories
3680
3680
3681 Show definition of symbolic path name NAME. If no name is given,
3681 Show definition of symbolic path name NAME. If no name is given,
3682 show definition of all available names.
3682 show definition of all available names.
3683
3683
3684 Option -q/--quiet suppresses all output when searching for NAME
3684 Option -q/--quiet suppresses all output when searching for NAME
3685 and shows only the path names when listing all definitions.
3685 and shows only the path names when listing all definitions.
3686
3686
3687 Path names are defined in the [paths] section of your
3687 Path names are defined in the [paths] section of your
3688 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3688 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3689 repository, ``.hg/hgrc`` is used, too.
3689 repository, ``.hg/hgrc`` is used, too.
3690
3690
3691 The path names ``default`` and ``default-push`` have a special
3691 The path names ``default`` and ``default-push`` have a special
3692 meaning. When performing a push or pull operation, they are used
3692 meaning. When performing a push or pull operation, they are used
3693 as fallbacks if no location is specified on the command-line.
3693 as fallbacks if no location is specified on the command-line.
3694 When ``default-push`` is set, it will be used for push and
3694 When ``default-push`` is set, it will be used for push and
3695 ``default`` will be used for pull; otherwise ``default`` is used
3695 ``default`` will be used for pull; otherwise ``default`` is used
3696 as the fallback for both. When cloning a repository, the clone
3696 as the fallback for both. When cloning a repository, the clone
3697 source is written as ``default`` in ``.hg/hgrc``. Note that
3697 source is written as ``default`` in ``.hg/hgrc``. Note that
3698 ``default`` and ``default-push`` apply to all inbound (e.g.
3698 ``default`` and ``default-push`` apply to all inbound (e.g.
3699 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3699 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3700 :hg:`bundle`) operations.
3700 :hg:`bundle`) operations.
3701
3701
3702 See :hg:`help urls` for more information.
3702 See :hg:`help urls` for more information.
3703
3703
3704 Returns 0 on success.
3704 Returns 0 on success.
3705 """
3705 """
3706 if search:
3706 if search:
3707 for name, path in ui.configitems("paths"):
3707 for name, path in ui.configitems("paths"):
3708 if name == search:
3708 if name == search:
3709 ui.status("%s\n" % util.hidepassword(path))
3709 ui.status("%s\n" % util.hidepassword(path))
3710 return
3710 return
3711 if not ui.quiet:
3711 if not ui.quiet:
3712 ui.warn(_("not found!\n"))
3712 ui.warn(_("not found!\n"))
3713 return 1
3713 return 1
3714 else:
3714 else:
3715 for name, path in ui.configitems("paths"):
3715 for name, path in ui.configitems("paths"):
3716 if ui.quiet:
3716 if ui.quiet:
3717 ui.write("%s\n" % name)
3717 ui.write("%s\n" % name)
3718 else:
3718 else:
3719 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3719 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3720
3720
3721 def postincoming(ui, repo, modheads, optupdate, checkout):
3721 def postincoming(ui, repo, modheads, optupdate, checkout):
3722 if modheads == 0:
3722 if modheads == 0:
3723 return
3723 return
3724 if optupdate:
3724 if optupdate:
3725 try:
3725 try:
3726 return hg.update(repo, checkout)
3726 return hg.update(repo, checkout)
3727 except util.Abort, inst:
3727 except util.Abort, inst:
3728 ui.warn(_("not updating: %s\n" % str(inst)))
3728 ui.warn(_("not updating: %s\n" % str(inst)))
3729 return 0
3729 return 0
3730 if modheads > 1:
3730 if modheads > 1:
3731 currentbranchheads = len(repo.branchheads())
3731 currentbranchheads = len(repo.branchheads())
3732 if currentbranchheads == modheads:
3732 if currentbranchheads == modheads:
3733 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3733 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3734 elif currentbranchheads > 1:
3734 elif currentbranchheads > 1:
3735 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3735 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3736 else:
3736 else:
3737 ui.status(_("(run 'hg heads' to see heads)\n"))
3737 ui.status(_("(run 'hg heads' to see heads)\n"))
3738 else:
3738 else:
3739 ui.status(_("(run 'hg update' to get a working copy)\n"))
3739 ui.status(_("(run 'hg update' to get a working copy)\n"))
3740
3740
3741 @command('^pull',
3741 @command('^pull',
3742 [('u', 'update', None,
3742 [('u', 'update', None,
3743 _('update to new branch head if changesets were pulled')),
3743 _('update to new branch head if changesets were pulled')),
3744 ('f', 'force', None, _('run even when remote repository is unrelated')),
3744 ('f', 'force', None, _('run even when remote repository is unrelated')),
3745 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3745 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3746 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3746 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3747 ('b', 'branch', [], _('a specific branch you would like to pull'),
3747 ('b', 'branch', [], _('a specific branch you would like to pull'),
3748 _('BRANCH')),
3748 _('BRANCH')),
3749 ] + remoteopts,
3749 ] + remoteopts,
3750 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3750 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3751 def pull(ui, repo, source="default", **opts):
3751 def pull(ui, repo, source="default", **opts):
3752 """pull changes from the specified source
3752 """pull changes from the specified source
3753
3753
3754 Pull changes from a remote repository to a local one.
3754 Pull changes from a remote repository to a local one.
3755
3755
3756 This finds all changes from the repository at the specified path
3756 This finds all changes from the repository at the specified path
3757 or URL and adds them to a local repository (the current one unless
3757 or URL and adds them to a local repository (the current one unless
3758 -R is specified). By default, this does not update the copy of the
3758 -R is specified). By default, this does not update the copy of the
3759 project in the working directory.
3759 project in the working directory.
3760
3760
3761 Use :hg:`incoming` if you want to see what would have been added
3761 Use :hg:`incoming` if you want to see what would have been added
3762 by a pull at the time you issued this command. If you then decide
3762 by a pull at the time you issued this command. If you then decide
3763 to add those changes to the repository, you should use :hg:`pull
3763 to add those changes to the repository, you should use :hg:`pull
3764 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3764 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3765
3765
3766 If SOURCE is omitted, the 'default' path will be used.
3766 If SOURCE is omitted, the 'default' path will be used.
3767 See :hg:`help urls` for more information.
3767 See :hg:`help urls` for more information.
3768
3768
3769 Returns 0 on success, 1 if an update had unresolved files.
3769 Returns 0 on success, 1 if an update had unresolved files.
3770 """
3770 """
3771 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3771 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3772 other = hg.peer(repo, opts, source)
3772 other = hg.peer(repo, opts, source)
3773 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3773 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3774 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3774 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3775
3775
3776 if opts.get('bookmark'):
3776 if opts.get('bookmark'):
3777 if not revs:
3777 if not revs:
3778 revs = []
3778 revs = []
3779 rb = other.listkeys('bookmarks')
3779 rb = other.listkeys('bookmarks')
3780 for b in opts['bookmark']:
3780 for b in opts['bookmark']:
3781 if b not in rb:
3781 if b not in rb:
3782 raise util.Abort(_('remote bookmark %s not found!') % b)
3782 raise util.Abort(_('remote bookmark %s not found!') % b)
3783 revs.append(rb[b])
3783 revs.append(rb[b])
3784
3784
3785 if revs:
3785 if revs:
3786 try:
3786 try:
3787 revs = [other.lookup(rev) for rev in revs]
3787 revs = [other.lookup(rev) for rev in revs]
3788 except error.CapabilityError:
3788 except error.CapabilityError:
3789 err = _("other repository doesn't support revision lookup, "
3789 err = _("other repository doesn't support revision lookup, "
3790 "so a rev cannot be specified.")
3790 "so a rev cannot be specified.")
3791 raise util.Abort(err)
3791 raise util.Abort(err)
3792
3792
3793 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3793 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3794 bookmarks.updatefromremote(ui, repo, other)
3794 bookmarks.updatefromremote(ui, repo, other)
3795 if checkout:
3795 if checkout:
3796 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3796 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3797 repo._subtoppath = source
3797 repo._subtoppath = source
3798 try:
3798 try:
3799 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3799 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3800
3800
3801 finally:
3801 finally:
3802 del repo._subtoppath
3802 del repo._subtoppath
3803
3803
3804 # update specified bookmarks
3804 # update specified bookmarks
3805 if opts.get('bookmark'):
3805 if opts.get('bookmark'):
3806 for b in opts['bookmark']:
3806 for b in opts['bookmark']:
3807 # explicit pull overrides local bookmark if any
3807 # explicit pull overrides local bookmark if any
3808 ui.status(_("importing bookmark %s\n") % b)
3808 ui.status(_("importing bookmark %s\n") % b)
3809 repo._bookmarks[b] = repo[rb[b]].node()
3809 repo._bookmarks[b] = repo[rb[b]].node()
3810 bookmarks.write(repo)
3810 bookmarks.write(repo)
3811
3811
3812 return ret
3812 return ret
3813
3813
3814 @command('^push',
3814 @command('^push',
3815 [('f', 'force', None, _('force push')),
3815 [('f', 'force', None, _('force push')),
3816 ('r', 'rev', [],
3816 ('r', 'rev', [],
3817 _('a changeset intended to be included in the destination'),
3817 _('a changeset intended to be included in the destination'),
3818 _('REV')),
3818 _('REV')),
3819 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3819 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3820 ('b', 'branch', [],
3820 ('b', 'branch', [],
3821 _('a specific branch you would like to push'), _('BRANCH')),
3821 _('a specific branch you would like to push'), _('BRANCH')),
3822 ('', 'new-branch', False, _('allow pushing a new branch')),
3822 ('', 'new-branch', False, _('allow pushing a new branch')),
3823 ] + remoteopts,
3823 ] + remoteopts,
3824 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3824 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3825 def push(ui, repo, dest=None, **opts):
3825 def push(ui, repo, dest=None, **opts):
3826 """push changes to the specified destination
3826 """push changes to the specified destination
3827
3827
3828 Push changesets from the local repository to the specified
3828 Push changesets from the local repository to the specified
3829 destination.
3829 destination.
3830
3830
3831 This operation is symmetrical to pull: it is identical to a pull
3831 This operation is symmetrical to pull: it is identical to a pull
3832 in the destination repository from the current one.
3832 in the destination repository from the current one.
3833
3833
3834 By default, push will not allow creation of new heads at the
3834 By default, push will not allow creation of new heads at the
3835 destination, since multiple heads would make it unclear which head
3835 destination, since multiple heads would make it unclear which head
3836 to use. In this situation, it is recommended to pull and merge
3836 to use. In this situation, it is recommended to pull and merge
3837 before pushing.
3837 before pushing.
3838
3838
3839 Use --new-branch if you want to allow push to create a new named
3839 Use --new-branch if you want to allow push to create a new named
3840 branch that is not present at the destination. This allows you to
3840 branch that is not present at the destination. This allows you to
3841 only create a new branch without forcing other changes.
3841 only create a new branch without forcing other changes.
3842
3842
3843 Use -f/--force to override the default behavior and push all
3843 Use -f/--force to override the default behavior and push all
3844 changesets on all branches.
3844 changesets on all branches.
3845
3845
3846 If -r/--rev is used, the specified revision and all its ancestors
3846 If -r/--rev is used, the specified revision and all its ancestors
3847 will be pushed to the remote repository.
3847 will be pushed to the remote repository.
3848
3848
3849 Please see :hg:`help urls` for important details about ``ssh://``
3849 Please see :hg:`help urls` for important details about ``ssh://``
3850 URLs. If DESTINATION is omitted, a default path will be used.
3850 URLs. If DESTINATION is omitted, a default path will be used.
3851
3851
3852 Returns 0 if push was successful, 1 if nothing to push.
3852 Returns 0 if push was successful, 1 if nothing to push.
3853 """
3853 """
3854
3854
3855 if opts.get('bookmark'):
3855 if opts.get('bookmark'):
3856 for b in opts['bookmark']:
3856 for b in opts['bookmark']:
3857 # translate -B options to -r so changesets get pushed
3857 # translate -B options to -r so changesets get pushed
3858 if b in repo._bookmarks:
3858 if b in repo._bookmarks:
3859 opts.setdefault('rev', []).append(b)
3859 opts.setdefault('rev', []).append(b)
3860 else:
3860 else:
3861 # if we try to push a deleted bookmark, translate it to null
3861 # if we try to push a deleted bookmark, translate it to null
3862 # this lets simultaneous -r, -b options continue working
3862 # this lets simultaneous -r, -b options continue working
3863 opts.setdefault('rev', []).append("null")
3863 opts.setdefault('rev', []).append("null")
3864
3864
3865 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3865 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3866 dest, branches = hg.parseurl(dest, opts.get('branch'))
3866 dest, branches = hg.parseurl(dest, opts.get('branch'))
3867 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3867 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3868 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3868 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3869 other = hg.peer(repo, opts, dest)
3869 other = hg.peer(repo, opts, dest)
3870 if revs:
3870 if revs:
3871 revs = [repo.lookup(rev) for rev in revs]
3871 revs = [repo.lookup(rev) for rev in revs]
3872
3872
3873 repo._subtoppath = dest
3873 repo._subtoppath = dest
3874 try:
3874 try:
3875 # push subrepos depth-first for coherent ordering
3875 # push subrepos depth-first for coherent ordering
3876 c = repo['']
3876 c = repo['']
3877 subs = c.substate # only repos that are committed
3877 subs = c.substate # only repos that are committed
3878 for s in sorted(subs):
3878 for s in sorted(subs):
3879 if not c.sub(s).push(opts.get('force')):
3879 if not c.sub(s).push(opts.get('force')):
3880 return False
3880 return False
3881 finally:
3881 finally:
3882 del repo._subtoppath
3882 del repo._subtoppath
3883 result = repo.push(other, opts.get('force'), revs=revs,
3883 result = repo.push(other, opts.get('force'), revs=revs,
3884 newbranch=opts.get('new_branch'))
3884 newbranch=opts.get('new_branch'))
3885
3885
3886 result = (result == 0)
3886 result = (result == 0)
3887
3887
3888 if opts.get('bookmark'):
3888 if opts.get('bookmark'):
3889 rb = other.listkeys('bookmarks')
3889 rb = other.listkeys('bookmarks')
3890 for b in opts['bookmark']:
3890 for b in opts['bookmark']:
3891 # explicit push overrides remote bookmark if any
3891 # explicit push overrides remote bookmark if any
3892 if b in repo._bookmarks:
3892 if b in repo._bookmarks:
3893 ui.status(_("exporting bookmark %s\n") % b)
3893 ui.status(_("exporting bookmark %s\n") % b)
3894 new = repo[b].hex()
3894 new = repo[b].hex()
3895 elif b in rb:
3895 elif b in rb:
3896 ui.status(_("deleting remote bookmark %s\n") % b)
3896 ui.status(_("deleting remote bookmark %s\n") % b)
3897 new = '' # delete
3897 new = '' # delete
3898 else:
3898 else:
3899 ui.warn(_('bookmark %s does not exist on the local '
3899 ui.warn(_('bookmark %s does not exist on the local '
3900 'or remote repository!\n') % b)
3900 'or remote repository!\n') % b)
3901 return 2
3901 return 2
3902 old = rb.get(b, '')
3902 old = rb.get(b, '')
3903 r = other.pushkey('bookmarks', b, old, new)
3903 r = other.pushkey('bookmarks', b, old, new)
3904 if not r:
3904 if not r:
3905 ui.warn(_('updating bookmark %s failed!\n') % b)
3905 ui.warn(_('updating bookmark %s failed!\n') % b)
3906 if not result:
3906 if not result:
3907 result = 2
3907 result = 2
3908
3908
3909 return result
3909 return result
3910
3910
3911 @command('recover', [])
3911 @command('recover', [])
3912 def recover(ui, repo):
3912 def recover(ui, repo):
3913 """roll back an interrupted transaction
3913 """roll back an interrupted transaction
3914
3914
3915 Recover from an interrupted commit or pull.
3915 Recover from an interrupted commit or pull.
3916
3916
3917 This command tries to fix the repository status after an
3917 This command tries to fix the repository status after an
3918 interrupted operation. It should only be necessary when Mercurial
3918 interrupted operation. It should only be necessary when Mercurial
3919 suggests it.
3919 suggests it.
3920
3920
3921 Returns 0 if successful, 1 if nothing to recover or verify fails.
3921 Returns 0 if successful, 1 if nothing to recover or verify fails.
3922 """
3922 """
3923 if repo.recover():
3923 if repo.recover():
3924 return hg.verify(repo)
3924 return hg.verify(repo)
3925 return 1
3925 return 1
3926
3926
3927 @command('^remove|rm',
3927 @command('^remove|rm',
3928 [('A', 'after', None, _('record delete for missing files')),
3928 [('A', 'after', None, _('record delete for missing files')),
3929 ('f', 'force', None,
3929 ('f', 'force', None,
3930 _('remove (and delete) file even if added or modified')),
3930 _('remove (and delete) file even if added or modified')),
3931 ] + walkopts,
3931 ] + walkopts,
3932 _('[OPTION]... FILE...'))
3932 _('[OPTION]... FILE...'))
3933 def remove(ui, repo, *pats, **opts):
3933 def remove(ui, repo, *pats, **opts):
3934 """remove the specified files on the next commit
3934 """remove the specified files on the next commit
3935
3935
3936 Schedule the indicated files for removal from the repository.
3936 Schedule the indicated files for removal from the repository.
3937
3937
3938 This only removes files from the current branch, not from the
3938 This only removes files from the current branch, not from the
3939 entire project history. -A/--after can be used to remove only
3939 entire project history. -A/--after can be used to remove only
3940 files that have already been deleted, -f/--force can be used to
3940 files that have already been deleted, -f/--force can be used to
3941 force deletion, and -Af can be used to remove files from the next
3941 force deletion, and -Af can be used to remove files from the next
3942 revision without deleting them from the working directory.
3942 revision without deleting them from the working directory.
3943
3943
3944 The following table details the behavior of remove for different
3944 The following table details the behavior of remove for different
3945 file states (columns) and option combinations (rows). The file
3945 file states (columns) and option combinations (rows). The file
3946 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3946 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3947 reported by :hg:`status`). The actions are Warn, Remove (from
3947 reported by :hg:`status`). The actions are Warn, Remove (from
3948 branch) and Delete (from disk)::
3948 branch) and Delete (from disk)::
3949
3949
3950 A C M !
3950 A C M !
3951 none W RD W R
3951 none W RD W R
3952 -f R RD RD R
3952 -f R RD RD R
3953 -A W W W R
3953 -A W W W R
3954 -Af R R R R
3954 -Af R R R R
3955
3955
3956 Note that remove never deletes files in Added [A] state from the
3956 Note that remove never deletes files in Added [A] state from the
3957 working directory, not even if option --force is specified.
3957 working directory, not even if option --force is specified.
3958
3958
3959 This command schedules the files to be removed at the next commit.
3959 This command schedules the files to be removed at the next commit.
3960 To undo a remove before that, see :hg:`revert`.
3960 To undo a remove before that, see :hg:`revert`.
3961
3961
3962 Returns 0 on success, 1 if any warnings encountered.
3962 Returns 0 on success, 1 if any warnings encountered.
3963 """
3963 """
3964
3964
3965 ret = 0
3965 ret = 0
3966 after, force = opts.get('after'), opts.get('force')
3966 after, force = opts.get('after'), opts.get('force')
3967 if not pats and not after:
3967 if not pats and not after:
3968 raise util.Abort(_('no files specified'))
3968 raise util.Abort(_('no files specified'))
3969
3969
3970 m = scmutil.match(repo[None], pats, opts)
3970 m = scmutil.match(repo[None], pats, opts)
3971 s = repo.status(match=m, clean=True)
3971 s = repo.status(match=m, clean=True)
3972 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3972 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3973
3973
3974 for f in m.files():
3974 for f in m.files():
3975 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3975 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3976 if os.path.exists(m.rel(f)):
3976 if os.path.exists(m.rel(f)):
3977 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3977 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3978 ret = 1
3978 ret = 1
3979
3979
3980 if force:
3980 if force:
3981 list = modified + deleted + clean + added
3981 list = modified + deleted + clean + added
3982 elif after:
3982 elif after:
3983 list = deleted
3983 list = deleted
3984 for f in modified + added + clean:
3984 for f in modified + added + clean:
3985 ui.warn(_('not removing %s: file still exists (use -f'
3985 ui.warn(_('not removing %s: file still exists (use -f'
3986 ' to force removal)\n') % m.rel(f))
3986 ' to force removal)\n') % m.rel(f))
3987 ret = 1
3987 ret = 1
3988 else:
3988 else:
3989 list = deleted + clean
3989 list = deleted + clean
3990 for f in modified:
3990 for f in modified:
3991 ui.warn(_('not removing %s: file is modified (use -f'
3991 ui.warn(_('not removing %s: file is modified (use -f'
3992 ' to force removal)\n') % m.rel(f))
3992 ' to force removal)\n') % m.rel(f))
3993 ret = 1
3993 ret = 1
3994 for f in added:
3994 for f in added:
3995 ui.warn(_('not removing %s: file has been marked for add (use -f'
3995 ui.warn(_('not removing %s: file has been marked for add (use -f'
3996 ' to force removal)\n') % m.rel(f))
3996 ' to force removal)\n') % m.rel(f))
3997 ret = 1
3997 ret = 1
3998
3998
3999 for f in sorted(list):
3999 for f in sorted(list):
4000 if ui.verbose or not m.exact(f):
4000 if ui.verbose or not m.exact(f):
4001 ui.status(_('removing %s\n') % m.rel(f))
4001 ui.status(_('removing %s\n') % m.rel(f))
4002
4002
4003 wlock = repo.wlock()
4003 wlock = repo.wlock()
4004 try:
4004 try:
4005 if not after:
4005 if not after:
4006 for f in list:
4006 for f in list:
4007 if f in added:
4007 if f in added:
4008 continue # we never unlink added files on remove
4008 continue # we never unlink added files on remove
4009 try:
4009 try:
4010 util.unlinkpath(repo.wjoin(f))
4010 util.unlinkpath(repo.wjoin(f))
4011 except OSError, inst:
4011 except OSError, inst:
4012 if inst.errno != errno.ENOENT:
4012 if inst.errno != errno.ENOENT:
4013 raise
4013 raise
4014 repo[None].forget(list)
4014 repo[None].forget(list)
4015 finally:
4015 finally:
4016 wlock.release()
4016 wlock.release()
4017
4017
4018 return ret
4018 return ret
4019
4019
4020 @command('rename|move|mv',
4020 @command('rename|move|mv',
4021 [('A', 'after', None, _('record a rename that has already occurred')),
4021 [('A', 'after', None, _('record a rename that has already occurred')),
4022 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4022 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4023 ] + walkopts + dryrunopts,
4023 ] + walkopts + dryrunopts,
4024 _('[OPTION]... SOURCE... DEST'))
4024 _('[OPTION]... SOURCE... DEST'))
4025 def rename(ui, repo, *pats, **opts):
4025 def rename(ui, repo, *pats, **opts):
4026 """rename files; equivalent of copy + remove
4026 """rename files; equivalent of copy + remove
4027
4027
4028 Mark dest as copies of sources; mark sources for deletion. If dest
4028 Mark dest as copies of sources; mark sources for deletion. If dest
4029 is a directory, copies are put in that directory. If dest is a
4029 is a directory, copies are put in that directory. If dest is a
4030 file, there can only be one source.
4030 file, there can only be one source.
4031
4031
4032 By default, this command copies the contents of files as they
4032 By default, this command copies the contents of files as they
4033 exist in the working directory. If invoked with -A/--after, the
4033 exist in the working directory. If invoked with -A/--after, the
4034 operation is recorded, but no copying is performed.
4034 operation is recorded, but no copying is performed.
4035
4035
4036 This command takes effect at the next commit. To undo a rename
4036 This command takes effect at the next commit. To undo a rename
4037 before that, see :hg:`revert`.
4037 before that, see :hg:`revert`.
4038
4038
4039 Returns 0 on success, 1 if errors are encountered.
4039 Returns 0 on success, 1 if errors are encountered.
4040 """
4040 """
4041 wlock = repo.wlock(False)
4041 wlock = repo.wlock(False)
4042 try:
4042 try:
4043 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4043 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4044 finally:
4044 finally:
4045 wlock.release()
4045 wlock.release()
4046
4046
4047 @command('resolve',
4047 @command('resolve',
4048 [('a', 'all', None, _('select all unresolved files')),
4048 [('a', 'all', None, _('select all unresolved files')),
4049 ('l', 'list', None, _('list state of files needing merge')),
4049 ('l', 'list', None, _('list state of files needing merge')),
4050 ('m', 'mark', None, _('mark files as resolved')),
4050 ('m', 'mark', None, _('mark files as resolved')),
4051 ('u', 'unmark', None, _('mark files as unresolved')),
4051 ('u', 'unmark', None, _('mark files as unresolved')),
4052 ('t', 'tool', '', _('specify merge tool')),
4052 ('t', 'tool', '', _('specify merge tool')),
4053 ('n', 'no-status', None, _('hide status prefix'))]
4053 ('n', 'no-status', None, _('hide status prefix'))]
4054 + walkopts,
4054 + walkopts,
4055 _('[OPTION]... [FILE]...'))
4055 _('[OPTION]... [FILE]...'))
4056 def resolve(ui, repo, *pats, **opts):
4056 def resolve(ui, repo, *pats, **opts):
4057 """redo merges or set/view the merge status of files
4057 """redo merges or set/view the merge status of files
4058
4058
4059 Merges with unresolved conflicts are often the result of
4059 Merges with unresolved conflicts are often the result of
4060 non-interactive merging using the ``internal:merge`` configuration
4060 non-interactive merging using the ``internal:merge`` configuration
4061 setting, or a command-line merge tool like ``diff3``. The resolve
4061 setting, or a command-line merge tool like ``diff3``. The resolve
4062 command is used to manage the files involved in a merge, after
4062 command is used to manage the files involved in a merge, after
4063 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4063 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4064 working directory must have two parents).
4064 working directory must have two parents).
4065
4065
4066 The resolve command can be used in the following ways:
4066 The resolve command can be used in the following ways:
4067
4067
4068 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4068 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4069 files, discarding any previous merge attempts. Re-merging is not
4069 files, discarding any previous merge attempts. Re-merging is not
4070 performed for files already marked as resolved. Use ``--all/-a``
4070 performed for files already marked as resolved. Use ``--all/-a``
4071 to selects all unresolved files. ``--tool`` can be used to specify
4071 to selects all unresolved files. ``--tool`` can be used to specify
4072 the merge tool used for the given files. It overrides the HGMERGE
4072 the merge tool used for the given files. It overrides the HGMERGE
4073 environment variable and your configuration files.
4073 environment variable and your configuration files.
4074
4074
4075 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4075 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4076 (e.g. after having manually fixed-up the files). The default is
4076 (e.g. after having manually fixed-up the files). The default is
4077 to mark all unresolved files.
4077 to mark all unresolved files.
4078
4078
4079 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4079 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4080 default is to mark all resolved files.
4080 default is to mark all resolved files.
4081
4081
4082 - :hg:`resolve -l`: list files which had or still have conflicts.
4082 - :hg:`resolve -l`: list files which had or still have conflicts.
4083 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4083 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4084
4084
4085 Note that Mercurial will not let you commit files with unresolved
4085 Note that Mercurial will not let you commit files with unresolved
4086 merge conflicts. You must use :hg:`resolve -m ...` before you can
4086 merge conflicts. You must use :hg:`resolve -m ...` before you can
4087 commit after a conflicting merge.
4087 commit after a conflicting merge.
4088
4088
4089 Returns 0 on success, 1 if any files fail a resolve attempt.
4089 Returns 0 on success, 1 if any files fail a resolve attempt.
4090 """
4090 """
4091
4091
4092 all, mark, unmark, show, nostatus = \
4092 all, mark, unmark, show, nostatus = \
4093 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4093 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4094
4094
4095 if (show and (mark or unmark)) or (mark and unmark):
4095 if (show and (mark or unmark)) or (mark and unmark):
4096 raise util.Abort(_("too many options specified"))
4096 raise util.Abort(_("too many options specified"))
4097 if pats and all:
4097 if pats and all:
4098 raise util.Abort(_("can't specify --all and patterns"))
4098 raise util.Abort(_("can't specify --all and patterns"))
4099 if not (all or pats or show or mark or unmark):
4099 if not (all or pats or show or mark or unmark):
4100 raise util.Abort(_('no files or directories specified; '
4100 raise util.Abort(_('no files or directories specified; '
4101 'use --all to remerge all files'))
4101 'use --all to remerge all files'))
4102
4102
4103 ms = mergemod.mergestate(repo)
4103 ms = mergemod.mergestate(repo)
4104 m = scmutil.match(repo[None], pats, opts)
4104 m = scmutil.match(repo[None], pats, opts)
4105 ret = 0
4105 ret = 0
4106
4106
4107 for f in ms:
4107 for f in ms:
4108 if m(f):
4108 if m(f):
4109 if show:
4109 if show:
4110 if nostatus:
4110 if nostatus:
4111 ui.write("%s\n" % f)
4111 ui.write("%s\n" % f)
4112 else:
4112 else:
4113 ui.write("%s %s\n" % (ms[f].upper(), f),
4113 ui.write("%s %s\n" % (ms[f].upper(), f),
4114 label='resolve.' +
4114 label='resolve.' +
4115 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4115 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4116 elif mark:
4116 elif mark:
4117 ms.mark(f, "r")
4117 ms.mark(f, "r")
4118 elif unmark:
4118 elif unmark:
4119 ms.mark(f, "u")
4119 ms.mark(f, "u")
4120 else:
4120 else:
4121 wctx = repo[None]
4121 wctx = repo[None]
4122 mctx = wctx.parents()[-1]
4122 mctx = wctx.parents()[-1]
4123
4123
4124 # backup pre-resolve (merge uses .orig for its own purposes)
4124 # backup pre-resolve (merge uses .orig for its own purposes)
4125 a = repo.wjoin(f)
4125 a = repo.wjoin(f)
4126 util.copyfile(a, a + ".resolve")
4126 util.copyfile(a, a + ".resolve")
4127
4127
4128 try:
4128 try:
4129 # resolve file
4129 # resolve file
4130 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4130 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4131 if ms.resolve(f, wctx, mctx):
4131 if ms.resolve(f, wctx, mctx):
4132 ret = 1
4132 ret = 1
4133 finally:
4133 finally:
4134 ui.setconfig('ui', 'forcemerge', '')
4134 ui.setconfig('ui', 'forcemerge', '')
4135
4135
4136 # replace filemerge's .orig file with our resolve file
4136 # replace filemerge's .orig file with our resolve file
4137 util.rename(a + ".resolve", a + ".orig")
4137 util.rename(a + ".resolve", a + ".orig")
4138
4138
4139 ms.commit()
4139 ms.commit()
4140 return ret
4140 return ret
4141
4141
4142 @command('revert',
4142 @command('revert',
4143 [('a', 'all', None, _('revert all changes when no arguments given')),
4143 [('a', 'all', None, _('revert all changes when no arguments given')),
4144 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4144 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4145 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4145 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4146 ('', 'no-backup', None, _('do not save backup copies of files')),
4146 ('', 'no-backup', None, _('do not save backup copies of files')),
4147 ] + walkopts + dryrunopts,
4147 ] + walkopts + dryrunopts,
4148 _('[OPTION]... [-r REV] [NAME]...'))
4148 _('[OPTION]... [-r REV] [NAME]...'))
4149 def revert(ui, repo, *pats, **opts):
4149 def revert(ui, repo, *pats, **opts):
4150 """restore files to their checkout state
4150 """restore files to their checkout state
4151
4151
4152 .. note::
4152 .. note::
4153 To check out earlier revisions, you should use :hg:`update REV`.
4153 To check out earlier revisions, you should use :hg:`update REV`.
4154 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4154 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4155
4155
4156 With no revision specified, revert the specified files or directories
4156 With no revision specified, revert the specified files or directories
4157 to the state they had in the first parent of the working directory.
4157 to the state they had in the first parent of the working directory.
4158 This restores the contents of files to an unmodified
4158 This restores the contents of files to an unmodified
4159 state and unschedules adds, removes, copies, and renames.
4159 state and unschedules adds, removes, copies, and renames.
4160
4160
4161 Using the -r/--rev or -d/--date options, revert the given files or
4161 Using the -r/--rev or -d/--date options, revert the given files or
4162 directories to their states as of a specific revision. Because
4162 directories to their states as of a specific revision. Because
4163 revert does not change the working directory parents, this will
4163 revert does not change the working directory parents, this will
4164 cause these files to appear modified. This can be helpful to "back
4164 cause these files to appear modified. This can be helpful to "back
4165 out" some or all of an earlier change. See :hg:`backout` for a
4165 out" some or all of an earlier change. See :hg:`backout` for a
4166 related method.
4166 related method.
4167
4167
4168 Modified files are saved with a .orig suffix before reverting.
4168 Modified files are saved with a .orig suffix before reverting.
4169 To disable these backups, use --no-backup.
4169 To disable these backups, use --no-backup.
4170
4170
4171 See :hg:`help dates` for a list of formats valid for -d/--date.
4171 See :hg:`help dates` for a list of formats valid for -d/--date.
4172
4172
4173 Returns 0 on success.
4173 Returns 0 on success.
4174 """
4174 """
4175
4175
4176 if opts.get("date"):
4176 if opts.get("date"):
4177 if opts.get("rev"):
4177 if opts.get("rev"):
4178 raise util.Abort(_("you can't specify a revision and a date"))
4178 raise util.Abort(_("you can't specify a revision and a date"))
4179 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4179 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4180
4180
4181 parent, p2 = repo.dirstate.parents()
4181 parent, p2 = repo.dirstate.parents()
4182 ctx = scmutil.revsingle(repo, opts.get('rev'))
4182 ctx = scmutil.revsingle(repo, opts.get('rev'))
4183 node = ctx.node()
4183 node = ctx.node()
4184
4184
4185 if not pats and not opts.get('all'):
4185 if not pats and not opts.get('all'):
4186 msg = _("no files or directories specified")
4186 msg = _("no files or directories specified")
4187 hint = _("use --all to discard all changes")
4187 hint = _("use --all to discard all changes")
4188 if p2 != nullid:
4188 if p2 != nullid:
4189 hint = _("uncommitted merge, use --all to discard all changes,"
4189 hint = _("uncommitted merge, use --all to discard all changes,"
4190 " or 'hg update -C .' to abort the merge")
4190 " or 'hg update -C .' to abort the merge")
4191 elif node != parent:
4191 elif node != parent:
4192 if util.any(repo.status()):
4192 if util.any(repo.status()):
4193 hint = _("uncommitted changes, use --all to discard all"
4193 hint = _("uncommitted changes, use --all to discard all"
4194 " changes, or 'hg update %s' to update") % ctx.rev()
4194 " changes, or 'hg update %s' to update") % ctx.rev()
4195 else:
4195 else:
4196 hint = _("use --all to revert all files,"
4196 hint = _("use --all to revert all files,"
4197 " or 'hg update %s' to update") % ctx.rev()
4197 " or 'hg update %s' to update") % ctx.rev()
4198 raise util.Abort(msg, hint=hint)
4198 raise util.Abort(msg, hint=hint)
4199
4199
4200 mf = ctx.manifest()
4200 mf = ctx.manifest()
4201 if node == parent:
4201 if node == parent:
4202 pmf = mf
4202 pmf = mf
4203 else:
4203 else:
4204 pmf = None
4204 pmf = None
4205
4205
4206 # need all matching names in dirstate and manifest of target rev,
4206 # need all matching names in dirstate and manifest of target rev,
4207 # so have to walk both. do not print errors if files exist in one
4207 # so have to walk both. do not print errors if files exist in one
4208 # but not other.
4208 # but not other.
4209
4209
4210 names = {}
4210 names = {}
4211
4211
4212 wlock = repo.wlock()
4212 wlock = repo.wlock()
4213 try:
4213 try:
4214 # walk dirstate.
4214 # walk dirstate.
4215
4215
4216 m = scmutil.match(repo[None], pats, opts)
4216 m = scmutil.match(repo[None], pats, opts)
4217 m.bad = lambda x, y: False
4217 m.bad = lambda x, y: False
4218 for abs in repo.walk(m):
4218 for abs in repo.walk(m):
4219 names[abs] = m.rel(abs), m.exact(abs)
4219 names[abs] = m.rel(abs), m.exact(abs)
4220
4220
4221 # walk target manifest.
4221 # walk target manifest.
4222
4222
4223 def badfn(path, msg):
4223 def badfn(path, msg):
4224 if path in names:
4224 if path in names:
4225 return
4225 return
4226 path_ = path + '/'
4226 path_ = path + '/'
4227 for f in names:
4227 for f in names:
4228 if f.startswith(path_):
4228 if f.startswith(path_):
4229 return
4229 return
4230 ui.warn("%s: %s\n" % (m.rel(path), msg))
4230 ui.warn("%s: %s\n" % (m.rel(path), msg))
4231
4231
4232 m = scmutil.match(repo[node], pats, opts)
4232 m = scmutil.match(repo[node], pats, opts)
4233 m.bad = badfn
4233 m.bad = badfn
4234 for abs in repo[node].walk(m):
4234 for abs in repo[node].walk(m):
4235 if abs not in names:
4235 if abs not in names:
4236 names[abs] = m.rel(abs), m.exact(abs)
4236 names[abs] = m.rel(abs), m.exact(abs)
4237
4237
4238 m = scmutil.matchfiles(repo, names)
4238 m = scmutil.matchfiles(repo, names)
4239 changes = repo.status(match=m)[:4]
4239 changes = repo.status(match=m)[:4]
4240 modified, added, removed, deleted = map(set, changes)
4240 modified, added, removed, deleted = map(set, changes)
4241
4241
4242 # if f is a rename, also revert the source
4242 # if f is a rename, also revert the source
4243 cwd = repo.getcwd()
4243 cwd = repo.getcwd()
4244 for f in added:
4244 for f in added:
4245 src = repo.dirstate.copied(f)
4245 src = repo.dirstate.copied(f)
4246 if src and src not in names and repo.dirstate[src] == 'r':
4246 if src and src not in names and repo.dirstate[src] == 'r':
4247 removed.add(src)
4247 removed.add(src)
4248 names[src] = (repo.pathto(src, cwd), True)
4248 names[src] = (repo.pathto(src, cwd), True)
4249
4249
4250 def removeforget(abs):
4250 def removeforget(abs):
4251 if repo.dirstate[abs] == 'a':
4251 if repo.dirstate[abs] == 'a':
4252 return _('forgetting %s\n')
4252 return _('forgetting %s\n')
4253 return _('removing %s\n')
4253 return _('removing %s\n')
4254
4254
4255 revert = ([], _('reverting %s\n'))
4255 revert = ([], _('reverting %s\n'))
4256 add = ([], _('adding %s\n'))
4256 add = ([], _('adding %s\n'))
4257 remove = ([], removeforget)
4257 remove = ([], removeforget)
4258 undelete = ([], _('undeleting %s\n'))
4258 undelete = ([], _('undeleting %s\n'))
4259
4259
4260 disptable = (
4260 disptable = (
4261 # dispatch table:
4261 # dispatch table:
4262 # file state
4262 # file state
4263 # action if in target manifest
4263 # action if in target manifest
4264 # action if not in target manifest
4264 # action if not in target manifest
4265 # make backup if in target manifest
4265 # make backup if in target manifest
4266 # make backup if not in target manifest
4266 # make backup if not in target manifest
4267 (modified, revert, remove, True, True),
4267 (modified, revert, remove, True, True),
4268 (added, revert, remove, True, False),
4268 (added, revert, remove, True, False),
4269 (removed, undelete, None, False, False),
4269 (removed, undelete, None, False, False),
4270 (deleted, revert, remove, False, False),
4270 (deleted, revert, remove, False, False),
4271 )
4271 )
4272
4272
4273 for abs, (rel, exact) in sorted(names.items()):
4273 for abs, (rel, exact) in sorted(names.items()):
4274 mfentry = mf.get(abs)
4274 mfentry = mf.get(abs)
4275 target = repo.wjoin(abs)
4275 target = repo.wjoin(abs)
4276 def handle(xlist, dobackup):
4276 def handle(xlist, dobackup):
4277 xlist[0].append(abs)
4277 xlist[0].append(abs)
4278 if (dobackup and not opts.get('no_backup') and
4278 if (dobackup and not opts.get('no_backup') and
4279 os.path.lexists(target)):
4279 os.path.lexists(target)):
4280 bakname = "%s.orig" % rel
4280 bakname = "%s.orig" % rel
4281 ui.note(_('saving current version of %s as %s\n') %
4281 ui.note(_('saving current version of %s as %s\n') %
4282 (rel, bakname))
4282 (rel, bakname))
4283 if not opts.get('dry_run'):
4283 if not opts.get('dry_run'):
4284 util.rename(target, bakname)
4284 util.rename(target, bakname)
4285 if ui.verbose or not exact:
4285 if ui.verbose or not exact:
4286 msg = xlist[1]
4286 msg = xlist[1]
4287 if not isinstance(msg, basestring):
4287 if not isinstance(msg, basestring):
4288 msg = msg(abs)
4288 msg = msg(abs)
4289 ui.status(msg % rel)
4289 ui.status(msg % rel)
4290 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4290 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4291 if abs not in table:
4291 if abs not in table:
4292 continue
4292 continue
4293 # file has changed in dirstate
4293 # file has changed in dirstate
4294 if mfentry:
4294 if mfentry:
4295 handle(hitlist, backuphit)
4295 handle(hitlist, backuphit)
4296 elif misslist is not None:
4296 elif misslist is not None:
4297 handle(misslist, backupmiss)
4297 handle(misslist, backupmiss)
4298 break
4298 break
4299 else:
4299 else:
4300 if abs not in repo.dirstate:
4300 if abs not in repo.dirstate:
4301 if mfentry:
4301 if mfentry:
4302 handle(add, True)
4302 handle(add, True)
4303 elif exact:
4303 elif exact:
4304 ui.warn(_('file not managed: %s\n') % rel)
4304 ui.warn(_('file not managed: %s\n') % rel)
4305 continue
4305 continue
4306 # file has not changed in dirstate
4306 # file has not changed in dirstate
4307 if node == parent:
4307 if node == parent:
4308 if exact:
4308 if exact:
4309 ui.warn(_('no changes needed to %s\n') % rel)
4309 ui.warn(_('no changes needed to %s\n') % rel)
4310 continue
4310 continue
4311 if pmf is None:
4311 if pmf is None:
4312 # only need parent manifest in this unlikely case,
4312 # only need parent manifest in this unlikely case,
4313 # so do not read by default
4313 # so do not read by default
4314 pmf = repo[parent].manifest()
4314 pmf = repo[parent].manifest()
4315 if abs in pmf:
4315 if abs in pmf:
4316 if mfentry:
4316 if mfentry:
4317 # if version of file is same in parent and target
4317 # if version of file is same in parent and target
4318 # manifests, do nothing
4318 # manifests, do nothing
4319 if (pmf[abs] != mfentry or
4319 if (pmf[abs] != mfentry or
4320 pmf.flags(abs) != mf.flags(abs)):
4320 pmf.flags(abs) != mf.flags(abs)):
4321 handle(revert, False)
4321 handle(revert, False)
4322 else:
4322 else:
4323 handle(remove, False)
4323 handle(remove, False)
4324
4324
4325 if not opts.get('dry_run'):
4325 if not opts.get('dry_run'):
4326 def checkout(f):
4326 def checkout(f):
4327 fc = ctx[f]
4327 fc = ctx[f]
4328 repo.wwrite(f, fc.data(), fc.flags())
4328 repo.wwrite(f, fc.data(), fc.flags())
4329
4329
4330 audit_path = scmutil.pathauditor(repo.root)
4330 audit_path = scmutil.pathauditor(repo.root)
4331 for f in remove[0]:
4331 for f in remove[0]:
4332 if repo.dirstate[f] == 'a':
4332 if repo.dirstate[f] == 'a':
4333 repo.dirstate.drop(f)
4333 repo.dirstate.drop(f)
4334 continue
4334 continue
4335 audit_path(f)
4335 audit_path(f)
4336 try:
4336 try:
4337 util.unlinkpath(repo.wjoin(f))
4337 util.unlinkpath(repo.wjoin(f))
4338 except OSError:
4338 except OSError:
4339 pass
4339 pass
4340 repo.dirstate.remove(f)
4340 repo.dirstate.remove(f)
4341
4341
4342 normal = None
4342 normal = None
4343 if node == parent:
4343 if node == parent:
4344 # We're reverting to our parent. If possible, we'd like status
4344 # We're reverting to our parent. If possible, we'd like status
4345 # to report the file as clean. We have to use normallookup for
4345 # to report the file as clean. We have to use normallookup for
4346 # merges to avoid losing information about merged/dirty files.
4346 # merges to avoid losing information about merged/dirty files.
4347 if p2 != nullid:
4347 if p2 != nullid:
4348 normal = repo.dirstate.normallookup
4348 normal = repo.dirstate.normallookup
4349 else:
4349 else:
4350 normal = repo.dirstate.normal
4350 normal = repo.dirstate.normal
4351 for f in revert[0]:
4351 for f in revert[0]:
4352 checkout(f)
4352 checkout(f)
4353 if normal:
4353 if normal:
4354 normal(f)
4354 normal(f)
4355
4355
4356 for f in add[0]:
4356 for f in add[0]:
4357 checkout(f)
4357 checkout(f)
4358 repo.dirstate.add(f)
4358 repo.dirstate.add(f)
4359
4359
4360 normal = repo.dirstate.normallookup
4360 normal = repo.dirstate.normallookup
4361 if node == parent and p2 == nullid:
4361 if node == parent and p2 == nullid:
4362 normal = repo.dirstate.normal
4362 normal = repo.dirstate.normal
4363 for f in undelete[0]:
4363 for f in undelete[0]:
4364 checkout(f)
4364 checkout(f)
4365 normal(f)
4365 normal(f)
4366
4366
4367 finally:
4367 finally:
4368 wlock.release()
4368 wlock.release()
4369
4369
4370 @command('rollback', dryrunopts)
4370 @command('rollback', dryrunopts)
4371 def rollback(ui, repo, **opts):
4371 def rollback(ui, repo, **opts):
4372 """roll back the last transaction (dangerous)
4372 """roll back the last transaction (dangerous)
4373
4373
4374 This command should be used with care. There is only one level of
4374 This command should be used with care. There is only one level of
4375 rollback, and there is no way to undo a rollback. It will also
4375 rollback, and there is no way to undo a rollback. It will also
4376 restore the dirstate at the time of the last transaction, losing
4376 restore the dirstate at the time of the last transaction, losing
4377 any dirstate changes since that time. This command does not alter
4377 any dirstate changes since that time. This command does not alter
4378 the working directory.
4378 the working directory.
4379
4379
4380 Transactions are used to encapsulate the effects of all commands
4380 Transactions are used to encapsulate the effects of all commands
4381 that create new changesets or propagate existing changesets into a
4381 that create new changesets or propagate existing changesets into a
4382 repository. For example, the following commands are transactional,
4382 repository. For example, the following commands are transactional,
4383 and their effects can be rolled back:
4383 and their effects can be rolled back:
4384
4384
4385 - commit
4385 - commit
4386 - import
4386 - import
4387 - pull
4387 - pull
4388 - push (with this repository as the destination)
4388 - push (with this repository as the destination)
4389 - unbundle
4389 - unbundle
4390
4390
4391 This command is not intended for use on public repositories. Once
4391 This command is not intended for use on public repositories. Once
4392 changes are visible for pull by other users, rolling a transaction
4392 changes are visible for pull by other users, rolling a transaction
4393 back locally is ineffective (someone else may already have pulled
4393 back locally is ineffective (someone else may already have pulled
4394 the changes). Furthermore, a race is possible with readers of the
4394 the changes). Furthermore, a race is possible with readers of the
4395 repository; for example an in-progress pull from the repository
4395 repository; for example an in-progress pull from the repository
4396 may fail if a rollback is performed.
4396 may fail if a rollback is performed.
4397
4397
4398 Returns 0 on success, 1 if no rollback data is available.
4398 Returns 0 on success, 1 if no rollback data is available.
4399 """
4399 """
4400 return repo.rollback(opts.get('dry_run'))
4400 return repo.rollback(opts.get('dry_run'))
4401
4401
4402 @command('root', [])
4402 @command('root', [])
4403 def root(ui, repo):
4403 def root(ui, repo):
4404 """print the root (top) of the current working directory
4404 """print the root (top) of the current working directory
4405
4405
4406 Print the root directory of the current repository.
4406 Print the root directory of the current repository.
4407
4407
4408 Returns 0 on success.
4408 Returns 0 on success.
4409 """
4409 """
4410 ui.write(repo.root + "\n")
4410 ui.write(repo.root + "\n")
4411
4411
4412 @command('^serve',
4412 @command('^serve',
4413 [('A', 'accesslog', '', _('name of access log file to write to'),
4413 [('A', 'accesslog', '', _('name of access log file to write to'),
4414 _('FILE')),
4414 _('FILE')),
4415 ('d', 'daemon', None, _('run server in background')),
4415 ('d', 'daemon', None, _('run server in background')),
4416 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4416 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4417 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4417 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4418 # use string type, then we can check if something was passed
4418 # use string type, then we can check if something was passed
4419 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4419 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4420 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4420 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4421 _('ADDR')),
4421 _('ADDR')),
4422 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4422 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4423 _('PREFIX')),
4423 _('PREFIX')),
4424 ('n', 'name', '',
4424 ('n', 'name', '',
4425 _('name to show in web pages (default: working directory)'), _('NAME')),
4425 _('name to show in web pages (default: working directory)'), _('NAME')),
4426 ('', 'web-conf', '',
4426 ('', 'web-conf', '',
4427 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4427 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4428 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4428 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4429 _('FILE')),
4429 _('FILE')),
4430 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4430 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4431 ('', 'stdio', None, _('for remote clients')),
4431 ('', 'stdio', None, _('for remote clients')),
4432 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4432 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4433 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4433 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4434 ('', 'style', '', _('template style to use'), _('STYLE')),
4434 ('', 'style', '', _('template style to use'), _('STYLE')),
4435 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4435 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4436 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4436 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4437 _('[OPTION]...'))
4437 _('[OPTION]...'))
4438 def serve(ui, repo, **opts):
4438 def serve(ui, repo, **opts):
4439 """start stand-alone webserver
4439 """start stand-alone webserver
4440
4440
4441 Start a local HTTP repository browser and pull server. You can use
4441 Start a local HTTP repository browser and pull server. You can use
4442 this for ad-hoc sharing and browsing of repositories. It is
4442 this for ad-hoc sharing and browsing of repositories. It is
4443 recommended to use a real web server to serve a repository for
4443 recommended to use a real web server to serve a repository for
4444 longer periods of time.
4444 longer periods of time.
4445
4445
4446 Please note that the server does not implement access control.
4446 Please note that the server does not implement access control.
4447 This means that, by default, anybody can read from the server and
4447 This means that, by default, anybody can read from the server and
4448 nobody can write to it by default. Set the ``web.allow_push``
4448 nobody can write to it by default. Set the ``web.allow_push``
4449 option to ``*`` to allow everybody to push to the server. You
4449 option to ``*`` to allow everybody to push to the server. You
4450 should use a real web server if you need to authenticate users.
4450 should use a real web server if you need to authenticate users.
4451
4451
4452 By default, the server logs accesses to stdout and errors to
4452 By default, the server logs accesses to stdout and errors to
4453 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4453 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4454 files.
4454 files.
4455
4455
4456 To have the server choose a free port number to listen on, specify
4456 To have the server choose a free port number to listen on, specify
4457 a port number of 0; in this case, the server will print the port
4457 a port number of 0; in this case, the server will print the port
4458 number it uses.
4458 number it uses.
4459
4459
4460 Returns 0 on success.
4460 Returns 0 on success.
4461 """
4461 """
4462
4462
4463 if opts["stdio"] and opts["cmdserver"]:
4463 if opts["stdio"] and opts["cmdserver"]:
4464 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4464 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4465
4465
4466 def checkrepo():
4466 def checkrepo():
4467 if repo is None:
4467 if repo is None:
4468 raise error.RepoError(_("There is no Mercurial repository here"
4468 raise error.RepoError(_("There is no Mercurial repository here"
4469 " (.hg not found)"))
4469 " (.hg not found)"))
4470
4470
4471 if opts["stdio"]:
4471 if opts["stdio"]:
4472 checkrepo()
4472 checkrepo()
4473 s = sshserver.sshserver(ui, repo)
4473 s = sshserver.sshserver(ui, repo)
4474 s.serve_forever()
4474 s.serve_forever()
4475
4475
4476 if opts["cmdserver"]:
4476 if opts["cmdserver"]:
4477 checkrepo()
4477 checkrepo()
4478 s = commandserver.server(ui, repo, opts["cmdserver"])
4478 s = commandserver.server(ui, repo, opts["cmdserver"])
4479 return s.serve()
4479 return s.serve()
4480
4480
4481 # this way we can check if something was given in the command-line
4481 # this way we can check if something was given in the command-line
4482 if opts.get('port'):
4482 if opts.get('port'):
4483 opts['port'] = util.getport(opts.get('port'))
4483 opts['port'] = util.getport(opts.get('port'))
4484
4484
4485 baseui = repo and repo.baseui or ui
4485 baseui = repo and repo.baseui or ui
4486 optlist = ("name templates style address port prefix ipv6"
4486 optlist = ("name templates style address port prefix ipv6"
4487 " accesslog errorlog certificate encoding")
4487 " accesslog errorlog certificate encoding")
4488 for o in optlist.split():
4488 for o in optlist.split():
4489 val = opts.get(o, '')
4489 val = opts.get(o, '')
4490 if val in (None, ''): # should check against default options instead
4490 if val in (None, ''): # should check against default options instead
4491 continue
4491 continue
4492 baseui.setconfig("web", o, val)
4492 baseui.setconfig("web", o, val)
4493 if repo and repo.ui != baseui:
4493 if repo and repo.ui != baseui:
4494 repo.ui.setconfig("web", o, val)
4494 repo.ui.setconfig("web", o, val)
4495
4495
4496 o = opts.get('web_conf') or opts.get('webdir_conf')
4496 o = opts.get('web_conf') or opts.get('webdir_conf')
4497 if not o:
4497 if not o:
4498 if not repo:
4498 if not repo:
4499 raise error.RepoError(_("There is no Mercurial repository"
4499 raise error.RepoError(_("There is no Mercurial repository"
4500 " here (.hg not found)"))
4500 " here (.hg not found)"))
4501 o = repo.root
4501 o = repo.root
4502
4502
4503 app = hgweb.hgweb(o, baseui=ui)
4503 app = hgweb.hgweb(o, baseui=ui)
4504
4504
4505 class service(object):
4505 class service(object):
4506 def init(self):
4506 def init(self):
4507 util.setsignalhandler()
4507 util.setsignalhandler()
4508 self.httpd = hgweb.server.create_server(ui, app)
4508 self.httpd = hgweb.server.create_server(ui, app)
4509
4509
4510 if opts['port'] and not ui.verbose:
4510 if opts['port'] and not ui.verbose:
4511 return
4511 return
4512
4512
4513 if self.httpd.prefix:
4513 if self.httpd.prefix:
4514 prefix = self.httpd.prefix.strip('/') + '/'
4514 prefix = self.httpd.prefix.strip('/') + '/'
4515 else:
4515 else:
4516 prefix = ''
4516 prefix = ''
4517
4517
4518 port = ':%d' % self.httpd.port
4518 port = ':%d' % self.httpd.port
4519 if port == ':80':
4519 if port == ':80':
4520 port = ''
4520 port = ''
4521
4521
4522 bindaddr = self.httpd.addr
4522 bindaddr = self.httpd.addr
4523 if bindaddr == '0.0.0.0':
4523 if bindaddr == '0.0.0.0':
4524 bindaddr = '*'
4524 bindaddr = '*'
4525 elif ':' in bindaddr: # IPv6
4525 elif ':' in bindaddr: # IPv6
4526 bindaddr = '[%s]' % bindaddr
4526 bindaddr = '[%s]' % bindaddr
4527
4527
4528 fqaddr = self.httpd.fqaddr
4528 fqaddr = self.httpd.fqaddr
4529 if ':' in fqaddr:
4529 if ':' in fqaddr:
4530 fqaddr = '[%s]' % fqaddr
4530 fqaddr = '[%s]' % fqaddr
4531 if opts['port']:
4531 if opts['port']:
4532 write = ui.status
4532 write = ui.status
4533 else:
4533 else:
4534 write = ui.write
4534 write = ui.write
4535 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4535 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4536 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4536 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4537
4537
4538 def run(self):
4538 def run(self):
4539 self.httpd.serve_forever()
4539 self.httpd.serve_forever()
4540
4540
4541 service = service()
4541 service = service()
4542
4542
4543 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4543 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4544
4544
4545 @command('showconfig|debugconfig',
4545 @command('showconfig|debugconfig',
4546 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4546 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4547 _('[-u] [NAME]...'))
4547 _('[-u] [NAME]...'))
4548 def showconfig(ui, repo, *values, **opts):
4548 def showconfig(ui, repo, *values, **opts):
4549 """show combined config settings from all hgrc files
4549 """show combined config settings from all hgrc files
4550
4550
4551 With no arguments, print names and values of all config items.
4551 With no arguments, print names and values of all config items.
4552
4552
4553 With one argument of the form section.name, print just the value
4553 With one argument of the form section.name, print just the value
4554 of that config item.
4554 of that config item.
4555
4555
4556 With multiple arguments, print names and values of all config
4556 With multiple arguments, print names and values of all config
4557 items with matching section names.
4557 items with matching section names.
4558
4558
4559 With --debug, the source (filename and line number) is printed
4559 With --debug, the source (filename and line number) is printed
4560 for each config item.
4560 for each config item.
4561
4561
4562 Returns 0 on success.
4562 Returns 0 on success.
4563 """
4563 """
4564
4564
4565 for f in scmutil.rcpath():
4565 for f in scmutil.rcpath():
4566 ui.debug('read config from: %s\n' % f)
4566 ui.debug('read config from: %s\n' % f)
4567 untrusted = bool(opts.get('untrusted'))
4567 untrusted = bool(opts.get('untrusted'))
4568 if values:
4568 if values:
4569 sections = [v for v in values if '.' not in v]
4569 sections = [v for v in values if '.' not in v]
4570 items = [v for v in values if '.' in v]
4570 items = [v for v in values if '.' in v]
4571 if len(items) > 1 or items and sections:
4571 if len(items) > 1 or items and sections:
4572 raise util.Abort(_('only one config item permitted'))
4572 raise util.Abort(_('only one config item permitted'))
4573 for section, name, value in ui.walkconfig(untrusted=untrusted):
4573 for section, name, value in ui.walkconfig(untrusted=untrusted):
4574 value = str(value).replace('\n', '\\n')
4574 value = str(value).replace('\n', '\\n')
4575 sectname = section + '.' + name
4575 sectname = section + '.' + name
4576 if values:
4576 if values:
4577 for v in values:
4577 for v in values:
4578 if v == section:
4578 if v == section:
4579 ui.debug('%s: ' %
4579 ui.debug('%s: ' %
4580 ui.configsource(section, name, untrusted))
4580 ui.configsource(section, name, untrusted))
4581 ui.write('%s=%s\n' % (sectname, value))
4581 ui.write('%s=%s\n' % (sectname, value))
4582 elif v == sectname:
4582 elif v == sectname:
4583 ui.debug('%s: ' %
4583 ui.debug('%s: ' %
4584 ui.configsource(section, name, untrusted))
4584 ui.configsource(section, name, untrusted))
4585 ui.write(value, '\n')
4585 ui.write(value, '\n')
4586 else:
4586 else:
4587 ui.debug('%s: ' %
4587 ui.debug('%s: ' %
4588 ui.configsource(section, name, untrusted))
4588 ui.configsource(section, name, untrusted))
4589 ui.write('%s=%s\n' % (sectname, value))
4589 ui.write('%s=%s\n' % (sectname, value))
4590
4590
4591 @command('^status|st',
4591 @command('^status|st',
4592 [('A', 'all', None, _('show status of all files')),
4592 [('A', 'all', None, _('show status of all files')),
4593 ('m', 'modified', None, _('show only modified files')),
4593 ('m', 'modified', None, _('show only modified files')),
4594 ('a', 'added', None, _('show only added files')),
4594 ('a', 'added', None, _('show only added files')),
4595 ('r', 'removed', None, _('show only removed files')),
4595 ('r', 'removed', None, _('show only removed files')),
4596 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4596 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4597 ('c', 'clean', None, _('show only files without changes')),
4597 ('c', 'clean', None, _('show only files without changes')),
4598 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4598 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4599 ('i', 'ignored', None, _('show only ignored files')),
4599 ('i', 'ignored', None, _('show only ignored files')),
4600 ('n', 'no-status', None, _('hide status prefix')),
4600 ('n', 'no-status', None, _('hide status prefix')),
4601 ('C', 'copies', None, _('show source of copied files')),
4601 ('C', 'copies', None, _('show source of copied files')),
4602 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4602 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4603 ('', 'rev', [], _('show difference from revision'), _('REV')),
4603 ('', 'rev', [], _('show difference from revision'), _('REV')),
4604 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4604 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4605 ] + walkopts + subrepoopts,
4605 ] + walkopts + subrepoopts,
4606 _('[OPTION]... [FILE]...'))
4606 _('[OPTION]... [FILE]...'))
4607 def status(ui, repo, *pats, **opts):
4607 def status(ui, repo, *pats, **opts):
4608 """show changed files in the working directory
4608 """show changed files in the working directory
4609
4609
4610 Show status of files in the repository. If names are given, only
4610 Show status of files in the repository. If names are given, only
4611 files that match are shown. Files that are clean or ignored or
4611 files that match are shown. Files that are clean or ignored or
4612 the source of a copy/move operation, are not listed unless
4612 the source of a copy/move operation, are not listed unless
4613 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4613 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4614 Unless options described with "show only ..." are given, the
4614 Unless options described with "show only ..." are given, the
4615 options -mardu are used.
4615 options -mardu are used.
4616
4616
4617 Option -q/--quiet hides untracked (unknown and ignored) files
4617 Option -q/--quiet hides untracked (unknown and ignored) files
4618 unless explicitly requested with -u/--unknown or -i/--ignored.
4618 unless explicitly requested with -u/--unknown or -i/--ignored.
4619
4619
4620 .. note::
4620 .. note::
4621 status may appear to disagree with diff if permissions have
4621 status may appear to disagree with diff if permissions have
4622 changed or a merge has occurred. The standard diff format does
4622 changed or a merge has occurred. The standard diff format does
4623 not report permission changes and diff only reports changes
4623 not report permission changes and diff only reports changes
4624 relative to one merge parent.
4624 relative to one merge parent.
4625
4625
4626 If one revision is given, it is used as the base revision.
4626 If one revision is given, it is used as the base revision.
4627 If two revisions are given, the differences between them are
4627 If two revisions are given, the differences between them are
4628 shown. The --change option can also be used as a shortcut to list
4628 shown. The --change option can also be used as a shortcut to list
4629 the changed files of a revision from its first parent.
4629 the changed files of a revision from its first parent.
4630
4630
4631 The codes used to show the status of files are::
4631 The codes used to show the status of files are::
4632
4632
4633 M = modified
4633 M = modified
4634 A = added
4634 A = added
4635 R = removed
4635 R = removed
4636 C = clean
4636 C = clean
4637 ! = missing (deleted by non-hg command, but still tracked)
4637 ! = missing (deleted by non-hg command, but still tracked)
4638 ? = not tracked
4638 ? = not tracked
4639 I = ignored
4639 I = ignored
4640 = origin of the previous file listed as A (added)
4640 = origin of the previous file listed as A (added)
4641
4641
4642 Returns 0 on success.
4642 Returns 0 on success.
4643 """
4643 """
4644
4644
4645 revs = opts.get('rev')
4645 revs = opts.get('rev')
4646 change = opts.get('change')
4646 change = opts.get('change')
4647
4647
4648 if revs and change:
4648 if revs and change:
4649 msg = _('cannot specify --rev and --change at the same time')
4649 msg = _('cannot specify --rev and --change at the same time')
4650 raise util.Abort(msg)
4650 raise util.Abort(msg)
4651 elif change:
4651 elif change:
4652 node2 = repo.lookup(change)
4652 node2 = repo.lookup(change)
4653 node1 = repo[node2].p1().node()
4653 node1 = repo[node2].p1().node()
4654 else:
4654 else:
4655 node1, node2 = scmutil.revpair(repo, revs)
4655 node1, node2 = scmutil.revpair(repo, revs)
4656
4656
4657 cwd = (pats and repo.getcwd()) or ''
4657 cwd = (pats and repo.getcwd()) or ''
4658 end = opts.get('print0') and '\0' or '\n'
4658 end = opts.get('print0') and '\0' or '\n'
4659 copy = {}
4659 copy = {}
4660 states = 'modified added removed deleted unknown ignored clean'.split()
4660 states = 'modified added removed deleted unknown ignored clean'.split()
4661 show = [k for k in states if opts.get(k)]
4661 show = [k for k in states if opts.get(k)]
4662 if opts.get('all'):
4662 if opts.get('all'):
4663 show += ui.quiet and (states[:4] + ['clean']) or states
4663 show += ui.quiet and (states[:4] + ['clean']) or states
4664 if not show:
4664 if not show:
4665 show = ui.quiet and states[:4] or states[:5]
4665 show = ui.quiet and states[:4] or states[:5]
4666
4666
4667 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4667 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4668 'ignored' in show, 'clean' in show, 'unknown' in show,
4668 'ignored' in show, 'clean' in show, 'unknown' in show,
4669 opts.get('subrepos'))
4669 opts.get('subrepos'))
4670 changestates = zip(states, 'MAR!?IC', stat)
4670 changestates = zip(states, 'MAR!?IC', stat)
4671
4671
4672 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4672 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4673 ctxn = repo[nullid]
4673 ctxn = repo[nullid]
4674 ctx1 = repo[node1]
4674 ctx1 = repo[node1]
4675 ctx2 = repo[node2]
4675 ctx2 = repo[node2]
4676 added = stat[1]
4676 added = stat[1]
4677 if node2 is None:
4677 if node2 is None:
4678 added = stat[0] + stat[1] # merged?
4678 added = stat[0] + stat[1] # merged?
4679
4679
4680 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4680 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4681 if k in added:
4681 if k in added:
4682 copy[k] = v
4682 copy[k] = v
4683 elif v in added:
4683 elif v in added:
4684 copy[v] = k
4684 copy[v] = k
4685
4685
4686 for state, char, files in changestates:
4686 for state, char, files in changestates:
4687 if state in show:
4687 if state in show:
4688 format = "%s %%s%s" % (char, end)
4688 format = "%s %%s%s" % (char, end)
4689 if opts.get('no_status'):
4689 if opts.get('no_status'):
4690 format = "%%s%s" % end
4690 format = "%%s%s" % end
4691
4691
4692 for f in files:
4692 for f in files:
4693 ui.write(format % repo.pathto(f, cwd),
4693 ui.write(format % repo.pathto(f, cwd),
4694 label='status.' + state)
4694 label='status.' + state)
4695 if f in copy:
4695 if f in copy:
4696 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4696 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4697 label='status.copied')
4697 label='status.copied')
4698
4698
4699 @command('^summary|sum',
4699 @command('^summary|sum',
4700 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4700 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4701 def summary(ui, repo, **opts):
4701 def summary(ui, repo, **opts):
4702 """summarize working directory state
4702 """summarize working directory state
4703
4703
4704 This generates a brief summary of the working directory state,
4704 This generates a brief summary of the working directory state,
4705 including parents, branch, commit status, and available updates.
4705 including parents, branch, commit status, and available updates.
4706
4706
4707 With the --remote option, this will check the default paths for
4707 With the --remote option, this will check the default paths for
4708 incoming and outgoing changes. This can be time-consuming.
4708 incoming and outgoing changes. This can be time-consuming.
4709
4709
4710 Returns 0 on success.
4710 Returns 0 on success.
4711 """
4711 """
4712
4712
4713 ctx = repo[None]
4713 ctx = repo[None]
4714 parents = ctx.parents()
4714 parents = ctx.parents()
4715 pnode = parents[0].node()
4715 pnode = parents[0].node()
4716
4716
4717 for p in parents:
4717 for p in parents:
4718 # label with log.changeset (instead of log.parent) since this
4718 # label with log.changeset (instead of log.parent) since this
4719 # shows a working directory parent *changeset*:
4719 # shows a working directory parent *changeset*:
4720 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4720 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4721 label='log.changeset')
4721 label='log.changeset')
4722 ui.write(' '.join(p.tags()), label='log.tag')
4722 ui.write(' '.join(p.tags()), label='log.tag')
4723 if p.bookmarks():
4723 if p.bookmarks():
4724 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4724 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4725 if p.rev() == -1:
4725 if p.rev() == -1:
4726 if not len(repo):
4726 if not len(repo):
4727 ui.write(_(' (empty repository)'))
4727 ui.write(_(' (empty repository)'))
4728 else:
4728 else:
4729 ui.write(_(' (no revision checked out)'))
4729 ui.write(_(' (no revision checked out)'))
4730 ui.write('\n')
4730 ui.write('\n')
4731 if p.description():
4731 if p.description():
4732 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4732 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4733 label='log.summary')
4733 label='log.summary')
4734
4734
4735 branch = ctx.branch()
4735 branch = ctx.branch()
4736 bheads = repo.branchheads(branch)
4736 bheads = repo.branchheads(branch)
4737 m = _('branch: %s\n') % branch
4737 m = _('branch: %s\n') % branch
4738 if branch != 'default':
4738 if branch != 'default':
4739 ui.write(m, label='log.branch')
4739 ui.write(m, label='log.branch')
4740 else:
4740 else:
4741 ui.status(m, label='log.branch')
4741 ui.status(m, label='log.branch')
4742
4742
4743 st = list(repo.status(unknown=True))[:6]
4743 st = list(repo.status(unknown=True))[:6]
4744
4744
4745 c = repo.dirstate.copies()
4745 c = repo.dirstate.copies()
4746 copied, renamed = [], []
4746 copied, renamed = [], []
4747 for d, s in c.iteritems():
4747 for d, s in c.iteritems():
4748 if s in st[2]:
4748 if s in st[2]:
4749 st[2].remove(s)
4749 st[2].remove(s)
4750 renamed.append(d)
4750 renamed.append(d)
4751 else:
4751 else:
4752 copied.append(d)
4752 copied.append(d)
4753 if d in st[1]:
4753 if d in st[1]:
4754 st[1].remove(d)
4754 st[1].remove(d)
4755 st.insert(3, renamed)
4755 st.insert(3, renamed)
4756 st.insert(4, copied)
4756 st.insert(4, copied)
4757
4757
4758 ms = mergemod.mergestate(repo)
4758 ms = mergemod.mergestate(repo)
4759 st.append([f for f in ms if ms[f] == 'u'])
4759 st.append([f for f in ms if ms[f] == 'u'])
4760
4760
4761 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4761 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4762 st.append(subs)
4762 st.append(subs)
4763
4763
4764 labels = [ui.label(_('%d modified'), 'status.modified'),
4764 labels = [ui.label(_('%d modified'), 'status.modified'),
4765 ui.label(_('%d added'), 'status.added'),
4765 ui.label(_('%d added'), 'status.added'),
4766 ui.label(_('%d removed'), 'status.removed'),
4766 ui.label(_('%d removed'), 'status.removed'),
4767 ui.label(_('%d renamed'), 'status.copied'),
4767 ui.label(_('%d renamed'), 'status.copied'),
4768 ui.label(_('%d copied'), 'status.copied'),
4768 ui.label(_('%d copied'), 'status.copied'),
4769 ui.label(_('%d deleted'), 'status.deleted'),
4769 ui.label(_('%d deleted'), 'status.deleted'),
4770 ui.label(_('%d unknown'), 'status.unknown'),
4770 ui.label(_('%d unknown'), 'status.unknown'),
4771 ui.label(_('%d ignored'), 'status.ignored'),
4771 ui.label(_('%d ignored'), 'status.ignored'),
4772 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4772 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4773 ui.label(_('%d subrepos'), 'status.modified')]
4773 ui.label(_('%d subrepos'), 'status.modified')]
4774 t = []
4774 t = []
4775 for s, l in zip(st, labels):
4775 for s, l in zip(st, labels):
4776 if s:
4776 if s:
4777 t.append(l % len(s))
4777 t.append(l % len(s))
4778
4778
4779 t = ', '.join(t)
4779 t = ', '.join(t)
4780 cleanworkdir = False
4780 cleanworkdir = False
4781
4781
4782 if len(parents) > 1:
4782 if len(parents) > 1:
4783 t += _(' (merge)')
4783 t += _(' (merge)')
4784 elif branch != parents[0].branch():
4784 elif branch != parents[0].branch():
4785 t += _(' (new branch)')
4785 t += _(' (new branch)')
4786 elif (parents[0].extra().get('close') and
4786 elif (parents[0].extra().get('close') and
4787 pnode in repo.branchheads(branch, closed=True)):
4787 pnode in repo.branchheads(branch, closed=True)):
4788 t += _(' (head closed)')
4788 t += _(' (head closed)')
4789 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4789 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4790 t += _(' (clean)')
4790 t += _(' (clean)')
4791 cleanworkdir = True
4791 cleanworkdir = True
4792 elif pnode not in bheads:
4792 elif pnode not in bheads:
4793 t += _(' (new branch head)')
4793 t += _(' (new branch head)')
4794
4794
4795 if cleanworkdir:
4795 if cleanworkdir:
4796 ui.status(_('commit: %s\n') % t.strip())
4796 ui.status(_('commit: %s\n') % t.strip())
4797 else:
4797 else:
4798 ui.write(_('commit: %s\n') % t.strip())
4798 ui.write(_('commit: %s\n') % t.strip())
4799
4799
4800 # all ancestors of branch heads - all ancestors of parent = new csets
4800 # all ancestors of branch heads - all ancestors of parent = new csets
4801 new = [0] * len(repo)
4801 new = [0] * len(repo)
4802 cl = repo.changelog
4802 cl = repo.changelog
4803 for a in [cl.rev(n) for n in bheads]:
4803 for a in [cl.rev(n) for n in bheads]:
4804 new[a] = 1
4804 new[a] = 1
4805 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4805 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4806 new[a] = 1
4806 new[a] = 1
4807 for a in [p.rev() for p in parents]:
4807 for a in [p.rev() for p in parents]:
4808 if a >= 0:
4808 if a >= 0:
4809 new[a] = 0
4809 new[a] = 0
4810 for a in cl.ancestors(*[p.rev() for p in parents]):
4810 for a in cl.ancestors(*[p.rev() for p in parents]):
4811 new[a] = 0
4811 new[a] = 0
4812 new = sum(new)
4812 new = sum(new)
4813
4813
4814 if new == 0:
4814 if new == 0:
4815 ui.status(_('update: (current)\n'))
4815 ui.status(_('update: (current)\n'))
4816 elif pnode not in bheads:
4816 elif pnode not in bheads:
4817 ui.write(_('update: %d new changesets (update)\n') % new)
4817 ui.write(_('update: %d new changesets (update)\n') % new)
4818 else:
4818 else:
4819 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4819 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4820 (new, len(bheads)))
4820 (new, len(bheads)))
4821
4821
4822 if opts.get('remote'):
4822 if opts.get('remote'):
4823 t = []
4823 t = []
4824 source, branches = hg.parseurl(ui.expandpath('default'))
4824 source, branches = hg.parseurl(ui.expandpath('default'))
4825 other = hg.peer(repo, {}, source)
4825 other = hg.peer(repo, {}, source)
4826 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4826 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4827 ui.debug('comparing with %s\n' % util.hidepassword(source))
4827 ui.debug('comparing with %s\n' % util.hidepassword(source))
4828 repo.ui.pushbuffer()
4828 repo.ui.pushbuffer()
4829 commoninc = discovery.findcommonincoming(repo, other)
4829 commoninc = discovery.findcommonincoming(repo, other)
4830 _common, incoming, _rheads = commoninc
4830 _common, incoming, _rheads = commoninc
4831 repo.ui.popbuffer()
4831 repo.ui.popbuffer()
4832 if incoming:
4832 if incoming:
4833 t.append(_('1 or more incoming'))
4833 t.append(_('1 or more incoming'))
4834
4834
4835 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4835 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4836 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4836 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4837 if source != dest:
4837 if source != dest:
4838 other = hg.peer(repo, {}, dest)
4838 other = hg.peer(repo, {}, dest)
4839 commoninc = None
4839 commoninc = None
4840 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4840 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4841 repo.ui.pushbuffer()
4841 repo.ui.pushbuffer()
4842 common, outheads = discovery.findcommonoutgoing(repo, other,
4842 common, outheads = discovery.findcommonoutgoing(repo, other,
4843 commoninc=commoninc)
4843 commoninc=commoninc)
4844 repo.ui.popbuffer()
4844 repo.ui.popbuffer()
4845 o = repo.changelog.findmissing(common=common, heads=outheads)
4845 o = repo.changelog.findmissing(common=common, heads=outheads)
4846 if o:
4846 if o:
4847 t.append(_('%d outgoing') % len(o))
4847 t.append(_('%d outgoing') % len(o))
4848 if 'bookmarks' in other.listkeys('namespaces'):
4848 if 'bookmarks' in other.listkeys('namespaces'):
4849 lmarks = repo.listkeys('bookmarks')
4849 lmarks = repo.listkeys('bookmarks')
4850 rmarks = other.listkeys('bookmarks')
4850 rmarks = other.listkeys('bookmarks')
4851 diff = set(rmarks) - set(lmarks)
4851 diff = set(rmarks) - set(lmarks)
4852 if len(diff) > 0:
4852 if len(diff) > 0:
4853 t.append(_('%d incoming bookmarks') % len(diff))
4853 t.append(_('%d incoming bookmarks') % len(diff))
4854 diff = set(lmarks) - set(rmarks)
4854 diff = set(lmarks) - set(rmarks)
4855 if len(diff) > 0:
4855 if len(diff) > 0:
4856 t.append(_('%d outgoing bookmarks') % len(diff))
4856 t.append(_('%d outgoing bookmarks') % len(diff))
4857
4857
4858 if t:
4858 if t:
4859 ui.write(_('remote: %s\n') % (', '.join(t)))
4859 ui.write(_('remote: %s\n') % (', '.join(t)))
4860 else:
4860 else:
4861 ui.status(_('remote: (synced)\n'))
4861 ui.status(_('remote: (synced)\n'))
4862
4862
4863 @command('tag',
4863 @command('tag',
4864 [('f', 'force', None, _('force tag')),
4864 [('f', 'force', None, _('force tag')),
4865 ('l', 'local', None, _('make the tag local')),
4865 ('l', 'local', None, _('make the tag local')),
4866 ('r', 'rev', '', _('revision to tag'), _('REV')),
4866 ('r', 'rev', '', _('revision to tag'), _('REV')),
4867 ('', 'remove', None, _('remove a tag')),
4867 ('', 'remove', None, _('remove a tag')),
4868 # -l/--local is already there, commitopts cannot be used
4868 # -l/--local is already there, commitopts cannot be used
4869 ('e', 'edit', None, _('edit commit message')),
4869 ('e', 'edit', None, _('edit commit message')),
4870 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4870 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4871 ] + commitopts2,
4871 ] + commitopts2,
4872 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4872 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4873 def tag(ui, repo, name1, *names, **opts):
4873 def tag(ui, repo, name1, *names, **opts):
4874 """add one or more tags for the current or given revision
4874 """add one or more tags for the current or given revision
4875
4875
4876 Name a particular revision using <name>.
4876 Name a particular revision using <name>.
4877
4877
4878 Tags are used to name particular revisions of the repository and are
4878 Tags are used to name particular revisions of the repository and are
4879 very useful to compare different revisions, to go back to significant
4879 very useful to compare different revisions, to go back to significant
4880 earlier versions or to mark branch points as releases, etc. Changing
4880 earlier versions or to mark branch points as releases, etc. Changing
4881 an existing tag is normally disallowed; use -f/--force to override.
4881 an existing tag is normally disallowed; use -f/--force to override.
4882
4882
4883 If no revision is given, the parent of the working directory is
4883 If no revision is given, the parent of the working directory is
4884 used, or tip if no revision is checked out.
4884 used, or tip if no revision is checked out.
4885
4885
4886 To facilitate version control, distribution, and merging of tags,
4886 To facilitate version control, distribution, and merging of tags,
4887 they are stored as a file named ".hgtags" which is managed similarly
4887 they are stored as a file named ".hgtags" which is managed similarly
4888 to other project files and can be hand-edited if necessary. This
4888 to other project files and can be hand-edited if necessary. This
4889 also means that tagging creates a new commit. The file
4889 also means that tagging creates a new commit. The file
4890 ".hg/localtags" is used for local tags (not shared among
4890 ".hg/localtags" is used for local tags (not shared among
4891 repositories).
4891 repositories).
4892
4892
4893 Tag commits are usually made at the head of a branch. If the parent
4893 Tag commits are usually made at the head of a branch. If the parent
4894 of the working directory is not a branch head, :hg:`tag` aborts; use
4894 of the working directory is not a branch head, :hg:`tag` aborts; use
4895 -f/--force to force the tag commit to be based on a non-head
4895 -f/--force to force the tag commit to be based on a non-head
4896 changeset.
4896 changeset.
4897
4897
4898 See :hg:`help dates` for a list of formats valid for -d/--date.
4898 See :hg:`help dates` for a list of formats valid for -d/--date.
4899
4899
4900 Since tag names have priority over branch names during revision
4900 Since tag names have priority over branch names during revision
4901 lookup, using an existing branch name as a tag name is discouraged.
4901 lookup, using an existing branch name as a tag name is discouraged.
4902
4902
4903 Returns 0 on success.
4903 Returns 0 on success.
4904 """
4904 """
4905
4905
4906 rev_ = "."
4906 rev_ = "."
4907 names = [t.strip() for t in (name1,) + names]
4907 names = [t.strip() for t in (name1,) + names]
4908 if len(names) != len(set(names)):
4908 if len(names) != len(set(names)):
4909 raise util.Abort(_('tag names must be unique'))
4909 raise util.Abort(_('tag names must be unique'))
4910 for n in names:
4910 for n in names:
4911 if n in ['tip', '.', 'null']:
4911 if n in ['tip', '.', 'null']:
4912 raise util.Abort(_("the name '%s' is reserved") % n)
4912 raise util.Abort(_("the name '%s' is reserved") % n)
4913 if not n:
4913 if not n:
4914 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4914 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4915 if opts.get('rev') and opts.get('remove'):
4915 if opts.get('rev') and opts.get('remove'):
4916 raise util.Abort(_("--rev and --remove are incompatible"))
4916 raise util.Abort(_("--rev and --remove are incompatible"))
4917 if opts.get('rev'):
4917 if opts.get('rev'):
4918 rev_ = opts['rev']
4918 rev_ = opts['rev']
4919 message = opts.get('message')
4919 message = opts.get('message')
4920 if opts.get('remove'):
4920 if opts.get('remove'):
4921 expectedtype = opts.get('local') and 'local' or 'global'
4921 expectedtype = opts.get('local') and 'local' or 'global'
4922 for n in names:
4922 for n in names:
4923 if not repo.tagtype(n):
4923 if not repo.tagtype(n):
4924 raise util.Abort(_("tag '%s' does not exist") % n)
4924 raise util.Abort(_("tag '%s' does not exist") % n)
4925 if repo.tagtype(n) != expectedtype:
4925 if repo.tagtype(n) != expectedtype:
4926 if expectedtype == 'global':
4926 if expectedtype == 'global':
4927 raise util.Abort(_("tag '%s' is not a global tag") % n)
4927 raise util.Abort(_("tag '%s' is not a global tag") % n)
4928 else:
4928 else:
4929 raise util.Abort(_("tag '%s' is not a local tag") % n)
4929 raise util.Abort(_("tag '%s' is not a local tag") % n)
4930 rev_ = nullid
4930 rev_ = nullid
4931 if not message:
4931 if not message:
4932 # we don't translate commit messages
4932 # we don't translate commit messages
4933 message = 'Removed tag %s' % ', '.join(names)
4933 message = 'Removed tag %s' % ', '.join(names)
4934 elif not opts.get('force'):
4934 elif not opts.get('force'):
4935 for n in names:
4935 for n in names:
4936 if n in repo.tags():
4936 if n in repo.tags():
4937 raise util.Abort(_("tag '%s' already exists "
4937 raise util.Abort(_("tag '%s' already exists "
4938 "(use -f to force)") % n)
4938 "(use -f to force)") % n)
4939 if not opts.get('local'):
4939 if not opts.get('local'):
4940 p1, p2 = repo.dirstate.parents()
4940 p1, p2 = repo.dirstate.parents()
4941 if p2 != nullid:
4941 if p2 != nullid:
4942 raise util.Abort(_('uncommitted merge'))
4942 raise util.Abort(_('uncommitted merge'))
4943 bheads = repo.branchheads()
4943 bheads = repo.branchheads()
4944 if not opts.get('force') and bheads and p1 not in bheads:
4944 if not opts.get('force') and bheads and p1 not in bheads:
4945 raise util.Abort(_('not at a branch head (use -f to force)'))
4945 raise util.Abort(_('not at a branch head (use -f to force)'))
4946 r = scmutil.revsingle(repo, rev_).node()
4946 r = scmutil.revsingle(repo, rev_).node()
4947
4947
4948 if not message:
4948 if not message:
4949 # we don't translate commit messages
4949 # we don't translate commit messages
4950 message = ('Added tag %s for changeset %s' %
4950 message = ('Added tag %s for changeset %s' %
4951 (', '.join(names), short(r)))
4951 (', '.join(names), short(r)))
4952
4952
4953 date = opts.get('date')
4953 date = opts.get('date')
4954 if date:
4954 if date:
4955 date = util.parsedate(date)
4955 date = util.parsedate(date)
4956
4956
4957 if opts.get('edit'):
4957 if opts.get('edit'):
4958 message = ui.edit(message, ui.username())
4958 message = ui.edit(message, ui.username())
4959
4959
4960 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4960 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4961
4961
4962 @command('tags', [], '')
4962 @command('tags', [], '')
4963 def tags(ui, repo):
4963 def tags(ui, repo):
4964 """list repository tags
4964 """list repository tags
4965
4965
4966 This lists both regular and local tags. When the -v/--verbose
4966 This lists both regular and local tags. When the -v/--verbose
4967 switch is used, a third column "local" is printed for local tags.
4967 switch is used, a third column "local" is printed for local tags.
4968
4968
4969 Returns 0 on success.
4969 Returns 0 on success.
4970 """
4970 """
4971
4971
4972 hexfunc = ui.debugflag and hex or short
4972 hexfunc = ui.debugflag and hex or short
4973 tagtype = ""
4973 tagtype = ""
4974
4974
4975 for t, n in reversed(repo.tagslist()):
4975 for t, n in reversed(repo.tagslist()):
4976 if ui.quiet:
4976 if ui.quiet:
4977 ui.write("%s\n" % t)
4977 ui.write("%s\n" % t)
4978 continue
4978 continue
4979
4979
4980 hn = hexfunc(n)
4980 hn = hexfunc(n)
4981 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4981 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4982 spaces = " " * (30 - encoding.colwidth(t))
4982 spaces = " " * (30 - encoding.colwidth(t))
4983
4983
4984 if ui.verbose:
4984 if ui.verbose:
4985 if repo.tagtype(t) == 'local':
4985 if repo.tagtype(t) == 'local':
4986 tagtype = " local"
4986 tagtype = " local"
4987 else:
4987 else:
4988 tagtype = ""
4988 tagtype = ""
4989 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4989 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4990
4990
4991 @command('tip',
4991 @command('tip',
4992 [('p', 'patch', None, _('show patch')),
4992 [('p', 'patch', None, _('show patch')),
4993 ('g', 'git', None, _('use git extended diff format')),
4993 ('g', 'git', None, _('use git extended diff format')),
4994 ] + templateopts,
4994 ] + templateopts,
4995 _('[-p] [-g]'))
4995 _('[-p] [-g]'))
4996 def tip(ui, repo, **opts):
4996 def tip(ui, repo, **opts):
4997 """show the tip revision
4997 """show the tip revision
4998
4998
4999 The tip revision (usually just called the tip) is the changeset
4999 The tip revision (usually just called the tip) is the changeset
5000 most recently added to the repository (and therefore the most
5000 most recently added to the repository (and therefore the most
5001 recently changed head).
5001 recently changed head).
5002
5002
5003 If you have just made a commit, that commit will be the tip. If
5003 If you have just made a commit, that commit will be the tip. If
5004 you have just pulled changes from another repository, the tip of
5004 you have just pulled changes from another repository, the tip of
5005 that repository becomes the current tip. The "tip" tag is special
5005 that repository becomes the current tip. The "tip" tag is special
5006 and cannot be renamed or assigned to a different changeset.
5006 and cannot be renamed or assigned to a different changeset.
5007
5007
5008 Returns 0 on success.
5008 Returns 0 on success.
5009 """
5009 """
5010 displayer = cmdutil.show_changeset(ui, repo, opts)
5010 displayer = cmdutil.show_changeset(ui, repo, opts)
5011 displayer.show(repo[len(repo) - 1])
5011 displayer.show(repo[len(repo) - 1])
5012 displayer.close()
5012 displayer.close()
5013
5013
5014 @command('unbundle',
5014 @command('unbundle',
5015 [('u', 'update', None,
5015 [('u', 'update', None,
5016 _('update to new branch head if changesets were unbundled'))],
5016 _('update to new branch head if changesets were unbundled'))],
5017 _('[-u] FILE...'))
5017 _('[-u] FILE...'))
5018 def unbundle(ui, repo, fname1, *fnames, **opts):
5018 def unbundle(ui, repo, fname1, *fnames, **opts):
5019 """apply one or more changegroup files
5019 """apply one or more changegroup files
5020
5020
5021 Apply one or more compressed changegroup files generated by the
5021 Apply one or more compressed changegroup files generated by the
5022 bundle command.
5022 bundle command.
5023
5023
5024 Returns 0 on success, 1 if an update has unresolved files.
5024 Returns 0 on success, 1 if an update has unresolved files.
5025 """
5025 """
5026 fnames = (fname1,) + fnames
5026 fnames = (fname1,) + fnames
5027
5027
5028 lock = repo.lock()
5028 lock = repo.lock()
5029 wc = repo['.']
5029 wc = repo['.']
5030 try:
5030 try:
5031 for fname in fnames:
5031 for fname in fnames:
5032 f = url.open(ui, fname)
5032 f = url.open(ui, fname)
5033 gen = changegroup.readbundle(f, fname)
5033 gen = changegroup.readbundle(f, fname)
5034 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5034 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5035 lock=lock)
5035 lock=lock)
5036 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5036 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5037 finally:
5037 finally:
5038 lock.release()
5038 lock.release()
5039 return postincoming(ui, repo, modheads, opts.get('update'), None)
5039 return postincoming(ui, repo, modheads, opts.get('update'), None)
5040
5040
5041 @command('^update|up|checkout|co',
5041 @command('^update|up|checkout|co',
5042 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5042 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5043 ('c', 'check', None,
5043 ('c', 'check', None,
5044 _('update across branches if no uncommitted changes')),
5044 _('update across branches if no uncommitted changes')),
5045 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5045 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5046 ('r', 'rev', '', _('revision'), _('REV'))],
5046 ('r', 'rev', '', _('revision'), _('REV'))],
5047 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5047 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5048 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5048 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5049 """update working directory (or switch revisions)
5049 """update working directory (or switch revisions)
5050
5050
5051 Update the repository's working directory to the specified
5051 Update the repository's working directory to the specified
5052 changeset. If no changeset is specified, update to the tip of the
5052 changeset. If no changeset is specified, update to the tip of the
5053 current named branch.
5053 current named branch.
5054
5054
5055 If the changeset is not a descendant of the working directory's
5055 If the changeset is not a descendant of the working directory's
5056 parent, the update is aborted. With the -c/--check option, the
5056 parent, the update is aborted. With the -c/--check option, the
5057 working directory is checked for uncommitted changes; if none are
5057 working directory is checked for uncommitted changes; if none are
5058 found, the working directory is updated to the specified
5058 found, the working directory is updated to the specified
5059 changeset.
5059 changeset.
5060
5060
5061 Update sets the working directory's parent revison to the specified
5061 Update sets the working directory's parent revison to the specified
5062 changeset (see :hg:`help parents`).
5062 changeset (see :hg:`help parents`).
5063
5063
5064 The following rules apply when the working directory contains
5064 The following rules apply when the working directory contains
5065 uncommitted changes:
5065 uncommitted changes:
5066
5066
5067 1. If neither -c/--check nor -C/--clean is specified, and if
5067 1. If neither -c/--check nor -C/--clean is specified, and if
5068 the requested changeset is an ancestor or descendant of
5068 the requested changeset is an ancestor or descendant of
5069 the working directory's parent, the uncommitted changes
5069 the working directory's parent, the uncommitted changes
5070 are merged into the requested changeset and the merged
5070 are merged into the requested changeset and the merged
5071 result is left uncommitted. If the requested changeset is
5071 result is left uncommitted. If the requested changeset is
5072 not an ancestor or descendant (that is, it is on another
5072 not an ancestor or descendant (that is, it is on another
5073 branch), the update is aborted and the uncommitted changes
5073 branch), the update is aborted and the uncommitted changes
5074 are preserved.
5074 are preserved.
5075
5075
5076 2. With the -c/--check option, the update is aborted and the
5076 2. With the -c/--check option, the update is aborted and the
5077 uncommitted changes are preserved.
5077 uncommitted changes are preserved.
5078
5078
5079 3. With the -C/--clean option, uncommitted changes are discarded and
5079 3. With the -C/--clean option, uncommitted changes are discarded and
5080 the working directory is updated to the requested changeset.
5080 the working directory is updated to the requested changeset.
5081
5081
5082 Use null as the changeset to remove the working directory (like
5082 Use null as the changeset to remove the working directory (like
5083 :hg:`clone -U`).
5083 :hg:`clone -U`).
5084
5084
5085 If you want to update just one file to an older changeset, use
5085 If you want to revert just one file to an older revision, use
5086 :hg:`revert`.
5086 :hg:`revert [-r REV] NAME`.
5087
5087
5088 See :hg:`help dates` for a list of formats valid for -d/--date.
5088 See :hg:`help dates` for a list of formats valid for -d/--date.
5089
5089
5090 Returns 0 on success, 1 if there are unresolved files.
5090 Returns 0 on success, 1 if there are unresolved files.
5091 """
5091 """
5092 if rev and node:
5092 if rev and node:
5093 raise util.Abort(_("please specify just one revision"))
5093 raise util.Abort(_("please specify just one revision"))
5094
5094
5095 if rev is None or rev == '':
5095 if rev is None or rev == '':
5096 rev = node
5096 rev = node
5097
5097
5098 # if we defined a bookmark, we have to remember the original bookmark name
5098 # if we defined a bookmark, we have to remember the original bookmark name
5099 brev = rev
5099 brev = rev
5100 rev = scmutil.revsingle(repo, rev, rev).rev()
5100 rev = scmutil.revsingle(repo, rev, rev).rev()
5101
5101
5102 if check and clean:
5102 if check and clean:
5103 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5103 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5104
5104
5105 if check:
5105 if check:
5106 # we could use dirty() but we can ignore merge and branch trivia
5106 # we could use dirty() but we can ignore merge and branch trivia
5107 c = repo[None]
5107 c = repo[None]
5108 if c.modified() or c.added() or c.removed():
5108 if c.modified() or c.added() or c.removed():
5109 raise util.Abort(_("uncommitted local changes"))
5109 raise util.Abort(_("uncommitted local changes"))
5110
5110
5111 if date:
5111 if date:
5112 if rev is not None:
5112 if rev is not None:
5113 raise util.Abort(_("you can't specify a revision and a date"))
5113 raise util.Abort(_("you can't specify a revision and a date"))
5114 rev = cmdutil.finddate(ui, repo, date)
5114 rev = cmdutil.finddate(ui, repo, date)
5115
5115
5116 if clean or check:
5116 if clean or check:
5117 ret = hg.clean(repo, rev)
5117 ret = hg.clean(repo, rev)
5118 else:
5118 else:
5119 ret = hg.update(repo, rev)
5119 ret = hg.update(repo, rev)
5120
5120
5121 if brev in repo._bookmarks:
5121 if brev in repo._bookmarks:
5122 bookmarks.setcurrent(repo, brev)
5122 bookmarks.setcurrent(repo, brev)
5123
5123
5124 return ret
5124 return ret
5125
5125
5126 @command('verify', [])
5126 @command('verify', [])
5127 def verify(ui, repo):
5127 def verify(ui, repo):
5128 """verify the integrity of the repository
5128 """verify the integrity of the repository
5129
5129
5130 Verify the integrity of the current repository.
5130 Verify the integrity of the current repository.
5131
5131
5132 This will perform an extensive check of the repository's
5132 This will perform an extensive check of the repository's
5133 integrity, validating the hashes and checksums of each entry in
5133 integrity, validating the hashes and checksums of each entry in
5134 the changelog, manifest, and tracked files, as well as the
5134 the changelog, manifest, and tracked files, as well as the
5135 integrity of their crosslinks and indices.
5135 integrity of their crosslinks and indices.
5136
5136
5137 Returns 0 on success, 1 if errors are encountered.
5137 Returns 0 on success, 1 if errors are encountered.
5138 """
5138 """
5139 return hg.verify(repo)
5139 return hg.verify(repo)
5140
5140
5141 @command('version', [])
5141 @command('version', [])
5142 def version_(ui):
5142 def version_(ui):
5143 """output version and copyright information"""
5143 """output version and copyright information"""
5144 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5144 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5145 % util.version())
5145 % util.version())
5146 ui.status(_(
5146 ui.status(_(
5147 "(see http://mercurial.selenic.com for more information)\n"
5147 "(see http://mercurial.selenic.com for more information)\n"
5148 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5148 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5149 "This is free software; see the source for copying conditions. "
5149 "This is free software; see the source for copying conditions. "
5150 "There is NO\nwarranty; "
5150 "There is NO\nwarranty; "
5151 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5151 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5152 ))
5152 ))
5153
5153
5154 norepo = ("clone init version help debugcommands debugcomplete"
5154 norepo = ("clone init version help debugcommands debugcomplete"
5155 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5155 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5156 " debugknown debuggetbundle debugbundle")
5156 " debugknown debuggetbundle debugbundle")
5157 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5157 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5158 " debugdata debugindex debugindexdot debugrevlog")
5158 " debugdata debugindex debugindexdot debugrevlog")
General Comments 0
You need to be logged in to leave comments. Login now