##// END OF EJS Templates
remove: suggest forget to undo adds
Matt Mackall -
r15115:c84b3f42 default
parent child Browse files
Show More
@@ -1,5340 +1,5340 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 .. container:: verbose
310 .. container:: verbose
311
311
312 Examples:
312 Examples:
313
313
314 - create a zip file containing the 1.0 release::
314 - create a zip file containing the 1.0 release::
315
315
316 hg archive -r 1.0 project-1.0.zip
316 hg archive -r 1.0 project-1.0.zip
317
317
318 - create a tarball excluding .hg files::
318 - create a tarball excluding .hg files::
319
319
320 hg archive project.tar.gz -X ".hg*"
320 hg archive project.tar.gz -X ".hg*"
321
321
322 Valid types are:
322 Valid types are:
323
323
324 :``files``: a directory full of files (default)
324 :``files``: a directory full of files (default)
325 :``tar``: tar archive, uncompressed
325 :``tar``: tar archive, uncompressed
326 :``tbz2``: tar archive, compressed using bzip2
326 :``tbz2``: tar archive, compressed using bzip2
327 :``tgz``: tar archive, compressed using gzip
327 :``tgz``: tar archive, compressed using gzip
328 :``uzip``: zip archive, uncompressed
328 :``uzip``: zip archive, uncompressed
329 :``zip``: zip archive, compressed using deflate
329 :``zip``: zip archive, compressed using deflate
330
330
331 The exact name of the destination archive or directory is given
331 The exact name of the destination archive or directory is given
332 using a format string; see :hg:`help export` for details.
332 using a format string; see :hg:`help export` for details.
333
333
334 Each member added to an archive file has a directory prefix
334 Each member added to an archive file has a directory prefix
335 prepended. Use -p/--prefix to specify a format string for the
335 prepended. Use -p/--prefix to specify a format string for the
336 prefix. The default is the basename of the archive, with suffixes
336 prefix. The default is the basename of the archive, with suffixes
337 removed.
337 removed.
338
338
339 Returns 0 on success.
339 Returns 0 on success.
340 '''
340 '''
341
341
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 if not ctx:
343 if not ctx:
344 raise util.Abort(_('no working directory: please specify a revision'))
344 raise util.Abort(_('no working directory: please specify a revision'))
345 node = ctx.node()
345 node = ctx.node()
346 dest = cmdutil.makefilename(repo, dest, node)
346 dest = cmdutil.makefilename(repo, dest, node)
347 if os.path.realpath(dest) == repo.root:
347 if os.path.realpath(dest) == repo.root:
348 raise util.Abort(_('repository root cannot be destination'))
348 raise util.Abort(_('repository root cannot be destination'))
349
349
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 prefix = opts.get('prefix')
351 prefix = opts.get('prefix')
352
352
353 if dest == '-':
353 if dest == '-':
354 if kind == 'files':
354 if kind == 'files':
355 raise util.Abort(_('cannot archive plain files to stdout'))
355 raise util.Abort(_('cannot archive plain files to stdout'))
356 dest = cmdutil.makefileobj(repo, dest)
356 dest = cmdutil.makefileobj(repo, dest)
357 if not prefix:
357 if not prefix:
358 prefix = os.path.basename(repo.root) + '-%h'
358 prefix = os.path.basename(repo.root) + '-%h'
359
359
360 prefix = cmdutil.makefilename(repo, prefix, node)
360 prefix = cmdutil.makefilename(repo, prefix, node)
361 matchfn = scmutil.match(ctx, [], opts)
361 matchfn = scmutil.match(ctx, [], opts)
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 matchfn, prefix, subrepos=opts.get('subrepos'))
363 matchfn, prefix, subrepos=opts.get('subrepos'))
364
364
365 @command('backout',
365 @command('backout',
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
370 _('[OPTION]... [-r] REV'))
370 _('[OPTION]... [-r] REV'))
371 def backout(ui, repo, node=None, rev=None, **opts):
371 def backout(ui, repo, node=None, rev=None, **opts):
372 '''reverse effect of earlier changeset
372 '''reverse effect of earlier changeset
373
373
374 Prepare a new changeset with the effect of REV undone in the
374 Prepare a new changeset with the effect of REV undone in the
375 current working directory.
375 current working directory.
376
376
377 If REV is the parent of the working directory, then this new changeset
377 If REV is the parent of the working directory, then this new changeset
378 is committed automatically. Otherwise, hg needs to merge the
378 is committed automatically. Otherwise, hg needs to merge the
379 changes and the merged result is left uncommitted.
379 changes and the merged result is left uncommitted.
380
380
381 By default, the pending changeset will have one parent,
381 By default, the pending changeset will have one parent,
382 maintaining a linear history. With --merge, the pending changeset
382 maintaining a linear history. With --merge, the pending changeset
383 will instead have two parents: the old parent of the working
383 will instead have two parents: the old parent of the working
384 directory and a new child of REV that simply undoes REV.
384 directory and a new child of REV that simply undoes REV.
385
385
386 Before version 1.7, the behavior without --merge was equivalent to
386 Before version 1.7, the behavior without --merge was equivalent to
387 specifying --merge followed by :hg:`update --clean .` to cancel
387 specifying --merge followed by :hg:`update --clean .` to cancel
388 the merge and leave the child of REV as a head to be merged
388 the merge and leave the child of REV as a head to be merged
389 separately.
389 separately.
390
390
391 See :hg:`help dates` for a list of formats valid for -d/--date.
391 See :hg:`help dates` for a list of formats valid for -d/--date.
392
392
393 Returns 0 on success.
393 Returns 0 on success.
394 '''
394 '''
395 if rev and node:
395 if rev and node:
396 raise util.Abort(_("please specify just one revision"))
396 raise util.Abort(_("please specify just one revision"))
397
397
398 if not rev:
398 if not rev:
399 rev = node
399 rev = node
400
400
401 if not rev:
401 if not rev:
402 raise util.Abort(_("please specify a revision to backout"))
402 raise util.Abort(_("please specify a revision to backout"))
403
403
404 date = opts.get('date')
404 date = opts.get('date')
405 if date:
405 if date:
406 opts['date'] = util.parsedate(date)
406 opts['date'] = util.parsedate(date)
407
407
408 cmdutil.bailifchanged(repo)
408 cmdutil.bailifchanged(repo)
409 node = scmutil.revsingle(repo, rev).node()
409 node = scmutil.revsingle(repo, rev).node()
410
410
411 op1, op2 = repo.dirstate.parents()
411 op1, op2 = repo.dirstate.parents()
412 a = repo.changelog.ancestor(op1, node)
412 a = repo.changelog.ancestor(op1, node)
413 if a != node:
413 if a != node:
414 raise util.Abort(_('cannot backout change on a different branch'))
414 raise util.Abort(_('cannot backout change on a different branch'))
415
415
416 p1, p2 = repo.changelog.parents(node)
416 p1, p2 = repo.changelog.parents(node)
417 if p1 == nullid:
417 if p1 == nullid:
418 raise util.Abort(_('cannot backout a change with no parents'))
418 raise util.Abort(_('cannot backout a change with no parents'))
419 if p2 != nullid:
419 if p2 != nullid:
420 if not opts.get('parent'):
420 if not opts.get('parent'):
421 raise util.Abort(_('cannot backout a merge changeset without '
421 raise util.Abort(_('cannot backout a merge changeset without '
422 '--parent'))
422 '--parent'))
423 p = repo.lookup(opts['parent'])
423 p = repo.lookup(opts['parent'])
424 if p not in (p1, p2):
424 if p not in (p1, p2):
425 raise util.Abort(_('%s is not a parent of %s') %
425 raise util.Abort(_('%s is not a parent of %s') %
426 (short(p), short(node)))
426 (short(p), short(node)))
427 parent = p
427 parent = p
428 else:
428 else:
429 if opts.get('parent'):
429 if opts.get('parent'):
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
431 parent = p1
431 parent = p1
432
432
433 # the backout should appear on the same branch
433 # the backout should appear on the same branch
434 branch = repo.dirstate.branch()
434 branch = repo.dirstate.branch()
435 hg.clean(repo, node, show_stats=False)
435 hg.clean(repo, node, show_stats=False)
436 repo.dirstate.setbranch(branch)
436 repo.dirstate.setbranch(branch)
437 revert_opts = opts.copy()
437 revert_opts = opts.copy()
438 revert_opts['date'] = None
438 revert_opts['date'] = None
439 revert_opts['all'] = True
439 revert_opts['all'] = True
440 revert_opts['rev'] = hex(parent)
440 revert_opts['rev'] = hex(parent)
441 revert_opts['no_backup'] = None
441 revert_opts['no_backup'] = None
442 revert(ui, repo, **revert_opts)
442 revert(ui, repo, **revert_opts)
443 if not opts.get('merge') and op1 != node:
443 if not opts.get('merge') and op1 != node:
444 try:
444 try:
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
446 return hg.update(repo, op1)
446 return hg.update(repo, op1)
447 finally:
447 finally:
448 ui.setconfig('ui', 'forcemerge', '')
448 ui.setconfig('ui', 'forcemerge', '')
449
449
450 commit_opts = opts.copy()
450 commit_opts = opts.copy()
451 commit_opts['addremove'] = False
451 commit_opts['addremove'] = False
452 if not commit_opts['message'] and not commit_opts['logfile']:
452 if not commit_opts['message'] and not commit_opts['logfile']:
453 # we don't translate commit messages
453 # we don't translate commit messages
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
455 commit_opts['force_editor'] = True
455 commit_opts['force_editor'] = True
456 commit(ui, repo, **commit_opts)
456 commit(ui, repo, **commit_opts)
457 def nice(node):
457 def nice(node):
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
459 ui.status(_('changeset %s backs out changeset %s\n') %
459 ui.status(_('changeset %s backs out changeset %s\n') %
460 (nice(repo.changelog.tip()), nice(node)))
460 (nice(repo.changelog.tip()), nice(node)))
461 if opts.get('merge') and op1 != node:
461 if opts.get('merge') and op1 != node:
462 hg.clean(repo, op1, show_stats=False)
462 hg.clean(repo, op1, show_stats=False)
463 ui.status(_('merging with changeset %s\n')
463 ui.status(_('merging with changeset %s\n')
464 % nice(repo.changelog.tip()))
464 % nice(repo.changelog.tip()))
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.merge(repo, hex(repo.changelog.tip()))
467 return hg.merge(repo, hex(repo.changelog.tip()))
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470 return 0
470 return 0
471
471
472 @command('bisect',
472 @command('bisect',
473 [('r', 'reset', False, _('reset bisect state')),
473 [('r', 'reset', False, _('reset bisect state')),
474 ('g', 'good', False, _('mark changeset good')),
474 ('g', 'good', False, _('mark changeset good')),
475 ('b', 'bad', False, _('mark changeset bad')),
475 ('b', 'bad', False, _('mark changeset bad')),
476 ('s', 'skip', False, _('skip testing changeset')),
476 ('s', 'skip', False, _('skip testing changeset')),
477 ('e', 'extend', False, _('extend the bisect range')),
477 ('e', 'extend', False, _('extend the bisect range')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
479 ('U', 'noupdate', False, _('do not update to target'))],
479 ('U', 'noupdate', False, _('do not update to target'))],
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
481 def bisect(ui, repo, rev=None, extra=None, command=None,
481 def bisect(ui, repo, rev=None, extra=None, command=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
483 noupdate=None):
483 noupdate=None):
484 """subdivision search of changesets
484 """subdivision search of changesets
485
485
486 This command helps to find changesets which introduce problems. To
486 This command helps to find changesets which introduce problems. To
487 use, mark the earliest changeset you know exhibits the problem as
487 use, mark the earliest changeset you know exhibits the problem as
488 bad, then mark the latest changeset which is free from the problem
488 bad, then mark the latest changeset which is free from the problem
489 as good. Bisect will update your working directory to a revision
489 as good. Bisect will update your working directory to a revision
490 for testing (unless the -U/--noupdate option is specified). Once
490 for testing (unless the -U/--noupdate option is specified). Once
491 you have performed tests, mark the working directory as good or
491 you have performed tests, mark the working directory as good or
492 bad, and bisect will either update to another candidate changeset
492 bad, and bisect will either update to another candidate changeset
493 or announce that it has found the bad revision.
493 or announce that it has found the bad revision.
494
494
495 As a shortcut, you can also use the revision argument to mark a
495 As a shortcut, you can also use the revision argument to mark a
496 revision as good or bad without checking it out first.
496 revision as good or bad without checking it out first.
497
497
498 If you supply a command, it will be used for automatic bisection.
498 If you supply a command, it will be used for automatic bisection.
499 Its exit status will be used to mark revisions as good or bad:
499 Its exit status will be used to mark revisions as good or bad:
500 status 0 means good, 125 means to skip the revision, 127
500 status 0 means good, 125 means to skip the revision, 127
501 (command not found) will abort the bisection, and any other
501 (command not found) will abort the bisection, and any other
502 non-zero exit status means the revision is bad.
502 non-zero exit status means the revision is bad.
503
503
504 Returns 0 on success.
504 Returns 0 on success.
505 """
505 """
506 def extendbisectrange(nodes, good):
506 def extendbisectrange(nodes, good):
507 # bisect is incomplete when it ends on a merge node and
507 # bisect is incomplete when it ends on a merge node and
508 # one of the parent was not checked.
508 # one of the parent was not checked.
509 parents = repo[nodes[0]].parents()
509 parents = repo[nodes[0]].parents()
510 if len(parents) > 1:
510 if len(parents) > 1:
511 side = good and state['bad'] or state['good']
511 side = good and state['bad'] or state['good']
512 num = len(set(i.node() for i in parents) & set(side))
512 num = len(set(i.node() for i in parents) & set(side))
513 if num == 1:
513 if num == 1:
514 return parents[0].ancestor(parents[1])
514 return parents[0].ancestor(parents[1])
515 return None
515 return None
516
516
517 def print_result(nodes, good):
517 def print_result(nodes, good):
518 displayer = cmdutil.show_changeset(ui, repo, {})
518 displayer = cmdutil.show_changeset(ui, repo, {})
519 if len(nodes) == 1:
519 if len(nodes) == 1:
520 # narrowed it down to a single revision
520 # narrowed it down to a single revision
521 if good:
521 if good:
522 ui.write(_("The first good revision is:\n"))
522 ui.write(_("The first good revision is:\n"))
523 else:
523 else:
524 ui.write(_("The first bad revision is:\n"))
524 ui.write(_("The first bad revision is:\n"))
525 displayer.show(repo[nodes[0]])
525 displayer.show(repo[nodes[0]])
526 extendnode = extendbisectrange(nodes, good)
526 extendnode = extendbisectrange(nodes, good)
527 if extendnode is not None:
527 if extendnode is not None:
528 ui.write(_('Not all ancestors of this changeset have been'
528 ui.write(_('Not all ancestors of this changeset have been'
529 ' checked.\nUse bisect --extend to continue the '
529 ' checked.\nUse bisect --extend to continue the '
530 'bisection from\nthe common ancestor, %s.\n')
530 'bisection from\nthe common ancestor, %s.\n')
531 % extendnode)
531 % extendnode)
532 else:
532 else:
533 # multiple possible revisions
533 # multiple possible revisions
534 if good:
534 if good:
535 ui.write(_("Due to skipped revisions, the first "
535 ui.write(_("Due to skipped revisions, the first "
536 "good revision could be any of:\n"))
536 "good revision could be any of:\n"))
537 else:
537 else:
538 ui.write(_("Due to skipped revisions, the first "
538 ui.write(_("Due to skipped revisions, the first "
539 "bad revision could be any of:\n"))
539 "bad revision could be any of:\n"))
540 for n in nodes:
540 for n in nodes:
541 displayer.show(repo[n])
541 displayer.show(repo[n])
542 displayer.close()
542 displayer.close()
543
543
544 def check_state(state, interactive=True):
544 def check_state(state, interactive=True):
545 if not state['good'] or not state['bad']:
545 if not state['good'] or not state['bad']:
546 if (good or bad or skip or reset) and interactive:
546 if (good or bad or skip or reset) and interactive:
547 return
547 return
548 if not state['good']:
548 if not state['good']:
549 raise util.Abort(_('cannot bisect (no known good revisions)'))
549 raise util.Abort(_('cannot bisect (no known good revisions)'))
550 else:
550 else:
551 raise util.Abort(_('cannot bisect (no known bad revisions)'))
551 raise util.Abort(_('cannot bisect (no known bad revisions)'))
552 return True
552 return True
553
553
554 # backward compatibility
554 # backward compatibility
555 if rev in "good bad reset init".split():
555 if rev in "good bad reset init".split():
556 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
556 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
557 cmd, rev, extra = rev, extra, None
557 cmd, rev, extra = rev, extra, None
558 if cmd == "good":
558 if cmd == "good":
559 good = True
559 good = True
560 elif cmd == "bad":
560 elif cmd == "bad":
561 bad = True
561 bad = True
562 else:
562 else:
563 reset = True
563 reset = True
564 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
564 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
565 raise util.Abort(_('incompatible arguments'))
565 raise util.Abort(_('incompatible arguments'))
566
566
567 if reset:
567 if reset:
568 p = repo.join("bisect.state")
568 p = repo.join("bisect.state")
569 if os.path.exists(p):
569 if os.path.exists(p):
570 os.unlink(p)
570 os.unlink(p)
571 return
571 return
572
572
573 state = hbisect.load_state(repo)
573 state = hbisect.load_state(repo)
574
574
575 if command:
575 if command:
576 changesets = 1
576 changesets = 1
577 try:
577 try:
578 while changesets:
578 while changesets:
579 # update state
579 # update state
580 status = util.system(command, out=ui.fout)
580 status = util.system(command, out=ui.fout)
581 if status == 125:
581 if status == 125:
582 transition = "skip"
582 transition = "skip"
583 elif status == 0:
583 elif status == 0:
584 transition = "good"
584 transition = "good"
585 # status < 0 means process was killed
585 # status < 0 means process was killed
586 elif status == 127:
586 elif status == 127:
587 raise util.Abort(_("failed to execute %s") % command)
587 raise util.Abort(_("failed to execute %s") % command)
588 elif status < 0:
588 elif status < 0:
589 raise util.Abort(_("%s killed") % command)
589 raise util.Abort(_("%s killed") % command)
590 else:
590 else:
591 transition = "bad"
591 transition = "bad"
592 ctx = scmutil.revsingle(repo, rev)
592 ctx = scmutil.revsingle(repo, rev)
593 rev = None # clear for future iterations
593 rev = None # clear for future iterations
594 state[transition].append(ctx.node())
594 state[transition].append(ctx.node())
595 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
595 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
596 check_state(state, interactive=False)
596 check_state(state, interactive=False)
597 # bisect
597 # bisect
598 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
598 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
599 # update to next check
599 # update to next check
600 cmdutil.bailifchanged(repo)
600 cmdutil.bailifchanged(repo)
601 hg.clean(repo, nodes[0], show_stats=False)
601 hg.clean(repo, nodes[0], show_stats=False)
602 finally:
602 finally:
603 hbisect.save_state(repo, state)
603 hbisect.save_state(repo, state)
604 print_result(nodes, good)
604 print_result(nodes, good)
605 return
605 return
606
606
607 # update state
607 # update state
608
608
609 if rev:
609 if rev:
610 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
610 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
611 else:
611 else:
612 nodes = [repo.lookup('.')]
612 nodes = [repo.lookup('.')]
613
613
614 if good or bad or skip:
614 if good or bad or skip:
615 if good:
615 if good:
616 state['good'] += nodes
616 state['good'] += nodes
617 elif bad:
617 elif bad:
618 state['bad'] += nodes
618 state['bad'] += nodes
619 elif skip:
619 elif skip:
620 state['skip'] += nodes
620 state['skip'] += nodes
621 hbisect.save_state(repo, state)
621 hbisect.save_state(repo, state)
622
622
623 if not check_state(state):
623 if not check_state(state):
624 return
624 return
625
625
626 # actually bisect
626 # actually bisect
627 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
627 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
628 if extend:
628 if extend:
629 if not changesets:
629 if not changesets:
630 extendnode = extendbisectrange(nodes, good)
630 extendnode = extendbisectrange(nodes, good)
631 if extendnode is not None:
631 if extendnode is not None:
632 ui.write(_("Extending search to changeset %d:%s\n"
632 ui.write(_("Extending search to changeset %d:%s\n"
633 % (extendnode.rev(), extendnode)))
633 % (extendnode.rev(), extendnode)))
634 if noupdate:
634 if noupdate:
635 return
635 return
636 cmdutil.bailifchanged(repo)
636 cmdutil.bailifchanged(repo)
637 return hg.clean(repo, extendnode.node())
637 return hg.clean(repo, extendnode.node())
638 raise util.Abort(_("nothing to extend"))
638 raise util.Abort(_("nothing to extend"))
639
639
640 if changesets == 0:
640 if changesets == 0:
641 print_result(nodes, good)
641 print_result(nodes, good)
642 else:
642 else:
643 assert len(nodes) == 1 # only a single node can be tested next
643 assert len(nodes) == 1 # only a single node can be tested next
644 node = nodes[0]
644 node = nodes[0]
645 # compute the approximate number of remaining tests
645 # compute the approximate number of remaining tests
646 tests, size = 0, 2
646 tests, size = 0, 2
647 while size <= changesets:
647 while size <= changesets:
648 tests, size = tests + 1, size * 2
648 tests, size = tests + 1, size * 2
649 rev = repo.changelog.rev(node)
649 rev = repo.changelog.rev(node)
650 ui.write(_("Testing changeset %d:%s "
650 ui.write(_("Testing changeset %d:%s "
651 "(%d changesets remaining, ~%d tests)\n")
651 "(%d changesets remaining, ~%d tests)\n")
652 % (rev, short(node), changesets, tests))
652 % (rev, short(node), changesets, tests))
653 if not noupdate:
653 if not noupdate:
654 cmdutil.bailifchanged(repo)
654 cmdutil.bailifchanged(repo)
655 return hg.clean(repo, node)
655 return hg.clean(repo, node)
656
656
657 @command('bookmarks',
657 @command('bookmarks',
658 [('f', 'force', False, _('force')),
658 [('f', 'force', False, _('force')),
659 ('r', 'rev', '', _('revision'), _('REV')),
659 ('r', 'rev', '', _('revision'), _('REV')),
660 ('d', 'delete', False, _('delete a given bookmark')),
660 ('d', 'delete', False, _('delete a given bookmark')),
661 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
661 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
662 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
662 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
663 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
663 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
664 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
664 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
665 rename=None, inactive=False):
665 rename=None, inactive=False):
666 '''track a line of development with movable markers
666 '''track a line of development with movable markers
667
667
668 Bookmarks are pointers to certain commits that move when
668 Bookmarks are pointers to certain commits that move when
669 committing. Bookmarks are local. They can be renamed, copied and
669 committing. Bookmarks are local. They can be renamed, copied and
670 deleted. It is possible to use bookmark names in :hg:`merge` and
670 deleted. It is possible to use bookmark names in :hg:`merge` and
671 :hg:`update` to merge and update respectively to a given bookmark.
671 :hg:`update` to merge and update respectively to a given bookmark.
672
672
673 You can use :hg:`bookmark NAME` to set a bookmark on the working
673 You can use :hg:`bookmark NAME` to set a bookmark on the working
674 directory's parent revision with the given name. If you specify
674 directory's parent revision with the given name. If you specify
675 a revision using -r REV (where REV may be an existing bookmark),
675 a revision using -r REV (where REV may be an existing bookmark),
676 the bookmark is assigned to that revision.
676 the bookmark is assigned to that revision.
677
677
678 Bookmarks can be pushed and pulled between repositories (see :hg:`help
678 Bookmarks can be pushed and pulled between repositories (see :hg:`help
679 push` and :hg:`help pull`). This requires both the local and remote
679 push` and :hg:`help pull`). This requires both the local and remote
680 repositories to support bookmarks. For versions prior to 1.8, this means
680 repositories to support bookmarks. For versions prior to 1.8, this means
681 the bookmarks extension must be enabled.
681 the bookmarks extension must be enabled.
682 '''
682 '''
683 hexfn = ui.debugflag and hex or short
683 hexfn = ui.debugflag and hex or short
684 marks = repo._bookmarks
684 marks = repo._bookmarks
685 cur = repo.changectx('.').node()
685 cur = repo.changectx('.').node()
686
686
687 if rename:
687 if rename:
688 if rename not in marks:
688 if rename not in marks:
689 raise util.Abort(_("bookmark '%s' does not exist") % rename)
689 raise util.Abort(_("bookmark '%s' does not exist") % rename)
690 if mark in marks and not force:
690 if mark in marks and not force:
691 raise util.Abort(_("bookmark '%s' already exists "
691 raise util.Abort(_("bookmark '%s' already exists "
692 "(use -f to force)") % mark)
692 "(use -f to force)") % mark)
693 if mark is None:
693 if mark is None:
694 raise util.Abort(_("new bookmark name required"))
694 raise util.Abort(_("new bookmark name required"))
695 marks[mark] = marks[rename]
695 marks[mark] = marks[rename]
696 if repo._bookmarkcurrent == rename and not inactive:
696 if repo._bookmarkcurrent == rename and not inactive:
697 bookmarks.setcurrent(repo, mark)
697 bookmarks.setcurrent(repo, mark)
698 del marks[rename]
698 del marks[rename]
699 bookmarks.write(repo)
699 bookmarks.write(repo)
700 return
700 return
701
701
702 if delete:
702 if delete:
703 if mark is None:
703 if mark is None:
704 raise util.Abort(_("bookmark name required"))
704 raise util.Abort(_("bookmark name required"))
705 if mark not in marks:
705 if mark not in marks:
706 raise util.Abort(_("bookmark '%s' does not exist") % mark)
706 raise util.Abort(_("bookmark '%s' does not exist") % mark)
707 if mark == repo._bookmarkcurrent:
707 if mark == repo._bookmarkcurrent:
708 bookmarks.setcurrent(repo, None)
708 bookmarks.setcurrent(repo, None)
709 del marks[mark]
709 del marks[mark]
710 bookmarks.write(repo)
710 bookmarks.write(repo)
711 return
711 return
712
712
713 if mark is not None:
713 if mark is not None:
714 if "\n" in mark:
714 if "\n" in mark:
715 raise util.Abort(_("bookmark name cannot contain newlines"))
715 raise util.Abort(_("bookmark name cannot contain newlines"))
716 mark = mark.strip()
716 mark = mark.strip()
717 if not mark:
717 if not mark:
718 raise util.Abort(_("bookmark names cannot consist entirely of "
718 raise util.Abort(_("bookmark names cannot consist entirely of "
719 "whitespace"))
719 "whitespace"))
720 if inactive and mark == repo._bookmarkcurrent:
720 if inactive and mark == repo._bookmarkcurrent:
721 bookmarks.setcurrent(repo, None)
721 bookmarks.setcurrent(repo, None)
722 return
722 return
723 if mark in marks and not force:
723 if mark in marks and not force:
724 raise util.Abort(_("bookmark '%s' already exists "
724 raise util.Abort(_("bookmark '%s' already exists "
725 "(use -f to force)") % mark)
725 "(use -f to force)") % mark)
726 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
726 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
727 and not force):
727 and not force):
728 raise util.Abort(
728 raise util.Abort(
729 _("a bookmark cannot have the name of an existing branch"))
729 _("a bookmark cannot have the name of an existing branch"))
730 if rev:
730 if rev:
731 marks[mark] = repo.lookup(rev)
731 marks[mark] = repo.lookup(rev)
732 else:
732 else:
733 marks[mark] = repo.changectx('.').node()
733 marks[mark] = repo.changectx('.').node()
734 if not inactive and repo.changectx('.').node() == marks[mark]:
734 if not inactive and repo.changectx('.').node() == marks[mark]:
735 bookmarks.setcurrent(repo, mark)
735 bookmarks.setcurrent(repo, mark)
736 bookmarks.write(repo)
736 bookmarks.write(repo)
737 return
737 return
738
738
739 if mark is None:
739 if mark is None:
740 if rev:
740 if rev:
741 raise util.Abort(_("bookmark name required"))
741 raise util.Abort(_("bookmark name required"))
742 if len(marks) == 0:
742 if len(marks) == 0:
743 ui.status(_("no bookmarks set\n"))
743 ui.status(_("no bookmarks set\n"))
744 else:
744 else:
745 for bmark, n in sorted(marks.iteritems()):
745 for bmark, n in sorted(marks.iteritems()):
746 current = repo._bookmarkcurrent
746 current = repo._bookmarkcurrent
747 if bmark == current and n == cur:
747 if bmark == current and n == cur:
748 prefix, label = '*', 'bookmarks.current'
748 prefix, label = '*', 'bookmarks.current'
749 else:
749 else:
750 prefix, label = ' ', ''
750 prefix, label = ' ', ''
751
751
752 if ui.quiet:
752 if ui.quiet:
753 ui.write("%s\n" % bmark, label=label)
753 ui.write("%s\n" % bmark, label=label)
754 else:
754 else:
755 ui.write(" %s %-25s %d:%s\n" % (
755 ui.write(" %s %-25s %d:%s\n" % (
756 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
756 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
757 label=label)
757 label=label)
758 return
758 return
759
759
760 @command('branch',
760 @command('branch',
761 [('f', 'force', None,
761 [('f', 'force', None,
762 _('set branch name even if it shadows an existing branch')),
762 _('set branch name even if it shadows an existing branch')),
763 ('C', 'clean', None, _('reset branch name to parent branch name'))],
763 ('C', 'clean', None, _('reset branch name to parent branch name'))],
764 _('[-fC] [NAME]'))
764 _('[-fC] [NAME]'))
765 def branch(ui, repo, label=None, **opts):
765 def branch(ui, repo, label=None, **opts):
766 """set or show the current branch name
766 """set or show the current branch name
767
767
768 With no argument, show the current branch name. With one argument,
768 With no argument, show the current branch name. With one argument,
769 set the working directory branch name (the branch will not exist
769 set the working directory branch name (the branch will not exist
770 in the repository until the next commit). Standard practice
770 in the repository until the next commit). Standard practice
771 recommends that primary development take place on the 'default'
771 recommends that primary development take place on the 'default'
772 branch.
772 branch.
773
773
774 Unless -f/--force is specified, branch will not let you set a
774 Unless -f/--force is specified, branch will not let you set a
775 branch name that already exists, even if it's inactive.
775 branch name that already exists, even if it's inactive.
776
776
777 Use -C/--clean to reset the working directory branch to that of
777 Use -C/--clean to reset the working directory branch to that of
778 the parent of the working directory, negating a previous branch
778 the parent of the working directory, negating a previous branch
779 change.
779 change.
780
780
781 Use the command :hg:`update` to switch to an existing branch. Use
781 Use the command :hg:`update` to switch to an existing branch. Use
782 :hg:`commit --close-branch` to mark this branch as closed.
782 :hg:`commit --close-branch` to mark this branch as closed.
783
783
784 .. note::
784 .. note::
785
785
786 Branch names are permanent. Use :hg:`bookmark` to create a
786 Branch names are permanent. Use :hg:`bookmark` to create a
787 light-weight bookmark instead. See :hg:`help glossary` for more
787 light-weight bookmark instead. See :hg:`help glossary` for more
788 information about named branches and bookmarks.
788 information about named branches and bookmarks.
789
789
790 Returns 0 on success.
790 Returns 0 on success.
791 """
791 """
792
792
793 if opts.get('clean'):
793 if opts.get('clean'):
794 label = repo[None].p1().branch()
794 label = repo[None].p1().branch()
795 repo.dirstate.setbranch(label)
795 repo.dirstate.setbranch(label)
796 ui.status(_('reset working directory to branch %s\n') % label)
796 ui.status(_('reset working directory to branch %s\n') % label)
797 elif label:
797 elif label:
798 if not opts.get('force') and label in repo.branchtags():
798 if not opts.get('force') and label in repo.branchtags():
799 if label not in [p.branch() for p in repo.parents()]:
799 if label not in [p.branch() for p in repo.parents()]:
800 raise util.Abort(_('a branch of the same name already exists'),
800 raise util.Abort(_('a branch of the same name already exists'),
801 # i18n: "it" refers to an existing branch
801 # i18n: "it" refers to an existing branch
802 hint=_("use 'hg update' to switch to it"))
802 hint=_("use 'hg update' to switch to it"))
803 repo.dirstate.setbranch(label)
803 repo.dirstate.setbranch(label)
804 ui.status(_('marked working directory as branch %s\n') % label)
804 ui.status(_('marked working directory as branch %s\n') % label)
805 else:
805 else:
806 ui.write("%s\n" % repo.dirstate.branch())
806 ui.write("%s\n" % repo.dirstate.branch())
807
807
808 @command('branches',
808 @command('branches',
809 [('a', 'active', False, _('show only branches that have unmerged heads')),
809 [('a', 'active', False, _('show only branches that have unmerged heads')),
810 ('c', 'closed', False, _('show normal and closed branches'))],
810 ('c', 'closed', False, _('show normal and closed branches'))],
811 _('[-ac]'))
811 _('[-ac]'))
812 def branches(ui, repo, active=False, closed=False):
812 def branches(ui, repo, active=False, closed=False):
813 """list repository named branches
813 """list repository named branches
814
814
815 List the repository's named branches, indicating which ones are
815 List the repository's named branches, indicating which ones are
816 inactive. If -c/--closed is specified, also list branches which have
816 inactive. If -c/--closed is specified, also list branches which have
817 been marked closed (see :hg:`commit --close-branch`).
817 been marked closed (see :hg:`commit --close-branch`).
818
818
819 If -a/--active is specified, only show active branches. A branch
819 If -a/--active is specified, only show active branches. A branch
820 is considered active if it contains repository heads.
820 is considered active if it contains repository heads.
821
821
822 Use the command :hg:`update` to switch to an existing branch.
822 Use the command :hg:`update` to switch to an existing branch.
823
823
824 Returns 0.
824 Returns 0.
825 """
825 """
826
826
827 hexfunc = ui.debugflag and hex or short
827 hexfunc = ui.debugflag and hex or short
828 activebranches = [repo[n].branch() for n in repo.heads()]
828 activebranches = [repo[n].branch() for n in repo.heads()]
829 def testactive(tag, node):
829 def testactive(tag, node):
830 realhead = tag in activebranches
830 realhead = tag in activebranches
831 open = node in repo.branchheads(tag, closed=False)
831 open = node in repo.branchheads(tag, closed=False)
832 return realhead and open
832 return realhead and open
833 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
833 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
834 for tag, node in repo.branchtags().items()],
834 for tag, node in repo.branchtags().items()],
835 reverse=True)
835 reverse=True)
836
836
837 for isactive, node, tag in branches:
837 for isactive, node, tag in branches:
838 if (not active) or isactive:
838 if (not active) or isactive:
839 if ui.quiet:
839 if ui.quiet:
840 ui.write("%s\n" % tag)
840 ui.write("%s\n" % tag)
841 else:
841 else:
842 hn = repo.lookup(node)
842 hn = repo.lookup(node)
843 if isactive:
843 if isactive:
844 label = 'branches.active'
844 label = 'branches.active'
845 notice = ''
845 notice = ''
846 elif hn not in repo.branchheads(tag, closed=False):
846 elif hn not in repo.branchheads(tag, closed=False):
847 if not closed:
847 if not closed:
848 continue
848 continue
849 label = 'branches.closed'
849 label = 'branches.closed'
850 notice = _(' (closed)')
850 notice = _(' (closed)')
851 else:
851 else:
852 label = 'branches.inactive'
852 label = 'branches.inactive'
853 notice = _(' (inactive)')
853 notice = _(' (inactive)')
854 if tag == repo.dirstate.branch():
854 if tag == repo.dirstate.branch():
855 label = 'branches.current'
855 label = 'branches.current'
856 rev = str(node).rjust(31 - encoding.colwidth(tag))
856 rev = str(node).rjust(31 - encoding.colwidth(tag))
857 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
857 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
858 tag = ui.label(tag, label)
858 tag = ui.label(tag, label)
859 ui.write("%s %s%s\n" % (tag, rev, notice))
859 ui.write("%s %s%s\n" % (tag, rev, notice))
860
860
861 @command('bundle',
861 @command('bundle',
862 [('f', 'force', None, _('run even when the destination is unrelated')),
862 [('f', 'force', None, _('run even when the destination is unrelated')),
863 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
863 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
864 _('REV')),
864 _('REV')),
865 ('b', 'branch', [], _('a specific branch you would like to bundle'),
865 ('b', 'branch', [], _('a specific branch you would like to bundle'),
866 _('BRANCH')),
866 _('BRANCH')),
867 ('', 'base', [],
867 ('', 'base', [],
868 _('a base changeset assumed to be available at the destination'),
868 _('a base changeset assumed to be available at the destination'),
869 _('REV')),
869 _('REV')),
870 ('a', 'all', None, _('bundle all changesets in the repository')),
870 ('a', 'all', None, _('bundle all changesets in the repository')),
871 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
871 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
872 ] + remoteopts,
872 ] + remoteopts,
873 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
873 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
874 def bundle(ui, repo, fname, dest=None, **opts):
874 def bundle(ui, repo, fname, dest=None, **opts):
875 """create a changegroup file
875 """create a changegroup file
876
876
877 Generate a compressed changegroup file collecting changesets not
877 Generate a compressed changegroup file collecting changesets not
878 known to be in another repository.
878 known to be in another repository.
879
879
880 If you omit the destination repository, then hg assumes the
880 If you omit the destination repository, then hg assumes the
881 destination will have all the nodes you specify with --base
881 destination will have all the nodes you specify with --base
882 parameters. To create a bundle containing all changesets, use
882 parameters. To create a bundle containing all changesets, use
883 -a/--all (or --base null).
883 -a/--all (or --base null).
884
884
885 You can change compression method with the -t/--type option.
885 You can change compression method with the -t/--type option.
886 The available compression methods are: none, bzip2, and
886 The available compression methods are: none, bzip2, and
887 gzip (by default, bundles are compressed using bzip2).
887 gzip (by default, bundles are compressed using bzip2).
888
888
889 The bundle file can then be transferred using conventional means
889 The bundle file can then be transferred using conventional means
890 and applied to another repository with the unbundle or pull
890 and applied to another repository with the unbundle or pull
891 command. This is useful when direct push and pull are not
891 command. This is useful when direct push and pull are not
892 available or when exporting an entire repository is undesirable.
892 available or when exporting an entire repository is undesirable.
893
893
894 Applying bundles preserves all changeset contents including
894 Applying bundles preserves all changeset contents including
895 permissions, copy/rename information, and revision history.
895 permissions, copy/rename information, and revision history.
896
896
897 Returns 0 on success, 1 if no changes found.
897 Returns 0 on success, 1 if no changes found.
898 """
898 """
899 revs = None
899 revs = None
900 if 'rev' in opts:
900 if 'rev' in opts:
901 revs = scmutil.revrange(repo, opts['rev'])
901 revs = scmutil.revrange(repo, opts['rev'])
902
902
903 if opts.get('all'):
903 if opts.get('all'):
904 base = ['null']
904 base = ['null']
905 else:
905 else:
906 base = scmutil.revrange(repo, opts.get('base'))
906 base = scmutil.revrange(repo, opts.get('base'))
907 if base:
907 if base:
908 if dest:
908 if dest:
909 raise util.Abort(_("--base is incompatible with specifying "
909 raise util.Abort(_("--base is incompatible with specifying "
910 "a destination"))
910 "a destination"))
911 common = [repo.lookup(rev) for rev in base]
911 common = [repo.lookup(rev) for rev in base]
912 heads = revs and map(repo.lookup, revs) or revs
912 heads = revs and map(repo.lookup, revs) or revs
913 else:
913 else:
914 dest = ui.expandpath(dest or 'default-push', dest or 'default')
914 dest = ui.expandpath(dest or 'default-push', dest or 'default')
915 dest, branches = hg.parseurl(dest, opts.get('branch'))
915 dest, branches = hg.parseurl(dest, opts.get('branch'))
916 other = hg.peer(repo, opts, dest)
916 other = hg.peer(repo, opts, dest)
917 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
917 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
918 heads = revs and map(repo.lookup, revs) or revs
918 heads = revs and map(repo.lookup, revs) or revs
919 common, outheads = discovery.findcommonoutgoing(repo, other,
919 common, outheads = discovery.findcommonoutgoing(repo, other,
920 onlyheads=heads,
920 onlyheads=heads,
921 force=opts.get('force'))
921 force=opts.get('force'))
922
922
923 cg = repo.getbundle('bundle', common=common, heads=heads)
923 cg = repo.getbundle('bundle', common=common, heads=heads)
924 if not cg:
924 if not cg:
925 ui.status(_("no changes found\n"))
925 ui.status(_("no changes found\n"))
926 return 1
926 return 1
927
927
928 bundletype = opts.get('type', 'bzip2').lower()
928 bundletype = opts.get('type', 'bzip2').lower()
929 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
929 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
930 bundletype = btypes.get(bundletype)
930 bundletype = btypes.get(bundletype)
931 if bundletype not in changegroup.bundletypes:
931 if bundletype not in changegroup.bundletypes:
932 raise util.Abort(_('unknown bundle type specified with --type'))
932 raise util.Abort(_('unknown bundle type specified with --type'))
933
933
934 changegroup.writebundle(cg, fname, bundletype)
934 changegroup.writebundle(cg, fname, bundletype)
935
935
936 @command('cat',
936 @command('cat',
937 [('o', 'output', '',
937 [('o', 'output', '',
938 _('print output to file with formatted name'), _('FORMAT')),
938 _('print output to file with formatted name'), _('FORMAT')),
939 ('r', 'rev', '', _('print the given revision'), _('REV')),
939 ('r', 'rev', '', _('print the given revision'), _('REV')),
940 ('', 'decode', None, _('apply any matching decode filter')),
940 ('', 'decode', None, _('apply any matching decode filter')),
941 ] + walkopts,
941 ] + walkopts,
942 _('[OPTION]... FILE...'))
942 _('[OPTION]... FILE...'))
943 def cat(ui, repo, file1, *pats, **opts):
943 def cat(ui, repo, file1, *pats, **opts):
944 """output the current or given revision of files
944 """output the current or given revision of files
945
945
946 Print the specified files as they were at the given revision. If
946 Print the specified files as they were at the given revision. If
947 no revision is given, the parent of the working directory is used,
947 no revision is given, the parent of the working directory is used,
948 or tip if no revision is checked out.
948 or tip if no revision is checked out.
949
949
950 Output may be to a file, in which case the name of the file is
950 Output may be to a file, in which case the name of the file is
951 given using a format string. The formatting rules are the same as
951 given using a format string. The formatting rules are the same as
952 for the export command, with the following additions:
952 for the export command, with the following additions:
953
953
954 :``%s``: basename of file being printed
954 :``%s``: basename of file being printed
955 :``%d``: dirname of file being printed, or '.' if in repository root
955 :``%d``: dirname of file being printed, or '.' if in repository root
956 :``%p``: root-relative path name of file being printed
956 :``%p``: root-relative path name of file being printed
957
957
958 Returns 0 on success.
958 Returns 0 on success.
959 """
959 """
960 ctx = scmutil.revsingle(repo, opts.get('rev'))
960 ctx = scmutil.revsingle(repo, opts.get('rev'))
961 err = 1
961 err = 1
962 m = scmutil.match(ctx, (file1,) + pats, opts)
962 m = scmutil.match(ctx, (file1,) + pats, opts)
963 for abs in ctx.walk(m):
963 for abs in ctx.walk(m):
964 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
964 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
965 pathname=abs)
965 pathname=abs)
966 data = ctx[abs].data()
966 data = ctx[abs].data()
967 if opts.get('decode'):
967 if opts.get('decode'):
968 data = repo.wwritedata(abs, data)
968 data = repo.wwritedata(abs, data)
969 fp.write(data)
969 fp.write(data)
970 fp.close()
970 fp.close()
971 err = 0
971 err = 0
972 return err
972 return err
973
973
974 @command('^clone',
974 @command('^clone',
975 [('U', 'noupdate', None,
975 [('U', 'noupdate', None,
976 _('the clone will include an empty working copy (only a repository)')),
976 _('the clone will include an empty working copy (only a repository)')),
977 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
977 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
978 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
978 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
979 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
979 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
980 ('', 'pull', None, _('use pull protocol to copy metadata')),
980 ('', 'pull', None, _('use pull protocol to copy metadata')),
981 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
981 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
982 ] + remoteopts,
982 ] + remoteopts,
983 _('[OPTION]... SOURCE [DEST]'))
983 _('[OPTION]... SOURCE [DEST]'))
984 def clone(ui, source, dest=None, **opts):
984 def clone(ui, source, dest=None, **opts):
985 """make a copy of an existing repository
985 """make a copy of an existing repository
986
986
987 Create a copy of an existing repository in a new directory.
987 Create a copy of an existing repository in a new directory.
988
988
989 If no destination directory name is specified, it defaults to the
989 If no destination directory name is specified, it defaults to the
990 basename of the source.
990 basename of the source.
991
991
992 The location of the source is added to the new repository's
992 The location of the source is added to the new repository's
993 ``.hg/hgrc`` file, as the default to be used for future pulls.
993 ``.hg/hgrc`` file, as the default to be used for future pulls.
994
994
995 See :hg:`help urls` for valid source format details.
995 See :hg:`help urls` for valid source format details.
996
996
997 It is possible to specify an ``ssh://`` URL as the destination, but no
997 It is possible to specify an ``ssh://`` URL as the destination, but no
998 ``.hg/hgrc`` and working directory will be created on the remote side.
998 ``.hg/hgrc`` and working directory will be created on the remote side.
999 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
999 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
1000
1000
1001 A set of changesets (tags, or branch names) to pull may be specified
1001 A set of changesets (tags, or branch names) to pull may be specified
1002 by listing each changeset (tag, or branch name) with -r/--rev.
1002 by listing each changeset (tag, or branch name) with -r/--rev.
1003 If -r/--rev is used, the cloned repository will contain only a subset
1003 If -r/--rev is used, the cloned repository will contain only a subset
1004 of the changesets of the source repository. Only the set of changesets
1004 of the changesets of the source repository. Only the set of changesets
1005 defined by all -r/--rev options (including all their ancestors)
1005 defined by all -r/--rev options (including all their ancestors)
1006 will be pulled into the destination repository.
1006 will be pulled into the destination repository.
1007 No subsequent changesets (including subsequent tags) will be present
1007 No subsequent changesets (including subsequent tags) will be present
1008 in the destination.
1008 in the destination.
1009
1009
1010 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
1010 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
1011 local source repositories.
1011 local source repositories.
1012
1012
1013 For efficiency, hardlinks are used for cloning whenever the source
1013 For efficiency, hardlinks are used for cloning whenever the source
1014 and destination are on the same filesystem (note this applies only
1014 and destination are on the same filesystem (note this applies only
1015 to the repository data, not to the working directory). Some
1015 to the repository data, not to the working directory). Some
1016 filesystems, such as AFS, implement hardlinking incorrectly, but
1016 filesystems, such as AFS, implement hardlinking incorrectly, but
1017 do not report errors. In these cases, use the --pull option to
1017 do not report errors. In these cases, use the --pull option to
1018 avoid hardlinking.
1018 avoid hardlinking.
1019
1019
1020 In some cases, you can clone repositories and the working directory
1020 In some cases, you can clone repositories and the working directory
1021 using full hardlinks with ::
1021 using full hardlinks with ::
1022
1022
1023 $ cp -al REPO REPOCLONE
1023 $ cp -al REPO REPOCLONE
1024
1024
1025 This is the fastest way to clone, but it is not always safe. The
1025 This is the fastest way to clone, but it is not always safe. The
1026 operation is not atomic (making sure REPO is not modified during
1026 operation is not atomic (making sure REPO is not modified during
1027 the operation is up to you) and you have to make sure your editor
1027 the operation is up to you) and you have to make sure your editor
1028 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1028 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1029 this is not compatible with certain extensions that place their
1029 this is not compatible with certain extensions that place their
1030 metadata under the .hg directory, such as mq.
1030 metadata under the .hg directory, such as mq.
1031
1031
1032 Mercurial will update the working directory to the first applicable
1032 Mercurial will update the working directory to the first applicable
1033 revision from this list:
1033 revision from this list:
1034
1034
1035 a) null if -U or the source repository has no changesets
1035 a) null if -U or the source repository has no changesets
1036 b) if -u . and the source repository is local, the first parent of
1036 b) if -u . and the source repository is local, the first parent of
1037 the source repository's working directory
1037 the source repository's working directory
1038 c) the changeset specified with -u (if a branch name, this means the
1038 c) the changeset specified with -u (if a branch name, this means the
1039 latest head of that branch)
1039 latest head of that branch)
1040 d) the changeset specified with -r
1040 d) the changeset specified with -r
1041 e) the tipmost head specified with -b
1041 e) the tipmost head specified with -b
1042 f) the tipmost head specified with the url#branch source syntax
1042 f) the tipmost head specified with the url#branch source syntax
1043 g) the tipmost head of the default branch
1043 g) the tipmost head of the default branch
1044 h) tip
1044 h) tip
1045
1045
1046 Returns 0 on success.
1046 Returns 0 on success.
1047 """
1047 """
1048 if opts.get('noupdate') and opts.get('updaterev'):
1048 if opts.get('noupdate') and opts.get('updaterev'):
1049 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1049 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1050
1050
1051 r = hg.clone(ui, opts, source, dest,
1051 r = hg.clone(ui, opts, source, dest,
1052 pull=opts.get('pull'),
1052 pull=opts.get('pull'),
1053 stream=opts.get('uncompressed'),
1053 stream=opts.get('uncompressed'),
1054 rev=opts.get('rev'),
1054 rev=opts.get('rev'),
1055 update=opts.get('updaterev') or not opts.get('noupdate'),
1055 update=opts.get('updaterev') or not opts.get('noupdate'),
1056 branch=opts.get('branch'))
1056 branch=opts.get('branch'))
1057
1057
1058 return r is None
1058 return r is None
1059
1059
1060 @command('^commit|ci',
1060 @command('^commit|ci',
1061 [('A', 'addremove', None,
1061 [('A', 'addremove', None,
1062 _('mark new/missing files as added/removed before committing')),
1062 _('mark new/missing files as added/removed before committing')),
1063 ('', 'close-branch', None,
1063 ('', 'close-branch', None,
1064 _('mark a branch as closed, hiding it from the branch list')),
1064 _('mark a branch as closed, hiding it from the branch list')),
1065 ] + walkopts + commitopts + commitopts2,
1065 ] + walkopts + commitopts + commitopts2,
1066 _('[OPTION]... [FILE]...'))
1066 _('[OPTION]... [FILE]...'))
1067 def commit(ui, repo, *pats, **opts):
1067 def commit(ui, repo, *pats, **opts):
1068 """commit the specified files or all outstanding changes
1068 """commit the specified files or all outstanding changes
1069
1069
1070 Commit changes to the given files into the repository. Unlike a
1070 Commit changes to the given files into the repository. Unlike a
1071 centralized SCM, this operation is a local operation. See
1071 centralized SCM, this operation is a local operation. See
1072 :hg:`push` for a way to actively distribute your changes.
1072 :hg:`push` for a way to actively distribute your changes.
1073
1073
1074 If a list of files is omitted, all changes reported by :hg:`status`
1074 If a list of files is omitted, all changes reported by :hg:`status`
1075 will be committed.
1075 will be committed.
1076
1076
1077 If you are committing the result of a merge, do not provide any
1077 If you are committing the result of a merge, do not provide any
1078 filenames or -I/-X filters.
1078 filenames or -I/-X filters.
1079
1079
1080 If no commit message is specified, Mercurial starts your
1080 If no commit message is specified, Mercurial starts your
1081 configured editor where you can enter a message. In case your
1081 configured editor where you can enter a message. In case your
1082 commit fails, you will find a backup of your message in
1082 commit fails, you will find a backup of your message in
1083 ``.hg/last-message.txt``.
1083 ``.hg/last-message.txt``.
1084
1084
1085 See :hg:`help dates` for a list of formats valid for -d/--date.
1085 See :hg:`help dates` for a list of formats valid for -d/--date.
1086
1086
1087 Returns 0 on success, 1 if nothing changed.
1087 Returns 0 on success, 1 if nothing changed.
1088 """
1088 """
1089 extra = {}
1089 extra = {}
1090 if opts.get('close_branch'):
1090 if opts.get('close_branch'):
1091 if repo['.'].node() not in repo.branchheads():
1091 if repo['.'].node() not in repo.branchheads():
1092 # The topo heads set is included in the branch heads set of the
1092 # The topo heads set is included in the branch heads set of the
1093 # current branch, so it's sufficient to test branchheads
1093 # current branch, so it's sufficient to test branchheads
1094 raise util.Abort(_('can only close branch heads'))
1094 raise util.Abort(_('can only close branch heads'))
1095 extra['close'] = 1
1095 extra['close'] = 1
1096 e = cmdutil.commiteditor
1096 e = cmdutil.commiteditor
1097 if opts.get('force_editor'):
1097 if opts.get('force_editor'):
1098 e = cmdutil.commitforceeditor
1098 e = cmdutil.commitforceeditor
1099
1099
1100 def commitfunc(ui, repo, message, match, opts):
1100 def commitfunc(ui, repo, message, match, opts):
1101 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1101 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1102 editor=e, extra=extra)
1102 editor=e, extra=extra)
1103
1103
1104 branch = repo[None].branch()
1104 branch = repo[None].branch()
1105 bheads = repo.branchheads(branch)
1105 bheads = repo.branchheads(branch)
1106
1106
1107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1108 if not node:
1108 if not node:
1109 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1109 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1110 if stat[3]:
1110 if stat[3]:
1111 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1111 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1112 % len(stat[3]))
1112 % len(stat[3]))
1113 else:
1113 else:
1114 ui.status(_("nothing changed\n"))
1114 ui.status(_("nothing changed\n"))
1115 return 1
1115 return 1
1116
1116
1117 ctx = repo[node]
1117 ctx = repo[node]
1118 parents = ctx.parents()
1118 parents = ctx.parents()
1119
1119
1120 if (bheads and node not in bheads and not
1120 if (bheads and node not in bheads and not
1121 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1121 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1122 ui.status(_('created new head\n'))
1122 ui.status(_('created new head\n'))
1123 # The message is not printed for initial roots. For the other
1123 # The message is not printed for initial roots. For the other
1124 # changesets, it is printed in the following situations:
1124 # changesets, it is printed in the following situations:
1125 #
1125 #
1126 # Par column: for the 2 parents with ...
1126 # Par column: for the 2 parents with ...
1127 # N: null or no parent
1127 # N: null or no parent
1128 # B: parent is on another named branch
1128 # B: parent is on another named branch
1129 # C: parent is a regular non head changeset
1129 # C: parent is a regular non head changeset
1130 # H: parent was a branch head of the current branch
1130 # H: parent was a branch head of the current branch
1131 # Msg column: whether we print "created new head" message
1131 # Msg column: whether we print "created new head" message
1132 # In the following, it is assumed that there already exists some
1132 # In the following, it is assumed that there already exists some
1133 # initial branch heads of the current branch, otherwise nothing is
1133 # initial branch heads of the current branch, otherwise nothing is
1134 # printed anyway.
1134 # printed anyway.
1135 #
1135 #
1136 # Par Msg Comment
1136 # Par Msg Comment
1137 # NN y additional topo root
1137 # NN y additional topo root
1138 #
1138 #
1139 # BN y additional branch root
1139 # BN y additional branch root
1140 # CN y additional topo head
1140 # CN y additional topo head
1141 # HN n usual case
1141 # HN n usual case
1142 #
1142 #
1143 # BB y weird additional branch root
1143 # BB y weird additional branch root
1144 # CB y branch merge
1144 # CB y branch merge
1145 # HB n merge with named branch
1145 # HB n merge with named branch
1146 #
1146 #
1147 # CC y additional head from merge
1147 # CC y additional head from merge
1148 # CH n merge with a head
1148 # CH n merge with a head
1149 #
1149 #
1150 # HH n head merge: head count decreases
1150 # HH n head merge: head count decreases
1151
1151
1152 if not opts.get('close_branch'):
1152 if not opts.get('close_branch'):
1153 for r in parents:
1153 for r in parents:
1154 if r.extra().get('close') and r.branch() == branch:
1154 if r.extra().get('close') and r.branch() == branch:
1155 ui.status(_('reopening closed branch head %d\n') % r)
1155 ui.status(_('reopening closed branch head %d\n') % r)
1156
1156
1157 if ui.debugflag:
1157 if ui.debugflag:
1158 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1158 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1159 elif ui.verbose:
1159 elif ui.verbose:
1160 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1160 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1161
1161
1162 @command('copy|cp',
1162 @command('copy|cp',
1163 [('A', 'after', None, _('record a copy that has already occurred')),
1163 [('A', 'after', None, _('record a copy that has already occurred')),
1164 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1164 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1165 ] + walkopts + dryrunopts,
1165 ] + walkopts + dryrunopts,
1166 _('[OPTION]... [SOURCE]... DEST'))
1166 _('[OPTION]... [SOURCE]... DEST'))
1167 def copy(ui, repo, *pats, **opts):
1167 def copy(ui, repo, *pats, **opts):
1168 """mark files as copied for the next commit
1168 """mark files as copied for the next commit
1169
1169
1170 Mark dest as having copies of source files. If dest is a
1170 Mark dest as having copies of source files. If dest is a
1171 directory, copies are put in that directory. If dest is a file,
1171 directory, copies are put in that directory. If dest is a file,
1172 the source must be a single file.
1172 the source must be a single file.
1173
1173
1174 By default, this command copies the contents of files as they
1174 By default, this command copies the contents of files as they
1175 exist in the working directory. If invoked with -A/--after, the
1175 exist in the working directory. If invoked with -A/--after, the
1176 operation is recorded, but no copying is performed.
1176 operation is recorded, but no copying is performed.
1177
1177
1178 This command takes effect with the next commit. To undo a copy
1178 This command takes effect with the next commit. To undo a copy
1179 before that, see :hg:`revert`.
1179 before that, see :hg:`revert`.
1180
1180
1181 Returns 0 on success, 1 if errors are encountered.
1181 Returns 0 on success, 1 if errors are encountered.
1182 """
1182 """
1183 wlock = repo.wlock(False)
1183 wlock = repo.wlock(False)
1184 try:
1184 try:
1185 return cmdutil.copy(ui, repo, pats, opts)
1185 return cmdutil.copy(ui, repo, pats, opts)
1186 finally:
1186 finally:
1187 wlock.release()
1187 wlock.release()
1188
1188
1189 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1189 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1190 def debugancestor(ui, repo, *args):
1190 def debugancestor(ui, repo, *args):
1191 """find the ancestor revision of two revisions in a given index"""
1191 """find the ancestor revision of two revisions in a given index"""
1192 if len(args) == 3:
1192 if len(args) == 3:
1193 index, rev1, rev2 = args
1193 index, rev1, rev2 = args
1194 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1194 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1195 lookup = r.lookup
1195 lookup = r.lookup
1196 elif len(args) == 2:
1196 elif len(args) == 2:
1197 if not repo:
1197 if not repo:
1198 raise util.Abort(_("there is no Mercurial repository here "
1198 raise util.Abort(_("there is no Mercurial repository here "
1199 "(.hg not found)"))
1199 "(.hg not found)"))
1200 rev1, rev2 = args
1200 rev1, rev2 = args
1201 r = repo.changelog
1201 r = repo.changelog
1202 lookup = repo.lookup
1202 lookup = repo.lookup
1203 else:
1203 else:
1204 raise util.Abort(_('either two or three arguments required'))
1204 raise util.Abort(_('either two or three arguments required'))
1205 a = r.ancestor(lookup(rev1), lookup(rev2))
1205 a = r.ancestor(lookup(rev1), lookup(rev2))
1206 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1206 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1207
1207
1208 @command('debugbuilddag',
1208 @command('debugbuilddag',
1209 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1209 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1210 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1210 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1211 ('n', 'new-file', None, _('add new file at each rev'))],
1211 ('n', 'new-file', None, _('add new file at each rev'))],
1212 _('[OPTION]... [TEXT]'))
1212 _('[OPTION]... [TEXT]'))
1213 def debugbuilddag(ui, repo, text=None,
1213 def debugbuilddag(ui, repo, text=None,
1214 mergeable_file=False,
1214 mergeable_file=False,
1215 overwritten_file=False,
1215 overwritten_file=False,
1216 new_file=False):
1216 new_file=False):
1217 """builds a repo with a given DAG from scratch in the current empty repo
1217 """builds a repo with a given DAG from scratch in the current empty repo
1218
1218
1219 The description of the DAG is read from stdin if not given on the
1219 The description of the DAG is read from stdin if not given on the
1220 command line.
1220 command line.
1221
1221
1222 Elements:
1222 Elements:
1223
1223
1224 - "+n" is a linear run of n nodes based on the current default parent
1224 - "+n" is a linear run of n nodes based on the current default parent
1225 - "." is a single node based on the current default parent
1225 - "." is a single node based on the current default parent
1226 - "$" resets the default parent to null (implied at the start);
1226 - "$" resets the default parent to null (implied at the start);
1227 otherwise the default parent is always the last node created
1227 otherwise the default parent is always the last node created
1228 - "<p" sets the default parent to the backref p
1228 - "<p" sets the default parent to the backref p
1229 - "*p" is a fork at parent p, which is a backref
1229 - "*p" is a fork at parent p, which is a backref
1230 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1230 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1231 - "/p2" is a merge of the preceding node and p2
1231 - "/p2" is a merge of the preceding node and p2
1232 - ":tag" defines a local tag for the preceding node
1232 - ":tag" defines a local tag for the preceding node
1233 - "@branch" sets the named branch for subsequent nodes
1233 - "@branch" sets the named branch for subsequent nodes
1234 - "#...\\n" is a comment up to the end of the line
1234 - "#...\\n" is a comment up to the end of the line
1235
1235
1236 Whitespace between the above elements is ignored.
1236 Whitespace between the above elements is ignored.
1237
1237
1238 A backref is either
1238 A backref is either
1239
1239
1240 - a number n, which references the node curr-n, where curr is the current
1240 - a number n, which references the node curr-n, where curr is the current
1241 node, or
1241 node, or
1242 - the name of a local tag you placed earlier using ":tag", or
1242 - the name of a local tag you placed earlier using ":tag", or
1243 - empty to denote the default parent.
1243 - empty to denote the default parent.
1244
1244
1245 All string valued-elements are either strictly alphanumeric, or must
1245 All string valued-elements are either strictly alphanumeric, or must
1246 be enclosed in double quotes ("..."), with "\\" as escape character.
1246 be enclosed in double quotes ("..."), with "\\" as escape character.
1247 """
1247 """
1248
1248
1249 if text is None:
1249 if text is None:
1250 ui.status(_("reading DAG from stdin\n"))
1250 ui.status(_("reading DAG from stdin\n"))
1251 text = ui.fin.read()
1251 text = ui.fin.read()
1252
1252
1253 cl = repo.changelog
1253 cl = repo.changelog
1254 if len(cl) > 0:
1254 if len(cl) > 0:
1255 raise util.Abort(_('repository is not empty'))
1255 raise util.Abort(_('repository is not empty'))
1256
1256
1257 # determine number of revs in DAG
1257 # determine number of revs in DAG
1258 total = 0
1258 total = 0
1259 for type, data in dagparser.parsedag(text):
1259 for type, data in dagparser.parsedag(text):
1260 if type == 'n':
1260 if type == 'n':
1261 total += 1
1261 total += 1
1262
1262
1263 if mergeable_file:
1263 if mergeable_file:
1264 linesperrev = 2
1264 linesperrev = 2
1265 # make a file with k lines per rev
1265 # make a file with k lines per rev
1266 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1266 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1267 initialmergedlines.append("")
1267 initialmergedlines.append("")
1268
1268
1269 tags = []
1269 tags = []
1270
1270
1271 tr = repo.transaction("builddag")
1271 tr = repo.transaction("builddag")
1272 try:
1272 try:
1273
1273
1274 at = -1
1274 at = -1
1275 atbranch = 'default'
1275 atbranch = 'default'
1276 nodeids = []
1276 nodeids = []
1277 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1277 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1278 for type, data in dagparser.parsedag(text):
1278 for type, data in dagparser.parsedag(text):
1279 if type == 'n':
1279 if type == 'n':
1280 ui.note('node %s\n' % str(data))
1280 ui.note('node %s\n' % str(data))
1281 id, ps = data
1281 id, ps = data
1282
1282
1283 files = []
1283 files = []
1284 fctxs = {}
1284 fctxs = {}
1285
1285
1286 p2 = None
1286 p2 = None
1287 if mergeable_file:
1287 if mergeable_file:
1288 fn = "mf"
1288 fn = "mf"
1289 p1 = repo[ps[0]]
1289 p1 = repo[ps[0]]
1290 if len(ps) > 1:
1290 if len(ps) > 1:
1291 p2 = repo[ps[1]]
1291 p2 = repo[ps[1]]
1292 pa = p1.ancestor(p2)
1292 pa = p1.ancestor(p2)
1293 base, local, other = [x[fn].data() for x in pa, p1, p2]
1293 base, local, other = [x[fn].data() for x in pa, p1, p2]
1294 m3 = simplemerge.Merge3Text(base, local, other)
1294 m3 = simplemerge.Merge3Text(base, local, other)
1295 ml = [l.strip() for l in m3.merge_lines()]
1295 ml = [l.strip() for l in m3.merge_lines()]
1296 ml.append("")
1296 ml.append("")
1297 elif at > 0:
1297 elif at > 0:
1298 ml = p1[fn].data().split("\n")
1298 ml = p1[fn].data().split("\n")
1299 else:
1299 else:
1300 ml = initialmergedlines
1300 ml = initialmergedlines
1301 ml[id * linesperrev] += " r%i" % id
1301 ml[id * linesperrev] += " r%i" % id
1302 mergedtext = "\n".join(ml)
1302 mergedtext = "\n".join(ml)
1303 files.append(fn)
1303 files.append(fn)
1304 fctxs[fn] = context.memfilectx(fn, mergedtext)
1304 fctxs[fn] = context.memfilectx(fn, mergedtext)
1305
1305
1306 if overwritten_file:
1306 if overwritten_file:
1307 fn = "of"
1307 fn = "of"
1308 files.append(fn)
1308 files.append(fn)
1309 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1309 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1310
1310
1311 if new_file:
1311 if new_file:
1312 fn = "nf%i" % id
1312 fn = "nf%i" % id
1313 files.append(fn)
1313 files.append(fn)
1314 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1314 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1315 if len(ps) > 1:
1315 if len(ps) > 1:
1316 if not p2:
1316 if not p2:
1317 p2 = repo[ps[1]]
1317 p2 = repo[ps[1]]
1318 for fn in p2:
1318 for fn in p2:
1319 if fn.startswith("nf"):
1319 if fn.startswith("nf"):
1320 files.append(fn)
1320 files.append(fn)
1321 fctxs[fn] = p2[fn]
1321 fctxs[fn] = p2[fn]
1322
1322
1323 def fctxfn(repo, cx, path):
1323 def fctxfn(repo, cx, path):
1324 return fctxs.get(path)
1324 return fctxs.get(path)
1325
1325
1326 if len(ps) == 0 or ps[0] < 0:
1326 if len(ps) == 0 or ps[0] < 0:
1327 pars = [None, None]
1327 pars = [None, None]
1328 elif len(ps) == 1:
1328 elif len(ps) == 1:
1329 pars = [nodeids[ps[0]], None]
1329 pars = [nodeids[ps[0]], None]
1330 else:
1330 else:
1331 pars = [nodeids[p] for p in ps]
1331 pars = [nodeids[p] for p in ps]
1332 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1332 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1333 date=(id, 0),
1333 date=(id, 0),
1334 user="debugbuilddag",
1334 user="debugbuilddag",
1335 extra={'branch': atbranch})
1335 extra={'branch': atbranch})
1336 nodeid = repo.commitctx(cx)
1336 nodeid = repo.commitctx(cx)
1337 nodeids.append(nodeid)
1337 nodeids.append(nodeid)
1338 at = id
1338 at = id
1339 elif type == 'l':
1339 elif type == 'l':
1340 id, name = data
1340 id, name = data
1341 ui.note('tag %s\n' % name)
1341 ui.note('tag %s\n' % name)
1342 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1342 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1343 elif type == 'a':
1343 elif type == 'a':
1344 ui.note('branch %s\n' % data)
1344 ui.note('branch %s\n' % data)
1345 atbranch = data
1345 atbranch = data
1346 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1346 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1347 tr.close()
1347 tr.close()
1348 finally:
1348 finally:
1349 ui.progress(_('building'), None)
1349 ui.progress(_('building'), None)
1350 tr.release()
1350 tr.release()
1351
1351
1352 if tags:
1352 if tags:
1353 repo.opener.write("localtags", "".join(tags))
1353 repo.opener.write("localtags", "".join(tags))
1354
1354
1355 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1355 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1356 def debugbundle(ui, bundlepath, all=None, **opts):
1356 def debugbundle(ui, bundlepath, all=None, **opts):
1357 """lists the contents of a bundle"""
1357 """lists the contents of a bundle"""
1358 f = url.open(ui, bundlepath)
1358 f = url.open(ui, bundlepath)
1359 try:
1359 try:
1360 gen = changegroup.readbundle(f, bundlepath)
1360 gen = changegroup.readbundle(f, bundlepath)
1361 if all:
1361 if all:
1362 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1362 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1363
1363
1364 def showchunks(named):
1364 def showchunks(named):
1365 ui.write("\n%s\n" % named)
1365 ui.write("\n%s\n" % named)
1366 chain = None
1366 chain = None
1367 while True:
1367 while True:
1368 chunkdata = gen.deltachunk(chain)
1368 chunkdata = gen.deltachunk(chain)
1369 if not chunkdata:
1369 if not chunkdata:
1370 break
1370 break
1371 node = chunkdata['node']
1371 node = chunkdata['node']
1372 p1 = chunkdata['p1']
1372 p1 = chunkdata['p1']
1373 p2 = chunkdata['p2']
1373 p2 = chunkdata['p2']
1374 cs = chunkdata['cs']
1374 cs = chunkdata['cs']
1375 deltabase = chunkdata['deltabase']
1375 deltabase = chunkdata['deltabase']
1376 delta = chunkdata['delta']
1376 delta = chunkdata['delta']
1377 ui.write("%s %s %s %s %s %s\n" %
1377 ui.write("%s %s %s %s %s %s\n" %
1378 (hex(node), hex(p1), hex(p2),
1378 (hex(node), hex(p1), hex(p2),
1379 hex(cs), hex(deltabase), len(delta)))
1379 hex(cs), hex(deltabase), len(delta)))
1380 chain = node
1380 chain = node
1381
1381
1382 chunkdata = gen.changelogheader()
1382 chunkdata = gen.changelogheader()
1383 showchunks("changelog")
1383 showchunks("changelog")
1384 chunkdata = gen.manifestheader()
1384 chunkdata = gen.manifestheader()
1385 showchunks("manifest")
1385 showchunks("manifest")
1386 while True:
1386 while True:
1387 chunkdata = gen.filelogheader()
1387 chunkdata = gen.filelogheader()
1388 if not chunkdata:
1388 if not chunkdata:
1389 break
1389 break
1390 fname = chunkdata['filename']
1390 fname = chunkdata['filename']
1391 showchunks(fname)
1391 showchunks(fname)
1392 else:
1392 else:
1393 chunkdata = gen.changelogheader()
1393 chunkdata = gen.changelogheader()
1394 chain = None
1394 chain = None
1395 while True:
1395 while True:
1396 chunkdata = gen.deltachunk(chain)
1396 chunkdata = gen.deltachunk(chain)
1397 if not chunkdata:
1397 if not chunkdata:
1398 break
1398 break
1399 node = chunkdata['node']
1399 node = chunkdata['node']
1400 ui.write("%s\n" % hex(node))
1400 ui.write("%s\n" % hex(node))
1401 chain = node
1401 chain = node
1402 finally:
1402 finally:
1403 f.close()
1403 f.close()
1404
1404
1405 @command('debugcheckstate', [], '')
1405 @command('debugcheckstate', [], '')
1406 def debugcheckstate(ui, repo):
1406 def debugcheckstate(ui, repo):
1407 """validate the correctness of the current dirstate"""
1407 """validate the correctness of the current dirstate"""
1408 parent1, parent2 = repo.dirstate.parents()
1408 parent1, parent2 = repo.dirstate.parents()
1409 m1 = repo[parent1].manifest()
1409 m1 = repo[parent1].manifest()
1410 m2 = repo[parent2].manifest()
1410 m2 = repo[parent2].manifest()
1411 errors = 0
1411 errors = 0
1412 for f in repo.dirstate:
1412 for f in repo.dirstate:
1413 state = repo.dirstate[f]
1413 state = repo.dirstate[f]
1414 if state in "nr" and f not in m1:
1414 if state in "nr" and f not in m1:
1415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1416 errors += 1
1416 errors += 1
1417 if state in "a" and f in m1:
1417 if state in "a" and f in m1:
1418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1419 errors += 1
1419 errors += 1
1420 if state in "m" and f not in m1 and f not in m2:
1420 if state in "m" and f not in m1 and f not in m2:
1421 ui.warn(_("%s in state %s, but not in either manifest\n") %
1421 ui.warn(_("%s in state %s, but not in either manifest\n") %
1422 (f, state))
1422 (f, state))
1423 errors += 1
1423 errors += 1
1424 for f in m1:
1424 for f in m1:
1425 state = repo.dirstate[f]
1425 state = repo.dirstate[f]
1426 if state not in "nrm":
1426 if state not in "nrm":
1427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1428 errors += 1
1428 errors += 1
1429 if errors:
1429 if errors:
1430 error = _(".hg/dirstate inconsistent with current parent's manifest")
1430 error = _(".hg/dirstate inconsistent with current parent's manifest")
1431 raise util.Abort(error)
1431 raise util.Abort(error)
1432
1432
1433 @command('debugcommands', [], _('[COMMAND]'))
1433 @command('debugcommands', [], _('[COMMAND]'))
1434 def debugcommands(ui, cmd='', *args):
1434 def debugcommands(ui, cmd='', *args):
1435 """list all available commands and options"""
1435 """list all available commands and options"""
1436 for cmd, vals in sorted(table.iteritems()):
1436 for cmd, vals in sorted(table.iteritems()):
1437 cmd = cmd.split('|')[0].strip('^')
1437 cmd = cmd.split('|')[0].strip('^')
1438 opts = ', '.join([i[1] for i in vals[1]])
1438 opts = ', '.join([i[1] for i in vals[1]])
1439 ui.write('%s: %s\n' % (cmd, opts))
1439 ui.write('%s: %s\n' % (cmd, opts))
1440
1440
1441 @command('debugcomplete',
1441 @command('debugcomplete',
1442 [('o', 'options', None, _('show the command options'))],
1442 [('o', 'options', None, _('show the command options'))],
1443 _('[-o] CMD'))
1443 _('[-o] CMD'))
1444 def debugcomplete(ui, cmd='', **opts):
1444 def debugcomplete(ui, cmd='', **opts):
1445 """returns the completion list associated with the given command"""
1445 """returns the completion list associated with the given command"""
1446
1446
1447 if opts.get('options'):
1447 if opts.get('options'):
1448 options = []
1448 options = []
1449 otables = [globalopts]
1449 otables = [globalopts]
1450 if cmd:
1450 if cmd:
1451 aliases, entry = cmdutil.findcmd(cmd, table, False)
1451 aliases, entry = cmdutil.findcmd(cmd, table, False)
1452 otables.append(entry[1])
1452 otables.append(entry[1])
1453 for t in otables:
1453 for t in otables:
1454 for o in t:
1454 for o in t:
1455 if "(DEPRECATED)" in o[3]:
1455 if "(DEPRECATED)" in o[3]:
1456 continue
1456 continue
1457 if o[0]:
1457 if o[0]:
1458 options.append('-%s' % o[0])
1458 options.append('-%s' % o[0])
1459 options.append('--%s' % o[1])
1459 options.append('--%s' % o[1])
1460 ui.write("%s\n" % "\n".join(options))
1460 ui.write("%s\n" % "\n".join(options))
1461 return
1461 return
1462
1462
1463 cmdlist = cmdutil.findpossible(cmd, table)
1463 cmdlist = cmdutil.findpossible(cmd, table)
1464 if ui.verbose:
1464 if ui.verbose:
1465 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1465 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1466 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1466 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1467
1467
1468 @command('debugdag',
1468 @command('debugdag',
1469 [('t', 'tags', None, _('use tags as labels')),
1469 [('t', 'tags', None, _('use tags as labels')),
1470 ('b', 'branches', None, _('annotate with branch names')),
1470 ('b', 'branches', None, _('annotate with branch names')),
1471 ('', 'dots', None, _('use dots for runs')),
1471 ('', 'dots', None, _('use dots for runs')),
1472 ('s', 'spaces', None, _('separate elements by spaces'))],
1472 ('s', 'spaces', None, _('separate elements by spaces'))],
1473 _('[OPTION]... [FILE [REV]...]'))
1473 _('[OPTION]... [FILE [REV]...]'))
1474 def debugdag(ui, repo, file_=None, *revs, **opts):
1474 def debugdag(ui, repo, file_=None, *revs, **opts):
1475 """format the changelog or an index DAG as a concise textual description
1475 """format the changelog or an index DAG as a concise textual description
1476
1476
1477 If you pass a revlog index, the revlog's DAG is emitted. If you list
1477 If you pass a revlog index, the revlog's DAG is emitted. If you list
1478 revision numbers, they get labelled in the output as rN.
1478 revision numbers, they get labelled in the output as rN.
1479
1479
1480 Otherwise, the changelog DAG of the current repo is emitted.
1480 Otherwise, the changelog DAG of the current repo is emitted.
1481 """
1481 """
1482 spaces = opts.get('spaces')
1482 spaces = opts.get('spaces')
1483 dots = opts.get('dots')
1483 dots = opts.get('dots')
1484 if file_:
1484 if file_:
1485 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1485 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1486 revs = set((int(r) for r in revs))
1486 revs = set((int(r) for r in revs))
1487 def events():
1487 def events():
1488 for r in rlog:
1488 for r in rlog:
1489 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1489 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1490 if r in revs:
1490 if r in revs:
1491 yield 'l', (r, "r%i" % r)
1491 yield 'l', (r, "r%i" % r)
1492 elif repo:
1492 elif repo:
1493 cl = repo.changelog
1493 cl = repo.changelog
1494 tags = opts.get('tags')
1494 tags = opts.get('tags')
1495 branches = opts.get('branches')
1495 branches = opts.get('branches')
1496 if tags:
1496 if tags:
1497 labels = {}
1497 labels = {}
1498 for l, n in repo.tags().items():
1498 for l, n in repo.tags().items():
1499 labels.setdefault(cl.rev(n), []).append(l)
1499 labels.setdefault(cl.rev(n), []).append(l)
1500 def events():
1500 def events():
1501 b = "default"
1501 b = "default"
1502 for r in cl:
1502 for r in cl:
1503 if branches:
1503 if branches:
1504 newb = cl.read(cl.node(r))[5]['branch']
1504 newb = cl.read(cl.node(r))[5]['branch']
1505 if newb != b:
1505 if newb != b:
1506 yield 'a', newb
1506 yield 'a', newb
1507 b = newb
1507 b = newb
1508 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1508 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1509 if tags:
1509 if tags:
1510 ls = labels.get(r)
1510 ls = labels.get(r)
1511 if ls:
1511 if ls:
1512 for l in ls:
1512 for l in ls:
1513 yield 'l', (r, l)
1513 yield 'l', (r, l)
1514 else:
1514 else:
1515 raise util.Abort(_('need repo for changelog dag'))
1515 raise util.Abort(_('need repo for changelog dag'))
1516
1516
1517 for line in dagparser.dagtextlines(events(),
1517 for line in dagparser.dagtextlines(events(),
1518 addspaces=spaces,
1518 addspaces=spaces,
1519 wraplabels=True,
1519 wraplabels=True,
1520 wrapannotations=True,
1520 wrapannotations=True,
1521 wrapnonlinear=dots,
1521 wrapnonlinear=dots,
1522 usedots=dots,
1522 usedots=dots,
1523 maxlinewidth=70):
1523 maxlinewidth=70):
1524 ui.write(line)
1524 ui.write(line)
1525 ui.write("\n")
1525 ui.write("\n")
1526
1526
1527 @command('debugdata',
1527 @command('debugdata',
1528 [('c', 'changelog', False, _('open changelog')),
1528 [('c', 'changelog', False, _('open changelog')),
1529 ('m', 'manifest', False, _('open manifest'))],
1529 ('m', 'manifest', False, _('open manifest'))],
1530 _('-c|-m|FILE REV'))
1530 _('-c|-m|FILE REV'))
1531 def debugdata(ui, repo, file_, rev = None, **opts):
1531 def debugdata(ui, repo, file_, rev = None, **opts):
1532 """dump the contents of a data file revision"""
1532 """dump the contents of a data file revision"""
1533 if opts.get('changelog') or opts.get('manifest'):
1533 if opts.get('changelog') or opts.get('manifest'):
1534 file_, rev = None, file_
1534 file_, rev = None, file_
1535 elif rev is None:
1535 elif rev is None:
1536 raise error.CommandError('debugdata', _('invalid arguments'))
1536 raise error.CommandError('debugdata', _('invalid arguments'))
1537 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1537 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1538 try:
1538 try:
1539 ui.write(r.revision(r.lookup(rev)))
1539 ui.write(r.revision(r.lookup(rev)))
1540 except KeyError:
1540 except KeyError:
1541 raise util.Abort(_('invalid revision identifier %s') % rev)
1541 raise util.Abort(_('invalid revision identifier %s') % rev)
1542
1542
1543 @command('debugdate',
1543 @command('debugdate',
1544 [('e', 'extended', None, _('try extended date formats'))],
1544 [('e', 'extended', None, _('try extended date formats'))],
1545 _('[-e] DATE [RANGE]'))
1545 _('[-e] DATE [RANGE]'))
1546 def debugdate(ui, date, range=None, **opts):
1546 def debugdate(ui, date, range=None, **opts):
1547 """parse and display a date"""
1547 """parse and display a date"""
1548 if opts["extended"]:
1548 if opts["extended"]:
1549 d = util.parsedate(date, util.extendeddateformats)
1549 d = util.parsedate(date, util.extendeddateformats)
1550 else:
1550 else:
1551 d = util.parsedate(date)
1551 d = util.parsedate(date)
1552 ui.write("internal: %s %s\n" % d)
1552 ui.write("internal: %s %s\n" % d)
1553 ui.write("standard: %s\n" % util.datestr(d))
1553 ui.write("standard: %s\n" % util.datestr(d))
1554 if range:
1554 if range:
1555 m = util.matchdate(range)
1555 m = util.matchdate(range)
1556 ui.write("match: %s\n" % m(d[0]))
1556 ui.write("match: %s\n" % m(d[0]))
1557
1557
1558 @command('debugdiscovery',
1558 @command('debugdiscovery',
1559 [('', 'old', None, _('use old-style discovery')),
1559 [('', 'old', None, _('use old-style discovery')),
1560 ('', 'nonheads', None,
1560 ('', 'nonheads', None,
1561 _('use old-style discovery with non-heads included')),
1561 _('use old-style discovery with non-heads included')),
1562 ] + remoteopts,
1562 ] + remoteopts,
1563 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1563 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1564 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1564 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1565 """runs the changeset discovery protocol in isolation"""
1565 """runs the changeset discovery protocol in isolation"""
1566 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1566 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1567 remote = hg.peer(repo, opts, remoteurl)
1567 remote = hg.peer(repo, opts, remoteurl)
1568 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1568 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1569
1569
1570 # make sure tests are repeatable
1570 # make sure tests are repeatable
1571 random.seed(12323)
1571 random.seed(12323)
1572
1572
1573 def doit(localheads, remoteheads):
1573 def doit(localheads, remoteheads):
1574 if opts.get('old'):
1574 if opts.get('old'):
1575 if localheads:
1575 if localheads:
1576 raise util.Abort('cannot use localheads with old style discovery')
1576 raise util.Abort('cannot use localheads with old style discovery')
1577 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1577 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1578 force=True)
1578 force=True)
1579 common = set(common)
1579 common = set(common)
1580 if not opts.get('nonheads'):
1580 if not opts.get('nonheads'):
1581 ui.write("unpruned common: %s\n" % " ".join([short(n)
1581 ui.write("unpruned common: %s\n" % " ".join([short(n)
1582 for n in common]))
1582 for n in common]))
1583 dag = dagutil.revlogdag(repo.changelog)
1583 dag = dagutil.revlogdag(repo.changelog)
1584 all = dag.ancestorset(dag.internalizeall(common))
1584 all = dag.ancestorset(dag.internalizeall(common))
1585 common = dag.externalizeall(dag.headsetofconnecteds(all))
1585 common = dag.externalizeall(dag.headsetofconnecteds(all))
1586 else:
1586 else:
1587 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1587 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1588 common = set(common)
1588 common = set(common)
1589 rheads = set(hds)
1589 rheads = set(hds)
1590 lheads = set(repo.heads())
1590 lheads = set(repo.heads())
1591 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1591 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1592 if lheads <= common:
1592 if lheads <= common:
1593 ui.write("local is subset\n")
1593 ui.write("local is subset\n")
1594 elif rheads <= common:
1594 elif rheads <= common:
1595 ui.write("remote is subset\n")
1595 ui.write("remote is subset\n")
1596
1596
1597 serverlogs = opts.get('serverlog')
1597 serverlogs = opts.get('serverlog')
1598 if serverlogs:
1598 if serverlogs:
1599 for filename in serverlogs:
1599 for filename in serverlogs:
1600 logfile = open(filename, 'r')
1600 logfile = open(filename, 'r')
1601 try:
1601 try:
1602 line = logfile.readline()
1602 line = logfile.readline()
1603 while line:
1603 while line:
1604 parts = line.strip().split(';')
1604 parts = line.strip().split(';')
1605 op = parts[1]
1605 op = parts[1]
1606 if op == 'cg':
1606 if op == 'cg':
1607 pass
1607 pass
1608 elif op == 'cgss':
1608 elif op == 'cgss':
1609 doit(parts[2].split(' '), parts[3].split(' '))
1609 doit(parts[2].split(' '), parts[3].split(' '))
1610 elif op == 'unb':
1610 elif op == 'unb':
1611 doit(parts[3].split(' '), parts[2].split(' '))
1611 doit(parts[3].split(' '), parts[2].split(' '))
1612 line = logfile.readline()
1612 line = logfile.readline()
1613 finally:
1613 finally:
1614 logfile.close()
1614 logfile.close()
1615
1615
1616 else:
1616 else:
1617 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1617 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1618 opts.get('remote_head'))
1618 opts.get('remote_head'))
1619 localrevs = opts.get('local_head')
1619 localrevs = opts.get('local_head')
1620 doit(localrevs, remoterevs)
1620 doit(localrevs, remoterevs)
1621
1621
1622 @command('debugfileset', [], ('REVSPEC'))
1622 @command('debugfileset', [], ('REVSPEC'))
1623 def debugfileset(ui, repo, expr):
1623 def debugfileset(ui, repo, expr):
1624 '''parse and apply a fileset specification'''
1624 '''parse and apply a fileset specification'''
1625 if ui.verbose:
1625 if ui.verbose:
1626 tree = fileset.parse(expr)[0]
1626 tree = fileset.parse(expr)[0]
1627 ui.note(tree, "\n")
1627 ui.note(tree, "\n")
1628
1628
1629 for f in fileset.getfileset(repo[None], expr):
1629 for f in fileset.getfileset(repo[None], expr):
1630 ui.write("%s\n" % f)
1630 ui.write("%s\n" % f)
1631
1631
1632 @command('debugfsinfo', [], _('[PATH]'))
1632 @command('debugfsinfo', [], _('[PATH]'))
1633 def debugfsinfo(ui, path = "."):
1633 def debugfsinfo(ui, path = "."):
1634 """show information detected about current filesystem"""
1634 """show information detected about current filesystem"""
1635 util.writefile('.debugfsinfo', '')
1635 util.writefile('.debugfsinfo', '')
1636 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1636 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1637 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1637 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1638 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1638 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1639 and 'yes' or 'no'))
1639 and 'yes' or 'no'))
1640 os.unlink('.debugfsinfo')
1640 os.unlink('.debugfsinfo')
1641
1641
1642 @command('debuggetbundle',
1642 @command('debuggetbundle',
1643 [('H', 'head', [], _('id of head node'), _('ID')),
1643 [('H', 'head', [], _('id of head node'), _('ID')),
1644 ('C', 'common', [], _('id of common node'), _('ID')),
1644 ('C', 'common', [], _('id of common node'), _('ID')),
1645 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1645 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1646 _('REPO FILE [-H|-C ID]...'))
1646 _('REPO FILE [-H|-C ID]...'))
1647 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1647 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1648 """retrieves a bundle from a repo
1648 """retrieves a bundle from a repo
1649
1649
1650 Every ID must be a full-length hex node id string. Saves the bundle to the
1650 Every ID must be a full-length hex node id string. Saves the bundle to the
1651 given file.
1651 given file.
1652 """
1652 """
1653 repo = hg.peer(ui, opts, repopath)
1653 repo = hg.peer(ui, opts, repopath)
1654 if not repo.capable('getbundle'):
1654 if not repo.capable('getbundle'):
1655 raise util.Abort("getbundle() not supported by target repository")
1655 raise util.Abort("getbundle() not supported by target repository")
1656 args = {}
1656 args = {}
1657 if common:
1657 if common:
1658 args['common'] = [bin(s) for s in common]
1658 args['common'] = [bin(s) for s in common]
1659 if head:
1659 if head:
1660 args['heads'] = [bin(s) for s in head]
1660 args['heads'] = [bin(s) for s in head]
1661 bundle = repo.getbundle('debug', **args)
1661 bundle = repo.getbundle('debug', **args)
1662
1662
1663 bundletype = opts.get('type', 'bzip2').lower()
1663 bundletype = opts.get('type', 'bzip2').lower()
1664 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1664 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1665 bundletype = btypes.get(bundletype)
1665 bundletype = btypes.get(bundletype)
1666 if bundletype not in changegroup.bundletypes:
1666 if bundletype not in changegroup.bundletypes:
1667 raise util.Abort(_('unknown bundle type specified with --type'))
1667 raise util.Abort(_('unknown bundle type specified with --type'))
1668 changegroup.writebundle(bundle, bundlepath, bundletype)
1668 changegroup.writebundle(bundle, bundlepath, bundletype)
1669
1669
1670 @command('debugignore', [], '')
1670 @command('debugignore', [], '')
1671 def debugignore(ui, repo, *values, **opts):
1671 def debugignore(ui, repo, *values, **opts):
1672 """display the combined ignore pattern"""
1672 """display the combined ignore pattern"""
1673 ignore = repo.dirstate._ignore
1673 ignore = repo.dirstate._ignore
1674 includepat = getattr(ignore, 'includepat', None)
1674 includepat = getattr(ignore, 'includepat', None)
1675 if includepat is not None:
1675 if includepat is not None:
1676 ui.write("%s\n" % includepat)
1676 ui.write("%s\n" % includepat)
1677 else:
1677 else:
1678 raise util.Abort(_("no ignore patterns found"))
1678 raise util.Abort(_("no ignore patterns found"))
1679
1679
1680 @command('debugindex',
1680 @command('debugindex',
1681 [('c', 'changelog', False, _('open changelog')),
1681 [('c', 'changelog', False, _('open changelog')),
1682 ('m', 'manifest', False, _('open manifest')),
1682 ('m', 'manifest', False, _('open manifest')),
1683 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1683 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1684 _('[-f FORMAT] -c|-m|FILE'))
1684 _('[-f FORMAT] -c|-m|FILE'))
1685 def debugindex(ui, repo, file_ = None, **opts):
1685 def debugindex(ui, repo, file_ = None, **opts):
1686 """dump the contents of an index file"""
1686 """dump the contents of an index file"""
1687 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1687 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1688 format = opts.get('format', 0)
1688 format = opts.get('format', 0)
1689 if format not in (0, 1):
1689 if format not in (0, 1):
1690 raise util.Abort(_("unknown format %d") % format)
1690 raise util.Abort(_("unknown format %d") % format)
1691
1691
1692 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1692 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1693 if generaldelta:
1693 if generaldelta:
1694 basehdr = ' delta'
1694 basehdr = ' delta'
1695 else:
1695 else:
1696 basehdr = ' base'
1696 basehdr = ' base'
1697
1697
1698 if format == 0:
1698 if format == 0:
1699 ui.write(" rev offset length " + basehdr + " linkrev"
1699 ui.write(" rev offset length " + basehdr + " linkrev"
1700 " nodeid p1 p2\n")
1700 " nodeid p1 p2\n")
1701 elif format == 1:
1701 elif format == 1:
1702 ui.write(" rev flag offset length"
1702 ui.write(" rev flag offset length"
1703 " size " + basehdr + " link p1 p2 nodeid\n")
1703 " size " + basehdr + " link p1 p2 nodeid\n")
1704
1704
1705 for i in r:
1705 for i in r:
1706 node = r.node(i)
1706 node = r.node(i)
1707 if generaldelta:
1707 if generaldelta:
1708 base = r.deltaparent(i)
1708 base = r.deltaparent(i)
1709 else:
1709 else:
1710 base = r.chainbase(i)
1710 base = r.chainbase(i)
1711 if format == 0:
1711 if format == 0:
1712 try:
1712 try:
1713 pp = r.parents(node)
1713 pp = r.parents(node)
1714 except:
1714 except:
1715 pp = [nullid, nullid]
1715 pp = [nullid, nullid]
1716 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1716 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1717 i, r.start(i), r.length(i), base, r.linkrev(i),
1717 i, r.start(i), r.length(i), base, r.linkrev(i),
1718 short(node), short(pp[0]), short(pp[1])))
1718 short(node), short(pp[0]), short(pp[1])))
1719 elif format == 1:
1719 elif format == 1:
1720 pr = r.parentrevs(i)
1720 pr = r.parentrevs(i)
1721 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1721 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1722 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1722 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1723 base, r.linkrev(i), pr[0], pr[1], short(node)))
1723 base, r.linkrev(i), pr[0], pr[1], short(node)))
1724
1724
1725 @command('debugindexdot', [], _('FILE'))
1725 @command('debugindexdot', [], _('FILE'))
1726 def debugindexdot(ui, repo, file_):
1726 def debugindexdot(ui, repo, file_):
1727 """dump an index DAG as a graphviz dot file"""
1727 """dump an index DAG as a graphviz dot file"""
1728 r = None
1728 r = None
1729 if repo:
1729 if repo:
1730 filelog = repo.file(file_)
1730 filelog = repo.file(file_)
1731 if len(filelog):
1731 if len(filelog):
1732 r = filelog
1732 r = filelog
1733 if not r:
1733 if not r:
1734 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1734 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1735 ui.write("digraph G {\n")
1735 ui.write("digraph G {\n")
1736 for i in r:
1736 for i in r:
1737 node = r.node(i)
1737 node = r.node(i)
1738 pp = r.parents(node)
1738 pp = r.parents(node)
1739 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1739 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1740 if pp[1] != nullid:
1740 if pp[1] != nullid:
1741 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1741 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1742 ui.write("}\n")
1742 ui.write("}\n")
1743
1743
1744 @command('debuginstall', [], '')
1744 @command('debuginstall', [], '')
1745 def debuginstall(ui):
1745 def debuginstall(ui):
1746 '''test Mercurial installation
1746 '''test Mercurial installation
1747
1747
1748 Returns 0 on success.
1748 Returns 0 on success.
1749 '''
1749 '''
1750
1750
1751 def writetemp(contents):
1751 def writetemp(contents):
1752 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1752 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1753 f = os.fdopen(fd, "wb")
1753 f = os.fdopen(fd, "wb")
1754 f.write(contents)
1754 f.write(contents)
1755 f.close()
1755 f.close()
1756 return name
1756 return name
1757
1757
1758 problems = 0
1758 problems = 0
1759
1759
1760 # encoding
1760 # encoding
1761 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1761 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1762 try:
1762 try:
1763 encoding.fromlocal("test")
1763 encoding.fromlocal("test")
1764 except util.Abort, inst:
1764 except util.Abort, inst:
1765 ui.write(" %s\n" % inst)
1765 ui.write(" %s\n" % inst)
1766 ui.write(_(" (check that your locale is properly set)\n"))
1766 ui.write(_(" (check that your locale is properly set)\n"))
1767 problems += 1
1767 problems += 1
1768
1768
1769 # compiled modules
1769 # compiled modules
1770 ui.status(_("Checking installed modules (%s)...\n")
1770 ui.status(_("Checking installed modules (%s)...\n")
1771 % os.path.dirname(__file__))
1771 % os.path.dirname(__file__))
1772 try:
1772 try:
1773 import bdiff, mpatch, base85, osutil
1773 import bdiff, mpatch, base85, osutil
1774 except Exception, inst:
1774 except Exception, inst:
1775 ui.write(" %s\n" % inst)
1775 ui.write(" %s\n" % inst)
1776 ui.write(_(" One or more extensions could not be found"))
1776 ui.write(_(" One or more extensions could not be found"))
1777 ui.write(_(" (check that you compiled the extensions)\n"))
1777 ui.write(_(" (check that you compiled the extensions)\n"))
1778 problems += 1
1778 problems += 1
1779
1779
1780 # templates
1780 # templates
1781 ui.status(_("Checking templates...\n"))
1781 ui.status(_("Checking templates...\n"))
1782 try:
1782 try:
1783 import templater
1783 import templater
1784 templater.templater(templater.templatepath("map-cmdline.default"))
1784 templater.templater(templater.templatepath("map-cmdline.default"))
1785 except Exception, inst:
1785 except Exception, inst:
1786 ui.write(" %s\n" % inst)
1786 ui.write(" %s\n" % inst)
1787 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1787 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1788 problems += 1
1788 problems += 1
1789
1789
1790 # editor
1790 # editor
1791 ui.status(_("Checking commit editor...\n"))
1791 ui.status(_("Checking commit editor...\n"))
1792 editor = ui.geteditor()
1792 editor = ui.geteditor()
1793 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1793 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1794 if not cmdpath:
1794 if not cmdpath:
1795 if editor == 'vi':
1795 if editor == 'vi':
1796 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1796 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1797 ui.write(_(" (specify a commit editor in your configuration"
1797 ui.write(_(" (specify a commit editor in your configuration"
1798 " file)\n"))
1798 " file)\n"))
1799 else:
1799 else:
1800 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1800 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1801 ui.write(_(" (specify a commit editor in your configuration"
1801 ui.write(_(" (specify a commit editor in your configuration"
1802 " file)\n"))
1802 " file)\n"))
1803 problems += 1
1803 problems += 1
1804
1804
1805 # check username
1805 # check username
1806 ui.status(_("Checking username...\n"))
1806 ui.status(_("Checking username...\n"))
1807 try:
1807 try:
1808 ui.username()
1808 ui.username()
1809 except util.Abort, e:
1809 except util.Abort, e:
1810 ui.write(" %s\n" % e)
1810 ui.write(" %s\n" % e)
1811 ui.write(_(" (specify a username in your configuration file)\n"))
1811 ui.write(_(" (specify a username in your configuration file)\n"))
1812 problems += 1
1812 problems += 1
1813
1813
1814 if not problems:
1814 if not problems:
1815 ui.status(_("No problems detected\n"))
1815 ui.status(_("No problems detected\n"))
1816 else:
1816 else:
1817 ui.write(_("%s problems detected,"
1817 ui.write(_("%s problems detected,"
1818 " please check your install!\n") % problems)
1818 " please check your install!\n") % problems)
1819
1819
1820 return problems
1820 return problems
1821
1821
1822 @command('debugknown', [], _('REPO ID...'))
1822 @command('debugknown', [], _('REPO ID...'))
1823 def debugknown(ui, repopath, *ids, **opts):
1823 def debugknown(ui, repopath, *ids, **opts):
1824 """test whether node ids are known to a repo
1824 """test whether node ids are known to a repo
1825
1825
1826 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1826 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1827 indicating unknown/known.
1827 indicating unknown/known.
1828 """
1828 """
1829 repo = hg.peer(ui, opts, repopath)
1829 repo = hg.peer(ui, opts, repopath)
1830 if not repo.capable('known'):
1830 if not repo.capable('known'):
1831 raise util.Abort("known() not supported by target repository")
1831 raise util.Abort("known() not supported by target repository")
1832 flags = repo.known([bin(s) for s in ids])
1832 flags = repo.known([bin(s) for s in ids])
1833 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1833 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1834
1834
1835 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1835 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1836 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1836 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1837 '''access the pushkey key/value protocol
1837 '''access the pushkey key/value protocol
1838
1838
1839 With two args, list the keys in the given namespace.
1839 With two args, list the keys in the given namespace.
1840
1840
1841 With five args, set a key to new if it currently is set to old.
1841 With five args, set a key to new if it currently is set to old.
1842 Reports success or failure.
1842 Reports success or failure.
1843 '''
1843 '''
1844
1844
1845 target = hg.peer(ui, {}, repopath)
1845 target = hg.peer(ui, {}, repopath)
1846 if keyinfo:
1846 if keyinfo:
1847 key, old, new = keyinfo
1847 key, old, new = keyinfo
1848 r = target.pushkey(namespace, key, old, new)
1848 r = target.pushkey(namespace, key, old, new)
1849 ui.status(str(r) + '\n')
1849 ui.status(str(r) + '\n')
1850 return not r
1850 return not r
1851 else:
1851 else:
1852 for k, v in target.listkeys(namespace).iteritems():
1852 for k, v in target.listkeys(namespace).iteritems():
1853 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1853 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1854 v.encode('string-escape')))
1854 v.encode('string-escape')))
1855
1855
1856 @command('debugrebuildstate',
1856 @command('debugrebuildstate',
1857 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1857 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1858 _('[-r REV] [REV]'))
1858 _('[-r REV] [REV]'))
1859 def debugrebuildstate(ui, repo, rev="tip"):
1859 def debugrebuildstate(ui, repo, rev="tip"):
1860 """rebuild the dirstate as it would look like for the given revision"""
1860 """rebuild the dirstate as it would look like for the given revision"""
1861 ctx = scmutil.revsingle(repo, rev)
1861 ctx = scmutil.revsingle(repo, rev)
1862 wlock = repo.wlock()
1862 wlock = repo.wlock()
1863 try:
1863 try:
1864 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1864 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1865 finally:
1865 finally:
1866 wlock.release()
1866 wlock.release()
1867
1867
1868 @command('debugrename',
1868 @command('debugrename',
1869 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1869 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1870 _('[-r REV] FILE'))
1870 _('[-r REV] FILE'))
1871 def debugrename(ui, repo, file1, *pats, **opts):
1871 def debugrename(ui, repo, file1, *pats, **opts):
1872 """dump rename information"""
1872 """dump rename information"""
1873
1873
1874 ctx = scmutil.revsingle(repo, opts.get('rev'))
1874 ctx = scmutil.revsingle(repo, opts.get('rev'))
1875 m = scmutil.match(ctx, (file1,) + pats, opts)
1875 m = scmutil.match(ctx, (file1,) + pats, opts)
1876 for abs in ctx.walk(m):
1876 for abs in ctx.walk(m):
1877 fctx = ctx[abs]
1877 fctx = ctx[abs]
1878 o = fctx.filelog().renamed(fctx.filenode())
1878 o = fctx.filelog().renamed(fctx.filenode())
1879 rel = m.rel(abs)
1879 rel = m.rel(abs)
1880 if o:
1880 if o:
1881 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1881 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1882 else:
1882 else:
1883 ui.write(_("%s not renamed\n") % rel)
1883 ui.write(_("%s not renamed\n") % rel)
1884
1884
1885 @command('debugrevlog',
1885 @command('debugrevlog',
1886 [('c', 'changelog', False, _('open changelog')),
1886 [('c', 'changelog', False, _('open changelog')),
1887 ('m', 'manifest', False, _('open manifest')),
1887 ('m', 'manifest', False, _('open manifest')),
1888 ('d', 'dump', False, _('dump index data'))],
1888 ('d', 'dump', False, _('dump index data'))],
1889 _('-c|-m|FILE'))
1889 _('-c|-m|FILE'))
1890 def debugrevlog(ui, repo, file_ = None, **opts):
1890 def debugrevlog(ui, repo, file_ = None, **opts):
1891 """show data and statistics about a revlog"""
1891 """show data and statistics about a revlog"""
1892 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1892 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1893
1893
1894 if opts.get("dump"):
1894 if opts.get("dump"):
1895 numrevs = len(r)
1895 numrevs = len(r)
1896 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1896 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1897 " rawsize totalsize compression heads\n")
1897 " rawsize totalsize compression heads\n")
1898 ts = 0
1898 ts = 0
1899 heads = set()
1899 heads = set()
1900 for rev in xrange(numrevs):
1900 for rev in xrange(numrevs):
1901 dbase = r.deltaparent(rev)
1901 dbase = r.deltaparent(rev)
1902 if dbase == -1:
1902 if dbase == -1:
1903 dbase = rev
1903 dbase = rev
1904 cbase = r.chainbase(rev)
1904 cbase = r.chainbase(rev)
1905 p1, p2 = r.parentrevs(rev)
1905 p1, p2 = r.parentrevs(rev)
1906 rs = r.rawsize(rev)
1906 rs = r.rawsize(rev)
1907 ts = ts + rs
1907 ts = ts + rs
1908 heads -= set(r.parentrevs(rev))
1908 heads -= set(r.parentrevs(rev))
1909 heads.add(rev)
1909 heads.add(rev)
1910 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1910 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1911 (rev, p1, p2, r.start(rev), r.end(rev),
1911 (rev, p1, p2, r.start(rev), r.end(rev),
1912 r.start(dbase), r.start(cbase),
1912 r.start(dbase), r.start(cbase),
1913 r.start(p1), r.start(p2),
1913 r.start(p1), r.start(p2),
1914 rs, ts, ts / r.end(rev), len(heads)))
1914 rs, ts, ts / r.end(rev), len(heads)))
1915 return 0
1915 return 0
1916
1916
1917 v = r.version
1917 v = r.version
1918 format = v & 0xFFFF
1918 format = v & 0xFFFF
1919 flags = []
1919 flags = []
1920 gdelta = False
1920 gdelta = False
1921 if v & revlog.REVLOGNGINLINEDATA:
1921 if v & revlog.REVLOGNGINLINEDATA:
1922 flags.append('inline')
1922 flags.append('inline')
1923 if v & revlog.REVLOGGENERALDELTA:
1923 if v & revlog.REVLOGGENERALDELTA:
1924 gdelta = True
1924 gdelta = True
1925 flags.append('generaldelta')
1925 flags.append('generaldelta')
1926 if not flags:
1926 if not flags:
1927 flags = ['(none)']
1927 flags = ['(none)']
1928
1928
1929 nummerges = 0
1929 nummerges = 0
1930 numfull = 0
1930 numfull = 0
1931 numprev = 0
1931 numprev = 0
1932 nump1 = 0
1932 nump1 = 0
1933 nump2 = 0
1933 nump2 = 0
1934 numother = 0
1934 numother = 0
1935 nump1prev = 0
1935 nump1prev = 0
1936 nump2prev = 0
1936 nump2prev = 0
1937 chainlengths = []
1937 chainlengths = []
1938
1938
1939 datasize = [None, 0, 0L]
1939 datasize = [None, 0, 0L]
1940 fullsize = [None, 0, 0L]
1940 fullsize = [None, 0, 0L]
1941 deltasize = [None, 0, 0L]
1941 deltasize = [None, 0, 0L]
1942
1942
1943 def addsize(size, l):
1943 def addsize(size, l):
1944 if l[0] is None or size < l[0]:
1944 if l[0] is None or size < l[0]:
1945 l[0] = size
1945 l[0] = size
1946 if size > l[1]:
1946 if size > l[1]:
1947 l[1] = size
1947 l[1] = size
1948 l[2] += size
1948 l[2] += size
1949
1949
1950 numrevs = len(r)
1950 numrevs = len(r)
1951 for rev in xrange(numrevs):
1951 for rev in xrange(numrevs):
1952 p1, p2 = r.parentrevs(rev)
1952 p1, p2 = r.parentrevs(rev)
1953 delta = r.deltaparent(rev)
1953 delta = r.deltaparent(rev)
1954 if format > 0:
1954 if format > 0:
1955 addsize(r.rawsize(rev), datasize)
1955 addsize(r.rawsize(rev), datasize)
1956 if p2 != nullrev:
1956 if p2 != nullrev:
1957 nummerges += 1
1957 nummerges += 1
1958 size = r.length(rev)
1958 size = r.length(rev)
1959 if delta == nullrev:
1959 if delta == nullrev:
1960 chainlengths.append(0)
1960 chainlengths.append(0)
1961 numfull += 1
1961 numfull += 1
1962 addsize(size, fullsize)
1962 addsize(size, fullsize)
1963 else:
1963 else:
1964 chainlengths.append(chainlengths[delta] + 1)
1964 chainlengths.append(chainlengths[delta] + 1)
1965 addsize(size, deltasize)
1965 addsize(size, deltasize)
1966 if delta == rev - 1:
1966 if delta == rev - 1:
1967 numprev += 1
1967 numprev += 1
1968 if delta == p1:
1968 if delta == p1:
1969 nump1prev += 1
1969 nump1prev += 1
1970 elif delta == p2:
1970 elif delta == p2:
1971 nump2prev += 1
1971 nump2prev += 1
1972 elif delta == p1:
1972 elif delta == p1:
1973 nump1 += 1
1973 nump1 += 1
1974 elif delta == p2:
1974 elif delta == p2:
1975 nump2 += 1
1975 nump2 += 1
1976 elif delta != nullrev:
1976 elif delta != nullrev:
1977 numother += 1
1977 numother += 1
1978
1978
1979 numdeltas = numrevs - numfull
1979 numdeltas = numrevs - numfull
1980 numoprev = numprev - nump1prev - nump2prev
1980 numoprev = numprev - nump1prev - nump2prev
1981 totalrawsize = datasize[2]
1981 totalrawsize = datasize[2]
1982 datasize[2] /= numrevs
1982 datasize[2] /= numrevs
1983 fulltotal = fullsize[2]
1983 fulltotal = fullsize[2]
1984 fullsize[2] /= numfull
1984 fullsize[2] /= numfull
1985 deltatotal = deltasize[2]
1985 deltatotal = deltasize[2]
1986 deltasize[2] /= numrevs - numfull
1986 deltasize[2] /= numrevs - numfull
1987 totalsize = fulltotal + deltatotal
1987 totalsize = fulltotal + deltatotal
1988 avgchainlen = sum(chainlengths) / numrevs
1988 avgchainlen = sum(chainlengths) / numrevs
1989 compratio = totalrawsize / totalsize
1989 compratio = totalrawsize / totalsize
1990
1990
1991 basedfmtstr = '%%%dd\n'
1991 basedfmtstr = '%%%dd\n'
1992 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1992 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1993
1993
1994 def dfmtstr(max):
1994 def dfmtstr(max):
1995 return basedfmtstr % len(str(max))
1995 return basedfmtstr % len(str(max))
1996 def pcfmtstr(max, padding=0):
1996 def pcfmtstr(max, padding=0):
1997 return basepcfmtstr % (len(str(max)), ' ' * padding)
1997 return basepcfmtstr % (len(str(max)), ' ' * padding)
1998
1998
1999 def pcfmt(value, total):
1999 def pcfmt(value, total):
2000 return (value, 100 * float(value) / total)
2000 return (value, 100 * float(value) / total)
2001
2001
2002 ui.write('format : %d\n' % format)
2002 ui.write('format : %d\n' % format)
2003 ui.write('flags : %s\n' % ', '.join(flags))
2003 ui.write('flags : %s\n' % ', '.join(flags))
2004
2004
2005 ui.write('\n')
2005 ui.write('\n')
2006 fmt = pcfmtstr(totalsize)
2006 fmt = pcfmtstr(totalsize)
2007 fmt2 = dfmtstr(totalsize)
2007 fmt2 = dfmtstr(totalsize)
2008 ui.write('revisions : ' + fmt2 % numrevs)
2008 ui.write('revisions : ' + fmt2 % numrevs)
2009 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2009 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2010 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2010 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2011 ui.write('revisions : ' + fmt2 % numrevs)
2011 ui.write('revisions : ' + fmt2 % numrevs)
2012 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2012 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2013 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2013 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2014 ui.write('revision size : ' + fmt2 % totalsize)
2014 ui.write('revision size : ' + fmt2 % totalsize)
2015 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2015 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2016 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2016 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2017
2017
2018 ui.write('\n')
2018 ui.write('\n')
2019 fmt = dfmtstr(max(avgchainlen, compratio))
2019 fmt = dfmtstr(max(avgchainlen, compratio))
2020 ui.write('avg chain length : ' + fmt % avgchainlen)
2020 ui.write('avg chain length : ' + fmt % avgchainlen)
2021 ui.write('compression ratio : ' + fmt % compratio)
2021 ui.write('compression ratio : ' + fmt % compratio)
2022
2022
2023 if format > 0:
2023 if format > 0:
2024 ui.write('\n')
2024 ui.write('\n')
2025 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2025 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2026 % tuple(datasize))
2026 % tuple(datasize))
2027 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2027 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2028 % tuple(fullsize))
2028 % tuple(fullsize))
2029 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2029 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2030 % tuple(deltasize))
2030 % tuple(deltasize))
2031
2031
2032 if numdeltas > 0:
2032 if numdeltas > 0:
2033 ui.write('\n')
2033 ui.write('\n')
2034 fmt = pcfmtstr(numdeltas)
2034 fmt = pcfmtstr(numdeltas)
2035 fmt2 = pcfmtstr(numdeltas, 4)
2035 fmt2 = pcfmtstr(numdeltas, 4)
2036 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2036 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2037 if numprev > 0:
2037 if numprev > 0:
2038 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2038 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2039 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2039 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2040 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2040 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2041 if gdelta:
2041 if gdelta:
2042 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2042 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2043 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2043 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2044 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2044 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2045
2045
2046 @command('debugrevspec', [], ('REVSPEC'))
2046 @command('debugrevspec', [], ('REVSPEC'))
2047 def debugrevspec(ui, repo, expr):
2047 def debugrevspec(ui, repo, expr):
2048 '''parse and apply a revision specification'''
2048 '''parse and apply a revision specification'''
2049 if ui.verbose:
2049 if ui.verbose:
2050 tree = revset.parse(expr)[0]
2050 tree = revset.parse(expr)[0]
2051 ui.note(tree, "\n")
2051 ui.note(tree, "\n")
2052 newtree = revset.findaliases(ui, tree)
2052 newtree = revset.findaliases(ui, tree)
2053 if newtree != tree:
2053 if newtree != tree:
2054 ui.note(newtree, "\n")
2054 ui.note(newtree, "\n")
2055 func = revset.match(ui, expr)
2055 func = revset.match(ui, expr)
2056 for c in func(repo, range(len(repo))):
2056 for c in func(repo, range(len(repo))):
2057 ui.write("%s\n" % c)
2057 ui.write("%s\n" % c)
2058
2058
2059 @command('debugsetparents', [], _('REV1 [REV2]'))
2059 @command('debugsetparents', [], _('REV1 [REV2]'))
2060 def debugsetparents(ui, repo, rev1, rev2=None):
2060 def debugsetparents(ui, repo, rev1, rev2=None):
2061 """manually set the parents of the current working directory
2061 """manually set the parents of the current working directory
2062
2062
2063 This is useful for writing repository conversion tools, but should
2063 This is useful for writing repository conversion tools, but should
2064 be used with care.
2064 be used with care.
2065
2065
2066 Returns 0 on success.
2066 Returns 0 on success.
2067 """
2067 """
2068
2068
2069 r1 = scmutil.revsingle(repo, rev1).node()
2069 r1 = scmutil.revsingle(repo, rev1).node()
2070 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2070 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2071
2071
2072 wlock = repo.wlock()
2072 wlock = repo.wlock()
2073 try:
2073 try:
2074 repo.dirstate.setparents(r1, r2)
2074 repo.dirstate.setparents(r1, r2)
2075 finally:
2075 finally:
2076 wlock.release()
2076 wlock.release()
2077
2077
2078 @command('debugstate',
2078 @command('debugstate',
2079 [('', 'nodates', None, _('do not display the saved mtime')),
2079 [('', 'nodates', None, _('do not display the saved mtime')),
2080 ('', 'datesort', None, _('sort by saved mtime'))],
2080 ('', 'datesort', None, _('sort by saved mtime'))],
2081 _('[OPTION]...'))
2081 _('[OPTION]...'))
2082 def debugstate(ui, repo, nodates=None, datesort=None):
2082 def debugstate(ui, repo, nodates=None, datesort=None):
2083 """show the contents of the current dirstate"""
2083 """show the contents of the current dirstate"""
2084 timestr = ""
2084 timestr = ""
2085 showdate = not nodates
2085 showdate = not nodates
2086 if datesort:
2086 if datesort:
2087 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2087 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2088 else:
2088 else:
2089 keyfunc = None # sort by filename
2089 keyfunc = None # sort by filename
2090 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2090 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2091 if showdate:
2091 if showdate:
2092 if ent[3] == -1:
2092 if ent[3] == -1:
2093 # Pad or slice to locale representation
2093 # Pad or slice to locale representation
2094 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2094 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2095 time.localtime(0)))
2095 time.localtime(0)))
2096 timestr = 'unset'
2096 timestr = 'unset'
2097 timestr = (timestr[:locale_len] +
2097 timestr = (timestr[:locale_len] +
2098 ' ' * (locale_len - len(timestr)))
2098 ' ' * (locale_len - len(timestr)))
2099 else:
2099 else:
2100 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2100 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2101 time.localtime(ent[3]))
2101 time.localtime(ent[3]))
2102 if ent[1] & 020000:
2102 if ent[1] & 020000:
2103 mode = 'lnk'
2103 mode = 'lnk'
2104 else:
2104 else:
2105 mode = '%3o' % (ent[1] & 0777)
2105 mode = '%3o' % (ent[1] & 0777)
2106 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2106 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2107 for f in repo.dirstate.copies():
2107 for f in repo.dirstate.copies():
2108 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2108 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2109
2109
2110 @command('debugsub',
2110 @command('debugsub',
2111 [('r', 'rev', '',
2111 [('r', 'rev', '',
2112 _('revision to check'), _('REV'))],
2112 _('revision to check'), _('REV'))],
2113 _('[-r REV] [REV]'))
2113 _('[-r REV] [REV]'))
2114 def debugsub(ui, repo, rev=None):
2114 def debugsub(ui, repo, rev=None):
2115 ctx = scmutil.revsingle(repo, rev, None)
2115 ctx = scmutil.revsingle(repo, rev, None)
2116 for k, v in sorted(ctx.substate.items()):
2116 for k, v in sorted(ctx.substate.items()):
2117 ui.write('path %s\n' % k)
2117 ui.write('path %s\n' % k)
2118 ui.write(' source %s\n' % v[0])
2118 ui.write(' source %s\n' % v[0])
2119 ui.write(' revision %s\n' % v[1])
2119 ui.write(' revision %s\n' % v[1])
2120
2120
2121 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2121 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2122 def debugwalk(ui, repo, *pats, **opts):
2122 def debugwalk(ui, repo, *pats, **opts):
2123 """show how files match on given patterns"""
2123 """show how files match on given patterns"""
2124 m = scmutil.match(repo[None], pats, opts)
2124 m = scmutil.match(repo[None], pats, opts)
2125 items = list(repo.walk(m))
2125 items = list(repo.walk(m))
2126 if not items:
2126 if not items:
2127 return
2127 return
2128 fmt = 'f %%-%ds %%-%ds %%s' % (
2128 fmt = 'f %%-%ds %%-%ds %%s' % (
2129 max([len(abs) for abs in items]),
2129 max([len(abs) for abs in items]),
2130 max([len(m.rel(abs)) for abs in items]))
2130 max([len(m.rel(abs)) for abs in items]))
2131 for abs in items:
2131 for abs in items:
2132 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2132 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2133 ui.write("%s\n" % line.rstrip())
2133 ui.write("%s\n" % line.rstrip())
2134
2134
2135 @command('debugwireargs',
2135 @command('debugwireargs',
2136 [('', 'three', '', 'three'),
2136 [('', 'three', '', 'three'),
2137 ('', 'four', '', 'four'),
2137 ('', 'four', '', 'four'),
2138 ('', 'five', '', 'five'),
2138 ('', 'five', '', 'five'),
2139 ] + remoteopts,
2139 ] + remoteopts,
2140 _('REPO [OPTIONS]... [ONE [TWO]]'))
2140 _('REPO [OPTIONS]... [ONE [TWO]]'))
2141 def debugwireargs(ui, repopath, *vals, **opts):
2141 def debugwireargs(ui, repopath, *vals, **opts):
2142 repo = hg.peer(ui, opts, repopath)
2142 repo = hg.peer(ui, opts, repopath)
2143 for opt in remoteopts:
2143 for opt in remoteopts:
2144 del opts[opt[1]]
2144 del opts[opt[1]]
2145 args = {}
2145 args = {}
2146 for k, v in opts.iteritems():
2146 for k, v in opts.iteritems():
2147 if v:
2147 if v:
2148 args[k] = v
2148 args[k] = v
2149 # run twice to check that we don't mess up the stream for the next command
2149 # run twice to check that we don't mess up the stream for the next command
2150 res1 = repo.debugwireargs(*vals, **args)
2150 res1 = repo.debugwireargs(*vals, **args)
2151 res2 = repo.debugwireargs(*vals, **args)
2151 res2 = repo.debugwireargs(*vals, **args)
2152 ui.write("%s\n" % res1)
2152 ui.write("%s\n" % res1)
2153 if res1 != res2:
2153 if res1 != res2:
2154 ui.warn("%s\n" % res2)
2154 ui.warn("%s\n" % res2)
2155
2155
2156 @command('^diff',
2156 @command('^diff',
2157 [('r', 'rev', [], _('revision'), _('REV')),
2157 [('r', 'rev', [], _('revision'), _('REV')),
2158 ('c', 'change', '', _('change made by revision'), _('REV'))
2158 ('c', 'change', '', _('change made by revision'), _('REV'))
2159 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2159 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2161 def diff(ui, repo, *pats, **opts):
2161 def diff(ui, repo, *pats, **opts):
2162 """diff repository (or selected files)
2162 """diff repository (or selected files)
2163
2163
2164 Show differences between revisions for the specified files.
2164 Show differences between revisions for the specified files.
2165
2165
2166 Differences between files are shown using the unified diff format.
2166 Differences between files are shown using the unified diff format.
2167
2167
2168 .. note::
2168 .. note::
2169 diff may generate unexpected results for merges, as it will
2169 diff may generate unexpected results for merges, as it will
2170 default to comparing against the working directory's first
2170 default to comparing against the working directory's first
2171 parent changeset if no revisions are specified.
2171 parent changeset if no revisions are specified.
2172
2172
2173 When two revision arguments are given, then changes are shown
2173 When two revision arguments are given, then changes are shown
2174 between those revisions. If only one revision is specified then
2174 between those revisions. If only one revision is specified then
2175 that revision is compared to the working directory, and, when no
2175 that revision is compared to the working directory, and, when no
2176 revisions are specified, the working directory files are compared
2176 revisions are specified, the working directory files are compared
2177 to its parent.
2177 to its parent.
2178
2178
2179 Alternatively you can specify -c/--change with a revision to see
2179 Alternatively you can specify -c/--change with a revision to see
2180 the changes in that changeset relative to its first parent.
2180 the changes in that changeset relative to its first parent.
2181
2181
2182 Without the -a/--text option, diff will avoid generating diffs of
2182 Without the -a/--text option, diff will avoid generating diffs of
2183 files it detects as binary. With -a, diff will generate a diff
2183 files it detects as binary. With -a, diff will generate a diff
2184 anyway, probably with undesirable results.
2184 anyway, probably with undesirable results.
2185
2185
2186 Use the -g/--git option to generate diffs in the git extended diff
2186 Use the -g/--git option to generate diffs in the git extended diff
2187 format. For more information, read :hg:`help diffs`.
2187 format. For more information, read :hg:`help diffs`.
2188
2188
2189 .. container:: verbose
2189 .. container:: verbose
2190
2190
2191 Examples:
2191 Examples:
2192
2192
2193 - compare a file in the current working directory to its parent::
2193 - compare a file in the current working directory to its parent::
2194
2194
2195 hg diff foo.c
2195 hg diff foo.c
2196
2196
2197 - compare two historical versions of a directory, with rename info::
2197 - compare two historical versions of a directory, with rename info::
2198
2198
2199 hg diff --git -r 1.0:1.2 lib/
2199 hg diff --git -r 1.0:1.2 lib/
2200
2200
2201 - get change stats relative to the last change on some date::
2201 - get change stats relative to the last change on some date::
2202
2202
2203 hg diff --stat -r "date('may 2')"
2203 hg diff --stat -r "date('may 2')"
2204
2204
2205 - diff all newly-added files that contain a keyword::
2205 - diff all newly-added files that contain a keyword::
2206
2206
2207 hg diff "set:added() and grep(GNU)"
2207 hg diff "set:added() and grep(GNU)"
2208
2208
2209 - compare a revision and its parents::
2209 - compare a revision and its parents::
2210
2210
2211 hg diff -c 9353 # compare against first parent
2211 hg diff -c 9353 # compare against first parent
2212 hg diff -r 9353^:9353 # same using revset syntax
2212 hg diff -r 9353^:9353 # same using revset syntax
2213 hg diff -r 9353^2:9353 # compare against the second parent
2213 hg diff -r 9353^2:9353 # compare against the second parent
2214
2214
2215 Returns 0 on success.
2215 Returns 0 on success.
2216 """
2216 """
2217
2217
2218 revs = opts.get('rev')
2218 revs = opts.get('rev')
2219 change = opts.get('change')
2219 change = opts.get('change')
2220 stat = opts.get('stat')
2220 stat = opts.get('stat')
2221 reverse = opts.get('reverse')
2221 reverse = opts.get('reverse')
2222
2222
2223 if revs and change:
2223 if revs and change:
2224 msg = _('cannot specify --rev and --change at the same time')
2224 msg = _('cannot specify --rev and --change at the same time')
2225 raise util.Abort(msg)
2225 raise util.Abort(msg)
2226 elif change:
2226 elif change:
2227 node2 = scmutil.revsingle(repo, change, None).node()
2227 node2 = scmutil.revsingle(repo, change, None).node()
2228 node1 = repo[node2].p1().node()
2228 node1 = repo[node2].p1().node()
2229 else:
2229 else:
2230 node1, node2 = scmutil.revpair(repo, revs)
2230 node1, node2 = scmutil.revpair(repo, revs)
2231
2231
2232 if reverse:
2232 if reverse:
2233 node1, node2 = node2, node1
2233 node1, node2 = node2, node1
2234
2234
2235 diffopts = patch.diffopts(ui, opts)
2235 diffopts = patch.diffopts(ui, opts)
2236 m = scmutil.match(repo[node2], pats, opts)
2236 m = scmutil.match(repo[node2], pats, opts)
2237 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2237 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2238 listsubrepos=opts.get('subrepos'))
2238 listsubrepos=opts.get('subrepos'))
2239
2239
2240 @command('^export',
2240 @command('^export',
2241 [('o', 'output', '',
2241 [('o', 'output', '',
2242 _('print output to file with formatted name'), _('FORMAT')),
2242 _('print output to file with formatted name'), _('FORMAT')),
2243 ('', 'switch-parent', None, _('diff against the second parent')),
2243 ('', 'switch-parent', None, _('diff against the second parent')),
2244 ('r', 'rev', [], _('revisions to export'), _('REV')),
2244 ('r', 'rev', [], _('revisions to export'), _('REV')),
2245 ] + diffopts,
2245 ] + diffopts,
2246 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2246 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2247 def export(ui, repo, *changesets, **opts):
2247 def export(ui, repo, *changesets, **opts):
2248 """dump the header and diffs for one or more changesets
2248 """dump the header and diffs for one or more changesets
2249
2249
2250 Print the changeset header and diffs for one or more revisions.
2250 Print the changeset header and diffs for one or more revisions.
2251
2251
2252 The information shown in the changeset header is: author, date,
2252 The information shown in the changeset header is: author, date,
2253 branch name (if non-default), changeset hash, parent(s) and commit
2253 branch name (if non-default), changeset hash, parent(s) and commit
2254 comment.
2254 comment.
2255
2255
2256 .. note::
2256 .. note::
2257 export may generate unexpected diff output for merge
2257 export may generate unexpected diff output for merge
2258 changesets, as it will compare the merge changeset against its
2258 changesets, as it will compare the merge changeset against its
2259 first parent only.
2259 first parent only.
2260
2260
2261 Output may be to a file, in which case the name of the file is
2261 Output may be to a file, in which case the name of the file is
2262 given using a format string. The formatting rules are as follows:
2262 given using a format string. The formatting rules are as follows:
2263
2263
2264 :``%%``: literal "%" character
2264 :``%%``: literal "%" character
2265 :``%H``: changeset hash (40 hexadecimal digits)
2265 :``%H``: changeset hash (40 hexadecimal digits)
2266 :``%N``: number of patches being generated
2266 :``%N``: number of patches being generated
2267 :``%R``: changeset revision number
2267 :``%R``: changeset revision number
2268 :``%b``: basename of the exporting repository
2268 :``%b``: basename of the exporting repository
2269 :``%h``: short-form changeset hash (12 hexadecimal digits)
2269 :``%h``: short-form changeset hash (12 hexadecimal digits)
2270 :``%m``: first line of the commit message (only alphanumeric characters)
2270 :``%m``: first line of the commit message (only alphanumeric characters)
2271 :``%n``: zero-padded sequence number, starting at 1
2271 :``%n``: zero-padded sequence number, starting at 1
2272 :``%r``: zero-padded changeset revision number
2272 :``%r``: zero-padded changeset revision number
2273
2273
2274 Without the -a/--text option, export will avoid generating diffs
2274 Without the -a/--text option, export will avoid generating diffs
2275 of files it detects as binary. With -a, export will generate a
2275 of files it detects as binary. With -a, export will generate a
2276 diff anyway, probably with undesirable results.
2276 diff anyway, probably with undesirable results.
2277
2277
2278 Use the -g/--git option to generate diffs in the git extended diff
2278 Use the -g/--git option to generate diffs in the git extended diff
2279 format. See :hg:`help diffs` for more information.
2279 format. See :hg:`help diffs` for more information.
2280
2280
2281 With the --switch-parent option, the diff will be against the
2281 With the --switch-parent option, the diff will be against the
2282 second parent. It can be useful to review a merge.
2282 second parent. It can be useful to review a merge.
2283
2283
2284 .. container:: verbose
2284 .. container:: verbose
2285
2285
2286 Examples:
2286 Examples:
2287
2287
2288 - use export and import to transplant a bugfix to the current
2288 - use export and import to transplant a bugfix to the current
2289 branch::
2289 branch::
2290
2290
2291 hg export -r 9353 | hg import -
2291 hg export -r 9353 | hg import -
2292
2292
2293 - export all the changesets between two revisions to a file with
2293 - export all the changesets between two revisions to a file with
2294 rename information::
2294 rename information::
2295
2295
2296 hg export --git -r 123:150 > changes.txt
2296 hg export --git -r 123:150 > changes.txt
2297
2297
2298 - split outgoing changes into a series of patches with
2298 - split outgoing changes into a series of patches with
2299 descriptive names::
2299 descriptive names::
2300
2300
2301 hg export -r "outgoing()" -o "%n-%m.patch"
2301 hg export -r "outgoing()" -o "%n-%m.patch"
2302
2302
2303 Returns 0 on success.
2303 Returns 0 on success.
2304 """
2304 """
2305 changesets += tuple(opts.get('rev', []))
2305 changesets += tuple(opts.get('rev', []))
2306 if not changesets:
2306 if not changesets:
2307 raise util.Abort(_("export requires at least one changeset"))
2307 raise util.Abort(_("export requires at least one changeset"))
2308 revs = scmutil.revrange(repo, changesets)
2308 revs = scmutil.revrange(repo, changesets)
2309 if len(revs) > 1:
2309 if len(revs) > 1:
2310 ui.note(_('exporting patches:\n'))
2310 ui.note(_('exporting patches:\n'))
2311 else:
2311 else:
2312 ui.note(_('exporting patch:\n'))
2312 ui.note(_('exporting patch:\n'))
2313 cmdutil.export(repo, revs, template=opts.get('output'),
2313 cmdutil.export(repo, revs, template=opts.get('output'),
2314 switch_parent=opts.get('switch_parent'),
2314 switch_parent=opts.get('switch_parent'),
2315 opts=patch.diffopts(ui, opts))
2315 opts=patch.diffopts(ui, opts))
2316
2316
2317 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2317 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2318 def forget(ui, repo, *pats, **opts):
2318 def forget(ui, repo, *pats, **opts):
2319 """forget the specified files on the next commit
2319 """forget the specified files on the next commit
2320
2320
2321 Mark the specified files so they will no longer be tracked
2321 Mark the specified files so they will no longer be tracked
2322 after the next commit.
2322 after the next commit.
2323
2323
2324 This only removes files from the current branch, not from the
2324 This only removes files from the current branch, not from the
2325 entire project history, and it does not delete them from the
2325 entire project history, and it does not delete them from the
2326 working directory.
2326 working directory.
2327
2327
2328 To undo a forget before the next commit, see :hg:`add`.
2328 To undo a forget before the next commit, see :hg:`add`.
2329
2329
2330 Returns 0 on success.
2330 Returns 0 on success.
2331 """
2331 """
2332
2332
2333 if not pats:
2333 if not pats:
2334 raise util.Abort(_('no files specified'))
2334 raise util.Abort(_('no files specified'))
2335
2335
2336 m = scmutil.match(repo[None], pats, opts)
2336 m = scmutil.match(repo[None], pats, opts)
2337 s = repo.status(match=m, clean=True)
2337 s = repo.status(match=m, clean=True)
2338 forget = sorted(s[0] + s[1] + s[3] + s[6])
2338 forget = sorted(s[0] + s[1] + s[3] + s[6])
2339 errs = 0
2339 errs = 0
2340
2340
2341 for f in m.files():
2341 for f in m.files():
2342 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2342 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2343 if os.path.exists(m.rel(f)):
2343 if os.path.exists(m.rel(f)):
2344 ui.warn(_('not removing %s: file is already untracked\n')
2344 ui.warn(_('not removing %s: file is already untracked\n')
2345 % m.rel(f))
2345 % m.rel(f))
2346 errs = 1
2346 errs = 1
2347
2347
2348 for f in forget:
2348 for f in forget:
2349 if ui.verbose or not m.exact(f):
2349 if ui.verbose or not m.exact(f):
2350 ui.status(_('removing %s\n') % m.rel(f))
2350 ui.status(_('removing %s\n') % m.rel(f))
2351
2351
2352 repo[None].forget(forget)
2352 repo[None].forget(forget)
2353 return errs
2353 return errs
2354
2354
2355 @command('grep',
2355 @command('grep',
2356 [('0', 'print0', None, _('end fields with NUL')),
2356 [('0', 'print0', None, _('end fields with NUL')),
2357 ('', 'all', None, _('print all revisions that match')),
2357 ('', 'all', None, _('print all revisions that match')),
2358 ('a', 'text', None, _('treat all files as text')),
2358 ('a', 'text', None, _('treat all files as text')),
2359 ('f', 'follow', None,
2359 ('f', 'follow', None,
2360 _('follow changeset history,'
2360 _('follow changeset history,'
2361 ' or file history across copies and renames')),
2361 ' or file history across copies and renames')),
2362 ('i', 'ignore-case', None, _('ignore case when matching')),
2362 ('i', 'ignore-case', None, _('ignore case when matching')),
2363 ('l', 'files-with-matches', None,
2363 ('l', 'files-with-matches', None,
2364 _('print only filenames and revisions that match')),
2364 _('print only filenames and revisions that match')),
2365 ('n', 'line-number', None, _('print matching line numbers')),
2365 ('n', 'line-number', None, _('print matching line numbers')),
2366 ('r', 'rev', [],
2366 ('r', 'rev', [],
2367 _('only search files changed within revision range'), _('REV')),
2367 _('only search files changed within revision range'), _('REV')),
2368 ('u', 'user', None, _('list the author (long with -v)')),
2368 ('u', 'user', None, _('list the author (long with -v)')),
2369 ('d', 'date', None, _('list the date (short with -q)')),
2369 ('d', 'date', None, _('list the date (short with -q)')),
2370 ] + walkopts,
2370 ] + walkopts,
2371 _('[OPTION]... PATTERN [FILE]...'))
2371 _('[OPTION]... PATTERN [FILE]...'))
2372 def grep(ui, repo, pattern, *pats, **opts):
2372 def grep(ui, repo, pattern, *pats, **opts):
2373 """search for a pattern in specified files and revisions
2373 """search for a pattern in specified files and revisions
2374
2374
2375 Search revisions of files for a regular expression.
2375 Search revisions of files for a regular expression.
2376
2376
2377 This command behaves differently than Unix grep. It only accepts
2377 This command behaves differently than Unix grep. It only accepts
2378 Python/Perl regexps. It searches repository history, not the
2378 Python/Perl regexps. It searches repository history, not the
2379 working directory. It always prints the revision number in which a
2379 working directory. It always prints the revision number in which a
2380 match appears.
2380 match appears.
2381
2381
2382 By default, grep only prints output for the first revision of a
2382 By default, grep only prints output for the first revision of a
2383 file in which it finds a match. To get it to print every revision
2383 file in which it finds a match. To get it to print every revision
2384 that contains a change in match status ("-" for a match that
2384 that contains a change in match status ("-" for a match that
2385 becomes a non-match, or "+" for a non-match that becomes a match),
2385 becomes a non-match, or "+" for a non-match that becomes a match),
2386 use the --all flag.
2386 use the --all flag.
2387
2387
2388 Returns 0 if a match is found, 1 otherwise.
2388 Returns 0 if a match is found, 1 otherwise.
2389 """
2389 """
2390 reflags = 0
2390 reflags = 0
2391 if opts.get('ignore_case'):
2391 if opts.get('ignore_case'):
2392 reflags |= re.I
2392 reflags |= re.I
2393 try:
2393 try:
2394 regexp = re.compile(pattern, reflags)
2394 regexp = re.compile(pattern, reflags)
2395 except re.error, inst:
2395 except re.error, inst:
2396 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2396 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2397 return 1
2397 return 1
2398 sep, eol = ':', '\n'
2398 sep, eol = ':', '\n'
2399 if opts.get('print0'):
2399 if opts.get('print0'):
2400 sep = eol = '\0'
2400 sep = eol = '\0'
2401
2401
2402 getfile = util.lrucachefunc(repo.file)
2402 getfile = util.lrucachefunc(repo.file)
2403
2403
2404 def matchlines(body):
2404 def matchlines(body):
2405 begin = 0
2405 begin = 0
2406 linenum = 0
2406 linenum = 0
2407 while True:
2407 while True:
2408 match = regexp.search(body, begin)
2408 match = regexp.search(body, begin)
2409 if not match:
2409 if not match:
2410 break
2410 break
2411 mstart, mend = match.span()
2411 mstart, mend = match.span()
2412 linenum += body.count('\n', begin, mstart) + 1
2412 linenum += body.count('\n', begin, mstart) + 1
2413 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2413 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2414 begin = body.find('\n', mend) + 1 or len(body)
2414 begin = body.find('\n', mend) + 1 or len(body)
2415 lend = begin - 1
2415 lend = begin - 1
2416 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2416 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2417
2417
2418 class linestate(object):
2418 class linestate(object):
2419 def __init__(self, line, linenum, colstart, colend):
2419 def __init__(self, line, linenum, colstart, colend):
2420 self.line = line
2420 self.line = line
2421 self.linenum = linenum
2421 self.linenum = linenum
2422 self.colstart = colstart
2422 self.colstart = colstart
2423 self.colend = colend
2423 self.colend = colend
2424
2424
2425 def __hash__(self):
2425 def __hash__(self):
2426 return hash((self.linenum, self.line))
2426 return hash((self.linenum, self.line))
2427
2427
2428 def __eq__(self, other):
2428 def __eq__(self, other):
2429 return self.line == other.line
2429 return self.line == other.line
2430
2430
2431 matches = {}
2431 matches = {}
2432 copies = {}
2432 copies = {}
2433 def grepbody(fn, rev, body):
2433 def grepbody(fn, rev, body):
2434 matches[rev].setdefault(fn, [])
2434 matches[rev].setdefault(fn, [])
2435 m = matches[rev][fn]
2435 m = matches[rev][fn]
2436 for lnum, cstart, cend, line in matchlines(body):
2436 for lnum, cstart, cend, line in matchlines(body):
2437 s = linestate(line, lnum, cstart, cend)
2437 s = linestate(line, lnum, cstart, cend)
2438 m.append(s)
2438 m.append(s)
2439
2439
2440 def difflinestates(a, b):
2440 def difflinestates(a, b):
2441 sm = difflib.SequenceMatcher(None, a, b)
2441 sm = difflib.SequenceMatcher(None, a, b)
2442 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2442 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2443 if tag == 'insert':
2443 if tag == 'insert':
2444 for i in xrange(blo, bhi):
2444 for i in xrange(blo, bhi):
2445 yield ('+', b[i])
2445 yield ('+', b[i])
2446 elif tag == 'delete':
2446 elif tag == 'delete':
2447 for i in xrange(alo, ahi):
2447 for i in xrange(alo, ahi):
2448 yield ('-', a[i])
2448 yield ('-', a[i])
2449 elif tag == 'replace':
2449 elif tag == 'replace':
2450 for i in xrange(alo, ahi):
2450 for i in xrange(alo, ahi):
2451 yield ('-', a[i])
2451 yield ('-', a[i])
2452 for i in xrange(blo, bhi):
2452 for i in xrange(blo, bhi):
2453 yield ('+', b[i])
2453 yield ('+', b[i])
2454
2454
2455 def display(fn, ctx, pstates, states):
2455 def display(fn, ctx, pstates, states):
2456 rev = ctx.rev()
2456 rev = ctx.rev()
2457 datefunc = ui.quiet and util.shortdate or util.datestr
2457 datefunc = ui.quiet and util.shortdate or util.datestr
2458 found = False
2458 found = False
2459 filerevmatches = {}
2459 filerevmatches = {}
2460 def binary():
2460 def binary():
2461 flog = getfile(fn)
2461 flog = getfile(fn)
2462 return util.binary(flog.read(ctx.filenode(fn)))
2462 return util.binary(flog.read(ctx.filenode(fn)))
2463
2463
2464 if opts.get('all'):
2464 if opts.get('all'):
2465 iter = difflinestates(pstates, states)
2465 iter = difflinestates(pstates, states)
2466 else:
2466 else:
2467 iter = [('', l) for l in states]
2467 iter = [('', l) for l in states]
2468 for change, l in iter:
2468 for change, l in iter:
2469 cols = [fn, str(rev)]
2469 cols = [fn, str(rev)]
2470 before, match, after = None, None, None
2470 before, match, after = None, None, None
2471 if opts.get('line_number'):
2471 if opts.get('line_number'):
2472 cols.append(str(l.linenum))
2472 cols.append(str(l.linenum))
2473 if opts.get('all'):
2473 if opts.get('all'):
2474 cols.append(change)
2474 cols.append(change)
2475 if opts.get('user'):
2475 if opts.get('user'):
2476 cols.append(ui.shortuser(ctx.user()))
2476 cols.append(ui.shortuser(ctx.user()))
2477 if opts.get('date'):
2477 if opts.get('date'):
2478 cols.append(datefunc(ctx.date()))
2478 cols.append(datefunc(ctx.date()))
2479 if opts.get('files_with_matches'):
2479 if opts.get('files_with_matches'):
2480 c = (fn, rev)
2480 c = (fn, rev)
2481 if c in filerevmatches:
2481 if c in filerevmatches:
2482 continue
2482 continue
2483 filerevmatches[c] = 1
2483 filerevmatches[c] = 1
2484 else:
2484 else:
2485 before = l.line[:l.colstart]
2485 before = l.line[:l.colstart]
2486 match = l.line[l.colstart:l.colend]
2486 match = l.line[l.colstart:l.colend]
2487 after = l.line[l.colend:]
2487 after = l.line[l.colend:]
2488 ui.write(sep.join(cols))
2488 ui.write(sep.join(cols))
2489 if before is not None:
2489 if before is not None:
2490 if not opts.get('text') and binary():
2490 if not opts.get('text') and binary():
2491 ui.write(sep + " Binary file matches")
2491 ui.write(sep + " Binary file matches")
2492 else:
2492 else:
2493 ui.write(sep + before)
2493 ui.write(sep + before)
2494 ui.write(match, label='grep.match')
2494 ui.write(match, label='grep.match')
2495 ui.write(after)
2495 ui.write(after)
2496 ui.write(eol)
2496 ui.write(eol)
2497 found = True
2497 found = True
2498 return found
2498 return found
2499
2499
2500 skip = {}
2500 skip = {}
2501 revfiles = {}
2501 revfiles = {}
2502 matchfn = scmutil.match(repo[None], pats, opts)
2502 matchfn = scmutil.match(repo[None], pats, opts)
2503 found = False
2503 found = False
2504 follow = opts.get('follow')
2504 follow = opts.get('follow')
2505
2505
2506 def prep(ctx, fns):
2506 def prep(ctx, fns):
2507 rev = ctx.rev()
2507 rev = ctx.rev()
2508 pctx = ctx.p1()
2508 pctx = ctx.p1()
2509 parent = pctx.rev()
2509 parent = pctx.rev()
2510 matches.setdefault(rev, {})
2510 matches.setdefault(rev, {})
2511 matches.setdefault(parent, {})
2511 matches.setdefault(parent, {})
2512 files = revfiles.setdefault(rev, [])
2512 files = revfiles.setdefault(rev, [])
2513 for fn in fns:
2513 for fn in fns:
2514 flog = getfile(fn)
2514 flog = getfile(fn)
2515 try:
2515 try:
2516 fnode = ctx.filenode(fn)
2516 fnode = ctx.filenode(fn)
2517 except error.LookupError:
2517 except error.LookupError:
2518 continue
2518 continue
2519
2519
2520 copied = flog.renamed(fnode)
2520 copied = flog.renamed(fnode)
2521 copy = follow and copied and copied[0]
2521 copy = follow and copied and copied[0]
2522 if copy:
2522 if copy:
2523 copies.setdefault(rev, {})[fn] = copy
2523 copies.setdefault(rev, {})[fn] = copy
2524 if fn in skip:
2524 if fn in skip:
2525 if copy:
2525 if copy:
2526 skip[copy] = True
2526 skip[copy] = True
2527 continue
2527 continue
2528 files.append(fn)
2528 files.append(fn)
2529
2529
2530 if fn not in matches[rev]:
2530 if fn not in matches[rev]:
2531 grepbody(fn, rev, flog.read(fnode))
2531 grepbody(fn, rev, flog.read(fnode))
2532
2532
2533 pfn = copy or fn
2533 pfn = copy or fn
2534 if pfn not in matches[parent]:
2534 if pfn not in matches[parent]:
2535 try:
2535 try:
2536 fnode = pctx.filenode(pfn)
2536 fnode = pctx.filenode(pfn)
2537 grepbody(pfn, parent, flog.read(fnode))
2537 grepbody(pfn, parent, flog.read(fnode))
2538 except error.LookupError:
2538 except error.LookupError:
2539 pass
2539 pass
2540
2540
2541 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2541 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2542 rev = ctx.rev()
2542 rev = ctx.rev()
2543 parent = ctx.p1().rev()
2543 parent = ctx.p1().rev()
2544 for fn in sorted(revfiles.get(rev, [])):
2544 for fn in sorted(revfiles.get(rev, [])):
2545 states = matches[rev][fn]
2545 states = matches[rev][fn]
2546 copy = copies.get(rev, {}).get(fn)
2546 copy = copies.get(rev, {}).get(fn)
2547 if fn in skip:
2547 if fn in skip:
2548 if copy:
2548 if copy:
2549 skip[copy] = True
2549 skip[copy] = True
2550 continue
2550 continue
2551 pstates = matches.get(parent, {}).get(copy or fn, [])
2551 pstates = matches.get(parent, {}).get(copy or fn, [])
2552 if pstates or states:
2552 if pstates or states:
2553 r = display(fn, ctx, pstates, states)
2553 r = display(fn, ctx, pstates, states)
2554 found = found or r
2554 found = found or r
2555 if r and not opts.get('all'):
2555 if r and not opts.get('all'):
2556 skip[fn] = True
2556 skip[fn] = True
2557 if copy:
2557 if copy:
2558 skip[copy] = True
2558 skip[copy] = True
2559 del matches[rev]
2559 del matches[rev]
2560 del revfiles[rev]
2560 del revfiles[rev]
2561
2561
2562 return not found
2562 return not found
2563
2563
2564 @command('heads',
2564 @command('heads',
2565 [('r', 'rev', '',
2565 [('r', 'rev', '',
2566 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2566 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2567 ('t', 'topo', False, _('show topological heads only')),
2567 ('t', 'topo', False, _('show topological heads only')),
2568 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2568 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2569 ('c', 'closed', False, _('show normal and closed branch heads')),
2569 ('c', 'closed', False, _('show normal and closed branch heads')),
2570 ] + templateopts,
2570 ] + templateopts,
2571 _('[-ac] [-r STARTREV] [REV]...'))
2571 _('[-ac] [-r STARTREV] [REV]...'))
2572 def heads(ui, repo, *branchrevs, **opts):
2572 def heads(ui, repo, *branchrevs, **opts):
2573 """show current repository heads or show branch heads
2573 """show current repository heads or show branch heads
2574
2574
2575 With no arguments, show all repository branch heads.
2575 With no arguments, show all repository branch heads.
2576
2576
2577 Repository "heads" are changesets with no child changesets. They are
2577 Repository "heads" are changesets with no child changesets. They are
2578 where development generally takes place and are the usual targets
2578 where development generally takes place and are the usual targets
2579 for update and merge operations. Branch heads are changesets that have
2579 for update and merge operations. Branch heads are changesets that have
2580 no child changeset on the same branch.
2580 no child changeset on the same branch.
2581
2581
2582 If one or more REVs are given, only branch heads on the branches
2582 If one or more REVs are given, only branch heads on the branches
2583 associated with the specified changesets are shown. This means
2583 associated with the specified changesets are shown. This means
2584 that you can use :hg:`heads foo` to see the heads on a branch
2584 that you can use :hg:`heads foo` to see the heads on a branch
2585 named ``foo``.
2585 named ``foo``.
2586
2586
2587 If -c/--closed is specified, also show branch heads marked closed
2587 If -c/--closed is specified, also show branch heads marked closed
2588 (see :hg:`commit --close-branch`).
2588 (see :hg:`commit --close-branch`).
2589
2589
2590 If STARTREV is specified, only those heads that are descendants of
2590 If STARTREV is specified, only those heads that are descendants of
2591 STARTREV will be displayed.
2591 STARTREV will be displayed.
2592
2592
2593 If -t/--topo is specified, named branch mechanics will be ignored and only
2593 If -t/--topo is specified, named branch mechanics will be ignored and only
2594 changesets without children will be shown.
2594 changesets without children will be shown.
2595
2595
2596 Returns 0 if matching heads are found, 1 if not.
2596 Returns 0 if matching heads are found, 1 if not.
2597 """
2597 """
2598
2598
2599 start = None
2599 start = None
2600 if 'rev' in opts:
2600 if 'rev' in opts:
2601 start = scmutil.revsingle(repo, opts['rev'], None).node()
2601 start = scmutil.revsingle(repo, opts['rev'], None).node()
2602
2602
2603 if opts.get('topo'):
2603 if opts.get('topo'):
2604 heads = [repo[h] for h in repo.heads(start)]
2604 heads = [repo[h] for h in repo.heads(start)]
2605 else:
2605 else:
2606 heads = []
2606 heads = []
2607 for branch in repo.branchmap():
2607 for branch in repo.branchmap():
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2609 heads = [repo[h] for h in heads]
2609 heads = [repo[h] for h in heads]
2610
2610
2611 if branchrevs:
2611 if branchrevs:
2612 branches = set(repo[br].branch() for br in branchrevs)
2612 branches = set(repo[br].branch() for br in branchrevs)
2613 heads = [h for h in heads if h.branch() in branches]
2613 heads = [h for h in heads if h.branch() in branches]
2614
2614
2615 if opts.get('active') and branchrevs:
2615 if opts.get('active') and branchrevs:
2616 dagheads = repo.heads(start)
2616 dagheads = repo.heads(start)
2617 heads = [h for h in heads if h.node() in dagheads]
2617 heads = [h for h in heads if h.node() in dagheads]
2618
2618
2619 if branchrevs:
2619 if branchrevs:
2620 haveheads = set(h.branch() for h in heads)
2620 haveheads = set(h.branch() for h in heads)
2621 if branches - haveheads:
2621 if branches - haveheads:
2622 headless = ', '.join(b for b in branches - haveheads)
2622 headless = ', '.join(b for b in branches - haveheads)
2623 msg = _('no open branch heads found on branches %s')
2623 msg = _('no open branch heads found on branches %s')
2624 if opts.get('rev'):
2624 if opts.get('rev'):
2625 msg += _(' (started at %s)' % opts['rev'])
2625 msg += _(' (started at %s)' % opts['rev'])
2626 ui.warn((msg + '\n') % headless)
2626 ui.warn((msg + '\n') % headless)
2627
2627
2628 if not heads:
2628 if not heads:
2629 return 1
2629 return 1
2630
2630
2631 heads = sorted(heads, key=lambda x: -x.rev())
2631 heads = sorted(heads, key=lambda x: -x.rev())
2632 displayer = cmdutil.show_changeset(ui, repo, opts)
2632 displayer = cmdutil.show_changeset(ui, repo, opts)
2633 for ctx in heads:
2633 for ctx in heads:
2634 displayer.show(ctx)
2634 displayer.show(ctx)
2635 displayer.close()
2635 displayer.close()
2636
2636
2637 @command('help',
2637 @command('help',
2638 [('e', 'extension', None, _('show only help for extensions')),
2638 [('e', 'extension', None, _('show only help for extensions')),
2639 ('c', 'command', None, _('show only help for commands'))],
2639 ('c', 'command', None, _('show only help for commands'))],
2640 _('[-ec] [TOPIC]'))
2640 _('[-ec] [TOPIC]'))
2641 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2641 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2642 """show help for a given topic or a help overview
2642 """show help for a given topic or a help overview
2643
2643
2644 With no arguments, print a list of commands with short help messages.
2644 With no arguments, print a list of commands with short help messages.
2645
2645
2646 Given a topic, extension, or command name, print help for that
2646 Given a topic, extension, or command name, print help for that
2647 topic.
2647 topic.
2648
2648
2649 Returns 0 if successful.
2649 Returns 0 if successful.
2650 """
2650 """
2651
2651
2652 optlist = []
2652 optlist = []
2653 textwidth = min(ui.termwidth(), 80) - 2
2653 textwidth = min(ui.termwidth(), 80) - 2
2654
2654
2655 # list all option lists
2655 # list all option lists
2656 def opttext(optlist, width):
2656 def opttext(optlist, width):
2657 out = []
2657 out = []
2658 multioccur = False
2658 multioccur = False
2659 for title, options in optlist:
2659 for title, options in optlist:
2660 out.append(("\n%s" % title, None))
2660 out.append(("\n%s" % title, None))
2661 for option in options:
2661 for option in options:
2662 if len(option) == 5:
2662 if len(option) == 5:
2663 shortopt, longopt, default, desc, optlabel = option
2663 shortopt, longopt, default, desc, optlabel = option
2664 else:
2664 else:
2665 shortopt, longopt, default, desc = option
2665 shortopt, longopt, default, desc = option
2666 optlabel = _("VALUE") # default label
2666 optlabel = _("VALUE") # default label
2667
2667
2668 if _("DEPRECATED") in desc and not ui.verbose:
2668 if _("DEPRECATED") in desc and not ui.verbose:
2669 continue
2669 continue
2670 if isinstance(default, list):
2670 if isinstance(default, list):
2671 numqualifier = " %s [+]" % optlabel
2671 numqualifier = " %s [+]" % optlabel
2672 multioccur = True
2672 multioccur = True
2673 elif (default is not None) and not isinstance(default, bool):
2673 elif (default is not None) and not isinstance(default, bool):
2674 numqualifier = " %s" % optlabel
2674 numqualifier = " %s" % optlabel
2675 else:
2675 else:
2676 numqualifier = ""
2676 numqualifier = ""
2677 out.append(("%2s%s" %
2677 out.append(("%2s%s" %
2678 (shortopt and "-%s" % shortopt,
2678 (shortopt and "-%s" % shortopt,
2679 longopt and " --%s%s" %
2679 longopt and " --%s%s" %
2680 (longopt, numqualifier)),
2680 (longopt, numqualifier)),
2681 "%s%s" % (desc,
2681 "%s%s" % (desc,
2682 default
2682 default
2683 and _(" (default: %s)") % default
2683 and _(" (default: %s)") % default
2684 or "")))
2684 or "")))
2685 if multioccur:
2685 if multioccur:
2686 msg = _("\n[+] marked option can be specified multiple times")
2686 msg = _("\n[+] marked option can be specified multiple times")
2687 if ui.verbose and name != 'shortlist':
2687 if ui.verbose and name != 'shortlist':
2688 out.append((msg, None))
2688 out.append((msg, None))
2689 else:
2689 else:
2690 out.insert(-1, (msg, None))
2690 out.insert(-1, (msg, None))
2691
2691
2692 text = ""
2692 text = ""
2693 if out:
2693 if out:
2694 colwidth = encoding.colwidth
2694 colwidth = encoding.colwidth
2695 # normalize: (opt or message, desc or None, width of opt)
2695 # normalize: (opt or message, desc or None, width of opt)
2696 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2696 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2697 for opt, desc in out]
2697 for opt, desc in out]
2698 hanging = max([e[2] for e in entries])
2698 hanging = max([e[2] for e in entries])
2699 for opt, desc, width in entries:
2699 for opt, desc, width in entries:
2700 if desc:
2700 if desc:
2701 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2701 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2702 hangindent = ' ' * (hanging + 3)
2702 hangindent = ' ' * (hanging + 3)
2703 text += '%s\n' % (util.wrap(desc, width,
2703 text += '%s\n' % (util.wrap(desc, width,
2704 initindent=initindent,
2704 initindent=initindent,
2705 hangindent=hangindent))
2705 hangindent=hangindent))
2706 else:
2706 else:
2707 text += "%s\n" % opt
2707 text += "%s\n" % opt
2708
2708
2709 return text
2709 return text
2710
2710
2711 def addglobalopts(aliases):
2711 def addglobalopts(aliases):
2712 if ui.verbose:
2712 if ui.verbose:
2713 optlist.append((_("global options:"), globalopts))
2713 optlist.append((_("global options:"), globalopts))
2714 if name == 'shortlist':
2714 if name == 'shortlist':
2715 optlist.append((_('use "hg help" for the full list '
2715 optlist.append((_('use "hg help" for the full list '
2716 'of commands'), ()))
2716 'of commands'), ()))
2717 else:
2717 else:
2718 if name == 'shortlist':
2718 if name == 'shortlist':
2719 msg = _('use "hg help" for the full list of commands '
2719 msg = _('use "hg help" for the full list of commands '
2720 'or "hg -v" for details')
2720 'or "hg -v" for details')
2721 elif name and not full:
2721 elif name and not full:
2722 msg = _('use "hg help %s" to show the full help text' % name)
2722 msg = _('use "hg help %s" to show the full help text' % name)
2723 elif aliases:
2723 elif aliases:
2724 msg = _('use "hg -v help%s" to show builtin aliases and '
2724 msg = _('use "hg -v help%s" to show builtin aliases and '
2725 'global options') % (name and " " + name or "")
2725 'global options') % (name and " " + name or "")
2726 else:
2726 else:
2727 msg = _('use "hg -v help %s" to show global options') % name
2727 msg = _('use "hg -v help %s" to show global options') % name
2728 optlist.append((msg, ()))
2728 optlist.append((msg, ()))
2729
2729
2730 def helpcmd(name):
2730 def helpcmd(name):
2731 try:
2731 try:
2732 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2732 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2733 except error.AmbiguousCommand, inst:
2733 except error.AmbiguousCommand, inst:
2734 # py3k fix: except vars can't be used outside the scope of the
2734 # py3k fix: except vars can't be used outside the scope of the
2735 # except block, nor can be used inside a lambda. python issue4617
2735 # except block, nor can be used inside a lambda. python issue4617
2736 prefix = inst.args[0]
2736 prefix = inst.args[0]
2737 select = lambda c: c.lstrip('^').startswith(prefix)
2737 select = lambda c: c.lstrip('^').startswith(prefix)
2738 helplist(_('list of commands:\n\n'), select)
2738 helplist(_('list of commands:\n\n'), select)
2739 return
2739 return
2740
2740
2741 # check if it's an invalid alias and display its error if it is
2741 # check if it's an invalid alias and display its error if it is
2742 if getattr(entry[0], 'badalias', False):
2742 if getattr(entry[0], 'badalias', False):
2743 if not unknowncmd:
2743 if not unknowncmd:
2744 entry[0](ui)
2744 entry[0](ui)
2745 return
2745 return
2746
2746
2747 # synopsis
2747 # synopsis
2748 if len(entry) > 2:
2748 if len(entry) > 2:
2749 if entry[2].startswith('hg'):
2749 if entry[2].startswith('hg'):
2750 ui.write("%s\n" % entry[2])
2750 ui.write("%s\n" % entry[2])
2751 else:
2751 else:
2752 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2752 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2753 else:
2753 else:
2754 ui.write('hg %s\n' % aliases[0])
2754 ui.write('hg %s\n' % aliases[0])
2755
2755
2756 # aliases
2756 # aliases
2757 if full and not ui.quiet and len(aliases) > 1:
2757 if full and not ui.quiet and len(aliases) > 1:
2758 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2758 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2759
2759
2760 # description
2760 # description
2761 doc = gettext(entry[0].__doc__)
2761 doc = gettext(entry[0].__doc__)
2762 if not doc:
2762 if not doc:
2763 doc = _("(no help text available)")
2763 doc = _("(no help text available)")
2764 if util.safehasattr(entry[0], 'definition'): # aliased command
2764 if util.safehasattr(entry[0], 'definition'): # aliased command
2765 if entry[0].definition.startswith('!'): # shell alias
2765 if entry[0].definition.startswith('!'): # shell alias
2766 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2766 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2767 else:
2767 else:
2768 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2768 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2769 if ui.quiet or not full:
2769 if ui.quiet or not full:
2770 doc = doc.splitlines()[0]
2770 doc = doc.splitlines()[0]
2771 keep = ui.verbose and ['verbose'] or []
2771 keep = ui.verbose and ['verbose'] or []
2772 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2772 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2773 ui.write("\n%s\n" % formatted)
2773 ui.write("\n%s\n" % formatted)
2774 if pruned:
2774 if pruned:
2775 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2775 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2776
2776
2777 if not ui.quiet:
2777 if not ui.quiet:
2778 # options
2778 # options
2779 if entry[1]:
2779 if entry[1]:
2780 optlist.append((_("options:\n"), entry[1]))
2780 optlist.append((_("options:\n"), entry[1]))
2781
2781
2782 addglobalopts(False)
2782 addglobalopts(False)
2783
2783
2784 # check if this command shadows a non-trivial (multi-line)
2784 # check if this command shadows a non-trivial (multi-line)
2785 # extension help text
2785 # extension help text
2786 try:
2786 try:
2787 mod = extensions.find(name)
2787 mod = extensions.find(name)
2788 doc = gettext(mod.__doc__) or ''
2788 doc = gettext(mod.__doc__) or ''
2789 if '\n' in doc.strip():
2789 if '\n' in doc.strip():
2790 msg = _('use "hg help -e %s" to show help for '
2790 msg = _('use "hg help -e %s" to show help for '
2791 'the %s extension') % (name, name)
2791 'the %s extension') % (name, name)
2792 ui.write('\n%s\n' % msg)
2792 ui.write('\n%s\n' % msg)
2793 except KeyError:
2793 except KeyError:
2794 pass
2794 pass
2795
2795
2796 def helplist(header, select=None):
2796 def helplist(header, select=None):
2797 h = {}
2797 h = {}
2798 cmds = {}
2798 cmds = {}
2799 for c, e in table.iteritems():
2799 for c, e in table.iteritems():
2800 f = c.split("|", 1)[0]
2800 f = c.split("|", 1)[0]
2801 if select and not select(f):
2801 if select and not select(f):
2802 continue
2802 continue
2803 if (not select and name != 'shortlist' and
2803 if (not select and name != 'shortlist' and
2804 e[0].__module__ != __name__):
2804 e[0].__module__ != __name__):
2805 continue
2805 continue
2806 if name == "shortlist" and not f.startswith("^"):
2806 if name == "shortlist" and not f.startswith("^"):
2807 continue
2807 continue
2808 f = f.lstrip("^")
2808 f = f.lstrip("^")
2809 if not ui.debugflag and f.startswith("debug"):
2809 if not ui.debugflag and f.startswith("debug"):
2810 continue
2810 continue
2811 doc = e[0].__doc__
2811 doc = e[0].__doc__
2812 if doc and 'DEPRECATED' in doc and not ui.verbose:
2812 if doc and 'DEPRECATED' in doc and not ui.verbose:
2813 continue
2813 continue
2814 doc = gettext(doc)
2814 doc = gettext(doc)
2815 if not doc:
2815 if not doc:
2816 doc = _("(no help text available)")
2816 doc = _("(no help text available)")
2817 h[f] = doc.splitlines()[0].rstrip()
2817 h[f] = doc.splitlines()[0].rstrip()
2818 cmds[f] = c.lstrip("^")
2818 cmds[f] = c.lstrip("^")
2819
2819
2820 if not h:
2820 if not h:
2821 ui.status(_('no commands defined\n'))
2821 ui.status(_('no commands defined\n'))
2822 return
2822 return
2823
2823
2824 ui.status(header)
2824 ui.status(header)
2825 fns = sorted(h)
2825 fns = sorted(h)
2826 m = max(map(len, fns))
2826 m = max(map(len, fns))
2827 for f in fns:
2827 for f in fns:
2828 if ui.verbose:
2828 if ui.verbose:
2829 commands = cmds[f].replace("|",", ")
2829 commands = cmds[f].replace("|",", ")
2830 ui.write(" %s:\n %s\n"%(commands, h[f]))
2830 ui.write(" %s:\n %s\n"%(commands, h[f]))
2831 else:
2831 else:
2832 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2832 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2833 initindent=' %-*s ' % (m, f),
2833 initindent=' %-*s ' % (m, f),
2834 hangindent=' ' * (m + 4))))
2834 hangindent=' ' * (m + 4))))
2835
2835
2836 if not ui.quiet:
2836 if not ui.quiet:
2837 addglobalopts(True)
2837 addglobalopts(True)
2838
2838
2839 def helptopic(name):
2839 def helptopic(name):
2840 for names, header, doc in help.helptable:
2840 for names, header, doc in help.helptable:
2841 if name in names:
2841 if name in names:
2842 break
2842 break
2843 else:
2843 else:
2844 raise error.UnknownCommand(name)
2844 raise error.UnknownCommand(name)
2845
2845
2846 # description
2846 # description
2847 if not doc:
2847 if not doc:
2848 doc = _("(no help text available)")
2848 doc = _("(no help text available)")
2849 if util.safehasattr(doc, '__call__'):
2849 if util.safehasattr(doc, '__call__'):
2850 doc = doc()
2850 doc = doc()
2851
2851
2852 ui.write("%s\n\n" % header)
2852 ui.write("%s\n\n" % header)
2853 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2853 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2854 try:
2854 try:
2855 cmdutil.findcmd(name, table)
2855 cmdutil.findcmd(name, table)
2856 ui.write(_('\nuse "hg help -c %s" to see help for '
2856 ui.write(_('\nuse "hg help -c %s" to see help for '
2857 'the %s command\n') % (name, name))
2857 'the %s command\n') % (name, name))
2858 except error.UnknownCommand:
2858 except error.UnknownCommand:
2859 pass
2859 pass
2860
2860
2861 def helpext(name):
2861 def helpext(name):
2862 try:
2862 try:
2863 mod = extensions.find(name)
2863 mod = extensions.find(name)
2864 doc = gettext(mod.__doc__) or _('no help text available')
2864 doc = gettext(mod.__doc__) or _('no help text available')
2865 except KeyError:
2865 except KeyError:
2866 mod = None
2866 mod = None
2867 doc = extensions.disabledext(name)
2867 doc = extensions.disabledext(name)
2868 if not doc:
2868 if not doc:
2869 raise error.UnknownCommand(name)
2869 raise error.UnknownCommand(name)
2870
2870
2871 if '\n' not in doc:
2871 if '\n' not in doc:
2872 head, tail = doc, ""
2872 head, tail = doc, ""
2873 else:
2873 else:
2874 head, tail = doc.split('\n', 1)
2874 head, tail = doc.split('\n', 1)
2875 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2875 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2876 if tail:
2876 if tail:
2877 ui.write(minirst.format(tail, textwidth))
2877 ui.write(minirst.format(tail, textwidth))
2878 ui.status('\n\n')
2878 ui.status('\n\n')
2879
2879
2880 if mod:
2880 if mod:
2881 try:
2881 try:
2882 ct = mod.cmdtable
2882 ct = mod.cmdtable
2883 except AttributeError:
2883 except AttributeError:
2884 ct = {}
2884 ct = {}
2885 modcmds = set([c.split('|', 1)[0] for c in ct])
2885 modcmds = set([c.split('|', 1)[0] for c in ct])
2886 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2886 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2887 else:
2887 else:
2888 ui.write(_('use "hg help extensions" for information on enabling '
2888 ui.write(_('use "hg help extensions" for information on enabling '
2889 'extensions\n'))
2889 'extensions\n'))
2890
2890
2891 def helpextcmd(name):
2891 def helpextcmd(name):
2892 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2892 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2893 doc = gettext(mod.__doc__).splitlines()[0]
2893 doc = gettext(mod.__doc__).splitlines()[0]
2894
2894
2895 msg = help.listexts(_("'%s' is provided by the following "
2895 msg = help.listexts(_("'%s' is provided by the following "
2896 "extension:") % cmd, {ext: doc}, indent=4)
2896 "extension:") % cmd, {ext: doc}, indent=4)
2897 ui.write(minirst.format(msg, textwidth))
2897 ui.write(minirst.format(msg, textwidth))
2898 ui.write('\n\n')
2898 ui.write('\n\n')
2899 ui.write(_('use "hg help extensions" for information on enabling '
2899 ui.write(_('use "hg help extensions" for information on enabling '
2900 'extensions\n'))
2900 'extensions\n'))
2901
2901
2902 if name and name != 'shortlist':
2902 if name and name != 'shortlist':
2903 i = None
2903 i = None
2904 if unknowncmd:
2904 if unknowncmd:
2905 queries = (helpextcmd,)
2905 queries = (helpextcmd,)
2906 elif opts.get('extension'):
2906 elif opts.get('extension'):
2907 queries = (helpext,)
2907 queries = (helpext,)
2908 elif opts.get('command'):
2908 elif opts.get('command'):
2909 queries = (helpcmd,)
2909 queries = (helpcmd,)
2910 else:
2910 else:
2911 queries = (helptopic, helpcmd, helpext, helpextcmd)
2911 queries = (helptopic, helpcmd, helpext, helpextcmd)
2912 for f in queries:
2912 for f in queries:
2913 try:
2913 try:
2914 f(name)
2914 f(name)
2915 i = None
2915 i = None
2916 break
2916 break
2917 except error.UnknownCommand, inst:
2917 except error.UnknownCommand, inst:
2918 i = inst
2918 i = inst
2919 if i:
2919 if i:
2920 raise i
2920 raise i
2921
2921
2922 else:
2922 else:
2923 # program name
2923 # program name
2924 ui.status(_("Mercurial Distributed SCM\n"))
2924 ui.status(_("Mercurial Distributed SCM\n"))
2925 ui.status('\n')
2925 ui.status('\n')
2926
2926
2927 # list of commands
2927 # list of commands
2928 if name == "shortlist":
2928 if name == "shortlist":
2929 header = _('basic commands:\n\n')
2929 header = _('basic commands:\n\n')
2930 else:
2930 else:
2931 header = _('list of commands:\n\n')
2931 header = _('list of commands:\n\n')
2932
2932
2933 helplist(header)
2933 helplist(header)
2934 if name != 'shortlist':
2934 if name != 'shortlist':
2935 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2935 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2936 if text:
2936 if text:
2937 ui.write("\n%s\n" % minirst.format(text, textwidth))
2937 ui.write("\n%s\n" % minirst.format(text, textwidth))
2938
2938
2939 if not name:
2939 if not name:
2940 ui.write(_("\nadditional help topics:\n\n"))
2940 ui.write(_("\nadditional help topics:\n\n"))
2941 topics = []
2941 topics = []
2942 for names, header, doc in help.helptable:
2942 for names, header, doc in help.helptable:
2943 topics.append((sorted(names, key=len, reverse=True)[0], header))
2943 topics.append((sorted(names, key=len, reverse=True)[0], header))
2944 topics_len = max([len(s[0]) for s in topics])
2944 topics_len = max([len(s[0]) for s in topics])
2945 for t, desc in topics:
2945 for t, desc in topics:
2946 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2946 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2947
2947
2948 ui.write(opttext(optlist, textwidth))
2948 ui.write(opttext(optlist, textwidth))
2949
2949
2950 @command('identify|id',
2950 @command('identify|id',
2951 [('r', 'rev', '',
2951 [('r', 'rev', '',
2952 _('identify the specified revision'), _('REV')),
2952 _('identify the specified revision'), _('REV')),
2953 ('n', 'num', None, _('show local revision number')),
2953 ('n', 'num', None, _('show local revision number')),
2954 ('i', 'id', None, _('show global revision id')),
2954 ('i', 'id', None, _('show global revision id')),
2955 ('b', 'branch', None, _('show branch')),
2955 ('b', 'branch', None, _('show branch')),
2956 ('t', 'tags', None, _('show tags')),
2956 ('t', 'tags', None, _('show tags')),
2957 ('B', 'bookmarks', None, _('show bookmarks'))],
2957 ('B', 'bookmarks', None, _('show bookmarks'))],
2958 _('[-nibtB] [-r REV] [SOURCE]'))
2958 _('[-nibtB] [-r REV] [SOURCE]'))
2959 def identify(ui, repo, source=None, rev=None,
2959 def identify(ui, repo, source=None, rev=None,
2960 num=None, id=None, branch=None, tags=None, bookmarks=None):
2960 num=None, id=None, branch=None, tags=None, bookmarks=None):
2961 """identify the working copy or specified revision
2961 """identify the working copy or specified revision
2962
2962
2963 Print a summary identifying the repository state at REV using one or
2963 Print a summary identifying the repository state at REV using one or
2964 two parent hash identifiers, followed by a "+" if the working
2964 two parent hash identifiers, followed by a "+" if the working
2965 directory has uncommitted changes, the branch name (if not default),
2965 directory has uncommitted changes, the branch name (if not default),
2966 a list of tags, and a list of bookmarks.
2966 a list of tags, and a list of bookmarks.
2967
2967
2968 When REV is not given, print a summary of the current state of the
2968 When REV is not given, print a summary of the current state of the
2969 repository.
2969 repository.
2970
2970
2971 Specifying a path to a repository root or Mercurial bundle will
2971 Specifying a path to a repository root or Mercurial bundle will
2972 cause lookup to operate on that repository/bundle.
2972 cause lookup to operate on that repository/bundle.
2973
2973
2974 .. container:: verbose
2974 .. container:: verbose
2975
2975
2976 Examples:
2976 Examples:
2977
2977
2978 - generate a build identifier for the working directory::
2978 - generate a build identifier for the working directory::
2979
2979
2980 hg id --id > build-id.dat
2980 hg id --id > build-id.dat
2981
2981
2982 - find the revision corresponding to a tag::
2982 - find the revision corresponding to a tag::
2983
2983
2984 hg id -n -r 1.3
2984 hg id -n -r 1.3
2985
2985
2986 - check the most recent revision of a remote repository::
2986 - check the most recent revision of a remote repository::
2987
2987
2988 hg id -r tip http://selenic.com/hg/
2988 hg id -r tip http://selenic.com/hg/
2989
2989
2990 Returns 0 if successful.
2990 Returns 0 if successful.
2991 """
2991 """
2992
2992
2993 if not repo and not source:
2993 if not repo and not source:
2994 raise util.Abort(_("there is no Mercurial repository here "
2994 raise util.Abort(_("there is no Mercurial repository here "
2995 "(.hg not found)"))
2995 "(.hg not found)"))
2996
2996
2997 hexfunc = ui.debugflag and hex or short
2997 hexfunc = ui.debugflag and hex or short
2998 default = not (num or id or branch or tags or bookmarks)
2998 default = not (num or id or branch or tags or bookmarks)
2999 output = []
2999 output = []
3000 revs = []
3000 revs = []
3001
3001
3002 if source:
3002 if source:
3003 source, branches = hg.parseurl(ui.expandpath(source))
3003 source, branches = hg.parseurl(ui.expandpath(source))
3004 repo = hg.peer(ui, {}, source)
3004 repo = hg.peer(ui, {}, source)
3005 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3005 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3006
3006
3007 if not repo.local():
3007 if not repo.local():
3008 if num or branch or tags:
3008 if num or branch or tags:
3009 raise util.Abort(
3009 raise util.Abort(
3010 _("can't query remote revision number, branch, or tags"))
3010 _("can't query remote revision number, branch, or tags"))
3011 if not rev and revs:
3011 if not rev and revs:
3012 rev = revs[0]
3012 rev = revs[0]
3013 if not rev:
3013 if not rev:
3014 rev = "tip"
3014 rev = "tip"
3015
3015
3016 remoterev = repo.lookup(rev)
3016 remoterev = repo.lookup(rev)
3017 if default or id:
3017 if default or id:
3018 output = [hexfunc(remoterev)]
3018 output = [hexfunc(remoterev)]
3019
3019
3020 def getbms():
3020 def getbms():
3021 bms = []
3021 bms = []
3022
3022
3023 if 'bookmarks' in repo.listkeys('namespaces'):
3023 if 'bookmarks' in repo.listkeys('namespaces'):
3024 hexremoterev = hex(remoterev)
3024 hexremoterev = hex(remoterev)
3025 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3025 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3026 if bmr == hexremoterev]
3026 if bmr == hexremoterev]
3027
3027
3028 return bms
3028 return bms
3029
3029
3030 if bookmarks:
3030 if bookmarks:
3031 output.extend(getbms())
3031 output.extend(getbms())
3032 elif default and not ui.quiet:
3032 elif default and not ui.quiet:
3033 # multiple bookmarks for a single parent separated by '/'
3033 # multiple bookmarks for a single parent separated by '/'
3034 bm = '/'.join(getbms())
3034 bm = '/'.join(getbms())
3035 if bm:
3035 if bm:
3036 output.append(bm)
3036 output.append(bm)
3037 else:
3037 else:
3038 if not rev:
3038 if not rev:
3039 ctx = repo[None]
3039 ctx = repo[None]
3040 parents = ctx.parents()
3040 parents = ctx.parents()
3041 changed = ""
3041 changed = ""
3042 if default or id or num:
3042 if default or id or num:
3043 changed = util.any(repo.status()) and "+" or ""
3043 changed = util.any(repo.status()) and "+" or ""
3044 if default or id:
3044 if default or id:
3045 output = ["%s%s" %
3045 output = ["%s%s" %
3046 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3046 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3047 if num:
3047 if num:
3048 output.append("%s%s" %
3048 output.append("%s%s" %
3049 ('+'.join([str(p.rev()) for p in parents]), changed))
3049 ('+'.join([str(p.rev()) for p in parents]), changed))
3050 else:
3050 else:
3051 ctx = scmutil.revsingle(repo, rev)
3051 ctx = scmutil.revsingle(repo, rev)
3052 if default or id:
3052 if default or id:
3053 output = [hexfunc(ctx.node())]
3053 output = [hexfunc(ctx.node())]
3054 if num:
3054 if num:
3055 output.append(str(ctx.rev()))
3055 output.append(str(ctx.rev()))
3056
3056
3057 if default and not ui.quiet:
3057 if default and not ui.quiet:
3058 b = ctx.branch()
3058 b = ctx.branch()
3059 if b != 'default':
3059 if b != 'default':
3060 output.append("(%s)" % b)
3060 output.append("(%s)" % b)
3061
3061
3062 # multiple tags for a single parent separated by '/'
3062 # multiple tags for a single parent separated by '/'
3063 t = '/'.join(ctx.tags())
3063 t = '/'.join(ctx.tags())
3064 if t:
3064 if t:
3065 output.append(t)
3065 output.append(t)
3066
3066
3067 # multiple bookmarks for a single parent separated by '/'
3067 # multiple bookmarks for a single parent separated by '/'
3068 bm = '/'.join(ctx.bookmarks())
3068 bm = '/'.join(ctx.bookmarks())
3069 if bm:
3069 if bm:
3070 output.append(bm)
3070 output.append(bm)
3071 else:
3071 else:
3072 if branch:
3072 if branch:
3073 output.append(ctx.branch())
3073 output.append(ctx.branch())
3074
3074
3075 if tags:
3075 if tags:
3076 output.extend(ctx.tags())
3076 output.extend(ctx.tags())
3077
3077
3078 if bookmarks:
3078 if bookmarks:
3079 output.extend(ctx.bookmarks())
3079 output.extend(ctx.bookmarks())
3080
3080
3081 ui.write("%s\n" % ' '.join(output))
3081 ui.write("%s\n" % ' '.join(output))
3082
3082
3083 @command('import|patch',
3083 @command('import|patch',
3084 [('p', 'strip', 1,
3084 [('p', 'strip', 1,
3085 _('directory strip option for patch. This has the same '
3085 _('directory strip option for patch. This has the same '
3086 'meaning as the corresponding patch option'), _('NUM')),
3086 'meaning as the corresponding patch option'), _('NUM')),
3087 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3087 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3088 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3088 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3089 ('', 'no-commit', None,
3089 ('', 'no-commit', None,
3090 _("don't commit, just update the working directory")),
3090 _("don't commit, just update the working directory")),
3091 ('', 'bypass', None,
3091 ('', 'bypass', None,
3092 _("apply patch without touching the working directory")),
3092 _("apply patch without touching the working directory")),
3093 ('', 'exact', None,
3093 ('', 'exact', None,
3094 _('apply patch to the nodes from which it was generated')),
3094 _('apply patch to the nodes from which it was generated')),
3095 ('', 'import-branch', None,
3095 ('', 'import-branch', None,
3096 _('use any branch information in patch (implied by --exact)'))] +
3096 _('use any branch information in patch (implied by --exact)'))] +
3097 commitopts + commitopts2 + similarityopts,
3097 commitopts + commitopts2 + similarityopts,
3098 _('[OPTION]... PATCH...'))
3098 _('[OPTION]... PATCH...'))
3099 def import_(ui, repo, patch1, *patches, **opts):
3099 def import_(ui, repo, patch1, *patches, **opts):
3100 """import an ordered set of patches
3100 """import an ordered set of patches
3101
3101
3102 Import a list of patches and commit them individually (unless
3102 Import a list of patches and commit them individually (unless
3103 --no-commit is specified).
3103 --no-commit is specified).
3104
3104
3105 If there are outstanding changes in the working directory, import
3105 If there are outstanding changes in the working directory, import
3106 will abort unless given the -f/--force flag.
3106 will abort unless given the -f/--force flag.
3107
3107
3108 You can import a patch straight from a mail message. Even patches
3108 You can import a patch straight from a mail message. Even patches
3109 as attachments work (to use the body part, it must have type
3109 as attachments work (to use the body part, it must have type
3110 text/plain or text/x-patch). From and Subject headers of email
3110 text/plain or text/x-patch). From and Subject headers of email
3111 message are used as default committer and commit message. All
3111 message are used as default committer and commit message. All
3112 text/plain body parts before first diff are added to commit
3112 text/plain body parts before first diff are added to commit
3113 message.
3113 message.
3114
3114
3115 If the imported patch was generated by :hg:`export`, user and
3115 If the imported patch was generated by :hg:`export`, user and
3116 description from patch override values from message headers and
3116 description from patch override values from message headers and
3117 body. Values given on command line with -m/--message and -u/--user
3117 body. Values given on command line with -m/--message and -u/--user
3118 override these.
3118 override these.
3119
3119
3120 If --exact is specified, import will set the working directory to
3120 If --exact is specified, import will set the working directory to
3121 the parent of each patch before applying it, and will abort if the
3121 the parent of each patch before applying it, and will abort if the
3122 resulting changeset has a different ID than the one recorded in
3122 resulting changeset has a different ID than the one recorded in
3123 the patch. This may happen due to character set problems or other
3123 the patch. This may happen due to character set problems or other
3124 deficiencies in the text patch format.
3124 deficiencies in the text patch format.
3125
3125
3126 Use --bypass to apply and commit patches directly to the
3126 Use --bypass to apply and commit patches directly to the
3127 repository, not touching the working directory. Without --exact,
3127 repository, not touching the working directory. Without --exact,
3128 patches will be applied on top of the working directory parent
3128 patches will be applied on top of the working directory parent
3129 revision.
3129 revision.
3130
3130
3131 With -s/--similarity, hg will attempt to discover renames and
3131 With -s/--similarity, hg will attempt to discover renames and
3132 copies in the patch in the same way as 'addremove'.
3132 copies in the patch in the same way as 'addremove'.
3133
3133
3134 To read a patch from standard input, use "-" as the patch name. If
3134 To read a patch from standard input, use "-" as the patch name. If
3135 a URL is specified, the patch will be downloaded from it.
3135 a URL is specified, the patch will be downloaded from it.
3136 See :hg:`help dates` for a list of formats valid for -d/--date.
3136 See :hg:`help dates` for a list of formats valid for -d/--date.
3137
3137
3138 .. container:: verbose
3138 .. container:: verbose
3139
3139
3140 Examples:
3140 Examples:
3141
3141
3142 - import a traditional patch from a website and detect renames::
3142 - import a traditional patch from a website and detect renames::
3143
3143
3144 hg import -s 80 http://example.com/bugfix.patch
3144 hg import -s 80 http://example.com/bugfix.patch
3145
3145
3146 - import a changeset from an hgweb server::
3146 - import a changeset from an hgweb server::
3147
3147
3148 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3148 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3149
3149
3150 - import all the patches in an Unix-style mbox::
3150 - import all the patches in an Unix-style mbox::
3151
3151
3152 hg import incoming-patches.mbox
3152 hg import incoming-patches.mbox
3153
3153
3154 - attempt to exactly restore an exported changeset (not always
3154 - attempt to exactly restore an exported changeset (not always
3155 possible)::
3155 possible)::
3156
3156
3157 hg import --exact proposed-fix.patch
3157 hg import --exact proposed-fix.patch
3158
3158
3159 Returns 0 on success.
3159 Returns 0 on success.
3160 """
3160 """
3161 patches = (patch1,) + patches
3161 patches = (patch1,) + patches
3162
3162
3163 date = opts.get('date')
3163 date = opts.get('date')
3164 if date:
3164 if date:
3165 opts['date'] = util.parsedate(date)
3165 opts['date'] = util.parsedate(date)
3166
3166
3167 update = not opts.get('bypass')
3167 update = not opts.get('bypass')
3168 if not update and opts.get('no_commit'):
3168 if not update and opts.get('no_commit'):
3169 raise util.Abort(_('cannot use --no-commit with --bypass'))
3169 raise util.Abort(_('cannot use --no-commit with --bypass'))
3170 try:
3170 try:
3171 sim = float(opts.get('similarity') or 0)
3171 sim = float(opts.get('similarity') or 0)
3172 except ValueError:
3172 except ValueError:
3173 raise util.Abort(_('similarity must be a number'))
3173 raise util.Abort(_('similarity must be a number'))
3174 if sim < 0 or sim > 100:
3174 if sim < 0 or sim > 100:
3175 raise util.Abort(_('similarity must be between 0 and 100'))
3175 raise util.Abort(_('similarity must be between 0 and 100'))
3176 if sim and not update:
3176 if sim and not update:
3177 raise util.Abort(_('cannot use --similarity with --bypass'))
3177 raise util.Abort(_('cannot use --similarity with --bypass'))
3178
3178
3179 if (opts.get('exact') or not opts.get('force')) and update:
3179 if (opts.get('exact') or not opts.get('force')) and update:
3180 cmdutil.bailifchanged(repo)
3180 cmdutil.bailifchanged(repo)
3181
3181
3182 d = opts["base"]
3182 d = opts["base"]
3183 strip = opts["strip"]
3183 strip = opts["strip"]
3184 wlock = lock = None
3184 wlock = lock = None
3185 msgs = []
3185 msgs = []
3186
3186
3187 def checkexact(repo, n, nodeid):
3187 def checkexact(repo, n, nodeid):
3188 if opts.get('exact') and hex(n) != nodeid:
3188 if opts.get('exact') and hex(n) != nodeid:
3189 repo.rollback()
3189 repo.rollback()
3190 raise util.Abort(_('patch is damaged or loses information'))
3190 raise util.Abort(_('patch is damaged or loses information'))
3191
3191
3192 def tryone(ui, hunk, parents):
3192 def tryone(ui, hunk, parents):
3193 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3193 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3194 patch.extract(ui, hunk)
3194 patch.extract(ui, hunk)
3195
3195
3196 if not tmpname:
3196 if not tmpname:
3197 return None
3197 return None
3198 commitid = _('to working directory')
3198 commitid = _('to working directory')
3199
3199
3200 try:
3200 try:
3201 cmdline_message = cmdutil.logmessage(ui, opts)
3201 cmdline_message = cmdutil.logmessage(ui, opts)
3202 if cmdline_message:
3202 if cmdline_message:
3203 # pickup the cmdline msg
3203 # pickup the cmdline msg
3204 message = cmdline_message
3204 message = cmdline_message
3205 elif message:
3205 elif message:
3206 # pickup the patch msg
3206 # pickup the patch msg
3207 message = message.strip()
3207 message = message.strip()
3208 else:
3208 else:
3209 # launch the editor
3209 # launch the editor
3210 message = None
3210 message = None
3211 ui.debug('message:\n%s\n' % message)
3211 ui.debug('message:\n%s\n' % message)
3212
3212
3213 if len(parents) == 1:
3213 if len(parents) == 1:
3214 parents.append(repo[nullid])
3214 parents.append(repo[nullid])
3215 if opts.get('exact'):
3215 if opts.get('exact'):
3216 if not nodeid or not p1:
3216 if not nodeid or not p1:
3217 raise util.Abort(_('not a Mercurial patch'))
3217 raise util.Abort(_('not a Mercurial patch'))
3218 p1 = repo[p1]
3218 p1 = repo[p1]
3219 p2 = repo[p2 or nullid]
3219 p2 = repo[p2 or nullid]
3220 elif p2:
3220 elif p2:
3221 try:
3221 try:
3222 p1 = repo[p1]
3222 p1 = repo[p1]
3223 p2 = repo[p2]
3223 p2 = repo[p2]
3224 except error.RepoError:
3224 except error.RepoError:
3225 p1, p2 = parents
3225 p1, p2 = parents
3226 else:
3226 else:
3227 p1, p2 = parents
3227 p1, p2 = parents
3228
3228
3229 n = None
3229 n = None
3230 if update:
3230 if update:
3231 if opts.get('exact') and p1 != parents[0]:
3231 if opts.get('exact') and p1 != parents[0]:
3232 hg.clean(repo, p1.node())
3232 hg.clean(repo, p1.node())
3233 if p1 != parents[0] and p2 != parents[1]:
3233 if p1 != parents[0] and p2 != parents[1]:
3234 repo.dirstate.setparents(p1.node(), p2.node())
3234 repo.dirstate.setparents(p1.node(), p2.node())
3235
3235
3236 if opts.get('exact') or opts.get('import_branch'):
3236 if opts.get('exact') or opts.get('import_branch'):
3237 repo.dirstate.setbranch(branch or 'default')
3237 repo.dirstate.setbranch(branch or 'default')
3238
3238
3239 files = set()
3239 files = set()
3240 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3240 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3241 eolmode=None, similarity=sim / 100.0)
3241 eolmode=None, similarity=sim / 100.0)
3242 files = list(files)
3242 files = list(files)
3243 if opts.get('no_commit'):
3243 if opts.get('no_commit'):
3244 if message:
3244 if message:
3245 msgs.append(message)
3245 msgs.append(message)
3246 else:
3246 else:
3247 if opts.get('exact'):
3247 if opts.get('exact'):
3248 m = None
3248 m = None
3249 else:
3249 else:
3250 m = scmutil.matchfiles(repo, files or [])
3250 m = scmutil.matchfiles(repo, files or [])
3251 n = repo.commit(message, opts.get('user') or user,
3251 n = repo.commit(message, opts.get('user') or user,
3252 opts.get('date') or date, match=m,
3252 opts.get('date') or date, match=m,
3253 editor=cmdutil.commiteditor)
3253 editor=cmdutil.commiteditor)
3254 checkexact(repo, n, nodeid)
3254 checkexact(repo, n, nodeid)
3255 # Force a dirstate write so that the next transaction
3255 # Force a dirstate write so that the next transaction
3256 # backups an up-to-date file.
3256 # backups an up-to-date file.
3257 repo.dirstate.write()
3257 repo.dirstate.write()
3258 else:
3258 else:
3259 if opts.get('exact') or opts.get('import_branch'):
3259 if opts.get('exact') or opts.get('import_branch'):
3260 branch = branch or 'default'
3260 branch = branch or 'default'
3261 else:
3261 else:
3262 branch = p1.branch()
3262 branch = p1.branch()
3263 store = patch.filestore()
3263 store = patch.filestore()
3264 try:
3264 try:
3265 files = set()
3265 files = set()
3266 try:
3266 try:
3267 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3267 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3268 files, eolmode=None)
3268 files, eolmode=None)
3269 except patch.PatchError, e:
3269 except patch.PatchError, e:
3270 raise util.Abort(str(e))
3270 raise util.Abort(str(e))
3271 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3271 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3272 message,
3272 message,
3273 opts.get('user') or user,
3273 opts.get('user') or user,
3274 opts.get('date') or date,
3274 opts.get('date') or date,
3275 branch, files, store,
3275 branch, files, store,
3276 editor=cmdutil.commiteditor)
3276 editor=cmdutil.commiteditor)
3277 repo.savecommitmessage(memctx.description())
3277 repo.savecommitmessage(memctx.description())
3278 n = memctx.commit()
3278 n = memctx.commit()
3279 checkexact(repo, n, nodeid)
3279 checkexact(repo, n, nodeid)
3280 finally:
3280 finally:
3281 store.close()
3281 store.close()
3282 if n:
3282 if n:
3283 commitid = short(n)
3283 commitid = short(n)
3284 return commitid
3284 return commitid
3285 finally:
3285 finally:
3286 os.unlink(tmpname)
3286 os.unlink(tmpname)
3287
3287
3288 try:
3288 try:
3289 wlock = repo.wlock()
3289 wlock = repo.wlock()
3290 lock = repo.lock()
3290 lock = repo.lock()
3291 parents = repo.parents()
3291 parents = repo.parents()
3292 lastcommit = None
3292 lastcommit = None
3293 for p in patches:
3293 for p in patches:
3294 pf = os.path.join(d, p)
3294 pf = os.path.join(d, p)
3295
3295
3296 if pf == '-':
3296 if pf == '-':
3297 ui.status(_("applying patch from stdin\n"))
3297 ui.status(_("applying patch from stdin\n"))
3298 pf = ui.fin
3298 pf = ui.fin
3299 else:
3299 else:
3300 ui.status(_("applying %s\n") % p)
3300 ui.status(_("applying %s\n") % p)
3301 pf = url.open(ui, pf)
3301 pf = url.open(ui, pf)
3302
3302
3303 haspatch = False
3303 haspatch = False
3304 for hunk in patch.split(pf):
3304 for hunk in patch.split(pf):
3305 commitid = tryone(ui, hunk, parents)
3305 commitid = tryone(ui, hunk, parents)
3306 if commitid:
3306 if commitid:
3307 haspatch = True
3307 haspatch = True
3308 if lastcommit:
3308 if lastcommit:
3309 ui.status(_('applied %s\n') % lastcommit)
3309 ui.status(_('applied %s\n') % lastcommit)
3310 lastcommit = commitid
3310 lastcommit = commitid
3311 if update or opts.get('exact'):
3311 if update or opts.get('exact'):
3312 parents = repo.parents()
3312 parents = repo.parents()
3313 else:
3313 else:
3314 parents = [repo[commitid]]
3314 parents = [repo[commitid]]
3315
3315
3316 if not haspatch:
3316 if not haspatch:
3317 raise util.Abort(_('no diffs found'))
3317 raise util.Abort(_('no diffs found'))
3318
3318
3319 if msgs:
3319 if msgs:
3320 repo.savecommitmessage('\n* * *\n'.join(msgs))
3320 repo.savecommitmessage('\n* * *\n'.join(msgs))
3321 finally:
3321 finally:
3322 release(lock, wlock)
3322 release(lock, wlock)
3323
3323
3324 @command('incoming|in',
3324 @command('incoming|in',
3325 [('f', 'force', None,
3325 [('f', 'force', None,
3326 _('run even if remote repository is unrelated')),
3326 _('run even if remote repository is unrelated')),
3327 ('n', 'newest-first', None, _('show newest record first')),
3327 ('n', 'newest-first', None, _('show newest record first')),
3328 ('', 'bundle', '',
3328 ('', 'bundle', '',
3329 _('file to store the bundles into'), _('FILE')),
3329 _('file to store the bundles into'), _('FILE')),
3330 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3330 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3331 ('B', 'bookmarks', False, _("compare bookmarks")),
3331 ('B', 'bookmarks', False, _("compare bookmarks")),
3332 ('b', 'branch', [],
3332 ('b', 'branch', [],
3333 _('a specific branch you would like to pull'), _('BRANCH')),
3333 _('a specific branch you would like to pull'), _('BRANCH')),
3334 ] + logopts + remoteopts + subrepoopts,
3334 ] + logopts + remoteopts + subrepoopts,
3335 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3335 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3336 def incoming(ui, repo, source="default", **opts):
3336 def incoming(ui, repo, source="default", **opts):
3337 """show new changesets found in source
3337 """show new changesets found in source
3338
3338
3339 Show new changesets found in the specified path/URL or the default
3339 Show new changesets found in the specified path/URL or the default
3340 pull location. These are the changesets that would have been pulled
3340 pull location. These are the changesets that would have been pulled
3341 if a pull at the time you issued this command.
3341 if a pull at the time you issued this command.
3342
3342
3343 For remote repository, using --bundle avoids downloading the
3343 For remote repository, using --bundle avoids downloading the
3344 changesets twice if the incoming is followed by a pull.
3344 changesets twice if the incoming is followed by a pull.
3345
3345
3346 See pull for valid source format details.
3346 See pull for valid source format details.
3347
3347
3348 Returns 0 if there are incoming changes, 1 otherwise.
3348 Returns 0 if there are incoming changes, 1 otherwise.
3349 """
3349 """
3350 if opts.get('bundle') and opts.get('subrepos'):
3350 if opts.get('bundle') and opts.get('subrepos'):
3351 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3351 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3352
3352
3353 if opts.get('bookmarks'):
3353 if opts.get('bookmarks'):
3354 source, branches = hg.parseurl(ui.expandpath(source),
3354 source, branches = hg.parseurl(ui.expandpath(source),
3355 opts.get('branch'))
3355 opts.get('branch'))
3356 other = hg.peer(repo, opts, source)
3356 other = hg.peer(repo, opts, source)
3357 if 'bookmarks' not in other.listkeys('namespaces'):
3357 if 'bookmarks' not in other.listkeys('namespaces'):
3358 ui.warn(_("remote doesn't support bookmarks\n"))
3358 ui.warn(_("remote doesn't support bookmarks\n"))
3359 return 0
3359 return 0
3360 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3360 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3361 return bookmarks.diff(ui, repo, other)
3361 return bookmarks.diff(ui, repo, other)
3362
3362
3363 repo._subtoppath = ui.expandpath(source)
3363 repo._subtoppath = ui.expandpath(source)
3364 try:
3364 try:
3365 return hg.incoming(ui, repo, source, opts)
3365 return hg.incoming(ui, repo, source, opts)
3366 finally:
3366 finally:
3367 del repo._subtoppath
3367 del repo._subtoppath
3368
3368
3369
3369
3370 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3370 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3371 def init(ui, dest=".", **opts):
3371 def init(ui, dest=".", **opts):
3372 """create a new repository in the given directory
3372 """create a new repository in the given directory
3373
3373
3374 Initialize a new repository in the given directory. If the given
3374 Initialize a new repository in the given directory. If the given
3375 directory does not exist, it will be created.
3375 directory does not exist, it will be created.
3376
3376
3377 If no directory is given, the current directory is used.
3377 If no directory is given, the current directory is used.
3378
3378
3379 It is possible to specify an ``ssh://`` URL as the destination.
3379 It is possible to specify an ``ssh://`` URL as the destination.
3380 See :hg:`help urls` for more information.
3380 See :hg:`help urls` for more information.
3381
3381
3382 Returns 0 on success.
3382 Returns 0 on success.
3383 """
3383 """
3384 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3384 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3385
3385
3386 @command('locate',
3386 @command('locate',
3387 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3387 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3388 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3388 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3389 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3389 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3390 ] + walkopts,
3390 ] + walkopts,
3391 _('[OPTION]... [PATTERN]...'))
3391 _('[OPTION]... [PATTERN]...'))
3392 def locate(ui, repo, *pats, **opts):
3392 def locate(ui, repo, *pats, **opts):
3393 """locate files matching specific patterns
3393 """locate files matching specific patterns
3394
3394
3395 Print files under Mercurial control in the working directory whose
3395 Print files under Mercurial control in the working directory whose
3396 names match the given patterns.
3396 names match the given patterns.
3397
3397
3398 By default, this command searches all directories in the working
3398 By default, this command searches all directories in the working
3399 directory. To search just the current directory and its
3399 directory. To search just the current directory and its
3400 subdirectories, use "--include .".
3400 subdirectories, use "--include .".
3401
3401
3402 If no patterns are given to match, this command prints the names
3402 If no patterns are given to match, this command prints the names
3403 of all files under Mercurial control in the working directory.
3403 of all files under Mercurial control in the working directory.
3404
3404
3405 If you want to feed the output of this command into the "xargs"
3405 If you want to feed the output of this command into the "xargs"
3406 command, use the -0 option to both this command and "xargs". This
3406 command, use the -0 option to both this command and "xargs". This
3407 will avoid the problem of "xargs" treating single filenames that
3407 will avoid the problem of "xargs" treating single filenames that
3408 contain whitespace as multiple filenames.
3408 contain whitespace as multiple filenames.
3409
3409
3410 Returns 0 if a match is found, 1 otherwise.
3410 Returns 0 if a match is found, 1 otherwise.
3411 """
3411 """
3412 end = opts.get('print0') and '\0' or '\n'
3412 end = opts.get('print0') and '\0' or '\n'
3413 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3413 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3414
3414
3415 ret = 1
3415 ret = 1
3416 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3416 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3417 m.bad = lambda x, y: False
3417 m.bad = lambda x, y: False
3418 for abs in repo[rev].walk(m):
3418 for abs in repo[rev].walk(m):
3419 if not rev and abs not in repo.dirstate:
3419 if not rev and abs not in repo.dirstate:
3420 continue
3420 continue
3421 if opts.get('fullpath'):
3421 if opts.get('fullpath'):
3422 ui.write(repo.wjoin(abs), end)
3422 ui.write(repo.wjoin(abs), end)
3423 else:
3423 else:
3424 ui.write(((pats and m.rel(abs)) or abs), end)
3424 ui.write(((pats and m.rel(abs)) or abs), end)
3425 ret = 0
3425 ret = 0
3426
3426
3427 return ret
3427 return ret
3428
3428
3429 @command('^log|history',
3429 @command('^log|history',
3430 [('f', 'follow', None,
3430 [('f', 'follow', None,
3431 _('follow changeset history, or file history across copies and renames')),
3431 _('follow changeset history, or file history across copies and renames')),
3432 ('', 'follow-first', None,
3432 ('', 'follow-first', None,
3433 _('only follow the first parent of merge changesets')),
3433 _('only follow the first parent of merge changesets')),
3434 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3434 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3435 ('C', 'copies', None, _('show copied files')),
3435 ('C', 'copies', None, _('show copied files')),
3436 ('k', 'keyword', [],
3436 ('k', 'keyword', [],
3437 _('do case-insensitive search for a given text'), _('TEXT')),
3437 _('do case-insensitive search for a given text'), _('TEXT')),
3438 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3438 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3439 ('', 'removed', None, _('include revisions where files were removed')),
3439 ('', 'removed', None, _('include revisions where files were removed')),
3440 ('m', 'only-merges', None, _('show only merges')),
3440 ('m', 'only-merges', None, _('show only merges')),
3441 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3441 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3442 ('', 'only-branch', [],
3442 ('', 'only-branch', [],
3443 _('show only changesets within the given named branch (DEPRECATED)'),
3443 _('show only changesets within the given named branch (DEPRECATED)'),
3444 _('BRANCH')),
3444 _('BRANCH')),
3445 ('b', 'branch', [],
3445 ('b', 'branch', [],
3446 _('show changesets within the given named branch'), _('BRANCH')),
3446 _('show changesets within the given named branch'), _('BRANCH')),
3447 ('P', 'prune', [],
3447 ('P', 'prune', [],
3448 _('do not display revision or any of its ancestors'), _('REV')),
3448 _('do not display revision or any of its ancestors'), _('REV')),
3449 ('', 'hidden', False, _('show hidden changesets')),
3449 ('', 'hidden', False, _('show hidden changesets')),
3450 ] + logopts + walkopts,
3450 ] + logopts + walkopts,
3451 _('[OPTION]... [FILE]'))
3451 _('[OPTION]... [FILE]'))
3452 def log(ui, repo, *pats, **opts):
3452 def log(ui, repo, *pats, **opts):
3453 """show revision history of entire repository or files
3453 """show revision history of entire repository or files
3454
3454
3455 Print the revision history of the specified files or the entire
3455 Print the revision history of the specified files or the entire
3456 project.
3456 project.
3457
3457
3458 If no revision range is specified, the default is ``tip:0`` unless
3458 If no revision range is specified, the default is ``tip:0`` unless
3459 --follow is set, in which case the working directory parent is
3459 --follow is set, in which case the working directory parent is
3460 used as the starting revision.
3460 used as the starting revision.
3461
3461
3462 File history is shown without following rename or copy history of
3462 File history is shown without following rename or copy history of
3463 files. Use -f/--follow with a filename to follow history across
3463 files. Use -f/--follow with a filename to follow history across
3464 renames and copies. --follow without a filename will only show
3464 renames and copies. --follow without a filename will only show
3465 ancestors or descendants of the starting revision.
3465 ancestors or descendants of the starting revision.
3466
3466
3467 By default this command prints revision number and changeset id,
3467 By default this command prints revision number and changeset id,
3468 tags, non-trivial parents, user, date and time, and a summary for
3468 tags, non-trivial parents, user, date and time, and a summary for
3469 each commit. When the -v/--verbose switch is used, the list of
3469 each commit. When the -v/--verbose switch is used, the list of
3470 changed files and full commit message are shown.
3470 changed files and full commit message are shown.
3471
3471
3472 .. note::
3472 .. note::
3473 log -p/--patch may generate unexpected diff output for merge
3473 log -p/--patch may generate unexpected diff output for merge
3474 changesets, as it will only compare the merge changeset against
3474 changesets, as it will only compare the merge changeset against
3475 its first parent. Also, only files different from BOTH parents
3475 its first parent. Also, only files different from BOTH parents
3476 will appear in files:.
3476 will appear in files:.
3477
3477
3478 .. note::
3478 .. note::
3479 for performance reasons, log FILE may omit duplicate changes
3479 for performance reasons, log FILE may omit duplicate changes
3480 made on branches and will not show deletions. To see all
3480 made on branches and will not show deletions. To see all
3481 changes including duplicates and deletions, use the --removed
3481 changes including duplicates and deletions, use the --removed
3482 switch.
3482 switch.
3483
3483
3484 .. container:: verbose
3484 .. container:: verbose
3485
3485
3486 Some examples:
3486 Some examples:
3487
3487
3488 - changesets with full descriptions and file lists::
3488 - changesets with full descriptions and file lists::
3489
3489
3490 hg log -v
3490 hg log -v
3491
3491
3492 - changesets ancestral to the working directory::
3492 - changesets ancestral to the working directory::
3493
3493
3494 hg log -f
3494 hg log -f
3495
3495
3496 - last 10 commits on the current branch::
3496 - last 10 commits on the current branch::
3497
3497
3498 hg log -l 10 -b .
3498 hg log -l 10 -b .
3499
3499
3500 - changesets showing all modifications of a file, including removals::
3500 - changesets showing all modifications of a file, including removals::
3501
3501
3502 hg log --removed file.c
3502 hg log --removed file.c
3503
3503
3504 - all changesets that touch a directory, with diffs, excluding merges::
3504 - all changesets that touch a directory, with diffs, excluding merges::
3505
3505
3506 hg log -Mp lib/
3506 hg log -Mp lib/
3507
3507
3508 - all revision numbers that match a keyword::
3508 - all revision numbers that match a keyword::
3509
3509
3510 hg log -k bug --template "{rev}\\n"
3510 hg log -k bug --template "{rev}\\n"
3511
3511
3512 - check if a given changeset is included is a tagged release::
3512 - check if a given changeset is included is a tagged release::
3513
3513
3514 hg log -r "a21ccf and ancestor(1.9)"
3514 hg log -r "a21ccf and ancestor(1.9)"
3515
3515
3516 - find all changesets by some user in a date range::
3516 - find all changesets by some user in a date range::
3517
3517
3518 hg log -k alice -d "may 2008 to jul 2008"
3518 hg log -k alice -d "may 2008 to jul 2008"
3519
3519
3520 - summary of all changesets after the last tag::
3520 - summary of all changesets after the last tag::
3521
3521
3522 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3522 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3523
3523
3524 See :hg:`help dates` for a list of formats valid for -d/--date.
3524 See :hg:`help dates` for a list of formats valid for -d/--date.
3525
3525
3526 See :hg:`help revisions` and :hg:`help revsets` for more about
3526 See :hg:`help revisions` and :hg:`help revsets` for more about
3527 specifying revisions.
3527 specifying revisions.
3528
3528
3529 Returns 0 on success.
3529 Returns 0 on success.
3530 """
3530 """
3531
3531
3532 matchfn = scmutil.match(repo[None], pats, opts)
3532 matchfn = scmutil.match(repo[None], pats, opts)
3533 limit = cmdutil.loglimit(opts)
3533 limit = cmdutil.loglimit(opts)
3534 count = 0
3534 count = 0
3535
3535
3536 endrev = None
3536 endrev = None
3537 if opts.get('copies') and opts.get('rev'):
3537 if opts.get('copies') and opts.get('rev'):
3538 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3538 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3539
3539
3540 df = False
3540 df = False
3541 if opts["date"]:
3541 if opts["date"]:
3542 df = util.matchdate(opts["date"])
3542 df = util.matchdate(opts["date"])
3543
3543
3544 branches = opts.get('branch', []) + opts.get('only_branch', [])
3544 branches = opts.get('branch', []) + opts.get('only_branch', [])
3545 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3545 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3546
3546
3547 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3547 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3548 def prep(ctx, fns):
3548 def prep(ctx, fns):
3549 rev = ctx.rev()
3549 rev = ctx.rev()
3550 parents = [p for p in repo.changelog.parentrevs(rev)
3550 parents = [p for p in repo.changelog.parentrevs(rev)
3551 if p != nullrev]
3551 if p != nullrev]
3552 if opts.get('no_merges') and len(parents) == 2:
3552 if opts.get('no_merges') and len(parents) == 2:
3553 return
3553 return
3554 if opts.get('only_merges') and len(parents) != 2:
3554 if opts.get('only_merges') and len(parents) != 2:
3555 return
3555 return
3556 if opts.get('branch') and ctx.branch() not in opts['branch']:
3556 if opts.get('branch') and ctx.branch() not in opts['branch']:
3557 return
3557 return
3558 if not opts.get('hidden') and ctx.hidden():
3558 if not opts.get('hidden') and ctx.hidden():
3559 return
3559 return
3560 if df and not df(ctx.date()[0]):
3560 if df and not df(ctx.date()[0]):
3561 return
3561 return
3562 if opts['user'] and not [k for k in opts['user']
3562 if opts['user'] and not [k for k in opts['user']
3563 if k.lower() in ctx.user().lower()]:
3563 if k.lower() in ctx.user().lower()]:
3564 return
3564 return
3565 if opts.get('keyword'):
3565 if opts.get('keyword'):
3566 for k in [kw.lower() for kw in opts['keyword']]:
3566 for k in [kw.lower() for kw in opts['keyword']]:
3567 if (k in ctx.user().lower() or
3567 if (k in ctx.user().lower() or
3568 k in ctx.description().lower() or
3568 k in ctx.description().lower() or
3569 k in " ".join(ctx.files()).lower()):
3569 k in " ".join(ctx.files()).lower()):
3570 break
3570 break
3571 else:
3571 else:
3572 return
3572 return
3573
3573
3574 copies = None
3574 copies = None
3575 if opts.get('copies') and rev:
3575 if opts.get('copies') and rev:
3576 copies = []
3576 copies = []
3577 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3577 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3578 for fn in ctx.files():
3578 for fn in ctx.files():
3579 rename = getrenamed(fn, rev)
3579 rename = getrenamed(fn, rev)
3580 if rename:
3580 if rename:
3581 copies.append((fn, rename[0]))
3581 copies.append((fn, rename[0]))
3582
3582
3583 revmatchfn = None
3583 revmatchfn = None
3584 if opts.get('patch') or opts.get('stat'):
3584 if opts.get('patch') or opts.get('stat'):
3585 if opts.get('follow') or opts.get('follow_first'):
3585 if opts.get('follow') or opts.get('follow_first'):
3586 # note: this might be wrong when following through merges
3586 # note: this might be wrong when following through merges
3587 revmatchfn = scmutil.match(repo[None], fns, default='path')
3587 revmatchfn = scmutil.match(repo[None], fns, default='path')
3588 else:
3588 else:
3589 revmatchfn = matchfn
3589 revmatchfn = matchfn
3590
3590
3591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3592
3592
3593 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3593 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3594 if count == limit:
3594 if count == limit:
3595 break
3595 break
3596 if displayer.flush(ctx.rev()):
3596 if displayer.flush(ctx.rev()):
3597 count += 1
3597 count += 1
3598 displayer.close()
3598 displayer.close()
3599
3599
3600 @command('manifest',
3600 @command('manifest',
3601 [('r', 'rev', '', _('revision to display'), _('REV')),
3601 [('r', 'rev', '', _('revision to display'), _('REV')),
3602 ('', 'all', False, _("list files from all revisions"))],
3602 ('', 'all', False, _("list files from all revisions"))],
3603 _('[-r REV]'))
3603 _('[-r REV]'))
3604 def manifest(ui, repo, node=None, rev=None, **opts):
3604 def manifest(ui, repo, node=None, rev=None, **opts):
3605 """output the current or given revision of the project manifest
3605 """output the current or given revision of the project manifest
3606
3606
3607 Print a list of version controlled files for the given revision.
3607 Print a list of version controlled files for the given revision.
3608 If no revision is given, the first parent of the working directory
3608 If no revision is given, the first parent of the working directory
3609 is used, or the null revision if no revision is checked out.
3609 is used, or the null revision if no revision is checked out.
3610
3610
3611 With -v, print file permissions, symlink and executable bits.
3611 With -v, print file permissions, symlink and executable bits.
3612 With --debug, print file revision hashes.
3612 With --debug, print file revision hashes.
3613
3613
3614 If option --all is specified, the list of all files from all revisions
3614 If option --all is specified, the list of all files from all revisions
3615 is printed. This includes deleted and renamed files.
3615 is printed. This includes deleted and renamed files.
3616
3616
3617 Returns 0 on success.
3617 Returns 0 on success.
3618 """
3618 """
3619 if opts.get('all'):
3619 if opts.get('all'):
3620 if rev or node:
3620 if rev or node:
3621 raise util.Abort(_("can't specify a revision with --all"))
3621 raise util.Abort(_("can't specify a revision with --all"))
3622
3622
3623 res = []
3623 res = []
3624 prefix = "data/"
3624 prefix = "data/"
3625 suffix = ".i"
3625 suffix = ".i"
3626 plen = len(prefix)
3626 plen = len(prefix)
3627 slen = len(suffix)
3627 slen = len(suffix)
3628 lock = repo.lock()
3628 lock = repo.lock()
3629 try:
3629 try:
3630 for fn, b, size in repo.store.datafiles():
3630 for fn, b, size in repo.store.datafiles():
3631 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3631 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3632 res.append(fn[plen:-slen])
3632 res.append(fn[plen:-slen])
3633 finally:
3633 finally:
3634 lock.release()
3634 lock.release()
3635 for f in sorted(res):
3635 for f in sorted(res):
3636 ui.write("%s\n" % f)
3636 ui.write("%s\n" % f)
3637 return
3637 return
3638
3638
3639 if rev and node:
3639 if rev and node:
3640 raise util.Abort(_("please specify just one revision"))
3640 raise util.Abort(_("please specify just one revision"))
3641
3641
3642 if not node:
3642 if not node:
3643 node = rev
3643 node = rev
3644
3644
3645 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3645 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3646 ctx = scmutil.revsingle(repo, node)
3646 ctx = scmutil.revsingle(repo, node)
3647 for f in ctx:
3647 for f in ctx:
3648 if ui.debugflag:
3648 if ui.debugflag:
3649 ui.write("%40s " % hex(ctx.manifest()[f]))
3649 ui.write("%40s " % hex(ctx.manifest()[f]))
3650 if ui.verbose:
3650 if ui.verbose:
3651 ui.write(decor[ctx.flags(f)])
3651 ui.write(decor[ctx.flags(f)])
3652 ui.write("%s\n" % f)
3652 ui.write("%s\n" % f)
3653
3653
3654 @command('^merge',
3654 @command('^merge',
3655 [('f', 'force', None, _('force a merge with outstanding changes')),
3655 [('f', 'force', None, _('force a merge with outstanding changes')),
3656 ('r', 'rev', '', _('revision to merge'), _('REV')),
3656 ('r', 'rev', '', _('revision to merge'), _('REV')),
3657 ('P', 'preview', None,
3657 ('P', 'preview', None,
3658 _('review revisions to merge (no merge is performed)'))
3658 _('review revisions to merge (no merge is performed)'))
3659 ] + mergetoolopts,
3659 ] + mergetoolopts,
3660 _('[-P] [-f] [[-r] REV]'))
3660 _('[-P] [-f] [[-r] REV]'))
3661 def merge(ui, repo, node=None, **opts):
3661 def merge(ui, repo, node=None, **opts):
3662 """merge working directory with another revision
3662 """merge working directory with another revision
3663
3663
3664 The current working directory is updated with all changes made in
3664 The current working directory is updated with all changes made in
3665 the requested revision since the last common predecessor revision.
3665 the requested revision since the last common predecessor revision.
3666
3666
3667 Files that changed between either parent are marked as changed for
3667 Files that changed between either parent are marked as changed for
3668 the next commit and a commit must be performed before any further
3668 the next commit and a commit must be performed before any further
3669 updates to the repository are allowed. The next commit will have
3669 updates to the repository are allowed. The next commit will have
3670 two parents.
3670 two parents.
3671
3671
3672 ``--tool`` can be used to specify the merge tool used for file
3672 ``--tool`` can be used to specify the merge tool used for file
3673 merges. It overrides the HGMERGE environment variable and your
3673 merges. It overrides the HGMERGE environment variable and your
3674 configuration files. See :hg:`help merge-tools` for options.
3674 configuration files. See :hg:`help merge-tools` for options.
3675
3675
3676 If no revision is specified, the working directory's parent is a
3676 If no revision is specified, the working directory's parent is a
3677 head revision, and the current branch contains exactly one other
3677 head revision, and the current branch contains exactly one other
3678 head, the other head is merged with by default. Otherwise, an
3678 head, the other head is merged with by default. Otherwise, an
3679 explicit revision with which to merge with must be provided.
3679 explicit revision with which to merge with must be provided.
3680
3680
3681 :hg:`resolve` must be used to resolve unresolved files.
3681 :hg:`resolve` must be used to resolve unresolved files.
3682
3682
3683 To undo an uncommitted merge, use :hg:`update --clean .` which
3683 To undo an uncommitted merge, use :hg:`update --clean .` which
3684 will check out a clean copy of the original merge parent, losing
3684 will check out a clean copy of the original merge parent, losing
3685 all changes.
3685 all changes.
3686
3686
3687 Returns 0 on success, 1 if there are unresolved files.
3687 Returns 0 on success, 1 if there are unresolved files.
3688 """
3688 """
3689
3689
3690 if opts.get('rev') and node:
3690 if opts.get('rev') and node:
3691 raise util.Abort(_("please specify just one revision"))
3691 raise util.Abort(_("please specify just one revision"))
3692 if not node:
3692 if not node:
3693 node = opts.get('rev')
3693 node = opts.get('rev')
3694
3694
3695 if not node:
3695 if not node:
3696 branch = repo[None].branch()
3696 branch = repo[None].branch()
3697 bheads = repo.branchheads(branch)
3697 bheads = repo.branchheads(branch)
3698 if len(bheads) > 2:
3698 if len(bheads) > 2:
3699 raise util.Abort(_("branch '%s' has %d heads - "
3699 raise util.Abort(_("branch '%s' has %d heads - "
3700 "please merge with an explicit rev")
3700 "please merge with an explicit rev")
3701 % (branch, len(bheads)),
3701 % (branch, len(bheads)),
3702 hint=_("run 'hg heads .' to see heads"))
3702 hint=_("run 'hg heads .' to see heads"))
3703
3703
3704 parent = repo.dirstate.p1()
3704 parent = repo.dirstate.p1()
3705 if len(bheads) == 1:
3705 if len(bheads) == 1:
3706 if len(repo.heads()) > 1:
3706 if len(repo.heads()) > 1:
3707 raise util.Abort(_("branch '%s' has one head - "
3707 raise util.Abort(_("branch '%s' has one head - "
3708 "please merge with an explicit rev")
3708 "please merge with an explicit rev")
3709 % branch,
3709 % branch,
3710 hint=_("run 'hg heads' to see all heads"))
3710 hint=_("run 'hg heads' to see all heads"))
3711 msg = _('there is nothing to merge')
3711 msg = _('there is nothing to merge')
3712 if parent != repo.lookup(repo[None].branch()):
3712 if parent != repo.lookup(repo[None].branch()):
3713 msg = _('%s - use "hg update" instead') % msg
3713 msg = _('%s - use "hg update" instead') % msg
3714 raise util.Abort(msg)
3714 raise util.Abort(msg)
3715
3715
3716 if parent not in bheads:
3716 if parent not in bheads:
3717 raise util.Abort(_('working directory not at a head revision'),
3717 raise util.Abort(_('working directory not at a head revision'),
3718 hint=_("use 'hg update' or merge with an "
3718 hint=_("use 'hg update' or merge with an "
3719 "explicit revision"))
3719 "explicit revision"))
3720 node = parent == bheads[0] and bheads[-1] or bheads[0]
3720 node = parent == bheads[0] and bheads[-1] or bheads[0]
3721 else:
3721 else:
3722 node = scmutil.revsingle(repo, node).node()
3722 node = scmutil.revsingle(repo, node).node()
3723
3723
3724 if opts.get('preview'):
3724 if opts.get('preview'):
3725 # find nodes that are ancestors of p2 but not of p1
3725 # find nodes that are ancestors of p2 but not of p1
3726 p1 = repo.lookup('.')
3726 p1 = repo.lookup('.')
3727 p2 = repo.lookup(node)
3727 p2 = repo.lookup(node)
3728 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3728 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3729
3729
3730 displayer = cmdutil.show_changeset(ui, repo, opts)
3730 displayer = cmdutil.show_changeset(ui, repo, opts)
3731 for node in nodes:
3731 for node in nodes:
3732 displayer.show(repo[node])
3732 displayer.show(repo[node])
3733 displayer.close()
3733 displayer.close()
3734 return 0
3734 return 0
3735
3735
3736 try:
3736 try:
3737 # ui.forcemerge is an internal variable, do not document
3737 # ui.forcemerge is an internal variable, do not document
3738 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3738 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3739 return hg.merge(repo, node, force=opts.get('force'))
3739 return hg.merge(repo, node, force=opts.get('force'))
3740 finally:
3740 finally:
3741 ui.setconfig('ui', 'forcemerge', '')
3741 ui.setconfig('ui', 'forcemerge', '')
3742
3742
3743 @command('outgoing|out',
3743 @command('outgoing|out',
3744 [('f', 'force', None, _('run even when the destination is unrelated')),
3744 [('f', 'force', None, _('run even when the destination is unrelated')),
3745 ('r', 'rev', [],
3745 ('r', 'rev', [],
3746 _('a changeset intended to be included in the destination'), _('REV')),
3746 _('a changeset intended to be included in the destination'), _('REV')),
3747 ('n', 'newest-first', None, _('show newest record first')),
3747 ('n', 'newest-first', None, _('show newest record first')),
3748 ('B', 'bookmarks', False, _('compare bookmarks')),
3748 ('B', 'bookmarks', False, _('compare bookmarks')),
3749 ('b', 'branch', [], _('a specific branch you would like to push'),
3749 ('b', 'branch', [], _('a specific branch you would like to push'),
3750 _('BRANCH')),
3750 _('BRANCH')),
3751 ] + logopts + remoteopts + subrepoopts,
3751 ] + logopts + remoteopts + subrepoopts,
3752 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3752 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3753 def outgoing(ui, repo, dest=None, **opts):
3753 def outgoing(ui, repo, dest=None, **opts):
3754 """show changesets not found in the destination
3754 """show changesets not found in the destination
3755
3755
3756 Show changesets not found in the specified destination repository
3756 Show changesets not found in the specified destination repository
3757 or the default push location. These are the changesets that would
3757 or the default push location. These are the changesets that would
3758 be pushed if a push was requested.
3758 be pushed if a push was requested.
3759
3759
3760 See pull for details of valid destination formats.
3760 See pull for details of valid destination formats.
3761
3761
3762 Returns 0 if there are outgoing changes, 1 otherwise.
3762 Returns 0 if there are outgoing changes, 1 otherwise.
3763 """
3763 """
3764
3764
3765 if opts.get('bookmarks'):
3765 if opts.get('bookmarks'):
3766 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3766 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3767 dest, branches = hg.parseurl(dest, opts.get('branch'))
3767 dest, branches = hg.parseurl(dest, opts.get('branch'))
3768 other = hg.peer(repo, opts, dest)
3768 other = hg.peer(repo, opts, dest)
3769 if 'bookmarks' not in other.listkeys('namespaces'):
3769 if 'bookmarks' not in other.listkeys('namespaces'):
3770 ui.warn(_("remote doesn't support bookmarks\n"))
3770 ui.warn(_("remote doesn't support bookmarks\n"))
3771 return 0
3771 return 0
3772 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3772 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3773 return bookmarks.diff(ui, other, repo)
3773 return bookmarks.diff(ui, other, repo)
3774
3774
3775 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3775 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3776 try:
3776 try:
3777 return hg.outgoing(ui, repo, dest, opts)
3777 return hg.outgoing(ui, repo, dest, opts)
3778 finally:
3778 finally:
3779 del repo._subtoppath
3779 del repo._subtoppath
3780
3780
3781 @command('parents',
3781 @command('parents',
3782 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3782 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3783 ] + templateopts,
3783 ] + templateopts,
3784 _('[-r REV] [FILE]'))
3784 _('[-r REV] [FILE]'))
3785 def parents(ui, repo, file_=None, **opts):
3785 def parents(ui, repo, file_=None, **opts):
3786 """show the parents of the working directory or revision
3786 """show the parents of the working directory or revision
3787
3787
3788 Print the working directory's parent revisions. If a revision is
3788 Print the working directory's parent revisions. If a revision is
3789 given via -r/--rev, the parent of that revision will be printed.
3789 given via -r/--rev, the parent of that revision will be printed.
3790 If a file argument is given, the revision in which the file was
3790 If a file argument is given, the revision in which the file was
3791 last changed (before the working directory revision or the
3791 last changed (before the working directory revision or the
3792 argument to --rev if given) is printed.
3792 argument to --rev if given) is printed.
3793
3793
3794 Returns 0 on success.
3794 Returns 0 on success.
3795 """
3795 """
3796
3796
3797 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3797 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3798
3798
3799 if file_:
3799 if file_:
3800 m = scmutil.match(ctx, (file_,), opts)
3800 m = scmutil.match(ctx, (file_,), opts)
3801 if m.anypats() or len(m.files()) != 1:
3801 if m.anypats() or len(m.files()) != 1:
3802 raise util.Abort(_('can only specify an explicit filename'))
3802 raise util.Abort(_('can only specify an explicit filename'))
3803 file_ = m.files()[0]
3803 file_ = m.files()[0]
3804 filenodes = []
3804 filenodes = []
3805 for cp in ctx.parents():
3805 for cp in ctx.parents():
3806 if not cp:
3806 if not cp:
3807 continue
3807 continue
3808 try:
3808 try:
3809 filenodes.append(cp.filenode(file_))
3809 filenodes.append(cp.filenode(file_))
3810 except error.LookupError:
3810 except error.LookupError:
3811 pass
3811 pass
3812 if not filenodes:
3812 if not filenodes:
3813 raise util.Abort(_("'%s' not found in manifest!") % file_)
3813 raise util.Abort(_("'%s' not found in manifest!") % file_)
3814 fl = repo.file(file_)
3814 fl = repo.file(file_)
3815 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3815 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3816 else:
3816 else:
3817 p = [cp.node() for cp in ctx.parents()]
3817 p = [cp.node() for cp in ctx.parents()]
3818
3818
3819 displayer = cmdutil.show_changeset(ui, repo, opts)
3819 displayer = cmdutil.show_changeset(ui, repo, opts)
3820 for n in p:
3820 for n in p:
3821 if n != nullid:
3821 if n != nullid:
3822 displayer.show(repo[n])
3822 displayer.show(repo[n])
3823 displayer.close()
3823 displayer.close()
3824
3824
3825 @command('paths', [], _('[NAME]'))
3825 @command('paths', [], _('[NAME]'))
3826 def paths(ui, repo, search=None):
3826 def paths(ui, repo, search=None):
3827 """show aliases for remote repositories
3827 """show aliases for remote repositories
3828
3828
3829 Show definition of symbolic path name NAME. If no name is given,
3829 Show definition of symbolic path name NAME. If no name is given,
3830 show definition of all available names.
3830 show definition of all available names.
3831
3831
3832 Option -q/--quiet suppresses all output when searching for NAME
3832 Option -q/--quiet suppresses all output when searching for NAME
3833 and shows only the path names when listing all definitions.
3833 and shows only the path names when listing all definitions.
3834
3834
3835 Path names are defined in the [paths] section of your
3835 Path names are defined in the [paths] section of your
3836 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3836 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3837 repository, ``.hg/hgrc`` is used, too.
3837 repository, ``.hg/hgrc`` is used, too.
3838
3838
3839 The path names ``default`` and ``default-push`` have a special
3839 The path names ``default`` and ``default-push`` have a special
3840 meaning. When performing a push or pull operation, they are used
3840 meaning. When performing a push or pull operation, they are used
3841 as fallbacks if no location is specified on the command-line.
3841 as fallbacks if no location is specified on the command-line.
3842 When ``default-push`` is set, it will be used for push and
3842 When ``default-push`` is set, it will be used for push and
3843 ``default`` will be used for pull; otherwise ``default`` is used
3843 ``default`` will be used for pull; otherwise ``default`` is used
3844 as the fallback for both. When cloning a repository, the clone
3844 as the fallback for both. When cloning a repository, the clone
3845 source is written as ``default`` in ``.hg/hgrc``. Note that
3845 source is written as ``default`` in ``.hg/hgrc``. Note that
3846 ``default`` and ``default-push`` apply to all inbound (e.g.
3846 ``default`` and ``default-push`` apply to all inbound (e.g.
3847 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3847 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3848 :hg:`bundle`) operations.
3848 :hg:`bundle`) operations.
3849
3849
3850 See :hg:`help urls` for more information.
3850 See :hg:`help urls` for more information.
3851
3851
3852 Returns 0 on success.
3852 Returns 0 on success.
3853 """
3853 """
3854 if search:
3854 if search:
3855 for name, path in ui.configitems("paths"):
3855 for name, path in ui.configitems("paths"):
3856 if name == search:
3856 if name == search:
3857 ui.status("%s\n" % util.hidepassword(path))
3857 ui.status("%s\n" % util.hidepassword(path))
3858 return
3858 return
3859 if not ui.quiet:
3859 if not ui.quiet:
3860 ui.warn(_("not found!\n"))
3860 ui.warn(_("not found!\n"))
3861 return 1
3861 return 1
3862 else:
3862 else:
3863 for name, path in ui.configitems("paths"):
3863 for name, path in ui.configitems("paths"):
3864 if ui.quiet:
3864 if ui.quiet:
3865 ui.write("%s\n" % name)
3865 ui.write("%s\n" % name)
3866 else:
3866 else:
3867 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3867 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3868
3868
3869 def postincoming(ui, repo, modheads, optupdate, checkout):
3869 def postincoming(ui, repo, modheads, optupdate, checkout):
3870 if modheads == 0:
3870 if modheads == 0:
3871 return
3871 return
3872 if optupdate:
3872 if optupdate:
3873 try:
3873 try:
3874 return hg.update(repo, checkout)
3874 return hg.update(repo, checkout)
3875 except util.Abort, inst:
3875 except util.Abort, inst:
3876 ui.warn(_("not updating: %s\n" % str(inst)))
3876 ui.warn(_("not updating: %s\n" % str(inst)))
3877 return 0
3877 return 0
3878 if modheads > 1:
3878 if modheads > 1:
3879 currentbranchheads = len(repo.branchheads())
3879 currentbranchheads = len(repo.branchheads())
3880 if currentbranchheads == modheads:
3880 if currentbranchheads == modheads:
3881 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3881 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3882 elif currentbranchheads > 1:
3882 elif currentbranchheads > 1:
3883 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3883 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3884 else:
3884 else:
3885 ui.status(_("(run 'hg heads' to see heads)\n"))
3885 ui.status(_("(run 'hg heads' to see heads)\n"))
3886 else:
3886 else:
3887 ui.status(_("(run 'hg update' to get a working copy)\n"))
3887 ui.status(_("(run 'hg update' to get a working copy)\n"))
3888
3888
3889 @command('^pull',
3889 @command('^pull',
3890 [('u', 'update', None,
3890 [('u', 'update', None,
3891 _('update to new branch head if changesets were pulled')),
3891 _('update to new branch head if changesets were pulled')),
3892 ('f', 'force', None, _('run even when remote repository is unrelated')),
3892 ('f', 'force', None, _('run even when remote repository is unrelated')),
3893 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3893 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3894 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3894 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3895 ('b', 'branch', [], _('a specific branch you would like to pull'),
3895 ('b', 'branch', [], _('a specific branch you would like to pull'),
3896 _('BRANCH')),
3896 _('BRANCH')),
3897 ] + remoteopts,
3897 ] + remoteopts,
3898 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3898 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3899 def pull(ui, repo, source="default", **opts):
3899 def pull(ui, repo, source="default", **opts):
3900 """pull changes from the specified source
3900 """pull changes from the specified source
3901
3901
3902 Pull changes from a remote repository to a local one.
3902 Pull changes from a remote repository to a local one.
3903
3903
3904 This finds all changes from the repository at the specified path
3904 This finds all changes from the repository at the specified path
3905 or URL and adds them to a local repository (the current one unless
3905 or URL and adds them to a local repository (the current one unless
3906 -R is specified). By default, this does not update the copy of the
3906 -R is specified). By default, this does not update the copy of the
3907 project in the working directory.
3907 project in the working directory.
3908
3908
3909 Use :hg:`incoming` if you want to see what would have been added
3909 Use :hg:`incoming` if you want to see what would have been added
3910 by a pull at the time you issued this command. If you then decide
3910 by a pull at the time you issued this command. If you then decide
3911 to add those changes to the repository, you should use :hg:`pull
3911 to add those changes to the repository, you should use :hg:`pull
3912 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3912 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3913
3913
3914 If SOURCE is omitted, the 'default' path will be used.
3914 If SOURCE is omitted, the 'default' path will be used.
3915 See :hg:`help urls` for more information.
3915 See :hg:`help urls` for more information.
3916
3916
3917 Returns 0 on success, 1 if an update had unresolved files.
3917 Returns 0 on success, 1 if an update had unresolved files.
3918 """
3918 """
3919 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3919 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3920 other = hg.peer(repo, opts, source)
3920 other = hg.peer(repo, opts, source)
3921 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3921 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3922 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3922 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3923
3923
3924 if opts.get('bookmark'):
3924 if opts.get('bookmark'):
3925 if not revs:
3925 if not revs:
3926 revs = []
3926 revs = []
3927 rb = other.listkeys('bookmarks')
3927 rb = other.listkeys('bookmarks')
3928 for b in opts['bookmark']:
3928 for b in opts['bookmark']:
3929 if b not in rb:
3929 if b not in rb:
3930 raise util.Abort(_('remote bookmark %s not found!') % b)
3930 raise util.Abort(_('remote bookmark %s not found!') % b)
3931 revs.append(rb[b])
3931 revs.append(rb[b])
3932
3932
3933 if revs:
3933 if revs:
3934 try:
3934 try:
3935 revs = [other.lookup(rev) for rev in revs]
3935 revs = [other.lookup(rev) for rev in revs]
3936 except error.CapabilityError:
3936 except error.CapabilityError:
3937 err = _("other repository doesn't support revision lookup, "
3937 err = _("other repository doesn't support revision lookup, "
3938 "so a rev cannot be specified.")
3938 "so a rev cannot be specified.")
3939 raise util.Abort(err)
3939 raise util.Abort(err)
3940
3940
3941 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3941 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3942 bookmarks.updatefromremote(ui, repo, other)
3942 bookmarks.updatefromremote(ui, repo, other)
3943 if checkout:
3943 if checkout:
3944 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3944 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3945 repo._subtoppath = source
3945 repo._subtoppath = source
3946 try:
3946 try:
3947 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3947 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3948
3948
3949 finally:
3949 finally:
3950 del repo._subtoppath
3950 del repo._subtoppath
3951
3951
3952 # update specified bookmarks
3952 # update specified bookmarks
3953 if opts.get('bookmark'):
3953 if opts.get('bookmark'):
3954 for b in opts['bookmark']:
3954 for b in opts['bookmark']:
3955 # explicit pull overrides local bookmark if any
3955 # explicit pull overrides local bookmark if any
3956 ui.status(_("importing bookmark %s\n") % b)
3956 ui.status(_("importing bookmark %s\n") % b)
3957 repo._bookmarks[b] = repo[rb[b]].node()
3957 repo._bookmarks[b] = repo[rb[b]].node()
3958 bookmarks.write(repo)
3958 bookmarks.write(repo)
3959
3959
3960 return ret
3960 return ret
3961
3961
3962 @command('^push',
3962 @command('^push',
3963 [('f', 'force', None, _('force push')),
3963 [('f', 'force', None, _('force push')),
3964 ('r', 'rev', [],
3964 ('r', 'rev', [],
3965 _('a changeset intended to be included in the destination'),
3965 _('a changeset intended to be included in the destination'),
3966 _('REV')),
3966 _('REV')),
3967 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3967 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3968 ('b', 'branch', [],
3968 ('b', 'branch', [],
3969 _('a specific branch you would like to push'), _('BRANCH')),
3969 _('a specific branch you would like to push'), _('BRANCH')),
3970 ('', 'new-branch', False, _('allow pushing a new branch')),
3970 ('', 'new-branch', False, _('allow pushing a new branch')),
3971 ] + remoteopts,
3971 ] + remoteopts,
3972 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3972 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3973 def push(ui, repo, dest=None, **opts):
3973 def push(ui, repo, dest=None, **opts):
3974 """push changes to the specified destination
3974 """push changes to the specified destination
3975
3975
3976 Push changesets from the local repository to the specified
3976 Push changesets from the local repository to the specified
3977 destination.
3977 destination.
3978
3978
3979 This operation is symmetrical to pull: it is identical to a pull
3979 This operation is symmetrical to pull: it is identical to a pull
3980 in the destination repository from the current one.
3980 in the destination repository from the current one.
3981
3981
3982 By default, push will not allow creation of new heads at the
3982 By default, push will not allow creation of new heads at the
3983 destination, since multiple heads would make it unclear which head
3983 destination, since multiple heads would make it unclear which head
3984 to use. In this situation, it is recommended to pull and merge
3984 to use. In this situation, it is recommended to pull and merge
3985 before pushing.
3985 before pushing.
3986
3986
3987 Use --new-branch if you want to allow push to create a new named
3987 Use --new-branch if you want to allow push to create a new named
3988 branch that is not present at the destination. This allows you to
3988 branch that is not present at the destination. This allows you to
3989 only create a new branch without forcing other changes.
3989 only create a new branch without forcing other changes.
3990
3990
3991 Use -f/--force to override the default behavior and push all
3991 Use -f/--force to override the default behavior and push all
3992 changesets on all branches.
3992 changesets on all branches.
3993
3993
3994 If -r/--rev is used, the specified revision and all its ancestors
3994 If -r/--rev is used, the specified revision and all its ancestors
3995 will be pushed to the remote repository.
3995 will be pushed to the remote repository.
3996
3996
3997 Please see :hg:`help urls` for important details about ``ssh://``
3997 Please see :hg:`help urls` for important details about ``ssh://``
3998 URLs. If DESTINATION is omitted, a default path will be used.
3998 URLs. If DESTINATION is omitted, a default path will be used.
3999
3999
4000 Returns 0 if push was successful, 1 if nothing to push.
4000 Returns 0 if push was successful, 1 if nothing to push.
4001 """
4001 """
4002
4002
4003 if opts.get('bookmark'):
4003 if opts.get('bookmark'):
4004 for b in opts['bookmark']:
4004 for b in opts['bookmark']:
4005 # translate -B options to -r so changesets get pushed
4005 # translate -B options to -r so changesets get pushed
4006 if b in repo._bookmarks:
4006 if b in repo._bookmarks:
4007 opts.setdefault('rev', []).append(b)
4007 opts.setdefault('rev', []).append(b)
4008 else:
4008 else:
4009 # if we try to push a deleted bookmark, translate it to null
4009 # if we try to push a deleted bookmark, translate it to null
4010 # this lets simultaneous -r, -b options continue working
4010 # this lets simultaneous -r, -b options continue working
4011 opts.setdefault('rev', []).append("null")
4011 opts.setdefault('rev', []).append("null")
4012
4012
4013 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4013 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4014 dest, branches = hg.parseurl(dest, opts.get('branch'))
4014 dest, branches = hg.parseurl(dest, opts.get('branch'))
4015 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4015 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4016 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4016 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4017 other = hg.peer(repo, opts, dest)
4017 other = hg.peer(repo, opts, dest)
4018 if revs:
4018 if revs:
4019 revs = [repo.lookup(rev) for rev in revs]
4019 revs = [repo.lookup(rev) for rev in revs]
4020
4020
4021 repo._subtoppath = dest
4021 repo._subtoppath = dest
4022 try:
4022 try:
4023 # push subrepos depth-first for coherent ordering
4023 # push subrepos depth-first for coherent ordering
4024 c = repo['']
4024 c = repo['']
4025 subs = c.substate # only repos that are committed
4025 subs = c.substate # only repos that are committed
4026 for s in sorted(subs):
4026 for s in sorted(subs):
4027 if not c.sub(s).push(opts.get('force')):
4027 if not c.sub(s).push(opts.get('force')):
4028 return False
4028 return False
4029 finally:
4029 finally:
4030 del repo._subtoppath
4030 del repo._subtoppath
4031 result = repo.push(other, opts.get('force'), revs=revs,
4031 result = repo.push(other, opts.get('force'), revs=revs,
4032 newbranch=opts.get('new_branch'))
4032 newbranch=opts.get('new_branch'))
4033
4033
4034 result = (result == 0)
4034 result = (result == 0)
4035
4035
4036 if opts.get('bookmark'):
4036 if opts.get('bookmark'):
4037 rb = other.listkeys('bookmarks')
4037 rb = other.listkeys('bookmarks')
4038 for b in opts['bookmark']:
4038 for b in opts['bookmark']:
4039 # explicit push overrides remote bookmark if any
4039 # explicit push overrides remote bookmark if any
4040 if b in repo._bookmarks:
4040 if b in repo._bookmarks:
4041 ui.status(_("exporting bookmark %s\n") % b)
4041 ui.status(_("exporting bookmark %s\n") % b)
4042 new = repo[b].hex()
4042 new = repo[b].hex()
4043 elif b in rb:
4043 elif b in rb:
4044 ui.status(_("deleting remote bookmark %s\n") % b)
4044 ui.status(_("deleting remote bookmark %s\n") % b)
4045 new = '' # delete
4045 new = '' # delete
4046 else:
4046 else:
4047 ui.warn(_('bookmark %s does not exist on the local '
4047 ui.warn(_('bookmark %s does not exist on the local '
4048 'or remote repository!\n') % b)
4048 'or remote repository!\n') % b)
4049 return 2
4049 return 2
4050 old = rb.get(b, '')
4050 old = rb.get(b, '')
4051 r = other.pushkey('bookmarks', b, old, new)
4051 r = other.pushkey('bookmarks', b, old, new)
4052 if not r:
4052 if not r:
4053 ui.warn(_('updating bookmark %s failed!\n') % b)
4053 ui.warn(_('updating bookmark %s failed!\n') % b)
4054 if not result:
4054 if not result:
4055 result = 2
4055 result = 2
4056
4056
4057 return result
4057 return result
4058
4058
4059 @command('recover', [])
4059 @command('recover', [])
4060 def recover(ui, repo):
4060 def recover(ui, repo):
4061 """roll back an interrupted transaction
4061 """roll back an interrupted transaction
4062
4062
4063 Recover from an interrupted commit or pull.
4063 Recover from an interrupted commit or pull.
4064
4064
4065 This command tries to fix the repository status after an
4065 This command tries to fix the repository status after an
4066 interrupted operation. It should only be necessary when Mercurial
4066 interrupted operation. It should only be necessary when Mercurial
4067 suggests it.
4067 suggests it.
4068
4068
4069 Returns 0 if successful, 1 if nothing to recover or verify fails.
4069 Returns 0 if successful, 1 if nothing to recover or verify fails.
4070 """
4070 """
4071 if repo.recover():
4071 if repo.recover():
4072 return hg.verify(repo)
4072 return hg.verify(repo)
4073 return 1
4073 return 1
4074
4074
4075 @command('^remove|rm',
4075 @command('^remove|rm',
4076 [('A', 'after', None, _('record delete for missing files')),
4076 [('A', 'after', None, _('record delete for missing files')),
4077 ('f', 'force', None,
4077 ('f', 'force', None,
4078 _('remove (and delete) file even if added or modified')),
4078 _('remove (and delete) file even if added or modified')),
4079 ] + walkopts,
4079 ] + walkopts,
4080 _('[OPTION]... FILE...'))
4080 _('[OPTION]... FILE...'))
4081 def remove(ui, repo, *pats, **opts):
4081 def remove(ui, repo, *pats, **opts):
4082 """remove the specified files on the next commit
4082 """remove the specified files on the next commit
4083
4083
4084 Schedule the indicated files for removal from the current branch.
4084 Schedule the indicated files for removal from the current branch.
4085
4085
4086 This command schedules the files to be removed at the next commit.
4086 This command schedules the files to be removed at the next commit.
4087 To undo a remove before that, see :hg:`revert`. To undo added
4087 To undo a remove before that, see :hg:`revert`. To undo added
4088 files, see :hg:`forget`.
4088 files, see :hg:`forget`.
4089
4089
4090 .. container:: verbose
4090 .. container:: verbose
4091
4091
4092 -A/--after can be used to remove only files that have already
4092 -A/--after can be used to remove only files that have already
4093 been deleted, -f/--force can be used to force deletion, and -Af
4093 been deleted, -f/--force can be used to force deletion, and -Af
4094 can be used to remove files from the next revision without
4094 can be used to remove files from the next revision without
4095 deleting them from the working directory.
4095 deleting them from the working directory.
4096
4096
4097 The following table details the behavior of remove for different
4097 The following table details the behavior of remove for different
4098 file states (columns) and option combinations (rows). The file
4098 file states (columns) and option combinations (rows). The file
4099 states are Added [A], Clean [C], Modified [M] and Missing [!]
4099 states are Added [A], Clean [C], Modified [M] and Missing [!]
4100 (as reported by :hg:`status`). The actions are Warn, Remove
4100 (as reported by :hg:`status`). The actions are Warn, Remove
4101 (from branch) and Delete (from disk):
4101 (from branch) and Delete (from disk):
4102
4102
4103 ======= == == == ==
4103 ======= == == == ==
4104 A C M !
4104 A C M !
4105 ======= == == == ==
4105 ======= == == == ==
4106 none W RD W R
4106 none W RD W R
4107 -f R RD RD R
4107 -f R RD RD R
4108 -A W W W R
4108 -A W W W R
4109 -Af R R R R
4109 -Af R R R R
4110 ======= == == == ==
4110 ======= == == == ==
4111
4111
4112 Note that remove never deletes files in Added [A] state from the
4112 Note that remove never deletes files in Added [A] state from the
4113 working directory, not even if option --force is specified.
4113 working directory, not even if option --force is specified.
4114
4114
4115 Returns 0 on success, 1 if any warnings encountered.
4115 Returns 0 on success, 1 if any warnings encountered.
4116 """
4116 """
4117
4117
4118 ret = 0
4118 ret = 0
4119 after, force = opts.get('after'), opts.get('force')
4119 after, force = opts.get('after'), opts.get('force')
4120 if not pats and not after:
4120 if not pats and not after:
4121 raise util.Abort(_('no files specified'))
4121 raise util.Abort(_('no files specified'))
4122
4122
4123 m = scmutil.match(repo[None], pats, opts)
4123 m = scmutil.match(repo[None], pats, opts)
4124 s = repo.status(match=m, clean=True)
4124 s = repo.status(match=m, clean=True)
4125 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4125 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4126
4126
4127 for f in m.files():
4127 for f in m.files():
4128 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4128 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4129 if os.path.exists(m.rel(f)):
4129 if os.path.exists(m.rel(f)):
4130 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4130 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4131 ret = 1
4131 ret = 1
4132
4132
4133 if force:
4133 if force:
4134 list = modified + deleted + clean + added
4134 list = modified + deleted + clean + added
4135 elif after:
4135 elif after:
4136 list = deleted
4136 list = deleted
4137 for f in modified + added + clean:
4137 for f in modified + added + clean:
4138 ui.warn(_('not removing %s: file still exists (use -f'
4138 ui.warn(_('not removing %s: file still exists (use -f'
4139 ' to force removal)\n') % m.rel(f))
4139 ' to force removal)\n') % m.rel(f))
4140 ret = 1
4140 ret = 1
4141 else:
4141 else:
4142 list = deleted + clean
4142 list = deleted + clean
4143 for f in modified:
4143 for f in modified:
4144 ui.warn(_('not removing %s: file is modified (use -f'
4144 ui.warn(_('not removing %s: file is modified (use -f'
4145 ' to force removal)\n') % m.rel(f))
4145 ' to force removal)\n') % m.rel(f))
4146 ret = 1
4146 ret = 1
4147 for f in added:
4147 for f in added:
4148 ui.warn(_('not removing %s: file has been marked for add (use -f'
4148 ui.warn(_('not removing %s: file has been marked for add'
4149 ' to force removal)\n') % m.rel(f))
4149 ' (use forget to undo)\n') % m.rel(f))
4150 ret = 1
4150 ret = 1
4151
4151
4152 for f in sorted(list):
4152 for f in sorted(list):
4153 if ui.verbose or not m.exact(f):
4153 if ui.verbose or not m.exact(f):
4154 ui.status(_('removing %s\n') % m.rel(f))
4154 ui.status(_('removing %s\n') % m.rel(f))
4155
4155
4156 wlock = repo.wlock()
4156 wlock = repo.wlock()
4157 try:
4157 try:
4158 if not after:
4158 if not after:
4159 for f in list:
4159 for f in list:
4160 if f in added:
4160 if f in added:
4161 continue # we never unlink added files on remove
4161 continue # we never unlink added files on remove
4162 try:
4162 try:
4163 util.unlinkpath(repo.wjoin(f))
4163 util.unlinkpath(repo.wjoin(f))
4164 except OSError, inst:
4164 except OSError, inst:
4165 if inst.errno != errno.ENOENT:
4165 if inst.errno != errno.ENOENT:
4166 raise
4166 raise
4167 repo[None].forget(list)
4167 repo[None].forget(list)
4168 finally:
4168 finally:
4169 wlock.release()
4169 wlock.release()
4170
4170
4171 return ret
4171 return ret
4172
4172
4173 @command('rename|move|mv',
4173 @command('rename|move|mv',
4174 [('A', 'after', None, _('record a rename that has already occurred')),
4174 [('A', 'after', None, _('record a rename that has already occurred')),
4175 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4175 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4176 ] + walkopts + dryrunopts,
4176 ] + walkopts + dryrunopts,
4177 _('[OPTION]... SOURCE... DEST'))
4177 _('[OPTION]... SOURCE... DEST'))
4178 def rename(ui, repo, *pats, **opts):
4178 def rename(ui, repo, *pats, **opts):
4179 """rename files; equivalent of copy + remove
4179 """rename files; equivalent of copy + remove
4180
4180
4181 Mark dest as copies of sources; mark sources for deletion. If dest
4181 Mark dest as copies of sources; mark sources for deletion. If dest
4182 is a directory, copies are put in that directory. If dest is a
4182 is a directory, copies are put in that directory. If dest is a
4183 file, there can only be one source.
4183 file, there can only be one source.
4184
4184
4185 By default, this command copies the contents of files as they
4185 By default, this command copies the contents of files as they
4186 exist in the working directory. If invoked with -A/--after, the
4186 exist in the working directory. If invoked with -A/--after, the
4187 operation is recorded, but no copying is performed.
4187 operation is recorded, but no copying is performed.
4188
4188
4189 This command takes effect at the next commit. To undo a rename
4189 This command takes effect at the next commit. To undo a rename
4190 before that, see :hg:`revert`.
4190 before that, see :hg:`revert`.
4191
4191
4192 Returns 0 on success, 1 if errors are encountered.
4192 Returns 0 on success, 1 if errors are encountered.
4193 """
4193 """
4194 wlock = repo.wlock(False)
4194 wlock = repo.wlock(False)
4195 try:
4195 try:
4196 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4196 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4197 finally:
4197 finally:
4198 wlock.release()
4198 wlock.release()
4199
4199
4200 @command('resolve',
4200 @command('resolve',
4201 [('a', 'all', None, _('select all unresolved files')),
4201 [('a', 'all', None, _('select all unresolved files')),
4202 ('l', 'list', None, _('list state of files needing merge')),
4202 ('l', 'list', None, _('list state of files needing merge')),
4203 ('m', 'mark', None, _('mark files as resolved')),
4203 ('m', 'mark', None, _('mark files as resolved')),
4204 ('u', 'unmark', None, _('mark files as unresolved')),
4204 ('u', 'unmark', None, _('mark files as unresolved')),
4205 ('n', 'no-status', None, _('hide status prefix'))]
4205 ('n', 'no-status', None, _('hide status prefix'))]
4206 + mergetoolopts + walkopts,
4206 + mergetoolopts + walkopts,
4207 _('[OPTION]... [FILE]...'))
4207 _('[OPTION]... [FILE]...'))
4208 def resolve(ui, repo, *pats, **opts):
4208 def resolve(ui, repo, *pats, **opts):
4209 """redo merges or set/view the merge status of files
4209 """redo merges or set/view the merge status of files
4210
4210
4211 Merges with unresolved conflicts are often the result of
4211 Merges with unresolved conflicts are often the result of
4212 non-interactive merging using the ``internal:merge`` configuration
4212 non-interactive merging using the ``internal:merge`` configuration
4213 setting, or a command-line merge tool like ``diff3``. The resolve
4213 setting, or a command-line merge tool like ``diff3``. The resolve
4214 command is used to manage the files involved in a merge, after
4214 command is used to manage the files involved in a merge, after
4215 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4215 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4216 working directory must have two parents).
4216 working directory must have two parents).
4217
4217
4218 The resolve command can be used in the following ways:
4218 The resolve command can be used in the following ways:
4219
4219
4220 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4220 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4221 files, discarding any previous merge attempts. Re-merging is not
4221 files, discarding any previous merge attempts. Re-merging is not
4222 performed for files already marked as resolved. Use ``--all/-a``
4222 performed for files already marked as resolved. Use ``--all/-a``
4223 to select all unresolved files. ``--tool`` can be used to specify
4223 to select all unresolved files. ``--tool`` can be used to specify
4224 the merge tool used for the given files. It overrides the HGMERGE
4224 the merge tool used for the given files. It overrides the HGMERGE
4225 environment variable and your configuration files.
4225 environment variable and your configuration files.
4226
4226
4227 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4227 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4228 (e.g. after having manually fixed-up the files). The default is
4228 (e.g. after having manually fixed-up the files). The default is
4229 to mark all unresolved files.
4229 to mark all unresolved files.
4230
4230
4231 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4231 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4232 default is to mark all resolved files.
4232 default is to mark all resolved files.
4233
4233
4234 - :hg:`resolve -l`: list files which had or still have conflicts.
4234 - :hg:`resolve -l`: list files which had or still have conflicts.
4235 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4235 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4236
4236
4237 Note that Mercurial will not let you commit files with unresolved
4237 Note that Mercurial will not let you commit files with unresolved
4238 merge conflicts. You must use :hg:`resolve -m ...` before you can
4238 merge conflicts. You must use :hg:`resolve -m ...` before you can
4239 commit after a conflicting merge.
4239 commit after a conflicting merge.
4240
4240
4241 Returns 0 on success, 1 if any files fail a resolve attempt.
4241 Returns 0 on success, 1 if any files fail a resolve attempt.
4242 """
4242 """
4243
4243
4244 all, mark, unmark, show, nostatus = \
4244 all, mark, unmark, show, nostatus = \
4245 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4245 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4246
4246
4247 if (show and (mark or unmark)) or (mark and unmark):
4247 if (show and (mark or unmark)) or (mark and unmark):
4248 raise util.Abort(_("too many options specified"))
4248 raise util.Abort(_("too many options specified"))
4249 if pats and all:
4249 if pats and all:
4250 raise util.Abort(_("can't specify --all and patterns"))
4250 raise util.Abort(_("can't specify --all and patterns"))
4251 if not (all or pats or show or mark or unmark):
4251 if not (all or pats or show or mark or unmark):
4252 raise util.Abort(_('no files or directories specified; '
4252 raise util.Abort(_('no files or directories specified; '
4253 'use --all to remerge all files'))
4253 'use --all to remerge all files'))
4254
4254
4255 ms = mergemod.mergestate(repo)
4255 ms = mergemod.mergestate(repo)
4256 m = scmutil.match(repo[None], pats, opts)
4256 m = scmutil.match(repo[None], pats, opts)
4257 ret = 0
4257 ret = 0
4258
4258
4259 for f in ms:
4259 for f in ms:
4260 if m(f):
4260 if m(f):
4261 if show:
4261 if show:
4262 if nostatus:
4262 if nostatus:
4263 ui.write("%s\n" % f)
4263 ui.write("%s\n" % f)
4264 else:
4264 else:
4265 ui.write("%s %s\n" % (ms[f].upper(), f),
4265 ui.write("%s %s\n" % (ms[f].upper(), f),
4266 label='resolve.' +
4266 label='resolve.' +
4267 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4267 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4268 elif mark:
4268 elif mark:
4269 ms.mark(f, "r")
4269 ms.mark(f, "r")
4270 elif unmark:
4270 elif unmark:
4271 ms.mark(f, "u")
4271 ms.mark(f, "u")
4272 else:
4272 else:
4273 wctx = repo[None]
4273 wctx = repo[None]
4274 mctx = wctx.parents()[-1]
4274 mctx = wctx.parents()[-1]
4275
4275
4276 # backup pre-resolve (merge uses .orig for its own purposes)
4276 # backup pre-resolve (merge uses .orig for its own purposes)
4277 a = repo.wjoin(f)
4277 a = repo.wjoin(f)
4278 util.copyfile(a, a + ".resolve")
4278 util.copyfile(a, a + ".resolve")
4279
4279
4280 try:
4280 try:
4281 # resolve file
4281 # resolve file
4282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4283 if ms.resolve(f, wctx, mctx):
4283 if ms.resolve(f, wctx, mctx):
4284 ret = 1
4284 ret = 1
4285 finally:
4285 finally:
4286 ui.setconfig('ui', 'forcemerge', '')
4286 ui.setconfig('ui', 'forcemerge', '')
4287
4287
4288 # replace filemerge's .orig file with our resolve file
4288 # replace filemerge's .orig file with our resolve file
4289 util.rename(a + ".resolve", a + ".orig")
4289 util.rename(a + ".resolve", a + ".orig")
4290
4290
4291 ms.commit()
4291 ms.commit()
4292 return ret
4292 return ret
4293
4293
4294 @command('revert',
4294 @command('revert',
4295 [('a', 'all', None, _('revert all changes when no arguments given')),
4295 [('a', 'all', None, _('revert all changes when no arguments given')),
4296 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4296 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4297 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4297 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4298 ('C', 'no-backup', None, _('do not save backup copies of files')),
4298 ('C', 'no-backup', None, _('do not save backup copies of files')),
4299 ] + walkopts + dryrunopts,
4299 ] + walkopts + dryrunopts,
4300 _('[OPTION]... [-r REV] [NAME]...'))
4300 _('[OPTION]... [-r REV] [NAME]...'))
4301 def revert(ui, repo, *pats, **opts):
4301 def revert(ui, repo, *pats, **opts):
4302 """restore files to their checkout state
4302 """restore files to their checkout state
4303
4303
4304 .. note::
4304 .. note::
4305 To check out earlier revisions, you should use :hg:`update REV`.
4305 To check out earlier revisions, you should use :hg:`update REV`.
4306 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4306 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4307
4307
4308 With no revision specified, revert the specified files or directories
4308 With no revision specified, revert the specified files or directories
4309 to the contents they had in the parent of the working directory.
4309 to the contents they had in the parent of the working directory.
4310 This restores the contents of files to an unmodified
4310 This restores the contents of files to an unmodified
4311 state and unschedules adds, removes, copies, and renames. If the
4311 state and unschedules adds, removes, copies, and renames. If the
4312 working directory has two parents, you must explicitly specify a
4312 working directory has two parents, you must explicitly specify a
4313 revision.
4313 revision.
4314
4314
4315 Using the -r/--rev or -d/--date options, revert the given files or
4315 Using the -r/--rev or -d/--date options, revert the given files or
4316 directories to their states as of a specific revision. Because
4316 directories to their states as of a specific revision. Because
4317 revert does not change the working directory parents, this will
4317 revert does not change the working directory parents, this will
4318 cause these files to appear modified. This can be helpful to "back
4318 cause these files to appear modified. This can be helpful to "back
4319 out" some or all of an earlier change. See :hg:`backout` for a
4319 out" some or all of an earlier change. See :hg:`backout` for a
4320 related method.
4320 related method.
4321
4321
4322 Modified files are saved with a .orig suffix before reverting.
4322 Modified files are saved with a .orig suffix before reverting.
4323 To disable these backups, use --no-backup.
4323 To disable these backups, use --no-backup.
4324
4324
4325 See :hg:`help dates` for a list of formats valid for -d/--date.
4325 See :hg:`help dates` for a list of formats valid for -d/--date.
4326
4326
4327 Returns 0 on success.
4327 Returns 0 on success.
4328 """
4328 """
4329
4329
4330 if opts.get("date"):
4330 if opts.get("date"):
4331 if opts.get("rev"):
4331 if opts.get("rev"):
4332 raise util.Abort(_("you can't specify a revision and a date"))
4332 raise util.Abort(_("you can't specify a revision and a date"))
4333 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4333 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4334
4334
4335 parent, p2 = repo.dirstate.parents()
4335 parent, p2 = repo.dirstate.parents()
4336 if not opts.get('rev') and p2 != nullid:
4336 if not opts.get('rev') and p2 != nullid:
4337 # revert after merge is a trap for new users (issue2915)
4337 # revert after merge is a trap for new users (issue2915)
4338 raise util.Abort(_('uncommitted merge with no revision specified'),
4338 raise util.Abort(_('uncommitted merge with no revision specified'),
4339 hint=_('use "hg update" or see "hg help revert"'))
4339 hint=_('use "hg update" or see "hg help revert"'))
4340
4340
4341 ctx = scmutil.revsingle(repo, opts.get('rev'))
4341 ctx = scmutil.revsingle(repo, opts.get('rev'))
4342 node = ctx.node()
4342 node = ctx.node()
4343
4343
4344 if not pats and not opts.get('all'):
4344 if not pats and not opts.get('all'):
4345 msg = _("no files or directories specified")
4345 msg = _("no files or directories specified")
4346 if p2 != nullid:
4346 if p2 != nullid:
4347 hint = _("uncommitted merge, use --all to discard all changes,"
4347 hint = _("uncommitted merge, use --all to discard all changes,"
4348 " or 'hg update -C .' to abort the merge")
4348 " or 'hg update -C .' to abort the merge")
4349 raise util.Abort(msg, hint=hint)
4349 raise util.Abort(msg, hint=hint)
4350 dirty = util.any(repo.status())
4350 dirty = util.any(repo.status())
4351 if node != parent:
4351 if node != parent:
4352 if dirty:
4352 if dirty:
4353 hint = _("uncommitted changes, use --all to discard all"
4353 hint = _("uncommitted changes, use --all to discard all"
4354 " changes, or 'hg update %s' to update") % ctx.rev()
4354 " changes, or 'hg update %s' to update") % ctx.rev()
4355 else:
4355 else:
4356 hint = _("use --all to revert all files,"
4356 hint = _("use --all to revert all files,"
4357 " or 'hg update %s' to update") % ctx.rev()
4357 " or 'hg update %s' to update") % ctx.rev()
4358 elif dirty:
4358 elif dirty:
4359 hint = _("uncommitted changes, use --all to discard all changes")
4359 hint = _("uncommitted changes, use --all to discard all changes")
4360 else:
4360 else:
4361 hint = _("use --all to revert all files")
4361 hint = _("use --all to revert all files")
4362 raise util.Abort(msg, hint=hint)
4362 raise util.Abort(msg, hint=hint)
4363
4363
4364 mf = ctx.manifest()
4364 mf = ctx.manifest()
4365 if node == parent:
4365 if node == parent:
4366 pmf = mf
4366 pmf = mf
4367 else:
4367 else:
4368 pmf = None
4368 pmf = None
4369
4369
4370 # need all matching names in dirstate and manifest of target rev,
4370 # need all matching names in dirstate and manifest of target rev,
4371 # so have to walk both. do not print errors if files exist in one
4371 # so have to walk both. do not print errors if files exist in one
4372 # but not other.
4372 # but not other.
4373
4373
4374 names = {}
4374 names = {}
4375
4375
4376 wlock = repo.wlock()
4376 wlock = repo.wlock()
4377 try:
4377 try:
4378 # walk dirstate.
4378 # walk dirstate.
4379
4379
4380 m = scmutil.match(repo[None], pats, opts)
4380 m = scmutil.match(repo[None], pats, opts)
4381 m.bad = lambda x, y: False
4381 m.bad = lambda x, y: False
4382 for abs in repo.walk(m):
4382 for abs in repo.walk(m):
4383 names[abs] = m.rel(abs), m.exact(abs)
4383 names[abs] = m.rel(abs), m.exact(abs)
4384
4384
4385 # walk target manifest.
4385 # walk target manifest.
4386
4386
4387 def badfn(path, msg):
4387 def badfn(path, msg):
4388 if path in names:
4388 if path in names:
4389 return
4389 return
4390 path_ = path + '/'
4390 path_ = path + '/'
4391 for f in names:
4391 for f in names:
4392 if f.startswith(path_):
4392 if f.startswith(path_):
4393 return
4393 return
4394 ui.warn("%s: %s\n" % (m.rel(path), msg))
4394 ui.warn("%s: %s\n" % (m.rel(path), msg))
4395
4395
4396 m = scmutil.match(repo[node], pats, opts)
4396 m = scmutil.match(repo[node], pats, opts)
4397 m.bad = badfn
4397 m.bad = badfn
4398 for abs in repo[node].walk(m):
4398 for abs in repo[node].walk(m):
4399 if abs not in names:
4399 if abs not in names:
4400 names[abs] = m.rel(abs), m.exact(abs)
4400 names[abs] = m.rel(abs), m.exact(abs)
4401
4401
4402 m = scmutil.matchfiles(repo, names)
4402 m = scmutil.matchfiles(repo, names)
4403 changes = repo.status(match=m)[:4]
4403 changes = repo.status(match=m)[:4]
4404 modified, added, removed, deleted = map(set, changes)
4404 modified, added, removed, deleted = map(set, changes)
4405
4405
4406 # if f is a rename, also revert the source
4406 # if f is a rename, also revert the source
4407 cwd = repo.getcwd()
4407 cwd = repo.getcwd()
4408 for f in added:
4408 for f in added:
4409 src = repo.dirstate.copied(f)
4409 src = repo.dirstate.copied(f)
4410 if src and src not in names and repo.dirstate[src] == 'r':
4410 if src and src not in names and repo.dirstate[src] == 'r':
4411 removed.add(src)
4411 removed.add(src)
4412 names[src] = (repo.pathto(src, cwd), True)
4412 names[src] = (repo.pathto(src, cwd), True)
4413
4413
4414 def removeforget(abs):
4414 def removeforget(abs):
4415 if repo.dirstate[abs] == 'a':
4415 if repo.dirstate[abs] == 'a':
4416 return _('forgetting %s\n')
4416 return _('forgetting %s\n')
4417 return _('removing %s\n')
4417 return _('removing %s\n')
4418
4418
4419 revert = ([], _('reverting %s\n'))
4419 revert = ([], _('reverting %s\n'))
4420 add = ([], _('adding %s\n'))
4420 add = ([], _('adding %s\n'))
4421 remove = ([], removeforget)
4421 remove = ([], removeforget)
4422 undelete = ([], _('undeleting %s\n'))
4422 undelete = ([], _('undeleting %s\n'))
4423
4423
4424 disptable = (
4424 disptable = (
4425 # dispatch table:
4425 # dispatch table:
4426 # file state
4426 # file state
4427 # action if in target manifest
4427 # action if in target manifest
4428 # action if not in target manifest
4428 # action if not in target manifest
4429 # make backup if in target manifest
4429 # make backup if in target manifest
4430 # make backup if not in target manifest
4430 # make backup if not in target manifest
4431 (modified, revert, remove, True, True),
4431 (modified, revert, remove, True, True),
4432 (added, revert, remove, True, False),
4432 (added, revert, remove, True, False),
4433 (removed, undelete, None, False, False),
4433 (removed, undelete, None, False, False),
4434 (deleted, revert, remove, False, False),
4434 (deleted, revert, remove, False, False),
4435 )
4435 )
4436
4436
4437 for abs, (rel, exact) in sorted(names.items()):
4437 for abs, (rel, exact) in sorted(names.items()):
4438 mfentry = mf.get(abs)
4438 mfentry = mf.get(abs)
4439 target = repo.wjoin(abs)
4439 target = repo.wjoin(abs)
4440 def handle(xlist, dobackup):
4440 def handle(xlist, dobackup):
4441 xlist[0].append(abs)
4441 xlist[0].append(abs)
4442 if (dobackup and not opts.get('no_backup') and
4442 if (dobackup and not opts.get('no_backup') and
4443 os.path.lexists(target)):
4443 os.path.lexists(target)):
4444 bakname = "%s.orig" % rel
4444 bakname = "%s.orig" % rel
4445 ui.note(_('saving current version of %s as %s\n') %
4445 ui.note(_('saving current version of %s as %s\n') %
4446 (rel, bakname))
4446 (rel, bakname))
4447 if not opts.get('dry_run'):
4447 if not opts.get('dry_run'):
4448 util.rename(target, bakname)
4448 util.rename(target, bakname)
4449 if ui.verbose or not exact:
4449 if ui.verbose or not exact:
4450 msg = xlist[1]
4450 msg = xlist[1]
4451 if not isinstance(msg, basestring):
4451 if not isinstance(msg, basestring):
4452 msg = msg(abs)
4452 msg = msg(abs)
4453 ui.status(msg % rel)
4453 ui.status(msg % rel)
4454 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4454 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4455 if abs not in table:
4455 if abs not in table:
4456 continue
4456 continue
4457 # file has changed in dirstate
4457 # file has changed in dirstate
4458 if mfentry:
4458 if mfentry:
4459 handle(hitlist, backuphit)
4459 handle(hitlist, backuphit)
4460 elif misslist is not None:
4460 elif misslist is not None:
4461 handle(misslist, backupmiss)
4461 handle(misslist, backupmiss)
4462 break
4462 break
4463 else:
4463 else:
4464 if abs not in repo.dirstate:
4464 if abs not in repo.dirstate:
4465 if mfentry:
4465 if mfentry:
4466 handle(add, True)
4466 handle(add, True)
4467 elif exact:
4467 elif exact:
4468 ui.warn(_('file not managed: %s\n') % rel)
4468 ui.warn(_('file not managed: %s\n') % rel)
4469 continue
4469 continue
4470 # file has not changed in dirstate
4470 # file has not changed in dirstate
4471 if node == parent:
4471 if node == parent:
4472 if exact:
4472 if exact:
4473 ui.warn(_('no changes needed to %s\n') % rel)
4473 ui.warn(_('no changes needed to %s\n') % rel)
4474 continue
4474 continue
4475 if pmf is None:
4475 if pmf is None:
4476 # only need parent manifest in this unlikely case,
4476 # only need parent manifest in this unlikely case,
4477 # so do not read by default
4477 # so do not read by default
4478 pmf = repo[parent].manifest()
4478 pmf = repo[parent].manifest()
4479 if abs in pmf:
4479 if abs in pmf:
4480 if mfentry:
4480 if mfentry:
4481 # if version of file is same in parent and target
4481 # if version of file is same in parent and target
4482 # manifests, do nothing
4482 # manifests, do nothing
4483 if (pmf[abs] != mfentry or
4483 if (pmf[abs] != mfentry or
4484 pmf.flags(abs) != mf.flags(abs)):
4484 pmf.flags(abs) != mf.flags(abs)):
4485 handle(revert, False)
4485 handle(revert, False)
4486 else:
4486 else:
4487 handle(remove, False)
4487 handle(remove, False)
4488
4488
4489 if not opts.get('dry_run'):
4489 if not opts.get('dry_run'):
4490 def checkout(f):
4490 def checkout(f):
4491 fc = ctx[f]
4491 fc = ctx[f]
4492 repo.wwrite(f, fc.data(), fc.flags())
4492 repo.wwrite(f, fc.data(), fc.flags())
4493
4493
4494 audit_path = scmutil.pathauditor(repo.root)
4494 audit_path = scmutil.pathauditor(repo.root)
4495 for f in remove[0]:
4495 for f in remove[0]:
4496 if repo.dirstate[f] == 'a':
4496 if repo.dirstate[f] == 'a':
4497 repo.dirstate.drop(f)
4497 repo.dirstate.drop(f)
4498 continue
4498 continue
4499 audit_path(f)
4499 audit_path(f)
4500 try:
4500 try:
4501 util.unlinkpath(repo.wjoin(f))
4501 util.unlinkpath(repo.wjoin(f))
4502 except OSError:
4502 except OSError:
4503 pass
4503 pass
4504 repo.dirstate.remove(f)
4504 repo.dirstate.remove(f)
4505
4505
4506 normal = None
4506 normal = None
4507 if node == parent:
4507 if node == parent:
4508 # We're reverting to our parent. If possible, we'd like status
4508 # We're reverting to our parent. If possible, we'd like status
4509 # to report the file as clean. We have to use normallookup for
4509 # to report the file as clean. We have to use normallookup for
4510 # merges to avoid losing information about merged/dirty files.
4510 # merges to avoid losing information about merged/dirty files.
4511 if p2 != nullid:
4511 if p2 != nullid:
4512 normal = repo.dirstate.normallookup
4512 normal = repo.dirstate.normallookup
4513 else:
4513 else:
4514 normal = repo.dirstate.normal
4514 normal = repo.dirstate.normal
4515 for f in revert[0]:
4515 for f in revert[0]:
4516 checkout(f)
4516 checkout(f)
4517 if normal:
4517 if normal:
4518 normal(f)
4518 normal(f)
4519
4519
4520 for f in add[0]:
4520 for f in add[0]:
4521 checkout(f)
4521 checkout(f)
4522 repo.dirstate.add(f)
4522 repo.dirstate.add(f)
4523
4523
4524 normal = repo.dirstate.normallookup
4524 normal = repo.dirstate.normallookup
4525 if node == parent and p2 == nullid:
4525 if node == parent and p2 == nullid:
4526 normal = repo.dirstate.normal
4526 normal = repo.dirstate.normal
4527 for f in undelete[0]:
4527 for f in undelete[0]:
4528 checkout(f)
4528 checkout(f)
4529 normal(f)
4529 normal(f)
4530
4530
4531 finally:
4531 finally:
4532 wlock.release()
4532 wlock.release()
4533
4533
4534 @command('rollback', dryrunopts)
4534 @command('rollback', dryrunopts)
4535 def rollback(ui, repo, **opts):
4535 def rollback(ui, repo, **opts):
4536 """roll back the last transaction (dangerous)
4536 """roll back the last transaction (dangerous)
4537
4537
4538 This command should be used with care. There is only one level of
4538 This command should be used with care. There is only one level of
4539 rollback, and there is no way to undo a rollback. It will also
4539 rollback, and there is no way to undo a rollback. It will also
4540 restore the dirstate at the time of the last transaction, losing
4540 restore the dirstate at the time of the last transaction, losing
4541 any dirstate changes since that time. This command does not alter
4541 any dirstate changes since that time. This command does not alter
4542 the working directory.
4542 the working directory.
4543
4543
4544 Transactions are used to encapsulate the effects of all commands
4544 Transactions are used to encapsulate the effects of all commands
4545 that create new changesets or propagate existing changesets into a
4545 that create new changesets or propagate existing changesets into a
4546 repository. For example, the following commands are transactional,
4546 repository. For example, the following commands are transactional,
4547 and their effects can be rolled back:
4547 and their effects can be rolled back:
4548
4548
4549 - commit
4549 - commit
4550 - import
4550 - import
4551 - pull
4551 - pull
4552 - push (with this repository as the destination)
4552 - push (with this repository as the destination)
4553 - unbundle
4553 - unbundle
4554
4554
4555 This command is not intended for use on public repositories. Once
4555 This command is not intended for use on public repositories. Once
4556 changes are visible for pull by other users, rolling a transaction
4556 changes are visible for pull by other users, rolling a transaction
4557 back locally is ineffective (someone else may already have pulled
4557 back locally is ineffective (someone else may already have pulled
4558 the changes). Furthermore, a race is possible with readers of the
4558 the changes). Furthermore, a race is possible with readers of the
4559 repository; for example an in-progress pull from the repository
4559 repository; for example an in-progress pull from the repository
4560 may fail if a rollback is performed.
4560 may fail if a rollback is performed.
4561
4561
4562 Returns 0 on success, 1 if no rollback data is available.
4562 Returns 0 on success, 1 if no rollback data is available.
4563 """
4563 """
4564 return repo.rollback(opts.get('dry_run'))
4564 return repo.rollback(opts.get('dry_run'))
4565
4565
4566 @command('root', [])
4566 @command('root', [])
4567 def root(ui, repo):
4567 def root(ui, repo):
4568 """print the root (top) of the current working directory
4568 """print the root (top) of the current working directory
4569
4569
4570 Print the root directory of the current repository.
4570 Print the root directory of the current repository.
4571
4571
4572 Returns 0 on success.
4572 Returns 0 on success.
4573 """
4573 """
4574 ui.write(repo.root + "\n")
4574 ui.write(repo.root + "\n")
4575
4575
4576 @command('^serve',
4576 @command('^serve',
4577 [('A', 'accesslog', '', _('name of access log file to write to'),
4577 [('A', 'accesslog', '', _('name of access log file to write to'),
4578 _('FILE')),
4578 _('FILE')),
4579 ('d', 'daemon', None, _('run server in background')),
4579 ('d', 'daemon', None, _('run server in background')),
4580 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4580 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4581 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4581 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4582 # use string type, then we can check if something was passed
4582 # use string type, then we can check if something was passed
4583 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4583 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4584 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4584 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4585 _('ADDR')),
4585 _('ADDR')),
4586 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4586 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4587 _('PREFIX')),
4587 _('PREFIX')),
4588 ('n', 'name', '',
4588 ('n', 'name', '',
4589 _('name to show in web pages (default: working directory)'), _('NAME')),
4589 _('name to show in web pages (default: working directory)'), _('NAME')),
4590 ('', 'web-conf', '',
4590 ('', 'web-conf', '',
4591 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4591 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4592 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4592 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4593 _('FILE')),
4593 _('FILE')),
4594 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4594 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4595 ('', 'stdio', None, _('for remote clients')),
4595 ('', 'stdio', None, _('for remote clients')),
4596 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4596 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4597 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4597 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4598 ('', 'style', '', _('template style to use'), _('STYLE')),
4598 ('', 'style', '', _('template style to use'), _('STYLE')),
4599 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4599 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4600 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4600 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4601 _('[OPTION]...'))
4601 _('[OPTION]...'))
4602 def serve(ui, repo, **opts):
4602 def serve(ui, repo, **opts):
4603 """start stand-alone webserver
4603 """start stand-alone webserver
4604
4604
4605 Start a local HTTP repository browser and pull server. You can use
4605 Start a local HTTP repository browser and pull server. You can use
4606 this for ad-hoc sharing and browsing of repositories. It is
4606 this for ad-hoc sharing and browsing of repositories. It is
4607 recommended to use a real web server to serve a repository for
4607 recommended to use a real web server to serve a repository for
4608 longer periods of time.
4608 longer periods of time.
4609
4609
4610 Please note that the server does not implement access control.
4610 Please note that the server does not implement access control.
4611 This means that, by default, anybody can read from the server and
4611 This means that, by default, anybody can read from the server and
4612 nobody can write to it by default. Set the ``web.allow_push``
4612 nobody can write to it by default. Set the ``web.allow_push``
4613 option to ``*`` to allow everybody to push to the server. You
4613 option to ``*`` to allow everybody to push to the server. You
4614 should use a real web server if you need to authenticate users.
4614 should use a real web server if you need to authenticate users.
4615
4615
4616 By default, the server logs accesses to stdout and errors to
4616 By default, the server logs accesses to stdout and errors to
4617 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4617 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4618 files.
4618 files.
4619
4619
4620 To have the server choose a free port number to listen on, specify
4620 To have the server choose a free port number to listen on, specify
4621 a port number of 0; in this case, the server will print the port
4621 a port number of 0; in this case, the server will print the port
4622 number it uses.
4622 number it uses.
4623
4623
4624 Returns 0 on success.
4624 Returns 0 on success.
4625 """
4625 """
4626
4626
4627 if opts["stdio"] and opts["cmdserver"]:
4627 if opts["stdio"] and opts["cmdserver"]:
4628 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4628 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4629
4629
4630 def checkrepo():
4630 def checkrepo():
4631 if repo is None:
4631 if repo is None:
4632 raise error.RepoError(_("There is no Mercurial repository here"
4632 raise error.RepoError(_("There is no Mercurial repository here"
4633 " (.hg not found)"))
4633 " (.hg not found)"))
4634
4634
4635 if opts["stdio"]:
4635 if opts["stdio"]:
4636 checkrepo()
4636 checkrepo()
4637 s = sshserver.sshserver(ui, repo)
4637 s = sshserver.sshserver(ui, repo)
4638 s.serve_forever()
4638 s.serve_forever()
4639
4639
4640 if opts["cmdserver"]:
4640 if opts["cmdserver"]:
4641 checkrepo()
4641 checkrepo()
4642 s = commandserver.server(ui, repo, opts["cmdserver"])
4642 s = commandserver.server(ui, repo, opts["cmdserver"])
4643 return s.serve()
4643 return s.serve()
4644
4644
4645 # this way we can check if something was given in the command-line
4645 # this way we can check if something was given in the command-line
4646 if opts.get('port'):
4646 if opts.get('port'):
4647 opts['port'] = util.getport(opts.get('port'))
4647 opts['port'] = util.getport(opts.get('port'))
4648
4648
4649 baseui = repo and repo.baseui or ui
4649 baseui = repo and repo.baseui or ui
4650 optlist = ("name templates style address port prefix ipv6"
4650 optlist = ("name templates style address port prefix ipv6"
4651 " accesslog errorlog certificate encoding")
4651 " accesslog errorlog certificate encoding")
4652 for o in optlist.split():
4652 for o in optlist.split():
4653 val = opts.get(o, '')
4653 val = opts.get(o, '')
4654 if val in (None, ''): # should check against default options instead
4654 if val in (None, ''): # should check against default options instead
4655 continue
4655 continue
4656 baseui.setconfig("web", o, val)
4656 baseui.setconfig("web", o, val)
4657 if repo and repo.ui != baseui:
4657 if repo and repo.ui != baseui:
4658 repo.ui.setconfig("web", o, val)
4658 repo.ui.setconfig("web", o, val)
4659
4659
4660 o = opts.get('web_conf') or opts.get('webdir_conf')
4660 o = opts.get('web_conf') or opts.get('webdir_conf')
4661 if not o:
4661 if not o:
4662 if not repo:
4662 if not repo:
4663 raise error.RepoError(_("There is no Mercurial repository"
4663 raise error.RepoError(_("There is no Mercurial repository"
4664 " here (.hg not found)"))
4664 " here (.hg not found)"))
4665 o = repo.root
4665 o = repo.root
4666
4666
4667 app = hgweb.hgweb(o, baseui=ui)
4667 app = hgweb.hgweb(o, baseui=ui)
4668
4668
4669 class service(object):
4669 class service(object):
4670 def init(self):
4670 def init(self):
4671 util.setsignalhandler()
4671 util.setsignalhandler()
4672 self.httpd = hgweb.server.create_server(ui, app)
4672 self.httpd = hgweb.server.create_server(ui, app)
4673
4673
4674 if opts['port'] and not ui.verbose:
4674 if opts['port'] and not ui.verbose:
4675 return
4675 return
4676
4676
4677 if self.httpd.prefix:
4677 if self.httpd.prefix:
4678 prefix = self.httpd.prefix.strip('/') + '/'
4678 prefix = self.httpd.prefix.strip('/') + '/'
4679 else:
4679 else:
4680 prefix = ''
4680 prefix = ''
4681
4681
4682 port = ':%d' % self.httpd.port
4682 port = ':%d' % self.httpd.port
4683 if port == ':80':
4683 if port == ':80':
4684 port = ''
4684 port = ''
4685
4685
4686 bindaddr = self.httpd.addr
4686 bindaddr = self.httpd.addr
4687 if bindaddr == '0.0.0.0':
4687 if bindaddr == '0.0.0.0':
4688 bindaddr = '*'
4688 bindaddr = '*'
4689 elif ':' in bindaddr: # IPv6
4689 elif ':' in bindaddr: # IPv6
4690 bindaddr = '[%s]' % bindaddr
4690 bindaddr = '[%s]' % bindaddr
4691
4691
4692 fqaddr = self.httpd.fqaddr
4692 fqaddr = self.httpd.fqaddr
4693 if ':' in fqaddr:
4693 if ':' in fqaddr:
4694 fqaddr = '[%s]' % fqaddr
4694 fqaddr = '[%s]' % fqaddr
4695 if opts['port']:
4695 if opts['port']:
4696 write = ui.status
4696 write = ui.status
4697 else:
4697 else:
4698 write = ui.write
4698 write = ui.write
4699 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4699 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4700 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4700 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4701
4701
4702 def run(self):
4702 def run(self):
4703 self.httpd.serve_forever()
4703 self.httpd.serve_forever()
4704
4704
4705 service = service()
4705 service = service()
4706
4706
4707 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4707 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4708
4708
4709 @command('showconfig|debugconfig',
4709 @command('showconfig|debugconfig',
4710 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4710 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4711 _('[-u] [NAME]...'))
4711 _('[-u] [NAME]...'))
4712 def showconfig(ui, repo, *values, **opts):
4712 def showconfig(ui, repo, *values, **opts):
4713 """show combined config settings from all hgrc files
4713 """show combined config settings from all hgrc files
4714
4714
4715 With no arguments, print names and values of all config items.
4715 With no arguments, print names and values of all config items.
4716
4716
4717 With one argument of the form section.name, print just the value
4717 With one argument of the form section.name, print just the value
4718 of that config item.
4718 of that config item.
4719
4719
4720 With multiple arguments, print names and values of all config
4720 With multiple arguments, print names and values of all config
4721 items with matching section names.
4721 items with matching section names.
4722
4722
4723 With --debug, the source (filename and line number) is printed
4723 With --debug, the source (filename and line number) is printed
4724 for each config item.
4724 for each config item.
4725
4725
4726 Returns 0 on success.
4726 Returns 0 on success.
4727 """
4727 """
4728
4728
4729 for f in scmutil.rcpath():
4729 for f in scmutil.rcpath():
4730 ui.debug('read config from: %s\n' % f)
4730 ui.debug('read config from: %s\n' % f)
4731 untrusted = bool(opts.get('untrusted'))
4731 untrusted = bool(opts.get('untrusted'))
4732 if values:
4732 if values:
4733 sections = [v for v in values if '.' not in v]
4733 sections = [v for v in values if '.' not in v]
4734 items = [v for v in values if '.' in v]
4734 items = [v for v in values if '.' in v]
4735 if len(items) > 1 or items and sections:
4735 if len(items) > 1 or items and sections:
4736 raise util.Abort(_('only one config item permitted'))
4736 raise util.Abort(_('only one config item permitted'))
4737 for section, name, value in ui.walkconfig(untrusted=untrusted):
4737 for section, name, value in ui.walkconfig(untrusted=untrusted):
4738 value = str(value).replace('\n', '\\n')
4738 value = str(value).replace('\n', '\\n')
4739 sectname = section + '.' + name
4739 sectname = section + '.' + name
4740 if values:
4740 if values:
4741 for v in values:
4741 for v in values:
4742 if v == section:
4742 if v == section:
4743 ui.debug('%s: ' %
4743 ui.debug('%s: ' %
4744 ui.configsource(section, name, untrusted))
4744 ui.configsource(section, name, untrusted))
4745 ui.write('%s=%s\n' % (sectname, value))
4745 ui.write('%s=%s\n' % (sectname, value))
4746 elif v == sectname:
4746 elif v == sectname:
4747 ui.debug('%s: ' %
4747 ui.debug('%s: ' %
4748 ui.configsource(section, name, untrusted))
4748 ui.configsource(section, name, untrusted))
4749 ui.write(value, '\n')
4749 ui.write(value, '\n')
4750 else:
4750 else:
4751 ui.debug('%s: ' %
4751 ui.debug('%s: ' %
4752 ui.configsource(section, name, untrusted))
4752 ui.configsource(section, name, untrusted))
4753 ui.write('%s=%s\n' % (sectname, value))
4753 ui.write('%s=%s\n' % (sectname, value))
4754
4754
4755 @command('^status|st',
4755 @command('^status|st',
4756 [('A', 'all', None, _('show status of all files')),
4756 [('A', 'all', None, _('show status of all files')),
4757 ('m', 'modified', None, _('show only modified files')),
4757 ('m', 'modified', None, _('show only modified files')),
4758 ('a', 'added', None, _('show only added files')),
4758 ('a', 'added', None, _('show only added files')),
4759 ('r', 'removed', None, _('show only removed files')),
4759 ('r', 'removed', None, _('show only removed files')),
4760 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4760 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4761 ('c', 'clean', None, _('show only files without changes')),
4761 ('c', 'clean', None, _('show only files without changes')),
4762 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4762 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4763 ('i', 'ignored', None, _('show only ignored files')),
4763 ('i', 'ignored', None, _('show only ignored files')),
4764 ('n', 'no-status', None, _('hide status prefix')),
4764 ('n', 'no-status', None, _('hide status prefix')),
4765 ('C', 'copies', None, _('show source of copied files')),
4765 ('C', 'copies', None, _('show source of copied files')),
4766 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4766 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4767 ('', 'rev', [], _('show difference from revision'), _('REV')),
4767 ('', 'rev', [], _('show difference from revision'), _('REV')),
4768 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4768 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4769 ] + walkopts + subrepoopts,
4769 ] + walkopts + subrepoopts,
4770 _('[OPTION]... [FILE]...'))
4770 _('[OPTION]... [FILE]...'))
4771 def status(ui, repo, *pats, **opts):
4771 def status(ui, repo, *pats, **opts):
4772 """show changed files in the working directory
4772 """show changed files in the working directory
4773
4773
4774 Show status of files in the repository. If names are given, only
4774 Show status of files in the repository. If names are given, only
4775 files that match are shown. Files that are clean or ignored or
4775 files that match are shown. Files that are clean or ignored or
4776 the source of a copy/move operation, are not listed unless
4776 the source of a copy/move operation, are not listed unless
4777 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4777 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4778 Unless options described with "show only ..." are given, the
4778 Unless options described with "show only ..." are given, the
4779 options -mardu are used.
4779 options -mardu are used.
4780
4780
4781 Option -q/--quiet hides untracked (unknown and ignored) files
4781 Option -q/--quiet hides untracked (unknown and ignored) files
4782 unless explicitly requested with -u/--unknown or -i/--ignored.
4782 unless explicitly requested with -u/--unknown or -i/--ignored.
4783
4783
4784 .. note::
4784 .. note::
4785 status may appear to disagree with diff if permissions have
4785 status may appear to disagree with diff if permissions have
4786 changed or a merge has occurred. The standard diff format does
4786 changed or a merge has occurred. The standard diff format does
4787 not report permission changes and diff only reports changes
4787 not report permission changes and diff only reports changes
4788 relative to one merge parent.
4788 relative to one merge parent.
4789
4789
4790 If one revision is given, it is used as the base revision.
4790 If one revision is given, it is used as the base revision.
4791 If two revisions are given, the differences between them are
4791 If two revisions are given, the differences between them are
4792 shown. The --change option can also be used as a shortcut to list
4792 shown. The --change option can also be used as a shortcut to list
4793 the changed files of a revision from its first parent.
4793 the changed files of a revision from its first parent.
4794
4794
4795 The codes used to show the status of files are::
4795 The codes used to show the status of files are::
4796
4796
4797 M = modified
4797 M = modified
4798 A = added
4798 A = added
4799 R = removed
4799 R = removed
4800 C = clean
4800 C = clean
4801 ! = missing (deleted by non-hg command, but still tracked)
4801 ! = missing (deleted by non-hg command, but still tracked)
4802 ? = not tracked
4802 ? = not tracked
4803 I = ignored
4803 I = ignored
4804 = origin of the previous file listed as A (added)
4804 = origin of the previous file listed as A (added)
4805
4805
4806 Returns 0 on success.
4806 Returns 0 on success.
4807 """
4807 """
4808
4808
4809 revs = opts.get('rev')
4809 revs = opts.get('rev')
4810 change = opts.get('change')
4810 change = opts.get('change')
4811
4811
4812 if revs and change:
4812 if revs and change:
4813 msg = _('cannot specify --rev and --change at the same time')
4813 msg = _('cannot specify --rev and --change at the same time')
4814 raise util.Abort(msg)
4814 raise util.Abort(msg)
4815 elif change:
4815 elif change:
4816 node2 = repo.lookup(change)
4816 node2 = repo.lookup(change)
4817 node1 = repo[node2].p1().node()
4817 node1 = repo[node2].p1().node()
4818 else:
4818 else:
4819 node1, node2 = scmutil.revpair(repo, revs)
4819 node1, node2 = scmutil.revpair(repo, revs)
4820
4820
4821 cwd = (pats and repo.getcwd()) or ''
4821 cwd = (pats and repo.getcwd()) or ''
4822 end = opts.get('print0') and '\0' or '\n'
4822 end = opts.get('print0') and '\0' or '\n'
4823 copy = {}
4823 copy = {}
4824 states = 'modified added removed deleted unknown ignored clean'.split()
4824 states = 'modified added removed deleted unknown ignored clean'.split()
4825 show = [k for k in states if opts.get(k)]
4825 show = [k for k in states if opts.get(k)]
4826 if opts.get('all'):
4826 if opts.get('all'):
4827 show += ui.quiet and (states[:4] + ['clean']) or states
4827 show += ui.quiet and (states[:4] + ['clean']) or states
4828 if not show:
4828 if not show:
4829 show = ui.quiet and states[:4] or states[:5]
4829 show = ui.quiet and states[:4] or states[:5]
4830
4830
4831 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4831 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4832 'ignored' in show, 'clean' in show, 'unknown' in show,
4832 'ignored' in show, 'clean' in show, 'unknown' in show,
4833 opts.get('subrepos'))
4833 opts.get('subrepos'))
4834 changestates = zip(states, 'MAR!?IC', stat)
4834 changestates = zip(states, 'MAR!?IC', stat)
4835
4835
4836 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4836 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4837 ctxn = repo[nullid]
4837 ctxn = repo[nullid]
4838 ctx1 = repo[node1]
4838 ctx1 = repo[node1]
4839 ctx2 = repo[node2]
4839 ctx2 = repo[node2]
4840 added = stat[1]
4840 added = stat[1]
4841 if node2 is None:
4841 if node2 is None:
4842 added = stat[0] + stat[1] # merged?
4842 added = stat[0] + stat[1] # merged?
4843
4843
4844 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4844 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4845 if k in added:
4845 if k in added:
4846 copy[k] = v
4846 copy[k] = v
4847 elif v in added:
4847 elif v in added:
4848 copy[v] = k
4848 copy[v] = k
4849
4849
4850 for state, char, files in changestates:
4850 for state, char, files in changestates:
4851 if state in show:
4851 if state in show:
4852 format = "%s %%s%s" % (char, end)
4852 format = "%s %%s%s" % (char, end)
4853 if opts.get('no_status'):
4853 if opts.get('no_status'):
4854 format = "%%s%s" % end
4854 format = "%%s%s" % end
4855
4855
4856 for f in files:
4856 for f in files:
4857 ui.write(format % repo.pathto(f, cwd),
4857 ui.write(format % repo.pathto(f, cwd),
4858 label='status.' + state)
4858 label='status.' + state)
4859 if f in copy:
4859 if f in copy:
4860 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4860 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4861 label='status.copied')
4861 label='status.copied')
4862
4862
4863 @command('^summary|sum',
4863 @command('^summary|sum',
4864 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4864 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4865 def summary(ui, repo, **opts):
4865 def summary(ui, repo, **opts):
4866 """summarize working directory state
4866 """summarize working directory state
4867
4867
4868 This generates a brief summary of the working directory state,
4868 This generates a brief summary of the working directory state,
4869 including parents, branch, commit status, and available updates.
4869 including parents, branch, commit status, and available updates.
4870
4870
4871 With the --remote option, this will check the default paths for
4871 With the --remote option, this will check the default paths for
4872 incoming and outgoing changes. This can be time-consuming.
4872 incoming and outgoing changes. This can be time-consuming.
4873
4873
4874 Returns 0 on success.
4874 Returns 0 on success.
4875 """
4875 """
4876
4876
4877 ctx = repo[None]
4877 ctx = repo[None]
4878 parents = ctx.parents()
4878 parents = ctx.parents()
4879 pnode = parents[0].node()
4879 pnode = parents[0].node()
4880 marks = []
4880 marks = []
4881
4881
4882 for p in parents:
4882 for p in parents:
4883 # label with log.changeset (instead of log.parent) since this
4883 # label with log.changeset (instead of log.parent) since this
4884 # shows a working directory parent *changeset*:
4884 # shows a working directory parent *changeset*:
4885 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4885 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4886 label='log.changeset')
4886 label='log.changeset')
4887 ui.write(' '.join(p.tags()), label='log.tag')
4887 ui.write(' '.join(p.tags()), label='log.tag')
4888 if p.bookmarks():
4888 if p.bookmarks():
4889 marks.extend(p.bookmarks())
4889 marks.extend(p.bookmarks())
4890 if p.rev() == -1:
4890 if p.rev() == -1:
4891 if not len(repo):
4891 if not len(repo):
4892 ui.write(_(' (empty repository)'))
4892 ui.write(_(' (empty repository)'))
4893 else:
4893 else:
4894 ui.write(_(' (no revision checked out)'))
4894 ui.write(_(' (no revision checked out)'))
4895 ui.write('\n')
4895 ui.write('\n')
4896 if p.description():
4896 if p.description():
4897 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4897 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4898 label='log.summary')
4898 label='log.summary')
4899
4899
4900 branch = ctx.branch()
4900 branch = ctx.branch()
4901 bheads = repo.branchheads(branch)
4901 bheads = repo.branchheads(branch)
4902 m = _('branch: %s\n') % branch
4902 m = _('branch: %s\n') % branch
4903 if branch != 'default':
4903 if branch != 'default':
4904 ui.write(m, label='log.branch')
4904 ui.write(m, label='log.branch')
4905 else:
4905 else:
4906 ui.status(m, label='log.branch')
4906 ui.status(m, label='log.branch')
4907
4907
4908 if marks:
4908 if marks:
4909 current = repo._bookmarkcurrent
4909 current = repo._bookmarkcurrent
4910 ui.write(_('bookmarks:'), label='log.bookmark')
4910 ui.write(_('bookmarks:'), label='log.bookmark')
4911 if current is not None:
4911 if current is not None:
4912 try:
4912 try:
4913 marks.remove(current)
4913 marks.remove(current)
4914 ui.write(' *' + current, label='bookmarks.current')
4914 ui.write(' *' + current, label='bookmarks.current')
4915 except ValueError:
4915 except ValueError:
4916 # current bookmark not in parent ctx marks
4916 # current bookmark not in parent ctx marks
4917 pass
4917 pass
4918 for m in marks:
4918 for m in marks:
4919 ui.write(' ' + m, label='log.bookmark')
4919 ui.write(' ' + m, label='log.bookmark')
4920 ui.write('\n', label='log.bookmark')
4920 ui.write('\n', label='log.bookmark')
4921
4921
4922 st = list(repo.status(unknown=True))[:6]
4922 st = list(repo.status(unknown=True))[:6]
4923
4923
4924 c = repo.dirstate.copies()
4924 c = repo.dirstate.copies()
4925 copied, renamed = [], []
4925 copied, renamed = [], []
4926 for d, s in c.iteritems():
4926 for d, s in c.iteritems():
4927 if s in st[2]:
4927 if s in st[2]:
4928 st[2].remove(s)
4928 st[2].remove(s)
4929 renamed.append(d)
4929 renamed.append(d)
4930 else:
4930 else:
4931 copied.append(d)
4931 copied.append(d)
4932 if d in st[1]:
4932 if d in st[1]:
4933 st[1].remove(d)
4933 st[1].remove(d)
4934 st.insert(3, renamed)
4934 st.insert(3, renamed)
4935 st.insert(4, copied)
4935 st.insert(4, copied)
4936
4936
4937 ms = mergemod.mergestate(repo)
4937 ms = mergemod.mergestate(repo)
4938 st.append([f for f in ms if ms[f] == 'u'])
4938 st.append([f for f in ms if ms[f] == 'u'])
4939
4939
4940 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4940 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4941 st.append(subs)
4941 st.append(subs)
4942
4942
4943 labels = [ui.label(_('%d modified'), 'status.modified'),
4943 labels = [ui.label(_('%d modified'), 'status.modified'),
4944 ui.label(_('%d added'), 'status.added'),
4944 ui.label(_('%d added'), 'status.added'),
4945 ui.label(_('%d removed'), 'status.removed'),
4945 ui.label(_('%d removed'), 'status.removed'),
4946 ui.label(_('%d renamed'), 'status.copied'),
4946 ui.label(_('%d renamed'), 'status.copied'),
4947 ui.label(_('%d copied'), 'status.copied'),
4947 ui.label(_('%d copied'), 'status.copied'),
4948 ui.label(_('%d deleted'), 'status.deleted'),
4948 ui.label(_('%d deleted'), 'status.deleted'),
4949 ui.label(_('%d unknown'), 'status.unknown'),
4949 ui.label(_('%d unknown'), 'status.unknown'),
4950 ui.label(_('%d ignored'), 'status.ignored'),
4950 ui.label(_('%d ignored'), 'status.ignored'),
4951 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4951 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4952 ui.label(_('%d subrepos'), 'status.modified')]
4952 ui.label(_('%d subrepos'), 'status.modified')]
4953 t = []
4953 t = []
4954 for s, l in zip(st, labels):
4954 for s, l in zip(st, labels):
4955 if s:
4955 if s:
4956 t.append(l % len(s))
4956 t.append(l % len(s))
4957
4957
4958 t = ', '.join(t)
4958 t = ', '.join(t)
4959 cleanworkdir = False
4959 cleanworkdir = False
4960
4960
4961 if len(parents) > 1:
4961 if len(parents) > 1:
4962 t += _(' (merge)')
4962 t += _(' (merge)')
4963 elif branch != parents[0].branch():
4963 elif branch != parents[0].branch():
4964 t += _(' (new branch)')
4964 t += _(' (new branch)')
4965 elif (parents[0].extra().get('close') and
4965 elif (parents[0].extra().get('close') and
4966 pnode in repo.branchheads(branch, closed=True)):
4966 pnode in repo.branchheads(branch, closed=True)):
4967 t += _(' (head closed)')
4967 t += _(' (head closed)')
4968 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4968 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4969 t += _(' (clean)')
4969 t += _(' (clean)')
4970 cleanworkdir = True
4970 cleanworkdir = True
4971 elif pnode not in bheads:
4971 elif pnode not in bheads:
4972 t += _(' (new branch head)')
4972 t += _(' (new branch head)')
4973
4973
4974 if cleanworkdir:
4974 if cleanworkdir:
4975 ui.status(_('commit: %s\n') % t.strip())
4975 ui.status(_('commit: %s\n') % t.strip())
4976 else:
4976 else:
4977 ui.write(_('commit: %s\n') % t.strip())
4977 ui.write(_('commit: %s\n') % t.strip())
4978
4978
4979 # all ancestors of branch heads - all ancestors of parent = new csets
4979 # all ancestors of branch heads - all ancestors of parent = new csets
4980 new = [0] * len(repo)
4980 new = [0] * len(repo)
4981 cl = repo.changelog
4981 cl = repo.changelog
4982 for a in [cl.rev(n) for n in bheads]:
4982 for a in [cl.rev(n) for n in bheads]:
4983 new[a] = 1
4983 new[a] = 1
4984 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4984 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4985 new[a] = 1
4985 new[a] = 1
4986 for a in [p.rev() for p in parents]:
4986 for a in [p.rev() for p in parents]:
4987 if a >= 0:
4987 if a >= 0:
4988 new[a] = 0
4988 new[a] = 0
4989 for a in cl.ancestors(*[p.rev() for p in parents]):
4989 for a in cl.ancestors(*[p.rev() for p in parents]):
4990 new[a] = 0
4990 new[a] = 0
4991 new = sum(new)
4991 new = sum(new)
4992
4992
4993 if new == 0:
4993 if new == 0:
4994 ui.status(_('update: (current)\n'))
4994 ui.status(_('update: (current)\n'))
4995 elif pnode not in bheads:
4995 elif pnode not in bheads:
4996 ui.write(_('update: %d new changesets (update)\n') % new)
4996 ui.write(_('update: %d new changesets (update)\n') % new)
4997 else:
4997 else:
4998 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4998 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4999 (new, len(bheads)))
4999 (new, len(bheads)))
5000
5000
5001 if opts.get('remote'):
5001 if opts.get('remote'):
5002 t = []
5002 t = []
5003 source, branches = hg.parseurl(ui.expandpath('default'))
5003 source, branches = hg.parseurl(ui.expandpath('default'))
5004 other = hg.peer(repo, {}, source)
5004 other = hg.peer(repo, {}, source)
5005 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5005 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5006 ui.debug('comparing with %s\n' % util.hidepassword(source))
5006 ui.debug('comparing with %s\n' % util.hidepassword(source))
5007 repo.ui.pushbuffer()
5007 repo.ui.pushbuffer()
5008 commoninc = discovery.findcommonincoming(repo, other)
5008 commoninc = discovery.findcommonincoming(repo, other)
5009 _common, incoming, _rheads = commoninc
5009 _common, incoming, _rheads = commoninc
5010 repo.ui.popbuffer()
5010 repo.ui.popbuffer()
5011 if incoming:
5011 if incoming:
5012 t.append(_('1 or more incoming'))
5012 t.append(_('1 or more incoming'))
5013
5013
5014 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5014 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5015 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5015 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5016 if source != dest:
5016 if source != dest:
5017 other = hg.peer(repo, {}, dest)
5017 other = hg.peer(repo, {}, dest)
5018 commoninc = None
5018 commoninc = None
5019 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5019 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5020 repo.ui.pushbuffer()
5020 repo.ui.pushbuffer()
5021 common, outheads = discovery.findcommonoutgoing(repo, other,
5021 common, outheads = discovery.findcommonoutgoing(repo, other,
5022 commoninc=commoninc)
5022 commoninc=commoninc)
5023 repo.ui.popbuffer()
5023 repo.ui.popbuffer()
5024 o = repo.changelog.findmissing(common=common, heads=outheads)
5024 o = repo.changelog.findmissing(common=common, heads=outheads)
5025 if o:
5025 if o:
5026 t.append(_('%d outgoing') % len(o))
5026 t.append(_('%d outgoing') % len(o))
5027 if 'bookmarks' in other.listkeys('namespaces'):
5027 if 'bookmarks' in other.listkeys('namespaces'):
5028 lmarks = repo.listkeys('bookmarks')
5028 lmarks = repo.listkeys('bookmarks')
5029 rmarks = other.listkeys('bookmarks')
5029 rmarks = other.listkeys('bookmarks')
5030 diff = set(rmarks) - set(lmarks)
5030 diff = set(rmarks) - set(lmarks)
5031 if len(diff) > 0:
5031 if len(diff) > 0:
5032 t.append(_('%d incoming bookmarks') % len(diff))
5032 t.append(_('%d incoming bookmarks') % len(diff))
5033 diff = set(lmarks) - set(rmarks)
5033 diff = set(lmarks) - set(rmarks)
5034 if len(diff) > 0:
5034 if len(diff) > 0:
5035 t.append(_('%d outgoing bookmarks') % len(diff))
5035 t.append(_('%d outgoing bookmarks') % len(diff))
5036
5036
5037 if t:
5037 if t:
5038 ui.write(_('remote: %s\n') % (', '.join(t)))
5038 ui.write(_('remote: %s\n') % (', '.join(t)))
5039 else:
5039 else:
5040 ui.status(_('remote: (synced)\n'))
5040 ui.status(_('remote: (synced)\n'))
5041
5041
5042 @command('tag',
5042 @command('tag',
5043 [('f', 'force', None, _('force tag')),
5043 [('f', 'force', None, _('force tag')),
5044 ('l', 'local', None, _('make the tag local')),
5044 ('l', 'local', None, _('make the tag local')),
5045 ('r', 'rev', '', _('revision to tag'), _('REV')),
5045 ('r', 'rev', '', _('revision to tag'), _('REV')),
5046 ('', 'remove', None, _('remove a tag')),
5046 ('', 'remove', None, _('remove a tag')),
5047 # -l/--local is already there, commitopts cannot be used
5047 # -l/--local is already there, commitopts cannot be used
5048 ('e', 'edit', None, _('edit commit message')),
5048 ('e', 'edit', None, _('edit commit message')),
5049 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5049 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5050 ] + commitopts2,
5050 ] + commitopts2,
5051 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5051 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5052 def tag(ui, repo, name1, *names, **opts):
5052 def tag(ui, repo, name1, *names, **opts):
5053 """add one or more tags for the current or given revision
5053 """add one or more tags for the current or given revision
5054
5054
5055 Name a particular revision using <name>.
5055 Name a particular revision using <name>.
5056
5056
5057 Tags are used to name particular revisions of the repository and are
5057 Tags are used to name particular revisions of the repository and are
5058 very useful to compare different revisions, to go back to significant
5058 very useful to compare different revisions, to go back to significant
5059 earlier versions or to mark branch points as releases, etc. Changing
5059 earlier versions or to mark branch points as releases, etc. Changing
5060 an existing tag is normally disallowed; use -f/--force to override.
5060 an existing tag is normally disallowed; use -f/--force to override.
5061
5061
5062 If no revision is given, the parent of the working directory is
5062 If no revision is given, the parent of the working directory is
5063 used, or tip if no revision is checked out.
5063 used, or tip if no revision is checked out.
5064
5064
5065 To facilitate version control, distribution, and merging of tags,
5065 To facilitate version control, distribution, and merging of tags,
5066 they are stored as a file named ".hgtags" which is managed similarly
5066 they are stored as a file named ".hgtags" which is managed similarly
5067 to other project files and can be hand-edited if necessary. This
5067 to other project files and can be hand-edited if necessary. This
5068 also means that tagging creates a new commit. The file
5068 also means that tagging creates a new commit. The file
5069 ".hg/localtags" is used for local tags (not shared among
5069 ".hg/localtags" is used for local tags (not shared among
5070 repositories).
5070 repositories).
5071
5071
5072 Tag commits are usually made at the head of a branch. If the parent
5072 Tag commits are usually made at the head of a branch. If the parent
5073 of the working directory is not a branch head, :hg:`tag` aborts; use
5073 of the working directory is not a branch head, :hg:`tag` aborts; use
5074 -f/--force to force the tag commit to be based on a non-head
5074 -f/--force to force the tag commit to be based on a non-head
5075 changeset.
5075 changeset.
5076
5076
5077 See :hg:`help dates` for a list of formats valid for -d/--date.
5077 See :hg:`help dates` for a list of formats valid for -d/--date.
5078
5078
5079 Since tag names have priority over branch names during revision
5079 Since tag names have priority over branch names during revision
5080 lookup, using an existing branch name as a tag name is discouraged.
5080 lookup, using an existing branch name as a tag name is discouraged.
5081
5081
5082 Returns 0 on success.
5082 Returns 0 on success.
5083 """
5083 """
5084
5084
5085 rev_ = "."
5085 rev_ = "."
5086 names = [t.strip() for t in (name1,) + names]
5086 names = [t.strip() for t in (name1,) + names]
5087 if len(names) != len(set(names)):
5087 if len(names) != len(set(names)):
5088 raise util.Abort(_('tag names must be unique'))
5088 raise util.Abort(_('tag names must be unique'))
5089 for n in names:
5089 for n in names:
5090 if n in ['tip', '.', 'null']:
5090 if n in ['tip', '.', 'null']:
5091 raise util.Abort(_("the name '%s' is reserved") % n)
5091 raise util.Abort(_("the name '%s' is reserved") % n)
5092 if not n:
5092 if not n:
5093 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5093 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5094 if opts.get('rev') and opts.get('remove'):
5094 if opts.get('rev') and opts.get('remove'):
5095 raise util.Abort(_("--rev and --remove are incompatible"))
5095 raise util.Abort(_("--rev and --remove are incompatible"))
5096 if opts.get('rev'):
5096 if opts.get('rev'):
5097 rev_ = opts['rev']
5097 rev_ = opts['rev']
5098 message = opts.get('message')
5098 message = opts.get('message')
5099 if opts.get('remove'):
5099 if opts.get('remove'):
5100 expectedtype = opts.get('local') and 'local' or 'global'
5100 expectedtype = opts.get('local') and 'local' or 'global'
5101 for n in names:
5101 for n in names:
5102 if not repo.tagtype(n):
5102 if not repo.tagtype(n):
5103 raise util.Abort(_("tag '%s' does not exist") % n)
5103 raise util.Abort(_("tag '%s' does not exist") % n)
5104 if repo.tagtype(n) != expectedtype:
5104 if repo.tagtype(n) != expectedtype:
5105 if expectedtype == 'global':
5105 if expectedtype == 'global':
5106 raise util.Abort(_("tag '%s' is not a global tag") % n)
5106 raise util.Abort(_("tag '%s' is not a global tag") % n)
5107 else:
5107 else:
5108 raise util.Abort(_("tag '%s' is not a local tag") % n)
5108 raise util.Abort(_("tag '%s' is not a local tag") % n)
5109 rev_ = nullid
5109 rev_ = nullid
5110 if not message:
5110 if not message:
5111 # we don't translate commit messages
5111 # we don't translate commit messages
5112 message = 'Removed tag %s' % ', '.join(names)
5112 message = 'Removed tag %s' % ', '.join(names)
5113 elif not opts.get('force'):
5113 elif not opts.get('force'):
5114 for n in names:
5114 for n in names:
5115 if n in repo.tags():
5115 if n in repo.tags():
5116 raise util.Abort(_("tag '%s' already exists "
5116 raise util.Abort(_("tag '%s' already exists "
5117 "(use -f to force)") % n)
5117 "(use -f to force)") % n)
5118 if not opts.get('local'):
5118 if not opts.get('local'):
5119 p1, p2 = repo.dirstate.parents()
5119 p1, p2 = repo.dirstate.parents()
5120 if p2 != nullid:
5120 if p2 != nullid:
5121 raise util.Abort(_('uncommitted merge'))
5121 raise util.Abort(_('uncommitted merge'))
5122 bheads = repo.branchheads()
5122 bheads = repo.branchheads()
5123 if not opts.get('force') and bheads and p1 not in bheads:
5123 if not opts.get('force') and bheads and p1 not in bheads:
5124 raise util.Abort(_('not at a branch head (use -f to force)'))
5124 raise util.Abort(_('not at a branch head (use -f to force)'))
5125 r = scmutil.revsingle(repo, rev_).node()
5125 r = scmutil.revsingle(repo, rev_).node()
5126
5126
5127 if not message:
5127 if not message:
5128 # we don't translate commit messages
5128 # we don't translate commit messages
5129 message = ('Added tag %s for changeset %s' %
5129 message = ('Added tag %s for changeset %s' %
5130 (', '.join(names), short(r)))
5130 (', '.join(names), short(r)))
5131
5131
5132 date = opts.get('date')
5132 date = opts.get('date')
5133 if date:
5133 if date:
5134 date = util.parsedate(date)
5134 date = util.parsedate(date)
5135
5135
5136 if opts.get('edit'):
5136 if opts.get('edit'):
5137 message = ui.edit(message, ui.username())
5137 message = ui.edit(message, ui.username())
5138
5138
5139 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5139 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5140
5140
5141 @command('tags', [], '')
5141 @command('tags', [], '')
5142 def tags(ui, repo):
5142 def tags(ui, repo):
5143 """list repository tags
5143 """list repository tags
5144
5144
5145 This lists both regular and local tags. When the -v/--verbose
5145 This lists both regular and local tags. When the -v/--verbose
5146 switch is used, a third column "local" is printed for local tags.
5146 switch is used, a third column "local" is printed for local tags.
5147
5147
5148 Returns 0 on success.
5148 Returns 0 on success.
5149 """
5149 """
5150
5150
5151 hexfunc = ui.debugflag and hex or short
5151 hexfunc = ui.debugflag and hex or short
5152 tagtype = ""
5152 tagtype = ""
5153
5153
5154 for t, n in reversed(repo.tagslist()):
5154 for t, n in reversed(repo.tagslist()):
5155 if ui.quiet:
5155 if ui.quiet:
5156 ui.write("%s\n" % t, label='tags.normal')
5156 ui.write("%s\n" % t, label='tags.normal')
5157 continue
5157 continue
5158
5158
5159 hn = hexfunc(n)
5159 hn = hexfunc(n)
5160 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5160 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5161 rev = ui.label(r, 'log.changeset')
5161 rev = ui.label(r, 'log.changeset')
5162 spaces = " " * (30 - encoding.colwidth(t))
5162 spaces = " " * (30 - encoding.colwidth(t))
5163
5163
5164 tag = ui.label(t, 'tags.normal')
5164 tag = ui.label(t, 'tags.normal')
5165 if ui.verbose:
5165 if ui.verbose:
5166 if repo.tagtype(t) == 'local':
5166 if repo.tagtype(t) == 'local':
5167 tagtype = " local"
5167 tagtype = " local"
5168 tag = ui.label(t, 'tags.local')
5168 tag = ui.label(t, 'tags.local')
5169 else:
5169 else:
5170 tagtype = ""
5170 tagtype = ""
5171 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5171 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5172
5172
5173 @command('tip',
5173 @command('tip',
5174 [('p', 'patch', None, _('show patch')),
5174 [('p', 'patch', None, _('show patch')),
5175 ('g', 'git', None, _('use git extended diff format')),
5175 ('g', 'git', None, _('use git extended diff format')),
5176 ] + templateopts,
5176 ] + templateopts,
5177 _('[-p] [-g]'))
5177 _('[-p] [-g]'))
5178 def tip(ui, repo, **opts):
5178 def tip(ui, repo, **opts):
5179 """show the tip revision
5179 """show the tip revision
5180
5180
5181 The tip revision (usually just called the tip) is the changeset
5181 The tip revision (usually just called the tip) is the changeset
5182 most recently added to the repository (and therefore the most
5182 most recently added to the repository (and therefore the most
5183 recently changed head).
5183 recently changed head).
5184
5184
5185 If you have just made a commit, that commit will be the tip. If
5185 If you have just made a commit, that commit will be the tip. If
5186 you have just pulled changes from another repository, the tip of
5186 you have just pulled changes from another repository, the tip of
5187 that repository becomes the current tip. The "tip" tag is special
5187 that repository becomes the current tip. The "tip" tag is special
5188 and cannot be renamed or assigned to a different changeset.
5188 and cannot be renamed or assigned to a different changeset.
5189
5189
5190 Returns 0 on success.
5190 Returns 0 on success.
5191 """
5191 """
5192 displayer = cmdutil.show_changeset(ui, repo, opts)
5192 displayer = cmdutil.show_changeset(ui, repo, opts)
5193 displayer.show(repo[len(repo) - 1])
5193 displayer.show(repo[len(repo) - 1])
5194 displayer.close()
5194 displayer.close()
5195
5195
5196 @command('unbundle',
5196 @command('unbundle',
5197 [('u', 'update', None,
5197 [('u', 'update', None,
5198 _('update to new branch head if changesets were unbundled'))],
5198 _('update to new branch head if changesets were unbundled'))],
5199 _('[-u] FILE...'))
5199 _('[-u] FILE...'))
5200 def unbundle(ui, repo, fname1, *fnames, **opts):
5200 def unbundle(ui, repo, fname1, *fnames, **opts):
5201 """apply one or more changegroup files
5201 """apply one or more changegroup files
5202
5202
5203 Apply one or more compressed changegroup files generated by the
5203 Apply one or more compressed changegroup files generated by the
5204 bundle command.
5204 bundle command.
5205
5205
5206 Returns 0 on success, 1 if an update has unresolved files.
5206 Returns 0 on success, 1 if an update has unresolved files.
5207 """
5207 """
5208 fnames = (fname1,) + fnames
5208 fnames = (fname1,) + fnames
5209
5209
5210 lock = repo.lock()
5210 lock = repo.lock()
5211 wc = repo['.']
5211 wc = repo['.']
5212 try:
5212 try:
5213 for fname in fnames:
5213 for fname in fnames:
5214 f = url.open(ui, fname)
5214 f = url.open(ui, fname)
5215 gen = changegroup.readbundle(f, fname)
5215 gen = changegroup.readbundle(f, fname)
5216 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5216 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5217 lock=lock)
5217 lock=lock)
5218 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5218 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5219 finally:
5219 finally:
5220 lock.release()
5220 lock.release()
5221 return postincoming(ui, repo, modheads, opts.get('update'), None)
5221 return postincoming(ui, repo, modheads, opts.get('update'), None)
5222
5222
5223 @command('^update|up|checkout|co',
5223 @command('^update|up|checkout|co',
5224 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5224 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5225 ('c', 'check', None,
5225 ('c', 'check', None,
5226 _('update across branches if no uncommitted changes')),
5226 _('update across branches if no uncommitted changes')),
5227 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5227 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5228 ('r', 'rev', '', _('revision'), _('REV'))],
5228 ('r', 'rev', '', _('revision'), _('REV'))],
5229 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5229 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5230 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5230 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5231 """update working directory (or switch revisions)
5231 """update working directory (or switch revisions)
5232
5232
5233 Update the repository's working directory to the specified
5233 Update the repository's working directory to the specified
5234 changeset. If no changeset is specified, update to the tip of the
5234 changeset. If no changeset is specified, update to the tip of the
5235 current named branch.
5235 current named branch.
5236
5236
5237 If the changeset is not a descendant of the working directory's
5237 If the changeset is not a descendant of the working directory's
5238 parent, the update is aborted. With the -c/--check option, the
5238 parent, the update is aborted. With the -c/--check option, the
5239 working directory is checked for uncommitted changes; if none are
5239 working directory is checked for uncommitted changes; if none are
5240 found, the working directory is updated to the specified
5240 found, the working directory is updated to the specified
5241 changeset.
5241 changeset.
5242
5242
5243 Update sets the working directory's parent revison to the specified
5243 Update sets the working directory's parent revison to the specified
5244 changeset (see :hg:`help parents`).
5244 changeset (see :hg:`help parents`).
5245
5245
5246 The following rules apply when the working directory contains
5246 The following rules apply when the working directory contains
5247 uncommitted changes:
5247 uncommitted changes:
5248
5248
5249 1. If neither -c/--check nor -C/--clean is specified, and if
5249 1. If neither -c/--check nor -C/--clean is specified, and if
5250 the requested changeset is an ancestor or descendant of
5250 the requested changeset is an ancestor or descendant of
5251 the working directory's parent, the uncommitted changes
5251 the working directory's parent, the uncommitted changes
5252 are merged into the requested changeset and the merged
5252 are merged into the requested changeset and the merged
5253 result is left uncommitted. If the requested changeset is
5253 result is left uncommitted. If the requested changeset is
5254 not an ancestor or descendant (that is, it is on another
5254 not an ancestor or descendant (that is, it is on another
5255 branch), the update is aborted and the uncommitted changes
5255 branch), the update is aborted and the uncommitted changes
5256 are preserved.
5256 are preserved.
5257
5257
5258 2. With the -c/--check option, the update is aborted and the
5258 2. With the -c/--check option, the update is aborted and the
5259 uncommitted changes are preserved.
5259 uncommitted changes are preserved.
5260
5260
5261 3. With the -C/--clean option, uncommitted changes are discarded and
5261 3. With the -C/--clean option, uncommitted changes are discarded and
5262 the working directory is updated to the requested changeset.
5262 the working directory is updated to the requested changeset.
5263
5263
5264 Use null as the changeset to remove the working directory (like
5264 Use null as the changeset to remove the working directory (like
5265 :hg:`clone -U`).
5265 :hg:`clone -U`).
5266
5266
5267 If you want to revert just one file to an older revision, use
5267 If you want to revert just one file to an older revision, use
5268 :hg:`revert [-r REV] NAME`.
5268 :hg:`revert [-r REV] NAME`.
5269
5269
5270 See :hg:`help dates` for a list of formats valid for -d/--date.
5270 See :hg:`help dates` for a list of formats valid for -d/--date.
5271
5271
5272 Returns 0 on success, 1 if there are unresolved files.
5272 Returns 0 on success, 1 if there are unresolved files.
5273 """
5273 """
5274 if rev and node:
5274 if rev and node:
5275 raise util.Abort(_("please specify just one revision"))
5275 raise util.Abort(_("please specify just one revision"))
5276
5276
5277 if rev is None or rev == '':
5277 if rev is None or rev == '':
5278 rev = node
5278 rev = node
5279
5279
5280 # if we defined a bookmark, we have to remember the original bookmark name
5280 # if we defined a bookmark, we have to remember the original bookmark name
5281 brev = rev
5281 brev = rev
5282 rev = scmutil.revsingle(repo, rev, rev).rev()
5282 rev = scmutil.revsingle(repo, rev, rev).rev()
5283
5283
5284 if check and clean:
5284 if check and clean:
5285 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5285 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5286
5286
5287 if check:
5287 if check:
5288 # we could use dirty() but we can ignore merge and branch trivia
5288 # we could use dirty() but we can ignore merge and branch trivia
5289 c = repo[None]
5289 c = repo[None]
5290 if c.modified() or c.added() or c.removed():
5290 if c.modified() or c.added() or c.removed():
5291 raise util.Abort(_("uncommitted local changes"))
5291 raise util.Abort(_("uncommitted local changes"))
5292
5292
5293 if date:
5293 if date:
5294 if rev is not None:
5294 if rev is not None:
5295 raise util.Abort(_("you can't specify a revision and a date"))
5295 raise util.Abort(_("you can't specify a revision and a date"))
5296 rev = cmdutil.finddate(ui, repo, date)
5296 rev = cmdutil.finddate(ui, repo, date)
5297
5297
5298 if clean or check:
5298 if clean or check:
5299 ret = hg.clean(repo, rev)
5299 ret = hg.clean(repo, rev)
5300 else:
5300 else:
5301 ret = hg.update(repo, rev)
5301 ret = hg.update(repo, rev)
5302
5302
5303 if brev in repo._bookmarks:
5303 if brev in repo._bookmarks:
5304 bookmarks.setcurrent(repo, brev)
5304 bookmarks.setcurrent(repo, brev)
5305
5305
5306 return ret
5306 return ret
5307
5307
5308 @command('verify', [])
5308 @command('verify', [])
5309 def verify(ui, repo):
5309 def verify(ui, repo):
5310 """verify the integrity of the repository
5310 """verify the integrity of the repository
5311
5311
5312 Verify the integrity of the current repository.
5312 Verify the integrity of the current repository.
5313
5313
5314 This will perform an extensive check of the repository's
5314 This will perform an extensive check of the repository's
5315 integrity, validating the hashes and checksums of each entry in
5315 integrity, validating the hashes and checksums of each entry in
5316 the changelog, manifest, and tracked files, as well as the
5316 the changelog, manifest, and tracked files, as well as the
5317 integrity of their crosslinks and indices.
5317 integrity of their crosslinks and indices.
5318
5318
5319 Returns 0 on success, 1 if errors are encountered.
5319 Returns 0 on success, 1 if errors are encountered.
5320 """
5320 """
5321 return hg.verify(repo)
5321 return hg.verify(repo)
5322
5322
5323 @command('version', [])
5323 @command('version', [])
5324 def version_(ui):
5324 def version_(ui):
5325 """output version and copyright information"""
5325 """output version and copyright information"""
5326 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5326 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5327 % util.version())
5327 % util.version())
5328 ui.status(_(
5328 ui.status(_(
5329 "(see http://mercurial.selenic.com for more information)\n"
5329 "(see http://mercurial.selenic.com for more information)\n"
5330 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5330 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5331 "This is free software; see the source for copying conditions. "
5331 "This is free software; see the source for copying conditions. "
5332 "There is NO\nwarranty; "
5332 "There is NO\nwarranty; "
5333 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5333 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5334 ))
5334 ))
5335
5335
5336 norepo = ("clone init version help debugcommands debugcomplete"
5336 norepo = ("clone init version help debugcommands debugcomplete"
5337 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5337 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5338 " debugknown debuggetbundle debugbundle")
5338 " debugknown debuggetbundle debugbundle")
5339 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5339 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5340 " debugdata debugindex debugindexdot debugrevlog")
5340 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,256 +1,256 b''
1 $ remove() {
1 $ remove() {
2 > hg rm $@
2 > hg rm $@
3 > echo "exit code: $?" # no-check-code
3 > echo "exit code: $?" # no-check-code
4 > hg st
4 > hg st
5 > # do not use ls -R, which recurses in .hg subdirs on Mac OS X 10.5
5 > # do not use ls -R, which recurses in .hg subdirs on Mac OS X 10.5
6 > find . -name .hg -prune -o -type f -print | sort
6 > find . -name .hg -prune -o -type f -print | sort
7 > hg up -C
7 > hg up -C
8 > }
8 > }
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12 $ echo a > foo
12 $ echo a > foo
13
13
14 file not managed
14 file not managed
15
15
16 $ remove foo
16 $ remove foo
17 not removing foo: file is untracked
17 not removing foo: file is untracked
18 exit code: 1
18 exit code: 1
19 ? foo
19 ? foo
20 ./foo
20 ./foo
21 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
22
22
23 $ hg add foo
23 $ hg add foo
24 $ hg commit -m1
24 $ hg commit -m1
25
25
26 the table cases
26 the table cases
27 00 state added, options none
27 00 state added, options none
28
28
29 $ echo b > bar
29 $ echo b > bar
30 $ hg add bar
30 $ hg add bar
31 $ remove bar
31 $ remove bar
32 not removing bar: file has been marked for add (use -f to force removal)
32 not removing bar: file has been marked for add (use forget to undo)
33 exit code: 1
33 exit code: 1
34 A bar
34 A bar
35 ./bar
35 ./bar
36 ./foo
36 ./foo
37 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
38
38
39 01 state clean, options none
39 01 state clean, options none
40
40
41 $ remove foo
41 $ remove foo
42 exit code: 0
42 exit code: 0
43 R foo
43 R foo
44 ? bar
44 ? bar
45 ./bar
45 ./bar
46 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
47
47
48 02 state modified, options none
48 02 state modified, options none
49
49
50 $ echo b >> foo
50 $ echo b >> foo
51 $ remove foo
51 $ remove foo
52 not removing foo: file is modified (use -f to force removal)
52 not removing foo: file is modified (use -f to force removal)
53 exit code: 1
53 exit code: 1
54 M foo
54 M foo
55 ? bar
55 ? bar
56 ./bar
56 ./bar
57 ./foo
57 ./foo
58 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
59
59
60 03 state missing, options none
60 03 state missing, options none
61
61
62 $ rm foo
62 $ rm foo
63 $ remove foo
63 $ remove foo
64 exit code: 0
64 exit code: 0
65 R foo
65 R foo
66 ? bar
66 ? bar
67 ./bar
67 ./bar
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69
69
70 10 state added, options -f
70 10 state added, options -f
71
71
72 $ echo b > bar
72 $ echo b > bar
73 $ hg add bar
73 $ hg add bar
74 $ remove -f bar
74 $ remove -f bar
75 exit code: 0
75 exit code: 0
76 ? bar
76 ? bar
77 ./bar
77 ./bar
78 ./foo
78 ./foo
79 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 $ rm bar
80 $ rm bar
81
81
82 11 state clean, options -f
82 11 state clean, options -f
83
83
84 $ remove -f foo
84 $ remove -f foo
85 exit code: 0
85 exit code: 0
86 R foo
86 R foo
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88
88
89 12 state modified, options -f
89 12 state modified, options -f
90
90
91 $ echo b >> foo
91 $ echo b >> foo
92 $ remove -f foo
92 $ remove -f foo
93 exit code: 0
93 exit code: 0
94 R foo
94 R foo
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96
96
97 13 state missing, options -f
97 13 state missing, options -f
98
98
99 $ rm foo
99 $ rm foo
100 $ remove -f foo
100 $ remove -f foo
101 exit code: 0
101 exit code: 0
102 R foo
102 R foo
103 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
104
104
105 20 state added, options -A
105 20 state added, options -A
106
106
107 $ echo b > bar
107 $ echo b > bar
108 $ hg add bar
108 $ hg add bar
109 $ remove -A bar
109 $ remove -A bar
110 not removing bar: file still exists (use -f to force removal)
110 not removing bar: file still exists (use -f to force removal)
111 exit code: 1
111 exit code: 1
112 A bar
112 A bar
113 ./bar
113 ./bar
114 ./foo
114 ./foo
115 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
116
116
117 21 state clean, options -A
117 21 state clean, options -A
118
118
119 $ remove -A foo
119 $ remove -A foo
120 not removing foo: file still exists (use -f to force removal)
120 not removing foo: file still exists (use -f to force removal)
121 exit code: 1
121 exit code: 1
122 ? bar
122 ? bar
123 ./bar
123 ./bar
124 ./foo
124 ./foo
125 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
126
126
127 22 state modified, options -A
127 22 state modified, options -A
128
128
129 $ echo b >> foo
129 $ echo b >> foo
130 $ remove -A foo
130 $ remove -A foo
131 not removing foo: file still exists (use -f to force removal)
131 not removing foo: file still exists (use -f to force removal)
132 exit code: 1
132 exit code: 1
133 M foo
133 M foo
134 ? bar
134 ? bar
135 ./bar
135 ./bar
136 ./foo
136 ./foo
137 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
138
138
139 23 state missing, options -A
139 23 state missing, options -A
140
140
141 $ rm foo
141 $ rm foo
142 $ remove -A foo
142 $ remove -A foo
143 exit code: 0
143 exit code: 0
144 R foo
144 R foo
145 ? bar
145 ? bar
146 ./bar
146 ./bar
147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
148
148
149 30 state added, options -Af
149 30 state added, options -Af
150
150
151 $ echo b > bar
151 $ echo b > bar
152 $ hg add bar
152 $ hg add bar
153 $ remove -Af bar
153 $ remove -Af bar
154 exit code: 0
154 exit code: 0
155 ? bar
155 ? bar
156 ./bar
156 ./bar
157 ./foo
157 ./foo
158 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 $ rm bar
159 $ rm bar
160
160
161 31 state clean, options -Af
161 31 state clean, options -Af
162
162
163 $ remove -Af foo
163 $ remove -Af foo
164 exit code: 0
164 exit code: 0
165 R foo
165 R foo
166 ./foo
166 ./foo
167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
168
168
169 32 state modified, options -Af
169 32 state modified, options -Af
170
170
171 $ echo b >> foo
171 $ echo b >> foo
172 $ remove -Af foo
172 $ remove -Af foo
173 exit code: 0
173 exit code: 0
174 R foo
174 R foo
175 ./foo
175 ./foo
176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
177
177
178 33 state missing, options -Af
178 33 state missing, options -Af
179
179
180 $ rm foo
180 $ rm foo
181 $ remove -Af foo
181 $ remove -Af foo
182 exit code: 0
182 exit code: 0
183 R foo
183 R foo
184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185
185
186 test some directory stuff
186 test some directory stuff
187
187
188 $ mkdir test
188 $ mkdir test
189 $ echo a > test/foo
189 $ echo a > test/foo
190 $ echo b > test/bar
190 $ echo b > test/bar
191 $ hg ci -Am2
191 $ hg ci -Am2
192 adding test/bar
192 adding test/bar
193 adding test/foo
193 adding test/foo
194
194
195 dir, options none
195 dir, options none
196
196
197 $ rm test/bar
197 $ rm test/bar
198 $ remove test
198 $ remove test
199 removing test/bar
199 removing test/bar
200 removing test/foo
200 removing test/foo
201 exit code: 0
201 exit code: 0
202 R test/bar
202 R test/bar
203 R test/foo
203 R test/foo
204 ./foo
204 ./foo
205 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
206
206
207 dir, options -f
207 dir, options -f
208
208
209 $ rm test/bar
209 $ rm test/bar
210 $ remove -f test
210 $ remove -f test
211 removing test/bar
211 removing test/bar
212 removing test/foo
212 removing test/foo
213 exit code: 0
213 exit code: 0
214 R test/bar
214 R test/bar
215 R test/foo
215 R test/foo
216 ./foo
216 ./foo
217 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218
218
219 dir, options -A
219 dir, options -A
220
220
221 $ rm test/bar
221 $ rm test/bar
222 $ remove -A test
222 $ remove -A test
223 not removing test/foo: file still exists (use -f to force removal)
223 not removing test/foo: file still exists (use -f to force removal)
224 removing test/bar
224 removing test/bar
225 exit code: 1
225 exit code: 1
226 R test/bar
226 R test/bar
227 ./foo
227 ./foo
228 ./test/foo
228 ./test/foo
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
230
230
231 dir, options -Af
231 dir, options -Af
232
232
233 $ rm test/bar
233 $ rm test/bar
234 $ remove -Af test
234 $ remove -Af test
235 removing test/bar
235 removing test/bar
236 removing test/foo
236 removing test/foo
237 exit code: 0
237 exit code: 0
238 R test/bar
238 R test/bar
239 R test/foo
239 R test/foo
240 ./foo
240 ./foo
241 ./test/foo
241 ./test/foo
242 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
243
243
244 test remove dropping empty trees (issue1861)
244 test remove dropping empty trees (issue1861)
245
245
246 $ mkdir -p issue1861/b/c
246 $ mkdir -p issue1861/b/c
247 $ echo x > issue1861/x
247 $ echo x > issue1861/x
248 $ echo y > issue1861/b/c/y
248 $ echo y > issue1861/b/c/y
249 $ hg ci -Am add
249 $ hg ci -Am add
250 adding issue1861/b/c/y
250 adding issue1861/b/c/y
251 adding issue1861/x
251 adding issue1861/x
252 $ hg rm issue1861/b
252 $ hg rm issue1861/b
253 removing issue1861/b/c/y
253 removing issue1861/b/c/y
254 $ hg ci -m remove
254 $ hg ci -m remove
255 $ ls issue1861
255 $ ls issue1861
256 x
256 x
General Comments 0
You need to be logged in to leave comments. Login now