##// END OF EJS Templates
debugdiscovery: report heads in sorted order
Mads Kiilerich <mads at kiilerich.com> -
r18254:2dfe519d default
parent child Browse files
Show More
@@ -1,6039 +1,6041
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, encoding, templatekw, discovery
13 import patch, help, 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, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
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 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (e.g. if
546 - mark the current revision, or a known revision, to be skipped (e.g. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - skip all revisions that do not touch directories ``foo`` or ``bar``
552 - skip all revisions that do not touch directories ``foo`` or ``bar``
553
553
554 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
554 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
555
555
556 - forget the current bisection::
556 - forget the current bisection::
557
557
558 hg bisect --reset
558 hg bisect --reset
559
559
560 - use 'make && make tests' to automatically find the first broken
560 - use 'make && make tests' to automatically find the first broken
561 revision::
561 revision::
562
562
563 hg bisect --reset
563 hg bisect --reset
564 hg bisect --bad 34
564 hg bisect --bad 34
565 hg bisect --good 12
565 hg bisect --good 12
566 hg bisect --command 'make && make tests'
566 hg bisect --command 'make && make tests'
567
567
568 - see all changesets whose states are already known in the current
568 - see all changesets whose states are already known in the current
569 bisection::
569 bisection::
570
570
571 hg log -r "bisect(pruned)"
571 hg log -r "bisect(pruned)"
572
572
573 - see the changeset currently being bisected (especially useful
573 - see the changeset currently being bisected (especially useful
574 if running with -U/--noupdate)::
574 if running with -U/--noupdate)::
575
575
576 hg log -r "bisect(current)"
576 hg log -r "bisect(current)"
577
577
578 - see all changesets that took part in the current bisection::
578 - see all changesets that took part in the current bisection::
579
579
580 hg log -r "bisect(range)"
580 hg log -r "bisect(range)"
581
581
582 - with the graphlog extension, you can even get a nice graph::
582 - with the graphlog extension, you can even get a nice graph::
583
583
584 hg log --graph -r "bisect(range)"
584 hg log --graph -r "bisect(range)"
585
585
586 See :hg:`help revsets` for more about the `bisect()` keyword.
586 See :hg:`help revsets` for more about the `bisect()` keyword.
587
587
588 Returns 0 on success.
588 Returns 0 on success.
589 """
589 """
590 def extendbisectrange(nodes, good):
590 def extendbisectrange(nodes, good):
591 # bisect is incomplete when it ends on a merge node and
591 # bisect is incomplete when it ends on a merge node and
592 # one of the parent was not checked.
592 # one of the parent was not checked.
593 parents = repo[nodes[0]].parents()
593 parents = repo[nodes[0]].parents()
594 if len(parents) > 1:
594 if len(parents) > 1:
595 side = good and state['bad'] or state['good']
595 side = good and state['bad'] or state['good']
596 num = len(set(i.node() for i in parents) & set(side))
596 num = len(set(i.node() for i in parents) & set(side))
597 if num == 1:
597 if num == 1:
598 return parents[0].ancestor(parents[1])
598 return parents[0].ancestor(parents[1])
599 return None
599 return None
600
600
601 def print_result(nodes, good):
601 def print_result(nodes, good):
602 displayer = cmdutil.show_changeset(ui, repo, {})
602 displayer = cmdutil.show_changeset(ui, repo, {})
603 if len(nodes) == 1:
603 if len(nodes) == 1:
604 # narrowed it down to a single revision
604 # narrowed it down to a single revision
605 if good:
605 if good:
606 ui.write(_("The first good revision is:\n"))
606 ui.write(_("The first good revision is:\n"))
607 else:
607 else:
608 ui.write(_("The first bad revision is:\n"))
608 ui.write(_("The first bad revision is:\n"))
609 displayer.show(repo[nodes[0]])
609 displayer.show(repo[nodes[0]])
610 extendnode = extendbisectrange(nodes, good)
610 extendnode = extendbisectrange(nodes, good)
611 if extendnode is not None:
611 if extendnode is not None:
612 ui.write(_('Not all ancestors of this changeset have been'
612 ui.write(_('Not all ancestors of this changeset have been'
613 ' checked.\nUse bisect --extend to continue the '
613 ' checked.\nUse bisect --extend to continue the '
614 'bisection from\nthe common ancestor, %s.\n')
614 'bisection from\nthe common ancestor, %s.\n')
615 % extendnode)
615 % extendnode)
616 else:
616 else:
617 # multiple possible revisions
617 # multiple possible revisions
618 if good:
618 if good:
619 ui.write(_("Due to skipped revisions, the first "
619 ui.write(_("Due to skipped revisions, the first "
620 "good revision could be any of:\n"))
620 "good revision could be any of:\n"))
621 else:
621 else:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "bad revision could be any of:\n"))
623 "bad revision could be any of:\n"))
624 for n in nodes:
624 for n in nodes:
625 displayer.show(repo[n])
625 displayer.show(repo[n])
626 displayer.close()
626 displayer.close()
627
627
628 def check_state(state, interactive=True):
628 def check_state(state, interactive=True):
629 if not state['good'] or not state['bad']:
629 if not state['good'] or not state['bad']:
630 if (good or bad or skip or reset) and interactive:
630 if (good or bad or skip or reset) and interactive:
631 return
631 return
632 if not state['good']:
632 if not state['good']:
633 raise util.Abort(_('cannot bisect (no known good revisions)'))
633 raise util.Abort(_('cannot bisect (no known good revisions)'))
634 else:
634 else:
635 raise util.Abort(_('cannot bisect (no known bad revisions)'))
635 raise util.Abort(_('cannot bisect (no known bad revisions)'))
636 return True
636 return True
637
637
638 # backward compatibility
638 # backward compatibility
639 if rev in "good bad reset init".split():
639 if rev in "good bad reset init".split():
640 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
640 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
641 cmd, rev, extra = rev, extra, None
641 cmd, rev, extra = rev, extra, None
642 if cmd == "good":
642 if cmd == "good":
643 good = True
643 good = True
644 elif cmd == "bad":
644 elif cmd == "bad":
645 bad = True
645 bad = True
646 else:
646 else:
647 reset = True
647 reset = True
648 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
648 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
649 raise util.Abort(_('incompatible arguments'))
649 raise util.Abort(_('incompatible arguments'))
650
650
651 if reset:
651 if reset:
652 p = repo.join("bisect.state")
652 p = repo.join("bisect.state")
653 if os.path.exists(p):
653 if os.path.exists(p):
654 os.unlink(p)
654 os.unlink(p)
655 return
655 return
656
656
657 state = hbisect.load_state(repo)
657 state = hbisect.load_state(repo)
658
658
659 if command:
659 if command:
660 changesets = 1
660 changesets = 1
661 try:
661 try:
662 node = state['current'][0]
662 node = state['current'][0]
663 except LookupError:
663 except LookupError:
664 if noupdate:
664 if noupdate:
665 raise util.Abort(_('current bisect revision is unknown - '
665 raise util.Abort(_('current bisect revision is unknown - '
666 'start a new bisect to fix'))
666 'start a new bisect to fix'))
667 node, p2 = repo.dirstate.parents()
667 node, p2 = repo.dirstate.parents()
668 if p2 != nullid:
668 if p2 != nullid:
669 raise util.Abort(_('current bisect revision is a merge'))
669 raise util.Abort(_('current bisect revision is a merge'))
670 try:
670 try:
671 while changesets:
671 while changesets:
672 # update state
672 # update state
673 state['current'] = [node]
673 state['current'] = [node]
674 hbisect.save_state(repo, state)
674 hbisect.save_state(repo, state)
675 status = util.system(command,
675 status = util.system(command,
676 environ={'HG_NODE': hex(node)},
676 environ={'HG_NODE': hex(node)},
677 out=ui.fout)
677 out=ui.fout)
678 if status == 125:
678 if status == 125:
679 transition = "skip"
679 transition = "skip"
680 elif status == 0:
680 elif status == 0:
681 transition = "good"
681 transition = "good"
682 # status < 0 means process was killed
682 # status < 0 means process was killed
683 elif status == 127:
683 elif status == 127:
684 raise util.Abort(_("failed to execute %s") % command)
684 raise util.Abort(_("failed to execute %s") % command)
685 elif status < 0:
685 elif status < 0:
686 raise util.Abort(_("%s killed") % command)
686 raise util.Abort(_("%s killed") % command)
687 else:
687 else:
688 transition = "bad"
688 transition = "bad"
689 ctx = scmutil.revsingle(repo, rev, node)
689 ctx = scmutil.revsingle(repo, rev, node)
690 rev = None # clear for future iterations
690 rev = None # clear for future iterations
691 state[transition].append(ctx.node())
691 state[transition].append(ctx.node())
692 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
692 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
693 check_state(state, interactive=False)
693 check_state(state, interactive=False)
694 # bisect
694 # bisect
695 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
695 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
696 # update to next check
696 # update to next check
697 node = nodes[0]
697 node = nodes[0]
698 if not noupdate:
698 if not noupdate:
699 cmdutil.bailifchanged(repo)
699 cmdutil.bailifchanged(repo)
700 hg.clean(repo, node, show_stats=False)
700 hg.clean(repo, node, show_stats=False)
701 finally:
701 finally:
702 state['current'] = [node]
702 state['current'] = [node]
703 hbisect.save_state(repo, state)
703 hbisect.save_state(repo, state)
704 print_result(nodes, good)
704 print_result(nodes, good)
705 return
705 return
706
706
707 # update state
707 # update state
708
708
709 if rev:
709 if rev:
710 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
710 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
711 else:
711 else:
712 nodes = [repo.lookup('.')]
712 nodes = [repo.lookup('.')]
713
713
714 if good or bad or skip:
714 if good or bad or skip:
715 if good:
715 if good:
716 state['good'] += nodes
716 state['good'] += nodes
717 elif bad:
717 elif bad:
718 state['bad'] += nodes
718 state['bad'] += nodes
719 elif skip:
719 elif skip:
720 state['skip'] += nodes
720 state['skip'] += nodes
721 hbisect.save_state(repo, state)
721 hbisect.save_state(repo, state)
722
722
723 if not check_state(state):
723 if not check_state(state):
724 return
724 return
725
725
726 # actually bisect
726 # actually bisect
727 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
727 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
728 if extend:
728 if extend:
729 if not changesets:
729 if not changesets:
730 extendnode = extendbisectrange(nodes, good)
730 extendnode = extendbisectrange(nodes, good)
731 if extendnode is not None:
731 if extendnode is not None:
732 ui.write(_("Extending search to changeset %d:%s\n"
732 ui.write(_("Extending search to changeset %d:%s\n"
733 % (extendnode.rev(), extendnode)))
733 % (extendnode.rev(), extendnode)))
734 state['current'] = [extendnode.node()]
734 state['current'] = [extendnode.node()]
735 hbisect.save_state(repo, state)
735 hbisect.save_state(repo, state)
736 if noupdate:
736 if noupdate:
737 return
737 return
738 cmdutil.bailifchanged(repo)
738 cmdutil.bailifchanged(repo)
739 return hg.clean(repo, extendnode.node())
739 return hg.clean(repo, extendnode.node())
740 raise util.Abort(_("nothing to extend"))
740 raise util.Abort(_("nothing to extend"))
741
741
742 if changesets == 0:
742 if changesets == 0:
743 print_result(nodes, good)
743 print_result(nodes, good)
744 else:
744 else:
745 assert len(nodes) == 1 # only a single node can be tested next
745 assert len(nodes) == 1 # only a single node can be tested next
746 node = nodes[0]
746 node = nodes[0]
747 # compute the approximate number of remaining tests
747 # compute the approximate number of remaining tests
748 tests, size = 0, 2
748 tests, size = 0, 2
749 while size <= changesets:
749 while size <= changesets:
750 tests, size = tests + 1, size * 2
750 tests, size = tests + 1, size * 2
751 rev = repo.changelog.rev(node)
751 rev = repo.changelog.rev(node)
752 ui.write(_("Testing changeset %d:%s "
752 ui.write(_("Testing changeset %d:%s "
753 "(%d changesets remaining, ~%d tests)\n")
753 "(%d changesets remaining, ~%d tests)\n")
754 % (rev, short(node), changesets, tests))
754 % (rev, short(node), changesets, tests))
755 state['current'] = [node]
755 state['current'] = [node]
756 hbisect.save_state(repo, state)
756 hbisect.save_state(repo, state)
757 if not noupdate:
757 if not noupdate:
758 cmdutil.bailifchanged(repo)
758 cmdutil.bailifchanged(repo)
759 return hg.clean(repo, node)
759 return hg.clean(repo, node)
760
760
761 @command('bookmarks|bookmark',
761 @command('bookmarks|bookmark',
762 [('f', 'force', False, _('force')),
762 [('f', 'force', False, _('force')),
763 ('r', 'rev', '', _('revision'), _('REV')),
763 ('r', 'rev', '', _('revision'), _('REV')),
764 ('d', 'delete', False, _('delete a given bookmark')),
764 ('d', 'delete', False, _('delete a given bookmark')),
765 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
765 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
766 ('i', 'inactive', False, _('mark a bookmark inactive'))],
766 ('i', 'inactive', False, _('mark a bookmark inactive'))],
767 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
767 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
768 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
768 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
769 rename=None, inactive=False):
769 rename=None, inactive=False):
770 '''track a line of development with movable markers
770 '''track a line of development with movable markers
771
771
772 Bookmarks are pointers to certain commits that move when committing.
772 Bookmarks are pointers to certain commits that move when committing.
773 Bookmarks are local. They can be renamed, copied and deleted. It is
773 Bookmarks are local. They can be renamed, copied and deleted. It is
774 possible to use :hg:`merge NAME` to merge from a given bookmark, and
774 possible to use :hg:`merge NAME` to merge from a given bookmark, and
775 :hg:`update NAME` to update to a given bookmark.
775 :hg:`update NAME` to update to a given bookmark.
776
776
777 You can use :hg:`bookmark NAME` to set a bookmark on the working
777 You can use :hg:`bookmark NAME` to set a bookmark on the working
778 directory's parent revision with the given name. If you specify
778 directory's parent revision with the given name. If you specify
779 a revision using -r REV (where REV may be an existing bookmark),
779 a revision using -r REV (where REV may be an existing bookmark),
780 the bookmark is assigned to that revision.
780 the bookmark is assigned to that revision.
781
781
782 Bookmarks can be pushed and pulled between repositories (see :hg:`help
782 Bookmarks can be pushed and pulled between repositories (see :hg:`help
783 push` and :hg:`help pull`). This requires both the local and remote
783 push` and :hg:`help pull`). This requires both the local and remote
784 repositories to support bookmarks. For versions prior to 1.8, this means
784 repositories to support bookmarks. For versions prior to 1.8, this means
785 the bookmarks extension must be enabled.
785 the bookmarks extension must be enabled.
786
786
787 With -i/--inactive, the new bookmark will not be made the active
787 With -i/--inactive, the new bookmark will not be made the active
788 bookmark. If -r/--rev is given, the new bookmark will not be made
788 bookmark. If -r/--rev is given, the new bookmark will not be made
789 active even if -i/--inactive is not given. If no NAME is given, the
789 active even if -i/--inactive is not given. If no NAME is given, the
790 current active bookmark will be marked inactive.
790 current active bookmark will be marked inactive.
791 '''
791 '''
792 hexfn = ui.debugflag and hex or short
792 hexfn = ui.debugflag and hex or short
793 marks = repo._bookmarks
793 marks = repo._bookmarks
794 cur = repo.changectx('.').node()
794 cur = repo.changectx('.').node()
795
795
796 def checkformat(mark):
796 def checkformat(mark):
797 mark = mark.strip()
797 mark = mark.strip()
798 if not mark:
798 if not mark:
799 raise util.Abort(_("bookmark names cannot consist entirely of "
799 raise util.Abort(_("bookmark names cannot consist entirely of "
800 "whitespace"))
800 "whitespace"))
801 scmutil.checknewlabel(repo, mark, 'bookmark')
801 scmutil.checknewlabel(repo, mark, 'bookmark')
802 return mark
802 return mark
803
803
804 def checkconflict(repo, mark, force=False):
804 def checkconflict(repo, mark, force=False):
805 if mark in marks and not force:
805 if mark in marks and not force:
806 raise util.Abort(_("bookmark '%s' already exists "
806 raise util.Abort(_("bookmark '%s' already exists "
807 "(use -f to force)") % mark)
807 "(use -f to force)") % mark)
808 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
808 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
809 and not force):
809 and not force):
810 raise util.Abort(
810 raise util.Abort(
811 _("a bookmark cannot have the name of an existing branch"))
811 _("a bookmark cannot have the name of an existing branch"))
812
812
813 if delete and rename:
813 if delete and rename:
814 raise util.Abort(_("--delete and --rename are incompatible"))
814 raise util.Abort(_("--delete and --rename are incompatible"))
815 if delete and rev:
815 if delete and rev:
816 raise util.Abort(_("--rev is incompatible with --delete"))
816 raise util.Abort(_("--rev is incompatible with --delete"))
817 if rename and rev:
817 if rename and rev:
818 raise util.Abort(_("--rev is incompatible with --rename"))
818 raise util.Abort(_("--rev is incompatible with --rename"))
819 if mark is None and (delete or rev):
819 if mark is None and (delete or rev):
820 raise util.Abort(_("bookmark name required"))
820 raise util.Abort(_("bookmark name required"))
821
821
822 if delete:
822 if delete:
823 if mark not in marks:
823 if mark not in marks:
824 raise util.Abort(_("bookmark '%s' does not exist") % mark)
824 raise util.Abort(_("bookmark '%s' does not exist") % mark)
825 if mark == repo._bookmarkcurrent:
825 if mark == repo._bookmarkcurrent:
826 bookmarks.setcurrent(repo, None)
826 bookmarks.setcurrent(repo, None)
827 del marks[mark]
827 del marks[mark]
828 marks.write()
828 marks.write()
829
829
830 elif rename:
830 elif rename:
831 if mark is None:
831 if mark is None:
832 raise util.Abort(_("new bookmark name required"))
832 raise util.Abort(_("new bookmark name required"))
833 mark = checkformat(mark)
833 mark = checkformat(mark)
834 if rename not in marks:
834 if rename not in marks:
835 raise util.Abort(_("bookmark '%s' does not exist") % rename)
835 raise util.Abort(_("bookmark '%s' does not exist") % rename)
836 checkconflict(repo, mark, force)
836 checkconflict(repo, mark, force)
837 marks[mark] = marks[rename]
837 marks[mark] = marks[rename]
838 if repo._bookmarkcurrent == rename and not inactive:
838 if repo._bookmarkcurrent == rename and not inactive:
839 bookmarks.setcurrent(repo, mark)
839 bookmarks.setcurrent(repo, mark)
840 del marks[rename]
840 del marks[rename]
841 marks.write()
841 marks.write()
842
842
843 elif mark is not None:
843 elif mark is not None:
844 mark = checkformat(mark)
844 mark = checkformat(mark)
845 if inactive and mark == repo._bookmarkcurrent:
845 if inactive and mark == repo._bookmarkcurrent:
846 bookmarks.setcurrent(repo, None)
846 bookmarks.setcurrent(repo, None)
847 return
847 return
848 checkconflict(repo, mark, force)
848 checkconflict(repo, mark, force)
849 if rev:
849 if rev:
850 marks[mark] = scmutil.revsingle(repo, rev).node()
850 marks[mark] = scmutil.revsingle(repo, rev).node()
851 else:
851 else:
852 marks[mark] = cur
852 marks[mark] = cur
853 if not inactive and cur == marks[mark]:
853 if not inactive and cur == marks[mark]:
854 bookmarks.setcurrent(repo, mark)
854 bookmarks.setcurrent(repo, mark)
855 marks.write()
855 marks.write()
856
856
857 # Same message whether trying to deactivate the current bookmark (-i
857 # Same message whether trying to deactivate the current bookmark (-i
858 # with no NAME) or listing bookmarks
858 # with no NAME) or listing bookmarks
859 elif len(marks) == 0:
859 elif len(marks) == 0:
860 ui.status(_("no bookmarks set\n"))
860 ui.status(_("no bookmarks set\n"))
861
861
862 elif inactive:
862 elif inactive:
863 if not repo._bookmarkcurrent:
863 if not repo._bookmarkcurrent:
864 ui.status(_("no active bookmark\n"))
864 ui.status(_("no active bookmark\n"))
865 else:
865 else:
866 bookmarks.setcurrent(repo, None)
866 bookmarks.setcurrent(repo, None)
867
867
868 else: # show bookmarks
868 else: # show bookmarks
869 for bmark, n in sorted(marks.iteritems()):
869 for bmark, n in sorted(marks.iteritems()):
870 current = repo._bookmarkcurrent
870 current = repo._bookmarkcurrent
871 if bmark == current and n == cur:
871 if bmark == current and n == cur:
872 prefix, label = '*', 'bookmarks.current'
872 prefix, label = '*', 'bookmarks.current'
873 else:
873 else:
874 prefix, label = ' ', ''
874 prefix, label = ' ', ''
875
875
876 if ui.quiet:
876 if ui.quiet:
877 ui.write("%s\n" % bmark, label=label)
877 ui.write("%s\n" % bmark, label=label)
878 else:
878 else:
879 ui.write(" %s %-25s %d:%s\n" % (
879 ui.write(" %s %-25s %d:%s\n" % (
880 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
880 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
881 label=label)
881 label=label)
882
882
883 @command('branch',
883 @command('branch',
884 [('f', 'force', None,
884 [('f', 'force', None,
885 _('set branch name even if it shadows an existing branch')),
885 _('set branch name even if it shadows an existing branch')),
886 ('C', 'clean', None, _('reset branch name to parent branch name'))],
886 ('C', 'clean', None, _('reset branch name to parent branch name'))],
887 _('[-fC] [NAME]'))
887 _('[-fC] [NAME]'))
888 def branch(ui, repo, label=None, **opts):
888 def branch(ui, repo, label=None, **opts):
889 """set or show the current branch name
889 """set or show the current branch name
890
890
891 .. note::
891 .. note::
892 Branch names are permanent and global. Use :hg:`bookmark` to create a
892 Branch names are permanent and global. Use :hg:`bookmark` to create a
893 light-weight bookmark instead. See :hg:`help glossary` for more
893 light-weight bookmark instead. See :hg:`help glossary` for more
894 information about named branches and bookmarks.
894 information about named branches and bookmarks.
895
895
896 With no argument, show the current branch name. With one argument,
896 With no argument, show the current branch name. With one argument,
897 set the working directory branch name (the branch will not exist
897 set the working directory branch name (the branch will not exist
898 in the repository until the next commit). Standard practice
898 in the repository until the next commit). Standard practice
899 recommends that primary development take place on the 'default'
899 recommends that primary development take place on the 'default'
900 branch.
900 branch.
901
901
902 Unless -f/--force is specified, branch will not let you set a
902 Unless -f/--force is specified, branch will not let you set a
903 branch name that already exists, even if it's inactive.
903 branch name that already exists, even if it's inactive.
904
904
905 Use -C/--clean to reset the working directory branch to that of
905 Use -C/--clean to reset the working directory branch to that of
906 the parent of the working directory, negating a previous branch
906 the parent of the working directory, negating a previous branch
907 change.
907 change.
908
908
909 Use the command :hg:`update` to switch to an existing branch. Use
909 Use the command :hg:`update` to switch to an existing branch. Use
910 :hg:`commit --close-branch` to mark this branch as closed.
910 :hg:`commit --close-branch` to mark this branch as closed.
911
911
912 Returns 0 on success.
912 Returns 0 on success.
913 """
913 """
914 if not opts.get('clean') and not label:
914 if not opts.get('clean') and not label:
915 ui.write("%s\n" % repo.dirstate.branch())
915 ui.write("%s\n" % repo.dirstate.branch())
916 return
916 return
917
917
918 wlock = repo.wlock()
918 wlock = repo.wlock()
919 try:
919 try:
920 if opts.get('clean'):
920 if opts.get('clean'):
921 label = repo[None].p1().branch()
921 label = repo[None].p1().branch()
922 repo.dirstate.setbranch(label)
922 repo.dirstate.setbranch(label)
923 ui.status(_('reset working directory to branch %s\n') % label)
923 ui.status(_('reset working directory to branch %s\n') % label)
924 elif label:
924 elif label:
925 if not opts.get('force') and label in repo.branchmap():
925 if not opts.get('force') and label in repo.branchmap():
926 if label not in [p.branch() for p in repo.parents()]:
926 if label not in [p.branch() for p in repo.parents()]:
927 raise util.Abort(_('a branch of the same name already'
927 raise util.Abort(_('a branch of the same name already'
928 ' exists'),
928 ' exists'),
929 # i18n: "it" refers to an existing branch
929 # i18n: "it" refers to an existing branch
930 hint=_("use 'hg update' to switch to it"))
930 hint=_("use 'hg update' to switch to it"))
931 scmutil.checknewlabel(repo, label, 'branch')
931 scmutil.checknewlabel(repo, label, 'branch')
932 repo.dirstate.setbranch(label)
932 repo.dirstate.setbranch(label)
933 ui.status(_('marked working directory as branch %s\n') % label)
933 ui.status(_('marked working directory as branch %s\n') % label)
934 ui.status(_('(branches are permanent and global, '
934 ui.status(_('(branches are permanent and global, '
935 'did you want a bookmark?)\n'))
935 'did you want a bookmark?)\n'))
936 finally:
936 finally:
937 wlock.release()
937 wlock.release()
938
938
939 @command('branches',
939 @command('branches',
940 [('a', 'active', False, _('show only branches that have unmerged heads')),
940 [('a', 'active', False, _('show only branches that have unmerged heads')),
941 ('c', 'closed', False, _('show normal and closed branches'))],
941 ('c', 'closed', False, _('show normal and closed branches'))],
942 _('[-ac]'))
942 _('[-ac]'))
943 def branches(ui, repo, active=False, closed=False):
943 def branches(ui, repo, active=False, closed=False):
944 """list repository named branches
944 """list repository named branches
945
945
946 List the repository's named branches, indicating which ones are
946 List the repository's named branches, indicating which ones are
947 inactive. If -c/--closed is specified, also list branches which have
947 inactive. If -c/--closed is specified, also list branches which have
948 been marked closed (see :hg:`commit --close-branch`).
948 been marked closed (see :hg:`commit --close-branch`).
949
949
950 If -a/--active is specified, only show active branches. A branch
950 If -a/--active is specified, only show active branches. A branch
951 is considered active if it contains repository heads.
951 is considered active if it contains repository heads.
952
952
953 Use the command :hg:`update` to switch to an existing branch.
953 Use the command :hg:`update` to switch to an existing branch.
954
954
955 Returns 0.
955 Returns 0.
956 """
956 """
957
957
958 hexfunc = ui.debugflag and hex or short
958 hexfunc = ui.debugflag and hex or short
959
959
960 activebranches = set([repo[n].branch() for n in repo.heads()])
960 activebranches = set([repo[n].branch() for n in repo.heads()])
961 branches = []
961 branches = []
962 for tag, heads in repo.branchmap().iteritems():
962 for tag, heads in repo.branchmap().iteritems():
963 for h in reversed(heads):
963 for h in reversed(heads):
964 ctx = repo[h]
964 ctx = repo[h]
965 isopen = not ctx.closesbranch()
965 isopen = not ctx.closesbranch()
966 if isopen:
966 if isopen:
967 tip = ctx
967 tip = ctx
968 break
968 break
969 else:
969 else:
970 tip = repo[heads[-1]]
970 tip = repo[heads[-1]]
971 isactive = tag in activebranches and isopen
971 isactive = tag in activebranches and isopen
972 branches.append((tip, isactive, isopen))
972 branches.append((tip, isactive, isopen))
973 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
973 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
974 reverse=True)
974 reverse=True)
975
975
976 for ctx, isactive, isopen in branches:
976 for ctx, isactive, isopen in branches:
977 if (not active) or isactive:
977 if (not active) or isactive:
978 if isactive:
978 if isactive:
979 label = 'branches.active'
979 label = 'branches.active'
980 notice = ''
980 notice = ''
981 elif not isopen:
981 elif not isopen:
982 if not closed:
982 if not closed:
983 continue
983 continue
984 label = 'branches.closed'
984 label = 'branches.closed'
985 notice = _(' (closed)')
985 notice = _(' (closed)')
986 else:
986 else:
987 label = 'branches.inactive'
987 label = 'branches.inactive'
988 notice = _(' (inactive)')
988 notice = _(' (inactive)')
989 if ctx.branch() == repo.dirstate.branch():
989 if ctx.branch() == repo.dirstate.branch():
990 label = 'branches.current'
990 label = 'branches.current'
991 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
991 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
992 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
992 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
993 'log.changeset changeset.%s' % ctx.phasestr())
993 'log.changeset changeset.%s' % ctx.phasestr())
994 tag = ui.label(ctx.branch(), label)
994 tag = ui.label(ctx.branch(), label)
995 if ui.quiet:
995 if ui.quiet:
996 ui.write("%s\n" % tag)
996 ui.write("%s\n" % tag)
997 else:
997 else:
998 ui.write("%s %s%s\n" % (tag, rev, notice))
998 ui.write("%s %s%s\n" % (tag, rev, notice))
999
999
1000 @command('bundle',
1000 @command('bundle',
1001 [('f', 'force', None, _('run even when the destination is unrelated')),
1001 [('f', 'force', None, _('run even when the destination is unrelated')),
1002 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1002 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1003 _('REV')),
1003 _('REV')),
1004 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1004 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1005 _('BRANCH')),
1005 _('BRANCH')),
1006 ('', 'base', [],
1006 ('', 'base', [],
1007 _('a base changeset assumed to be available at the destination'),
1007 _('a base changeset assumed to be available at the destination'),
1008 _('REV')),
1008 _('REV')),
1009 ('a', 'all', None, _('bundle all changesets in the repository')),
1009 ('a', 'all', None, _('bundle all changesets in the repository')),
1010 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1010 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1011 ] + remoteopts,
1011 ] + remoteopts,
1012 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1012 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1013 def bundle(ui, repo, fname, dest=None, **opts):
1013 def bundle(ui, repo, fname, dest=None, **opts):
1014 """create a changegroup file
1014 """create a changegroup file
1015
1015
1016 Generate a compressed changegroup file collecting changesets not
1016 Generate a compressed changegroup file collecting changesets not
1017 known to be in another repository.
1017 known to be in another repository.
1018
1018
1019 If you omit the destination repository, then hg assumes the
1019 If you omit the destination repository, then hg assumes the
1020 destination will have all the nodes you specify with --base
1020 destination will have all the nodes you specify with --base
1021 parameters. To create a bundle containing all changesets, use
1021 parameters. To create a bundle containing all changesets, use
1022 -a/--all (or --base null).
1022 -a/--all (or --base null).
1023
1023
1024 You can change compression method with the -t/--type option.
1024 You can change compression method with the -t/--type option.
1025 The available compression methods are: none, bzip2, and
1025 The available compression methods are: none, bzip2, and
1026 gzip (by default, bundles are compressed using bzip2).
1026 gzip (by default, bundles are compressed using bzip2).
1027
1027
1028 The bundle file can then be transferred using conventional means
1028 The bundle file can then be transferred using conventional means
1029 and applied to another repository with the unbundle or pull
1029 and applied to another repository with the unbundle or pull
1030 command. This is useful when direct push and pull are not
1030 command. This is useful when direct push and pull are not
1031 available or when exporting an entire repository is undesirable.
1031 available or when exporting an entire repository is undesirable.
1032
1032
1033 Applying bundles preserves all changeset contents including
1033 Applying bundles preserves all changeset contents including
1034 permissions, copy/rename information, and revision history.
1034 permissions, copy/rename information, and revision history.
1035
1035
1036 Returns 0 on success, 1 if no changes found.
1036 Returns 0 on success, 1 if no changes found.
1037 """
1037 """
1038 revs = None
1038 revs = None
1039 if 'rev' in opts:
1039 if 'rev' in opts:
1040 revs = scmutil.revrange(repo, opts['rev'])
1040 revs = scmutil.revrange(repo, opts['rev'])
1041
1041
1042 bundletype = opts.get('type', 'bzip2').lower()
1042 bundletype = opts.get('type', 'bzip2').lower()
1043 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1043 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1044 bundletype = btypes.get(bundletype)
1044 bundletype = btypes.get(bundletype)
1045 if bundletype not in changegroup.bundletypes:
1045 if bundletype not in changegroup.bundletypes:
1046 raise util.Abort(_('unknown bundle type specified with --type'))
1046 raise util.Abort(_('unknown bundle type specified with --type'))
1047
1047
1048 if opts.get('all'):
1048 if opts.get('all'):
1049 base = ['null']
1049 base = ['null']
1050 else:
1050 else:
1051 base = scmutil.revrange(repo, opts.get('base'))
1051 base = scmutil.revrange(repo, opts.get('base'))
1052 if base:
1052 if base:
1053 if dest:
1053 if dest:
1054 raise util.Abort(_("--base is incompatible with specifying "
1054 raise util.Abort(_("--base is incompatible with specifying "
1055 "a destination"))
1055 "a destination"))
1056 common = [repo.lookup(rev) for rev in base]
1056 common = [repo.lookup(rev) for rev in base]
1057 heads = revs and map(repo.lookup, revs) or revs
1057 heads = revs and map(repo.lookup, revs) or revs
1058 cg = repo.getbundle('bundle', heads=heads, common=common)
1058 cg = repo.getbundle('bundle', heads=heads, common=common)
1059 outgoing = None
1059 outgoing = None
1060 else:
1060 else:
1061 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1061 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1062 dest, branches = hg.parseurl(dest, opts.get('branch'))
1062 dest, branches = hg.parseurl(dest, opts.get('branch'))
1063 other = hg.peer(repo, opts, dest)
1063 other = hg.peer(repo, opts, dest)
1064 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1064 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1065 heads = revs and map(repo.lookup, revs) or revs
1065 heads = revs and map(repo.lookup, revs) or revs
1066 outgoing = discovery.findcommonoutgoing(repo, other,
1066 outgoing = discovery.findcommonoutgoing(repo, other,
1067 onlyheads=heads,
1067 onlyheads=heads,
1068 force=opts.get('force'),
1068 force=opts.get('force'),
1069 portable=True)
1069 portable=True)
1070 cg = repo.getlocalbundle('bundle', outgoing)
1070 cg = repo.getlocalbundle('bundle', outgoing)
1071 if not cg:
1071 if not cg:
1072 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1072 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1073 return 1
1073 return 1
1074
1074
1075 changegroup.writebundle(cg, fname, bundletype)
1075 changegroup.writebundle(cg, fname, bundletype)
1076
1076
1077 @command('cat',
1077 @command('cat',
1078 [('o', 'output', '',
1078 [('o', 'output', '',
1079 _('print output to file with formatted name'), _('FORMAT')),
1079 _('print output to file with formatted name'), _('FORMAT')),
1080 ('r', 'rev', '', _('print the given revision'), _('REV')),
1080 ('r', 'rev', '', _('print the given revision'), _('REV')),
1081 ('', 'decode', None, _('apply any matching decode filter')),
1081 ('', 'decode', None, _('apply any matching decode filter')),
1082 ] + walkopts,
1082 ] + walkopts,
1083 _('[OPTION]... FILE...'))
1083 _('[OPTION]... FILE...'))
1084 def cat(ui, repo, file1, *pats, **opts):
1084 def cat(ui, repo, file1, *pats, **opts):
1085 """output the current or given revision of files
1085 """output the current or given revision of files
1086
1086
1087 Print the specified files as they were at the given revision. If
1087 Print the specified files as they were at the given revision. If
1088 no revision is given, the parent of the working directory is used,
1088 no revision is given, the parent of the working directory is used,
1089 or tip if no revision is checked out.
1089 or tip if no revision is checked out.
1090
1090
1091 Output may be to a file, in which case the name of the file is
1091 Output may be to a file, in which case the name of the file is
1092 given using a format string. The formatting rules are the same as
1092 given using a format string. The formatting rules are the same as
1093 for the export command, with the following additions:
1093 for the export command, with the following additions:
1094
1094
1095 :``%s``: basename of file being printed
1095 :``%s``: basename of file being printed
1096 :``%d``: dirname of file being printed, or '.' if in repository root
1096 :``%d``: dirname of file being printed, or '.' if in repository root
1097 :``%p``: root-relative path name of file being printed
1097 :``%p``: root-relative path name of file being printed
1098
1098
1099 Returns 0 on success.
1099 Returns 0 on success.
1100 """
1100 """
1101 ctx = scmutil.revsingle(repo, opts.get('rev'))
1101 ctx = scmutil.revsingle(repo, opts.get('rev'))
1102 err = 1
1102 err = 1
1103 m = scmutil.match(ctx, (file1,) + pats, opts)
1103 m = scmutil.match(ctx, (file1,) + pats, opts)
1104 for abs in ctx.walk(m):
1104 for abs in ctx.walk(m):
1105 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1105 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1106 pathname=abs)
1106 pathname=abs)
1107 data = ctx[abs].data()
1107 data = ctx[abs].data()
1108 if opts.get('decode'):
1108 if opts.get('decode'):
1109 data = repo.wwritedata(abs, data)
1109 data = repo.wwritedata(abs, data)
1110 fp.write(data)
1110 fp.write(data)
1111 fp.close()
1111 fp.close()
1112 err = 0
1112 err = 0
1113 return err
1113 return err
1114
1114
1115 @command('^clone',
1115 @command('^clone',
1116 [('U', 'noupdate', None,
1116 [('U', 'noupdate', None,
1117 _('the clone will include an empty working copy (only a repository)')),
1117 _('the clone will include an empty working copy (only a repository)')),
1118 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1118 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1119 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1119 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1120 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1120 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1121 ('', 'pull', None, _('use pull protocol to copy metadata')),
1121 ('', 'pull', None, _('use pull protocol to copy metadata')),
1122 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1122 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1123 ] + remoteopts,
1123 ] + remoteopts,
1124 _('[OPTION]... SOURCE [DEST]'))
1124 _('[OPTION]... SOURCE [DEST]'))
1125 def clone(ui, source, dest=None, **opts):
1125 def clone(ui, source, dest=None, **opts):
1126 """make a copy of an existing repository
1126 """make a copy of an existing repository
1127
1127
1128 Create a copy of an existing repository in a new directory.
1128 Create a copy of an existing repository in a new directory.
1129
1129
1130 If no destination directory name is specified, it defaults to the
1130 If no destination directory name is specified, it defaults to the
1131 basename of the source.
1131 basename of the source.
1132
1132
1133 The location of the source is added to the new repository's
1133 The location of the source is added to the new repository's
1134 ``.hg/hgrc`` file, as the default to be used for future pulls.
1134 ``.hg/hgrc`` file, as the default to be used for future pulls.
1135
1135
1136 Only local paths and ``ssh://`` URLs are supported as
1136 Only local paths and ``ssh://`` URLs are supported as
1137 destinations. For ``ssh://`` destinations, no working directory or
1137 destinations. For ``ssh://`` destinations, no working directory or
1138 ``.hg/hgrc`` will be created on the remote side.
1138 ``.hg/hgrc`` will be created on the remote side.
1139
1139
1140 To pull only a subset of changesets, specify one or more revisions
1140 To pull only a subset of changesets, specify one or more revisions
1141 identifiers with -r/--rev or branches with -b/--branch. The
1141 identifiers with -r/--rev or branches with -b/--branch. The
1142 resulting clone will contain only the specified changesets and
1142 resulting clone will contain only the specified changesets and
1143 their ancestors. These options (or 'clone src#rev dest') imply
1143 their ancestors. These options (or 'clone src#rev dest') imply
1144 --pull, even for local source repositories. Note that specifying a
1144 --pull, even for local source repositories. Note that specifying a
1145 tag will include the tagged changeset but not the changeset
1145 tag will include the tagged changeset but not the changeset
1146 containing the tag.
1146 containing the tag.
1147
1147
1148 To check out a particular version, use -u/--update, or
1148 To check out a particular version, use -u/--update, or
1149 -U/--noupdate to create a clone with no working directory.
1149 -U/--noupdate to create a clone with no working directory.
1150
1150
1151 .. container:: verbose
1151 .. container:: verbose
1152
1152
1153 For efficiency, hardlinks are used for cloning whenever the
1153 For efficiency, hardlinks are used for cloning whenever the
1154 source and destination are on the same filesystem (note this
1154 source and destination are on the same filesystem (note this
1155 applies only to the repository data, not to the working
1155 applies only to the repository data, not to the working
1156 directory). Some filesystems, such as AFS, implement hardlinking
1156 directory). Some filesystems, such as AFS, implement hardlinking
1157 incorrectly, but do not report errors. In these cases, use the
1157 incorrectly, but do not report errors. In these cases, use the
1158 --pull option to avoid hardlinking.
1158 --pull option to avoid hardlinking.
1159
1159
1160 In some cases, you can clone repositories and the working
1160 In some cases, you can clone repositories and the working
1161 directory using full hardlinks with ::
1161 directory using full hardlinks with ::
1162
1162
1163 $ cp -al REPO REPOCLONE
1163 $ cp -al REPO REPOCLONE
1164
1164
1165 This is the fastest way to clone, but it is not always safe. The
1165 This is the fastest way to clone, but it is not always safe. The
1166 operation is not atomic (making sure REPO is not modified during
1166 operation is not atomic (making sure REPO is not modified during
1167 the operation is up to you) and you have to make sure your
1167 the operation is up to you) and you have to make sure your
1168 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1168 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1169 so). Also, this is not compatible with certain extensions that
1169 so). Also, this is not compatible with certain extensions that
1170 place their metadata under the .hg directory, such as mq.
1170 place their metadata under the .hg directory, such as mq.
1171
1171
1172 Mercurial will update the working directory to the first applicable
1172 Mercurial will update the working directory to the first applicable
1173 revision from this list:
1173 revision from this list:
1174
1174
1175 a) null if -U or the source repository has no changesets
1175 a) null if -U or the source repository has no changesets
1176 b) if -u . and the source repository is local, the first parent of
1176 b) if -u . and the source repository is local, the first parent of
1177 the source repository's working directory
1177 the source repository's working directory
1178 c) the changeset specified with -u (if a branch name, this means the
1178 c) the changeset specified with -u (if a branch name, this means the
1179 latest head of that branch)
1179 latest head of that branch)
1180 d) the changeset specified with -r
1180 d) the changeset specified with -r
1181 e) the tipmost head specified with -b
1181 e) the tipmost head specified with -b
1182 f) the tipmost head specified with the url#branch source syntax
1182 f) the tipmost head specified with the url#branch source syntax
1183 g) the tipmost head of the default branch
1183 g) the tipmost head of the default branch
1184 h) tip
1184 h) tip
1185
1185
1186 Examples:
1186 Examples:
1187
1187
1188 - clone a remote repository to a new directory named hg/::
1188 - clone a remote repository to a new directory named hg/::
1189
1189
1190 hg clone http://selenic.com/hg
1190 hg clone http://selenic.com/hg
1191
1191
1192 - create a lightweight local clone::
1192 - create a lightweight local clone::
1193
1193
1194 hg clone project/ project-feature/
1194 hg clone project/ project-feature/
1195
1195
1196 - clone from an absolute path on an ssh server (note double-slash)::
1196 - clone from an absolute path on an ssh server (note double-slash)::
1197
1197
1198 hg clone ssh://user@server//home/projects/alpha/
1198 hg clone ssh://user@server//home/projects/alpha/
1199
1199
1200 - do a high-speed clone over a LAN while checking out a
1200 - do a high-speed clone over a LAN while checking out a
1201 specified version::
1201 specified version::
1202
1202
1203 hg clone --uncompressed http://server/repo -u 1.5
1203 hg clone --uncompressed http://server/repo -u 1.5
1204
1204
1205 - create a repository without changesets after a particular revision::
1205 - create a repository without changesets after a particular revision::
1206
1206
1207 hg clone -r 04e544 experimental/ good/
1207 hg clone -r 04e544 experimental/ good/
1208
1208
1209 - clone (and track) a particular named branch::
1209 - clone (and track) a particular named branch::
1210
1210
1211 hg clone http://selenic.com/hg#stable
1211 hg clone http://selenic.com/hg#stable
1212
1212
1213 See :hg:`help urls` for details on specifying URLs.
1213 See :hg:`help urls` for details on specifying URLs.
1214
1214
1215 Returns 0 on success.
1215 Returns 0 on success.
1216 """
1216 """
1217 if opts.get('noupdate') and opts.get('updaterev'):
1217 if opts.get('noupdate') and opts.get('updaterev'):
1218 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1218 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1219
1219
1220 r = hg.clone(ui, opts, source, dest,
1220 r = hg.clone(ui, opts, source, dest,
1221 pull=opts.get('pull'),
1221 pull=opts.get('pull'),
1222 stream=opts.get('uncompressed'),
1222 stream=opts.get('uncompressed'),
1223 rev=opts.get('rev'),
1223 rev=opts.get('rev'),
1224 update=opts.get('updaterev') or not opts.get('noupdate'),
1224 update=opts.get('updaterev') or not opts.get('noupdate'),
1225 branch=opts.get('branch'))
1225 branch=opts.get('branch'))
1226
1226
1227 return r is None
1227 return r is None
1228
1228
1229 @command('^commit|ci',
1229 @command('^commit|ci',
1230 [('A', 'addremove', None,
1230 [('A', 'addremove', None,
1231 _('mark new/missing files as added/removed before committing')),
1231 _('mark new/missing files as added/removed before committing')),
1232 ('', 'close-branch', None,
1232 ('', 'close-branch', None,
1233 _('mark a branch as closed, hiding it from the branch list')),
1233 _('mark a branch as closed, hiding it from the branch list')),
1234 ('', 'amend', None, _('amend the parent of the working dir')),
1234 ('', 'amend', None, _('amend the parent of the working dir')),
1235 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1235 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1236 _('[OPTION]... [FILE]...'))
1236 _('[OPTION]... [FILE]...'))
1237 def commit(ui, repo, *pats, **opts):
1237 def commit(ui, repo, *pats, **opts):
1238 """commit the specified files or all outstanding changes
1238 """commit the specified files or all outstanding changes
1239
1239
1240 Commit changes to the given files into the repository. Unlike a
1240 Commit changes to the given files into the repository. Unlike a
1241 centralized SCM, this operation is a local operation. See
1241 centralized SCM, this operation is a local operation. See
1242 :hg:`push` for a way to actively distribute your changes.
1242 :hg:`push` for a way to actively distribute your changes.
1243
1243
1244 If a list of files is omitted, all changes reported by :hg:`status`
1244 If a list of files is omitted, all changes reported by :hg:`status`
1245 will be committed.
1245 will be committed.
1246
1246
1247 If you are committing the result of a merge, do not provide any
1247 If you are committing the result of a merge, do not provide any
1248 filenames or -I/-X filters.
1248 filenames or -I/-X filters.
1249
1249
1250 If no commit message is specified, Mercurial starts your
1250 If no commit message is specified, Mercurial starts your
1251 configured editor where you can enter a message. In case your
1251 configured editor where you can enter a message. In case your
1252 commit fails, you will find a backup of your message in
1252 commit fails, you will find a backup of your message in
1253 ``.hg/last-message.txt``.
1253 ``.hg/last-message.txt``.
1254
1254
1255 The --amend flag can be used to amend the parent of the
1255 The --amend flag can be used to amend the parent of the
1256 working directory with a new commit that contains the changes
1256 working directory with a new commit that contains the changes
1257 in the parent in addition to those currently reported by :hg:`status`,
1257 in the parent in addition to those currently reported by :hg:`status`,
1258 if there are any. The old commit is stored in a backup bundle in
1258 if there are any. The old commit is stored in a backup bundle in
1259 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1259 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1260 on how to restore it).
1260 on how to restore it).
1261
1261
1262 Message, user and date are taken from the amended commit unless
1262 Message, user and date are taken from the amended commit unless
1263 specified. When a message isn't specified on the command line,
1263 specified. When a message isn't specified on the command line,
1264 the editor will open with the message of the amended commit.
1264 the editor will open with the message of the amended commit.
1265
1265
1266 It is not possible to amend public changesets (see :hg:`help phases`)
1266 It is not possible to amend public changesets (see :hg:`help phases`)
1267 or changesets that have children.
1267 or changesets that have children.
1268
1268
1269 See :hg:`help dates` for a list of formats valid for -d/--date.
1269 See :hg:`help dates` for a list of formats valid for -d/--date.
1270
1270
1271 Returns 0 on success, 1 if nothing changed.
1271 Returns 0 on success, 1 if nothing changed.
1272 """
1272 """
1273 if opts.get('subrepos'):
1273 if opts.get('subrepos'):
1274 # Let --subrepos on the command line override config setting.
1274 # Let --subrepos on the command line override config setting.
1275 ui.setconfig('ui', 'commitsubrepos', True)
1275 ui.setconfig('ui', 'commitsubrepos', True)
1276
1276
1277 extra = {}
1277 extra = {}
1278 if opts.get('close_branch'):
1278 if opts.get('close_branch'):
1279 if repo['.'].node() not in repo.branchheads():
1279 if repo['.'].node() not in repo.branchheads():
1280 # The topo heads set is included in the branch heads set of the
1280 # The topo heads set is included in the branch heads set of the
1281 # current branch, so it's sufficient to test branchheads
1281 # current branch, so it's sufficient to test branchheads
1282 raise util.Abort(_('can only close branch heads'))
1282 raise util.Abort(_('can only close branch heads'))
1283 extra['close'] = 1
1283 extra['close'] = 1
1284
1284
1285 branch = repo[None].branch()
1285 branch = repo[None].branch()
1286 bheads = repo.branchheads(branch)
1286 bheads = repo.branchheads(branch)
1287
1287
1288 if opts.get('amend'):
1288 if opts.get('amend'):
1289 if ui.configbool('ui', 'commitsubrepos'):
1289 if ui.configbool('ui', 'commitsubrepos'):
1290 raise util.Abort(_('cannot amend recursively'))
1290 raise util.Abort(_('cannot amend recursively'))
1291
1291
1292 old = repo['.']
1292 old = repo['.']
1293 if old.phase() == phases.public:
1293 if old.phase() == phases.public:
1294 raise util.Abort(_('cannot amend public changesets'))
1294 raise util.Abort(_('cannot amend public changesets'))
1295 if len(old.parents()) > 1:
1295 if len(old.parents()) > 1:
1296 raise util.Abort(_('cannot amend merge changesets'))
1296 raise util.Abort(_('cannot amend merge changesets'))
1297 if len(repo[None].parents()) > 1:
1297 if len(repo[None].parents()) > 1:
1298 raise util.Abort(_('cannot amend while merging'))
1298 raise util.Abort(_('cannot amend while merging'))
1299 if (not obsolete._enabled) and old.children():
1299 if (not obsolete._enabled) and old.children():
1300 raise util.Abort(_('cannot amend changeset with children'))
1300 raise util.Abort(_('cannot amend changeset with children'))
1301
1301
1302 e = cmdutil.commiteditor
1302 e = cmdutil.commiteditor
1303 if opts.get('force_editor'):
1303 if opts.get('force_editor'):
1304 e = cmdutil.commitforceeditor
1304 e = cmdutil.commitforceeditor
1305
1305
1306 def commitfunc(ui, repo, message, match, opts):
1306 def commitfunc(ui, repo, message, match, opts):
1307 editor = e
1307 editor = e
1308 # message contains text from -m or -l, if it's empty,
1308 # message contains text from -m or -l, if it's empty,
1309 # open the editor with the old message
1309 # open the editor with the old message
1310 if not message:
1310 if not message:
1311 message = old.description()
1311 message = old.description()
1312 editor = cmdutil.commitforceeditor
1312 editor = cmdutil.commitforceeditor
1313 return repo.commit(message,
1313 return repo.commit(message,
1314 opts.get('user') or old.user(),
1314 opts.get('user') or old.user(),
1315 opts.get('date') or old.date(),
1315 opts.get('date') or old.date(),
1316 match,
1316 match,
1317 editor=editor,
1317 editor=editor,
1318 extra=extra)
1318 extra=extra)
1319
1319
1320 current = repo._bookmarkcurrent
1320 current = repo._bookmarkcurrent
1321 marks = old.bookmarks()
1321 marks = old.bookmarks()
1322 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1322 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1323 if node == old.node():
1323 if node == old.node():
1324 ui.status(_("nothing changed\n"))
1324 ui.status(_("nothing changed\n"))
1325 return 1
1325 return 1
1326 elif marks:
1326 elif marks:
1327 ui.debug('moving bookmarks %r from %s to %s\n' %
1327 ui.debug('moving bookmarks %r from %s to %s\n' %
1328 (marks, old.hex(), hex(node)))
1328 (marks, old.hex(), hex(node)))
1329 newmarks = repo._bookmarks
1329 newmarks = repo._bookmarks
1330 for bm in marks:
1330 for bm in marks:
1331 newmarks[bm] = node
1331 newmarks[bm] = node
1332 if bm == current:
1332 if bm == current:
1333 bookmarks.setcurrent(repo, bm)
1333 bookmarks.setcurrent(repo, bm)
1334 newmarks.write()
1334 newmarks.write()
1335 else:
1335 else:
1336 e = cmdutil.commiteditor
1336 e = cmdutil.commiteditor
1337 if opts.get('force_editor'):
1337 if opts.get('force_editor'):
1338 e = cmdutil.commitforceeditor
1338 e = cmdutil.commitforceeditor
1339
1339
1340 def commitfunc(ui, repo, message, match, opts):
1340 def commitfunc(ui, repo, message, match, opts):
1341 return repo.commit(message, opts.get('user'), opts.get('date'),
1341 return repo.commit(message, opts.get('user'), opts.get('date'),
1342 match, editor=e, extra=extra)
1342 match, editor=e, extra=extra)
1343
1343
1344 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1344 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1345
1345
1346 if not node:
1346 if not node:
1347 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1347 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1348 if stat[3]:
1348 if stat[3]:
1349 ui.status(_("nothing changed (%d missing files, see "
1349 ui.status(_("nothing changed (%d missing files, see "
1350 "'hg status')\n") % len(stat[3]))
1350 "'hg status')\n") % len(stat[3]))
1351 else:
1351 else:
1352 ui.status(_("nothing changed\n"))
1352 ui.status(_("nothing changed\n"))
1353 return 1
1353 return 1
1354
1354
1355 ctx = repo[node]
1355 ctx = repo[node]
1356 parents = ctx.parents()
1356 parents = ctx.parents()
1357
1357
1358 if (not opts.get('amend') and bheads and node not in bheads and not
1358 if (not opts.get('amend') and bheads and node not in bheads and not
1359 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1359 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1360 ui.status(_('created new head\n'))
1360 ui.status(_('created new head\n'))
1361 # The message is not printed for initial roots. For the other
1361 # The message is not printed for initial roots. For the other
1362 # changesets, it is printed in the following situations:
1362 # changesets, it is printed in the following situations:
1363 #
1363 #
1364 # Par column: for the 2 parents with ...
1364 # Par column: for the 2 parents with ...
1365 # N: null or no parent
1365 # N: null or no parent
1366 # B: parent is on another named branch
1366 # B: parent is on another named branch
1367 # C: parent is a regular non head changeset
1367 # C: parent is a regular non head changeset
1368 # H: parent was a branch head of the current branch
1368 # H: parent was a branch head of the current branch
1369 # Msg column: whether we print "created new head" message
1369 # Msg column: whether we print "created new head" message
1370 # In the following, it is assumed that there already exists some
1370 # In the following, it is assumed that there already exists some
1371 # initial branch heads of the current branch, otherwise nothing is
1371 # initial branch heads of the current branch, otherwise nothing is
1372 # printed anyway.
1372 # printed anyway.
1373 #
1373 #
1374 # Par Msg Comment
1374 # Par Msg Comment
1375 # N N y additional topo root
1375 # N N y additional topo root
1376 #
1376 #
1377 # B N y additional branch root
1377 # B N y additional branch root
1378 # C N y additional topo head
1378 # C N y additional topo head
1379 # H N n usual case
1379 # H N n usual case
1380 #
1380 #
1381 # B B y weird additional branch root
1381 # B B y weird additional branch root
1382 # C B y branch merge
1382 # C B y branch merge
1383 # H B n merge with named branch
1383 # H B n merge with named branch
1384 #
1384 #
1385 # C C y additional head from merge
1385 # C C y additional head from merge
1386 # C H n merge with a head
1386 # C H n merge with a head
1387 #
1387 #
1388 # H H n head merge: head count decreases
1388 # H H n head merge: head count decreases
1389
1389
1390 if not opts.get('close_branch'):
1390 if not opts.get('close_branch'):
1391 for r in parents:
1391 for r in parents:
1392 if r.closesbranch() and r.branch() == branch:
1392 if r.closesbranch() and r.branch() == branch:
1393 ui.status(_('reopening closed branch head %d\n') % r)
1393 ui.status(_('reopening closed branch head %d\n') % r)
1394
1394
1395 if ui.debugflag:
1395 if ui.debugflag:
1396 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1396 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1397 elif ui.verbose:
1397 elif ui.verbose:
1398 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1398 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1399
1399
1400 @command('copy|cp',
1400 @command('copy|cp',
1401 [('A', 'after', None, _('record a copy that has already occurred')),
1401 [('A', 'after', None, _('record a copy that has already occurred')),
1402 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1402 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1403 ] + walkopts + dryrunopts,
1403 ] + walkopts + dryrunopts,
1404 _('[OPTION]... [SOURCE]... DEST'))
1404 _('[OPTION]... [SOURCE]... DEST'))
1405 def copy(ui, repo, *pats, **opts):
1405 def copy(ui, repo, *pats, **opts):
1406 """mark files as copied for the next commit
1406 """mark files as copied for the next commit
1407
1407
1408 Mark dest as having copies of source files. If dest is a
1408 Mark dest as having copies of source files. If dest is a
1409 directory, copies are put in that directory. If dest is a file,
1409 directory, copies are put in that directory. If dest is a file,
1410 the source must be a single file.
1410 the source must be a single file.
1411
1411
1412 By default, this command copies the contents of files as they
1412 By default, this command copies the contents of files as they
1413 exist in the working directory. If invoked with -A/--after, the
1413 exist in the working directory. If invoked with -A/--after, the
1414 operation is recorded, but no copying is performed.
1414 operation is recorded, but no copying is performed.
1415
1415
1416 This command takes effect with the next commit. To undo a copy
1416 This command takes effect with the next commit. To undo a copy
1417 before that, see :hg:`revert`.
1417 before that, see :hg:`revert`.
1418
1418
1419 Returns 0 on success, 1 if errors are encountered.
1419 Returns 0 on success, 1 if errors are encountered.
1420 """
1420 """
1421 wlock = repo.wlock(False)
1421 wlock = repo.wlock(False)
1422 try:
1422 try:
1423 return cmdutil.copy(ui, repo, pats, opts)
1423 return cmdutil.copy(ui, repo, pats, opts)
1424 finally:
1424 finally:
1425 wlock.release()
1425 wlock.release()
1426
1426
1427 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1427 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1428 def debugancestor(ui, repo, *args):
1428 def debugancestor(ui, repo, *args):
1429 """find the ancestor revision of two revisions in a given index"""
1429 """find the ancestor revision of two revisions in a given index"""
1430 if len(args) == 3:
1430 if len(args) == 3:
1431 index, rev1, rev2 = args
1431 index, rev1, rev2 = args
1432 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1432 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1433 lookup = r.lookup
1433 lookup = r.lookup
1434 elif len(args) == 2:
1434 elif len(args) == 2:
1435 if not repo:
1435 if not repo:
1436 raise util.Abort(_("there is no Mercurial repository here "
1436 raise util.Abort(_("there is no Mercurial repository here "
1437 "(.hg not found)"))
1437 "(.hg not found)"))
1438 rev1, rev2 = args
1438 rev1, rev2 = args
1439 r = repo.changelog
1439 r = repo.changelog
1440 lookup = repo.lookup
1440 lookup = repo.lookup
1441 else:
1441 else:
1442 raise util.Abort(_('either two or three arguments required'))
1442 raise util.Abort(_('either two or three arguments required'))
1443 a = r.ancestor(lookup(rev1), lookup(rev2))
1443 a = r.ancestor(lookup(rev1), lookup(rev2))
1444 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1444 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1445
1445
1446 @command('debugbuilddag',
1446 @command('debugbuilddag',
1447 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1447 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1448 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1448 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1449 ('n', 'new-file', None, _('add new file at each rev'))],
1449 ('n', 'new-file', None, _('add new file at each rev'))],
1450 _('[OPTION]... [TEXT]'))
1450 _('[OPTION]... [TEXT]'))
1451 def debugbuilddag(ui, repo, text=None,
1451 def debugbuilddag(ui, repo, text=None,
1452 mergeable_file=False,
1452 mergeable_file=False,
1453 overwritten_file=False,
1453 overwritten_file=False,
1454 new_file=False):
1454 new_file=False):
1455 """builds a repo with a given DAG from scratch in the current empty repo
1455 """builds a repo with a given DAG from scratch in the current empty repo
1456
1456
1457 The description of the DAG is read from stdin if not given on the
1457 The description of the DAG is read from stdin if not given on the
1458 command line.
1458 command line.
1459
1459
1460 Elements:
1460 Elements:
1461
1461
1462 - "+n" is a linear run of n nodes based on the current default parent
1462 - "+n" is a linear run of n nodes based on the current default parent
1463 - "." is a single node based on the current default parent
1463 - "." is a single node based on the current default parent
1464 - "$" resets the default parent to null (implied at the start);
1464 - "$" resets the default parent to null (implied at the start);
1465 otherwise the default parent is always the last node created
1465 otherwise the default parent is always the last node created
1466 - "<p" sets the default parent to the backref p
1466 - "<p" sets the default parent to the backref p
1467 - "*p" is a fork at parent p, which is a backref
1467 - "*p" is a fork at parent p, which is a backref
1468 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1468 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1469 - "/p2" is a merge of the preceding node and p2
1469 - "/p2" is a merge of the preceding node and p2
1470 - ":tag" defines a local tag for the preceding node
1470 - ":tag" defines a local tag for the preceding node
1471 - "@branch" sets the named branch for subsequent nodes
1471 - "@branch" sets the named branch for subsequent nodes
1472 - "#...\\n" is a comment up to the end of the line
1472 - "#...\\n" is a comment up to the end of the line
1473
1473
1474 Whitespace between the above elements is ignored.
1474 Whitespace between the above elements is ignored.
1475
1475
1476 A backref is either
1476 A backref is either
1477
1477
1478 - a number n, which references the node curr-n, where curr is the current
1478 - a number n, which references the node curr-n, where curr is the current
1479 node, or
1479 node, or
1480 - the name of a local tag you placed earlier using ":tag", or
1480 - the name of a local tag you placed earlier using ":tag", or
1481 - empty to denote the default parent.
1481 - empty to denote the default parent.
1482
1482
1483 All string valued-elements are either strictly alphanumeric, or must
1483 All string valued-elements are either strictly alphanumeric, or must
1484 be enclosed in double quotes ("..."), with "\\" as escape character.
1484 be enclosed in double quotes ("..."), with "\\" as escape character.
1485 """
1485 """
1486
1486
1487 if text is None:
1487 if text is None:
1488 ui.status(_("reading DAG from stdin\n"))
1488 ui.status(_("reading DAG from stdin\n"))
1489 text = ui.fin.read()
1489 text = ui.fin.read()
1490
1490
1491 cl = repo.changelog
1491 cl = repo.changelog
1492 if len(cl) > 0:
1492 if len(cl) > 0:
1493 raise util.Abort(_('repository is not empty'))
1493 raise util.Abort(_('repository is not empty'))
1494
1494
1495 # determine number of revs in DAG
1495 # determine number of revs in DAG
1496 total = 0
1496 total = 0
1497 for type, data in dagparser.parsedag(text):
1497 for type, data in dagparser.parsedag(text):
1498 if type == 'n':
1498 if type == 'n':
1499 total += 1
1499 total += 1
1500
1500
1501 if mergeable_file:
1501 if mergeable_file:
1502 linesperrev = 2
1502 linesperrev = 2
1503 # make a file with k lines per rev
1503 # make a file with k lines per rev
1504 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1504 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1505 initialmergedlines.append("")
1505 initialmergedlines.append("")
1506
1506
1507 tags = []
1507 tags = []
1508
1508
1509 lock = tr = None
1509 lock = tr = None
1510 try:
1510 try:
1511 lock = repo.lock()
1511 lock = repo.lock()
1512 tr = repo.transaction("builddag")
1512 tr = repo.transaction("builddag")
1513
1513
1514 at = -1
1514 at = -1
1515 atbranch = 'default'
1515 atbranch = 'default'
1516 nodeids = []
1516 nodeids = []
1517 id = 0
1517 id = 0
1518 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1518 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1519 for type, data in dagparser.parsedag(text):
1519 for type, data in dagparser.parsedag(text):
1520 if type == 'n':
1520 if type == 'n':
1521 ui.note(('node %s\n' % str(data)))
1521 ui.note(('node %s\n' % str(data)))
1522 id, ps = data
1522 id, ps = data
1523
1523
1524 files = []
1524 files = []
1525 fctxs = {}
1525 fctxs = {}
1526
1526
1527 p2 = None
1527 p2 = None
1528 if mergeable_file:
1528 if mergeable_file:
1529 fn = "mf"
1529 fn = "mf"
1530 p1 = repo[ps[0]]
1530 p1 = repo[ps[0]]
1531 if len(ps) > 1:
1531 if len(ps) > 1:
1532 p2 = repo[ps[1]]
1532 p2 = repo[ps[1]]
1533 pa = p1.ancestor(p2)
1533 pa = p1.ancestor(p2)
1534 base, local, other = [x[fn].data() for x in (pa, p1,
1534 base, local, other = [x[fn].data() for x in (pa, p1,
1535 p2)]
1535 p2)]
1536 m3 = simplemerge.Merge3Text(base, local, other)
1536 m3 = simplemerge.Merge3Text(base, local, other)
1537 ml = [l.strip() for l in m3.merge_lines()]
1537 ml = [l.strip() for l in m3.merge_lines()]
1538 ml.append("")
1538 ml.append("")
1539 elif at > 0:
1539 elif at > 0:
1540 ml = p1[fn].data().split("\n")
1540 ml = p1[fn].data().split("\n")
1541 else:
1541 else:
1542 ml = initialmergedlines
1542 ml = initialmergedlines
1543 ml[id * linesperrev] += " r%i" % id
1543 ml[id * linesperrev] += " r%i" % id
1544 mergedtext = "\n".join(ml)
1544 mergedtext = "\n".join(ml)
1545 files.append(fn)
1545 files.append(fn)
1546 fctxs[fn] = context.memfilectx(fn, mergedtext)
1546 fctxs[fn] = context.memfilectx(fn, mergedtext)
1547
1547
1548 if overwritten_file:
1548 if overwritten_file:
1549 fn = "of"
1549 fn = "of"
1550 files.append(fn)
1550 files.append(fn)
1551 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1551 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1552
1552
1553 if new_file:
1553 if new_file:
1554 fn = "nf%i" % id
1554 fn = "nf%i" % id
1555 files.append(fn)
1555 files.append(fn)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557 if len(ps) > 1:
1557 if len(ps) > 1:
1558 if not p2:
1558 if not p2:
1559 p2 = repo[ps[1]]
1559 p2 = repo[ps[1]]
1560 for fn in p2:
1560 for fn in p2:
1561 if fn.startswith("nf"):
1561 if fn.startswith("nf"):
1562 files.append(fn)
1562 files.append(fn)
1563 fctxs[fn] = p2[fn]
1563 fctxs[fn] = p2[fn]
1564
1564
1565 def fctxfn(repo, cx, path):
1565 def fctxfn(repo, cx, path):
1566 return fctxs.get(path)
1566 return fctxs.get(path)
1567
1567
1568 if len(ps) == 0 or ps[0] < 0:
1568 if len(ps) == 0 or ps[0] < 0:
1569 pars = [None, None]
1569 pars = [None, None]
1570 elif len(ps) == 1:
1570 elif len(ps) == 1:
1571 pars = [nodeids[ps[0]], None]
1571 pars = [nodeids[ps[0]], None]
1572 else:
1572 else:
1573 pars = [nodeids[p] for p in ps]
1573 pars = [nodeids[p] for p in ps]
1574 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1574 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1575 date=(id, 0),
1575 date=(id, 0),
1576 user="debugbuilddag",
1576 user="debugbuilddag",
1577 extra={'branch': atbranch})
1577 extra={'branch': atbranch})
1578 nodeid = repo.commitctx(cx)
1578 nodeid = repo.commitctx(cx)
1579 nodeids.append(nodeid)
1579 nodeids.append(nodeid)
1580 at = id
1580 at = id
1581 elif type == 'l':
1581 elif type == 'l':
1582 id, name = data
1582 id, name = data
1583 ui.note(('tag %s\n' % name))
1583 ui.note(('tag %s\n' % name))
1584 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1584 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1585 elif type == 'a':
1585 elif type == 'a':
1586 ui.note(('branch %s\n' % data))
1586 ui.note(('branch %s\n' % data))
1587 atbranch = data
1587 atbranch = data
1588 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1588 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1589 tr.close()
1589 tr.close()
1590
1590
1591 if tags:
1591 if tags:
1592 repo.opener.write("localtags", "".join(tags))
1592 repo.opener.write("localtags", "".join(tags))
1593 finally:
1593 finally:
1594 ui.progress(_('building'), None)
1594 ui.progress(_('building'), None)
1595 release(tr, lock)
1595 release(tr, lock)
1596
1596
1597 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1597 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1598 def debugbundle(ui, bundlepath, all=None, **opts):
1598 def debugbundle(ui, bundlepath, all=None, **opts):
1599 """lists the contents of a bundle"""
1599 """lists the contents of a bundle"""
1600 f = hg.openpath(ui, bundlepath)
1600 f = hg.openpath(ui, bundlepath)
1601 try:
1601 try:
1602 gen = changegroup.readbundle(f, bundlepath)
1602 gen = changegroup.readbundle(f, bundlepath)
1603 if all:
1603 if all:
1604 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1604 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1605
1605
1606 def showchunks(named):
1606 def showchunks(named):
1607 ui.write("\n%s\n" % named)
1607 ui.write("\n%s\n" % named)
1608 chain = None
1608 chain = None
1609 while True:
1609 while True:
1610 chunkdata = gen.deltachunk(chain)
1610 chunkdata = gen.deltachunk(chain)
1611 if not chunkdata:
1611 if not chunkdata:
1612 break
1612 break
1613 node = chunkdata['node']
1613 node = chunkdata['node']
1614 p1 = chunkdata['p1']
1614 p1 = chunkdata['p1']
1615 p2 = chunkdata['p2']
1615 p2 = chunkdata['p2']
1616 cs = chunkdata['cs']
1616 cs = chunkdata['cs']
1617 deltabase = chunkdata['deltabase']
1617 deltabase = chunkdata['deltabase']
1618 delta = chunkdata['delta']
1618 delta = chunkdata['delta']
1619 ui.write("%s %s %s %s %s %s\n" %
1619 ui.write("%s %s %s %s %s %s\n" %
1620 (hex(node), hex(p1), hex(p2),
1620 (hex(node), hex(p1), hex(p2),
1621 hex(cs), hex(deltabase), len(delta)))
1621 hex(cs), hex(deltabase), len(delta)))
1622 chain = node
1622 chain = node
1623
1623
1624 chunkdata = gen.changelogheader()
1624 chunkdata = gen.changelogheader()
1625 showchunks("changelog")
1625 showchunks("changelog")
1626 chunkdata = gen.manifestheader()
1626 chunkdata = gen.manifestheader()
1627 showchunks("manifest")
1627 showchunks("manifest")
1628 while True:
1628 while True:
1629 chunkdata = gen.filelogheader()
1629 chunkdata = gen.filelogheader()
1630 if not chunkdata:
1630 if not chunkdata:
1631 break
1631 break
1632 fname = chunkdata['filename']
1632 fname = chunkdata['filename']
1633 showchunks(fname)
1633 showchunks(fname)
1634 else:
1634 else:
1635 chunkdata = gen.changelogheader()
1635 chunkdata = gen.changelogheader()
1636 chain = None
1636 chain = None
1637 while True:
1637 while True:
1638 chunkdata = gen.deltachunk(chain)
1638 chunkdata = gen.deltachunk(chain)
1639 if not chunkdata:
1639 if not chunkdata:
1640 break
1640 break
1641 node = chunkdata['node']
1641 node = chunkdata['node']
1642 ui.write("%s\n" % hex(node))
1642 ui.write("%s\n" % hex(node))
1643 chain = node
1643 chain = node
1644 finally:
1644 finally:
1645 f.close()
1645 f.close()
1646
1646
1647 @command('debugcheckstate', [], '')
1647 @command('debugcheckstate', [], '')
1648 def debugcheckstate(ui, repo):
1648 def debugcheckstate(ui, repo):
1649 """validate the correctness of the current dirstate"""
1649 """validate the correctness of the current dirstate"""
1650 parent1, parent2 = repo.dirstate.parents()
1650 parent1, parent2 = repo.dirstate.parents()
1651 m1 = repo[parent1].manifest()
1651 m1 = repo[parent1].manifest()
1652 m2 = repo[parent2].manifest()
1652 m2 = repo[parent2].manifest()
1653 errors = 0
1653 errors = 0
1654 for f in repo.dirstate:
1654 for f in repo.dirstate:
1655 state = repo.dirstate[f]
1655 state = repo.dirstate[f]
1656 if state in "nr" and f not in m1:
1656 if state in "nr" and f not in m1:
1657 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1657 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1658 errors += 1
1658 errors += 1
1659 if state in "a" and f in m1:
1659 if state in "a" and f in m1:
1660 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1660 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1661 errors += 1
1661 errors += 1
1662 if state in "m" and f not in m1 and f not in m2:
1662 if state in "m" and f not in m1 and f not in m2:
1663 ui.warn(_("%s in state %s, but not in either manifest\n") %
1663 ui.warn(_("%s in state %s, but not in either manifest\n") %
1664 (f, state))
1664 (f, state))
1665 errors += 1
1665 errors += 1
1666 for f in m1:
1666 for f in m1:
1667 state = repo.dirstate[f]
1667 state = repo.dirstate[f]
1668 if state not in "nrm":
1668 if state not in "nrm":
1669 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1669 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1670 errors += 1
1670 errors += 1
1671 if errors:
1671 if errors:
1672 error = _(".hg/dirstate inconsistent with current parent's manifest")
1672 error = _(".hg/dirstate inconsistent with current parent's manifest")
1673 raise util.Abort(error)
1673 raise util.Abort(error)
1674
1674
1675 @command('debugcommands', [], _('[COMMAND]'))
1675 @command('debugcommands', [], _('[COMMAND]'))
1676 def debugcommands(ui, cmd='', *args):
1676 def debugcommands(ui, cmd='', *args):
1677 """list all available commands and options"""
1677 """list all available commands and options"""
1678 for cmd, vals in sorted(table.iteritems()):
1678 for cmd, vals in sorted(table.iteritems()):
1679 cmd = cmd.split('|')[0].strip('^')
1679 cmd = cmd.split('|')[0].strip('^')
1680 opts = ', '.join([i[1] for i in vals[1]])
1680 opts = ', '.join([i[1] for i in vals[1]])
1681 ui.write('%s: %s\n' % (cmd, opts))
1681 ui.write('%s: %s\n' % (cmd, opts))
1682
1682
1683 @command('debugcomplete',
1683 @command('debugcomplete',
1684 [('o', 'options', None, _('show the command options'))],
1684 [('o', 'options', None, _('show the command options'))],
1685 _('[-o] CMD'))
1685 _('[-o] CMD'))
1686 def debugcomplete(ui, cmd='', **opts):
1686 def debugcomplete(ui, cmd='', **opts):
1687 """returns the completion list associated with the given command"""
1687 """returns the completion list associated with the given command"""
1688
1688
1689 if opts.get('options'):
1689 if opts.get('options'):
1690 options = []
1690 options = []
1691 otables = [globalopts]
1691 otables = [globalopts]
1692 if cmd:
1692 if cmd:
1693 aliases, entry = cmdutil.findcmd(cmd, table, False)
1693 aliases, entry = cmdutil.findcmd(cmd, table, False)
1694 otables.append(entry[1])
1694 otables.append(entry[1])
1695 for t in otables:
1695 for t in otables:
1696 for o in t:
1696 for o in t:
1697 if "(DEPRECATED)" in o[3]:
1697 if "(DEPRECATED)" in o[3]:
1698 continue
1698 continue
1699 if o[0]:
1699 if o[0]:
1700 options.append('-%s' % o[0])
1700 options.append('-%s' % o[0])
1701 options.append('--%s' % o[1])
1701 options.append('--%s' % o[1])
1702 ui.write("%s\n" % "\n".join(options))
1702 ui.write("%s\n" % "\n".join(options))
1703 return
1703 return
1704
1704
1705 cmdlist = cmdutil.findpossible(cmd, table)
1705 cmdlist = cmdutil.findpossible(cmd, table)
1706 if ui.verbose:
1706 if ui.verbose:
1707 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1707 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1708 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1708 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1709
1709
1710 @command('debugdag',
1710 @command('debugdag',
1711 [('t', 'tags', None, _('use tags as labels')),
1711 [('t', 'tags', None, _('use tags as labels')),
1712 ('b', 'branches', None, _('annotate with branch names')),
1712 ('b', 'branches', None, _('annotate with branch names')),
1713 ('', 'dots', None, _('use dots for runs')),
1713 ('', 'dots', None, _('use dots for runs')),
1714 ('s', 'spaces', None, _('separate elements by spaces'))],
1714 ('s', 'spaces', None, _('separate elements by spaces'))],
1715 _('[OPTION]... [FILE [REV]...]'))
1715 _('[OPTION]... [FILE [REV]...]'))
1716 def debugdag(ui, repo, file_=None, *revs, **opts):
1716 def debugdag(ui, repo, file_=None, *revs, **opts):
1717 """format the changelog or an index DAG as a concise textual description
1717 """format the changelog or an index DAG as a concise textual description
1718
1718
1719 If you pass a revlog index, the revlog's DAG is emitted. If you list
1719 If you pass a revlog index, the revlog's DAG is emitted. If you list
1720 revision numbers, they get labeled in the output as rN.
1720 revision numbers, they get labeled in the output as rN.
1721
1721
1722 Otherwise, the changelog DAG of the current repo is emitted.
1722 Otherwise, the changelog DAG of the current repo is emitted.
1723 """
1723 """
1724 spaces = opts.get('spaces')
1724 spaces = opts.get('spaces')
1725 dots = opts.get('dots')
1725 dots = opts.get('dots')
1726 if file_:
1726 if file_:
1727 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1727 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1728 revs = set((int(r) for r in revs))
1728 revs = set((int(r) for r in revs))
1729 def events():
1729 def events():
1730 for r in rlog:
1730 for r in rlog:
1731 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1731 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1732 if p != -1)))
1732 if p != -1)))
1733 if r in revs:
1733 if r in revs:
1734 yield 'l', (r, "r%i" % r)
1734 yield 'l', (r, "r%i" % r)
1735 elif repo:
1735 elif repo:
1736 cl = repo.changelog
1736 cl = repo.changelog
1737 tags = opts.get('tags')
1737 tags = opts.get('tags')
1738 branches = opts.get('branches')
1738 branches = opts.get('branches')
1739 if tags:
1739 if tags:
1740 labels = {}
1740 labels = {}
1741 for l, n in repo.tags().items():
1741 for l, n in repo.tags().items():
1742 labels.setdefault(cl.rev(n), []).append(l)
1742 labels.setdefault(cl.rev(n), []).append(l)
1743 def events():
1743 def events():
1744 b = "default"
1744 b = "default"
1745 for r in cl:
1745 for r in cl:
1746 if branches:
1746 if branches:
1747 newb = cl.read(cl.node(r))[5]['branch']
1747 newb = cl.read(cl.node(r))[5]['branch']
1748 if newb != b:
1748 if newb != b:
1749 yield 'a', newb
1749 yield 'a', newb
1750 b = newb
1750 b = newb
1751 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1751 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1752 if p != -1)))
1752 if p != -1)))
1753 if tags:
1753 if tags:
1754 ls = labels.get(r)
1754 ls = labels.get(r)
1755 if ls:
1755 if ls:
1756 for l in ls:
1756 for l in ls:
1757 yield 'l', (r, l)
1757 yield 'l', (r, l)
1758 else:
1758 else:
1759 raise util.Abort(_('need repo for changelog dag'))
1759 raise util.Abort(_('need repo for changelog dag'))
1760
1760
1761 for line in dagparser.dagtextlines(events(),
1761 for line in dagparser.dagtextlines(events(),
1762 addspaces=spaces,
1762 addspaces=spaces,
1763 wraplabels=True,
1763 wraplabels=True,
1764 wrapannotations=True,
1764 wrapannotations=True,
1765 wrapnonlinear=dots,
1765 wrapnonlinear=dots,
1766 usedots=dots,
1766 usedots=dots,
1767 maxlinewidth=70):
1767 maxlinewidth=70):
1768 ui.write(line)
1768 ui.write(line)
1769 ui.write("\n")
1769 ui.write("\n")
1770
1770
1771 @command('debugdata',
1771 @command('debugdata',
1772 [('c', 'changelog', False, _('open changelog')),
1772 [('c', 'changelog', False, _('open changelog')),
1773 ('m', 'manifest', False, _('open manifest'))],
1773 ('m', 'manifest', False, _('open manifest'))],
1774 _('-c|-m|FILE REV'))
1774 _('-c|-m|FILE REV'))
1775 def debugdata(ui, repo, file_, rev = None, **opts):
1775 def debugdata(ui, repo, file_, rev = None, **opts):
1776 """dump the contents of a data file revision"""
1776 """dump the contents of a data file revision"""
1777 if opts.get('changelog') or opts.get('manifest'):
1777 if opts.get('changelog') or opts.get('manifest'):
1778 file_, rev = None, file_
1778 file_, rev = None, file_
1779 elif rev is None:
1779 elif rev is None:
1780 raise error.CommandError('debugdata', _('invalid arguments'))
1780 raise error.CommandError('debugdata', _('invalid arguments'))
1781 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1781 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1782 try:
1782 try:
1783 ui.write(r.revision(r.lookup(rev)))
1783 ui.write(r.revision(r.lookup(rev)))
1784 except KeyError:
1784 except KeyError:
1785 raise util.Abort(_('invalid revision identifier %s') % rev)
1785 raise util.Abort(_('invalid revision identifier %s') % rev)
1786
1786
1787 @command('debugdate',
1787 @command('debugdate',
1788 [('e', 'extended', None, _('try extended date formats'))],
1788 [('e', 'extended', None, _('try extended date formats'))],
1789 _('[-e] DATE [RANGE]'))
1789 _('[-e] DATE [RANGE]'))
1790 def debugdate(ui, date, range=None, **opts):
1790 def debugdate(ui, date, range=None, **opts):
1791 """parse and display a date"""
1791 """parse and display a date"""
1792 if opts["extended"]:
1792 if opts["extended"]:
1793 d = util.parsedate(date, util.extendeddateformats)
1793 d = util.parsedate(date, util.extendeddateformats)
1794 else:
1794 else:
1795 d = util.parsedate(date)
1795 d = util.parsedate(date)
1796 ui.write(("internal: %s %s\n") % d)
1796 ui.write(("internal: %s %s\n") % d)
1797 ui.write(("standard: %s\n") % util.datestr(d))
1797 ui.write(("standard: %s\n") % util.datestr(d))
1798 if range:
1798 if range:
1799 m = util.matchdate(range)
1799 m = util.matchdate(range)
1800 ui.write(("match: %s\n") % m(d[0]))
1800 ui.write(("match: %s\n") % m(d[0]))
1801
1801
1802 @command('debugdiscovery',
1802 @command('debugdiscovery',
1803 [('', 'old', None, _('use old-style discovery')),
1803 [('', 'old', None, _('use old-style discovery')),
1804 ('', 'nonheads', None,
1804 ('', 'nonheads', None,
1805 _('use old-style discovery with non-heads included')),
1805 _('use old-style discovery with non-heads included')),
1806 ] + remoteopts,
1806 ] + remoteopts,
1807 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1807 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1808 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1808 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1809 """runs the changeset discovery protocol in isolation"""
1809 """runs the changeset discovery protocol in isolation"""
1810 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1810 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1811 opts.get('branch'))
1811 opts.get('branch'))
1812 remote = hg.peer(repo, opts, remoteurl)
1812 remote = hg.peer(repo, opts, remoteurl)
1813 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1813 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1814
1814
1815 # make sure tests are repeatable
1815 # make sure tests are repeatable
1816 random.seed(12323)
1816 random.seed(12323)
1817
1817
1818 def doit(localheads, remoteheads, remote=remote):
1818 def doit(localheads, remoteheads, remote=remote):
1819 if opts.get('old'):
1819 if opts.get('old'):
1820 if localheads:
1820 if localheads:
1821 raise util.Abort('cannot use localheads with old style '
1821 raise util.Abort('cannot use localheads with old style '
1822 'discovery')
1822 'discovery')
1823 if not util.safehasattr(remote, 'branches'):
1823 if not util.safehasattr(remote, 'branches'):
1824 # enable in-client legacy support
1824 # enable in-client legacy support
1825 remote = localrepo.locallegacypeer(remote.local())
1825 remote = localrepo.locallegacypeer(remote.local())
1826 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1826 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1827 force=True)
1827 force=True)
1828 common = set(common)
1828 common = set(common)
1829 if not opts.get('nonheads'):
1829 if not opts.get('nonheads'):
1830 ui.write(("unpruned common: %s\n") % " ".join([short(n)
1830 ui.write(("unpruned common: %s\n") %
1831 for n in common]))
1831 " ".join(sorted(short(n) for n in common)))
1832 dag = dagutil.revlogdag(repo.changelog)
1832 dag = dagutil.revlogdag(repo.changelog)
1833 all = dag.ancestorset(dag.internalizeall(common))
1833 all = dag.ancestorset(dag.internalizeall(common))
1834 common = dag.externalizeall(dag.headsetofconnecteds(all))
1834 common = dag.externalizeall(dag.headsetofconnecteds(all))
1835 else:
1835 else:
1836 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1836 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1837 common = set(common)
1837 common = set(common)
1838 rheads = set(hds)
1838 rheads = set(hds)
1839 lheads = set(repo.heads())
1839 lheads = set(repo.heads())
1840 ui.write(("common heads: %s\n") % " ".join([short(n) for n in common]))
1840 ui.write(("common heads: %s\n") %
1841 " ".join(sorted(short(n) for n in common)))
1841 if lheads <= common:
1842 if lheads <= common:
1842 ui.write(("local is subset\n"))
1843 ui.write(("local is subset\n"))
1843 elif rheads <= common:
1844 elif rheads <= common:
1844 ui.write(("remote is subset\n"))
1845 ui.write(("remote is subset\n"))
1845
1846
1846 serverlogs = opts.get('serverlog')
1847 serverlogs = opts.get('serverlog')
1847 if serverlogs:
1848 if serverlogs:
1848 for filename in serverlogs:
1849 for filename in serverlogs:
1849 logfile = open(filename, 'r')
1850 logfile = open(filename, 'r')
1850 try:
1851 try:
1851 line = logfile.readline()
1852 line = logfile.readline()
1852 while line:
1853 while line:
1853 parts = line.strip().split(';')
1854 parts = line.strip().split(';')
1854 op = parts[1]
1855 op = parts[1]
1855 if op == 'cg':
1856 if op == 'cg':
1856 pass
1857 pass
1857 elif op == 'cgss':
1858 elif op == 'cgss':
1858 doit(parts[2].split(' '), parts[3].split(' '))
1859 doit(parts[2].split(' '), parts[3].split(' '))
1859 elif op == 'unb':
1860 elif op == 'unb':
1860 doit(parts[3].split(' '), parts[2].split(' '))
1861 doit(parts[3].split(' '), parts[2].split(' '))
1861 line = logfile.readline()
1862 line = logfile.readline()
1862 finally:
1863 finally:
1863 logfile.close()
1864 logfile.close()
1864
1865
1865 else:
1866 else:
1866 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1867 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1867 opts.get('remote_head'))
1868 opts.get('remote_head'))
1868 localrevs = opts.get('local_head')
1869 localrevs = opts.get('local_head')
1869 doit(localrevs, remoterevs)
1870 doit(localrevs, remoterevs)
1870
1871
1871 @command('debugfileset',
1872 @command('debugfileset',
1872 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1873 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1873 _('[-r REV] FILESPEC'))
1874 _('[-r REV] FILESPEC'))
1874 def debugfileset(ui, repo, expr, **opts):
1875 def debugfileset(ui, repo, expr, **opts):
1875 '''parse and apply a fileset specification'''
1876 '''parse and apply a fileset specification'''
1876 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1877 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1877 if ui.verbose:
1878 if ui.verbose:
1878 tree = fileset.parse(expr)[0]
1879 tree = fileset.parse(expr)[0]
1879 ui.note(tree, "\n")
1880 ui.note(tree, "\n")
1880
1881
1881 for f in fileset.getfileset(ctx, expr):
1882 for f in fileset.getfileset(ctx, expr):
1882 ui.write("%s\n" % f)
1883 ui.write("%s\n" % f)
1883
1884
1884 @command('debugfsinfo', [], _('[PATH]'))
1885 @command('debugfsinfo', [], _('[PATH]'))
1885 def debugfsinfo(ui, path = "."):
1886 def debugfsinfo(ui, path = "."):
1886 """show information detected about current filesystem"""
1887 """show information detected about current filesystem"""
1887 util.writefile('.debugfsinfo', '')
1888 util.writefile('.debugfsinfo', '')
1888 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1889 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1889 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1890 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1890 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1891 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1891 and 'yes' or 'no'))
1892 and 'yes' or 'no'))
1892 os.unlink('.debugfsinfo')
1893 os.unlink('.debugfsinfo')
1893
1894
1894 @command('debuggetbundle',
1895 @command('debuggetbundle',
1895 [('H', 'head', [], _('id of head node'), _('ID')),
1896 [('H', 'head', [], _('id of head node'), _('ID')),
1896 ('C', 'common', [], _('id of common node'), _('ID')),
1897 ('C', 'common', [], _('id of common node'), _('ID')),
1897 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1898 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1898 _('REPO FILE [-H|-C ID]...'))
1899 _('REPO FILE [-H|-C ID]...'))
1899 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1900 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1900 """retrieves a bundle from a repo
1901 """retrieves a bundle from a repo
1901
1902
1902 Every ID must be a full-length hex node id string. Saves the bundle to the
1903 Every ID must be a full-length hex node id string. Saves the bundle to the
1903 given file.
1904 given file.
1904 """
1905 """
1905 repo = hg.peer(ui, opts, repopath)
1906 repo = hg.peer(ui, opts, repopath)
1906 if not repo.capable('getbundle'):
1907 if not repo.capable('getbundle'):
1907 raise util.Abort("getbundle() not supported by target repository")
1908 raise util.Abort("getbundle() not supported by target repository")
1908 args = {}
1909 args = {}
1909 if common:
1910 if common:
1910 args['common'] = [bin(s) for s in common]
1911 args['common'] = [bin(s) for s in common]
1911 if head:
1912 if head:
1912 args['heads'] = [bin(s) for s in head]
1913 args['heads'] = [bin(s) for s in head]
1913 bundle = repo.getbundle('debug', **args)
1914 bundle = repo.getbundle('debug', **args)
1914
1915
1915 bundletype = opts.get('type', 'bzip2').lower()
1916 bundletype = opts.get('type', 'bzip2').lower()
1916 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1917 bundletype = btypes.get(bundletype)
1918 bundletype = btypes.get(bundletype)
1918 if bundletype not in changegroup.bundletypes:
1919 if bundletype not in changegroup.bundletypes:
1919 raise util.Abort(_('unknown bundle type specified with --type'))
1920 raise util.Abort(_('unknown bundle type specified with --type'))
1920 changegroup.writebundle(bundle, bundlepath, bundletype)
1921 changegroup.writebundle(bundle, bundlepath, bundletype)
1921
1922
1922 @command('debugignore', [], '')
1923 @command('debugignore', [], '')
1923 def debugignore(ui, repo, *values, **opts):
1924 def debugignore(ui, repo, *values, **opts):
1924 """display the combined ignore pattern"""
1925 """display the combined ignore pattern"""
1925 ignore = repo.dirstate._ignore
1926 ignore = repo.dirstate._ignore
1926 includepat = getattr(ignore, 'includepat', None)
1927 includepat = getattr(ignore, 'includepat', None)
1927 if includepat is not None:
1928 if includepat is not None:
1928 ui.write("%s\n" % includepat)
1929 ui.write("%s\n" % includepat)
1929 else:
1930 else:
1930 raise util.Abort(_("no ignore patterns found"))
1931 raise util.Abort(_("no ignore patterns found"))
1931
1932
1932 @command('debugindex',
1933 @command('debugindex',
1933 [('c', 'changelog', False, _('open changelog')),
1934 [('c', 'changelog', False, _('open changelog')),
1934 ('m', 'manifest', False, _('open manifest')),
1935 ('m', 'manifest', False, _('open manifest')),
1935 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1936 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1936 _('[-f FORMAT] -c|-m|FILE'))
1937 _('[-f FORMAT] -c|-m|FILE'))
1937 def debugindex(ui, repo, file_ = None, **opts):
1938 def debugindex(ui, repo, file_ = None, **opts):
1938 """dump the contents of an index file"""
1939 """dump the contents of an index file"""
1939 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1940 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1940 format = opts.get('format', 0)
1941 format = opts.get('format', 0)
1941 if format not in (0, 1):
1942 if format not in (0, 1):
1942 raise util.Abort(_("unknown format %d") % format)
1943 raise util.Abort(_("unknown format %d") % format)
1943
1944
1944 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1945 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1945 if generaldelta:
1946 if generaldelta:
1946 basehdr = ' delta'
1947 basehdr = ' delta'
1947 else:
1948 else:
1948 basehdr = ' base'
1949 basehdr = ' base'
1949
1950
1950 if format == 0:
1951 if format == 0:
1951 ui.write(" rev offset length " + basehdr + " linkrev"
1952 ui.write(" rev offset length " + basehdr + " linkrev"
1952 " nodeid p1 p2\n")
1953 " nodeid p1 p2\n")
1953 elif format == 1:
1954 elif format == 1:
1954 ui.write(" rev flag offset length"
1955 ui.write(" rev flag offset length"
1955 " size " + basehdr + " link p1 p2"
1956 " size " + basehdr + " link p1 p2"
1956 " nodeid\n")
1957 " nodeid\n")
1957
1958
1958 for i in r:
1959 for i in r:
1959 node = r.node(i)
1960 node = r.node(i)
1960 if generaldelta:
1961 if generaldelta:
1961 base = r.deltaparent(i)
1962 base = r.deltaparent(i)
1962 else:
1963 else:
1963 base = r.chainbase(i)
1964 base = r.chainbase(i)
1964 if format == 0:
1965 if format == 0:
1965 try:
1966 try:
1966 pp = r.parents(node)
1967 pp = r.parents(node)
1967 except Exception:
1968 except Exception:
1968 pp = [nullid, nullid]
1969 pp = [nullid, nullid]
1969 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1970 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1970 i, r.start(i), r.length(i), base, r.linkrev(i),
1971 i, r.start(i), r.length(i), base, r.linkrev(i),
1971 short(node), short(pp[0]), short(pp[1])))
1972 short(node), short(pp[0]), short(pp[1])))
1972 elif format == 1:
1973 elif format == 1:
1973 pr = r.parentrevs(i)
1974 pr = r.parentrevs(i)
1974 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1975 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1975 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1976 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1976 base, r.linkrev(i), pr[0], pr[1], short(node)))
1977 base, r.linkrev(i), pr[0], pr[1], short(node)))
1977
1978
1978 @command('debugindexdot', [], _('FILE'))
1979 @command('debugindexdot', [], _('FILE'))
1979 def debugindexdot(ui, repo, file_):
1980 def debugindexdot(ui, repo, file_):
1980 """dump an index DAG as a graphviz dot file"""
1981 """dump an index DAG as a graphviz dot file"""
1981 r = None
1982 r = None
1982 if repo:
1983 if repo:
1983 filelog = repo.file(file_)
1984 filelog = repo.file(file_)
1984 if len(filelog):
1985 if len(filelog):
1985 r = filelog
1986 r = filelog
1986 if not r:
1987 if not r:
1987 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1988 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1988 ui.write(("digraph G {\n"))
1989 ui.write(("digraph G {\n"))
1989 for i in r:
1990 for i in r:
1990 node = r.node(i)
1991 node = r.node(i)
1991 pp = r.parents(node)
1992 pp = r.parents(node)
1992 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1993 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1993 if pp[1] != nullid:
1994 if pp[1] != nullid:
1994 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1995 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1995 ui.write("}\n")
1996 ui.write("}\n")
1996
1997
1997 @command('debuginstall', [], '')
1998 @command('debuginstall', [], '')
1998 def debuginstall(ui):
1999 def debuginstall(ui):
1999 '''test Mercurial installation
2000 '''test Mercurial installation
2000
2001
2001 Returns 0 on success.
2002 Returns 0 on success.
2002 '''
2003 '''
2003
2004
2004 def writetemp(contents):
2005 def writetemp(contents):
2005 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2006 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2006 f = os.fdopen(fd, "wb")
2007 f = os.fdopen(fd, "wb")
2007 f.write(contents)
2008 f.write(contents)
2008 f.close()
2009 f.close()
2009 return name
2010 return name
2010
2011
2011 problems = 0
2012 problems = 0
2012
2013
2013 # encoding
2014 # encoding
2014 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2015 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2015 try:
2016 try:
2016 encoding.fromlocal("test")
2017 encoding.fromlocal("test")
2017 except util.Abort, inst:
2018 except util.Abort, inst:
2018 ui.write(" %s\n" % inst)
2019 ui.write(" %s\n" % inst)
2019 ui.write(_(" (check that your locale is properly set)\n"))
2020 ui.write(_(" (check that your locale is properly set)\n"))
2020 problems += 1
2021 problems += 1
2021
2022
2022 # Python lib
2023 # Python lib
2023 ui.status(_("checking Python lib (%s)...\n")
2024 ui.status(_("checking Python lib (%s)...\n")
2024 % os.path.dirname(os.__file__))
2025 % os.path.dirname(os.__file__))
2025
2026
2026 # compiled modules
2027 # compiled modules
2027 ui.status(_("checking installed modules (%s)...\n")
2028 ui.status(_("checking installed modules (%s)...\n")
2028 % os.path.dirname(__file__))
2029 % os.path.dirname(__file__))
2029 try:
2030 try:
2030 import bdiff, mpatch, base85, osutil
2031 import bdiff, mpatch, base85, osutil
2031 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2032 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2032 except Exception, inst:
2033 except Exception, inst:
2033 ui.write(" %s\n" % inst)
2034 ui.write(" %s\n" % inst)
2034 ui.write(_(" One or more extensions could not be found"))
2035 ui.write(_(" One or more extensions could not be found"))
2035 ui.write(_(" (check that you compiled the extensions)\n"))
2036 ui.write(_(" (check that you compiled the extensions)\n"))
2036 problems += 1
2037 problems += 1
2037
2038
2038 # templates
2039 # templates
2039 import templater
2040 import templater
2040 p = templater.templatepath()
2041 p = templater.templatepath()
2041 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2042 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2042 try:
2043 try:
2043 templater.templater(templater.templatepath("map-cmdline.default"))
2044 templater.templater(templater.templatepath("map-cmdline.default"))
2044 except Exception, inst:
2045 except Exception, inst:
2045 ui.write(" %s\n" % inst)
2046 ui.write(" %s\n" % inst)
2046 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2047 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2047 problems += 1
2048 problems += 1
2048
2049
2049 # editor
2050 # editor
2050 ui.status(_("checking commit editor...\n"))
2051 ui.status(_("checking commit editor...\n"))
2051 editor = ui.geteditor()
2052 editor = ui.geteditor()
2052 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2053 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2053 if not cmdpath:
2054 if not cmdpath:
2054 if editor == 'vi':
2055 if editor == 'vi':
2055 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2056 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2056 ui.write(_(" (specify a commit editor in your configuration"
2057 ui.write(_(" (specify a commit editor in your configuration"
2057 " file)\n"))
2058 " file)\n"))
2058 else:
2059 else:
2059 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2060 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2060 ui.write(_(" (specify a commit editor in your configuration"
2061 ui.write(_(" (specify a commit editor in your configuration"
2061 " file)\n"))
2062 " file)\n"))
2062 problems += 1
2063 problems += 1
2063
2064
2064 # check username
2065 # check username
2065 ui.status(_("checking username...\n"))
2066 ui.status(_("checking username...\n"))
2066 try:
2067 try:
2067 ui.username()
2068 ui.username()
2068 except util.Abort, e:
2069 except util.Abort, e:
2069 ui.write(" %s\n" % e)
2070 ui.write(" %s\n" % e)
2070 ui.write(_(" (specify a username in your configuration file)\n"))
2071 ui.write(_(" (specify a username in your configuration file)\n"))
2071 problems += 1
2072 problems += 1
2072
2073
2073 if not problems:
2074 if not problems:
2074 ui.status(_("no problems detected\n"))
2075 ui.status(_("no problems detected\n"))
2075 else:
2076 else:
2076 ui.write(_("%s problems detected,"
2077 ui.write(_("%s problems detected,"
2077 " please check your install!\n") % problems)
2078 " please check your install!\n") % problems)
2078
2079
2079 return problems
2080 return problems
2080
2081
2081 @command('debugknown', [], _('REPO ID...'))
2082 @command('debugknown', [], _('REPO ID...'))
2082 def debugknown(ui, repopath, *ids, **opts):
2083 def debugknown(ui, repopath, *ids, **opts):
2083 """test whether node ids are known to a repo
2084 """test whether node ids are known to a repo
2084
2085
2085 Every ID must be a full-length hex node id string. Returns a list of 0s
2086 Every ID must be a full-length hex node id string. Returns a list of 0s
2086 and 1s indicating unknown/known.
2087 and 1s indicating unknown/known.
2087 """
2088 """
2088 repo = hg.peer(ui, opts, repopath)
2089 repo = hg.peer(ui, opts, repopath)
2089 if not repo.capable('known'):
2090 if not repo.capable('known'):
2090 raise util.Abort("known() not supported by target repository")
2091 raise util.Abort("known() not supported by target repository")
2091 flags = repo.known([bin(s) for s in ids])
2092 flags = repo.known([bin(s) for s in ids])
2092 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2093 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2093
2094
2094 @command('debugobsolete',
2095 @command('debugobsolete',
2095 [('', 'flags', 0, _('markers flag')),
2096 [('', 'flags', 0, _('markers flag')),
2096 ] + commitopts2,
2097 ] + commitopts2,
2097 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2098 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2098 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2099 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2099 """create arbitrary obsolete marker"""
2100 """create arbitrary obsolete marker"""
2100 def parsenodeid(s):
2101 def parsenodeid(s):
2101 try:
2102 try:
2102 # We do not use revsingle/revrange functions here to accept
2103 # We do not use revsingle/revrange functions here to accept
2103 # arbitrary node identifiers, possibly not present in the
2104 # arbitrary node identifiers, possibly not present in the
2104 # local repository.
2105 # local repository.
2105 n = bin(s)
2106 n = bin(s)
2106 if len(n) != len(nullid):
2107 if len(n) != len(nullid):
2107 raise TypeError()
2108 raise TypeError()
2108 return n
2109 return n
2109 except TypeError:
2110 except TypeError:
2110 raise util.Abort('changeset references must be full hexadecimal '
2111 raise util.Abort('changeset references must be full hexadecimal '
2111 'node identifiers')
2112 'node identifiers')
2112
2113
2113 if precursor is not None:
2114 if precursor is not None:
2114 metadata = {}
2115 metadata = {}
2115 if 'date' in opts:
2116 if 'date' in opts:
2116 metadata['date'] = opts['date']
2117 metadata['date'] = opts['date']
2117 metadata['user'] = opts['user'] or ui.username()
2118 metadata['user'] = opts['user'] or ui.username()
2118 succs = tuple(parsenodeid(succ) for succ in successors)
2119 succs = tuple(parsenodeid(succ) for succ in successors)
2119 l = repo.lock()
2120 l = repo.lock()
2120 try:
2121 try:
2121 tr = repo.transaction('debugobsolete')
2122 tr = repo.transaction('debugobsolete')
2122 try:
2123 try:
2123 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2124 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2124 opts['flags'], metadata)
2125 opts['flags'], metadata)
2125 tr.close()
2126 tr.close()
2126 finally:
2127 finally:
2127 tr.release()
2128 tr.release()
2128 finally:
2129 finally:
2129 l.release()
2130 l.release()
2130 else:
2131 else:
2131 for m in obsolete.allmarkers(repo):
2132 for m in obsolete.allmarkers(repo):
2132 ui.write(hex(m.precnode()))
2133 ui.write(hex(m.precnode()))
2133 for repl in m.succnodes():
2134 for repl in m.succnodes():
2134 ui.write(' ')
2135 ui.write(' ')
2135 ui.write(hex(repl))
2136 ui.write(hex(repl))
2136 ui.write(' %X ' % m._data[2])
2137 ui.write(' %X ' % m._data[2])
2137 ui.write(m.metadata())
2138 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2139 sorted(m.metadata().items()))))
2138 ui.write('\n')
2140 ui.write('\n')
2139
2141
2140 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2142 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2141 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2143 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2142 '''access the pushkey key/value protocol
2144 '''access the pushkey key/value protocol
2143
2145
2144 With two args, list the keys in the given namespace.
2146 With two args, list the keys in the given namespace.
2145
2147
2146 With five args, set a key to new if it currently is set to old.
2148 With five args, set a key to new if it currently is set to old.
2147 Reports success or failure.
2149 Reports success or failure.
2148 '''
2150 '''
2149
2151
2150 target = hg.peer(ui, {}, repopath)
2152 target = hg.peer(ui, {}, repopath)
2151 if keyinfo:
2153 if keyinfo:
2152 key, old, new = keyinfo
2154 key, old, new = keyinfo
2153 r = target.pushkey(namespace, key, old, new)
2155 r = target.pushkey(namespace, key, old, new)
2154 ui.status(str(r) + '\n')
2156 ui.status(str(r) + '\n')
2155 return not r
2157 return not r
2156 else:
2158 else:
2157 for k, v in target.listkeys(namespace).iteritems():
2159 for k, v in target.listkeys(namespace).iteritems():
2158 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2160 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2159 v.encode('string-escape')))
2161 v.encode('string-escape')))
2160
2162
2161 @command('debugpvec', [], _('A B'))
2163 @command('debugpvec', [], _('A B'))
2162 def debugpvec(ui, repo, a, b=None):
2164 def debugpvec(ui, repo, a, b=None):
2163 ca = scmutil.revsingle(repo, a)
2165 ca = scmutil.revsingle(repo, a)
2164 cb = scmutil.revsingle(repo, b)
2166 cb = scmutil.revsingle(repo, b)
2165 pa = pvec.ctxpvec(ca)
2167 pa = pvec.ctxpvec(ca)
2166 pb = pvec.ctxpvec(cb)
2168 pb = pvec.ctxpvec(cb)
2167 if pa == pb:
2169 if pa == pb:
2168 rel = "="
2170 rel = "="
2169 elif pa > pb:
2171 elif pa > pb:
2170 rel = ">"
2172 rel = ">"
2171 elif pa < pb:
2173 elif pa < pb:
2172 rel = "<"
2174 rel = "<"
2173 elif pa | pb:
2175 elif pa | pb:
2174 rel = "|"
2176 rel = "|"
2175 ui.write(_("a: %s\n") % pa)
2177 ui.write(_("a: %s\n") % pa)
2176 ui.write(_("b: %s\n") % pb)
2178 ui.write(_("b: %s\n") % pb)
2177 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2179 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2178 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2180 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2179 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2181 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2180 pa.distance(pb), rel))
2182 pa.distance(pb), rel))
2181
2183
2182 @command('debugrebuildstate',
2184 @command('debugrebuildstate',
2183 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2185 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2184 _('[-r REV] [REV]'))
2186 _('[-r REV] [REV]'))
2185 def debugrebuildstate(ui, repo, rev="tip"):
2187 def debugrebuildstate(ui, repo, rev="tip"):
2186 """rebuild the dirstate as it would look like for the given revision"""
2188 """rebuild the dirstate as it would look like for the given revision"""
2187 ctx = scmutil.revsingle(repo, rev)
2189 ctx = scmutil.revsingle(repo, rev)
2188 wlock = repo.wlock()
2190 wlock = repo.wlock()
2189 try:
2191 try:
2190 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2192 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2191 finally:
2193 finally:
2192 wlock.release()
2194 wlock.release()
2193
2195
2194 @command('debugrename',
2196 @command('debugrename',
2195 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2197 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2196 _('[-r REV] FILE'))
2198 _('[-r REV] FILE'))
2197 def debugrename(ui, repo, file1, *pats, **opts):
2199 def debugrename(ui, repo, file1, *pats, **opts):
2198 """dump rename information"""
2200 """dump rename information"""
2199
2201
2200 ctx = scmutil.revsingle(repo, opts.get('rev'))
2202 ctx = scmutil.revsingle(repo, opts.get('rev'))
2201 m = scmutil.match(ctx, (file1,) + pats, opts)
2203 m = scmutil.match(ctx, (file1,) + pats, opts)
2202 for abs in ctx.walk(m):
2204 for abs in ctx.walk(m):
2203 fctx = ctx[abs]
2205 fctx = ctx[abs]
2204 o = fctx.filelog().renamed(fctx.filenode())
2206 o = fctx.filelog().renamed(fctx.filenode())
2205 rel = m.rel(abs)
2207 rel = m.rel(abs)
2206 if o:
2208 if o:
2207 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2209 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2208 else:
2210 else:
2209 ui.write(_("%s not renamed\n") % rel)
2211 ui.write(_("%s not renamed\n") % rel)
2210
2212
2211 @command('debugrevlog',
2213 @command('debugrevlog',
2212 [('c', 'changelog', False, _('open changelog')),
2214 [('c', 'changelog', False, _('open changelog')),
2213 ('m', 'manifest', False, _('open manifest')),
2215 ('m', 'manifest', False, _('open manifest')),
2214 ('d', 'dump', False, _('dump index data'))],
2216 ('d', 'dump', False, _('dump index data'))],
2215 _('-c|-m|FILE'))
2217 _('-c|-m|FILE'))
2216 def debugrevlog(ui, repo, file_ = None, **opts):
2218 def debugrevlog(ui, repo, file_ = None, **opts):
2217 """show data and statistics about a revlog"""
2219 """show data and statistics about a revlog"""
2218 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2220 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2219
2221
2220 if opts.get("dump"):
2222 if opts.get("dump"):
2221 numrevs = len(r)
2223 numrevs = len(r)
2222 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2224 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2223 " rawsize totalsize compression heads\n")
2225 " rawsize totalsize compression heads\n")
2224 ts = 0
2226 ts = 0
2225 heads = set()
2227 heads = set()
2226 for rev in xrange(numrevs):
2228 for rev in xrange(numrevs):
2227 dbase = r.deltaparent(rev)
2229 dbase = r.deltaparent(rev)
2228 if dbase == -1:
2230 if dbase == -1:
2229 dbase = rev
2231 dbase = rev
2230 cbase = r.chainbase(rev)
2232 cbase = r.chainbase(rev)
2231 p1, p2 = r.parentrevs(rev)
2233 p1, p2 = r.parentrevs(rev)
2232 rs = r.rawsize(rev)
2234 rs = r.rawsize(rev)
2233 ts = ts + rs
2235 ts = ts + rs
2234 heads -= set(r.parentrevs(rev))
2236 heads -= set(r.parentrevs(rev))
2235 heads.add(rev)
2237 heads.add(rev)
2236 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2238 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2237 (rev, p1, p2, r.start(rev), r.end(rev),
2239 (rev, p1, p2, r.start(rev), r.end(rev),
2238 r.start(dbase), r.start(cbase),
2240 r.start(dbase), r.start(cbase),
2239 r.start(p1), r.start(p2),
2241 r.start(p1), r.start(p2),
2240 rs, ts, ts / r.end(rev), len(heads)))
2242 rs, ts, ts / r.end(rev), len(heads)))
2241 return 0
2243 return 0
2242
2244
2243 v = r.version
2245 v = r.version
2244 format = v & 0xFFFF
2246 format = v & 0xFFFF
2245 flags = []
2247 flags = []
2246 gdelta = False
2248 gdelta = False
2247 if v & revlog.REVLOGNGINLINEDATA:
2249 if v & revlog.REVLOGNGINLINEDATA:
2248 flags.append('inline')
2250 flags.append('inline')
2249 if v & revlog.REVLOGGENERALDELTA:
2251 if v & revlog.REVLOGGENERALDELTA:
2250 gdelta = True
2252 gdelta = True
2251 flags.append('generaldelta')
2253 flags.append('generaldelta')
2252 if not flags:
2254 if not flags:
2253 flags = ['(none)']
2255 flags = ['(none)']
2254
2256
2255 nummerges = 0
2257 nummerges = 0
2256 numfull = 0
2258 numfull = 0
2257 numprev = 0
2259 numprev = 0
2258 nump1 = 0
2260 nump1 = 0
2259 nump2 = 0
2261 nump2 = 0
2260 numother = 0
2262 numother = 0
2261 nump1prev = 0
2263 nump1prev = 0
2262 nump2prev = 0
2264 nump2prev = 0
2263 chainlengths = []
2265 chainlengths = []
2264
2266
2265 datasize = [None, 0, 0L]
2267 datasize = [None, 0, 0L]
2266 fullsize = [None, 0, 0L]
2268 fullsize = [None, 0, 0L]
2267 deltasize = [None, 0, 0L]
2269 deltasize = [None, 0, 0L]
2268
2270
2269 def addsize(size, l):
2271 def addsize(size, l):
2270 if l[0] is None or size < l[0]:
2272 if l[0] is None or size < l[0]:
2271 l[0] = size
2273 l[0] = size
2272 if size > l[1]:
2274 if size > l[1]:
2273 l[1] = size
2275 l[1] = size
2274 l[2] += size
2276 l[2] += size
2275
2277
2276 numrevs = len(r)
2278 numrevs = len(r)
2277 for rev in xrange(numrevs):
2279 for rev in xrange(numrevs):
2278 p1, p2 = r.parentrevs(rev)
2280 p1, p2 = r.parentrevs(rev)
2279 delta = r.deltaparent(rev)
2281 delta = r.deltaparent(rev)
2280 if format > 0:
2282 if format > 0:
2281 addsize(r.rawsize(rev), datasize)
2283 addsize(r.rawsize(rev), datasize)
2282 if p2 != nullrev:
2284 if p2 != nullrev:
2283 nummerges += 1
2285 nummerges += 1
2284 size = r.length(rev)
2286 size = r.length(rev)
2285 if delta == nullrev:
2287 if delta == nullrev:
2286 chainlengths.append(0)
2288 chainlengths.append(0)
2287 numfull += 1
2289 numfull += 1
2288 addsize(size, fullsize)
2290 addsize(size, fullsize)
2289 else:
2291 else:
2290 chainlengths.append(chainlengths[delta] + 1)
2292 chainlengths.append(chainlengths[delta] + 1)
2291 addsize(size, deltasize)
2293 addsize(size, deltasize)
2292 if delta == rev - 1:
2294 if delta == rev - 1:
2293 numprev += 1
2295 numprev += 1
2294 if delta == p1:
2296 if delta == p1:
2295 nump1prev += 1
2297 nump1prev += 1
2296 elif delta == p2:
2298 elif delta == p2:
2297 nump2prev += 1
2299 nump2prev += 1
2298 elif delta == p1:
2300 elif delta == p1:
2299 nump1 += 1
2301 nump1 += 1
2300 elif delta == p2:
2302 elif delta == p2:
2301 nump2 += 1
2303 nump2 += 1
2302 elif delta != nullrev:
2304 elif delta != nullrev:
2303 numother += 1
2305 numother += 1
2304
2306
2305 # Adjust size min value for empty cases
2307 # Adjust size min value for empty cases
2306 for size in (datasize, fullsize, deltasize):
2308 for size in (datasize, fullsize, deltasize):
2307 if size[0] is None:
2309 if size[0] is None:
2308 size[0] = 0
2310 size[0] = 0
2309
2311
2310 numdeltas = numrevs - numfull
2312 numdeltas = numrevs - numfull
2311 numoprev = numprev - nump1prev - nump2prev
2313 numoprev = numprev - nump1prev - nump2prev
2312 totalrawsize = datasize[2]
2314 totalrawsize = datasize[2]
2313 datasize[2] /= numrevs
2315 datasize[2] /= numrevs
2314 fulltotal = fullsize[2]
2316 fulltotal = fullsize[2]
2315 fullsize[2] /= numfull
2317 fullsize[2] /= numfull
2316 deltatotal = deltasize[2]
2318 deltatotal = deltasize[2]
2317 if numrevs - numfull > 0:
2319 if numrevs - numfull > 0:
2318 deltasize[2] /= numrevs - numfull
2320 deltasize[2] /= numrevs - numfull
2319 totalsize = fulltotal + deltatotal
2321 totalsize = fulltotal + deltatotal
2320 avgchainlen = sum(chainlengths) / numrevs
2322 avgchainlen = sum(chainlengths) / numrevs
2321 compratio = totalrawsize / totalsize
2323 compratio = totalrawsize / totalsize
2322
2324
2323 basedfmtstr = '%%%dd\n'
2325 basedfmtstr = '%%%dd\n'
2324 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2326 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2325
2327
2326 def dfmtstr(max):
2328 def dfmtstr(max):
2327 return basedfmtstr % len(str(max))
2329 return basedfmtstr % len(str(max))
2328 def pcfmtstr(max, padding=0):
2330 def pcfmtstr(max, padding=0):
2329 return basepcfmtstr % (len(str(max)), ' ' * padding)
2331 return basepcfmtstr % (len(str(max)), ' ' * padding)
2330
2332
2331 def pcfmt(value, total):
2333 def pcfmt(value, total):
2332 return (value, 100 * float(value) / total)
2334 return (value, 100 * float(value) / total)
2333
2335
2334 ui.write(('format : %d\n') % format)
2336 ui.write(('format : %d\n') % format)
2335 ui.write(('flags : %s\n') % ', '.join(flags))
2337 ui.write(('flags : %s\n') % ', '.join(flags))
2336
2338
2337 ui.write('\n')
2339 ui.write('\n')
2338 fmt = pcfmtstr(totalsize)
2340 fmt = pcfmtstr(totalsize)
2339 fmt2 = dfmtstr(totalsize)
2341 fmt2 = dfmtstr(totalsize)
2340 ui.write(('revisions : ') + fmt2 % numrevs)
2342 ui.write(('revisions : ') + fmt2 % numrevs)
2341 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2343 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2342 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2344 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2343 ui.write(('revisions : ') + fmt2 % numrevs)
2345 ui.write(('revisions : ') + fmt2 % numrevs)
2344 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2346 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2345 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2347 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2346 ui.write(('revision size : ') + fmt2 % totalsize)
2348 ui.write(('revision size : ') + fmt2 % totalsize)
2347 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2349 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2348 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2350 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2349
2351
2350 ui.write('\n')
2352 ui.write('\n')
2351 fmt = dfmtstr(max(avgchainlen, compratio))
2353 fmt = dfmtstr(max(avgchainlen, compratio))
2352 ui.write(('avg chain length : ') + fmt % avgchainlen)
2354 ui.write(('avg chain length : ') + fmt % avgchainlen)
2353 ui.write(('compression ratio : ') + fmt % compratio)
2355 ui.write(('compression ratio : ') + fmt % compratio)
2354
2356
2355 if format > 0:
2357 if format > 0:
2356 ui.write('\n')
2358 ui.write('\n')
2357 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2359 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2358 % tuple(datasize))
2360 % tuple(datasize))
2359 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2361 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2360 % tuple(fullsize))
2362 % tuple(fullsize))
2361 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2363 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2362 % tuple(deltasize))
2364 % tuple(deltasize))
2363
2365
2364 if numdeltas > 0:
2366 if numdeltas > 0:
2365 ui.write('\n')
2367 ui.write('\n')
2366 fmt = pcfmtstr(numdeltas)
2368 fmt = pcfmtstr(numdeltas)
2367 fmt2 = pcfmtstr(numdeltas, 4)
2369 fmt2 = pcfmtstr(numdeltas, 4)
2368 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2370 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2369 if numprev > 0:
2371 if numprev > 0:
2370 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2372 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2371 numprev))
2373 numprev))
2372 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2374 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2373 numprev))
2375 numprev))
2374 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2376 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2375 numprev))
2377 numprev))
2376 if gdelta:
2378 if gdelta:
2377 ui.write(('deltas against p1 : ')
2379 ui.write(('deltas against p1 : ')
2378 + fmt % pcfmt(nump1, numdeltas))
2380 + fmt % pcfmt(nump1, numdeltas))
2379 ui.write(('deltas against p2 : ')
2381 ui.write(('deltas against p2 : ')
2380 + fmt % pcfmt(nump2, numdeltas))
2382 + fmt % pcfmt(nump2, numdeltas))
2381 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2383 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2382 numdeltas))
2384 numdeltas))
2383
2385
2384 @command('debugrevspec', [], ('REVSPEC'))
2386 @command('debugrevspec', [], ('REVSPEC'))
2385 def debugrevspec(ui, repo, expr):
2387 def debugrevspec(ui, repo, expr):
2386 """parse and apply a revision specification
2388 """parse and apply a revision specification
2387
2389
2388 Use --verbose to print the parsed tree before and after aliases
2390 Use --verbose to print the parsed tree before and after aliases
2389 expansion.
2391 expansion.
2390 """
2392 """
2391 if ui.verbose:
2393 if ui.verbose:
2392 tree = revset.parse(expr)[0]
2394 tree = revset.parse(expr)[0]
2393 ui.note(revset.prettyformat(tree), "\n")
2395 ui.note(revset.prettyformat(tree), "\n")
2394 newtree = revset.findaliases(ui, tree)
2396 newtree = revset.findaliases(ui, tree)
2395 if newtree != tree:
2397 if newtree != tree:
2396 ui.note(revset.prettyformat(newtree), "\n")
2398 ui.note(revset.prettyformat(newtree), "\n")
2397 func = revset.match(ui, expr)
2399 func = revset.match(ui, expr)
2398 for c in func(repo, range(len(repo))):
2400 for c in func(repo, range(len(repo))):
2399 ui.write("%s\n" % c)
2401 ui.write("%s\n" % c)
2400
2402
2401 @command('debugsetparents', [], _('REV1 [REV2]'))
2403 @command('debugsetparents', [], _('REV1 [REV2]'))
2402 def debugsetparents(ui, repo, rev1, rev2=None):
2404 def debugsetparents(ui, repo, rev1, rev2=None):
2403 """manually set the parents of the current working directory
2405 """manually set the parents of the current working directory
2404
2406
2405 This is useful for writing repository conversion tools, but should
2407 This is useful for writing repository conversion tools, but should
2406 be used with care.
2408 be used with care.
2407
2409
2408 Returns 0 on success.
2410 Returns 0 on success.
2409 """
2411 """
2410
2412
2411 r1 = scmutil.revsingle(repo, rev1).node()
2413 r1 = scmutil.revsingle(repo, rev1).node()
2412 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2414 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2413
2415
2414 wlock = repo.wlock()
2416 wlock = repo.wlock()
2415 try:
2417 try:
2416 repo.setparents(r1, r2)
2418 repo.setparents(r1, r2)
2417 finally:
2419 finally:
2418 wlock.release()
2420 wlock.release()
2419
2421
2420 @command('debugstate',
2422 @command('debugstate',
2421 [('', 'nodates', None, _('do not display the saved mtime')),
2423 [('', 'nodates', None, _('do not display the saved mtime')),
2422 ('', 'datesort', None, _('sort by saved mtime'))],
2424 ('', 'datesort', None, _('sort by saved mtime'))],
2423 _('[OPTION]...'))
2425 _('[OPTION]...'))
2424 def debugstate(ui, repo, nodates=None, datesort=None):
2426 def debugstate(ui, repo, nodates=None, datesort=None):
2425 """show the contents of the current dirstate"""
2427 """show the contents of the current dirstate"""
2426 timestr = ""
2428 timestr = ""
2427 showdate = not nodates
2429 showdate = not nodates
2428 if datesort:
2430 if datesort:
2429 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2431 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2430 else:
2432 else:
2431 keyfunc = None # sort by filename
2433 keyfunc = None # sort by filename
2432 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2434 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2433 if showdate:
2435 if showdate:
2434 if ent[3] == -1:
2436 if ent[3] == -1:
2435 # Pad or slice to locale representation
2437 # Pad or slice to locale representation
2436 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2438 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2437 time.localtime(0)))
2439 time.localtime(0)))
2438 timestr = 'unset'
2440 timestr = 'unset'
2439 timestr = (timestr[:locale_len] +
2441 timestr = (timestr[:locale_len] +
2440 ' ' * (locale_len - len(timestr)))
2442 ' ' * (locale_len - len(timestr)))
2441 else:
2443 else:
2442 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2444 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2443 time.localtime(ent[3]))
2445 time.localtime(ent[3]))
2444 if ent[1] & 020000:
2446 if ent[1] & 020000:
2445 mode = 'lnk'
2447 mode = 'lnk'
2446 else:
2448 else:
2447 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2449 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2448 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2450 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2449 for f in repo.dirstate.copies():
2451 for f in repo.dirstate.copies():
2450 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2452 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2451
2453
2452 @command('debugsub',
2454 @command('debugsub',
2453 [('r', 'rev', '',
2455 [('r', 'rev', '',
2454 _('revision to check'), _('REV'))],
2456 _('revision to check'), _('REV'))],
2455 _('[-r REV] [REV]'))
2457 _('[-r REV] [REV]'))
2456 def debugsub(ui, repo, rev=None):
2458 def debugsub(ui, repo, rev=None):
2457 ctx = scmutil.revsingle(repo, rev, None)
2459 ctx = scmutil.revsingle(repo, rev, None)
2458 for k, v in sorted(ctx.substate.items()):
2460 for k, v in sorted(ctx.substate.items()):
2459 ui.write(('path %s\n') % k)
2461 ui.write(('path %s\n') % k)
2460 ui.write((' source %s\n') % v[0])
2462 ui.write((' source %s\n') % v[0])
2461 ui.write((' revision %s\n') % v[1])
2463 ui.write((' revision %s\n') % v[1])
2462
2464
2463 @command('debugsuccessorssets',
2465 @command('debugsuccessorssets',
2464 [],
2466 [],
2465 _('[REV]'))
2467 _('[REV]'))
2466 def debugsuccessorssets(ui, repo, *revs):
2468 def debugsuccessorssets(ui, repo, *revs):
2467 """show set of successors for revision
2469 """show set of successors for revision
2468
2470
2469 A successors set of changeset A is a consistent group of revisions that
2471 A successors set of changeset A is a consistent group of revisions that
2470 succeed A. It contains non-obsolete changesets only.
2472 succeed A. It contains non-obsolete changesets only.
2471
2473
2472 In most cases a changeset A has a single successors set containing a single
2474 In most cases a changeset A has a single successors set containing a single
2473 successors (changeset A replaced by A').
2475 successors (changeset A replaced by A').
2474
2476
2475 A changeset that is made obsolete with no successors are called "pruned".
2477 A changeset that is made obsolete with no successors are called "pruned".
2476 Such changesets have no successors sets at all.
2478 Such changesets have no successors sets at all.
2477
2479
2478 A changeset that has been "split" will have a successors set containing
2480 A changeset that has been "split" will have a successors set containing
2479 more than one successors.
2481 more than one successors.
2480
2482
2481 A changeset that has been rewritten in multiple different ways is called
2483 A changeset that has been rewritten in multiple different ways is called
2482 "divergent". Such changesets have multiple successor sets (each of which
2484 "divergent". Such changesets have multiple successor sets (each of which
2483 may also be split, i.e. have multiple successors).
2485 may also be split, i.e. have multiple successors).
2484
2486
2485 Results are displayed as follows::
2487 Results are displayed as follows::
2486
2488
2487 <rev1>
2489 <rev1>
2488 <successors-1A>
2490 <successors-1A>
2489 <rev2>
2491 <rev2>
2490 <successors-2A>
2492 <successors-2A>
2491 <successors-2B1> <successors-2B2> <successors-2B3>
2493 <successors-2B1> <successors-2B2> <successors-2B3>
2492
2494
2493 Here rev2 has two possible (i.e. divergent) successors sets. The first
2495 Here rev2 has two possible (i.e. divergent) successors sets. The first
2494 holds one element, whereas the second holds three (i.e. the changeset has
2496 holds one element, whereas the second holds three (i.e. the changeset has
2495 been split).
2497 been split).
2496 """
2498 """
2497 # passed to successorssets caching computation from one call to another
2499 # passed to successorssets caching computation from one call to another
2498 cache = {}
2500 cache = {}
2499 ctx2str = str
2501 ctx2str = str
2500 node2str = short
2502 node2str = short
2501 if ui.debug():
2503 if ui.debug():
2502 def ctx2str(ctx):
2504 def ctx2str(ctx):
2503 return ctx.hex()
2505 return ctx.hex()
2504 node2str = hex
2506 node2str = hex
2505 for rev in scmutil.revrange(repo, revs):
2507 for rev in scmutil.revrange(repo, revs):
2506 ctx = repo[rev]
2508 ctx = repo[rev]
2507 ui.write('%s\n'% ctx2str(ctx))
2509 ui.write('%s\n'% ctx2str(ctx))
2508 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2510 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2509 if succsset:
2511 if succsset:
2510 ui.write(' ')
2512 ui.write(' ')
2511 ui.write(node2str(succsset[0]))
2513 ui.write(node2str(succsset[0]))
2512 for node in succsset[1:]:
2514 for node in succsset[1:]:
2513 ui.write(' ')
2515 ui.write(' ')
2514 ui.write(node2str(node))
2516 ui.write(node2str(node))
2515 ui.write('\n')
2517 ui.write('\n')
2516
2518
2517 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2519 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2518 def debugwalk(ui, repo, *pats, **opts):
2520 def debugwalk(ui, repo, *pats, **opts):
2519 """show how files match on given patterns"""
2521 """show how files match on given patterns"""
2520 m = scmutil.match(repo[None], pats, opts)
2522 m = scmutil.match(repo[None], pats, opts)
2521 items = list(repo.walk(m))
2523 items = list(repo.walk(m))
2522 if not items:
2524 if not items:
2523 return
2525 return
2524 f = lambda fn: fn
2526 f = lambda fn: fn
2525 if ui.configbool('ui', 'slash') and os.sep != '/':
2527 if ui.configbool('ui', 'slash') and os.sep != '/':
2526 f = lambda fn: util.normpath(fn)
2528 f = lambda fn: util.normpath(fn)
2527 fmt = 'f %%-%ds %%-%ds %%s' % (
2529 fmt = 'f %%-%ds %%-%ds %%s' % (
2528 max([len(abs) for abs in items]),
2530 max([len(abs) for abs in items]),
2529 max([len(m.rel(abs)) for abs in items]))
2531 max([len(m.rel(abs)) for abs in items]))
2530 for abs in items:
2532 for abs in items:
2531 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2533 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2532 ui.write("%s\n" % line.rstrip())
2534 ui.write("%s\n" % line.rstrip())
2533
2535
2534 @command('debugwireargs',
2536 @command('debugwireargs',
2535 [('', 'three', '', 'three'),
2537 [('', 'three', '', 'three'),
2536 ('', 'four', '', 'four'),
2538 ('', 'four', '', 'four'),
2537 ('', 'five', '', 'five'),
2539 ('', 'five', '', 'five'),
2538 ] + remoteopts,
2540 ] + remoteopts,
2539 _('REPO [OPTIONS]... [ONE [TWO]]'))
2541 _('REPO [OPTIONS]... [ONE [TWO]]'))
2540 def debugwireargs(ui, repopath, *vals, **opts):
2542 def debugwireargs(ui, repopath, *vals, **opts):
2541 repo = hg.peer(ui, opts, repopath)
2543 repo = hg.peer(ui, opts, repopath)
2542 for opt in remoteopts:
2544 for opt in remoteopts:
2543 del opts[opt[1]]
2545 del opts[opt[1]]
2544 args = {}
2546 args = {}
2545 for k, v in opts.iteritems():
2547 for k, v in opts.iteritems():
2546 if v:
2548 if v:
2547 args[k] = v
2549 args[k] = v
2548 # run twice to check that we don't mess up the stream for the next command
2550 # run twice to check that we don't mess up the stream for the next command
2549 res1 = repo.debugwireargs(*vals, **args)
2551 res1 = repo.debugwireargs(*vals, **args)
2550 res2 = repo.debugwireargs(*vals, **args)
2552 res2 = repo.debugwireargs(*vals, **args)
2551 ui.write("%s\n" % res1)
2553 ui.write("%s\n" % res1)
2552 if res1 != res2:
2554 if res1 != res2:
2553 ui.warn("%s\n" % res2)
2555 ui.warn("%s\n" % res2)
2554
2556
2555 @command('^diff',
2557 @command('^diff',
2556 [('r', 'rev', [], _('revision'), _('REV')),
2558 [('r', 'rev', [], _('revision'), _('REV')),
2557 ('c', 'change', '', _('change made by revision'), _('REV'))
2559 ('c', 'change', '', _('change made by revision'), _('REV'))
2558 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2560 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2559 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2561 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2560 def diff(ui, repo, *pats, **opts):
2562 def diff(ui, repo, *pats, **opts):
2561 """diff repository (or selected files)
2563 """diff repository (or selected files)
2562
2564
2563 Show differences between revisions for the specified files.
2565 Show differences between revisions for the specified files.
2564
2566
2565 Differences between files are shown using the unified diff format.
2567 Differences between files are shown using the unified diff format.
2566
2568
2567 .. note::
2569 .. note::
2568 diff may generate unexpected results for merges, as it will
2570 diff may generate unexpected results for merges, as it will
2569 default to comparing against the working directory's first
2571 default to comparing against the working directory's first
2570 parent changeset if no revisions are specified.
2572 parent changeset if no revisions are specified.
2571
2573
2572 When two revision arguments are given, then changes are shown
2574 When two revision arguments are given, then changes are shown
2573 between those revisions. If only one revision is specified then
2575 between those revisions. If only one revision is specified then
2574 that revision is compared to the working directory, and, when no
2576 that revision is compared to the working directory, and, when no
2575 revisions are specified, the working directory files are compared
2577 revisions are specified, the working directory files are compared
2576 to its parent.
2578 to its parent.
2577
2579
2578 Alternatively you can specify -c/--change with a revision to see
2580 Alternatively you can specify -c/--change with a revision to see
2579 the changes in that changeset relative to its first parent.
2581 the changes in that changeset relative to its first parent.
2580
2582
2581 Without the -a/--text option, diff will avoid generating diffs of
2583 Without the -a/--text option, diff will avoid generating diffs of
2582 files it detects as binary. With -a, diff will generate a diff
2584 files it detects as binary. With -a, diff will generate a diff
2583 anyway, probably with undesirable results.
2585 anyway, probably with undesirable results.
2584
2586
2585 Use the -g/--git option to generate diffs in the git extended diff
2587 Use the -g/--git option to generate diffs in the git extended diff
2586 format. For more information, read :hg:`help diffs`.
2588 format. For more information, read :hg:`help diffs`.
2587
2589
2588 .. container:: verbose
2590 .. container:: verbose
2589
2591
2590 Examples:
2592 Examples:
2591
2593
2592 - compare a file in the current working directory to its parent::
2594 - compare a file in the current working directory to its parent::
2593
2595
2594 hg diff foo.c
2596 hg diff foo.c
2595
2597
2596 - compare two historical versions of a directory, with rename info::
2598 - compare two historical versions of a directory, with rename info::
2597
2599
2598 hg diff --git -r 1.0:1.2 lib/
2600 hg diff --git -r 1.0:1.2 lib/
2599
2601
2600 - get change stats relative to the last change on some date::
2602 - get change stats relative to the last change on some date::
2601
2603
2602 hg diff --stat -r "date('may 2')"
2604 hg diff --stat -r "date('may 2')"
2603
2605
2604 - diff all newly-added files that contain a keyword::
2606 - diff all newly-added files that contain a keyword::
2605
2607
2606 hg diff "set:added() and grep(GNU)"
2608 hg diff "set:added() and grep(GNU)"
2607
2609
2608 - compare a revision and its parents::
2610 - compare a revision and its parents::
2609
2611
2610 hg diff -c 9353 # compare against first parent
2612 hg diff -c 9353 # compare against first parent
2611 hg diff -r 9353^:9353 # same using revset syntax
2613 hg diff -r 9353^:9353 # same using revset syntax
2612 hg diff -r 9353^2:9353 # compare against the second parent
2614 hg diff -r 9353^2:9353 # compare against the second parent
2613
2615
2614 Returns 0 on success.
2616 Returns 0 on success.
2615 """
2617 """
2616
2618
2617 revs = opts.get('rev')
2619 revs = opts.get('rev')
2618 change = opts.get('change')
2620 change = opts.get('change')
2619 stat = opts.get('stat')
2621 stat = opts.get('stat')
2620 reverse = opts.get('reverse')
2622 reverse = opts.get('reverse')
2621
2623
2622 if revs and change:
2624 if revs and change:
2623 msg = _('cannot specify --rev and --change at the same time')
2625 msg = _('cannot specify --rev and --change at the same time')
2624 raise util.Abort(msg)
2626 raise util.Abort(msg)
2625 elif change:
2627 elif change:
2626 node2 = scmutil.revsingle(repo, change, None).node()
2628 node2 = scmutil.revsingle(repo, change, None).node()
2627 node1 = repo[node2].p1().node()
2629 node1 = repo[node2].p1().node()
2628 else:
2630 else:
2629 node1, node2 = scmutil.revpair(repo, revs)
2631 node1, node2 = scmutil.revpair(repo, revs)
2630
2632
2631 if reverse:
2633 if reverse:
2632 node1, node2 = node2, node1
2634 node1, node2 = node2, node1
2633
2635
2634 diffopts = patch.diffopts(ui, opts)
2636 diffopts = patch.diffopts(ui, opts)
2635 m = scmutil.match(repo[node2], pats, opts)
2637 m = scmutil.match(repo[node2], pats, opts)
2636 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2638 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2637 listsubrepos=opts.get('subrepos'))
2639 listsubrepos=opts.get('subrepos'))
2638
2640
2639 @command('^export',
2641 @command('^export',
2640 [('o', 'output', '',
2642 [('o', 'output', '',
2641 _('print output to file with formatted name'), _('FORMAT')),
2643 _('print output to file with formatted name'), _('FORMAT')),
2642 ('', 'switch-parent', None, _('diff against the second parent')),
2644 ('', 'switch-parent', None, _('diff against the second parent')),
2643 ('r', 'rev', [], _('revisions to export'), _('REV')),
2645 ('r', 'rev', [], _('revisions to export'), _('REV')),
2644 ] + diffopts,
2646 ] + diffopts,
2645 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2647 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2646 def export(ui, repo, *changesets, **opts):
2648 def export(ui, repo, *changesets, **opts):
2647 """dump the header and diffs for one or more changesets
2649 """dump the header and diffs for one or more changesets
2648
2650
2649 Print the changeset header and diffs for one or more revisions.
2651 Print the changeset header and diffs for one or more revisions.
2650
2652
2651 The information shown in the changeset header is: author, date,
2653 The information shown in the changeset header is: author, date,
2652 branch name (if non-default), changeset hash, parent(s) and commit
2654 branch name (if non-default), changeset hash, parent(s) and commit
2653 comment.
2655 comment.
2654
2656
2655 .. note::
2657 .. note::
2656 export may generate unexpected diff output for merge
2658 export may generate unexpected diff output for merge
2657 changesets, as it will compare the merge changeset against its
2659 changesets, as it will compare the merge changeset against its
2658 first parent only.
2660 first parent only.
2659
2661
2660 Output may be to a file, in which case the name of the file is
2662 Output may be to a file, in which case the name of the file is
2661 given using a format string. The formatting rules are as follows:
2663 given using a format string. The formatting rules are as follows:
2662
2664
2663 :``%%``: literal "%" character
2665 :``%%``: literal "%" character
2664 :``%H``: changeset hash (40 hexadecimal digits)
2666 :``%H``: changeset hash (40 hexadecimal digits)
2665 :``%N``: number of patches being generated
2667 :``%N``: number of patches being generated
2666 :``%R``: changeset revision number
2668 :``%R``: changeset revision number
2667 :``%b``: basename of the exporting repository
2669 :``%b``: basename of the exporting repository
2668 :``%h``: short-form changeset hash (12 hexadecimal digits)
2670 :``%h``: short-form changeset hash (12 hexadecimal digits)
2669 :``%m``: first line of the commit message (only alphanumeric characters)
2671 :``%m``: first line of the commit message (only alphanumeric characters)
2670 :``%n``: zero-padded sequence number, starting at 1
2672 :``%n``: zero-padded sequence number, starting at 1
2671 :``%r``: zero-padded changeset revision number
2673 :``%r``: zero-padded changeset revision number
2672
2674
2673 Without the -a/--text option, export will avoid generating diffs
2675 Without the -a/--text option, export will avoid generating diffs
2674 of files it detects as binary. With -a, export will generate a
2676 of files it detects as binary. With -a, export will generate a
2675 diff anyway, probably with undesirable results.
2677 diff anyway, probably with undesirable results.
2676
2678
2677 Use the -g/--git option to generate diffs in the git extended diff
2679 Use the -g/--git option to generate diffs in the git extended diff
2678 format. See :hg:`help diffs` for more information.
2680 format. See :hg:`help diffs` for more information.
2679
2681
2680 With the --switch-parent option, the diff will be against the
2682 With the --switch-parent option, the diff will be against the
2681 second parent. It can be useful to review a merge.
2683 second parent. It can be useful to review a merge.
2682
2684
2683 .. container:: verbose
2685 .. container:: verbose
2684
2686
2685 Examples:
2687 Examples:
2686
2688
2687 - use export and import to transplant a bugfix to the current
2689 - use export and import to transplant a bugfix to the current
2688 branch::
2690 branch::
2689
2691
2690 hg export -r 9353 | hg import -
2692 hg export -r 9353 | hg import -
2691
2693
2692 - export all the changesets between two revisions to a file with
2694 - export all the changesets between two revisions to a file with
2693 rename information::
2695 rename information::
2694
2696
2695 hg export --git -r 123:150 > changes.txt
2697 hg export --git -r 123:150 > changes.txt
2696
2698
2697 - split outgoing changes into a series of patches with
2699 - split outgoing changes into a series of patches with
2698 descriptive names::
2700 descriptive names::
2699
2701
2700 hg export -r "outgoing()" -o "%n-%m.patch"
2702 hg export -r "outgoing()" -o "%n-%m.patch"
2701
2703
2702 Returns 0 on success.
2704 Returns 0 on success.
2703 """
2705 """
2704 changesets += tuple(opts.get('rev', []))
2706 changesets += tuple(opts.get('rev', []))
2705 revs = scmutil.revrange(repo, changesets)
2707 revs = scmutil.revrange(repo, changesets)
2706 if not revs:
2708 if not revs:
2707 raise util.Abort(_("export requires at least one changeset"))
2709 raise util.Abort(_("export requires at least one changeset"))
2708 if len(revs) > 1:
2710 if len(revs) > 1:
2709 ui.note(_('exporting patches:\n'))
2711 ui.note(_('exporting patches:\n'))
2710 else:
2712 else:
2711 ui.note(_('exporting patch:\n'))
2713 ui.note(_('exporting patch:\n'))
2712 cmdutil.export(repo, revs, template=opts.get('output'),
2714 cmdutil.export(repo, revs, template=opts.get('output'),
2713 switch_parent=opts.get('switch_parent'),
2715 switch_parent=opts.get('switch_parent'),
2714 opts=patch.diffopts(ui, opts))
2716 opts=patch.diffopts(ui, opts))
2715
2717
2716 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2718 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2717 def forget(ui, repo, *pats, **opts):
2719 def forget(ui, repo, *pats, **opts):
2718 """forget the specified files on the next commit
2720 """forget the specified files on the next commit
2719
2721
2720 Mark the specified files so they will no longer be tracked
2722 Mark the specified files so they will no longer be tracked
2721 after the next commit.
2723 after the next commit.
2722
2724
2723 This only removes files from the current branch, not from the
2725 This only removes files from the current branch, not from the
2724 entire project history, and it does not delete them from the
2726 entire project history, and it does not delete them from the
2725 working directory.
2727 working directory.
2726
2728
2727 To undo a forget before the next commit, see :hg:`add`.
2729 To undo a forget before the next commit, see :hg:`add`.
2728
2730
2729 .. container:: verbose
2731 .. container:: verbose
2730
2732
2731 Examples:
2733 Examples:
2732
2734
2733 - forget newly-added binary files::
2735 - forget newly-added binary files::
2734
2736
2735 hg forget "set:added() and binary()"
2737 hg forget "set:added() and binary()"
2736
2738
2737 - forget files that would be excluded by .hgignore::
2739 - forget files that would be excluded by .hgignore::
2738
2740
2739 hg forget "set:hgignore()"
2741 hg forget "set:hgignore()"
2740
2742
2741 Returns 0 on success.
2743 Returns 0 on success.
2742 """
2744 """
2743
2745
2744 if not pats:
2746 if not pats:
2745 raise util.Abort(_('no files specified'))
2747 raise util.Abort(_('no files specified'))
2746
2748
2747 m = scmutil.match(repo[None], pats, opts)
2749 m = scmutil.match(repo[None], pats, opts)
2748 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2750 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2749 return rejected and 1 or 0
2751 return rejected and 1 or 0
2750
2752
2751 @command(
2753 @command(
2752 'graft',
2754 'graft',
2753 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2755 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2754 ('c', 'continue', False, _('resume interrupted graft')),
2756 ('c', 'continue', False, _('resume interrupted graft')),
2755 ('e', 'edit', False, _('invoke editor on commit messages')),
2757 ('e', 'edit', False, _('invoke editor on commit messages')),
2756 ('', 'log', None, _('append graft info to log message')),
2758 ('', 'log', None, _('append graft info to log message')),
2757 ('D', 'currentdate', False,
2759 ('D', 'currentdate', False,
2758 _('record the current date as commit date')),
2760 _('record the current date as commit date')),
2759 ('U', 'currentuser', False,
2761 ('U', 'currentuser', False,
2760 _('record the current user as committer'), _('DATE'))]
2762 _('record the current user as committer'), _('DATE'))]
2761 + commitopts2 + mergetoolopts + dryrunopts,
2763 + commitopts2 + mergetoolopts + dryrunopts,
2762 _('[OPTION]... [-r] REV...'))
2764 _('[OPTION]... [-r] REV...'))
2763 def graft(ui, repo, *revs, **opts):
2765 def graft(ui, repo, *revs, **opts):
2764 '''copy changes from other branches onto the current branch
2766 '''copy changes from other branches onto the current branch
2765
2767
2766 This command uses Mercurial's merge logic to copy individual
2768 This command uses Mercurial's merge logic to copy individual
2767 changes from other branches without merging branches in the
2769 changes from other branches without merging branches in the
2768 history graph. This is sometimes known as 'backporting' or
2770 history graph. This is sometimes known as 'backporting' or
2769 'cherry-picking'. By default, graft will copy user, date, and
2771 'cherry-picking'. By default, graft will copy user, date, and
2770 description from the source changesets.
2772 description from the source changesets.
2771
2773
2772 Changesets that are ancestors of the current revision, that have
2774 Changesets that are ancestors of the current revision, that have
2773 already been grafted, or that are merges will be skipped.
2775 already been grafted, or that are merges will be skipped.
2774
2776
2775 If --log is specified, log messages will have a comment appended
2777 If --log is specified, log messages will have a comment appended
2776 of the form::
2778 of the form::
2777
2779
2778 (grafted from CHANGESETHASH)
2780 (grafted from CHANGESETHASH)
2779
2781
2780 If a graft merge results in conflicts, the graft process is
2782 If a graft merge results in conflicts, the graft process is
2781 interrupted so that the current merge can be manually resolved.
2783 interrupted so that the current merge can be manually resolved.
2782 Once all conflicts are addressed, the graft process can be
2784 Once all conflicts are addressed, the graft process can be
2783 continued with the -c/--continue option.
2785 continued with the -c/--continue option.
2784
2786
2785 .. note::
2787 .. note::
2786 The -c/--continue option does not reapply earlier options.
2788 The -c/--continue option does not reapply earlier options.
2787
2789
2788 .. container:: verbose
2790 .. container:: verbose
2789
2791
2790 Examples:
2792 Examples:
2791
2793
2792 - copy a single change to the stable branch and edit its description::
2794 - copy a single change to the stable branch and edit its description::
2793
2795
2794 hg update stable
2796 hg update stable
2795 hg graft --edit 9393
2797 hg graft --edit 9393
2796
2798
2797 - graft a range of changesets with one exception, updating dates::
2799 - graft a range of changesets with one exception, updating dates::
2798
2800
2799 hg graft -D "2085::2093 and not 2091"
2801 hg graft -D "2085::2093 and not 2091"
2800
2802
2801 - continue a graft after resolving conflicts::
2803 - continue a graft after resolving conflicts::
2802
2804
2803 hg graft -c
2805 hg graft -c
2804
2806
2805 - show the source of a grafted changeset::
2807 - show the source of a grafted changeset::
2806
2808
2807 hg log --debug -r tip
2809 hg log --debug -r tip
2808
2810
2809 Returns 0 on successful completion.
2811 Returns 0 on successful completion.
2810 '''
2812 '''
2811
2813
2812 revs = list(revs)
2814 revs = list(revs)
2813 revs.extend(opts['rev'])
2815 revs.extend(opts['rev'])
2814
2816
2815 if not opts.get('user') and opts.get('currentuser'):
2817 if not opts.get('user') and opts.get('currentuser'):
2816 opts['user'] = ui.username()
2818 opts['user'] = ui.username()
2817 if not opts.get('date') and opts.get('currentdate'):
2819 if not opts.get('date') and opts.get('currentdate'):
2818 opts['date'] = "%d %d" % util.makedate()
2820 opts['date'] = "%d %d" % util.makedate()
2819
2821
2820 editor = None
2822 editor = None
2821 if opts.get('edit'):
2823 if opts.get('edit'):
2822 editor = cmdutil.commitforceeditor
2824 editor = cmdutil.commitforceeditor
2823
2825
2824 cont = False
2826 cont = False
2825 if opts['continue']:
2827 if opts['continue']:
2826 cont = True
2828 cont = True
2827 if revs:
2829 if revs:
2828 raise util.Abort(_("can't specify --continue and revisions"))
2830 raise util.Abort(_("can't specify --continue and revisions"))
2829 # read in unfinished revisions
2831 # read in unfinished revisions
2830 try:
2832 try:
2831 nodes = repo.opener.read('graftstate').splitlines()
2833 nodes = repo.opener.read('graftstate').splitlines()
2832 revs = [repo[node].rev() for node in nodes]
2834 revs = [repo[node].rev() for node in nodes]
2833 except IOError, inst:
2835 except IOError, inst:
2834 if inst.errno != errno.ENOENT:
2836 if inst.errno != errno.ENOENT:
2835 raise
2837 raise
2836 raise util.Abort(_("no graft state found, can't continue"))
2838 raise util.Abort(_("no graft state found, can't continue"))
2837 else:
2839 else:
2838 cmdutil.bailifchanged(repo)
2840 cmdutil.bailifchanged(repo)
2839 if not revs:
2841 if not revs:
2840 raise util.Abort(_('no revisions specified'))
2842 raise util.Abort(_('no revisions specified'))
2841 revs = scmutil.revrange(repo, revs)
2843 revs = scmutil.revrange(repo, revs)
2842
2844
2843 # check for merges
2845 # check for merges
2844 for rev in repo.revs('%ld and merge()', revs):
2846 for rev in repo.revs('%ld and merge()', revs):
2845 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2847 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2846 revs.remove(rev)
2848 revs.remove(rev)
2847 if not revs:
2849 if not revs:
2848 return -1
2850 return -1
2849
2851
2850 # check for ancestors of dest branch
2852 # check for ancestors of dest branch
2851 for rev in repo.revs('::. and %ld', revs):
2853 for rev in repo.revs('::. and %ld', revs):
2852 ui.warn(_('skipping ancestor revision %s\n') % rev)
2854 ui.warn(_('skipping ancestor revision %s\n') % rev)
2853 revs.remove(rev)
2855 revs.remove(rev)
2854 if not revs:
2856 if not revs:
2855 return -1
2857 return -1
2856
2858
2857 # analyze revs for earlier grafts
2859 # analyze revs for earlier grafts
2858 ids = {}
2860 ids = {}
2859 for ctx in repo.set("%ld", revs):
2861 for ctx in repo.set("%ld", revs):
2860 ids[ctx.hex()] = ctx.rev()
2862 ids[ctx.hex()] = ctx.rev()
2861 n = ctx.extra().get('source')
2863 n = ctx.extra().get('source')
2862 if n:
2864 if n:
2863 ids[n] = ctx.rev()
2865 ids[n] = ctx.rev()
2864
2866
2865 # check ancestors for earlier grafts
2867 # check ancestors for earlier grafts
2866 ui.debug('scanning for duplicate grafts\n')
2868 ui.debug('scanning for duplicate grafts\n')
2867 for ctx in repo.set("::. - ::%ld", revs):
2869 for ctx in repo.set("::. - ::%ld", revs):
2868 n = ctx.extra().get('source')
2870 n = ctx.extra().get('source')
2869 if n in ids:
2871 if n in ids:
2870 r = repo[n].rev()
2872 r = repo[n].rev()
2871 if r in revs:
2873 if r in revs:
2872 ui.warn(_('skipping already grafted revision %s\n') % r)
2874 ui.warn(_('skipping already grafted revision %s\n') % r)
2873 revs.remove(r)
2875 revs.remove(r)
2874 elif ids[n] in revs:
2876 elif ids[n] in revs:
2875 ui.warn(_('skipping already grafted revision %s '
2877 ui.warn(_('skipping already grafted revision %s '
2876 '(same origin %d)\n') % (ids[n], r))
2878 '(same origin %d)\n') % (ids[n], r))
2877 revs.remove(ids[n])
2879 revs.remove(ids[n])
2878 elif ctx.hex() in ids:
2880 elif ctx.hex() in ids:
2879 r = ids[ctx.hex()]
2881 r = ids[ctx.hex()]
2880 ui.warn(_('skipping already grafted revision %s '
2882 ui.warn(_('skipping already grafted revision %s '
2881 '(was grafted from %d)\n') % (r, ctx.rev()))
2883 '(was grafted from %d)\n') % (r, ctx.rev()))
2882 revs.remove(r)
2884 revs.remove(r)
2883 if not revs:
2885 if not revs:
2884 return -1
2886 return -1
2885
2887
2886 wlock = repo.wlock()
2888 wlock = repo.wlock()
2887 try:
2889 try:
2888 current = repo['.']
2890 current = repo['.']
2889 for pos, ctx in enumerate(repo.set("%ld", revs)):
2891 for pos, ctx in enumerate(repo.set("%ld", revs)):
2890
2892
2891 ui.status(_('grafting revision %s\n') % ctx.rev())
2893 ui.status(_('grafting revision %s\n') % ctx.rev())
2892 if opts.get('dry_run'):
2894 if opts.get('dry_run'):
2893 continue
2895 continue
2894
2896
2895 source = ctx.extra().get('source')
2897 source = ctx.extra().get('source')
2896 if not source:
2898 if not source:
2897 source = ctx.hex()
2899 source = ctx.hex()
2898 extra = {'source': source}
2900 extra = {'source': source}
2899 user = ctx.user()
2901 user = ctx.user()
2900 if opts.get('user'):
2902 if opts.get('user'):
2901 user = opts['user']
2903 user = opts['user']
2902 date = ctx.date()
2904 date = ctx.date()
2903 if opts.get('date'):
2905 if opts.get('date'):
2904 date = opts['date']
2906 date = opts['date']
2905 message = ctx.description()
2907 message = ctx.description()
2906 if opts.get('log'):
2908 if opts.get('log'):
2907 message += '\n(grafted from %s)' % ctx.hex()
2909 message += '\n(grafted from %s)' % ctx.hex()
2908
2910
2909 # we don't merge the first commit when continuing
2911 # we don't merge the first commit when continuing
2910 if not cont:
2912 if not cont:
2911 # perform the graft merge with p1(rev) as 'ancestor'
2913 # perform the graft merge with p1(rev) as 'ancestor'
2912 try:
2914 try:
2913 # ui.forcemerge is an internal variable, do not document
2915 # ui.forcemerge is an internal variable, do not document
2914 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2916 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2915 stats = mergemod.update(repo, ctx.node(), True, True, False,
2917 stats = mergemod.update(repo, ctx.node(), True, True, False,
2916 ctx.p1().node())
2918 ctx.p1().node())
2917 finally:
2919 finally:
2918 repo.ui.setconfig('ui', 'forcemerge', '')
2920 repo.ui.setconfig('ui', 'forcemerge', '')
2919 # report any conflicts
2921 # report any conflicts
2920 if stats and stats[3] > 0:
2922 if stats and stats[3] > 0:
2921 # write out state for --continue
2923 # write out state for --continue
2922 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2924 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2923 repo.opener.write('graftstate', ''.join(nodelines))
2925 repo.opener.write('graftstate', ''.join(nodelines))
2924 raise util.Abort(
2926 raise util.Abort(
2925 _("unresolved conflicts, can't continue"),
2927 _("unresolved conflicts, can't continue"),
2926 hint=_('use hg resolve and hg graft --continue'))
2928 hint=_('use hg resolve and hg graft --continue'))
2927 else:
2929 else:
2928 cont = False
2930 cont = False
2929
2931
2930 # drop the second merge parent
2932 # drop the second merge parent
2931 repo.setparents(current.node(), nullid)
2933 repo.setparents(current.node(), nullid)
2932 repo.dirstate.write()
2934 repo.dirstate.write()
2933 # fix up dirstate for copies and renames
2935 # fix up dirstate for copies and renames
2934 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2936 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2935
2937
2936 # commit
2938 # commit
2937 node = repo.commit(text=message, user=user,
2939 node = repo.commit(text=message, user=user,
2938 date=date, extra=extra, editor=editor)
2940 date=date, extra=extra, editor=editor)
2939 if node is None:
2941 if node is None:
2940 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2942 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2941 else:
2943 else:
2942 current = repo[node]
2944 current = repo[node]
2943 finally:
2945 finally:
2944 wlock.release()
2946 wlock.release()
2945
2947
2946 # remove state when we complete successfully
2948 # remove state when we complete successfully
2947 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2949 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2948 util.unlinkpath(repo.join('graftstate'))
2950 util.unlinkpath(repo.join('graftstate'))
2949
2951
2950 return 0
2952 return 0
2951
2953
2952 @command('grep',
2954 @command('grep',
2953 [('0', 'print0', None, _('end fields with NUL')),
2955 [('0', 'print0', None, _('end fields with NUL')),
2954 ('', 'all', None, _('print all revisions that match')),
2956 ('', 'all', None, _('print all revisions that match')),
2955 ('a', 'text', None, _('treat all files as text')),
2957 ('a', 'text', None, _('treat all files as text')),
2956 ('f', 'follow', None,
2958 ('f', 'follow', None,
2957 _('follow changeset history,'
2959 _('follow changeset history,'
2958 ' or file history across copies and renames')),
2960 ' or file history across copies and renames')),
2959 ('i', 'ignore-case', None, _('ignore case when matching')),
2961 ('i', 'ignore-case', None, _('ignore case when matching')),
2960 ('l', 'files-with-matches', None,
2962 ('l', 'files-with-matches', None,
2961 _('print only filenames and revisions that match')),
2963 _('print only filenames and revisions that match')),
2962 ('n', 'line-number', None, _('print matching line numbers')),
2964 ('n', 'line-number', None, _('print matching line numbers')),
2963 ('r', 'rev', [],
2965 ('r', 'rev', [],
2964 _('only search files changed within revision range'), _('REV')),
2966 _('only search files changed within revision range'), _('REV')),
2965 ('u', 'user', None, _('list the author (long with -v)')),
2967 ('u', 'user', None, _('list the author (long with -v)')),
2966 ('d', 'date', None, _('list the date (short with -q)')),
2968 ('d', 'date', None, _('list the date (short with -q)')),
2967 ] + walkopts,
2969 ] + walkopts,
2968 _('[OPTION]... PATTERN [FILE]...'))
2970 _('[OPTION]... PATTERN [FILE]...'))
2969 def grep(ui, repo, pattern, *pats, **opts):
2971 def grep(ui, repo, pattern, *pats, **opts):
2970 """search for a pattern in specified files and revisions
2972 """search for a pattern in specified files and revisions
2971
2973
2972 Search revisions of files for a regular expression.
2974 Search revisions of files for a regular expression.
2973
2975
2974 This command behaves differently than Unix grep. It only accepts
2976 This command behaves differently than Unix grep. It only accepts
2975 Python/Perl regexps. It searches repository history, not the
2977 Python/Perl regexps. It searches repository history, not the
2976 working directory. It always prints the revision number in which a
2978 working directory. It always prints the revision number in which a
2977 match appears.
2979 match appears.
2978
2980
2979 By default, grep only prints output for the first revision of a
2981 By default, grep only prints output for the first revision of a
2980 file in which it finds a match. To get it to print every revision
2982 file in which it finds a match. To get it to print every revision
2981 that contains a change in match status ("-" for a match that
2983 that contains a change in match status ("-" for a match that
2982 becomes a non-match, or "+" for a non-match that becomes a match),
2984 becomes a non-match, or "+" for a non-match that becomes a match),
2983 use the --all flag.
2985 use the --all flag.
2984
2986
2985 Returns 0 if a match is found, 1 otherwise.
2987 Returns 0 if a match is found, 1 otherwise.
2986 """
2988 """
2987 reflags = re.M
2989 reflags = re.M
2988 if opts.get('ignore_case'):
2990 if opts.get('ignore_case'):
2989 reflags |= re.I
2991 reflags |= re.I
2990 try:
2992 try:
2991 regexp = re.compile(pattern, reflags)
2993 regexp = re.compile(pattern, reflags)
2992 except re.error, inst:
2994 except re.error, inst:
2993 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2995 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2994 return 1
2996 return 1
2995 sep, eol = ':', '\n'
2997 sep, eol = ':', '\n'
2996 if opts.get('print0'):
2998 if opts.get('print0'):
2997 sep = eol = '\0'
2999 sep = eol = '\0'
2998
3000
2999 getfile = util.lrucachefunc(repo.file)
3001 getfile = util.lrucachefunc(repo.file)
3000
3002
3001 def matchlines(body):
3003 def matchlines(body):
3002 begin = 0
3004 begin = 0
3003 linenum = 0
3005 linenum = 0
3004 while begin < len(body):
3006 while begin < len(body):
3005 match = regexp.search(body, begin)
3007 match = regexp.search(body, begin)
3006 if not match:
3008 if not match:
3007 break
3009 break
3008 mstart, mend = match.span()
3010 mstart, mend = match.span()
3009 linenum += body.count('\n', begin, mstart) + 1
3011 linenum += body.count('\n', begin, mstart) + 1
3010 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3012 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3011 begin = body.find('\n', mend) + 1 or len(body) + 1
3013 begin = body.find('\n', mend) + 1 or len(body) + 1
3012 lend = begin - 1
3014 lend = begin - 1
3013 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3015 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3014
3016
3015 class linestate(object):
3017 class linestate(object):
3016 def __init__(self, line, linenum, colstart, colend):
3018 def __init__(self, line, linenum, colstart, colend):
3017 self.line = line
3019 self.line = line
3018 self.linenum = linenum
3020 self.linenum = linenum
3019 self.colstart = colstart
3021 self.colstart = colstart
3020 self.colend = colend
3022 self.colend = colend
3021
3023
3022 def __hash__(self):
3024 def __hash__(self):
3023 return hash((self.linenum, self.line))
3025 return hash((self.linenum, self.line))
3024
3026
3025 def __eq__(self, other):
3027 def __eq__(self, other):
3026 return self.line == other.line
3028 return self.line == other.line
3027
3029
3028 matches = {}
3030 matches = {}
3029 copies = {}
3031 copies = {}
3030 def grepbody(fn, rev, body):
3032 def grepbody(fn, rev, body):
3031 matches[rev].setdefault(fn, [])
3033 matches[rev].setdefault(fn, [])
3032 m = matches[rev][fn]
3034 m = matches[rev][fn]
3033 for lnum, cstart, cend, line in matchlines(body):
3035 for lnum, cstart, cend, line in matchlines(body):
3034 s = linestate(line, lnum, cstart, cend)
3036 s = linestate(line, lnum, cstart, cend)
3035 m.append(s)
3037 m.append(s)
3036
3038
3037 def difflinestates(a, b):
3039 def difflinestates(a, b):
3038 sm = difflib.SequenceMatcher(None, a, b)
3040 sm = difflib.SequenceMatcher(None, a, b)
3039 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3041 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3040 if tag == 'insert':
3042 if tag == 'insert':
3041 for i in xrange(blo, bhi):
3043 for i in xrange(blo, bhi):
3042 yield ('+', b[i])
3044 yield ('+', b[i])
3043 elif tag == 'delete':
3045 elif tag == 'delete':
3044 for i in xrange(alo, ahi):
3046 for i in xrange(alo, ahi):
3045 yield ('-', a[i])
3047 yield ('-', a[i])
3046 elif tag == 'replace':
3048 elif tag == 'replace':
3047 for i in xrange(alo, ahi):
3049 for i in xrange(alo, ahi):
3048 yield ('-', a[i])
3050 yield ('-', a[i])
3049 for i in xrange(blo, bhi):
3051 for i in xrange(blo, bhi):
3050 yield ('+', b[i])
3052 yield ('+', b[i])
3051
3053
3052 def display(fn, ctx, pstates, states):
3054 def display(fn, ctx, pstates, states):
3053 rev = ctx.rev()
3055 rev = ctx.rev()
3054 datefunc = ui.quiet and util.shortdate or util.datestr
3056 datefunc = ui.quiet and util.shortdate or util.datestr
3055 found = False
3057 found = False
3056 filerevmatches = {}
3058 filerevmatches = {}
3057 def binary():
3059 def binary():
3058 flog = getfile(fn)
3060 flog = getfile(fn)
3059 return util.binary(flog.read(ctx.filenode(fn)))
3061 return util.binary(flog.read(ctx.filenode(fn)))
3060
3062
3061 if opts.get('all'):
3063 if opts.get('all'):
3062 iter = difflinestates(pstates, states)
3064 iter = difflinestates(pstates, states)
3063 else:
3065 else:
3064 iter = [('', l) for l in states]
3066 iter = [('', l) for l in states]
3065 for change, l in iter:
3067 for change, l in iter:
3066 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3068 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3067 before, match, after = None, None, None
3069 before, match, after = None, None, None
3068
3070
3069 if opts.get('line_number'):
3071 if opts.get('line_number'):
3070 cols.append((str(l.linenum), 'grep.linenumber'))
3072 cols.append((str(l.linenum), 'grep.linenumber'))
3071 if opts.get('all'):
3073 if opts.get('all'):
3072 cols.append((change, 'grep.change'))
3074 cols.append((change, 'grep.change'))
3073 if opts.get('user'):
3075 if opts.get('user'):
3074 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3076 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3075 if opts.get('date'):
3077 if opts.get('date'):
3076 cols.append((datefunc(ctx.date()), 'grep.date'))
3078 cols.append((datefunc(ctx.date()), 'grep.date'))
3077 if opts.get('files_with_matches'):
3079 if opts.get('files_with_matches'):
3078 c = (fn, rev)
3080 c = (fn, rev)
3079 if c in filerevmatches:
3081 if c in filerevmatches:
3080 continue
3082 continue
3081 filerevmatches[c] = 1
3083 filerevmatches[c] = 1
3082 else:
3084 else:
3083 before = l.line[:l.colstart]
3085 before = l.line[:l.colstart]
3084 match = l.line[l.colstart:l.colend]
3086 match = l.line[l.colstart:l.colend]
3085 after = l.line[l.colend:]
3087 after = l.line[l.colend:]
3086 for col, label in cols[:-1]:
3088 for col, label in cols[:-1]:
3087 ui.write(col, label=label)
3089 ui.write(col, label=label)
3088 ui.write(sep, label='grep.sep')
3090 ui.write(sep, label='grep.sep')
3089 ui.write(cols[-1][0], label=cols[-1][1])
3091 ui.write(cols[-1][0], label=cols[-1][1])
3090 if before is not None:
3092 if before is not None:
3091 ui.write(sep, label='grep.sep')
3093 ui.write(sep, label='grep.sep')
3092 if not opts.get('text') and binary():
3094 if not opts.get('text') and binary():
3093 ui.write(" Binary file matches")
3095 ui.write(" Binary file matches")
3094 else:
3096 else:
3095 ui.write(before)
3097 ui.write(before)
3096 ui.write(match, label='grep.match')
3098 ui.write(match, label='grep.match')
3097 ui.write(after)
3099 ui.write(after)
3098 ui.write(eol)
3100 ui.write(eol)
3099 found = True
3101 found = True
3100 return found
3102 return found
3101
3103
3102 skip = {}
3104 skip = {}
3103 revfiles = {}
3105 revfiles = {}
3104 matchfn = scmutil.match(repo[None], pats, opts)
3106 matchfn = scmutil.match(repo[None], pats, opts)
3105 found = False
3107 found = False
3106 follow = opts.get('follow')
3108 follow = opts.get('follow')
3107
3109
3108 def prep(ctx, fns):
3110 def prep(ctx, fns):
3109 rev = ctx.rev()
3111 rev = ctx.rev()
3110 pctx = ctx.p1()
3112 pctx = ctx.p1()
3111 parent = pctx.rev()
3113 parent = pctx.rev()
3112 matches.setdefault(rev, {})
3114 matches.setdefault(rev, {})
3113 matches.setdefault(parent, {})
3115 matches.setdefault(parent, {})
3114 files = revfiles.setdefault(rev, [])
3116 files = revfiles.setdefault(rev, [])
3115 for fn in fns:
3117 for fn in fns:
3116 flog = getfile(fn)
3118 flog = getfile(fn)
3117 try:
3119 try:
3118 fnode = ctx.filenode(fn)
3120 fnode = ctx.filenode(fn)
3119 except error.LookupError:
3121 except error.LookupError:
3120 continue
3122 continue
3121
3123
3122 copied = flog.renamed(fnode)
3124 copied = flog.renamed(fnode)
3123 copy = follow and copied and copied[0]
3125 copy = follow and copied and copied[0]
3124 if copy:
3126 if copy:
3125 copies.setdefault(rev, {})[fn] = copy
3127 copies.setdefault(rev, {})[fn] = copy
3126 if fn in skip:
3128 if fn in skip:
3127 if copy:
3129 if copy:
3128 skip[copy] = True
3130 skip[copy] = True
3129 continue
3131 continue
3130 files.append(fn)
3132 files.append(fn)
3131
3133
3132 if fn not in matches[rev]:
3134 if fn not in matches[rev]:
3133 grepbody(fn, rev, flog.read(fnode))
3135 grepbody(fn, rev, flog.read(fnode))
3134
3136
3135 pfn = copy or fn
3137 pfn = copy or fn
3136 if pfn not in matches[parent]:
3138 if pfn not in matches[parent]:
3137 try:
3139 try:
3138 fnode = pctx.filenode(pfn)
3140 fnode = pctx.filenode(pfn)
3139 grepbody(pfn, parent, flog.read(fnode))
3141 grepbody(pfn, parent, flog.read(fnode))
3140 except error.LookupError:
3142 except error.LookupError:
3141 pass
3143 pass
3142
3144
3143 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3145 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3144 rev = ctx.rev()
3146 rev = ctx.rev()
3145 parent = ctx.p1().rev()
3147 parent = ctx.p1().rev()
3146 for fn in sorted(revfiles.get(rev, [])):
3148 for fn in sorted(revfiles.get(rev, [])):
3147 states = matches[rev][fn]
3149 states = matches[rev][fn]
3148 copy = copies.get(rev, {}).get(fn)
3150 copy = copies.get(rev, {}).get(fn)
3149 if fn in skip:
3151 if fn in skip:
3150 if copy:
3152 if copy:
3151 skip[copy] = True
3153 skip[copy] = True
3152 continue
3154 continue
3153 pstates = matches.get(parent, {}).get(copy or fn, [])
3155 pstates = matches.get(parent, {}).get(copy or fn, [])
3154 if pstates or states:
3156 if pstates or states:
3155 r = display(fn, ctx, pstates, states)
3157 r = display(fn, ctx, pstates, states)
3156 found = found or r
3158 found = found or r
3157 if r and not opts.get('all'):
3159 if r and not opts.get('all'):
3158 skip[fn] = True
3160 skip[fn] = True
3159 if copy:
3161 if copy:
3160 skip[copy] = True
3162 skip[copy] = True
3161 del matches[rev]
3163 del matches[rev]
3162 del revfiles[rev]
3164 del revfiles[rev]
3163
3165
3164 return not found
3166 return not found
3165
3167
3166 @command('heads',
3168 @command('heads',
3167 [('r', 'rev', '',
3169 [('r', 'rev', '',
3168 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3170 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3169 ('t', 'topo', False, _('show topological heads only')),
3171 ('t', 'topo', False, _('show topological heads only')),
3170 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3172 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3171 ('c', 'closed', False, _('show normal and closed branch heads')),
3173 ('c', 'closed', False, _('show normal and closed branch heads')),
3172 ] + templateopts,
3174 ] + templateopts,
3173 _('[-ct] [-r STARTREV] [REV]...'))
3175 _('[-ct] [-r STARTREV] [REV]...'))
3174 def heads(ui, repo, *branchrevs, **opts):
3176 def heads(ui, repo, *branchrevs, **opts):
3175 """show current repository heads or show branch heads
3177 """show current repository heads or show branch heads
3176
3178
3177 With no arguments, show all repository branch heads.
3179 With no arguments, show all repository branch heads.
3178
3180
3179 Repository "heads" are changesets with no child changesets. They are
3181 Repository "heads" are changesets with no child changesets. They are
3180 where development generally takes place and are the usual targets
3182 where development generally takes place and are the usual targets
3181 for update and merge operations. Branch heads are changesets that have
3183 for update and merge operations. Branch heads are changesets that have
3182 no child changeset on the same branch.
3184 no child changeset on the same branch.
3183
3185
3184 If one or more REVs are given, only branch heads on the branches
3186 If one or more REVs are given, only branch heads on the branches
3185 associated with the specified changesets are shown. This means
3187 associated with the specified changesets are shown. This means
3186 that you can use :hg:`heads foo` to see the heads on a branch
3188 that you can use :hg:`heads foo` to see the heads on a branch
3187 named ``foo``.
3189 named ``foo``.
3188
3190
3189 If -c/--closed is specified, also show branch heads marked closed
3191 If -c/--closed is specified, also show branch heads marked closed
3190 (see :hg:`commit --close-branch`).
3192 (see :hg:`commit --close-branch`).
3191
3193
3192 If STARTREV is specified, only those heads that are descendants of
3194 If STARTREV is specified, only those heads that are descendants of
3193 STARTREV will be displayed.
3195 STARTREV will be displayed.
3194
3196
3195 If -t/--topo is specified, named branch mechanics will be ignored and only
3197 If -t/--topo is specified, named branch mechanics will be ignored and only
3196 changesets without children will be shown.
3198 changesets without children will be shown.
3197
3199
3198 Returns 0 if matching heads are found, 1 if not.
3200 Returns 0 if matching heads are found, 1 if not.
3199 """
3201 """
3200
3202
3201 start = None
3203 start = None
3202 if 'rev' in opts:
3204 if 'rev' in opts:
3203 start = scmutil.revsingle(repo, opts['rev'], None).node()
3205 start = scmutil.revsingle(repo, opts['rev'], None).node()
3204
3206
3205 if opts.get('topo'):
3207 if opts.get('topo'):
3206 heads = [repo[h] for h in repo.heads(start)]
3208 heads = [repo[h] for h in repo.heads(start)]
3207 else:
3209 else:
3208 heads = []
3210 heads = []
3209 for branch in repo.branchmap():
3211 for branch in repo.branchmap():
3210 heads += repo.branchheads(branch, start, opts.get('closed'))
3212 heads += repo.branchheads(branch, start, opts.get('closed'))
3211 heads = [repo[h] for h in heads]
3213 heads = [repo[h] for h in heads]
3212
3214
3213 if branchrevs:
3215 if branchrevs:
3214 branches = set(repo[br].branch() for br in branchrevs)
3216 branches = set(repo[br].branch() for br in branchrevs)
3215 heads = [h for h in heads if h.branch() in branches]
3217 heads = [h for h in heads if h.branch() in branches]
3216
3218
3217 if opts.get('active') and branchrevs:
3219 if opts.get('active') and branchrevs:
3218 dagheads = repo.heads(start)
3220 dagheads = repo.heads(start)
3219 heads = [h for h in heads if h.node() in dagheads]
3221 heads = [h for h in heads if h.node() in dagheads]
3220
3222
3221 if branchrevs:
3223 if branchrevs:
3222 haveheads = set(h.branch() for h in heads)
3224 haveheads = set(h.branch() for h in heads)
3223 if branches - haveheads:
3225 if branches - haveheads:
3224 headless = ', '.join(b for b in branches - haveheads)
3226 headless = ', '.join(b for b in branches - haveheads)
3225 msg = _('no open branch heads found on branches %s')
3227 msg = _('no open branch heads found on branches %s')
3226 if opts.get('rev'):
3228 if opts.get('rev'):
3227 msg += _(' (started at %s)') % opts['rev']
3229 msg += _(' (started at %s)') % opts['rev']
3228 ui.warn((msg + '\n') % headless)
3230 ui.warn((msg + '\n') % headless)
3229
3231
3230 if not heads:
3232 if not heads:
3231 return 1
3233 return 1
3232
3234
3233 heads = sorted(heads, key=lambda x: -x.rev())
3235 heads = sorted(heads, key=lambda x: -x.rev())
3234 displayer = cmdutil.show_changeset(ui, repo, opts)
3236 displayer = cmdutil.show_changeset(ui, repo, opts)
3235 for ctx in heads:
3237 for ctx in heads:
3236 displayer.show(ctx)
3238 displayer.show(ctx)
3237 displayer.close()
3239 displayer.close()
3238
3240
3239 @command('help',
3241 @command('help',
3240 [('e', 'extension', None, _('show only help for extensions')),
3242 [('e', 'extension', None, _('show only help for extensions')),
3241 ('c', 'command', None, _('show only help for commands')),
3243 ('c', 'command', None, _('show only help for commands')),
3242 ('k', 'keyword', '', _('show topics matching keyword')),
3244 ('k', 'keyword', '', _('show topics matching keyword')),
3243 ],
3245 ],
3244 _('[-ec] [TOPIC]'))
3246 _('[-ec] [TOPIC]'))
3245 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3247 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3246 """show help for a given topic or a help overview
3248 """show help for a given topic or a help overview
3247
3249
3248 With no arguments, print a list of commands with short help messages.
3250 With no arguments, print a list of commands with short help messages.
3249
3251
3250 Given a topic, extension, or command name, print help for that
3252 Given a topic, extension, or command name, print help for that
3251 topic.
3253 topic.
3252
3254
3253 Returns 0 if successful.
3255 Returns 0 if successful.
3254 """
3256 """
3255
3257
3256 textwidth = min(ui.termwidth(), 80) - 2
3258 textwidth = min(ui.termwidth(), 80) - 2
3257
3259
3258 def helpcmd(name):
3260 def helpcmd(name):
3259 try:
3261 try:
3260 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3262 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3261 except error.AmbiguousCommand, inst:
3263 except error.AmbiguousCommand, inst:
3262 # py3k fix: except vars can't be used outside the scope of the
3264 # py3k fix: except vars can't be used outside the scope of the
3263 # except block, nor can be used inside a lambda. python issue4617
3265 # except block, nor can be used inside a lambda. python issue4617
3264 prefix = inst.args[0]
3266 prefix = inst.args[0]
3265 select = lambda c: c.lstrip('^').startswith(prefix)
3267 select = lambda c: c.lstrip('^').startswith(prefix)
3266 rst = helplist(select)
3268 rst = helplist(select)
3267 return rst
3269 return rst
3268
3270
3269 rst = []
3271 rst = []
3270
3272
3271 # check if it's an invalid alias and display its error if it is
3273 # check if it's an invalid alias and display its error if it is
3272 if getattr(entry[0], 'badalias', False):
3274 if getattr(entry[0], 'badalias', False):
3273 if not unknowncmd:
3275 if not unknowncmd:
3274 ui.pushbuffer()
3276 ui.pushbuffer()
3275 entry[0](ui)
3277 entry[0](ui)
3276 rst.append(ui.popbuffer())
3278 rst.append(ui.popbuffer())
3277 return rst
3279 return rst
3278
3280
3279 # synopsis
3281 # synopsis
3280 if len(entry) > 2:
3282 if len(entry) > 2:
3281 if entry[2].startswith('hg'):
3283 if entry[2].startswith('hg'):
3282 rst.append("%s\n" % entry[2])
3284 rst.append("%s\n" % entry[2])
3283 else:
3285 else:
3284 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3286 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3285 else:
3287 else:
3286 rst.append('hg %s\n' % aliases[0])
3288 rst.append('hg %s\n' % aliases[0])
3287 # aliases
3289 # aliases
3288 if full and not ui.quiet and len(aliases) > 1:
3290 if full and not ui.quiet and len(aliases) > 1:
3289 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3291 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3290 rst.append('\n')
3292 rst.append('\n')
3291
3293
3292 # description
3294 # description
3293 doc = gettext(entry[0].__doc__)
3295 doc = gettext(entry[0].__doc__)
3294 if not doc:
3296 if not doc:
3295 doc = _("(no help text available)")
3297 doc = _("(no help text available)")
3296 if util.safehasattr(entry[0], 'definition'): # aliased command
3298 if util.safehasattr(entry[0], 'definition'): # aliased command
3297 if entry[0].definition.startswith('!'): # shell alias
3299 if entry[0].definition.startswith('!'): # shell alias
3298 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3300 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3299 else:
3301 else:
3300 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3302 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3301 doc = doc.splitlines(True)
3303 doc = doc.splitlines(True)
3302 if ui.quiet or not full:
3304 if ui.quiet or not full:
3303 rst.append(doc[0])
3305 rst.append(doc[0])
3304 else:
3306 else:
3305 rst.extend(doc)
3307 rst.extend(doc)
3306 rst.append('\n')
3308 rst.append('\n')
3307
3309
3308 # check if this command shadows a non-trivial (multi-line)
3310 # check if this command shadows a non-trivial (multi-line)
3309 # extension help text
3311 # extension help text
3310 try:
3312 try:
3311 mod = extensions.find(name)
3313 mod = extensions.find(name)
3312 doc = gettext(mod.__doc__) or ''
3314 doc = gettext(mod.__doc__) or ''
3313 if '\n' in doc.strip():
3315 if '\n' in doc.strip():
3314 msg = _('use "hg help -e %s" to show help for '
3316 msg = _('use "hg help -e %s" to show help for '
3315 'the %s extension') % (name, name)
3317 'the %s extension') % (name, name)
3316 rst.append('\n%s\n' % msg)
3318 rst.append('\n%s\n' % msg)
3317 except KeyError:
3319 except KeyError:
3318 pass
3320 pass
3319
3321
3320 # options
3322 # options
3321 if not ui.quiet and entry[1]:
3323 if not ui.quiet and entry[1]:
3322 rst.append('\n%s\n\n' % _("options:"))
3324 rst.append('\n%s\n\n' % _("options:"))
3323 rst.append(help.optrst(entry[1], ui.verbose))
3325 rst.append(help.optrst(entry[1], ui.verbose))
3324
3326
3325 if ui.verbose:
3327 if ui.verbose:
3326 rst.append('\n%s\n\n' % _("global options:"))
3328 rst.append('\n%s\n\n' % _("global options:"))
3327 rst.append(help.optrst(globalopts, ui.verbose))
3329 rst.append(help.optrst(globalopts, ui.verbose))
3328
3330
3329 if not ui.verbose:
3331 if not ui.verbose:
3330 if not full:
3332 if not full:
3331 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3333 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3332 % name)
3334 % name)
3333 elif not ui.quiet:
3335 elif not ui.quiet:
3334 omitted = _('use "hg -v help %s" to show more complete'
3336 omitted = _('use "hg -v help %s" to show more complete'
3335 ' help and the global options') % name
3337 ' help and the global options') % name
3336 notomitted = _('use "hg -v help %s" to show'
3338 notomitted = _('use "hg -v help %s" to show'
3337 ' the global options') % name
3339 ' the global options') % name
3338 help.indicateomitted(rst, omitted, notomitted)
3340 help.indicateomitted(rst, omitted, notomitted)
3339
3341
3340 return rst
3342 return rst
3341
3343
3342
3344
3343 def helplist(select=None):
3345 def helplist(select=None):
3344 # list of commands
3346 # list of commands
3345 if name == "shortlist":
3347 if name == "shortlist":
3346 header = _('basic commands:\n\n')
3348 header = _('basic commands:\n\n')
3347 else:
3349 else:
3348 header = _('list of commands:\n\n')
3350 header = _('list of commands:\n\n')
3349
3351
3350 h = {}
3352 h = {}
3351 cmds = {}
3353 cmds = {}
3352 for c, e in table.iteritems():
3354 for c, e in table.iteritems():
3353 f = c.split("|", 1)[0]
3355 f = c.split("|", 1)[0]
3354 if select and not select(f):
3356 if select and not select(f):
3355 continue
3357 continue
3356 if (not select and name != 'shortlist' and
3358 if (not select and name != 'shortlist' and
3357 e[0].__module__ != __name__):
3359 e[0].__module__ != __name__):
3358 continue
3360 continue
3359 if name == "shortlist" and not f.startswith("^"):
3361 if name == "shortlist" and not f.startswith("^"):
3360 continue
3362 continue
3361 f = f.lstrip("^")
3363 f = f.lstrip("^")
3362 if not ui.debugflag and f.startswith("debug"):
3364 if not ui.debugflag and f.startswith("debug"):
3363 continue
3365 continue
3364 doc = e[0].__doc__
3366 doc = e[0].__doc__
3365 if doc and 'DEPRECATED' in doc and not ui.verbose:
3367 if doc and 'DEPRECATED' in doc and not ui.verbose:
3366 continue
3368 continue
3367 doc = gettext(doc)
3369 doc = gettext(doc)
3368 if not doc:
3370 if not doc:
3369 doc = _("(no help text available)")
3371 doc = _("(no help text available)")
3370 h[f] = doc.splitlines()[0].rstrip()
3372 h[f] = doc.splitlines()[0].rstrip()
3371 cmds[f] = c.lstrip("^")
3373 cmds[f] = c.lstrip("^")
3372
3374
3373 rst = []
3375 rst = []
3374 if not h:
3376 if not h:
3375 if not ui.quiet:
3377 if not ui.quiet:
3376 rst.append(_('no commands defined\n'))
3378 rst.append(_('no commands defined\n'))
3377 return rst
3379 return rst
3378
3380
3379 if not ui.quiet:
3381 if not ui.quiet:
3380 rst.append(header)
3382 rst.append(header)
3381 fns = sorted(h)
3383 fns = sorted(h)
3382 for f in fns:
3384 for f in fns:
3383 if ui.verbose:
3385 if ui.verbose:
3384 commands = cmds[f].replace("|",", ")
3386 commands = cmds[f].replace("|",", ")
3385 rst.append(" :%s: %s\n" % (commands, h[f]))
3387 rst.append(" :%s: %s\n" % (commands, h[f]))
3386 else:
3388 else:
3387 rst.append(' :%s: %s\n' % (f, h[f]))
3389 rst.append(' :%s: %s\n' % (f, h[f]))
3388
3390
3389 if not name:
3391 if not name:
3390 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3392 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3391 if exts:
3393 if exts:
3392 rst.append('\n')
3394 rst.append('\n')
3393 rst.extend(exts)
3395 rst.extend(exts)
3394
3396
3395 rst.append(_("\nadditional help topics:\n\n"))
3397 rst.append(_("\nadditional help topics:\n\n"))
3396 topics = []
3398 topics = []
3397 for names, header, doc in help.helptable:
3399 for names, header, doc in help.helptable:
3398 topics.append((names[0], header))
3400 topics.append((names[0], header))
3399 for t, desc in topics:
3401 for t, desc in topics:
3400 rst.append(" :%s: %s\n" % (t, desc))
3402 rst.append(" :%s: %s\n" % (t, desc))
3401
3403
3402 optlist = []
3404 optlist = []
3403 if not ui.quiet:
3405 if not ui.quiet:
3404 if ui.verbose:
3406 if ui.verbose:
3405 optlist.append((_("global options:"), globalopts))
3407 optlist.append((_("global options:"), globalopts))
3406 if name == 'shortlist':
3408 if name == 'shortlist':
3407 optlist.append((_('use "hg help" for the full list '
3409 optlist.append((_('use "hg help" for the full list '
3408 'of commands'), ()))
3410 'of commands'), ()))
3409 else:
3411 else:
3410 if name == 'shortlist':
3412 if name == 'shortlist':
3411 msg = _('use "hg help" for the full list of commands '
3413 msg = _('use "hg help" for the full list of commands '
3412 'or "hg -v" for details')
3414 'or "hg -v" for details')
3413 elif name and not full:
3415 elif name and not full:
3414 msg = _('use "hg help %s" to show the full help '
3416 msg = _('use "hg help %s" to show the full help '
3415 'text') % name
3417 'text') % name
3416 else:
3418 else:
3417 msg = _('use "hg -v help%s" to show builtin aliases and '
3419 msg = _('use "hg -v help%s" to show builtin aliases and '
3418 'global options') % (name and " " + name or "")
3420 'global options') % (name and " " + name or "")
3419 optlist.append((msg, ()))
3421 optlist.append((msg, ()))
3420
3422
3421 if optlist:
3423 if optlist:
3422 for title, options in optlist:
3424 for title, options in optlist:
3423 rst.append('\n%s\n' % title)
3425 rst.append('\n%s\n' % title)
3424 if options:
3426 if options:
3425 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3427 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3426 return rst
3428 return rst
3427
3429
3428 def helptopic(name):
3430 def helptopic(name):
3429 for names, header, doc in help.helptable:
3431 for names, header, doc in help.helptable:
3430 if name in names:
3432 if name in names:
3431 break
3433 break
3432 else:
3434 else:
3433 raise error.UnknownCommand(name)
3435 raise error.UnknownCommand(name)
3434
3436
3435 rst = ["%s\n\n" % header]
3437 rst = ["%s\n\n" % header]
3436 # description
3438 # description
3437 if not doc:
3439 if not doc:
3438 rst.append(" %s\n" % _("(no help text available)"))
3440 rst.append(" %s\n" % _("(no help text available)"))
3439 if util.safehasattr(doc, '__call__'):
3441 if util.safehasattr(doc, '__call__'):
3440 rst += [" %s\n" % l for l in doc().splitlines()]
3442 rst += [" %s\n" % l for l in doc().splitlines()]
3441
3443
3442 if not ui.verbose:
3444 if not ui.verbose:
3443 omitted = (_('use "hg help -v %s" to show more complete help') %
3445 omitted = (_('use "hg help -v %s" to show more complete help') %
3444 name)
3446 name)
3445 help.indicateomitted(rst, omitted)
3447 help.indicateomitted(rst, omitted)
3446
3448
3447 try:
3449 try:
3448 cmdutil.findcmd(name, table)
3450 cmdutil.findcmd(name, table)
3449 rst.append(_('\nuse "hg help -c %s" to see help for '
3451 rst.append(_('\nuse "hg help -c %s" to see help for '
3450 'the %s command\n') % (name, name))
3452 'the %s command\n') % (name, name))
3451 except error.UnknownCommand:
3453 except error.UnknownCommand:
3452 pass
3454 pass
3453 return rst
3455 return rst
3454
3456
3455 def helpext(name):
3457 def helpext(name):
3456 try:
3458 try:
3457 mod = extensions.find(name)
3459 mod = extensions.find(name)
3458 doc = gettext(mod.__doc__) or _('no help text available')
3460 doc = gettext(mod.__doc__) or _('no help text available')
3459 except KeyError:
3461 except KeyError:
3460 mod = None
3462 mod = None
3461 doc = extensions.disabledext(name)
3463 doc = extensions.disabledext(name)
3462 if not doc:
3464 if not doc:
3463 raise error.UnknownCommand(name)
3465 raise error.UnknownCommand(name)
3464
3466
3465 if '\n' not in doc:
3467 if '\n' not in doc:
3466 head, tail = doc, ""
3468 head, tail = doc, ""
3467 else:
3469 else:
3468 head, tail = doc.split('\n', 1)
3470 head, tail = doc.split('\n', 1)
3469 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3471 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3470 if tail:
3472 if tail:
3471 rst.extend(tail.splitlines(True))
3473 rst.extend(tail.splitlines(True))
3472 rst.append('\n')
3474 rst.append('\n')
3473
3475
3474 if not ui.verbose:
3476 if not ui.verbose:
3475 omitted = (_('use "hg help -v %s" to show more complete help') %
3477 omitted = (_('use "hg help -v %s" to show more complete help') %
3476 name)
3478 name)
3477 help.indicateomitted(rst, omitted)
3479 help.indicateomitted(rst, omitted)
3478
3480
3479 if mod:
3481 if mod:
3480 try:
3482 try:
3481 ct = mod.cmdtable
3483 ct = mod.cmdtable
3482 except AttributeError:
3484 except AttributeError:
3483 ct = {}
3485 ct = {}
3484 modcmds = set([c.split('|', 1)[0] for c in ct])
3486 modcmds = set([c.split('|', 1)[0] for c in ct])
3485 rst.extend(helplist(modcmds.__contains__))
3487 rst.extend(helplist(modcmds.__contains__))
3486 else:
3488 else:
3487 rst.append(_('use "hg help extensions" for information on enabling '
3489 rst.append(_('use "hg help extensions" for information on enabling '
3488 'extensions\n'))
3490 'extensions\n'))
3489 return rst
3491 return rst
3490
3492
3491 def helpextcmd(name):
3493 def helpextcmd(name):
3492 cmd, ext, mod = extensions.disabledcmd(ui, name,
3494 cmd, ext, mod = extensions.disabledcmd(ui, name,
3493 ui.configbool('ui', 'strict'))
3495 ui.configbool('ui', 'strict'))
3494 doc = gettext(mod.__doc__).splitlines()[0]
3496 doc = gettext(mod.__doc__).splitlines()[0]
3495
3497
3496 rst = help.listexts(_("'%s' is provided by the following "
3498 rst = help.listexts(_("'%s' is provided by the following "
3497 "extension:") % cmd, {ext: doc}, indent=4)
3499 "extension:") % cmd, {ext: doc}, indent=4)
3498 rst.append('\n')
3500 rst.append('\n')
3499 rst.append(_('use "hg help extensions" for information on enabling '
3501 rst.append(_('use "hg help extensions" for information on enabling '
3500 'extensions\n'))
3502 'extensions\n'))
3501 return rst
3503 return rst
3502
3504
3503
3505
3504 rst = []
3506 rst = []
3505 kw = opts.get('keyword')
3507 kw = opts.get('keyword')
3506 if kw:
3508 if kw:
3507 matches = help.topicmatch(kw)
3509 matches = help.topicmatch(kw)
3508 for t, title in (('topics', _('Topics')),
3510 for t, title in (('topics', _('Topics')),
3509 ('commands', _('Commands')),
3511 ('commands', _('Commands')),
3510 ('extensions', _('Extensions')),
3512 ('extensions', _('Extensions')),
3511 ('extensioncommands', _('Extension Commands'))):
3513 ('extensioncommands', _('Extension Commands'))):
3512 if matches[t]:
3514 if matches[t]:
3513 rst.append('%s:\n\n' % title)
3515 rst.append('%s:\n\n' % title)
3514 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3516 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3515 rst.append('\n')
3517 rst.append('\n')
3516 elif name and name != 'shortlist':
3518 elif name and name != 'shortlist':
3517 i = None
3519 i = None
3518 if unknowncmd:
3520 if unknowncmd:
3519 queries = (helpextcmd,)
3521 queries = (helpextcmd,)
3520 elif opts.get('extension'):
3522 elif opts.get('extension'):
3521 queries = (helpext,)
3523 queries = (helpext,)
3522 elif opts.get('command'):
3524 elif opts.get('command'):
3523 queries = (helpcmd,)
3525 queries = (helpcmd,)
3524 else:
3526 else:
3525 queries = (helptopic, helpcmd, helpext, helpextcmd)
3527 queries = (helptopic, helpcmd, helpext, helpextcmd)
3526 for f in queries:
3528 for f in queries:
3527 try:
3529 try:
3528 rst = f(name)
3530 rst = f(name)
3529 i = None
3531 i = None
3530 break
3532 break
3531 except error.UnknownCommand, inst:
3533 except error.UnknownCommand, inst:
3532 i = inst
3534 i = inst
3533 if i:
3535 if i:
3534 raise i
3536 raise i
3535 else:
3537 else:
3536 # program name
3538 # program name
3537 if not ui.quiet:
3539 if not ui.quiet:
3538 rst = [_("Mercurial Distributed SCM\n"), '\n']
3540 rst = [_("Mercurial Distributed SCM\n"), '\n']
3539 rst.extend(helplist())
3541 rst.extend(helplist())
3540
3542
3541 keep = ui.verbose and ['verbose'] or []
3543 keep = ui.verbose and ['verbose'] or []
3542 text = ''.join(rst)
3544 text = ''.join(rst)
3543 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3545 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3544 if 'verbose' in pruned:
3546 if 'verbose' in pruned:
3545 keep.append('omitted')
3547 keep.append('omitted')
3546 else:
3548 else:
3547 keep.append('notomitted')
3549 keep.append('notomitted')
3548 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3550 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3549 ui.write(formatted)
3551 ui.write(formatted)
3550
3552
3551
3553
3552 @command('identify|id',
3554 @command('identify|id',
3553 [('r', 'rev', '',
3555 [('r', 'rev', '',
3554 _('identify the specified revision'), _('REV')),
3556 _('identify the specified revision'), _('REV')),
3555 ('n', 'num', None, _('show local revision number')),
3557 ('n', 'num', None, _('show local revision number')),
3556 ('i', 'id', None, _('show global revision id')),
3558 ('i', 'id', None, _('show global revision id')),
3557 ('b', 'branch', None, _('show branch')),
3559 ('b', 'branch', None, _('show branch')),
3558 ('t', 'tags', None, _('show tags')),
3560 ('t', 'tags', None, _('show tags')),
3559 ('B', 'bookmarks', None, _('show bookmarks')),
3561 ('B', 'bookmarks', None, _('show bookmarks')),
3560 ] + remoteopts,
3562 ] + remoteopts,
3561 _('[-nibtB] [-r REV] [SOURCE]'))
3563 _('[-nibtB] [-r REV] [SOURCE]'))
3562 def identify(ui, repo, source=None, rev=None,
3564 def identify(ui, repo, source=None, rev=None,
3563 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3565 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3564 """identify the working copy or specified revision
3566 """identify the working copy or specified revision
3565
3567
3566 Print a summary identifying the repository state at REV using one or
3568 Print a summary identifying the repository state at REV using one or
3567 two parent hash identifiers, followed by a "+" if the working
3569 two parent hash identifiers, followed by a "+" if the working
3568 directory has uncommitted changes, the branch name (if not default),
3570 directory has uncommitted changes, the branch name (if not default),
3569 a list of tags, and a list of bookmarks.
3571 a list of tags, and a list of bookmarks.
3570
3572
3571 When REV is not given, print a summary of the current state of the
3573 When REV is not given, print a summary of the current state of the
3572 repository.
3574 repository.
3573
3575
3574 Specifying a path to a repository root or Mercurial bundle will
3576 Specifying a path to a repository root or Mercurial bundle will
3575 cause lookup to operate on that repository/bundle.
3577 cause lookup to operate on that repository/bundle.
3576
3578
3577 .. container:: verbose
3579 .. container:: verbose
3578
3580
3579 Examples:
3581 Examples:
3580
3582
3581 - generate a build identifier for the working directory::
3583 - generate a build identifier for the working directory::
3582
3584
3583 hg id --id > build-id.dat
3585 hg id --id > build-id.dat
3584
3586
3585 - find the revision corresponding to a tag::
3587 - find the revision corresponding to a tag::
3586
3588
3587 hg id -n -r 1.3
3589 hg id -n -r 1.3
3588
3590
3589 - check the most recent revision of a remote repository::
3591 - check the most recent revision of a remote repository::
3590
3592
3591 hg id -r tip http://selenic.com/hg/
3593 hg id -r tip http://selenic.com/hg/
3592
3594
3593 Returns 0 if successful.
3595 Returns 0 if successful.
3594 """
3596 """
3595
3597
3596 if not repo and not source:
3598 if not repo and not source:
3597 raise util.Abort(_("there is no Mercurial repository here "
3599 raise util.Abort(_("there is no Mercurial repository here "
3598 "(.hg not found)"))
3600 "(.hg not found)"))
3599
3601
3600 hexfunc = ui.debugflag and hex or short
3602 hexfunc = ui.debugflag and hex or short
3601 default = not (num or id or branch or tags or bookmarks)
3603 default = not (num or id or branch or tags or bookmarks)
3602 output = []
3604 output = []
3603 revs = []
3605 revs = []
3604
3606
3605 if source:
3607 if source:
3606 source, branches = hg.parseurl(ui.expandpath(source))
3608 source, branches = hg.parseurl(ui.expandpath(source))
3607 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3609 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3608 repo = peer.local()
3610 repo = peer.local()
3609 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3611 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3610
3612
3611 if not repo:
3613 if not repo:
3612 if num or branch or tags:
3614 if num or branch or tags:
3613 raise util.Abort(
3615 raise util.Abort(
3614 _("can't query remote revision number, branch, or tags"))
3616 _("can't query remote revision number, branch, or tags"))
3615 if not rev and revs:
3617 if not rev and revs:
3616 rev = revs[0]
3618 rev = revs[0]
3617 if not rev:
3619 if not rev:
3618 rev = "tip"
3620 rev = "tip"
3619
3621
3620 remoterev = peer.lookup(rev)
3622 remoterev = peer.lookup(rev)
3621 if default or id:
3623 if default or id:
3622 output = [hexfunc(remoterev)]
3624 output = [hexfunc(remoterev)]
3623
3625
3624 def getbms():
3626 def getbms():
3625 bms = []
3627 bms = []
3626
3628
3627 if 'bookmarks' in peer.listkeys('namespaces'):
3629 if 'bookmarks' in peer.listkeys('namespaces'):
3628 hexremoterev = hex(remoterev)
3630 hexremoterev = hex(remoterev)
3629 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3631 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3630 if bmr == hexremoterev]
3632 if bmr == hexremoterev]
3631
3633
3632 return bms
3634 return bms
3633
3635
3634 if bookmarks:
3636 if bookmarks:
3635 output.extend(getbms())
3637 output.extend(getbms())
3636 elif default and not ui.quiet:
3638 elif default and not ui.quiet:
3637 # multiple bookmarks for a single parent separated by '/'
3639 # multiple bookmarks for a single parent separated by '/'
3638 bm = '/'.join(getbms())
3640 bm = '/'.join(getbms())
3639 if bm:
3641 if bm:
3640 output.append(bm)
3642 output.append(bm)
3641 else:
3643 else:
3642 if not rev:
3644 if not rev:
3643 ctx = repo[None]
3645 ctx = repo[None]
3644 parents = ctx.parents()
3646 parents = ctx.parents()
3645 changed = ""
3647 changed = ""
3646 if default or id or num:
3648 if default or id or num:
3647 if (util.any(repo.status())
3649 if (util.any(repo.status())
3648 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3650 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3649 changed = '+'
3651 changed = '+'
3650 if default or id:
3652 if default or id:
3651 output = ["%s%s" %
3653 output = ["%s%s" %
3652 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3654 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3653 if num:
3655 if num:
3654 output.append("%s%s" %
3656 output.append("%s%s" %
3655 ('+'.join([str(p.rev()) for p in parents]), changed))
3657 ('+'.join([str(p.rev()) for p in parents]), changed))
3656 else:
3658 else:
3657 ctx = scmutil.revsingle(repo, rev)
3659 ctx = scmutil.revsingle(repo, rev)
3658 if default or id:
3660 if default or id:
3659 output = [hexfunc(ctx.node())]
3661 output = [hexfunc(ctx.node())]
3660 if num:
3662 if num:
3661 output.append(str(ctx.rev()))
3663 output.append(str(ctx.rev()))
3662
3664
3663 if default and not ui.quiet:
3665 if default and not ui.quiet:
3664 b = ctx.branch()
3666 b = ctx.branch()
3665 if b != 'default':
3667 if b != 'default':
3666 output.append("(%s)" % b)
3668 output.append("(%s)" % b)
3667
3669
3668 # multiple tags for a single parent separated by '/'
3670 # multiple tags for a single parent separated by '/'
3669 t = '/'.join(ctx.tags())
3671 t = '/'.join(ctx.tags())
3670 if t:
3672 if t:
3671 output.append(t)
3673 output.append(t)
3672
3674
3673 # multiple bookmarks for a single parent separated by '/'
3675 # multiple bookmarks for a single parent separated by '/'
3674 bm = '/'.join(ctx.bookmarks())
3676 bm = '/'.join(ctx.bookmarks())
3675 if bm:
3677 if bm:
3676 output.append(bm)
3678 output.append(bm)
3677 else:
3679 else:
3678 if branch:
3680 if branch:
3679 output.append(ctx.branch())
3681 output.append(ctx.branch())
3680
3682
3681 if tags:
3683 if tags:
3682 output.extend(ctx.tags())
3684 output.extend(ctx.tags())
3683
3685
3684 if bookmarks:
3686 if bookmarks:
3685 output.extend(ctx.bookmarks())
3687 output.extend(ctx.bookmarks())
3686
3688
3687 ui.write("%s\n" % ' '.join(output))
3689 ui.write("%s\n" % ' '.join(output))
3688
3690
3689 @command('import|patch',
3691 @command('import|patch',
3690 [('p', 'strip', 1,
3692 [('p', 'strip', 1,
3691 _('directory strip option for patch. This has the same '
3693 _('directory strip option for patch. This has the same '
3692 'meaning as the corresponding patch option'), _('NUM')),
3694 'meaning as the corresponding patch option'), _('NUM')),
3693 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3695 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3694 ('e', 'edit', False, _('invoke editor on commit messages')),
3696 ('e', 'edit', False, _('invoke editor on commit messages')),
3695 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3697 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3696 ('', 'no-commit', None,
3698 ('', 'no-commit', None,
3697 _("don't commit, just update the working directory")),
3699 _("don't commit, just update the working directory")),
3698 ('', 'bypass', None,
3700 ('', 'bypass', None,
3699 _("apply patch without touching the working directory")),
3701 _("apply patch without touching the working directory")),
3700 ('', 'exact', None,
3702 ('', 'exact', None,
3701 _('apply patch to the nodes from which it was generated')),
3703 _('apply patch to the nodes from which it was generated')),
3702 ('', 'import-branch', None,
3704 ('', 'import-branch', None,
3703 _('use any branch information in patch (implied by --exact)'))] +
3705 _('use any branch information in patch (implied by --exact)'))] +
3704 commitopts + commitopts2 + similarityopts,
3706 commitopts + commitopts2 + similarityopts,
3705 _('[OPTION]... PATCH...'))
3707 _('[OPTION]... PATCH...'))
3706 def import_(ui, repo, patch1=None, *patches, **opts):
3708 def import_(ui, repo, patch1=None, *patches, **opts):
3707 """import an ordered set of patches
3709 """import an ordered set of patches
3708
3710
3709 Import a list of patches and commit them individually (unless
3711 Import a list of patches and commit them individually (unless
3710 --no-commit is specified).
3712 --no-commit is specified).
3711
3713
3712 If there are outstanding changes in the working directory, import
3714 If there are outstanding changes in the working directory, import
3713 will abort unless given the -f/--force flag.
3715 will abort unless given the -f/--force flag.
3714
3716
3715 You can import a patch straight from a mail message. Even patches
3717 You can import a patch straight from a mail message. Even patches
3716 as attachments work (to use the body part, it must have type
3718 as attachments work (to use the body part, it must have type
3717 text/plain or text/x-patch). From and Subject headers of email
3719 text/plain or text/x-patch). From and Subject headers of email
3718 message are used as default committer and commit message. All
3720 message are used as default committer and commit message. All
3719 text/plain body parts before first diff are added to commit
3721 text/plain body parts before first diff are added to commit
3720 message.
3722 message.
3721
3723
3722 If the imported patch was generated by :hg:`export`, user and
3724 If the imported patch was generated by :hg:`export`, user and
3723 description from patch override values from message headers and
3725 description from patch override values from message headers and
3724 body. Values given on command line with -m/--message and -u/--user
3726 body. Values given on command line with -m/--message and -u/--user
3725 override these.
3727 override these.
3726
3728
3727 If --exact is specified, import will set the working directory to
3729 If --exact is specified, import will set the working directory to
3728 the parent of each patch before applying it, and will abort if the
3730 the parent of each patch before applying it, and will abort if the
3729 resulting changeset has a different ID than the one recorded in
3731 resulting changeset has a different ID than the one recorded in
3730 the patch. This may happen due to character set problems or other
3732 the patch. This may happen due to character set problems or other
3731 deficiencies in the text patch format.
3733 deficiencies in the text patch format.
3732
3734
3733 Use --bypass to apply and commit patches directly to the
3735 Use --bypass to apply and commit patches directly to the
3734 repository, not touching the working directory. Without --exact,
3736 repository, not touching the working directory. Without --exact,
3735 patches will be applied on top of the working directory parent
3737 patches will be applied on top of the working directory parent
3736 revision.
3738 revision.
3737
3739
3738 With -s/--similarity, hg will attempt to discover renames and
3740 With -s/--similarity, hg will attempt to discover renames and
3739 copies in the patch in the same way as :hg:`addremove`.
3741 copies in the patch in the same way as :hg:`addremove`.
3740
3742
3741 To read a patch from standard input, use "-" as the patch name. If
3743 To read a patch from standard input, use "-" as the patch name. If
3742 a URL is specified, the patch will be downloaded from it.
3744 a URL is specified, the patch will be downloaded from it.
3743 See :hg:`help dates` for a list of formats valid for -d/--date.
3745 See :hg:`help dates` for a list of formats valid for -d/--date.
3744
3746
3745 .. container:: verbose
3747 .. container:: verbose
3746
3748
3747 Examples:
3749 Examples:
3748
3750
3749 - import a traditional patch from a website and detect renames::
3751 - import a traditional patch from a website and detect renames::
3750
3752
3751 hg import -s 80 http://example.com/bugfix.patch
3753 hg import -s 80 http://example.com/bugfix.patch
3752
3754
3753 - import a changeset from an hgweb server::
3755 - import a changeset from an hgweb server::
3754
3756
3755 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3757 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3756
3758
3757 - import all the patches in an Unix-style mbox::
3759 - import all the patches in an Unix-style mbox::
3758
3760
3759 hg import incoming-patches.mbox
3761 hg import incoming-patches.mbox
3760
3762
3761 - attempt to exactly restore an exported changeset (not always
3763 - attempt to exactly restore an exported changeset (not always
3762 possible)::
3764 possible)::
3763
3765
3764 hg import --exact proposed-fix.patch
3766 hg import --exact proposed-fix.patch
3765
3767
3766 Returns 0 on success.
3768 Returns 0 on success.
3767 """
3769 """
3768
3770
3769 if not patch1:
3771 if not patch1:
3770 raise util.Abort(_('need at least one patch to import'))
3772 raise util.Abort(_('need at least one patch to import'))
3771
3773
3772 patches = (patch1,) + patches
3774 patches = (patch1,) + patches
3773
3775
3774 date = opts.get('date')
3776 date = opts.get('date')
3775 if date:
3777 if date:
3776 opts['date'] = util.parsedate(date)
3778 opts['date'] = util.parsedate(date)
3777
3779
3778 editor = cmdutil.commiteditor
3780 editor = cmdutil.commiteditor
3779 if opts.get('edit'):
3781 if opts.get('edit'):
3780 editor = cmdutil.commitforceeditor
3782 editor = cmdutil.commitforceeditor
3781
3783
3782 update = not opts.get('bypass')
3784 update = not opts.get('bypass')
3783 if not update and opts.get('no_commit'):
3785 if not update and opts.get('no_commit'):
3784 raise util.Abort(_('cannot use --no-commit with --bypass'))
3786 raise util.Abort(_('cannot use --no-commit with --bypass'))
3785 try:
3787 try:
3786 sim = float(opts.get('similarity') or 0)
3788 sim = float(opts.get('similarity') or 0)
3787 except ValueError:
3789 except ValueError:
3788 raise util.Abort(_('similarity must be a number'))
3790 raise util.Abort(_('similarity must be a number'))
3789 if sim < 0 or sim > 100:
3791 if sim < 0 or sim > 100:
3790 raise util.Abort(_('similarity must be between 0 and 100'))
3792 raise util.Abort(_('similarity must be between 0 and 100'))
3791 if sim and not update:
3793 if sim and not update:
3792 raise util.Abort(_('cannot use --similarity with --bypass'))
3794 raise util.Abort(_('cannot use --similarity with --bypass'))
3793
3795
3794 if (opts.get('exact') or not opts.get('force')) and update:
3796 if (opts.get('exact') or not opts.get('force')) and update:
3795 cmdutil.bailifchanged(repo)
3797 cmdutil.bailifchanged(repo)
3796
3798
3797 base = opts["base"]
3799 base = opts["base"]
3798 strip = opts["strip"]
3800 strip = opts["strip"]
3799 wlock = lock = tr = None
3801 wlock = lock = tr = None
3800 msgs = []
3802 msgs = []
3801
3803
3802 def checkexact(repo, n, nodeid):
3804 def checkexact(repo, n, nodeid):
3803 if opts.get('exact') and hex(n) != nodeid:
3805 if opts.get('exact') and hex(n) != nodeid:
3804 repo.rollback()
3806 repo.rollback()
3805 raise util.Abort(_('patch is damaged or loses information'))
3807 raise util.Abort(_('patch is damaged or loses information'))
3806
3808
3807 def tryone(ui, hunk, parents):
3809 def tryone(ui, hunk, parents):
3808 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3810 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3809 patch.extract(ui, hunk)
3811 patch.extract(ui, hunk)
3810
3812
3811 if not tmpname:
3813 if not tmpname:
3812 return (None, None)
3814 return (None, None)
3813 msg = _('applied to working directory')
3815 msg = _('applied to working directory')
3814
3816
3815 try:
3817 try:
3816 cmdline_message = cmdutil.logmessage(ui, opts)
3818 cmdline_message = cmdutil.logmessage(ui, opts)
3817 if cmdline_message:
3819 if cmdline_message:
3818 # pickup the cmdline msg
3820 # pickup the cmdline msg
3819 message = cmdline_message
3821 message = cmdline_message
3820 elif message:
3822 elif message:
3821 # pickup the patch msg
3823 # pickup the patch msg
3822 message = message.strip()
3824 message = message.strip()
3823 else:
3825 else:
3824 # launch the editor
3826 # launch the editor
3825 message = None
3827 message = None
3826 ui.debug('message:\n%s\n' % message)
3828 ui.debug('message:\n%s\n' % message)
3827
3829
3828 if len(parents) == 1:
3830 if len(parents) == 1:
3829 parents.append(repo[nullid])
3831 parents.append(repo[nullid])
3830 if opts.get('exact'):
3832 if opts.get('exact'):
3831 if not nodeid or not p1:
3833 if not nodeid or not p1:
3832 raise util.Abort(_('not a Mercurial patch'))
3834 raise util.Abort(_('not a Mercurial patch'))
3833 p1 = repo[p1]
3835 p1 = repo[p1]
3834 p2 = repo[p2 or nullid]
3836 p2 = repo[p2 or nullid]
3835 elif p2:
3837 elif p2:
3836 try:
3838 try:
3837 p1 = repo[p1]
3839 p1 = repo[p1]
3838 p2 = repo[p2]
3840 p2 = repo[p2]
3839 # Without any options, consider p2 only if the
3841 # Without any options, consider p2 only if the
3840 # patch is being applied on top of the recorded
3842 # patch is being applied on top of the recorded
3841 # first parent.
3843 # first parent.
3842 if p1 != parents[0]:
3844 if p1 != parents[0]:
3843 p1 = parents[0]
3845 p1 = parents[0]
3844 p2 = repo[nullid]
3846 p2 = repo[nullid]
3845 except error.RepoError:
3847 except error.RepoError:
3846 p1, p2 = parents
3848 p1, p2 = parents
3847 else:
3849 else:
3848 p1, p2 = parents
3850 p1, p2 = parents
3849
3851
3850 n = None
3852 n = None
3851 if update:
3853 if update:
3852 if p1 != parents[0]:
3854 if p1 != parents[0]:
3853 hg.clean(repo, p1.node())
3855 hg.clean(repo, p1.node())
3854 if p2 != parents[1]:
3856 if p2 != parents[1]:
3855 repo.setparents(p1.node(), p2.node())
3857 repo.setparents(p1.node(), p2.node())
3856
3858
3857 if opts.get('exact') or opts.get('import_branch'):
3859 if opts.get('exact') or opts.get('import_branch'):
3858 repo.dirstate.setbranch(branch or 'default')
3860 repo.dirstate.setbranch(branch or 'default')
3859
3861
3860 files = set()
3862 files = set()
3861 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3863 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3862 eolmode=None, similarity=sim / 100.0)
3864 eolmode=None, similarity=sim / 100.0)
3863 files = list(files)
3865 files = list(files)
3864 if opts.get('no_commit'):
3866 if opts.get('no_commit'):
3865 if message:
3867 if message:
3866 msgs.append(message)
3868 msgs.append(message)
3867 else:
3869 else:
3868 if opts.get('exact') or p2:
3870 if opts.get('exact') or p2:
3869 # If you got here, you either use --force and know what
3871 # If you got here, you either use --force and know what
3870 # you are doing or used --exact or a merge patch while
3872 # you are doing or used --exact or a merge patch while
3871 # being updated to its first parent.
3873 # being updated to its first parent.
3872 m = None
3874 m = None
3873 else:
3875 else:
3874 m = scmutil.matchfiles(repo, files or [])
3876 m = scmutil.matchfiles(repo, files or [])
3875 n = repo.commit(message, opts.get('user') or user,
3877 n = repo.commit(message, opts.get('user') or user,
3876 opts.get('date') or date, match=m,
3878 opts.get('date') or date, match=m,
3877 editor=editor)
3879 editor=editor)
3878 checkexact(repo, n, nodeid)
3880 checkexact(repo, n, nodeid)
3879 else:
3881 else:
3880 if opts.get('exact') or opts.get('import_branch'):
3882 if opts.get('exact') or opts.get('import_branch'):
3881 branch = branch or 'default'
3883 branch = branch or 'default'
3882 else:
3884 else:
3883 branch = p1.branch()
3885 branch = p1.branch()
3884 store = patch.filestore()
3886 store = patch.filestore()
3885 try:
3887 try:
3886 files = set()
3888 files = set()
3887 try:
3889 try:
3888 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3890 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3889 files, eolmode=None)
3891 files, eolmode=None)
3890 except patch.PatchError, e:
3892 except patch.PatchError, e:
3891 raise util.Abort(str(e))
3893 raise util.Abort(str(e))
3892 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3894 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3893 message,
3895 message,
3894 opts.get('user') or user,
3896 opts.get('user') or user,
3895 opts.get('date') or date,
3897 opts.get('date') or date,
3896 branch, files, store,
3898 branch, files, store,
3897 editor=cmdutil.commiteditor)
3899 editor=cmdutil.commiteditor)
3898 repo.savecommitmessage(memctx.description())
3900 repo.savecommitmessage(memctx.description())
3899 n = memctx.commit()
3901 n = memctx.commit()
3900 checkexact(repo, n, nodeid)
3902 checkexact(repo, n, nodeid)
3901 finally:
3903 finally:
3902 store.close()
3904 store.close()
3903 if n:
3905 if n:
3904 # i18n: refers to a short changeset id
3906 # i18n: refers to a short changeset id
3905 msg = _('created %s') % short(n)
3907 msg = _('created %s') % short(n)
3906 return (msg, n)
3908 return (msg, n)
3907 finally:
3909 finally:
3908 os.unlink(tmpname)
3910 os.unlink(tmpname)
3909
3911
3910 try:
3912 try:
3911 try:
3913 try:
3912 wlock = repo.wlock()
3914 wlock = repo.wlock()
3913 if not opts.get('no_commit'):
3915 if not opts.get('no_commit'):
3914 lock = repo.lock()
3916 lock = repo.lock()
3915 tr = repo.transaction('import')
3917 tr = repo.transaction('import')
3916 parents = repo.parents()
3918 parents = repo.parents()
3917 for patchurl in patches:
3919 for patchurl in patches:
3918 if patchurl == '-':
3920 if patchurl == '-':
3919 ui.status(_('applying patch from stdin\n'))
3921 ui.status(_('applying patch from stdin\n'))
3920 patchfile = ui.fin
3922 patchfile = ui.fin
3921 patchurl = 'stdin' # for error message
3923 patchurl = 'stdin' # for error message
3922 else:
3924 else:
3923 patchurl = os.path.join(base, patchurl)
3925 patchurl = os.path.join(base, patchurl)
3924 ui.status(_('applying %s\n') % patchurl)
3926 ui.status(_('applying %s\n') % patchurl)
3925 patchfile = hg.openpath(ui, patchurl)
3927 patchfile = hg.openpath(ui, patchurl)
3926
3928
3927 haspatch = False
3929 haspatch = False
3928 for hunk in patch.split(patchfile):
3930 for hunk in patch.split(patchfile):
3929 (msg, node) = tryone(ui, hunk, parents)
3931 (msg, node) = tryone(ui, hunk, parents)
3930 if msg:
3932 if msg:
3931 haspatch = True
3933 haspatch = True
3932 ui.note(msg + '\n')
3934 ui.note(msg + '\n')
3933 if update or opts.get('exact'):
3935 if update or opts.get('exact'):
3934 parents = repo.parents()
3936 parents = repo.parents()
3935 else:
3937 else:
3936 parents = [repo[node]]
3938 parents = [repo[node]]
3937
3939
3938 if not haspatch:
3940 if not haspatch:
3939 raise util.Abort(_('%s: no diffs found') % patchurl)
3941 raise util.Abort(_('%s: no diffs found') % patchurl)
3940
3942
3941 if tr:
3943 if tr:
3942 tr.close()
3944 tr.close()
3943 if msgs:
3945 if msgs:
3944 repo.savecommitmessage('\n* * *\n'.join(msgs))
3946 repo.savecommitmessage('\n* * *\n'.join(msgs))
3945 except: # re-raises
3947 except: # re-raises
3946 # wlock.release() indirectly calls dirstate.write(): since
3948 # wlock.release() indirectly calls dirstate.write(): since
3947 # we're crashing, we do not want to change the working dir
3949 # we're crashing, we do not want to change the working dir
3948 # parent after all, so make sure it writes nothing
3950 # parent after all, so make sure it writes nothing
3949 repo.dirstate.invalidate()
3951 repo.dirstate.invalidate()
3950 raise
3952 raise
3951 finally:
3953 finally:
3952 if tr:
3954 if tr:
3953 tr.release()
3955 tr.release()
3954 release(lock, wlock)
3956 release(lock, wlock)
3955
3957
3956 @command('incoming|in',
3958 @command('incoming|in',
3957 [('f', 'force', None,
3959 [('f', 'force', None,
3958 _('run even if remote repository is unrelated')),
3960 _('run even if remote repository is unrelated')),
3959 ('n', 'newest-first', None, _('show newest record first')),
3961 ('n', 'newest-first', None, _('show newest record first')),
3960 ('', 'bundle', '',
3962 ('', 'bundle', '',
3961 _('file to store the bundles into'), _('FILE')),
3963 _('file to store the bundles into'), _('FILE')),
3962 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3964 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3963 ('B', 'bookmarks', False, _("compare bookmarks")),
3965 ('B', 'bookmarks', False, _("compare bookmarks")),
3964 ('b', 'branch', [],
3966 ('b', 'branch', [],
3965 _('a specific branch you would like to pull'), _('BRANCH')),
3967 _('a specific branch you would like to pull'), _('BRANCH')),
3966 ] + logopts + remoteopts + subrepoopts,
3968 ] + logopts + remoteopts + subrepoopts,
3967 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3969 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3968 def incoming(ui, repo, source="default", **opts):
3970 def incoming(ui, repo, source="default", **opts):
3969 """show new changesets found in source
3971 """show new changesets found in source
3970
3972
3971 Show new changesets found in the specified path/URL or the default
3973 Show new changesets found in the specified path/URL or the default
3972 pull location. These are the changesets that would have been pulled
3974 pull location. These are the changesets that would have been pulled
3973 if a pull at the time you issued this command.
3975 if a pull at the time you issued this command.
3974
3976
3975 For remote repository, using --bundle avoids downloading the
3977 For remote repository, using --bundle avoids downloading the
3976 changesets twice if the incoming is followed by a pull.
3978 changesets twice if the incoming is followed by a pull.
3977
3979
3978 See pull for valid source format details.
3980 See pull for valid source format details.
3979
3981
3980 Returns 0 if there are incoming changes, 1 otherwise.
3982 Returns 0 if there are incoming changes, 1 otherwise.
3981 """
3983 """
3982 if opts.get('graph'):
3984 if opts.get('graph'):
3983 cmdutil.checkunsupportedgraphflags([], opts)
3985 cmdutil.checkunsupportedgraphflags([], opts)
3984 def display(other, chlist, displayer):
3986 def display(other, chlist, displayer):
3985 revdag = cmdutil.graphrevs(other, chlist, opts)
3987 revdag = cmdutil.graphrevs(other, chlist, opts)
3986 showparents = [ctx.node() for ctx in repo[None].parents()]
3988 showparents = [ctx.node() for ctx in repo[None].parents()]
3987 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3989 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3988 graphmod.asciiedges)
3990 graphmod.asciiedges)
3989
3991
3990 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3992 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3991 return 0
3993 return 0
3992
3994
3993 if opts.get('bundle') and opts.get('subrepos'):
3995 if opts.get('bundle') and opts.get('subrepos'):
3994 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3996 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3995
3997
3996 if opts.get('bookmarks'):
3998 if opts.get('bookmarks'):
3997 source, branches = hg.parseurl(ui.expandpath(source),
3999 source, branches = hg.parseurl(ui.expandpath(source),
3998 opts.get('branch'))
4000 opts.get('branch'))
3999 other = hg.peer(repo, opts, source)
4001 other = hg.peer(repo, opts, source)
4000 if 'bookmarks' not in other.listkeys('namespaces'):
4002 if 'bookmarks' not in other.listkeys('namespaces'):
4001 ui.warn(_("remote doesn't support bookmarks\n"))
4003 ui.warn(_("remote doesn't support bookmarks\n"))
4002 return 0
4004 return 0
4003 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4005 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4004 return bookmarks.diff(ui, repo, other)
4006 return bookmarks.diff(ui, repo, other)
4005
4007
4006 repo._subtoppath = ui.expandpath(source)
4008 repo._subtoppath = ui.expandpath(source)
4007 try:
4009 try:
4008 return hg.incoming(ui, repo, source, opts)
4010 return hg.incoming(ui, repo, source, opts)
4009 finally:
4011 finally:
4010 del repo._subtoppath
4012 del repo._subtoppath
4011
4013
4012
4014
4013 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4015 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
4014 def init(ui, dest=".", **opts):
4016 def init(ui, dest=".", **opts):
4015 """create a new repository in the given directory
4017 """create a new repository in the given directory
4016
4018
4017 Initialize a new repository in the given directory. If the given
4019 Initialize a new repository in the given directory. If the given
4018 directory does not exist, it will be created.
4020 directory does not exist, it will be created.
4019
4021
4020 If no directory is given, the current directory is used.
4022 If no directory is given, the current directory is used.
4021
4023
4022 It is possible to specify an ``ssh://`` URL as the destination.
4024 It is possible to specify an ``ssh://`` URL as the destination.
4023 See :hg:`help urls` for more information.
4025 See :hg:`help urls` for more information.
4024
4026
4025 Returns 0 on success.
4027 Returns 0 on success.
4026 """
4028 """
4027 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4029 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4028
4030
4029 @command('locate',
4031 @command('locate',
4030 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4032 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4031 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4033 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4032 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4034 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4033 ] + walkopts,
4035 ] + walkopts,
4034 _('[OPTION]... [PATTERN]...'))
4036 _('[OPTION]... [PATTERN]...'))
4035 def locate(ui, repo, *pats, **opts):
4037 def locate(ui, repo, *pats, **opts):
4036 """locate files matching specific patterns
4038 """locate files matching specific patterns
4037
4039
4038 Print files under Mercurial control in the working directory whose
4040 Print files under Mercurial control in the working directory whose
4039 names match the given patterns.
4041 names match the given patterns.
4040
4042
4041 By default, this command searches all directories in the working
4043 By default, this command searches all directories in the working
4042 directory. To search just the current directory and its
4044 directory. To search just the current directory and its
4043 subdirectories, use "--include .".
4045 subdirectories, use "--include .".
4044
4046
4045 If no patterns are given to match, this command prints the names
4047 If no patterns are given to match, this command prints the names
4046 of all files under Mercurial control in the working directory.
4048 of all files under Mercurial control in the working directory.
4047
4049
4048 If you want to feed the output of this command into the "xargs"
4050 If you want to feed the output of this command into the "xargs"
4049 command, use the -0 option to both this command and "xargs". This
4051 command, use the -0 option to both this command and "xargs". This
4050 will avoid the problem of "xargs" treating single filenames that
4052 will avoid the problem of "xargs" treating single filenames that
4051 contain whitespace as multiple filenames.
4053 contain whitespace as multiple filenames.
4052
4054
4053 Returns 0 if a match is found, 1 otherwise.
4055 Returns 0 if a match is found, 1 otherwise.
4054 """
4056 """
4055 end = opts.get('print0') and '\0' or '\n'
4057 end = opts.get('print0') and '\0' or '\n'
4056 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4058 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4057
4059
4058 ret = 1
4060 ret = 1
4059 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4061 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4060 m.bad = lambda x, y: False
4062 m.bad = lambda x, y: False
4061 for abs in repo[rev].walk(m):
4063 for abs in repo[rev].walk(m):
4062 if not rev and abs not in repo.dirstate:
4064 if not rev and abs not in repo.dirstate:
4063 continue
4065 continue
4064 if opts.get('fullpath'):
4066 if opts.get('fullpath'):
4065 ui.write(repo.wjoin(abs), end)
4067 ui.write(repo.wjoin(abs), end)
4066 else:
4068 else:
4067 ui.write(((pats and m.rel(abs)) or abs), end)
4069 ui.write(((pats and m.rel(abs)) or abs), end)
4068 ret = 0
4070 ret = 0
4069
4071
4070 return ret
4072 return ret
4071
4073
4072 @command('^log|history',
4074 @command('^log|history',
4073 [('f', 'follow', None,
4075 [('f', 'follow', None,
4074 _('follow changeset history, or file history across copies and renames')),
4076 _('follow changeset history, or file history across copies and renames')),
4075 ('', 'follow-first', None,
4077 ('', 'follow-first', None,
4076 _('only follow the first parent of merge changesets (DEPRECATED)')),
4078 _('only follow the first parent of merge changesets (DEPRECATED)')),
4077 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4079 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4078 ('C', 'copies', None, _('show copied files')),
4080 ('C', 'copies', None, _('show copied files')),
4079 ('k', 'keyword', [],
4081 ('k', 'keyword', [],
4080 _('do case-insensitive search for a given text'), _('TEXT')),
4082 _('do case-insensitive search for a given text'), _('TEXT')),
4081 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4083 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4082 ('', 'removed', None, _('include revisions where files were removed')),
4084 ('', 'removed', None, _('include revisions where files were removed')),
4083 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4085 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4084 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4086 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4085 ('', 'only-branch', [],
4087 ('', 'only-branch', [],
4086 _('show only changesets within the given named branch (DEPRECATED)'),
4088 _('show only changesets within the given named branch (DEPRECATED)'),
4087 _('BRANCH')),
4089 _('BRANCH')),
4088 ('b', 'branch', [],
4090 ('b', 'branch', [],
4089 _('show changesets within the given named branch'), _('BRANCH')),
4091 _('show changesets within the given named branch'), _('BRANCH')),
4090 ('P', 'prune', [],
4092 ('P', 'prune', [],
4091 _('do not display revision or any of its ancestors'), _('REV')),
4093 _('do not display revision or any of its ancestors'), _('REV')),
4092 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4094 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4093 ] + logopts + walkopts,
4095 ] + logopts + walkopts,
4094 _('[OPTION]... [FILE]'))
4096 _('[OPTION]... [FILE]'))
4095 def log(ui, repo, *pats, **opts):
4097 def log(ui, repo, *pats, **opts):
4096 """show revision history of entire repository or files
4098 """show revision history of entire repository or files
4097
4099
4098 Print the revision history of the specified files or the entire
4100 Print the revision history of the specified files or the entire
4099 project.
4101 project.
4100
4102
4101 If no revision range is specified, the default is ``tip:0`` unless
4103 If no revision range is specified, the default is ``tip:0`` unless
4102 --follow is set, in which case the working directory parent is
4104 --follow is set, in which case the working directory parent is
4103 used as the starting revision.
4105 used as the starting revision.
4104
4106
4105 File history is shown without following rename or copy history of
4107 File history is shown without following rename or copy history of
4106 files. Use -f/--follow with a filename to follow history across
4108 files. Use -f/--follow with a filename to follow history across
4107 renames and copies. --follow without a filename will only show
4109 renames and copies. --follow without a filename will only show
4108 ancestors or descendants of the starting revision.
4110 ancestors or descendants of the starting revision.
4109
4111
4110 By default this command prints revision number and changeset id,
4112 By default this command prints revision number and changeset id,
4111 tags, non-trivial parents, user, date and time, and a summary for
4113 tags, non-trivial parents, user, date and time, and a summary for
4112 each commit. When the -v/--verbose switch is used, the list of
4114 each commit. When the -v/--verbose switch is used, the list of
4113 changed files and full commit message are shown.
4115 changed files and full commit message are shown.
4114
4116
4115 .. note::
4117 .. note::
4116 log -p/--patch may generate unexpected diff output for merge
4118 log -p/--patch may generate unexpected diff output for merge
4117 changesets, as it will only compare the merge changeset against
4119 changesets, as it will only compare the merge changeset against
4118 its first parent. Also, only files different from BOTH parents
4120 its first parent. Also, only files different from BOTH parents
4119 will appear in files:.
4121 will appear in files:.
4120
4122
4121 .. note::
4123 .. note::
4122 for performance reasons, log FILE may omit duplicate changes
4124 for performance reasons, log FILE may omit duplicate changes
4123 made on branches and will not show deletions. To see all
4125 made on branches and will not show deletions. To see all
4124 changes including duplicates and deletions, use the --removed
4126 changes including duplicates and deletions, use the --removed
4125 switch.
4127 switch.
4126
4128
4127 .. container:: verbose
4129 .. container:: verbose
4128
4130
4129 Some examples:
4131 Some examples:
4130
4132
4131 - changesets with full descriptions and file lists::
4133 - changesets with full descriptions and file lists::
4132
4134
4133 hg log -v
4135 hg log -v
4134
4136
4135 - changesets ancestral to the working directory::
4137 - changesets ancestral to the working directory::
4136
4138
4137 hg log -f
4139 hg log -f
4138
4140
4139 - last 10 commits on the current branch::
4141 - last 10 commits on the current branch::
4140
4142
4141 hg log -l 10 -b .
4143 hg log -l 10 -b .
4142
4144
4143 - changesets showing all modifications of a file, including removals::
4145 - changesets showing all modifications of a file, including removals::
4144
4146
4145 hg log --removed file.c
4147 hg log --removed file.c
4146
4148
4147 - all changesets that touch a directory, with diffs, excluding merges::
4149 - all changesets that touch a directory, with diffs, excluding merges::
4148
4150
4149 hg log -Mp lib/
4151 hg log -Mp lib/
4150
4152
4151 - all revision numbers that match a keyword::
4153 - all revision numbers that match a keyword::
4152
4154
4153 hg log -k bug --template "{rev}\\n"
4155 hg log -k bug --template "{rev}\\n"
4154
4156
4155 - check if a given changeset is included is a tagged release::
4157 - check if a given changeset is included is a tagged release::
4156
4158
4157 hg log -r "a21ccf and ancestor(1.9)"
4159 hg log -r "a21ccf and ancestor(1.9)"
4158
4160
4159 - find all changesets by some user in a date range::
4161 - find all changesets by some user in a date range::
4160
4162
4161 hg log -k alice -d "may 2008 to jul 2008"
4163 hg log -k alice -d "may 2008 to jul 2008"
4162
4164
4163 - summary of all changesets after the last tag::
4165 - summary of all changesets after the last tag::
4164
4166
4165 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4167 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4166
4168
4167 See :hg:`help dates` for a list of formats valid for -d/--date.
4169 See :hg:`help dates` for a list of formats valid for -d/--date.
4168
4170
4169 See :hg:`help revisions` and :hg:`help revsets` for more about
4171 See :hg:`help revisions` and :hg:`help revsets` for more about
4170 specifying revisions.
4172 specifying revisions.
4171
4173
4172 See :hg:`help templates` for more about pre-packaged styles and
4174 See :hg:`help templates` for more about pre-packaged styles and
4173 specifying custom templates.
4175 specifying custom templates.
4174
4176
4175 Returns 0 on success.
4177 Returns 0 on success.
4176 """
4178 """
4177 if opts.get('graph'):
4179 if opts.get('graph'):
4178 return cmdutil.graphlog(ui, repo, *pats, **opts)
4180 return cmdutil.graphlog(ui, repo, *pats, **opts)
4179
4181
4180 matchfn = scmutil.match(repo[None], pats, opts)
4182 matchfn = scmutil.match(repo[None], pats, opts)
4181 limit = cmdutil.loglimit(opts)
4183 limit = cmdutil.loglimit(opts)
4182 count = 0
4184 count = 0
4183
4185
4184 getrenamed, endrev = None, None
4186 getrenamed, endrev = None, None
4185 if opts.get('copies'):
4187 if opts.get('copies'):
4186 if opts.get('rev'):
4188 if opts.get('rev'):
4187 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4189 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4188 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4190 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4189
4191
4190 df = False
4192 df = False
4191 if opts.get("date"):
4193 if opts.get("date"):
4192 df = util.matchdate(opts["date"])
4194 df = util.matchdate(opts["date"])
4193
4195
4194 branches = opts.get('branch', []) + opts.get('only_branch', [])
4196 branches = opts.get('branch', []) + opts.get('only_branch', [])
4195 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4197 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4196
4198
4197 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4199 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4198 def prep(ctx, fns):
4200 def prep(ctx, fns):
4199 rev = ctx.rev()
4201 rev = ctx.rev()
4200 parents = [p for p in repo.changelog.parentrevs(rev)
4202 parents = [p for p in repo.changelog.parentrevs(rev)
4201 if p != nullrev]
4203 if p != nullrev]
4202 if opts.get('no_merges') and len(parents) == 2:
4204 if opts.get('no_merges') and len(parents) == 2:
4203 return
4205 return
4204 if opts.get('only_merges') and len(parents) != 2:
4206 if opts.get('only_merges') and len(parents) != 2:
4205 return
4207 return
4206 if opts.get('branch') and ctx.branch() not in opts['branch']:
4208 if opts.get('branch') and ctx.branch() not in opts['branch']:
4207 return
4209 return
4208 if not opts.get('hidden') and ctx.hidden():
4210 if not opts.get('hidden') and ctx.hidden():
4209 return
4211 return
4210 if df and not df(ctx.date()[0]):
4212 if df and not df(ctx.date()[0]):
4211 return
4213 return
4212
4214
4213 lower = encoding.lower
4215 lower = encoding.lower
4214 if opts.get('user'):
4216 if opts.get('user'):
4215 luser = lower(ctx.user())
4217 luser = lower(ctx.user())
4216 for k in [lower(x) for x in opts['user']]:
4218 for k in [lower(x) for x in opts['user']]:
4217 if (k in luser):
4219 if (k in luser):
4218 break
4220 break
4219 else:
4221 else:
4220 return
4222 return
4221 if opts.get('keyword'):
4223 if opts.get('keyword'):
4222 luser = lower(ctx.user())
4224 luser = lower(ctx.user())
4223 ldesc = lower(ctx.description())
4225 ldesc = lower(ctx.description())
4224 lfiles = lower(" ".join(ctx.files()))
4226 lfiles = lower(" ".join(ctx.files()))
4225 for k in [lower(x) for x in opts['keyword']]:
4227 for k in [lower(x) for x in opts['keyword']]:
4226 if (k in luser or k in ldesc or k in lfiles):
4228 if (k in luser or k in ldesc or k in lfiles):
4227 break
4229 break
4228 else:
4230 else:
4229 return
4231 return
4230
4232
4231 copies = None
4233 copies = None
4232 if getrenamed is not None and rev:
4234 if getrenamed is not None and rev:
4233 copies = []
4235 copies = []
4234 for fn in ctx.files():
4236 for fn in ctx.files():
4235 rename = getrenamed(fn, rev)
4237 rename = getrenamed(fn, rev)
4236 if rename:
4238 if rename:
4237 copies.append((fn, rename[0]))
4239 copies.append((fn, rename[0]))
4238
4240
4239 revmatchfn = None
4241 revmatchfn = None
4240 if opts.get('patch') or opts.get('stat'):
4242 if opts.get('patch') or opts.get('stat'):
4241 if opts.get('follow') or opts.get('follow_first'):
4243 if opts.get('follow') or opts.get('follow_first'):
4242 # note: this might be wrong when following through merges
4244 # note: this might be wrong when following through merges
4243 revmatchfn = scmutil.match(repo[None], fns, default='path')
4245 revmatchfn = scmutil.match(repo[None], fns, default='path')
4244 else:
4246 else:
4245 revmatchfn = matchfn
4247 revmatchfn = matchfn
4246
4248
4247 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4249 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4248
4250
4249 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4251 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4250 if count == limit:
4252 if count == limit:
4251 break
4253 break
4252 if displayer.flush(ctx.rev()):
4254 if displayer.flush(ctx.rev()):
4253 count += 1
4255 count += 1
4254 displayer.close()
4256 displayer.close()
4255
4257
4256 @command('manifest',
4258 @command('manifest',
4257 [('r', 'rev', '', _('revision to display'), _('REV')),
4259 [('r', 'rev', '', _('revision to display'), _('REV')),
4258 ('', 'all', False, _("list files from all revisions"))],
4260 ('', 'all', False, _("list files from all revisions"))],
4259 _('[-r REV]'))
4261 _('[-r REV]'))
4260 def manifest(ui, repo, node=None, rev=None, **opts):
4262 def manifest(ui, repo, node=None, rev=None, **opts):
4261 """output the current or given revision of the project manifest
4263 """output the current or given revision of the project manifest
4262
4264
4263 Print a list of version controlled files for the given revision.
4265 Print a list of version controlled files for the given revision.
4264 If no revision is given, the first parent of the working directory
4266 If no revision is given, the first parent of the working directory
4265 is used, or the null revision if no revision is checked out.
4267 is used, or the null revision if no revision is checked out.
4266
4268
4267 With -v, print file permissions, symlink and executable bits.
4269 With -v, print file permissions, symlink and executable bits.
4268 With --debug, print file revision hashes.
4270 With --debug, print file revision hashes.
4269
4271
4270 If option --all is specified, the list of all files from all revisions
4272 If option --all is specified, the list of all files from all revisions
4271 is printed. This includes deleted and renamed files.
4273 is printed. This includes deleted and renamed files.
4272
4274
4273 Returns 0 on success.
4275 Returns 0 on success.
4274 """
4276 """
4275
4277
4276 fm = ui.formatter('manifest', opts)
4278 fm = ui.formatter('manifest', opts)
4277
4279
4278 if opts.get('all'):
4280 if opts.get('all'):
4279 if rev or node:
4281 if rev or node:
4280 raise util.Abort(_("can't specify a revision with --all"))
4282 raise util.Abort(_("can't specify a revision with --all"))
4281
4283
4282 res = []
4284 res = []
4283 prefix = "data/"
4285 prefix = "data/"
4284 suffix = ".i"
4286 suffix = ".i"
4285 plen = len(prefix)
4287 plen = len(prefix)
4286 slen = len(suffix)
4288 slen = len(suffix)
4287 lock = repo.lock()
4289 lock = repo.lock()
4288 try:
4290 try:
4289 for fn, b, size in repo.store.datafiles():
4291 for fn, b, size in repo.store.datafiles():
4290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4292 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4291 res.append(fn[plen:-slen])
4293 res.append(fn[plen:-slen])
4292 finally:
4294 finally:
4293 lock.release()
4295 lock.release()
4294 for f in res:
4296 for f in res:
4295 fm.startitem()
4297 fm.startitem()
4296 fm.write("path", '%s\n', f)
4298 fm.write("path", '%s\n', f)
4297 fm.end()
4299 fm.end()
4298 return
4300 return
4299
4301
4300 if rev and node:
4302 if rev and node:
4301 raise util.Abort(_("please specify just one revision"))
4303 raise util.Abort(_("please specify just one revision"))
4302
4304
4303 if not node:
4305 if not node:
4304 node = rev
4306 node = rev
4305
4307
4306 char = {'l': '@', 'x': '*', '': ''}
4308 char = {'l': '@', 'x': '*', '': ''}
4307 mode = {'l': '644', 'x': '755', '': '644'}
4309 mode = {'l': '644', 'x': '755', '': '644'}
4308 ctx = scmutil.revsingle(repo, node)
4310 ctx = scmutil.revsingle(repo, node)
4309 mf = ctx.manifest()
4311 mf = ctx.manifest()
4310 for f in ctx:
4312 for f in ctx:
4311 fm.startitem()
4313 fm.startitem()
4312 fl = ctx[f].flags()
4314 fl = ctx[f].flags()
4313 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4315 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4314 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4316 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4315 fm.write('path', '%s\n', f)
4317 fm.write('path', '%s\n', f)
4316 fm.end()
4318 fm.end()
4317
4319
4318 @command('^merge',
4320 @command('^merge',
4319 [('f', 'force', None, _('force a merge with outstanding changes')),
4321 [('f', 'force', None, _('force a merge with outstanding changes')),
4320 ('r', 'rev', '', _('revision to merge'), _('REV')),
4322 ('r', 'rev', '', _('revision to merge'), _('REV')),
4321 ('P', 'preview', None,
4323 ('P', 'preview', None,
4322 _('review revisions to merge (no merge is performed)'))
4324 _('review revisions to merge (no merge is performed)'))
4323 ] + mergetoolopts,
4325 ] + mergetoolopts,
4324 _('[-P] [-f] [[-r] REV]'))
4326 _('[-P] [-f] [[-r] REV]'))
4325 def merge(ui, repo, node=None, **opts):
4327 def merge(ui, repo, node=None, **opts):
4326 """merge working directory with another revision
4328 """merge working directory with another revision
4327
4329
4328 The current working directory is updated with all changes made in
4330 The current working directory is updated with all changes made in
4329 the requested revision since the last common predecessor revision.
4331 the requested revision since the last common predecessor revision.
4330
4332
4331 Files that changed between either parent are marked as changed for
4333 Files that changed between either parent are marked as changed for
4332 the next commit and a commit must be performed before any further
4334 the next commit and a commit must be performed before any further
4333 updates to the repository are allowed. The next commit will have
4335 updates to the repository are allowed. The next commit will have
4334 two parents.
4336 two parents.
4335
4337
4336 ``--tool`` can be used to specify the merge tool used for file
4338 ``--tool`` can be used to specify the merge tool used for file
4337 merges. It overrides the HGMERGE environment variable and your
4339 merges. It overrides the HGMERGE environment variable and your
4338 configuration files. See :hg:`help merge-tools` for options.
4340 configuration files. See :hg:`help merge-tools` for options.
4339
4341
4340 If no revision is specified, the working directory's parent is a
4342 If no revision is specified, the working directory's parent is a
4341 head revision, and the current branch contains exactly one other
4343 head revision, and the current branch contains exactly one other
4342 head, the other head is merged with by default. Otherwise, an
4344 head, the other head is merged with by default. Otherwise, an
4343 explicit revision with which to merge with must be provided.
4345 explicit revision with which to merge with must be provided.
4344
4346
4345 :hg:`resolve` must be used to resolve unresolved files.
4347 :hg:`resolve` must be used to resolve unresolved files.
4346
4348
4347 To undo an uncommitted merge, use :hg:`update --clean .` which
4349 To undo an uncommitted merge, use :hg:`update --clean .` which
4348 will check out a clean copy of the original merge parent, losing
4350 will check out a clean copy of the original merge parent, losing
4349 all changes.
4351 all changes.
4350
4352
4351 Returns 0 on success, 1 if there are unresolved files.
4353 Returns 0 on success, 1 if there are unresolved files.
4352 """
4354 """
4353
4355
4354 if opts.get('rev') and node:
4356 if opts.get('rev') and node:
4355 raise util.Abort(_("please specify just one revision"))
4357 raise util.Abort(_("please specify just one revision"))
4356 if not node:
4358 if not node:
4357 node = opts.get('rev')
4359 node = opts.get('rev')
4358
4360
4359 if node:
4361 if node:
4360 node = scmutil.revsingle(repo, node).node()
4362 node = scmutil.revsingle(repo, node).node()
4361
4363
4362 if not node and repo._bookmarkcurrent:
4364 if not node and repo._bookmarkcurrent:
4363 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4365 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4364 curhead = repo[repo._bookmarkcurrent].node()
4366 curhead = repo[repo._bookmarkcurrent].node()
4365 if len(bmheads) == 2:
4367 if len(bmheads) == 2:
4366 if curhead == bmheads[0]:
4368 if curhead == bmheads[0]:
4367 node = bmheads[1]
4369 node = bmheads[1]
4368 else:
4370 else:
4369 node = bmheads[0]
4371 node = bmheads[0]
4370 elif len(bmheads) > 2:
4372 elif len(bmheads) > 2:
4371 raise util.Abort(_("multiple matching bookmarks to merge - "
4373 raise util.Abort(_("multiple matching bookmarks to merge - "
4372 "please merge with an explicit rev or bookmark"),
4374 "please merge with an explicit rev or bookmark"),
4373 hint=_("run 'hg heads' to see all heads"))
4375 hint=_("run 'hg heads' to see all heads"))
4374 elif len(bmheads) <= 1:
4376 elif len(bmheads) <= 1:
4375 raise util.Abort(_("no matching bookmark to merge - "
4377 raise util.Abort(_("no matching bookmark to merge - "
4376 "please merge with an explicit rev or bookmark"),
4378 "please merge with an explicit rev or bookmark"),
4377 hint=_("run 'hg heads' to see all heads"))
4379 hint=_("run 'hg heads' to see all heads"))
4378
4380
4379 if not node and not repo._bookmarkcurrent:
4381 if not node and not repo._bookmarkcurrent:
4380 branch = repo[None].branch()
4382 branch = repo[None].branch()
4381 bheads = repo.branchheads(branch)
4383 bheads = repo.branchheads(branch)
4382 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4384 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4383
4385
4384 if len(nbhs) > 2:
4386 if len(nbhs) > 2:
4385 raise util.Abort(_("branch '%s' has %d heads - "
4387 raise util.Abort(_("branch '%s' has %d heads - "
4386 "please merge with an explicit rev")
4388 "please merge with an explicit rev")
4387 % (branch, len(bheads)),
4389 % (branch, len(bheads)),
4388 hint=_("run 'hg heads .' to see heads"))
4390 hint=_("run 'hg heads .' to see heads"))
4389
4391
4390 parent = repo.dirstate.p1()
4392 parent = repo.dirstate.p1()
4391 if len(nbhs) <= 1:
4393 if len(nbhs) <= 1:
4392 if len(bheads) > 1:
4394 if len(bheads) > 1:
4393 raise util.Abort(_("heads are bookmarked - "
4395 raise util.Abort(_("heads are bookmarked - "
4394 "please merge with an explicit rev"),
4396 "please merge with an explicit rev"),
4395 hint=_("run 'hg heads' to see all heads"))
4397 hint=_("run 'hg heads' to see all heads"))
4396 if len(repo.heads()) > 1:
4398 if len(repo.heads()) > 1:
4397 raise util.Abort(_("branch '%s' has one head - "
4399 raise util.Abort(_("branch '%s' has one head - "
4398 "please merge with an explicit rev")
4400 "please merge with an explicit rev")
4399 % branch,
4401 % branch,
4400 hint=_("run 'hg heads' to see all heads"))
4402 hint=_("run 'hg heads' to see all heads"))
4401 msg, hint = _('nothing to merge'), None
4403 msg, hint = _('nothing to merge'), None
4402 if parent != repo.lookup(branch):
4404 if parent != repo.lookup(branch):
4403 hint = _("use 'hg update' instead")
4405 hint = _("use 'hg update' instead")
4404 raise util.Abort(msg, hint=hint)
4406 raise util.Abort(msg, hint=hint)
4405
4407
4406 if parent not in bheads:
4408 if parent not in bheads:
4407 raise util.Abort(_('working directory not at a head revision'),
4409 raise util.Abort(_('working directory not at a head revision'),
4408 hint=_("use 'hg update' or merge with an "
4410 hint=_("use 'hg update' or merge with an "
4409 "explicit revision"))
4411 "explicit revision"))
4410 if parent == nbhs[0]:
4412 if parent == nbhs[0]:
4411 node = nbhs[-1]
4413 node = nbhs[-1]
4412 else:
4414 else:
4413 node = nbhs[0]
4415 node = nbhs[0]
4414
4416
4415 if opts.get('preview'):
4417 if opts.get('preview'):
4416 # find nodes that are ancestors of p2 but not of p1
4418 # find nodes that are ancestors of p2 but not of p1
4417 p1 = repo.lookup('.')
4419 p1 = repo.lookup('.')
4418 p2 = repo.lookup(node)
4420 p2 = repo.lookup(node)
4419 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4420
4422
4421 displayer = cmdutil.show_changeset(ui, repo, opts)
4423 displayer = cmdutil.show_changeset(ui, repo, opts)
4422 for node in nodes:
4424 for node in nodes:
4423 displayer.show(repo[node])
4425 displayer.show(repo[node])
4424 displayer.close()
4426 displayer.close()
4425 return 0
4427 return 0
4426
4428
4427 try:
4429 try:
4428 # ui.forcemerge is an internal variable, do not document
4430 # ui.forcemerge is an internal variable, do not document
4429 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4430 return hg.merge(repo, node, force=opts.get('force'))
4432 return hg.merge(repo, node, force=opts.get('force'))
4431 finally:
4433 finally:
4432 ui.setconfig('ui', 'forcemerge', '')
4434 ui.setconfig('ui', 'forcemerge', '')
4433
4435
4434 @command('outgoing|out',
4436 @command('outgoing|out',
4435 [('f', 'force', None, _('run even when the destination is unrelated')),
4437 [('f', 'force', None, _('run even when the destination is unrelated')),
4436 ('r', 'rev', [],
4438 ('r', 'rev', [],
4437 _('a changeset intended to be included in the destination'), _('REV')),
4439 _('a changeset intended to be included in the destination'), _('REV')),
4438 ('n', 'newest-first', None, _('show newest record first')),
4440 ('n', 'newest-first', None, _('show newest record first')),
4439 ('B', 'bookmarks', False, _('compare bookmarks')),
4441 ('B', 'bookmarks', False, _('compare bookmarks')),
4440 ('b', 'branch', [], _('a specific branch you would like to push'),
4442 ('b', 'branch', [], _('a specific branch you would like to push'),
4441 _('BRANCH')),
4443 _('BRANCH')),
4442 ] + logopts + remoteopts + subrepoopts,
4444 ] + logopts + remoteopts + subrepoopts,
4443 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4445 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4444 def outgoing(ui, repo, dest=None, **opts):
4446 def outgoing(ui, repo, dest=None, **opts):
4445 """show changesets not found in the destination
4447 """show changesets not found in the destination
4446
4448
4447 Show changesets not found in the specified destination repository
4449 Show changesets not found in the specified destination repository
4448 or the default push location. These are the changesets that would
4450 or the default push location. These are the changesets that would
4449 be pushed if a push was requested.
4451 be pushed if a push was requested.
4450
4452
4451 See pull for details of valid destination formats.
4453 See pull for details of valid destination formats.
4452
4454
4453 Returns 0 if there are outgoing changes, 1 otherwise.
4455 Returns 0 if there are outgoing changes, 1 otherwise.
4454 """
4456 """
4455 if opts.get('graph'):
4457 if opts.get('graph'):
4456 cmdutil.checkunsupportedgraphflags([], opts)
4458 cmdutil.checkunsupportedgraphflags([], opts)
4457 o = hg._outgoing(ui, repo, dest, opts)
4459 o = hg._outgoing(ui, repo, dest, opts)
4458 if o is None:
4460 if o is None:
4459 return
4461 return
4460
4462
4461 revdag = cmdutil.graphrevs(repo, o, opts)
4463 revdag = cmdutil.graphrevs(repo, o, opts)
4462 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4464 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4463 showparents = [ctx.node() for ctx in repo[None].parents()]
4465 showparents = [ctx.node() for ctx in repo[None].parents()]
4464 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4466 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4465 graphmod.asciiedges)
4467 graphmod.asciiedges)
4466 return 0
4468 return 0
4467
4469
4468 if opts.get('bookmarks'):
4470 if opts.get('bookmarks'):
4469 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4471 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4470 dest, branches = hg.parseurl(dest, opts.get('branch'))
4472 dest, branches = hg.parseurl(dest, opts.get('branch'))
4471 other = hg.peer(repo, opts, dest)
4473 other = hg.peer(repo, opts, dest)
4472 if 'bookmarks' not in other.listkeys('namespaces'):
4474 if 'bookmarks' not in other.listkeys('namespaces'):
4473 ui.warn(_("remote doesn't support bookmarks\n"))
4475 ui.warn(_("remote doesn't support bookmarks\n"))
4474 return 0
4476 return 0
4475 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4477 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4476 return bookmarks.diff(ui, other, repo)
4478 return bookmarks.diff(ui, other, repo)
4477
4479
4478 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4480 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4479 try:
4481 try:
4480 return hg.outgoing(ui, repo, dest, opts)
4482 return hg.outgoing(ui, repo, dest, opts)
4481 finally:
4483 finally:
4482 del repo._subtoppath
4484 del repo._subtoppath
4483
4485
4484 @command('parents',
4486 @command('parents',
4485 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4487 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4486 ] + templateopts,
4488 ] + templateopts,
4487 _('[-r REV] [FILE]'))
4489 _('[-r REV] [FILE]'))
4488 def parents(ui, repo, file_=None, **opts):
4490 def parents(ui, repo, file_=None, **opts):
4489 """show the parents of the working directory or revision
4491 """show the parents of the working directory or revision
4490
4492
4491 Print the working directory's parent revisions. If a revision is
4493 Print the working directory's parent revisions. If a revision is
4492 given via -r/--rev, the parent of that revision will be printed.
4494 given via -r/--rev, the parent of that revision will be printed.
4493 If a file argument is given, the revision in which the file was
4495 If a file argument is given, the revision in which the file was
4494 last changed (before the working directory revision or the
4496 last changed (before the working directory revision or the
4495 argument to --rev if given) is printed.
4497 argument to --rev if given) is printed.
4496
4498
4497 Returns 0 on success.
4499 Returns 0 on success.
4498 """
4500 """
4499
4501
4500 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4502 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4501
4503
4502 if file_:
4504 if file_:
4503 m = scmutil.match(ctx, (file_,), opts)
4505 m = scmutil.match(ctx, (file_,), opts)
4504 if m.anypats() or len(m.files()) != 1:
4506 if m.anypats() or len(m.files()) != 1:
4505 raise util.Abort(_('can only specify an explicit filename'))
4507 raise util.Abort(_('can only specify an explicit filename'))
4506 file_ = m.files()[0]
4508 file_ = m.files()[0]
4507 filenodes = []
4509 filenodes = []
4508 for cp in ctx.parents():
4510 for cp in ctx.parents():
4509 if not cp:
4511 if not cp:
4510 continue
4512 continue
4511 try:
4513 try:
4512 filenodes.append(cp.filenode(file_))
4514 filenodes.append(cp.filenode(file_))
4513 except error.LookupError:
4515 except error.LookupError:
4514 pass
4516 pass
4515 if not filenodes:
4517 if not filenodes:
4516 raise util.Abort(_("'%s' not found in manifest!") % file_)
4518 raise util.Abort(_("'%s' not found in manifest!") % file_)
4517 fl = repo.file(file_)
4519 fl = repo.file(file_)
4518 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4520 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4519 else:
4521 else:
4520 p = [cp.node() for cp in ctx.parents()]
4522 p = [cp.node() for cp in ctx.parents()]
4521
4523
4522 displayer = cmdutil.show_changeset(ui, repo, opts)
4524 displayer = cmdutil.show_changeset(ui, repo, opts)
4523 for n in p:
4525 for n in p:
4524 if n != nullid:
4526 if n != nullid:
4525 displayer.show(repo[n])
4527 displayer.show(repo[n])
4526 displayer.close()
4528 displayer.close()
4527
4529
4528 @command('paths', [], _('[NAME]'))
4530 @command('paths', [], _('[NAME]'))
4529 def paths(ui, repo, search=None):
4531 def paths(ui, repo, search=None):
4530 """show aliases for remote repositories
4532 """show aliases for remote repositories
4531
4533
4532 Show definition of symbolic path name NAME. If no name is given,
4534 Show definition of symbolic path name NAME. If no name is given,
4533 show definition of all available names.
4535 show definition of all available names.
4534
4536
4535 Option -q/--quiet suppresses all output when searching for NAME
4537 Option -q/--quiet suppresses all output when searching for NAME
4536 and shows only the path names when listing all definitions.
4538 and shows only the path names when listing all definitions.
4537
4539
4538 Path names are defined in the [paths] section of your
4540 Path names are defined in the [paths] section of your
4539 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4541 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4540 repository, ``.hg/hgrc`` is used, too.
4542 repository, ``.hg/hgrc`` is used, too.
4541
4543
4542 The path names ``default`` and ``default-push`` have a special
4544 The path names ``default`` and ``default-push`` have a special
4543 meaning. When performing a push or pull operation, they are used
4545 meaning. When performing a push or pull operation, they are used
4544 as fallbacks if no location is specified on the command-line.
4546 as fallbacks if no location is specified on the command-line.
4545 When ``default-push`` is set, it will be used for push and
4547 When ``default-push`` is set, it will be used for push and
4546 ``default`` will be used for pull; otherwise ``default`` is used
4548 ``default`` will be used for pull; otherwise ``default`` is used
4547 as the fallback for both. When cloning a repository, the clone
4549 as the fallback for both. When cloning a repository, the clone
4548 source is written as ``default`` in ``.hg/hgrc``. Note that
4550 source is written as ``default`` in ``.hg/hgrc``. Note that
4549 ``default`` and ``default-push`` apply to all inbound (e.g.
4551 ``default`` and ``default-push`` apply to all inbound (e.g.
4550 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4552 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4551 :hg:`bundle`) operations.
4553 :hg:`bundle`) operations.
4552
4554
4553 See :hg:`help urls` for more information.
4555 See :hg:`help urls` for more information.
4554
4556
4555 Returns 0 on success.
4557 Returns 0 on success.
4556 """
4558 """
4557 if search:
4559 if search:
4558 for name, path in ui.configitems("paths"):
4560 for name, path in ui.configitems("paths"):
4559 if name == search:
4561 if name == search:
4560 ui.status("%s\n" % util.hidepassword(path))
4562 ui.status("%s\n" % util.hidepassword(path))
4561 return
4563 return
4562 if not ui.quiet:
4564 if not ui.quiet:
4563 ui.warn(_("not found!\n"))
4565 ui.warn(_("not found!\n"))
4564 return 1
4566 return 1
4565 else:
4567 else:
4566 for name, path in ui.configitems("paths"):
4568 for name, path in ui.configitems("paths"):
4567 if ui.quiet:
4569 if ui.quiet:
4568 ui.write("%s\n" % name)
4570 ui.write("%s\n" % name)
4569 else:
4571 else:
4570 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4572 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4571
4573
4572 @command('phase',
4574 @command('phase',
4573 [('p', 'public', False, _('set changeset phase to public')),
4575 [('p', 'public', False, _('set changeset phase to public')),
4574 ('d', 'draft', False, _('set changeset phase to draft')),
4576 ('d', 'draft', False, _('set changeset phase to draft')),
4575 ('s', 'secret', False, _('set changeset phase to secret')),
4577 ('s', 'secret', False, _('set changeset phase to secret')),
4576 ('f', 'force', False, _('allow to move boundary backward')),
4578 ('f', 'force', False, _('allow to move boundary backward')),
4577 ('r', 'rev', [], _('target revision'), _('REV')),
4579 ('r', 'rev', [], _('target revision'), _('REV')),
4578 ],
4580 ],
4579 _('[-p|-d|-s] [-f] [-r] REV...'))
4581 _('[-p|-d|-s] [-f] [-r] REV...'))
4580 def phase(ui, repo, *revs, **opts):
4582 def phase(ui, repo, *revs, **opts):
4581 """set or show the current phase name
4583 """set or show the current phase name
4582
4584
4583 With no argument, show the phase name of specified revisions.
4585 With no argument, show the phase name of specified revisions.
4584
4586
4585 With one of -p/--public, -d/--draft or -s/--secret, change the
4587 With one of -p/--public, -d/--draft or -s/--secret, change the
4586 phase value of the specified revisions.
4588 phase value of the specified revisions.
4587
4589
4588 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4590 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4589 lower phase to an higher phase. Phases are ordered as follows::
4591 lower phase to an higher phase. Phases are ordered as follows::
4590
4592
4591 public < draft < secret
4593 public < draft < secret
4592
4594
4593 Return 0 on success, 1 if no phases were changed or some could not
4595 Return 0 on success, 1 if no phases were changed or some could not
4594 be changed.
4596 be changed.
4595 """
4597 """
4596 # search for a unique phase argument
4598 # search for a unique phase argument
4597 targetphase = None
4599 targetphase = None
4598 for idx, name in enumerate(phases.phasenames):
4600 for idx, name in enumerate(phases.phasenames):
4599 if opts[name]:
4601 if opts[name]:
4600 if targetphase is not None:
4602 if targetphase is not None:
4601 raise util.Abort(_('only one phase can be specified'))
4603 raise util.Abort(_('only one phase can be specified'))
4602 targetphase = idx
4604 targetphase = idx
4603
4605
4604 # look for specified revision
4606 # look for specified revision
4605 revs = list(revs)
4607 revs = list(revs)
4606 revs.extend(opts['rev'])
4608 revs.extend(opts['rev'])
4607 if not revs:
4609 if not revs:
4608 raise util.Abort(_('no revisions specified'))
4610 raise util.Abort(_('no revisions specified'))
4609
4611
4610 revs = scmutil.revrange(repo, revs)
4612 revs = scmutil.revrange(repo, revs)
4611
4613
4612 lock = None
4614 lock = None
4613 ret = 0
4615 ret = 0
4614 if targetphase is None:
4616 if targetphase is None:
4615 # display
4617 # display
4616 for r in revs:
4618 for r in revs:
4617 ctx = repo[r]
4619 ctx = repo[r]
4618 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4620 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4619 else:
4621 else:
4620 lock = repo.lock()
4622 lock = repo.lock()
4621 try:
4623 try:
4622 # set phase
4624 # set phase
4623 if not revs:
4625 if not revs:
4624 raise util.Abort(_('empty revision set'))
4626 raise util.Abort(_('empty revision set'))
4625 nodes = [repo[r].node() for r in revs]
4627 nodes = [repo[r].node() for r in revs]
4626 olddata = repo._phasecache.getphaserevs(repo)[:]
4628 olddata = repo._phasecache.getphaserevs(repo)[:]
4627 phases.advanceboundary(repo, targetphase, nodes)
4629 phases.advanceboundary(repo, targetphase, nodes)
4628 if opts['force']:
4630 if opts['force']:
4629 phases.retractboundary(repo, targetphase, nodes)
4631 phases.retractboundary(repo, targetphase, nodes)
4630 finally:
4632 finally:
4631 lock.release()
4633 lock.release()
4632 # moving revision from public to draft may hide them
4634 # moving revision from public to draft may hide them
4633 # We have to check result on an unfiltered repository
4635 # We have to check result on an unfiltered repository
4634 unfi = repo.unfiltered()
4636 unfi = repo.unfiltered()
4635 newdata = repo._phasecache.getphaserevs(unfi)
4637 newdata = repo._phasecache.getphaserevs(unfi)
4636 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4638 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4637 cl = unfi.changelog
4639 cl = unfi.changelog
4638 rejected = [n for n in nodes
4640 rejected = [n for n in nodes
4639 if newdata[cl.rev(n)] < targetphase]
4641 if newdata[cl.rev(n)] < targetphase]
4640 if rejected:
4642 if rejected:
4641 ui.warn(_('cannot move %i changesets to a more permissive '
4643 ui.warn(_('cannot move %i changesets to a more permissive '
4642 'phase, use --force\n') % len(rejected))
4644 'phase, use --force\n') % len(rejected))
4643 ret = 1
4645 ret = 1
4644 if changes:
4646 if changes:
4645 msg = _('phase changed for %i changesets\n') % changes
4647 msg = _('phase changed for %i changesets\n') % changes
4646 if ret:
4648 if ret:
4647 ui.status(msg)
4649 ui.status(msg)
4648 else:
4650 else:
4649 ui.note(msg)
4651 ui.note(msg)
4650 else:
4652 else:
4651 ui.warn(_('no phases changed\n'))
4653 ui.warn(_('no phases changed\n'))
4652 ret = 1
4654 ret = 1
4653 return ret
4655 return ret
4654
4656
4655 def postincoming(ui, repo, modheads, optupdate, checkout):
4657 def postincoming(ui, repo, modheads, optupdate, checkout):
4656 if modheads == 0:
4658 if modheads == 0:
4657 return
4659 return
4658 if optupdate:
4660 if optupdate:
4659 movemarkfrom = repo['.'].node()
4661 movemarkfrom = repo['.'].node()
4660 try:
4662 try:
4661 ret = hg.update(repo, checkout)
4663 ret = hg.update(repo, checkout)
4662 except util.Abort, inst:
4664 except util.Abort, inst:
4663 ui.warn(_("not updating: %s\n") % str(inst))
4665 ui.warn(_("not updating: %s\n") % str(inst))
4664 return 0
4666 return 0
4665 if not ret and not checkout:
4667 if not ret and not checkout:
4666 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4668 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4667 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4669 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4668 return ret
4670 return ret
4669 if modheads > 1:
4671 if modheads > 1:
4670 currentbranchheads = len(repo.branchheads())
4672 currentbranchheads = len(repo.branchheads())
4671 if currentbranchheads == modheads:
4673 if currentbranchheads == modheads:
4672 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4674 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4673 elif currentbranchheads > 1:
4675 elif currentbranchheads > 1:
4674 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4676 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4675 "merge)\n"))
4677 "merge)\n"))
4676 else:
4678 else:
4677 ui.status(_("(run 'hg heads' to see heads)\n"))
4679 ui.status(_("(run 'hg heads' to see heads)\n"))
4678 else:
4680 else:
4679 ui.status(_("(run 'hg update' to get a working copy)\n"))
4681 ui.status(_("(run 'hg update' to get a working copy)\n"))
4680
4682
4681 @command('^pull',
4683 @command('^pull',
4682 [('u', 'update', None,
4684 [('u', 'update', None,
4683 _('update to new branch head if changesets were pulled')),
4685 _('update to new branch head if changesets were pulled')),
4684 ('f', 'force', None, _('run even when remote repository is unrelated')),
4686 ('f', 'force', None, _('run even when remote repository is unrelated')),
4685 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4687 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4686 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4688 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4687 ('b', 'branch', [], _('a specific branch you would like to pull'),
4689 ('b', 'branch', [], _('a specific branch you would like to pull'),
4688 _('BRANCH')),
4690 _('BRANCH')),
4689 ] + remoteopts,
4691 ] + remoteopts,
4690 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4692 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4691 def pull(ui, repo, source="default", **opts):
4693 def pull(ui, repo, source="default", **opts):
4692 """pull changes from the specified source
4694 """pull changes from the specified source
4693
4695
4694 Pull changes from a remote repository to a local one.
4696 Pull changes from a remote repository to a local one.
4695
4697
4696 This finds all changes from the repository at the specified path
4698 This finds all changes from the repository at the specified path
4697 or URL and adds them to a local repository (the current one unless
4699 or URL and adds them to a local repository (the current one unless
4698 -R is specified). By default, this does not update the copy of the
4700 -R is specified). By default, this does not update the copy of the
4699 project in the working directory.
4701 project in the working directory.
4700
4702
4701 Use :hg:`incoming` if you want to see what would have been added
4703 Use :hg:`incoming` if you want to see what would have been added
4702 by a pull at the time you issued this command. If you then decide
4704 by a pull at the time you issued this command. If you then decide
4703 to add those changes to the repository, you should use :hg:`pull
4705 to add those changes to the repository, you should use :hg:`pull
4704 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4706 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4705
4707
4706 If SOURCE is omitted, the 'default' path will be used.
4708 If SOURCE is omitted, the 'default' path will be used.
4707 See :hg:`help urls` for more information.
4709 See :hg:`help urls` for more information.
4708
4710
4709 Returns 0 on success, 1 if an update had unresolved files.
4711 Returns 0 on success, 1 if an update had unresolved files.
4710 """
4712 """
4711 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4713 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4712 other = hg.peer(repo, opts, source)
4714 other = hg.peer(repo, opts, source)
4713 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4715 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4714 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4716 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4715
4717
4716 if opts.get('bookmark'):
4718 if opts.get('bookmark'):
4717 if not revs:
4719 if not revs:
4718 revs = []
4720 revs = []
4719 rb = other.listkeys('bookmarks')
4721 rb = other.listkeys('bookmarks')
4720 for b in opts['bookmark']:
4722 for b in opts['bookmark']:
4721 if b not in rb:
4723 if b not in rb:
4722 raise util.Abort(_('remote bookmark %s not found!') % b)
4724 raise util.Abort(_('remote bookmark %s not found!') % b)
4723 revs.append(rb[b])
4725 revs.append(rb[b])
4724
4726
4725 if revs:
4727 if revs:
4726 try:
4728 try:
4727 revs = [other.lookup(rev) for rev in revs]
4729 revs = [other.lookup(rev) for rev in revs]
4728 except error.CapabilityError:
4730 except error.CapabilityError:
4729 err = _("other repository doesn't support revision lookup, "
4731 err = _("other repository doesn't support revision lookup, "
4730 "so a rev cannot be specified.")
4732 "so a rev cannot be specified.")
4731 raise util.Abort(err)
4733 raise util.Abort(err)
4732
4734
4733 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4735 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4734 bookmarks.updatefromremote(ui, repo, other, source)
4736 bookmarks.updatefromremote(ui, repo, other, source)
4735 if checkout:
4737 if checkout:
4736 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4738 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4737 repo._subtoppath = source
4739 repo._subtoppath = source
4738 try:
4740 try:
4739 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4741 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4740
4742
4741 finally:
4743 finally:
4742 del repo._subtoppath
4744 del repo._subtoppath
4743
4745
4744 # update specified bookmarks
4746 # update specified bookmarks
4745 if opts.get('bookmark'):
4747 if opts.get('bookmark'):
4746 marks = repo._bookmarks
4748 marks = repo._bookmarks
4747 for b in opts['bookmark']:
4749 for b in opts['bookmark']:
4748 # explicit pull overrides local bookmark if any
4750 # explicit pull overrides local bookmark if any
4749 ui.status(_("importing bookmark %s\n") % b)
4751 ui.status(_("importing bookmark %s\n") % b)
4750 marks[b] = repo[rb[b]].node()
4752 marks[b] = repo[rb[b]].node()
4751 marks.write()
4753 marks.write()
4752
4754
4753 return ret
4755 return ret
4754
4756
4755 @command('^push',
4757 @command('^push',
4756 [('f', 'force', None, _('force push')),
4758 [('f', 'force', None, _('force push')),
4757 ('r', 'rev', [],
4759 ('r', 'rev', [],
4758 _('a changeset intended to be included in the destination'),
4760 _('a changeset intended to be included in the destination'),
4759 _('REV')),
4761 _('REV')),
4760 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4762 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4761 ('b', 'branch', [],
4763 ('b', 'branch', [],
4762 _('a specific branch you would like to push'), _('BRANCH')),
4764 _('a specific branch you would like to push'), _('BRANCH')),
4763 ('', 'new-branch', False, _('allow pushing a new branch')),
4765 ('', 'new-branch', False, _('allow pushing a new branch')),
4764 ] + remoteopts,
4766 ] + remoteopts,
4765 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4767 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4766 def push(ui, repo, dest=None, **opts):
4768 def push(ui, repo, dest=None, **opts):
4767 """push changes to the specified destination
4769 """push changes to the specified destination
4768
4770
4769 Push changesets from the local repository to the specified
4771 Push changesets from the local repository to the specified
4770 destination.
4772 destination.
4771
4773
4772 This operation is symmetrical to pull: it is identical to a pull
4774 This operation is symmetrical to pull: it is identical to a pull
4773 in the destination repository from the current one.
4775 in the destination repository from the current one.
4774
4776
4775 By default, push will not allow creation of new heads at the
4777 By default, push will not allow creation of new heads at the
4776 destination, since multiple heads would make it unclear which head
4778 destination, since multiple heads would make it unclear which head
4777 to use. In this situation, it is recommended to pull and merge
4779 to use. In this situation, it is recommended to pull and merge
4778 before pushing.
4780 before pushing.
4779
4781
4780 Use --new-branch if you want to allow push to create a new named
4782 Use --new-branch if you want to allow push to create a new named
4781 branch that is not present at the destination. This allows you to
4783 branch that is not present at the destination. This allows you to
4782 only create a new branch without forcing other changes.
4784 only create a new branch without forcing other changes.
4783
4785
4784 Use -f/--force to override the default behavior and push all
4786 Use -f/--force to override the default behavior and push all
4785 changesets on all branches.
4787 changesets on all branches.
4786
4788
4787 If -r/--rev is used, the specified revision and all its ancestors
4789 If -r/--rev is used, the specified revision and all its ancestors
4788 will be pushed to the remote repository.
4790 will be pushed to the remote repository.
4789
4791
4790 If -B/--bookmark is used, the specified bookmarked revision, its
4792 If -B/--bookmark is used, the specified bookmarked revision, its
4791 ancestors, and the bookmark will be pushed to the remote
4793 ancestors, and the bookmark will be pushed to the remote
4792 repository.
4794 repository.
4793
4795
4794 Please see :hg:`help urls` for important details about ``ssh://``
4796 Please see :hg:`help urls` for important details about ``ssh://``
4795 URLs. If DESTINATION is omitted, a default path will be used.
4797 URLs. If DESTINATION is omitted, a default path will be used.
4796
4798
4797 Returns 0 if push was successful, 1 if nothing to push.
4799 Returns 0 if push was successful, 1 if nothing to push.
4798 """
4800 """
4799
4801
4800 if opts.get('bookmark'):
4802 if opts.get('bookmark'):
4801 for b in opts['bookmark']:
4803 for b in opts['bookmark']:
4802 # translate -B options to -r so changesets get pushed
4804 # translate -B options to -r so changesets get pushed
4803 if b in repo._bookmarks:
4805 if b in repo._bookmarks:
4804 opts.setdefault('rev', []).append(b)
4806 opts.setdefault('rev', []).append(b)
4805 else:
4807 else:
4806 # if we try to push a deleted bookmark, translate it to null
4808 # if we try to push a deleted bookmark, translate it to null
4807 # this lets simultaneous -r, -b options continue working
4809 # this lets simultaneous -r, -b options continue working
4808 opts.setdefault('rev', []).append("null")
4810 opts.setdefault('rev', []).append("null")
4809
4811
4810 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4812 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4811 dest, branches = hg.parseurl(dest, opts.get('branch'))
4813 dest, branches = hg.parseurl(dest, opts.get('branch'))
4812 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4814 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4813 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4815 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4814 other = hg.peer(repo, opts, dest)
4816 other = hg.peer(repo, opts, dest)
4815 if revs:
4817 if revs:
4816 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4818 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4817
4819
4818 repo._subtoppath = dest
4820 repo._subtoppath = dest
4819 try:
4821 try:
4820 # push subrepos depth-first for coherent ordering
4822 # push subrepos depth-first for coherent ordering
4821 c = repo['']
4823 c = repo['']
4822 subs = c.substate # only repos that are committed
4824 subs = c.substate # only repos that are committed
4823 for s in sorted(subs):
4825 for s in sorted(subs):
4824 if c.sub(s).push(opts) == 0:
4826 if c.sub(s).push(opts) == 0:
4825 return False
4827 return False
4826 finally:
4828 finally:
4827 del repo._subtoppath
4829 del repo._subtoppath
4828 result = repo.push(other, opts.get('force'), revs=revs,
4830 result = repo.push(other, opts.get('force'), revs=revs,
4829 newbranch=opts.get('new_branch'))
4831 newbranch=opts.get('new_branch'))
4830
4832
4831 result = not result
4833 result = not result
4832
4834
4833 if opts.get('bookmark'):
4835 if opts.get('bookmark'):
4834 rb = other.listkeys('bookmarks')
4836 rb = other.listkeys('bookmarks')
4835 for b in opts['bookmark']:
4837 for b in opts['bookmark']:
4836 # explicit push overrides remote bookmark if any
4838 # explicit push overrides remote bookmark if any
4837 if b in repo._bookmarks:
4839 if b in repo._bookmarks:
4838 ui.status(_("exporting bookmark %s\n") % b)
4840 ui.status(_("exporting bookmark %s\n") % b)
4839 new = repo[b].hex()
4841 new = repo[b].hex()
4840 elif b in rb:
4842 elif b in rb:
4841 ui.status(_("deleting remote bookmark %s\n") % b)
4843 ui.status(_("deleting remote bookmark %s\n") % b)
4842 new = '' # delete
4844 new = '' # delete
4843 else:
4845 else:
4844 ui.warn(_('bookmark %s does not exist on the local '
4846 ui.warn(_('bookmark %s does not exist on the local '
4845 'or remote repository!\n') % b)
4847 'or remote repository!\n') % b)
4846 return 2
4848 return 2
4847 old = rb.get(b, '')
4849 old = rb.get(b, '')
4848 r = other.pushkey('bookmarks', b, old, new)
4850 r = other.pushkey('bookmarks', b, old, new)
4849 if not r:
4851 if not r:
4850 ui.warn(_('updating bookmark %s failed!\n') % b)
4852 ui.warn(_('updating bookmark %s failed!\n') % b)
4851 if not result:
4853 if not result:
4852 result = 2
4854 result = 2
4853
4855
4854 return result
4856 return result
4855
4857
4856 @command('recover', [])
4858 @command('recover', [])
4857 def recover(ui, repo):
4859 def recover(ui, repo):
4858 """roll back an interrupted transaction
4860 """roll back an interrupted transaction
4859
4861
4860 Recover from an interrupted commit or pull.
4862 Recover from an interrupted commit or pull.
4861
4863
4862 This command tries to fix the repository status after an
4864 This command tries to fix the repository status after an
4863 interrupted operation. It should only be necessary when Mercurial
4865 interrupted operation. It should only be necessary when Mercurial
4864 suggests it.
4866 suggests it.
4865
4867
4866 Returns 0 if successful, 1 if nothing to recover or verify fails.
4868 Returns 0 if successful, 1 if nothing to recover or verify fails.
4867 """
4869 """
4868 if repo.recover():
4870 if repo.recover():
4869 return hg.verify(repo)
4871 return hg.verify(repo)
4870 return 1
4872 return 1
4871
4873
4872 @command('^remove|rm',
4874 @command('^remove|rm',
4873 [('A', 'after', None, _('record delete for missing files')),
4875 [('A', 'after', None, _('record delete for missing files')),
4874 ('f', 'force', None,
4876 ('f', 'force', None,
4875 _('remove (and delete) file even if added or modified')),
4877 _('remove (and delete) file even if added or modified')),
4876 ] + walkopts,
4878 ] + walkopts,
4877 _('[OPTION]... FILE...'))
4879 _('[OPTION]... FILE...'))
4878 def remove(ui, repo, *pats, **opts):
4880 def remove(ui, repo, *pats, **opts):
4879 """remove the specified files on the next commit
4881 """remove the specified files on the next commit
4880
4882
4881 Schedule the indicated files for removal from the current branch.
4883 Schedule the indicated files for removal from the current branch.
4882
4884
4883 This command schedules the files to be removed at the next commit.
4885 This command schedules the files to be removed at the next commit.
4884 To undo a remove before that, see :hg:`revert`. To undo added
4886 To undo a remove before that, see :hg:`revert`. To undo added
4885 files, see :hg:`forget`.
4887 files, see :hg:`forget`.
4886
4888
4887 .. container:: verbose
4889 .. container:: verbose
4888
4890
4889 -A/--after can be used to remove only files that have already
4891 -A/--after can be used to remove only files that have already
4890 been deleted, -f/--force can be used to force deletion, and -Af
4892 been deleted, -f/--force can be used to force deletion, and -Af
4891 can be used to remove files from the next revision without
4893 can be used to remove files from the next revision without
4892 deleting them from the working directory.
4894 deleting them from the working directory.
4893
4895
4894 The following table details the behavior of remove for different
4896 The following table details the behavior of remove for different
4895 file states (columns) and option combinations (rows). The file
4897 file states (columns) and option combinations (rows). The file
4896 states are Added [A], Clean [C], Modified [M] and Missing [!]
4898 states are Added [A], Clean [C], Modified [M] and Missing [!]
4897 (as reported by :hg:`status`). The actions are Warn, Remove
4899 (as reported by :hg:`status`). The actions are Warn, Remove
4898 (from branch) and Delete (from disk):
4900 (from branch) and Delete (from disk):
4899
4901
4900 ======= == == == ==
4902 ======= == == == ==
4901 A C M !
4903 A C M !
4902 ======= == == == ==
4904 ======= == == == ==
4903 none W RD W R
4905 none W RD W R
4904 -f R RD RD R
4906 -f R RD RD R
4905 -A W W W R
4907 -A W W W R
4906 -Af R R R R
4908 -Af R R R R
4907 ======= == == == ==
4909 ======= == == == ==
4908
4910
4909 Note that remove never deletes files in Added [A] state from the
4911 Note that remove never deletes files in Added [A] state from the
4910 working directory, not even if option --force is specified.
4912 working directory, not even if option --force is specified.
4911
4913
4912 Returns 0 on success, 1 if any warnings encountered.
4914 Returns 0 on success, 1 if any warnings encountered.
4913 """
4915 """
4914
4916
4915 ret = 0
4917 ret = 0
4916 after, force = opts.get('after'), opts.get('force')
4918 after, force = opts.get('after'), opts.get('force')
4917 if not pats and not after:
4919 if not pats and not after:
4918 raise util.Abort(_('no files specified'))
4920 raise util.Abort(_('no files specified'))
4919
4921
4920 m = scmutil.match(repo[None], pats, opts)
4922 m = scmutil.match(repo[None], pats, opts)
4921 s = repo.status(match=m, clean=True)
4923 s = repo.status(match=m, clean=True)
4922 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4924 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4923
4925
4924 # warn about failure to delete explicit files/dirs
4926 # warn about failure to delete explicit files/dirs
4925 wctx = repo[None]
4927 wctx = repo[None]
4926 for f in m.files():
4928 for f in m.files():
4927 if f in repo.dirstate or f in wctx.dirs():
4929 if f in repo.dirstate or f in wctx.dirs():
4928 continue
4930 continue
4929 if os.path.exists(m.rel(f)):
4931 if os.path.exists(m.rel(f)):
4930 if os.path.isdir(m.rel(f)):
4932 if os.path.isdir(m.rel(f)):
4931 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4933 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4932 else:
4934 else:
4933 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4935 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4934 # missing files will generate a warning elsewhere
4936 # missing files will generate a warning elsewhere
4935 ret = 1
4937 ret = 1
4936
4938
4937 if force:
4939 if force:
4938 list = modified + deleted + clean + added
4940 list = modified + deleted + clean + added
4939 elif after:
4941 elif after:
4940 list = deleted
4942 list = deleted
4941 for f in modified + added + clean:
4943 for f in modified + added + clean:
4942 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4944 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4943 ret = 1
4945 ret = 1
4944 else:
4946 else:
4945 list = deleted + clean
4947 list = deleted + clean
4946 for f in modified:
4948 for f in modified:
4947 ui.warn(_('not removing %s: file is modified (use -f'
4949 ui.warn(_('not removing %s: file is modified (use -f'
4948 ' to force removal)\n') % m.rel(f))
4950 ' to force removal)\n') % m.rel(f))
4949 ret = 1
4951 ret = 1
4950 for f in added:
4952 for f in added:
4951 ui.warn(_('not removing %s: file has been marked for add'
4953 ui.warn(_('not removing %s: file has been marked for add'
4952 ' (use forget to undo)\n') % m.rel(f))
4954 ' (use forget to undo)\n') % m.rel(f))
4953 ret = 1
4955 ret = 1
4954
4956
4955 for f in sorted(list):
4957 for f in sorted(list):
4956 if ui.verbose or not m.exact(f):
4958 if ui.verbose or not m.exact(f):
4957 ui.status(_('removing %s\n') % m.rel(f))
4959 ui.status(_('removing %s\n') % m.rel(f))
4958
4960
4959 wlock = repo.wlock()
4961 wlock = repo.wlock()
4960 try:
4962 try:
4961 if not after:
4963 if not after:
4962 for f in list:
4964 for f in list:
4963 if f in added:
4965 if f in added:
4964 continue # we never unlink added files on remove
4966 continue # we never unlink added files on remove
4965 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4967 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4966 repo[None].forget(list)
4968 repo[None].forget(list)
4967 finally:
4969 finally:
4968 wlock.release()
4970 wlock.release()
4969
4971
4970 return ret
4972 return ret
4971
4973
4972 @command('rename|move|mv',
4974 @command('rename|move|mv',
4973 [('A', 'after', None, _('record a rename that has already occurred')),
4975 [('A', 'after', None, _('record a rename that has already occurred')),
4974 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4976 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4975 ] + walkopts + dryrunopts,
4977 ] + walkopts + dryrunopts,
4976 _('[OPTION]... SOURCE... DEST'))
4978 _('[OPTION]... SOURCE... DEST'))
4977 def rename(ui, repo, *pats, **opts):
4979 def rename(ui, repo, *pats, **opts):
4978 """rename files; equivalent of copy + remove
4980 """rename files; equivalent of copy + remove
4979
4981
4980 Mark dest as copies of sources; mark sources for deletion. If dest
4982 Mark dest as copies of sources; mark sources for deletion. If dest
4981 is a directory, copies are put in that directory. If dest is a
4983 is a directory, copies are put in that directory. If dest is a
4982 file, there can only be one source.
4984 file, there can only be one source.
4983
4985
4984 By default, this command copies the contents of files as they
4986 By default, this command copies the contents of files as they
4985 exist in the working directory. If invoked with -A/--after, the
4987 exist in the working directory. If invoked with -A/--after, the
4986 operation is recorded, but no copying is performed.
4988 operation is recorded, but no copying is performed.
4987
4989
4988 This command takes effect at the next commit. To undo a rename
4990 This command takes effect at the next commit. To undo a rename
4989 before that, see :hg:`revert`.
4991 before that, see :hg:`revert`.
4990
4992
4991 Returns 0 on success, 1 if errors are encountered.
4993 Returns 0 on success, 1 if errors are encountered.
4992 """
4994 """
4993 wlock = repo.wlock(False)
4995 wlock = repo.wlock(False)
4994 try:
4996 try:
4995 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4997 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4996 finally:
4998 finally:
4997 wlock.release()
4999 wlock.release()
4998
5000
4999 @command('resolve',
5001 @command('resolve',
5000 [('a', 'all', None, _('select all unresolved files')),
5002 [('a', 'all', None, _('select all unresolved files')),
5001 ('l', 'list', None, _('list state of files needing merge')),
5003 ('l', 'list', None, _('list state of files needing merge')),
5002 ('m', 'mark', None, _('mark files as resolved')),
5004 ('m', 'mark', None, _('mark files as resolved')),
5003 ('u', 'unmark', None, _('mark files as unresolved')),
5005 ('u', 'unmark', None, _('mark files as unresolved')),
5004 ('n', 'no-status', None, _('hide status prefix'))]
5006 ('n', 'no-status', None, _('hide status prefix'))]
5005 + mergetoolopts + walkopts,
5007 + mergetoolopts + walkopts,
5006 _('[OPTION]... [FILE]...'))
5008 _('[OPTION]... [FILE]...'))
5007 def resolve(ui, repo, *pats, **opts):
5009 def resolve(ui, repo, *pats, **opts):
5008 """redo merges or set/view the merge status of files
5010 """redo merges or set/view the merge status of files
5009
5011
5010 Merges with unresolved conflicts are often the result of
5012 Merges with unresolved conflicts are often the result of
5011 non-interactive merging using the ``internal:merge`` configuration
5013 non-interactive merging using the ``internal:merge`` configuration
5012 setting, or a command-line merge tool like ``diff3``. The resolve
5014 setting, or a command-line merge tool like ``diff3``. The resolve
5013 command is used to manage the files involved in a merge, after
5015 command is used to manage the files involved in a merge, after
5014 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5015 working directory must have two parents). See :hg:`help
5017 working directory must have two parents). See :hg:`help
5016 merge-tools` for information on configuring merge tools.
5018 merge-tools` for information on configuring merge tools.
5017
5019
5018 The resolve command can be used in the following ways:
5020 The resolve command can be used in the following ways:
5019
5021
5020 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5021 files, discarding any previous merge attempts. Re-merging is not
5023 files, discarding any previous merge attempts. Re-merging is not
5022 performed for files already marked as resolved. Use ``--all/-a``
5024 performed for files already marked as resolved. Use ``--all/-a``
5023 to select all unresolved files. ``--tool`` can be used to specify
5025 to select all unresolved files. ``--tool`` can be used to specify
5024 the merge tool used for the given files. It overrides the HGMERGE
5026 the merge tool used for the given files. It overrides the HGMERGE
5025 environment variable and your configuration files. Previous file
5027 environment variable and your configuration files. Previous file
5026 contents are saved with a ``.orig`` suffix.
5028 contents are saved with a ``.orig`` suffix.
5027
5029
5028 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5029 (e.g. after having manually fixed-up the files). The default is
5031 (e.g. after having manually fixed-up the files). The default is
5030 to mark all unresolved files.
5032 to mark all unresolved files.
5031
5033
5032 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5033 default is to mark all resolved files.
5035 default is to mark all resolved files.
5034
5036
5035 - :hg:`resolve -l`: list files which had or still have conflicts.
5037 - :hg:`resolve -l`: list files which had or still have conflicts.
5036 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5037
5039
5038 Note that Mercurial will not let you commit files with unresolved
5040 Note that Mercurial will not let you commit files with unresolved
5039 merge conflicts. You must use :hg:`resolve -m ...` before you can
5041 merge conflicts. You must use :hg:`resolve -m ...` before you can
5040 commit after a conflicting merge.
5042 commit after a conflicting merge.
5041
5043
5042 Returns 0 on success, 1 if any files fail a resolve attempt.
5044 Returns 0 on success, 1 if any files fail a resolve attempt.
5043 """
5045 """
5044
5046
5045 all, mark, unmark, show, nostatus = \
5047 all, mark, unmark, show, nostatus = \
5046 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5048 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5047
5049
5048 if (show and (mark or unmark)) or (mark and unmark):
5050 if (show and (mark or unmark)) or (mark and unmark):
5049 raise util.Abort(_("too many options specified"))
5051 raise util.Abort(_("too many options specified"))
5050 if pats and all:
5052 if pats and all:
5051 raise util.Abort(_("can't specify --all and patterns"))
5053 raise util.Abort(_("can't specify --all and patterns"))
5052 if not (all or pats or show or mark or unmark):
5054 if not (all or pats or show or mark or unmark):
5053 raise util.Abort(_('no files or directories specified; '
5055 raise util.Abort(_('no files or directories specified; '
5054 'use --all to remerge all files'))
5056 'use --all to remerge all files'))
5055
5057
5056 ms = mergemod.mergestate(repo)
5058 ms = mergemod.mergestate(repo)
5057 m = scmutil.match(repo[None], pats, opts)
5059 m = scmutil.match(repo[None], pats, opts)
5058 ret = 0
5060 ret = 0
5059
5061
5060 for f in ms:
5062 for f in ms:
5061 if m(f):
5063 if m(f):
5062 if show:
5064 if show:
5063 if nostatus:
5065 if nostatus:
5064 ui.write("%s\n" % f)
5066 ui.write("%s\n" % f)
5065 else:
5067 else:
5066 ui.write("%s %s\n" % (ms[f].upper(), f),
5068 ui.write("%s %s\n" % (ms[f].upper(), f),
5067 label='resolve.' +
5069 label='resolve.' +
5068 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5070 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5069 elif mark:
5071 elif mark:
5070 ms.mark(f, "r")
5072 ms.mark(f, "r")
5071 elif unmark:
5073 elif unmark:
5072 ms.mark(f, "u")
5074 ms.mark(f, "u")
5073 else:
5075 else:
5074 wctx = repo[None]
5076 wctx = repo[None]
5075 mctx = wctx.parents()[-1]
5077 mctx = wctx.parents()[-1]
5076
5078
5077 # backup pre-resolve (merge uses .orig for its own purposes)
5079 # backup pre-resolve (merge uses .orig for its own purposes)
5078 a = repo.wjoin(f)
5080 a = repo.wjoin(f)
5079 util.copyfile(a, a + ".resolve")
5081 util.copyfile(a, a + ".resolve")
5080
5082
5081 try:
5083 try:
5082 # resolve file
5084 # resolve file
5083 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5085 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5084 if ms.resolve(f, wctx, mctx):
5086 if ms.resolve(f, wctx, mctx):
5085 ret = 1
5087 ret = 1
5086 finally:
5088 finally:
5087 ui.setconfig('ui', 'forcemerge', '')
5089 ui.setconfig('ui', 'forcemerge', '')
5088 ms.commit()
5090 ms.commit()
5089
5091
5090 # replace filemerge's .orig file with our resolve file
5092 # replace filemerge's .orig file with our resolve file
5091 util.rename(a + ".resolve", a + ".orig")
5093 util.rename(a + ".resolve", a + ".orig")
5092
5094
5093 ms.commit()
5095 ms.commit()
5094 return ret
5096 return ret
5095
5097
5096 @command('revert',
5098 @command('revert',
5097 [('a', 'all', None, _('revert all changes when no arguments given')),
5099 [('a', 'all', None, _('revert all changes when no arguments given')),
5098 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5100 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5099 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5101 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5100 ('C', 'no-backup', None, _('do not save backup copies of files')),
5102 ('C', 'no-backup', None, _('do not save backup copies of files')),
5101 ] + walkopts + dryrunopts,
5103 ] + walkopts + dryrunopts,
5102 _('[OPTION]... [-r REV] [NAME]...'))
5104 _('[OPTION]... [-r REV] [NAME]...'))
5103 def revert(ui, repo, *pats, **opts):
5105 def revert(ui, repo, *pats, **opts):
5104 """restore files to their checkout state
5106 """restore files to their checkout state
5105
5107
5106 .. note::
5108 .. note::
5107
5109
5108 To check out earlier revisions, you should use :hg:`update REV`.
5110 To check out earlier revisions, you should use :hg:`update REV`.
5109 To cancel an uncommitted merge (and lose your changes), use
5111 To cancel an uncommitted merge (and lose your changes), use
5110 :hg:`update --clean .`.
5112 :hg:`update --clean .`.
5111
5113
5112 With no revision specified, revert the specified files or directories
5114 With no revision specified, revert the specified files or directories
5113 to the contents they had in the parent of the working directory.
5115 to the contents they had in the parent of the working directory.
5114 This restores the contents of files to an unmodified
5116 This restores the contents of files to an unmodified
5115 state and unschedules adds, removes, copies, and renames. If the
5117 state and unschedules adds, removes, copies, and renames. If the
5116 working directory has two parents, you must explicitly specify a
5118 working directory has two parents, you must explicitly specify a
5117 revision.
5119 revision.
5118
5120
5119 Using the -r/--rev or -d/--date options, revert the given files or
5121 Using the -r/--rev or -d/--date options, revert the given files or
5120 directories to their states as of a specific revision. Because
5122 directories to their states as of a specific revision. Because
5121 revert does not change the working directory parents, this will
5123 revert does not change the working directory parents, this will
5122 cause these files to appear modified. This can be helpful to "back
5124 cause these files to appear modified. This can be helpful to "back
5123 out" some or all of an earlier change. See :hg:`backout` for a
5125 out" some or all of an earlier change. See :hg:`backout` for a
5124 related method.
5126 related method.
5125
5127
5126 Modified files are saved with a .orig suffix before reverting.
5128 Modified files are saved with a .orig suffix before reverting.
5127 To disable these backups, use --no-backup.
5129 To disable these backups, use --no-backup.
5128
5130
5129 See :hg:`help dates` for a list of formats valid for -d/--date.
5131 See :hg:`help dates` for a list of formats valid for -d/--date.
5130
5132
5131 Returns 0 on success.
5133 Returns 0 on success.
5132 """
5134 """
5133
5135
5134 if opts.get("date"):
5136 if opts.get("date"):
5135 if opts.get("rev"):
5137 if opts.get("rev"):
5136 raise util.Abort(_("you can't specify a revision and a date"))
5138 raise util.Abort(_("you can't specify a revision and a date"))
5137 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5139 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5138
5140
5139 parent, p2 = repo.dirstate.parents()
5141 parent, p2 = repo.dirstate.parents()
5140 if not opts.get('rev') and p2 != nullid:
5142 if not opts.get('rev') and p2 != nullid:
5141 # revert after merge is a trap for new users (issue2915)
5143 # revert after merge is a trap for new users (issue2915)
5142 raise util.Abort(_('uncommitted merge with no revision specified'),
5144 raise util.Abort(_('uncommitted merge with no revision specified'),
5143 hint=_('use "hg update" or see "hg help revert"'))
5145 hint=_('use "hg update" or see "hg help revert"'))
5144
5146
5145 ctx = scmutil.revsingle(repo, opts.get('rev'))
5147 ctx = scmutil.revsingle(repo, opts.get('rev'))
5146
5148
5147 if not pats and not opts.get('all'):
5149 if not pats and not opts.get('all'):
5148 msg = _("no files or directories specified")
5150 msg = _("no files or directories specified")
5149 if p2 != nullid:
5151 if p2 != nullid:
5150 hint = _("uncommitted merge, use --all to discard all changes,"
5152 hint = _("uncommitted merge, use --all to discard all changes,"
5151 " or 'hg update -C .' to abort the merge")
5153 " or 'hg update -C .' to abort the merge")
5152 raise util.Abort(msg, hint=hint)
5154 raise util.Abort(msg, hint=hint)
5153 dirty = util.any(repo.status())
5155 dirty = util.any(repo.status())
5154 node = ctx.node()
5156 node = ctx.node()
5155 if node != parent:
5157 if node != parent:
5156 if dirty:
5158 if dirty:
5157 hint = _("uncommitted changes, use --all to discard all"
5159 hint = _("uncommitted changes, use --all to discard all"
5158 " changes, or 'hg update %s' to update") % ctx.rev()
5160 " changes, or 'hg update %s' to update") % ctx.rev()
5159 else:
5161 else:
5160 hint = _("use --all to revert all files,"
5162 hint = _("use --all to revert all files,"
5161 " or 'hg update %s' to update") % ctx.rev()
5163 " or 'hg update %s' to update") % ctx.rev()
5162 elif dirty:
5164 elif dirty:
5163 hint = _("uncommitted changes, use --all to discard all changes")
5165 hint = _("uncommitted changes, use --all to discard all changes")
5164 else:
5166 else:
5165 hint = _("use --all to revert all files")
5167 hint = _("use --all to revert all files")
5166 raise util.Abort(msg, hint=hint)
5168 raise util.Abort(msg, hint=hint)
5167
5169
5168 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5170 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5169
5171
5170 @command('rollback', dryrunopts +
5172 @command('rollback', dryrunopts +
5171 [('f', 'force', False, _('ignore safety measures'))])
5173 [('f', 'force', False, _('ignore safety measures'))])
5172 def rollback(ui, repo, **opts):
5174 def rollback(ui, repo, **opts):
5173 """roll back the last transaction (dangerous)
5175 """roll back the last transaction (dangerous)
5174
5176
5175 This command should be used with care. There is only one level of
5177 This command should be used with care. There is only one level of
5176 rollback, and there is no way to undo a rollback. It will also
5178 rollback, and there is no way to undo a rollback. It will also
5177 restore the dirstate at the time of the last transaction, losing
5179 restore the dirstate at the time of the last transaction, losing
5178 any dirstate changes since that time. This command does not alter
5180 any dirstate changes since that time. This command does not alter
5179 the working directory.
5181 the working directory.
5180
5182
5181 Transactions are used to encapsulate the effects of all commands
5183 Transactions are used to encapsulate the effects of all commands
5182 that create new changesets or propagate existing changesets into a
5184 that create new changesets or propagate existing changesets into a
5183 repository.
5185 repository.
5184
5186
5185 .. container:: verbose
5187 .. container:: verbose
5186
5188
5187 For example, the following commands are transactional, and their
5189 For example, the following commands are transactional, and their
5188 effects can be rolled back:
5190 effects can be rolled back:
5189
5191
5190 - commit
5192 - commit
5191 - import
5193 - import
5192 - pull
5194 - pull
5193 - push (with this repository as the destination)
5195 - push (with this repository as the destination)
5194 - unbundle
5196 - unbundle
5195
5197
5196 To avoid permanent data loss, rollback will refuse to rollback a
5198 To avoid permanent data loss, rollback will refuse to rollback a
5197 commit transaction if it isn't checked out. Use --force to
5199 commit transaction if it isn't checked out. Use --force to
5198 override this protection.
5200 override this protection.
5199
5201
5200 This command is not intended for use on public repositories. Once
5202 This command is not intended for use on public repositories. Once
5201 changes are visible for pull by other users, rolling a transaction
5203 changes are visible for pull by other users, rolling a transaction
5202 back locally is ineffective (someone else may already have pulled
5204 back locally is ineffective (someone else may already have pulled
5203 the changes). Furthermore, a race is possible with readers of the
5205 the changes). Furthermore, a race is possible with readers of the
5204 repository; for example an in-progress pull from the repository
5206 repository; for example an in-progress pull from the repository
5205 may fail if a rollback is performed.
5207 may fail if a rollback is performed.
5206
5208
5207 Returns 0 on success, 1 if no rollback data is available.
5209 Returns 0 on success, 1 if no rollback data is available.
5208 """
5210 """
5209 return repo.rollback(dryrun=opts.get('dry_run'),
5211 return repo.rollback(dryrun=opts.get('dry_run'),
5210 force=opts.get('force'))
5212 force=opts.get('force'))
5211
5213
5212 @command('root', [])
5214 @command('root', [])
5213 def root(ui, repo):
5215 def root(ui, repo):
5214 """print the root (top) of the current working directory
5216 """print the root (top) of the current working directory
5215
5217
5216 Print the root directory of the current repository.
5218 Print the root directory of the current repository.
5217
5219
5218 Returns 0 on success.
5220 Returns 0 on success.
5219 """
5221 """
5220 ui.write(repo.root + "\n")
5222 ui.write(repo.root + "\n")
5221
5223
5222 @command('^serve',
5224 @command('^serve',
5223 [('A', 'accesslog', '', _('name of access log file to write to'),
5225 [('A', 'accesslog', '', _('name of access log file to write to'),
5224 _('FILE')),
5226 _('FILE')),
5225 ('d', 'daemon', None, _('run server in background')),
5227 ('d', 'daemon', None, _('run server in background')),
5226 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5228 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5227 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5229 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5228 # use string type, then we can check if something was passed
5230 # use string type, then we can check if something was passed
5229 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5231 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5230 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5232 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5231 _('ADDR')),
5233 _('ADDR')),
5232 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5234 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5233 _('PREFIX')),
5235 _('PREFIX')),
5234 ('n', 'name', '',
5236 ('n', 'name', '',
5235 _('name to show in web pages (default: working directory)'), _('NAME')),
5237 _('name to show in web pages (default: working directory)'), _('NAME')),
5236 ('', 'web-conf', '',
5238 ('', 'web-conf', '',
5237 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5239 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5238 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5240 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5239 _('FILE')),
5241 _('FILE')),
5240 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5242 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5241 ('', 'stdio', None, _('for remote clients')),
5243 ('', 'stdio', None, _('for remote clients')),
5242 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5244 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5243 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5245 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5244 ('', 'style', '', _('template style to use'), _('STYLE')),
5246 ('', 'style', '', _('template style to use'), _('STYLE')),
5245 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5247 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5246 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5248 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5247 _('[OPTION]...'))
5249 _('[OPTION]...'))
5248 def serve(ui, repo, **opts):
5250 def serve(ui, repo, **opts):
5249 """start stand-alone webserver
5251 """start stand-alone webserver
5250
5252
5251 Start a local HTTP repository browser and pull server. You can use
5253 Start a local HTTP repository browser and pull server. You can use
5252 this for ad-hoc sharing and browsing of repositories. It is
5254 this for ad-hoc sharing and browsing of repositories. It is
5253 recommended to use a real web server to serve a repository for
5255 recommended to use a real web server to serve a repository for
5254 longer periods of time.
5256 longer periods of time.
5255
5257
5256 Please note that the server does not implement access control.
5258 Please note that the server does not implement access control.
5257 This means that, by default, anybody can read from the server and
5259 This means that, by default, anybody can read from the server and
5258 nobody can write to it by default. Set the ``web.allow_push``
5260 nobody can write to it by default. Set the ``web.allow_push``
5259 option to ``*`` to allow everybody to push to the server. You
5261 option to ``*`` to allow everybody to push to the server. You
5260 should use a real web server if you need to authenticate users.
5262 should use a real web server if you need to authenticate users.
5261
5263
5262 By default, the server logs accesses to stdout and errors to
5264 By default, the server logs accesses to stdout and errors to
5263 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5265 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5264 files.
5266 files.
5265
5267
5266 To have the server choose a free port number to listen on, specify
5268 To have the server choose a free port number to listen on, specify
5267 a port number of 0; in this case, the server will print the port
5269 a port number of 0; in this case, the server will print the port
5268 number it uses.
5270 number it uses.
5269
5271
5270 Returns 0 on success.
5272 Returns 0 on success.
5271 """
5273 """
5272
5274
5273 if opts["stdio"] and opts["cmdserver"]:
5275 if opts["stdio"] and opts["cmdserver"]:
5274 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5276 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5275
5277
5276 def checkrepo():
5278 def checkrepo():
5277 if repo is None:
5279 if repo is None:
5278 raise error.RepoError(_("there is no Mercurial repository here"
5280 raise error.RepoError(_("there is no Mercurial repository here"
5279 " (.hg not found)"))
5281 " (.hg not found)"))
5280
5282
5281 if opts["stdio"]:
5283 if opts["stdio"]:
5282 checkrepo()
5284 checkrepo()
5283 s = sshserver.sshserver(ui, repo)
5285 s = sshserver.sshserver(ui, repo)
5284 s.serve_forever()
5286 s.serve_forever()
5285
5287
5286 if opts["cmdserver"]:
5288 if opts["cmdserver"]:
5287 checkrepo()
5289 checkrepo()
5288 s = commandserver.server(ui, repo, opts["cmdserver"])
5290 s = commandserver.server(ui, repo, opts["cmdserver"])
5289 return s.serve()
5291 return s.serve()
5290
5292
5291 # this way we can check if something was given in the command-line
5293 # this way we can check if something was given in the command-line
5292 if opts.get('port'):
5294 if opts.get('port'):
5293 opts['port'] = util.getport(opts.get('port'))
5295 opts['port'] = util.getport(opts.get('port'))
5294
5296
5295 baseui = repo and repo.baseui or ui
5297 baseui = repo and repo.baseui or ui
5296 optlist = ("name templates style address port prefix ipv6"
5298 optlist = ("name templates style address port prefix ipv6"
5297 " accesslog errorlog certificate encoding")
5299 " accesslog errorlog certificate encoding")
5298 for o in optlist.split():
5300 for o in optlist.split():
5299 val = opts.get(o, '')
5301 val = opts.get(o, '')
5300 if val in (None, ''): # should check against default options instead
5302 if val in (None, ''): # should check against default options instead
5301 continue
5303 continue
5302 baseui.setconfig("web", o, val)
5304 baseui.setconfig("web", o, val)
5303 if repo and repo.ui != baseui:
5305 if repo and repo.ui != baseui:
5304 repo.ui.setconfig("web", o, val)
5306 repo.ui.setconfig("web", o, val)
5305
5307
5306 o = opts.get('web_conf') or opts.get('webdir_conf')
5308 o = opts.get('web_conf') or opts.get('webdir_conf')
5307 if not o:
5309 if not o:
5308 if not repo:
5310 if not repo:
5309 raise error.RepoError(_("there is no Mercurial repository"
5311 raise error.RepoError(_("there is no Mercurial repository"
5310 " here (.hg not found)"))
5312 " here (.hg not found)"))
5311 o = repo.root
5313 o = repo.root
5312
5314
5313 app = hgweb.hgweb(o, baseui=ui)
5315 app = hgweb.hgweb(o, baseui=ui)
5314
5316
5315 class service(object):
5317 class service(object):
5316 def init(self):
5318 def init(self):
5317 util.setsignalhandler()
5319 util.setsignalhandler()
5318 self.httpd = hgweb.server.create_server(ui, app)
5320 self.httpd = hgweb.server.create_server(ui, app)
5319
5321
5320 if opts['port'] and not ui.verbose:
5322 if opts['port'] and not ui.verbose:
5321 return
5323 return
5322
5324
5323 if self.httpd.prefix:
5325 if self.httpd.prefix:
5324 prefix = self.httpd.prefix.strip('/') + '/'
5326 prefix = self.httpd.prefix.strip('/') + '/'
5325 else:
5327 else:
5326 prefix = ''
5328 prefix = ''
5327
5329
5328 port = ':%d' % self.httpd.port
5330 port = ':%d' % self.httpd.port
5329 if port == ':80':
5331 if port == ':80':
5330 port = ''
5332 port = ''
5331
5333
5332 bindaddr = self.httpd.addr
5334 bindaddr = self.httpd.addr
5333 if bindaddr == '0.0.0.0':
5335 if bindaddr == '0.0.0.0':
5334 bindaddr = '*'
5336 bindaddr = '*'
5335 elif ':' in bindaddr: # IPv6
5337 elif ':' in bindaddr: # IPv6
5336 bindaddr = '[%s]' % bindaddr
5338 bindaddr = '[%s]' % bindaddr
5337
5339
5338 fqaddr = self.httpd.fqaddr
5340 fqaddr = self.httpd.fqaddr
5339 if ':' in fqaddr:
5341 if ':' in fqaddr:
5340 fqaddr = '[%s]' % fqaddr
5342 fqaddr = '[%s]' % fqaddr
5341 if opts['port']:
5343 if opts['port']:
5342 write = ui.status
5344 write = ui.status
5343 else:
5345 else:
5344 write = ui.write
5346 write = ui.write
5345 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5347 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5346 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5348 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5347
5349
5348 def run(self):
5350 def run(self):
5349 self.httpd.serve_forever()
5351 self.httpd.serve_forever()
5350
5352
5351 service = service()
5353 service = service()
5352
5354
5353 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5355 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5354
5356
5355 @command('showconfig|debugconfig',
5357 @command('showconfig|debugconfig',
5356 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5358 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5357 _('[-u] [NAME]...'))
5359 _('[-u] [NAME]...'))
5358 def showconfig(ui, repo, *values, **opts):
5360 def showconfig(ui, repo, *values, **opts):
5359 """show combined config settings from all hgrc files
5361 """show combined config settings from all hgrc files
5360
5362
5361 With no arguments, print names and values of all config items.
5363 With no arguments, print names and values of all config items.
5362
5364
5363 With one argument of the form section.name, print just the value
5365 With one argument of the form section.name, print just the value
5364 of that config item.
5366 of that config item.
5365
5367
5366 With multiple arguments, print names and values of all config
5368 With multiple arguments, print names and values of all config
5367 items with matching section names.
5369 items with matching section names.
5368
5370
5369 With --debug, the source (filename and line number) is printed
5371 With --debug, the source (filename and line number) is printed
5370 for each config item.
5372 for each config item.
5371
5373
5372 Returns 0 on success.
5374 Returns 0 on success.
5373 """
5375 """
5374
5376
5375 for f in scmutil.rcpath():
5377 for f in scmutil.rcpath():
5376 ui.debug('read config from: %s\n' % f)
5378 ui.debug('read config from: %s\n' % f)
5377 untrusted = bool(opts.get('untrusted'))
5379 untrusted = bool(opts.get('untrusted'))
5378 if values:
5380 if values:
5379 sections = [v for v in values if '.' not in v]
5381 sections = [v for v in values if '.' not in v]
5380 items = [v for v in values if '.' in v]
5382 items = [v for v in values if '.' in v]
5381 if len(items) > 1 or items and sections:
5383 if len(items) > 1 or items and sections:
5382 raise util.Abort(_('only one config item permitted'))
5384 raise util.Abort(_('only one config item permitted'))
5383 for section, name, value in ui.walkconfig(untrusted=untrusted):
5385 for section, name, value in ui.walkconfig(untrusted=untrusted):
5384 value = str(value).replace('\n', '\\n')
5386 value = str(value).replace('\n', '\\n')
5385 sectname = section + '.' + name
5387 sectname = section + '.' + name
5386 if values:
5388 if values:
5387 for v in values:
5389 for v in values:
5388 if v == section:
5390 if v == section:
5389 ui.debug('%s: ' %
5391 ui.debug('%s: ' %
5390 ui.configsource(section, name, untrusted))
5392 ui.configsource(section, name, untrusted))
5391 ui.write('%s=%s\n' % (sectname, value))
5393 ui.write('%s=%s\n' % (sectname, value))
5392 elif v == sectname:
5394 elif v == sectname:
5393 ui.debug('%s: ' %
5395 ui.debug('%s: ' %
5394 ui.configsource(section, name, untrusted))
5396 ui.configsource(section, name, untrusted))
5395 ui.write(value, '\n')
5397 ui.write(value, '\n')
5396 else:
5398 else:
5397 ui.debug('%s: ' %
5399 ui.debug('%s: ' %
5398 ui.configsource(section, name, untrusted))
5400 ui.configsource(section, name, untrusted))
5399 ui.write('%s=%s\n' % (sectname, value))
5401 ui.write('%s=%s\n' % (sectname, value))
5400
5402
5401 @command('^status|st',
5403 @command('^status|st',
5402 [('A', 'all', None, _('show status of all files')),
5404 [('A', 'all', None, _('show status of all files')),
5403 ('m', 'modified', None, _('show only modified files')),
5405 ('m', 'modified', None, _('show only modified files')),
5404 ('a', 'added', None, _('show only added files')),
5406 ('a', 'added', None, _('show only added files')),
5405 ('r', 'removed', None, _('show only removed files')),
5407 ('r', 'removed', None, _('show only removed files')),
5406 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5408 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5407 ('c', 'clean', None, _('show only files without changes')),
5409 ('c', 'clean', None, _('show only files without changes')),
5408 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5410 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5409 ('i', 'ignored', None, _('show only ignored files')),
5411 ('i', 'ignored', None, _('show only ignored files')),
5410 ('n', 'no-status', None, _('hide status prefix')),
5412 ('n', 'no-status', None, _('hide status prefix')),
5411 ('C', 'copies', None, _('show source of copied files')),
5413 ('C', 'copies', None, _('show source of copied files')),
5412 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5414 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5413 ('', 'rev', [], _('show difference from revision'), _('REV')),
5415 ('', 'rev', [], _('show difference from revision'), _('REV')),
5414 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5416 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5415 ] + walkopts + subrepoopts,
5417 ] + walkopts + subrepoopts,
5416 _('[OPTION]... [FILE]...'))
5418 _('[OPTION]... [FILE]...'))
5417 def status(ui, repo, *pats, **opts):
5419 def status(ui, repo, *pats, **opts):
5418 """show changed files in the working directory
5420 """show changed files in the working directory
5419
5421
5420 Show status of files in the repository. If names are given, only
5422 Show status of files in the repository. If names are given, only
5421 files that match are shown. Files that are clean or ignored or
5423 files that match are shown. Files that are clean or ignored or
5422 the source of a copy/move operation, are not listed unless
5424 the source of a copy/move operation, are not listed unless
5423 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5425 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5424 Unless options described with "show only ..." are given, the
5426 Unless options described with "show only ..." are given, the
5425 options -mardu are used.
5427 options -mardu are used.
5426
5428
5427 Option -q/--quiet hides untracked (unknown and ignored) files
5429 Option -q/--quiet hides untracked (unknown and ignored) files
5428 unless explicitly requested with -u/--unknown or -i/--ignored.
5430 unless explicitly requested with -u/--unknown or -i/--ignored.
5429
5431
5430 .. note::
5432 .. note::
5431 status may appear to disagree with diff if permissions have
5433 status may appear to disagree with diff if permissions have
5432 changed or a merge has occurred. The standard diff format does
5434 changed or a merge has occurred. The standard diff format does
5433 not report permission changes and diff only reports changes
5435 not report permission changes and diff only reports changes
5434 relative to one merge parent.
5436 relative to one merge parent.
5435
5437
5436 If one revision is given, it is used as the base revision.
5438 If one revision is given, it is used as the base revision.
5437 If two revisions are given, the differences between them are
5439 If two revisions are given, the differences between them are
5438 shown. The --change option can also be used as a shortcut to list
5440 shown. The --change option can also be used as a shortcut to list
5439 the changed files of a revision from its first parent.
5441 the changed files of a revision from its first parent.
5440
5442
5441 The codes used to show the status of files are::
5443 The codes used to show the status of files are::
5442
5444
5443 M = modified
5445 M = modified
5444 A = added
5446 A = added
5445 R = removed
5447 R = removed
5446 C = clean
5448 C = clean
5447 ! = missing (deleted by non-hg command, but still tracked)
5449 ! = missing (deleted by non-hg command, but still tracked)
5448 ? = not tracked
5450 ? = not tracked
5449 I = ignored
5451 I = ignored
5450 = origin of the previous file listed as A (added)
5452 = origin of the previous file listed as A (added)
5451
5453
5452 .. container:: verbose
5454 .. container:: verbose
5453
5455
5454 Examples:
5456 Examples:
5455
5457
5456 - show changes in the working directory relative to a
5458 - show changes in the working directory relative to a
5457 changeset::
5459 changeset::
5458
5460
5459 hg status --rev 9353
5461 hg status --rev 9353
5460
5462
5461 - show all changes including copies in an existing changeset::
5463 - show all changes including copies in an existing changeset::
5462
5464
5463 hg status --copies --change 9353
5465 hg status --copies --change 9353
5464
5466
5465 - get a NUL separated list of added files, suitable for xargs::
5467 - get a NUL separated list of added files, suitable for xargs::
5466
5468
5467 hg status -an0
5469 hg status -an0
5468
5470
5469 Returns 0 on success.
5471 Returns 0 on success.
5470 """
5472 """
5471
5473
5472 revs = opts.get('rev')
5474 revs = opts.get('rev')
5473 change = opts.get('change')
5475 change = opts.get('change')
5474
5476
5475 if revs and change:
5477 if revs and change:
5476 msg = _('cannot specify --rev and --change at the same time')
5478 msg = _('cannot specify --rev and --change at the same time')
5477 raise util.Abort(msg)
5479 raise util.Abort(msg)
5478 elif change:
5480 elif change:
5479 node2 = scmutil.revsingle(repo, change, None).node()
5481 node2 = scmutil.revsingle(repo, change, None).node()
5480 node1 = repo[node2].p1().node()
5482 node1 = repo[node2].p1().node()
5481 else:
5483 else:
5482 node1, node2 = scmutil.revpair(repo, revs)
5484 node1, node2 = scmutil.revpair(repo, revs)
5483
5485
5484 cwd = (pats and repo.getcwd()) or ''
5486 cwd = (pats and repo.getcwd()) or ''
5485 end = opts.get('print0') and '\0' or '\n'
5487 end = opts.get('print0') and '\0' or '\n'
5486 copy = {}
5488 copy = {}
5487 states = 'modified added removed deleted unknown ignored clean'.split()
5489 states = 'modified added removed deleted unknown ignored clean'.split()
5488 show = [k for k in states if opts.get(k)]
5490 show = [k for k in states if opts.get(k)]
5489 if opts.get('all'):
5491 if opts.get('all'):
5490 show += ui.quiet and (states[:4] + ['clean']) or states
5492 show += ui.quiet and (states[:4] + ['clean']) or states
5491 if not show:
5493 if not show:
5492 show = ui.quiet and states[:4] or states[:5]
5494 show = ui.quiet and states[:4] or states[:5]
5493
5495
5494 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5496 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5495 'ignored' in show, 'clean' in show, 'unknown' in show,
5497 'ignored' in show, 'clean' in show, 'unknown' in show,
5496 opts.get('subrepos'))
5498 opts.get('subrepos'))
5497 changestates = zip(states, 'MAR!?IC', stat)
5499 changestates = zip(states, 'MAR!?IC', stat)
5498
5500
5499 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5501 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5500 copy = copies.pathcopies(repo[node1], repo[node2])
5502 copy = copies.pathcopies(repo[node1], repo[node2])
5501
5503
5502 fm = ui.formatter('status', opts)
5504 fm = ui.formatter('status', opts)
5503 fmt = '%s' + end
5505 fmt = '%s' + end
5504 showchar = not opts.get('no_status')
5506 showchar = not opts.get('no_status')
5505
5507
5506 for state, char, files in changestates:
5508 for state, char, files in changestates:
5507 if state in show:
5509 if state in show:
5508 label = 'status.' + state
5510 label = 'status.' + state
5509 for f in files:
5511 for f in files:
5510 fm.startitem()
5512 fm.startitem()
5511 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5513 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5512 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5514 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5513 if f in copy:
5515 if f in copy:
5514 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5516 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5515 label='status.copied')
5517 label='status.copied')
5516 fm.end()
5518 fm.end()
5517
5519
5518 @command('^summary|sum',
5520 @command('^summary|sum',
5519 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5521 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5520 def summary(ui, repo, **opts):
5522 def summary(ui, repo, **opts):
5521 """summarize working directory state
5523 """summarize working directory state
5522
5524
5523 This generates a brief summary of the working directory state,
5525 This generates a brief summary of the working directory state,
5524 including parents, branch, commit status, and available updates.
5526 including parents, branch, commit status, and available updates.
5525
5527
5526 With the --remote option, this will check the default paths for
5528 With the --remote option, this will check the default paths for
5527 incoming and outgoing changes. This can be time-consuming.
5529 incoming and outgoing changes. This can be time-consuming.
5528
5530
5529 Returns 0 on success.
5531 Returns 0 on success.
5530 """
5532 """
5531
5533
5532 ctx = repo[None]
5534 ctx = repo[None]
5533 parents = ctx.parents()
5535 parents = ctx.parents()
5534 pnode = parents[0].node()
5536 pnode = parents[0].node()
5535 marks = []
5537 marks = []
5536
5538
5537 for p in parents:
5539 for p in parents:
5538 # label with log.changeset (instead of log.parent) since this
5540 # label with log.changeset (instead of log.parent) since this
5539 # shows a working directory parent *changeset*:
5541 # shows a working directory parent *changeset*:
5540 # i18n: column positioning for "hg summary"
5542 # i18n: column positioning for "hg summary"
5541 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5543 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5542 label='log.changeset changeset.%s' % p.phasestr())
5544 label='log.changeset changeset.%s' % p.phasestr())
5543 ui.write(' '.join(p.tags()), label='log.tag')
5545 ui.write(' '.join(p.tags()), label='log.tag')
5544 if p.bookmarks():
5546 if p.bookmarks():
5545 marks.extend(p.bookmarks())
5547 marks.extend(p.bookmarks())
5546 if p.rev() == -1:
5548 if p.rev() == -1:
5547 if not len(repo):
5549 if not len(repo):
5548 ui.write(_(' (empty repository)'))
5550 ui.write(_(' (empty repository)'))
5549 else:
5551 else:
5550 ui.write(_(' (no revision checked out)'))
5552 ui.write(_(' (no revision checked out)'))
5551 ui.write('\n')
5553 ui.write('\n')
5552 if p.description():
5554 if p.description():
5553 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5555 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5554 label='log.summary')
5556 label='log.summary')
5555
5557
5556 branch = ctx.branch()
5558 branch = ctx.branch()
5557 bheads = repo.branchheads(branch)
5559 bheads = repo.branchheads(branch)
5558 # i18n: column positioning for "hg summary"
5560 # i18n: column positioning for "hg summary"
5559 m = _('branch: %s\n') % branch
5561 m = _('branch: %s\n') % branch
5560 if branch != 'default':
5562 if branch != 'default':
5561 ui.write(m, label='log.branch')
5563 ui.write(m, label='log.branch')
5562 else:
5564 else:
5563 ui.status(m, label='log.branch')
5565 ui.status(m, label='log.branch')
5564
5566
5565 if marks:
5567 if marks:
5566 current = repo._bookmarkcurrent
5568 current = repo._bookmarkcurrent
5567 # i18n: column positioning for "hg summary"
5569 # i18n: column positioning for "hg summary"
5568 ui.write(_('bookmarks:'), label='log.bookmark')
5570 ui.write(_('bookmarks:'), label='log.bookmark')
5569 if current is not None:
5571 if current is not None:
5570 try:
5572 try:
5571 marks.remove(current)
5573 marks.remove(current)
5572 ui.write(' *' + current, label='bookmarks.current')
5574 ui.write(' *' + current, label='bookmarks.current')
5573 except ValueError:
5575 except ValueError:
5574 # current bookmark not in parent ctx marks
5576 # current bookmark not in parent ctx marks
5575 pass
5577 pass
5576 for m in marks:
5578 for m in marks:
5577 ui.write(' ' + m, label='log.bookmark')
5579 ui.write(' ' + m, label='log.bookmark')
5578 ui.write('\n', label='log.bookmark')
5580 ui.write('\n', label='log.bookmark')
5579
5581
5580 st = list(repo.status(unknown=True))[:6]
5582 st = list(repo.status(unknown=True))[:6]
5581
5583
5582 c = repo.dirstate.copies()
5584 c = repo.dirstate.copies()
5583 copied, renamed = [], []
5585 copied, renamed = [], []
5584 for d, s in c.iteritems():
5586 for d, s in c.iteritems():
5585 if s in st[2]:
5587 if s in st[2]:
5586 st[2].remove(s)
5588 st[2].remove(s)
5587 renamed.append(d)
5589 renamed.append(d)
5588 else:
5590 else:
5589 copied.append(d)
5591 copied.append(d)
5590 if d in st[1]:
5592 if d in st[1]:
5591 st[1].remove(d)
5593 st[1].remove(d)
5592 st.insert(3, renamed)
5594 st.insert(3, renamed)
5593 st.insert(4, copied)
5595 st.insert(4, copied)
5594
5596
5595 ms = mergemod.mergestate(repo)
5597 ms = mergemod.mergestate(repo)
5596 st.append([f for f in ms if ms[f] == 'u'])
5598 st.append([f for f in ms if ms[f] == 'u'])
5597
5599
5598 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5600 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5599 st.append(subs)
5601 st.append(subs)
5600
5602
5601 labels = [ui.label(_('%d modified'), 'status.modified'),
5603 labels = [ui.label(_('%d modified'), 'status.modified'),
5602 ui.label(_('%d added'), 'status.added'),
5604 ui.label(_('%d added'), 'status.added'),
5603 ui.label(_('%d removed'), 'status.removed'),
5605 ui.label(_('%d removed'), 'status.removed'),
5604 ui.label(_('%d renamed'), 'status.copied'),
5606 ui.label(_('%d renamed'), 'status.copied'),
5605 ui.label(_('%d copied'), 'status.copied'),
5607 ui.label(_('%d copied'), 'status.copied'),
5606 ui.label(_('%d deleted'), 'status.deleted'),
5608 ui.label(_('%d deleted'), 'status.deleted'),
5607 ui.label(_('%d unknown'), 'status.unknown'),
5609 ui.label(_('%d unknown'), 'status.unknown'),
5608 ui.label(_('%d ignored'), 'status.ignored'),
5610 ui.label(_('%d ignored'), 'status.ignored'),
5609 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5611 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5610 ui.label(_('%d subrepos'), 'status.modified')]
5612 ui.label(_('%d subrepos'), 'status.modified')]
5611 t = []
5613 t = []
5612 for s, l in zip(st, labels):
5614 for s, l in zip(st, labels):
5613 if s:
5615 if s:
5614 t.append(l % len(s))
5616 t.append(l % len(s))
5615
5617
5616 t = ', '.join(t)
5618 t = ', '.join(t)
5617 cleanworkdir = False
5619 cleanworkdir = False
5618
5620
5619 if len(parents) > 1:
5621 if len(parents) > 1:
5620 t += _(' (merge)')
5622 t += _(' (merge)')
5621 elif branch != parents[0].branch():
5623 elif branch != parents[0].branch():
5622 t += _(' (new branch)')
5624 t += _(' (new branch)')
5623 elif (parents[0].closesbranch() and
5625 elif (parents[0].closesbranch() and
5624 pnode in repo.branchheads(branch, closed=True)):
5626 pnode in repo.branchheads(branch, closed=True)):
5625 t += _(' (head closed)')
5627 t += _(' (head closed)')
5626 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5628 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5627 t += _(' (clean)')
5629 t += _(' (clean)')
5628 cleanworkdir = True
5630 cleanworkdir = True
5629 elif pnode not in bheads:
5631 elif pnode not in bheads:
5630 t += _(' (new branch head)')
5632 t += _(' (new branch head)')
5631
5633
5632 if cleanworkdir:
5634 if cleanworkdir:
5633 # i18n: column positioning for "hg summary"
5635 # i18n: column positioning for "hg summary"
5634 ui.status(_('commit: %s\n') % t.strip())
5636 ui.status(_('commit: %s\n') % t.strip())
5635 else:
5637 else:
5636 # i18n: column positioning for "hg summary"
5638 # i18n: column positioning for "hg summary"
5637 ui.write(_('commit: %s\n') % t.strip())
5639 ui.write(_('commit: %s\n') % t.strip())
5638
5640
5639 # all ancestors of branch heads - all ancestors of parent = new csets
5641 # all ancestors of branch heads - all ancestors of parent = new csets
5640 new = [0] * len(repo)
5642 new = [0] * len(repo)
5641 cl = repo.changelog
5643 cl = repo.changelog
5642 for a in [cl.rev(n) for n in bheads]:
5644 for a in [cl.rev(n) for n in bheads]:
5643 new[a] = 1
5645 new[a] = 1
5644 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5646 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5645 new[a] = 1
5647 new[a] = 1
5646 for a in [p.rev() for p in parents]:
5648 for a in [p.rev() for p in parents]:
5647 if a >= 0:
5649 if a >= 0:
5648 new[a] = 0
5650 new[a] = 0
5649 for a in cl.ancestors([p.rev() for p in parents]):
5651 for a in cl.ancestors([p.rev() for p in parents]):
5650 new[a] = 0
5652 new[a] = 0
5651 new = sum(new)
5653 new = sum(new)
5652
5654
5653 if new == 0:
5655 if new == 0:
5654 # i18n: column positioning for "hg summary"
5656 # i18n: column positioning for "hg summary"
5655 ui.status(_('update: (current)\n'))
5657 ui.status(_('update: (current)\n'))
5656 elif pnode not in bheads:
5658 elif pnode not in bheads:
5657 # i18n: column positioning for "hg summary"
5659 # i18n: column positioning for "hg summary"
5658 ui.write(_('update: %d new changesets (update)\n') % new)
5660 ui.write(_('update: %d new changesets (update)\n') % new)
5659 else:
5661 else:
5660 # i18n: column positioning for "hg summary"
5662 # i18n: column positioning for "hg summary"
5661 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5663 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5662 (new, len(bheads)))
5664 (new, len(bheads)))
5663
5665
5664 if opts.get('remote'):
5666 if opts.get('remote'):
5665 t = []
5667 t = []
5666 source, branches = hg.parseurl(ui.expandpath('default'))
5668 source, branches = hg.parseurl(ui.expandpath('default'))
5667 other = hg.peer(repo, {}, source)
5669 other = hg.peer(repo, {}, source)
5668 revs, checkout = hg.addbranchrevs(repo, other, branches,
5670 revs, checkout = hg.addbranchrevs(repo, other, branches,
5669 opts.get('rev'))
5671 opts.get('rev'))
5670 ui.debug('comparing with %s\n' % util.hidepassword(source))
5672 ui.debug('comparing with %s\n' % util.hidepassword(source))
5671 repo.ui.pushbuffer()
5673 repo.ui.pushbuffer()
5672 commoninc = discovery.findcommonincoming(repo, other)
5674 commoninc = discovery.findcommonincoming(repo, other)
5673 _common, incoming, _rheads = commoninc
5675 _common, incoming, _rheads = commoninc
5674 repo.ui.popbuffer()
5676 repo.ui.popbuffer()
5675 if incoming:
5677 if incoming:
5676 t.append(_('1 or more incoming'))
5678 t.append(_('1 or more incoming'))
5677
5679
5678 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5680 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5679 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5681 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5680 if source != dest:
5682 if source != dest:
5681 other = hg.peer(repo, {}, dest)
5683 other = hg.peer(repo, {}, dest)
5682 commoninc = None
5684 commoninc = None
5683 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5685 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5684 repo.ui.pushbuffer()
5686 repo.ui.pushbuffer()
5685 outgoing = discovery.findcommonoutgoing(repo, other,
5687 outgoing = discovery.findcommonoutgoing(repo, other,
5686 commoninc=commoninc)
5688 commoninc=commoninc)
5687 repo.ui.popbuffer()
5689 repo.ui.popbuffer()
5688 o = outgoing.missing
5690 o = outgoing.missing
5689 if o:
5691 if o:
5690 t.append(_('%d outgoing') % len(o))
5692 t.append(_('%d outgoing') % len(o))
5691 if 'bookmarks' in other.listkeys('namespaces'):
5693 if 'bookmarks' in other.listkeys('namespaces'):
5692 lmarks = repo.listkeys('bookmarks')
5694 lmarks = repo.listkeys('bookmarks')
5693 rmarks = other.listkeys('bookmarks')
5695 rmarks = other.listkeys('bookmarks')
5694 diff = set(rmarks) - set(lmarks)
5696 diff = set(rmarks) - set(lmarks)
5695 if len(diff) > 0:
5697 if len(diff) > 0:
5696 t.append(_('%d incoming bookmarks') % len(diff))
5698 t.append(_('%d incoming bookmarks') % len(diff))
5697 diff = set(lmarks) - set(rmarks)
5699 diff = set(lmarks) - set(rmarks)
5698 if len(diff) > 0:
5700 if len(diff) > 0:
5699 t.append(_('%d outgoing bookmarks') % len(diff))
5701 t.append(_('%d outgoing bookmarks') % len(diff))
5700
5702
5701 if t:
5703 if t:
5702 # i18n: column positioning for "hg summary"
5704 # i18n: column positioning for "hg summary"
5703 ui.write(_('remote: %s\n') % (', '.join(t)))
5705 ui.write(_('remote: %s\n') % (', '.join(t)))
5704 else:
5706 else:
5705 # i18n: column positioning for "hg summary"
5707 # i18n: column positioning for "hg summary"
5706 ui.status(_('remote: (synced)\n'))
5708 ui.status(_('remote: (synced)\n'))
5707
5709
5708 @command('tag',
5710 @command('tag',
5709 [('f', 'force', None, _('force tag')),
5711 [('f', 'force', None, _('force tag')),
5710 ('l', 'local', None, _('make the tag local')),
5712 ('l', 'local', None, _('make the tag local')),
5711 ('r', 'rev', '', _('revision to tag'), _('REV')),
5713 ('r', 'rev', '', _('revision to tag'), _('REV')),
5712 ('', 'remove', None, _('remove a tag')),
5714 ('', 'remove', None, _('remove a tag')),
5713 # -l/--local is already there, commitopts cannot be used
5715 # -l/--local is already there, commitopts cannot be used
5714 ('e', 'edit', None, _('edit commit message')),
5716 ('e', 'edit', None, _('edit commit message')),
5715 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5717 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5716 ] + commitopts2,
5718 ] + commitopts2,
5717 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5719 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5718 def tag(ui, repo, name1, *names, **opts):
5720 def tag(ui, repo, name1, *names, **opts):
5719 """add one or more tags for the current or given revision
5721 """add one or more tags for the current or given revision
5720
5722
5721 Name a particular revision using <name>.
5723 Name a particular revision using <name>.
5722
5724
5723 Tags are used to name particular revisions of the repository and are
5725 Tags are used to name particular revisions of the repository and are
5724 very useful to compare different revisions, to go back to significant
5726 very useful to compare different revisions, to go back to significant
5725 earlier versions or to mark branch points as releases, etc. Changing
5727 earlier versions or to mark branch points as releases, etc. Changing
5726 an existing tag is normally disallowed; use -f/--force to override.
5728 an existing tag is normally disallowed; use -f/--force to override.
5727
5729
5728 If no revision is given, the parent of the working directory is
5730 If no revision is given, the parent of the working directory is
5729 used, or tip if no revision is checked out.
5731 used, or tip if no revision is checked out.
5730
5732
5731 To facilitate version control, distribution, and merging of tags,
5733 To facilitate version control, distribution, and merging of tags,
5732 they are stored as a file named ".hgtags" which is managed similarly
5734 they are stored as a file named ".hgtags" which is managed similarly
5733 to other project files and can be hand-edited if necessary. This
5735 to other project files and can be hand-edited if necessary. This
5734 also means that tagging creates a new commit. The file
5736 also means that tagging creates a new commit. The file
5735 ".hg/localtags" is used for local tags (not shared among
5737 ".hg/localtags" is used for local tags (not shared among
5736 repositories).
5738 repositories).
5737
5739
5738 Tag commits are usually made at the head of a branch. If the parent
5740 Tag commits are usually made at the head of a branch. If the parent
5739 of the working directory is not a branch head, :hg:`tag` aborts; use
5741 of the working directory is not a branch head, :hg:`tag` aborts; use
5740 -f/--force to force the tag commit to be based on a non-head
5742 -f/--force to force the tag commit to be based on a non-head
5741 changeset.
5743 changeset.
5742
5744
5743 See :hg:`help dates` for a list of formats valid for -d/--date.
5745 See :hg:`help dates` for a list of formats valid for -d/--date.
5744
5746
5745 Since tag names have priority over branch names during revision
5747 Since tag names have priority over branch names during revision
5746 lookup, using an existing branch name as a tag name is discouraged.
5748 lookup, using an existing branch name as a tag name is discouraged.
5747
5749
5748 Returns 0 on success.
5750 Returns 0 on success.
5749 """
5751 """
5750 wlock = lock = None
5752 wlock = lock = None
5751 try:
5753 try:
5752 wlock = repo.wlock()
5754 wlock = repo.wlock()
5753 lock = repo.lock()
5755 lock = repo.lock()
5754 rev_ = "."
5756 rev_ = "."
5755 names = [t.strip() for t in (name1,) + names]
5757 names = [t.strip() for t in (name1,) + names]
5756 if len(names) != len(set(names)):
5758 if len(names) != len(set(names)):
5757 raise util.Abort(_('tag names must be unique'))
5759 raise util.Abort(_('tag names must be unique'))
5758 for n in names:
5760 for n in names:
5759 scmutil.checknewlabel(repo, n, 'tag')
5761 scmutil.checknewlabel(repo, n, 'tag')
5760 if not n:
5762 if not n:
5761 raise util.Abort(_('tag names cannot consist entirely of '
5763 raise util.Abort(_('tag names cannot consist entirely of '
5762 'whitespace'))
5764 'whitespace'))
5763 if opts.get('rev') and opts.get('remove'):
5765 if opts.get('rev') and opts.get('remove'):
5764 raise util.Abort(_("--rev and --remove are incompatible"))
5766 raise util.Abort(_("--rev and --remove are incompatible"))
5765 if opts.get('rev'):
5767 if opts.get('rev'):
5766 rev_ = opts['rev']
5768 rev_ = opts['rev']
5767 message = opts.get('message')
5769 message = opts.get('message')
5768 if opts.get('remove'):
5770 if opts.get('remove'):
5769 expectedtype = opts.get('local') and 'local' or 'global'
5771 expectedtype = opts.get('local') and 'local' or 'global'
5770 for n in names:
5772 for n in names:
5771 if not repo.tagtype(n):
5773 if not repo.tagtype(n):
5772 raise util.Abort(_("tag '%s' does not exist") % n)
5774 raise util.Abort(_("tag '%s' does not exist") % n)
5773 if repo.tagtype(n) != expectedtype:
5775 if repo.tagtype(n) != expectedtype:
5774 if expectedtype == 'global':
5776 if expectedtype == 'global':
5775 raise util.Abort(_("tag '%s' is not a global tag") % n)
5777 raise util.Abort(_("tag '%s' is not a global tag") % n)
5776 else:
5778 else:
5777 raise util.Abort(_("tag '%s' is not a local tag") % n)
5779 raise util.Abort(_("tag '%s' is not a local tag") % n)
5778 rev_ = nullid
5780 rev_ = nullid
5779 if not message:
5781 if not message:
5780 # we don't translate commit messages
5782 # we don't translate commit messages
5781 message = 'Removed tag %s' % ', '.join(names)
5783 message = 'Removed tag %s' % ', '.join(names)
5782 elif not opts.get('force'):
5784 elif not opts.get('force'):
5783 for n in names:
5785 for n in names:
5784 if n in repo.tags():
5786 if n in repo.tags():
5785 raise util.Abort(_("tag '%s' already exists "
5787 raise util.Abort(_("tag '%s' already exists "
5786 "(use -f to force)") % n)
5788 "(use -f to force)") % n)
5787 if not opts.get('local'):
5789 if not opts.get('local'):
5788 p1, p2 = repo.dirstate.parents()
5790 p1, p2 = repo.dirstate.parents()
5789 if p2 != nullid:
5791 if p2 != nullid:
5790 raise util.Abort(_('uncommitted merge'))
5792 raise util.Abort(_('uncommitted merge'))
5791 bheads = repo.branchheads()
5793 bheads = repo.branchheads()
5792 if not opts.get('force') and bheads and p1 not in bheads:
5794 if not opts.get('force') and bheads and p1 not in bheads:
5793 raise util.Abort(_('not at a branch head (use -f to force)'))
5795 raise util.Abort(_('not at a branch head (use -f to force)'))
5794 r = scmutil.revsingle(repo, rev_).node()
5796 r = scmutil.revsingle(repo, rev_).node()
5795
5797
5796 if not message:
5798 if not message:
5797 # we don't translate commit messages
5799 # we don't translate commit messages
5798 message = ('Added tag %s for changeset %s' %
5800 message = ('Added tag %s for changeset %s' %
5799 (', '.join(names), short(r)))
5801 (', '.join(names), short(r)))
5800
5802
5801 date = opts.get('date')
5803 date = opts.get('date')
5802 if date:
5804 if date:
5803 date = util.parsedate(date)
5805 date = util.parsedate(date)
5804
5806
5805 if opts.get('edit'):
5807 if opts.get('edit'):
5806 message = ui.edit(message, ui.username())
5808 message = ui.edit(message, ui.username())
5807
5809
5808 # don't allow tagging the null rev
5810 # don't allow tagging the null rev
5809 if (not opts.get('remove') and
5811 if (not opts.get('remove') and
5810 scmutil.revsingle(repo, rev_).rev() == nullrev):
5812 scmutil.revsingle(repo, rev_).rev() == nullrev):
5811 raise util.Abort(_("null revision specified"))
5813 raise util.Abort(_("null revision specified"))
5812
5814
5813 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5815 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5814 finally:
5816 finally:
5815 release(lock, wlock)
5817 release(lock, wlock)
5816
5818
5817 @command('tags', [], '')
5819 @command('tags', [], '')
5818 def tags(ui, repo, **opts):
5820 def tags(ui, repo, **opts):
5819 """list repository tags
5821 """list repository tags
5820
5822
5821 This lists both regular and local tags. When the -v/--verbose
5823 This lists both regular and local tags. When the -v/--verbose
5822 switch is used, a third column "local" is printed for local tags.
5824 switch is used, a third column "local" is printed for local tags.
5823
5825
5824 Returns 0 on success.
5826 Returns 0 on success.
5825 """
5827 """
5826
5828
5827 fm = ui.formatter('tags', opts)
5829 fm = ui.formatter('tags', opts)
5828 hexfunc = ui.debugflag and hex or short
5830 hexfunc = ui.debugflag and hex or short
5829 tagtype = ""
5831 tagtype = ""
5830
5832
5831 for t, n in reversed(repo.tagslist()):
5833 for t, n in reversed(repo.tagslist()):
5832 hn = hexfunc(n)
5834 hn = hexfunc(n)
5833 label = 'tags.normal'
5835 label = 'tags.normal'
5834 tagtype = ''
5836 tagtype = ''
5835 if repo.tagtype(t) == 'local':
5837 if repo.tagtype(t) == 'local':
5836 label = 'tags.local'
5838 label = 'tags.local'
5837 tagtype = 'local'
5839 tagtype = 'local'
5838
5840
5839 fm.startitem()
5841 fm.startitem()
5840 fm.write('tag', '%s', t, label=label)
5842 fm.write('tag', '%s', t, label=label)
5841 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5843 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5842 fm.condwrite(not ui.quiet, 'rev id', fmt,
5844 fm.condwrite(not ui.quiet, 'rev id', fmt,
5843 repo.changelog.rev(n), hn, label=label)
5845 repo.changelog.rev(n), hn, label=label)
5844 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5846 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5845 tagtype, label=label)
5847 tagtype, label=label)
5846 fm.plain('\n')
5848 fm.plain('\n')
5847 fm.end()
5849 fm.end()
5848
5850
5849 @command('tip',
5851 @command('tip',
5850 [('p', 'patch', None, _('show patch')),
5852 [('p', 'patch', None, _('show patch')),
5851 ('g', 'git', None, _('use git extended diff format')),
5853 ('g', 'git', None, _('use git extended diff format')),
5852 ] + templateopts,
5854 ] + templateopts,
5853 _('[-p] [-g]'))
5855 _('[-p] [-g]'))
5854 def tip(ui, repo, **opts):
5856 def tip(ui, repo, **opts):
5855 """show the tip revision
5857 """show the tip revision
5856
5858
5857 The tip revision (usually just called the tip) is the changeset
5859 The tip revision (usually just called the tip) is the changeset
5858 most recently added to the repository (and therefore the most
5860 most recently added to the repository (and therefore the most
5859 recently changed head).
5861 recently changed head).
5860
5862
5861 If you have just made a commit, that commit will be the tip. If
5863 If you have just made a commit, that commit will be the tip. If
5862 you have just pulled changes from another repository, the tip of
5864 you have just pulled changes from another repository, the tip of
5863 that repository becomes the current tip. The "tip" tag is special
5865 that repository becomes the current tip. The "tip" tag is special
5864 and cannot be renamed or assigned to a different changeset.
5866 and cannot be renamed or assigned to a different changeset.
5865
5867
5866 Returns 0 on success.
5868 Returns 0 on success.
5867 """
5869 """
5868 displayer = cmdutil.show_changeset(ui, repo, opts)
5870 displayer = cmdutil.show_changeset(ui, repo, opts)
5869 displayer.show(repo[len(repo) - 1])
5871 displayer.show(repo[len(repo) - 1])
5870 displayer.close()
5872 displayer.close()
5871
5873
5872 @command('unbundle',
5874 @command('unbundle',
5873 [('u', 'update', None,
5875 [('u', 'update', None,
5874 _('update to new branch head if changesets were unbundled'))],
5876 _('update to new branch head if changesets were unbundled'))],
5875 _('[-u] FILE...'))
5877 _('[-u] FILE...'))
5876 def unbundle(ui, repo, fname1, *fnames, **opts):
5878 def unbundle(ui, repo, fname1, *fnames, **opts):
5877 """apply one or more changegroup files
5879 """apply one or more changegroup files
5878
5880
5879 Apply one or more compressed changegroup files generated by the
5881 Apply one or more compressed changegroup files generated by the
5880 bundle command.
5882 bundle command.
5881
5883
5882 Returns 0 on success, 1 if an update has unresolved files.
5884 Returns 0 on success, 1 if an update has unresolved files.
5883 """
5885 """
5884 fnames = (fname1,) + fnames
5886 fnames = (fname1,) + fnames
5885
5887
5886 lock = repo.lock()
5888 lock = repo.lock()
5887 wc = repo['.']
5889 wc = repo['.']
5888 try:
5890 try:
5889 for fname in fnames:
5891 for fname in fnames:
5890 f = hg.openpath(ui, fname)
5892 f = hg.openpath(ui, fname)
5891 gen = changegroup.readbundle(f, fname)
5893 gen = changegroup.readbundle(f, fname)
5892 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5894 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5893 finally:
5895 finally:
5894 lock.release()
5896 lock.release()
5895 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5897 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5896 return postincoming(ui, repo, modheads, opts.get('update'), None)
5898 return postincoming(ui, repo, modheads, opts.get('update'), None)
5897
5899
5898 @command('^update|up|checkout|co',
5900 @command('^update|up|checkout|co',
5899 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5901 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5900 ('c', 'check', None,
5902 ('c', 'check', None,
5901 _('update across branches if no uncommitted changes')),
5903 _('update across branches if no uncommitted changes')),
5902 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5904 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5903 ('r', 'rev', '', _('revision'), _('REV'))],
5905 ('r', 'rev', '', _('revision'), _('REV'))],
5904 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5906 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5905 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5907 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5906 """update working directory (or switch revisions)
5908 """update working directory (or switch revisions)
5907
5909
5908 Update the repository's working directory to the specified
5910 Update the repository's working directory to the specified
5909 changeset. If no changeset is specified, update to the tip of the
5911 changeset. If no changeset is specified, update to the tip of the
5910 current named branch and move the current bookmark (see :hg:`help
5912 current named branch and move the current bookmark (see :hg:`help
5911 bookmarks`).
5913 bookmarks`).
5912
5914
5913 Update sets the working directory's parent revision to the specified
5915 Update sets the working directory's parent revision to the specified
5914 changeset (see :hg:`help parents`).
5916 changeset (see :hg:`help parents`).
5915
5917
5916 If the changeset is not a descendant or ancestor of the working
5918 If the changeset is not a descendant or ancestor of the working
5917 directory's parent, the update is aborted. With the -c/--check
5919 directory's parent, the update is aborted. With the -c/--check
5918 option, the working directory is checked for uncommitted changes; if
5920 option, the working directory is checked for uncommitted changes; if
5919 none are found, the working directory is updated to the specified
5921 none are found, the working directory is updated to the specified
5920 changeset.
5922 changeset.
5921
5923
5922 .. container:: verbose
5924 .. container:: verbose
5923
5925
5924 The following rules apply when the working directory contains
5926 The following rules apply when the working directory contains
5925 uncommitted changes:
5927 uncommitted changes:
5926
5928
5927 1. If neither -c/--check nor -C/--clean is specified, and if
5929 1. If neither -c/--check nor -C/--clean is specified, and if
5928 the requested changeset is an ancestor or descendant of
5930 the requested changeset is an ancestor or descendant of
5929 the working directory's parent, the uncommitted changes
5931 the working directory's parent, the uncommitted changes
5930 are merged into the requested changeset and the merged
5932 are merged into the requested changeset and the merged
5931 result is left uncommitted. If the requested changeset is
5933 result is left uncommitted. If the requested changeset is
5932 not an ancestor or descendant (that is, it is on another
5934 not an ancestor or descendant (that is, it is on another
5933 branch), the update is aborted and the uncommitted changes
5935 branch), the update is aborted and the uncommitted changes
5934 are preserved.
5936 are preserved.
5935
5937
5936 2. With the -c/--check option, the update is aborted and the
5938 2. With the -c/--check option, the update is aborted and the
5937 uncommitted changes are preserved.
5939 uncommitted changes are preserved.
5938
5940
5939 3. With the -C/--clean option, uncommitted changes are discarded and
5941 3. With the -C/--clean option, uncommitted changes are discarded and
5940 the working directory is updated to the requested changeset.
5942 the working directory is updated to the requested changeset.
5941
5943
5942 To cancel an uncommitted merge (and lose your changes), use
5944 To cancel an uncommitted merge (and lose your changes), use
5943 :hg:`update --clean .`.
5945 :hg:`update --clean .`.
5944
5946
5945 Use null as the changeset to remove the working directory (like
5947 Use null as the changeset to remove the working directory (like
5946 :hg:`clone -U`).
5948 :hg:`clone -U`).
5947
5949
5948 If you want to revert just one file to an older revision, use
5950 If you want to revert just one file to an older revision, use
5949 :hg:`revert [-r REV] NAME`.
5951 :hg:`revert [-r REV] NAME`.
5950
5952
5951 See :hg:`help dates` for a list of formats valid for -d/--date.
5953 See :hg:`help dates` for a list of formats valid for -d/--date.
5952
5954
5953 Returns 0 on success, 1 if there are unresolved files.
5955 Returns 0 on success, 1 if there are unresolved files.
5954 """
5956 """
5955 if rev and node:
5957 if rev and node:
5956 raise util.Abort(_("please specify just one revision"))
5958 raise util.Abort(_("please specify just one revision"))
5957
5959
5958 if rev is None or rev == '':
5960 if rev is None or rev == '':
5959 rev = node
5961 rev = node
5960
5962
5961 # with no argument, we also move the current bookmark, if any
5963 # with no argument, we also move the current bookmark, if any
5962 movemarkfrom = None
5964 movemarkfrom = None
5963 if rev is None:
5965 if rev is None:
5964 movemarkfrom = repo['.'].node()
5966 movemarkfrom = repo['.'].node()
5965
5967
5966 # if we defined a bookmark, we have to remember the original bookmark name
5968 # if we defined a bookmark, we have to remember the original bookmark name
5967 brev = rev
5969 brev = rev
5968 rev = scmutil.revsingle(repo, rev, rev).rev()
5970 rev = scmutil.revsingle(repo, rev, rev).rev()
5969
5971
5970 if check and clean:
5972 if check and clean:
5971 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5973 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5972
5974
5973 if date:
5975 if date:
5974 if rev is not None:
5976 if rev is not None:
5975 raise util.Abort(_("you can't specify a revision and a date"))
5977 raise util.Abort(_("you can't specify a revision and a date"))
5976 rev = cmdutil.finddate(ui, repo, date)
5978 rev = cmdutil.finddate(ui, repo, date)
5977
5979
5978 if check:
5980 if check:
5979 c = repo[None]
5981 c = repo[None]
5980 if c.dirty(merge=False, branch=False, missing=True):
5982 if c.dirty(merge=False, branch=False, missing=True):
5981 raise util.Abort(_("uncommitted local changes"))
5983 raise util.Abort(_("uncommitted local changes"))
5982 if rev is None:
5984 if rev is None:
5983 rev = repo[repo[None].branch()].rev()
5985 rev = repo[repo[None].branch()].rev()
5984 mergemod._checkunknown(repo, repo[None], repo[rev])
5986 mergemod._checkunknown(repo, repo[None], repo[rev])
5985
5987
5986 if clean:
5988 if clean:
5987 ret = hg.clean(repo, rev)
5989 ret = hg.clean(repo, rev)
5988 else:
5990 else:
5989 ret = hg.update(repo, rev)
5991 ret = hg.update(repo, rev)
5990
5992
5991 if not ret and movemarkfrom:
5993 if not ret and movemarkfrom:
5992 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5994 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5993 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5995 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5994 elif brev in repo._bookmarks:
5996 elif brev in repo._bookmarks:
5995 bookmarks.setcurrent(repo, brev)
5997 bookmarks.setcurrent(repo, brev)
5996 elif brev:
5998 elif brev:
5997 bookmarks.unsetcurrent(repo)
5999 bookmarks.unsetcurrent(repo)
5998
6000
5999 return ret
6001 return ret
6000
6002
6001 @command('verify', [])
6003 @command('verify', [])
6002 def verify(ui, repo):
6004 def verify(ui, repo):
6003 """verify the integrity of the repository
6005 """verify the integrity of the repository
6004
6006
6005 Verify the integrity of the current repository.
6007 Verify the integrity of the current repository.
6006
6008
6007 This will perform an extensive check of the repository's
6009 This will perform an extensive check of the repository's
6008 integrity, validating the hashes and checksums of each entry in
6010 integrity, validating the hashes and checksums of each entry in
6009 the changelog, manifest, and tracked files, as well as the
6011 the changelog, manifest, and tracked files, as well as the
6010 integrity of their crosslinks and indices.
6012 integrity of their crosslinks and indices.
6011
6013
6012 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6014 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6013 for more information about recovery from corruption of the
6015 for more information about recovery from corruption of the
6014 repository.
6016 repository.
6015
6017
6016 Returns 0 on success, 1 if errors are encountered.
6018 Returns 0 on success, 1 if errors are encountered.
6017 """
6019 """
6018 return hg.verify(repo)
6020 return hg.verify(repo)
6019
6021
6020 @command('version', [])
6022 @command('version', [])
6021 def version_(ui):
6023 def version_(ui):
6022 """output version and copyright information"""
6024 """output version and copyright information"""
6023 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6025 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6024 % util.version())
6026 % util.version())
6025 ui.status(_(
6027 ui.status(_(
6026 "(see http://mercurial.selenic.com for more information)\n"
6028 "(see http://mercurial.selenic.com for more information)\n"
6027 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6029 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6028 "This is free software; see the source for copying conditions. "
6030 "This is free software; see the source for copying conditions. "
6029 "There is NO\nwarranty; "
6031 "There is NO\nwarranty; "
6030 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6032 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6031 ))
6033 ))
6032
6034
6033 norepo = ("clone init version help debugcommands debugcomplete"
6035 norepo = ("clone init version help debugcommands debugcomplete"
6034 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6036 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6035 " debugknown debuggetbundle debugbundle")
6037 " debugknown debuggetbundle debugbundle")
6036 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6038 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6037 " debugdata debugindex debugindexdot debugrevlog")
6039 " debugdata debugindex debugindexdot debugrevlog")
6038 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6040 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6039 " remove resolve status debugwalk")
6041 " remove resolve status debugwalk")
@@ -1,327 +1,327
1
1
2 Function to test discovery between two repos in both directions, using both the local shortcut
2 Function to test discovery between two repos in both directions, using both the local shortcut
3 (which is currently not activated by default) and the full remotable protocol:
3 (which is currently not activated by default) and the full remotable protocol:
4
4
5 $ testdesc() { # revs_a, revs_b, dagdesc
5 $ testdesc() { # revs_a, revs_b, dagdesc
6 > if [ -d foo ]; then rm -rf foo; fi
6 > if [ -d foo ]; then rm -rf foo; fi
7 > hg init foo
7 > hg init foo
8 > cd foo
8 > cd foo
9 > hg debugbuilddag "$3"
9 > hg debugbuilddag "$3"
10 > hg clone . a $1 --quiet
10 > hg clone . a $1 --quiet
11 > hg clone . b $2 --quiet
11 > hg clone . b $2 --quiet
12 > echo
12 > echo
13 > echo "% -- a -> b tree"
13 > echo "% -- a -> b tree"
14 > hg -R a debugdiscovery b --verbose --old
14 > hg -R a debugdiscovery b --verbose --old
15 > echo
15 > echo
16 > echo "% -- a -> b set"
16 > echo "% -- a -> b set"
17 > hg -R a debugdiscovery b --verbose --debug
17 > hg -R a debugdiscovery b --verbose --debug
18 > echo
18 > echo
19 > echo "% -- b -> a tree"
19 > echo "% -- b -> a tree"
20 > hg -R b debugdiscovery a --verbose --old
20 > hg -R b debugdiscovery a --verbose --old
21 > echo
21 > echo
22 > echo "% -- b -> a set"
22 > echo "% -- b -> a set"
23 > hg -R b debugdiscovery a --verbose --debug
23 > hg -R b debugdiscovery a --verbose --debug
24 > cd ..
24 > cd ..
25 > }
25 > }
26
26
27
27
28 Small superset:
28 Small superset:
29
29
30 $ testdesc '-ra1 -ra2' '-rb1 -rb2 -rb3' '
30 $ testdesc '-ra1 -ra2' '-rb1 -rb2 -rb3' '
31 > +2:f +1:a1:b1
31 > +2:f +1:a1:b1
32 > <f +4 :a2
32 > <f +4 :a2
33 > +5 :b2
33 > +5 :b2
34 > <f +3 :b3'
34 > <f +3 :b3'
35
35
36 % -- a -> b tree
36 % -- a -> b tree
37 comparing with b
37 comparing with b
38 searching for changes
38 searching for changes
39 unpruned common: b5714e113bc0 66f7d451a68b 01241442b3c2
39 unpruned common: 01241442b3c2 66f7d451a68b b5714e113bc0
40 common heads: b5714e113bc0 01241442b3c2
40 common heads: 01241442b3c2 b5714e113bc0
41 local is subset
41 local is subset
42
42
43 % -- a -> b set
43 % -- a -> b set
44 comparing with b
44 comparing with b
45 query 1; heads
45 query 1; heads
46 searching for changes
46 searching for changes
47 all local heads known remotely
47 all local heads known remotely
48 common heads: b5714e113bc0 01241442b3c2
48 common heads: 01241442b3c2 b5714e113bc0
49 local is subset
49 local is subset
50
50
51 % -- b -> a tree
51 % -- b -> a tree
52 comparing with a
52 comparing with a
53 searching for changes
53 searching for changes
54 unpruned common: b5714e113bc0 01241442b3c2
54 unpruned common: 01241442b3c2 b5714e113bc0
55 common heads: b5714e113bc0 01241442b3c2
55 common heads: 01241442b3c2 b5714e113bc0
56 remote is subset
56 remote is subset
57
57
58 % -- b -> a set
58 % -- b -> a set
59 comparing with a
59 comparing with a
60 query 1; heads
60 query 1; heads
61 searching for changes
61 searching for changes
62 all remote heads known locally
62 all remote heads known locally
63 common heads: b5714e113bc0 01241442b3c2
63 common heads: 01241442b3c2 b5714e113bc0
64 remote is subset
64 remote is subset
65
65
66
66
67 Many new:
67 Many new:
68
68
69 $ testdesc '-ra1 -ra2' '-rb' '
69 $ testdesc '-ra1 -ra2' '-rb' '
70 > +2:f +3:a1 +3:b
70 > +2:f +3:a1 +3:b
71 > <f +30 :a2'
71 > <f +30 :a2'
72
72
73 % -- a -> b tree
73 % -- a -> b tree
74 comparing with b
74 comparing with b
75 searching for changes
75 searching for changes
76 unpruned common: bebd167eb94d
76 unpruned common: bebd167eb94d
77 common heads: bebd167eb94d
77 common heads: bebd167eb94d
78
78
79 % -- a -> b set
79 % -- a -> b set
80 comparing with b
80 comparing with b
81 query 1; heads
81 query 1; heads
82 searching for changes
82 searching for changes
83 taking initial sample
83 taking initial sample
84 searching: 2 queries
84 searching: 2 queries
85 query 2; still undecided: 29, sample size is: 29
85 query 2; still undecided: 29, sample size is: 29
86 2 total queries
86 2 total queries
87 common heads: bebd167eb94d
87 common heads: bebd167eb94d
88
88
89 % -- b -> a tree
89 % -- b -> a tree
90 comparing with a
90 comparing with a
91 searching for changes
91 searching for changes
92 unpruned common: bebd167eb94d 66f7d451a68b
92 unpruned common: 66f7d451a68b bebd167eb94d
93 common heads: bebd167eb94d
93 common heads: bebd167eb94d
94
94
95 % -- b -> a set
95 % -- b -> a set
96 comparing with a
96 comparing with a
97 query 1; heads
97 query 1; heads
98 searching for changes
98 searching for changes
99 taking initial sample
99 taking initial sample
100 searching: 2 queries
100 searching: 2 queries
101 query 2; still undecided: 2, sample size is: 2
101 query 2; still undecided: 2, sample size is: 2
102 2 total queries
102 2 total queries
103 common heads: bebd167eb94d
103 common heads: bebd167eb94d
104
104
105
105
106 Both sides many new with stub:
106 Both sides many new with stub:
107
107
108 $ testdesc '-ra1 -ra2' '-rb' '
108 $ testdesc '-ra1 -ra2' '-rb' '
109 > +2:f +2:a1 +30 :b
109 > +2:f +2:a1 +30 :b
110 > <f +30 :a2'
110 > <f +30 :a2'
111
111
112 % -- a -> b tree
112 % -- a -> b tree
113 comparing with b
113 comparing with b
114 searching for changes
114 searching for changes
115 unpruned common: 2dc09a01254d
115 unpruned common: 2dc09a01254d
116 common heads: 2dc09a01254d
116 common heads: 2dc09a01254d
117
117
118 % -- a -> b set
118 % -- a -> b set
119 comparing with b
119 comparing with b
120 query 1; heads
120 query 1; heads
121 searching for changes
121 searching for changes
122 taking initial sample
122 taking initial sample
123 searching: 2 queries
123 searching: 2 queries
124 query 2; still undecided: 29, sample size is: 29
124 query 2; still undecided: 29, sample size is: 29
125 2 total queries
125 2 total queries
126 common heads: 2dc09a01254d
126 common heads: 2dc09a01254d
127
127
128 % -- b -> a tree
128 % -- b -> a tree
129 comparing with a
129 comparing with a
130 searching for changes
130 searching for changes
131 unpruned common: 66f7d451a68b 2dc09a01254d
131 unpruned common: 2dc09a01254d 66f7d451a68b
132 common heads: 2dc09a01254d
132 common heads: 2dc09a01254d
133
133
134 % -- b -> a set
134 % -- b -> a set
135 comparing with a
135 comparing with a
136 query 1; heads
136 query 1; heads
137 searching for changes
137 searching for changes
138 taking initial sample
138 taking initial sample
139 searching: 2 queries
139 searching: 2 queries
140 query 2; still undecided: 29, sample size is: 29
140 query 2; still undecided: 29, sample size is: 29
141 2 total queries
141 2 total queries
142 common heads: 2dc09a01254d
142 common heads: 2dc09a01254d
143
143
144
144
145 Both many new:
145 Both many new:
146
146
147 $ testdesc '-ra' '-rb' '
147 $ testdesc '-ra' '-rb' '
148 > +2:f +30 :b
148 > +2:f +30 :b
149 > <f +30 :a'
149 > <f +30 :a'
150
150
151 % -- a -> b tree
151 % -- a -> b tree
152 comparing with b
152 comparing with b
153 searching for changes
153 searching for changes
154 unpruned common: 66f7d451a68b
154 unpruned common: 66f7d451a68b
155 common heads: 66f7d451a68b
155 common heads: 66f7d451a68b
156
156
157 % -- a -> b set
157 % -- a -> b set
158 comparing with b
158 comparing with b
159 query 1; heads
159 query 1; heads
160 searching for changes
160 searching for changes
161 taking quick initial sample
161 taking quick initial sample
162 searching: 2 queries
162 searching: 2 queries
163 query 2; still undecided: 31, sample size is: 31
163 query 2; still undecided: 31, sample size is: 31
164 2 total queries
164 2 total queries
165 common heads: 66f7d451a68b
165 common heads: 66f7d451a68b
166
166
167 % -- b -> a tree
167 % -- b -> a tree
168 comparing with a
168 comparing with a
169 searching for changes
169 searching for changes
170 unpruned common: 66f7d451a68b
170 unpruned common: 66f7d451a68b
171 common heads: 66f7d451a68b
171 common heads: 66f7d451a68b
172
172
173 % -- b -> a set
173 % -- b -> a set
174 comparing with a
174 comparing with a
175 query 1; heads
175 query 1; heads
176 searching for changes
176 searching for changes
177 taking quick initial sample
177 taking quick initial sample
178 searching: 2 queries
178 searching: 2 queries
179 query 2; still undecided: 31, sample size is: 31
179 query 2; still undecided: 31, sample size is: 31
180 2 total queries
180 2 total queries
181 common heads: 66f7d451a68b
181 common heads: 66f7d451a68b
182
182
183
183
184 Both many new skewed:
184 Both many new skewed:
185
185
186 $ testdesc '-ra' '-rb' '
186 $ testdesc '-ra' '-rb' '
187 > +2:f +30 :b
187 > +2:f +30 :b
188 > <f +50 :a'
188 > <f +50 :a'
189
189
190 % -- a -> b tree
190 % -- a -> b tree
191 comparing with b
191 comparing with b
192 searching for changes
192 searching for changes
193 unpruned common: 66f7d451a68b
193 unpruned common: 66f7d451a68b
194 common heads: 66f7d451a68b
194 common heads: 66f7d451a68b
195
195
196 % -- a -> b set
196 % -- a -> b set
197 comparing with b
197 comparing with b
198 query 1; heads
198 query 1; heads
199 searching for changes
199 searching for changes
200 taking quick initial sample
200 taking quick initial sample
201 searching: 2 queries
201 searching: 2 queries
202 query 2; still undecided: 51, sample size is: 51
202 query 2; still undecided: 51, sample size is: 51
203 2 total queries
203 2 total queries
204 common heads: 66f7d451a68b
204 common heads: 66f7d451a68b
205
205
206 % -- b -> a tree
206 % -- b -> a tree
207 comparing with a
207 comparing with a
208 searching for changes
208 searching for changes
209 unpruned common: 66f7d451a68b
209 unpruned common: 66f7d451a68b
210 common heads: 66f7d451a68b
210 common heads: 66f7d451a68b
211
211
212 % -- b -> a set
212 % -- b -> a set
213 comparing with a
213 comparing with a
214 query 1; heads
214 query 1; heads
215 searching for changes
215 searching for changes
216 taking quick initial sample
216 taking quick initial sample
217 searching: 2 queries
217 searching: 2 queries
218 query 2; still undecided: 31, sample size is: 31
218 query 2; still undecided: 31, sample size is: 31
219 2 total queries
219 2 total queries
220 common heads: 66f7d451a68b
220 common heads: 66f7d451a68b
221
221
222
222
223 Both many new on top of long history:
223 Both many new on top of long history:
224
224
225 $ testdesc '-ra' '-rb' '
225 $ testdesc '-ra' '-rb' '
226 > +1000:f +30 :b
226 > +1000:f +30 :b
227 > <f +50 :a'
227 > <f +50 :a'
228
228
229 % -- a -> b tree
229 % -- a -> b tree
230 comparing with b
230 comparing with b
231 searching for changes
231 searching for changes
232 unpruned common: 7ead0cba2838
232 unpruned common: 7ead0cba2838
233 common heads: 7ead0cba2838
233 common heads: 7ead0cba2838
234
234
235 % -- a -> b set
235 % -- a -> b set
236 comparing with b
236 comparing with b
237 query 1; heads
237 query 1; heads
238 searching for changes
238 searching for changes
239 taking quick initial sample
239 taking quick initial sample
240 searching: 2 queries
240 searching: 2 queries
241 query 2; still undecided: 1049, sample size is: 11
241 query 2; still undecided: 1049, sample size is: 11
242 sampling from both directions
242 sampling from both directions
243 searching: 3 queries
243 searching: 3 queries
244 query 3; still undecided: 31, sample size is: 31
244 query 3; still undecided: 31, sample size is: 31
245 3 total queries
245 3 total queries
246 common heads: 7ead0cba2838
246 common heads: 7ead0cba2838
247
247
248 % -- b -> a tree
248 % -- b -> a tree
249 comparing with a
249 comparing with a
250 searching for changes
250 searching for changes
251 unpruned common: 7ead0cba2838
251 unpruned common: 7ead0cba2838
252 common heads: 7ead0cba2838
252 common heads: 7ead0cba2838
253
253
254 % -- b -> a set
254 % -- b -> a set
255 comparing with a
255 comparing with a
256 query 1; heads
256 query 1; heads
257 searching for changes
257 searching for changes
258 taking quick initial sample
258 taking quick initial sample
259 searching: 2 queries
259 searching: 2 queries
260 query 2; still undecided: 1029, sample size is: 11
260 query 2; still undecided: 1029, sample size is: 11
261 sampling from both directions
261 sampling from both directions
262 searching: 3 queries
262 searching: 3 queries
263 query 3; still undecided: 15, sample size is: 15
263 query 3; still undecided: 15, sample size is: 15
264 3 total queries
264 3 total queries
265 common heads: 7ead0cba2838
265 common heads: 7ead0cba2838
266
266
267
267
268 One with >200 heads, which used to use up all of the sample:
268 One with >200 heads, which used to use up all of the sample:
269
269
270 $ hg init manyheads
270 $ hg init manyheads
271 $ cd manyheads
271 $ cd manyheads
272 $ echo "+300:r @a" >dagdesc
272 $ echo "+300:r @a" >dagdesc
273 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
273 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
274 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
274 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
275 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
275 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
276 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
276 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
277 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
277 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
278 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
278 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
279 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
279 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
280 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
280 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
281 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
281 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
282 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
282 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
283 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
283 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
284 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
284 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
285 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
285 $ echo "*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3 *r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3*r+3" >>dagdesc # 20 heads
286 $ echo "@b *r+3" >>dagdesc # one more head
286 $ echo "@b *r+3" >>dagdesc # one more head
287 $ hg debugbuilddag <dagdesc
287 $ hg debugbuilddag <dagdesc
288 reading DAG from stdin
288 reading DAG from stdin
289
289
290 $ hg heads -t --template . | wc -c
290 $ hg heads -t --template . | wc -c
291 \s*261 (re)
291 \s*261 (re)
292
292
293 $ hg clone -b a . a
293 $ hg clone -b a . a
294 adding changesets
294 adding changesets
295 adding manifests
295 adding manifests
296 adding file changes
296 adding file changes
297 added 1340 changesets with 0 changes to 0 files (+259 heads)
297 added 1340 changesets with 0 changes to 0 files (+259 heads)
298 updating to branch a
298 updating to branch a
299 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 $ hg clone -b b . b
300 $ hg clone -b b . b
301 adding changesets
301 adding changesets
302 adding manifests
302 adding manifests
303 adding file changes
303 adding file changes
304 added 304 changesets with 0 changes to 0 files
304 added 304 changesets with 0 changes to 0 files
305 updating to branch b
305 updating to branch b
306 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
306 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
307
307
308 $ hg -R a debugdiscovery b --debug --verbose
308 $ hg -R a debugdiscovery b --debug --verbose
309 comparing with b
309 comparing with b
310 query 1; heads
310 query 1; heads
311 searching for changes
311 searching for changes
312 taking quick initial sample
312 taking quick initial sample
313 searching: 2 queries
313 searching: 2 queries
314 query 2; still undecided: 1080, sample size is: 260
314 query 2; still undecided: 1080, sample size is: 260
315 sampling from both directions
315 sampling from both directions
316 searching: 3 queries
316 searching: 3 queries
317 query 3; still undecided: 820, sample size is: 260
317 query 3; still undecided: 820, sample size is: 260
318 sampling from both directions
318 sampling from both directions
319 searching: 4 queries
319 searching: 4 queries
320 query 4; still undecided: 560, sample size is: 260
320 query 4; still undecided: 560, sample size is: 260
321 sampling from both directions
321 sampling from both directions
322 searching: 5 queries
322 searching: 5 queries
323 query 5; still undecided: 300, sample size is: 200
323 query 5; still undecided: 300, sample size is: 200
324 5 total queries
324 5 total queries
325 common heads: 3ee37d65064a
325 common heads: 3ee37d65064a
326
326
327 $ cd ..
327 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now