##// END OF EJS Templates
debugrevlog: format columns (more) nicely when dumping index data
Mads Kiilerich -
r21032:67b6f114 default
parent child Browse files
Show More
@@ -1,5942 +1,5942 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import sys
12 import sys
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 from hgweb import server as hgweb_server
17 from hgweb import server as hgweb_server
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod
20 import dagparser, context, simplemerge, graphmod
21 import random
21 import random
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import phases, obsolete
23 import phases, obsolete
24
24
25 table = {}
25 table = {}
26
26
27 command = cmdutil.command(table)
27 command = cmdutil.command(table)
28
28
29 # common command options
29 # common command options
30
30
31 globalopts = [
31 globalopts = [
32 ('R', 'repository', '',
32 ('R', 'repository', '',
33 _('repository root directory or name of overlay bundle file'),
33 _('repository root directory or name of overlay bundle file'),
34 _('REPO')),
34 _('REPO')),
35 ('', 'cwd', '',
35 ('', 'cwd', '',
36 _('change working directory'), _('DIR')),
36 _('change working directory'), _('DIR')),
37 ('y', 'noninteractive', None,
37 ('y', 'noninteractive', None,
38 _('do not prompt, automatically pick the first choice for all prompts')),
38 _('do not prompt, automatically pick the first choice for all prompts')),
39 ('q', 'quiet', None, _('suppress output')),
39 ('q', 'quiet', None, _('suppress output')),
40 ('v', 'verbose', None, _('enable additional output')),
40 ('v', 'verbose', None, _('enable additional output')),
41 ('', 'config', [],
41 ('', 'config', [],
42 _('set/override config option (use \'section.name=value\')'),
42 _('set/override config option (use \'section.name=value\')'),
43 _('CONFIG')),
43 _('CONFIG')),
44 ('', 'debug', None, _('enable debugging output')),
44 ('', 'debug', None, _('enable debugging output')),
45 ('', 'debugger', None, _('start debugger')),
45 ('', 'debugger', None, _('start debugger')),
46 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
46 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
47 _('ENCODE')),
47 _('ENCODE')),
48 ('', 'encodingmode', encoding.encodingmode,
48 ('', 'encodingmode', encoding.encodingmode,
49 _('set the charset encoding mode'), _('MODE')),
49 _('set the charset encoding mode'), _('MODE')),
50 ('', 'traceback', None, _('always print a traceback on exception')),
50 ('', 'traceback', None, _('always print a traceback on exception')),
51 ('', 'time', None, _('time how long the command takes')),
51 ('', 'time', None, _('time how long the command takes')),
52 ('', 'profile', None, _('print command execution profile')),
52 ('', 'profile', None, _('print command execution profile')),
53 ('', 'version', None, _('output version information and exit')),
53 ('', 'version', None, _('output version information and exit')),
54 ('h', 'help', None, _('display help and exit')),
54 ('h', 'help', None, _('display help and exit')),
55 ('', 'hidden', False, _('consider hidden changesets')),
55 ('', 'hidden', False, _('consider hidden changesets')),
56 ]
56 ]
57
57
58 dryrunopts = [('n', 'dry-run', None,
58 dryrunopts = [('n', 'dry-run', None,
59 _('do not perform actions, just print output'))]
59 _('do not perform actions, just print output'))]
60
60
61 remoteopts = [
61 remoteopts = [
62 ('e', 'ssh', '',
62 ('e', 'ssh', '',
63 _('specify ssh command to use'), _('CMD')),
63 _('specify ssh command to use'), _('CMD')),
64 ('', 'remotecmd', '',
64 ('', 'remotecmd', '',
65 _('specify hg command to run on the remote side'), _('CMD')),
65 _('specify hg command to run on the remote side'), _('CMD')),
66 ('', 'insecure', None,
66 ('', 'insecure', None,
67 _('do not verify server certificate (ignoring web.cacerts config)')),
67 _('do not verify server certificate (ignoring web.cacerts config)')),
68 ]
68 ]
69
69
70 walkopts = [
70 walkopts = [
71 ('I', 'include', [],
71 ('I', 'include', [],
72 _('include names matching the given patterns'), _('PATTERN')),
72 _('include names matching the given patterns'), _('PATTERN')),
73 ('X', 'exclude', [],
73 ('X', 'exclude', [],
74 _('exclude names matching the given patterns'), _('PATTERN')),
74 _('exclude names matching the given patterns'), _('PATTERN')),
75 ]
75 ]
76
76
77 commitopts = [
77 commitopts = [
78 ('m', 'message', '',
78 ('m', 'message', '',
79 _('use text as commit message'), _('TEXT')),
79 _('use text as commit message'), _('TEXT')),
80 ('l', 'logfile', '',
80 ('l', 'logfile', '',
81 _('read commit message from file'), _('FILE')),
81 _('read commit message from file'), _('FILE')),
82 ]
82 ]
83
83
84 commitopts2 = [
84 commitopts2 = [
85 ('d', 'date', '',
85 ('d', 'date', '',
86 _('record the specified date as commit date'), _('DATE')),
86 _('record the specified date as commit date'), _('DATE')),
87 ('u', 'user', '',
87 ('u', 'user', '',
88 _('record the specified user as committer'), _('USER')),
88 _('record the specified user as committer'), _('USER')),
89 ]
89 ]
90
90
91 templateopts = [
91 templateopts = [
92 ('', 'style', '',
92 ('', 'style', '',
93 _('display using template map file (DEPRECATED)'), _('STYLE')),
93 _('display using template map file (DEPRECATED)'), _('STYLE')),
94 ('T', 'template', '',
94 ('T', 'template', '',
95 _('display with template'), _('TEMPLATE')),
95 _('display with template'), _('TEMPLATE')),
96 ]
96 ]
97
97
98 logopts = [
98 logopts = [
99 ('p', 'patch', None, _('show patch')),
99 ('p', 'patch', None, _('show patch')),
100 ('g', 'git', None, _('use git extended diff format')),
100 ('g', 'git', None, _('use git extended diff format')),
101 ('l', 'limit', '',
101 ('l', 'limit', '',
102 _('limit number of changes displayed'), _('NUM')),
102 _('limit number of changes displayed'), _('NUM')),
103 ('M', 'no-merges', None, _('do not show merges')),
103 ('M', 'no-merges', None, _('do not show merges')),
104 ('', 'stat', None, _('output diffstat-style summary of changes')),
104 ('', 'stat', None, _('output diffstat-style summary of changes')),
105 ('G', 'graph', None, _("show the revision DAG")),
105 ('G', 'graph', None, _("show the revision DAG")),
106 ] + templateopts
106 ] + templateopts
107
107
108 diffopts = [
108 diffopts = [
109 ('a', 'text', None, _('treat all files as text')),
109 ('a', 'text', None, _('treat all files as text')),
110 ('g', 'git', None, _('use git extended diff format')),
110 ('g', 'git', None, _('use git extended diff format')),
111 ('', 'nodates', None, _('omit dates from diff headers'))
111 ('', 'nodates', None, _('omit dates from diff headers'))
112 ]
112 ]
113
113
114 diffwsopts = [
114 diffwsopts = [
115 ('w', 'ignore-all-space', None,
115 ('w', 'ignore-all-space', None,
116 _('ignore white space when comparing lines')),
116 _('ignore white space when comparing lines')),
117 ('b', 'ignore-space-change', None,
117 ('b', 'ignore-space-change', None,
118 _('ignore changes in the amount of white space')),
118 _('ignore changes in the amount of white space')),
119 ('B', 'ignore-blank-lines', None,
119 ('B', 'ignore-blank-lines', None,
120 _('ignore changes whose lines are all blank')),
120 _('ignore changes whose lines are all blank')),
121 ]
121 ]
122
122
123 diffopts2 = [
123 diffopts2 = [
124 ('p', 'show-function', None, _('show which function each change is in')),
124 ('p', 'show-function', None, _('show which function each change is in')),
125 ('', 'reverse', None, _('produce a diff that undoes the changes')),
125 ('', 'reverse', None, _('produce a diff that undoes the changes')),
126 ] + diffwsopts + [
126 ] + diffwsopts + [
127 ('U', 'unified', '',
127 ('U', 'unified', '',
128 _('number of lines of context to show'), _('NUM')),
128 _('number of lines of context to show'), _('NUM')),
129 ('', 'stat', None, _('output diffstat-style summary of changes')),
129 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ]
130 ]
131
131
132 mergetoolopts = [
132 mergetoolopts = [
133 ('t', 'tool', '', _('specify merge tool')),
133 ('t', 'tool', '', _('specify merge tool')),
134 ]
134 ]
135
135
136 similarityopts = [
136 similarityopts = [
137 ('s', 'similarity', '',
137 ('s', 'similarity', '',
138 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
138 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
139 ]
139 ]
140
140
141 subrepoopts = [
141 subrepoopts = [
142 ('S', 'subrepos', None,
142 ('S', 'subrepos', None,
143 _('recurse into subrepositories'))
143 _('recurse into subrepositories'))
144 ]
144 ]
145
145
146 # Commands start here, listed alphabetically
146 # Commands start here, listed alphabetically
147
147
148 @command('^add',
148 @command('^add',
149 walkopts + subrepoopts + dryrunopts,
149 walkopts + subrepoopts + dryrunopts,
150 _('[OPTION]... [FILE]...'))
150 _('[OPTION]... [FILE]...'))
151 def add(ui, repo, *pats, **opts):
151 def add(ui, repo, *pats, **opts):
152 """add the specified files on the next commit
152 """add the specified files on the next commit
153
153
154 Schedule files to be version controlled and added to the
154 Schedule files to be version controlled and added to the
155 repository.
155 repository.
156
156
157 The files will be added to the repository at the next commit. To
157 The files will be added to the repository at the next commit. To
158 undo an add before that, see :hg:`forget`.
158 undo an add before that, see :hg:`forget`.
159
159
160 If no names are given, add all files to the repository.
160 If no names are given, add all files to the repository.
161
161
162 .. container:: verbose
162 .. container:: verbose
163
163
164 An example showing how new (unknown) files are added
164 An example showing how new (unknown) files are added
165 automatically by :hg:`add`::
165 automatically by :hg:`add`::
166
166
167 $ ls
167 $ ls
168 foo.c
168 foo.c
169 $ hg status
169 $ hg status
170 ? foo.c
170 ? foo.c
171 $ hg add
171 $ hg add
172 adding foo.c
172 adding foo.c
173 $ hg status
173 $ hg status
174 A foo.c
174 A foo.c
175
175
176 Returns 0 if all files are successfully added.
176 Returns 0 if all files are successfully added.
177 """
177 """
178
178
179 m = scmutil.match(repo[None], pats, opts)
179 m = scmutil.match(repo[None], pats, opts)
180 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
180 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
181 opts.get('subrepos'), prefix="", explicitonly=False)
181 opts.get('subrepos'), prefix="", explicitonly=False)
182 return rejected and 1 or 0
182 return rejected and 1 or 0
183
183
184 @command('addremove',
184 @command('addremove',
185 similarityopts + walkopts + dryrunopts,
185 similarityopts + walkopts + dryrunopts,
186 _('[OPTION]... [FILE]...'))
186 _('[OPTION]... [FILE]...'))
187 def addremove(ui, repo, *pats, **opts):
187 def addremove(ui, repo, *pats, **opts):
188 """add all new files, delete all missing files
188 """add all new files, delete all missing files
189
189
190 Add all new files and remove all missing files from the
190 Add all new files and remove all missing files from the
191 repository.
191 repository.
192
192
193 New files are ignored if they match any of the patterns in
193 New files are ignored if they match any of the patterns in
194 ``.hgignore``. As with add, these changes take effect at the next
194 ``.hgignore``. As with add, these changes take effect at the next
195 commit.
195 commit.
196
196
197 Use the -s/--similarity option to detect renamed files. This
197 Use the -s/--similarity option to detect renamed files. This
198 option takes a percentage between 0 (disabled) and 100 (files must
198 option takes a percentage between 0 (disabled) and 100 (files must
199 be identical) as its parameter. With a parameter greater than 0,
199 be identical) as its parameter. With a parameter greater than 0,
200 this compares every removed file with every added file and records
200 this compares every removed file with every added file and records
201 those similar enough as renames. Detecting renamed files this way
201 those similar enough as renames. Detecting renamed files this way
202 can be expensive. After using this option, :hg:`status -C` can be
202 can be expensive. After using this option, :hg:`status -C` can be
203 used to check which files were identified as moved or renamed. If
203 used to check which files were identified as moved or renamed. If
204 not specified, -s/--similarity defaults to 100 and only renames of
204 not specified, -s/--similarity defaults to 100 and only renames of
205 identical files are detected.
205 identical files are detected.
206
206
207 Returns 0 if all files are successfully added.
207 Returns 0 if all files are successfully added.
208 """
208 """
209 try:
209 try:
210 sim = float(opts.get('similarity') or 100)
210 sim = float(opts.get('similarity') or 100)
211 except ValueError:
211 except ValueError:
212 raise util.Abort(_('similarity must be a number'))
212 raise util.Abort(_('similarity must be a number'))
213 if sim < 0 or sim > 100:
213 if sim < 0 or sim > 100:
214 raise util.Abort(_('similarity must be between 0 and 100'))
214 raise util.Abort(_('similarity must be between 0 and 100'))
215 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
215 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
216
216
217 @command('^annotate|blame',
217 @command('^annotate|blame',
218 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
218 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
219 ('', 'follow', None,
219 ('', 'follow', None,
220 _('follow copies/renames and list the filename (DEPRECATED)')),
220 _('follow copies/renames and list the filename (DEPRECATED)')),
221 ('', 'no-follow', None, _("don't follow copies and renames")),
221 ('', 'no-follow', None, _("don't follow copies and renames")),
222 ('a', 'text', None, _('treat all files as text')),
222 ('a', 'text', None, _('treat all files as text')),
223 ('u', 'user', None, _('list the author (long with -v)')),
223 ('u', 'user', None, _('list the author (long with -v)')),
224 ('f', 'file', None, _('list the filename')),
224 ('f', 'file', None, _('list the filename')),
225 ('d', 'date', None, _('list the date (short with -q)')),
225 ('d', 'date', None, _('list the date (short with -q)')),
226 ('n', 'number', None, _('list the revision number (default)')),
226 ('n', 'number', None, _('list the revision number (default)')),
227 ('c', 'changeset', None, _('list the changeset')),
227 ('c', 'changeset', None, _('list the changeset')),
228 ('l', 'line-number', None, _('show line number at the first appearance'))
228 ('l', 'line-number', None, _('show line number at the first appearance'))
229 ] + diffwsopts + walkopts,
229 ] + diffwsopts + walkopts,
230 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
230 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
231 def annotate(ui, repo, *pats, **opts):
231 def annotate(ui, repo, *pats, **opts):
232 """show changeset information by line for each file
232 """show changeset information by line for each file
233
233
234 List changes in files, showing the revision id responsible for
234 List changes in files, showing the revision id responsible for
235 each line
235 each line
236
236
237 This command is useful for discovering when a change was made and
237 This command is useful for discovering when a change was made and
238 by whom.
238 by whom.
239
239
240 Without the -a/--text option, annotate will avoid processing files
240 Without the -a/--text option, annotate will avoid processing files
241 it detects as binary. With -a, annotate will annotate the file
241 it detects as binary. With -a, annotate will annotate the file
242 anyway, although the results will probably be neither useful
242 anyway, although the results will probably be neither useful
243 nor desirable.
243 nor desirable.
244
244
245 Returns 0 on success.
245 Returns 0 on success.
246 """
246 """
247 if opts.get('follow'):
247 if opts.get('follow'):
248 # --follow is deprecated and now just an alias for -f/--file
248 # --follow is deprecated and now just an alias for -f/--file
249 # to mimic the behavior of Mercurial before version 1.5
249 # to mimic the behavior of Mercurial before version 1.5
250 opts['file'] = True
250 opts['file'] = True
251
251
252 datefunc = ui.quiet and util.shortdate or util.datestr
252 datefunc = ui.quiet and util.shortdate or util.datestr
253 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
253 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
254
254
255 if not pats:
255 if not pats:
256 raise util.Abort(_('at least one filename or pattern is required'))
256 raise util.Abort(_('at least one filename or pattern is required'))
257
257
258 hexfn = ui.debugflag and hex or short
258 hexfn = ui.debugflag and hex or short
259
259
260 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
260 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
261 ('number', ' ', lambda x: str(x[0].rev())),
261 ('number', ' ', lambda x: str(x[0].rev())),
262 ('changeset', ' ', lambda x: hexfn(x[0].node())),
262 ('changeset', ' ', lambda x: hexfn(x[0].node())),
263 ('date', ' ', getdate),
263 ('date', ' ', getdate),
264 ('file', ' ', lambda x: x[0].path()),
264 ('file', ' ', lambda x: x[0].path()),
265 ('line_number', ':', lambda x: str(x[1])),
265 ('line_number', ':', lambda x: str(x[1])),
266 ]
266 ]
267
267
268 if (not opts.get('user') and not opts.get('changeset')
268 if (not opts.get('user') and not opts.get('changeset')
269 and not opts.get('date') and not opts.get('file')):
269 and not opts.get('date') and not opts.get('file')):
270 opts['number'] = True
270 opts['number'] = True
271
271
272 linenumber = opts.get('line_number') is not None
272 linenumber = opts.get('line_number') is not None
273 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
273 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
274 raise util.Abort(_('at least one of -n/-c is required for -l'))
274 raise util.Abort(_('at least one of -n/-c is required for -l'))
275
275
276 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
276 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
277 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
277 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
278
278
279 def bad(x, y):
279 def bad(x, y):
280 raise util.Abort("%s: %s" % (x, y))
280 raise util.Abort("%s: %s" % (x, y))
281
281
282 ctx = scmutil.revsingle(repo, opts.get('rev'))
282 ctx = scmutil.revsingle(repo, opts.get('rev'))
283 m = scmutil.match(ctx, pats, opts)
283 m = scmutil.match(ctx, pats, opts)
284 m.bad = bad
284 m.bad = bad
285 follow = not opts.get('no_follow')
285 follow = not opts.get('no_follow')
286 diffopts = patch.diffopts(ui, opts, section='annotate')
286 diffopts = patch.diffopts(ui, opts, section='annotate')
287 for abs in ctx.walk(m):
287 for abs in ctx.walk(m):
288 fctx = ctx[abs]
288 fctx = ctx[abs]
289 if not opts.get('text') and util.binary(fctx.data()):
289 if not opts.get('text') and util.binary(fctx.data()):
290 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
290 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
291 continue
291 continue
292
292
293 lines = fctx.annotate(follow=follow, linenumber=linenumber,
293 lines = fctx.annotate(follow=follow, linenumber=linenumber,
294 diffopts=diffopts)
294 diffopts=diffopts)
295 pieces = []
295 pieces = []
296
296
297 for f, sep in funcmap:
297 for f, sep in funcmap:
298 l = [f(n) for n, dummy in lines]
298 l = [f(n) for n, dummy in lines]
299 if l:
299 if l:
300 sized = [(x, encoding.colwidth(x)) for x in l]
300 sized = [(x, encoding.colwidth(x)) for x in l]
301 ml = max([w for x, w in sized])
301 ml = max([w for x, w in sized])
302 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
302 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
303 for x, w in sized])
303 for x, w in sized])
304
304
305 if pieces:
305 if pieces:
306 for p, l in zip(zip(*pieces), lines):
306 for p, l in zip(zip(*pieces), lines):
307 ui.write("%s: %s" % ("".join(p), l[1]))
307 ui.write("%s: %s" % ("".join(p), l[1]))
308
308
309 if lines and not lines[-1][1].endswith('\n'):
309 if lines and not lines[-1][1].endswith('\n'):
310 ui.write('\n')
310 ui.write('\n')
311
311
312 @command('archive',
312 @command('archive',
313 [('', 'no-decode', None, _('do not pass files through decoders')),
313 [('', 'no-decode', None, _('do not pass files through decoders')),
314 ('p', 'prefix', '', _('directory prefix for files in archive'),
314 ('p', 'prefix', '', _('directory prefix for files in archive'),
315 _('PREFIX')),
315 _('PREFIX')),
316 ('r', 'rev', '', _('revision to distribute'), _('REV')),
316 ('r', 'rev', '', _('revision to distribute'), _('REV')),
317 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
317 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
318 ] + subrepoopts + walkopts,
318 ] + subrepoopts + walkopts,
319 _('[OPTION]... DEST'))
319 _('[OPTION]... DEST'))
320 def archive(ui, repo, dest, **opts):
320 def archive(ui, repo, dest, **opts):
321 '''create an unversioned archive of a repository revision
321 '''create an unversioned archive of a repository revision
322
322
323 By default, the revision used is the parent of the working
323 By default, the revision used is the parent of the working
324 directory; use -r/--rev to specify a different revision.
324 directory; use -r/--rev to specify a different revision.
325
325
326 The archive type is automatically detected based on file
326 The archive type is automatically detected based on file
327 extension (or override using -t/--type).
327 extension (or override using -t/--type).
328
328
329 .. container:: verbose
329 .. container:: verbose
330
330
331 Examples:
331 Examples:
332
332
333 - create a zip file containing the 1.0 release::
333 - create a zip file containing the 1.0 release::
334
334
335 hg archive -r 1.0 project-1.0.zip
335 hg archive -r 1.0 project-1.0.zip
336
336
337 - create a tarball excluding .hg files::
337 - create a tarball excluding .hg files::
338
338
339 hg archive project.tar.gz -X ".hg*"
339 hg archive project.tar.gz -X ".hg*"
340
340
341 Valid types are:
341 Valid types are:
342
342
343 :``files``: a directory full of files (default)
343 :``files``: a directory full of files (default)
344 :``tar``: tar archive, uncompressed
344 :``tar``: tar archive, uncompressed
345 :``tbz2``: tar archive, compressed using bzip2
345 :``tbz2``: tar archive, compressed using bzip2
346 :``tgz``: tar archive, compressed using gzip
346 :``tgz``: tar archive, compressed using gzip
347 :``uzip``: zip archive, uncompressed
347 :``uzip``: zip archive, uncompressed
348 :``zip``: zip archive, compressed using deflate
348 :``zip``: zip archive, compressed using deflate
349
349
350 The exact name of the destination archive or directory is given
350 The exact name of the destination archive or directory is given
351 using a format string; see :hg:`help export` for details.
351 using a format string; see :hg:`help export` for details.
352
352
353 Each member added to an archive file has a directory prefix
353 Each member added to an archive file has a directory prefix
354 prepended. Use -p/--prefix to specify a format string for the
354 prepended. Use -p/--prefix to specify a format string for the
355 prefix. The default is the basename of the archive, with suffixes
355 prefix. The default is the basename of the archive, with suffixes
356 removed.
356 removed.
357
357
358 Returns 0 on success.
358 Returns 0 on success.
359 '''
359 '''
360
360
361 ctx = scmutil.revsingle(repo, opts.get('rev'))
361 ctx = scmutil.revsingle(repo, opts.get('rev'))
362 if not ctx:
362 if not ctx:
363 raise util.Abort(_('no working directory: please specify a revision'))
363 raise util.Abort(_('no working directory: please specify a revision'))
364 node = ctx.node()
364 node = ctx.node()
365 dest = cmdutil.makefilename(repo, dest, node)
365 dest = cmdutil.makefilename(repo, dest, node)
366 if os.path.realpath(dest) == repo.root:
366 if os.path.realpath(dest) == repo.root:
367 raise util.Abort(_('repository root cannot be destination'))
367 raise util.Abort(_('repository root cannot be destination'))
368
368
369 kind = opts.get('type') or archival.guesskind(dest) or 'files'
369 kind = opts.get('type') or archival.guesskind(dest) or 'files'
370 prefix = opts.get('prefix')
370 prefix = opts.get('prefix')
371
371
372 if dest == '-':
372 if dest == '-':
373 if kind == 'files':
373 if kind == 'files':
374 raise util.Abort(_('cannot archive plain files to stdout'))
374 raise util.Abort(_('cannot archive plain files to stdout'))
375 dest = cmdutil.makefileobj(repo, dest)
375 dest = cmdutil.makefileobj(repo, dest)
376 if not prefix:
376 if not prefix:
377 prefix = os.path.basename(repo.root) + '-%h'
377 prefix = os.path.basename(repo.root) + '-%h'
378
378
379 prefix = cmdutil.makefilename(repo, prefix, node)
379 prefix = cmdutil.makefilename(repo, prefix, node)
380 matchfn = scmutil.match(ctx, [], opts)
380 matchfn = scmutil.match(ctx, [], opts)
381 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
381 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
382 matchfn, prefix, subrepos=opts.get('subrepos'))
382 matchfn, prefix, subrepos=opts.get('subrepos'))
383
383
384 @command('backout',
384 @command('backout',
385 [('', 'merge', None, _('merge with old dirstate parent after backout')),
385 [('', 'merge', None, _('merge with old dirstate parent after backout')),
386 ('', 'parent', '',
386 ('', 'parent', '',
387 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
387 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
388 ('r', 'rev', '', _('revision to backout'), _('REV')),
388 ('r', 'rev', '', _('revision to backout'), _('REV')),
389 ] + mergetoolopts + walkopts + commitopts + commitopts2,
389 ] + mergetoolopts + walkopts + commitopts + commitopts2,
390 _('[OPTION]... [-r] REV'))
390 _('[OPTION]... [-r] REV'))
391 def backout(ui, repo, node=None, rev=None, **opts):
391 def backout(ui, repo, node=None, rev=None, **opts):
392 '''reverse effect of earlier changeset
392 '''reverse effect of earlier changeset
393
393
394 Prepare a new changeset with the effect of REV undone in the
394 Prepare a new changeset with the effect of REV undone in the
395 current working directory.
395 current working directory.
396
396
397 If REV is the parent of the working directory, then this new changeset
397 If REV is the parent of the working directory, then this new changeset
398 is committed automatically. Otherwise, hg needs to merge the
398 is committed automatically. Otherwise, hg needs to merge the
399 changes and the merged result is left uncommitted.
399 changes and the merged result is left uncommitted.
400
400
401 .. note::
401 .. note::
402
402
403 backout cannot be used to fix either an unwanted or
403 backout cannot be used to fix either an unwanted or
404 incorrect merge.
404 incorrect merge.
405
405
406 .. container:: verbose
406 .. container:: verbose
407
407
408 By default, the pending changeset will have one parent,
408 By default, the pending changeset will have one parent,
409 maintaining a linear history. With --merge, the pending
409 maintaining a linear history. With --merge, the pending
410 changeset will instead have two parents: the old parent of the
410 changeset will instead have two parents: the old parent of the
411 working directory and a new child of REV that simply undoes REV.
411 working directory and a new child of REV that simply undoes REV.
412
412
413 Before version 1.7, the behavior without --merge was equivalent
413 Before version 1.7, the behavior without --merge was equivalent
414 to specifying --merge followed by :hg:`update --clean .` to
414 to specifying --merge followed by :hg:`update --clean .` to
415 cancel the merge and leave the child of REV as a head to be
415 cancel the merge and leave the child of REV as a head to be
416 merged separately.
416 merged separately.
417
417
418 See :hg:`help dates` for a list of formats valid for -d/--date.
418 See :hg:`help dates` for a list of formats valid for -d/--date.
419
419
420 Returns 0 on success, 1 if nothing to backout or there are unresolved
420 Returns 0 on success, 1 if nothing to backout or there are unresolved
421 files.
421 files.
422 '''
422 '''
423 if rev and node:
423 if rev and node:
424 raise util.Abort(_("please specify just one revision"))
424 raise util.Abort(_("please specify just one revision"))
425
425
426 if not rev:
426 if not rev:
427 rev = node
427 rev = node
428
428
429 if not rev:
429 if not rev:
430 raise util.Abort(_("please specify a revision to backout"))
430 raise util.Abort(_("please specify a revision to backout"))
431
431
432 date = opts.get('date')
432 date = opts.get('date')
433 if date:
433 if date:
434 opts['date'] = util.parsedate(date)
434 opts['date'] = util.parsedate(date)
435
435
436 cmdutil.checkunfinished(repo)
436 cmdutil.checkunfinished(repo)
437 cmdutil.bailifchanged(repo)
437 cmdutil.bailifchanged(repo)
438 node = scmutil.revsingle(repo, rev).node()
438 node = scmutil.revsingle(repo, rev).node()
439
439
440 op1, op2 = repo.dirstate.parents()
440 op1, op2 = repo.dirstate.parents()
441 if node not in repo.changelog.commonancestors(op1, node):
441 if node not in repo.changelog.commonancestors(op1, node):
442 raise util.Abort(_('cannot backout change that is not an ancestor'))
442 raise util.Abort(_('cannot backout change that is not an ancestor'))
443
443
444 p1, p2 = repo.changelog.parents(node)
444 p1, p2 = repo.changelog.parents(node)
445 if p1 == nullid:
445 if p1 == nullid:
446 raise util.Abort(_('cannot backout a change with no parents'))
446 raise util.Abort(_('cannot backout a change with no parents'))
447 if p2 != nullid:
447 if p2 != nullid:
448 if not opts.get('parent'):
448 if not opts.get('parent'):
449 raise util.Abort(_('cannot backout a merge changeset'))
449 raise util.Abort(_('cannot backout a merge changeset'))
450 p = repo.lookup(opts['parent'])
450 p = repo.lookup(opts['parent'])
451 if p not in (p1, p2):
451 if p not in (p1, p2):
452 raise util.Abort(_('%s is not a parent of %s') %
452 raise util.Abort(_('%s is not a parent of %s') %
453 (short(p), short(node)))
453 (short(p), short(node)))
454 parent = p
454 parent = p
455 else:
455 else:
456 if opts.get('parent'):
456 if opts.get('parent'):
457 raise util.Abort(_('cannot use --parent on non-merge changeset'))
457 raise util.Abort(_('cannot use --parent on non-merge changeset'))
458 parent = p1
458 parent = p1
459
459
460 # the backout should appear on the same branch
460 # the backout should appear on the same branch
461 wlock = repo.wlock()
461 wlock = repo.wlock()
462 try:
462 try:
463 branch = repo.dirstate.branch()
463 branch = repo.dirstate.branch()
464 bheads = repo.branchheads(branch)
464 bheads = repo.branchheads(branch)
465 rctx = scmutil.revsingle(repo, hex(parent))
465 rctx = scmutil.revsingle(repo, hex(parent))
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 'backout')
469 'backout')
470 stats = mergemod.update(repo, parent, True, True, False,
470 stats = mergemod.update(repo, parent, True, True, False,
471 node, False)
471 node, False)
472 repo.setparents(op1, op2)
472 repo.setparents(op1, op2)
473 hg._showstats(repo, stats)
473 hg._showstats(repo, stats)
474 if stats[3]:
474 if stats[3]:
475 repo.ui.status(_("use 'hg resolve' to retry unresolved "
475 repo.ui.status(_("use 'hg resolve' to retry unresolved "
476 "file merges\n"))
476 "file merges\n"))
477 else:
477 else:
478 msg = _("changeset %s backed out, "
478 msg = _("changeset %s backed out, "
479 "don't forget to commit.\n")
479 "don't forget to commit.\n")
480 ui.status(msg % short(node))
480 ui.status(msg % short(node))
481 return stats[3] > 0
481 return stats[3] > 0
482 finally:
482 finally:
483 ui.setconfig('ui', 'forcemerge', '', '')
483 ui.setconfig('ui', 'forcemerge', '', '')
484 else:
484 else:
485 hg.clean(repo, node, show_stats=False)
485 hg.clean(repo, node, show_stats=False)
486 repo.dirstate.setbranch(branch)
486 repo.dirstate.setbranch(branch)
487 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
487 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
488
488
489
489
490 e = cmdutil.commiteditor
490 e = cmdutil.commiteditor
491 if not opts['message'] and not opts['logfile']:
491 if not opts['message'] and not opts['logfile']:
492 # we don't translate commit messages
492 # we don't translate commit messages
493 opts['message'] = "Backed out changeset %s" % short(node)
493 opts['message'] = "Backed out changeset %s" % short(node)
494 e = cmdutil.commitforceeditor
494 e = cmdutil.commitforceeditor
495
495
496 def commitfunc(ui, repo, message, match, opts):
496 def commitfunc(ui, repo, message, match, opts):
497 return repo.commit(message, opts.get('user'), opts.get('date'),
497 return repo.commit(message, opts.get('user'), opts.get('date'),
498 match, editor=e)
498 match, editor=e)
499 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
499 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
500 if not newnode:
500 if not newnode:
501 ui.status(_("nothing changed\n"))
501 ui.status(_("nothing changed\n"))
502 return 1
502 return 1
503 cmdutil.commitstatus(repo, newnode, branch, bheads)
503 cmdutil.commitstatus(repo, newnode, branch, bheads)
504
504
505 def nice(node):
505 def nice(node):
506 return '%d:%s' % (repo.changelog.rev(node), short(node))
506 return '%d:%s' % (repo.changelog.rev(node), short(node))
507 ui.status(_('changeset %s backs out changeset %s\n') %
507 ui.status(_('changeset %s backs out changeset %s\n') %
508 (nice(repo.changelog.tip()), nice(node)))
508 (nice(repo.changelog.tip()), nice(node)))
509 if opts.get('merge') and op1 != node:
509 if opts.get('merge') and op1 != node:
510 hg.clean(repo, op1, show_stats=False)
510 hg.clean(repo, op1, show_stats=False)
511 ui.status(_('merging with changeset %s\n')
511 ui.status(_('merging with changeset %s\n')
512 % nice(repo.changelog.tip()))
512 % nice(repo.changelog.tip()))
513 try:
513 try:
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
514 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
515 'backout')
515 'backout')
516 return hg.merge(repo, hex(repo.changelog.tip()))
516 return hg.merge(repo, hex(repo.changelog.tip()))
517 finally:
517 finally:
518 ui.setconfig('ui', 'forcemerge', '', '')
518 ui.setconfig('ui', 'forcemerge', '', '')
519 finally:
519 finally:
520 wlock.release()
520 wlock.release()
521 return 0
521 return 0
522
522
523 @command('bisect',
523 @command('bisect',
524 [('r', 'reset', False, _('reset bisect state')),
524 [('r', 'reset', False, _('reset bisect state')),
525 ('g', 'good', False, _('mark changeset good')),
525 ('g', 'good', False, _('mark changeset good')),
526 ('b', 'bad', False, _('mark changeset bad')),
526 ('b', 'bad', False, _('mark changeset bad')),
527 ('s', 'skip', False, _('skip testing changeset')),
527 ('s', 'skip', False, _('skip testing changeset')),
528 ('e', 'extend', False, _('extend the bisect range')),
528 ('e', 'extend', False, _('extend the bisect range')),
529 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
529 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
530 ('U', 'noupdate', False, _('do not update to target'))],
530 ('U', 'noupdate', False, _('do not update to target'))],
531 _("[-gbsr] [-U] [-c CMD] [REV]"))
531 _("[-gbsr] [-U] [-c CMD] [REV]"))
532 def bisect(ui, repo, rev=None, extra=None, command=None,
532 def bisect(ui, repo, rev=None, extra=None, command=None,
533 reset=None, good=None, bad=None, skip=None, extend=None,
533 reset=None, good=None, bad=None, skip=None, extend=None,
534 noupdate=None):
534 noupdate=None):
535 """subdivision search of changesets
535 """subdivision search of changesets
536
536
537 This command helps to find changesets which introduce problems. To
537 This command helps to find changesets which introduce problems. To
538 use, mark the earliest changeset you know exhibits the problem as
538 use, mark the earliest changeset you know exhibits the problem as
539 bad, then mark the latest changeset which is free from the problem
539 bad, then mark the latest changeset which is free from the problem
540 as good. Bisect will update your working directory to a revision
540 as good. Bisect will update your working directory to a revision
541 for testing (unless the -U/--noupdate option is specified). Once
541 for testing (unless the -U/--noupdate option is specified). Once
542 you have performed tests, mark the working directory as good or
542 you have performed tests, mark the working directory as good or
543 bad, and bisect will either update to another candidate changeset
543 bad, and bisect will either update to another candidate changeset
544 or announce that it has found the bad revision.
544 or announce that it has found the bad revision.
545
545
546 As a shortcut, you can also use the revision argument to mark a
546 As a shortcut, you can also use the revision argument to mark a
547 revision as good or bad without checking it out first.
547 revision as good or bad without checking it out first.
548
548
549 If you supply a command, it will be used for automatic bisection.
549 If you supply a command, it will be used for automatic bisection.
550 The environment variable HG_NODE will contain the ID of the
550 The environment variable HG_NODE will contain the ID of the
551 changeset being tested. The exit status of the command will be
551 changeset being tested. The exit status of the command will be
552 used to mark revisions as good or bad: status 0 means good, 125
552 used to mark revisions as good or bad: status 0 means good, 125
553 means to skip the revision, 127 (command not found) will abort the
553 means to skip the revision, 127 (command not found) will abort the
554 bisection, and any other non-zero exit status means the revision
554 bisection, and any other non-zero exit status means the revision
555 is bad.
555 is bad.
556
556
557 .. container:: verbose
557 .. container:: verbose
558
558
559 Some examples:
559 Some examples:
560
560
561 - start a bisection with known bad revision 34, and good revision 12::
561 - start a bisection with known bad revision 34, and good revision 12::
562
562
563 hg bisect --bad 34
563 hg bisect --bad 34
564 hg bisect --good 12
564 hg bisect --good 12
565
565
566 - advance the current bisection by marking current revision as good or
566 - advance the current bisection by marking current revision as good or
567 bad::
567 bad::
568
568
569 hg bisect --good
569 hg bisect --good
570 hg bisect --bad
570 hg bisect --bad
571
571
572 - mark the current revision, or a known revision, to be skipped (e.g. if
572 - mark the current revision, or a known revision, to be skipped (e.g. if
573 that revision is not usable because of another issue)::
573 that revision is not usable because of another issue)::
574
574
575 hg bisect --skip
575 hg bisect --skip
576 hg bisect --skip 23
576 hg bisect --skip 23
577
577
578 - skip all revisions that do not touch directories ``foo`` or ``bar``::
578 - skip all revisions that do not touch directories ``foo`` or ``bar``::
579
579
580 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
580 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
581
581
582 - forget the current bisection::
582 - forget the current bisection::
583
583
584 hg bisect --reset
584 hg bisect --reset
585
585
586 - use 'make && make tests' to automatically find the first broken
586 - use 'make && make tests' to automatically find the first broken
587 revision::
587 revision::
588
588
589 hg bisect --reset
589 hg bisect --reset
590 hg bisect --bad 34
590 hg bisect --bad 34
591 hg bisect --good 12
591 hg bisect --good 12
592 hg bisect --command "make && make tests"
592 hg bisect --command "make && make tests"
593
593
594 - see all changesets whose states are already known in the current
594 - see all changesets whose states are already known in the current
595 bisection::
595 bisection::
596
596
597 hg log -r "bisect(pruned)"
597 hg log -r "bisect(pruned)"
598
598
599 - see the changeset currently being bisected (especially useful
599 - see the changeset currently being bisected (especially useful
600 if running with -U/--noupdate)::
600 if running with -U/--noupdate)::
601
601
602 hg log -r "bisect(current)"
602 hg log -r "bisect(current)"
603
603
604 - see all changesets that took part in the current bisection::
604 - see all changesets that took part in the current bisection::
605
605
606 hg log -r "bisect(range)"
606 hg log -r "bisect(range)"
607
607
608 - you can even get a nice graph::
608 - you can even get a nice graph::
609
609
610 hg log --graph -r "bisect(range)"
610 hg log --graph -r "bisect(range)"
611
611
612 See :hg:`help revsets` for more about the `bisect()` keyword.
612 See :hg:`help revsets` for more about the `bisect()` keyword.
613
613
614 Returns 0 on success.
614 Returns 0 on success.
615 """
615 """
616 def extendbisectrange(nodes, good):
616 def extendbisectrange(nodes, good):
617 # bisect is incomplete when it ends on a merge node and
617 # bisect is incomplete when it ends on a merge node and
618 # one of the parent was not checked.
618 # one of the parent was not checked.
619 parents = repo[nodes[0]].parents()
619 parents = repo[nodes[0]].parents()
620 if len(parents) > 1:
620 if len(parents) > 1:
621 side = good and state['bad'] or state['good']
621 side = good and state['bad'] or state['good']
622 num = len(set(i.node() for i in parents) & set(side))
622 num = len(set(i.node() for i in parents) & set(side))
623 if num == 1:
623 if num == 1:
624 return parents[0].ancestor(parents[1])
624 return parents[0].ancestor(parents[1])
625 return None
625 return None
626
626
627 def print_result(nodes, good):
627 def print_result(nodes, good):
628 displayer = cmdutil.show_changeset(ui, repo, {})
628 displayer = cmdutil.show_changeset(ui, repo, {})
629 if len(nodes) == 1:
629 if len(nodes) == 1:
630 # narrowed it down to a single revision
630 # narrowed it down to a single revision
631 if good:
631 if good:
632 ui.write(_("The first good revision is:\n"))
632 ui.write(_("The first good revision is:\n"))
633 else:
633 else:
634 ui.write(_("The first bad revision is:\n"))
634 ui.write(_("The first bad revision is:\n"))
635 displayer.show(repo[nodes[0]])
635 displayer.show(repo[nodes[0]])
636 extendnode = extendbisectrange(nodes, good)
636 extendnode = extendbisectrange(nodes, good)
637 if extendnode is not None:
637 if extendnode is not None:
638 ui.write(_('Not all ancestors of this changeset have been'
638 ui.write(_('Not all ancestors of this changeset have been'
639 ' checked.\nUse bisect --extend to continue the '
639 ' checked.\nUse bisect --extend to continue the '
640 'bisection from\nthe common ancestor, %s.\n')
640 'bisection from\nthe common ancestor, %s.\n')
641 % extendnode)
641 % extendnode)
642 else:
642 else:
643 # multiple possible revisions
643 # multiple possible revisions
644 if good:
644 if good:
645 ui.write(_("Due to skipped revisions, the first "
645 ui.write(_("Due to skipped revisions, the first "
646 "good revision could be any of:\n"))
646 "good revision could be any of:\n"))
647 else:
647 else:
648 ui.write(_("Due to skipped revisions, the first "
648 ui.write(_("Due to skipped revisions, the first "
649 "bad revision could be any of:\n"))
649 "bad revision could be any of:\n"))
650 for n in nodes:
650 for n in nodes:
651 displayer.show(repo[n])
651 displayer.show(repo[n])
652 displayer.close()
652 displayer.close()
653
653
654 def check_state(state, interactive=True):
654 def check_state(state, interactive=True):
655 if not state['good'] or not state['bad']:
655 if not state['good'] or not state['bad']:
656 if (good or bad or skip or reset) and interactive:
656 if (good or bad or skip or reset) and interactive:
657 return
657 return
658 if not state['good']:
658 if not state['good']:
659 raise util.Abort(_('cannot bisect (no known good revisions)'))
659 raise util.Abort(_('cannot bisect (no known good revisions)'))
660 else:
660 else:
661 raise util.Abort(_('cannot bisect (no known bad revisions)'))
661 raise util.Abort(_('cannot bisect (no known bad revisions)'))
662 return True
662 return True
663
663
664 # backward compatibility
664 # backward compatibility
665 if rev in "good bad reset init".split():
665 if rev in "good bad reset init".split():
666 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
666 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
667 cmd, rev, extra = rev, extra, None
667 cmd, rev, extra = rev, extra, None
668 if cmd == "good":
668 if cmd == "good":
669 good = True
669 good = True
670 elif cmd == "bad":
670 elif cmd == "bad":
671 bad = True
671 bad = True
672 else:
672 else:
673 reset = True
673 reset = True
674 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
674 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
675 raise util.Abort(_('incompatible arguments'))
675 raise util.Abort(_('incompatible arguments'))
676
676
677 cmdutil.checkunfinished(repo)
677 cmdutil.checkunfinished(repo)
678
678
679 if reset:
679 if reset:
680 p = repo.join("bisect.state")
680 p = repo.join("bisect.state")
681 if os.path.exists(p):
681 if os.path.exists(p):
682 os.unlink(p)
682 os.unlink(p)
683 return
683 return
684
684
685 state = hbisect.load_state(repo)
685 state = hbisect.load_state(repo)
686
686
687 if command:
687 if command:
688 changesets = 1
688 changesets = 1
689 if noupdate:
689 if noupdate:
690 try:
690 try:
691 node = state['current'][0]
691 node = state['current'][0]
692 except LookupError:
692 except LookupError:
693 raise util.Abort(_('current bisect revision is unknown - '
693 raise util.Abort(_('current bisect revision is unknown - '
694 'start a new bisect to fix'))
694 'start a new bisect to fix'))
695 else:
695 else:
696 node, p2 = repo.dirstate.parents()
696 node, p2 = repo.dirstate.parents()
697 if p2 != nullid:
697 if p2 != nullid:
698 raise util.Abort(_('current bisect revision is a merge'))
698 raise util.Abort(_('current bisect revision is a merge'))
699 try:
699 try:
700 while changesets:
700 while changesets:
701 # update state
701 # update state
702 state['current'] = [node]
702 state['current'] = [node]
703 hbisect.save_state(repo, state)
703 hbisect.save_state(repo, state)
704 status = util.system(command,
704 status = util.system(command,
705 environ={'HG_NODE': hex(node)},
705 environ={'HG_NODE': hex(node)},
706 out=ui.fout)
706 out=ui.fout)
707 if status == 125:
707 if status == 125:
708 transition = "skip"
708 transition = "skip"
709 elif status == 0:
709 elif status == 0:
710 transition = "good"
710 transition = "good"
711 # status < 0 means process was killed
711 # status < 0 means process was killed
712 elif status == 127:
712 elif status == 127:
713 raise util.Abort(_("failed to execute %s") % command)
713 raise util.Abort(_("failed to execute %s") % command)
714 elif status < 0:
714 elif status < 0:
715 raise util.Abort(_("%s killed") % command)
715 raise util.Abort(_("%s killed") % command)
716 else:
716 else:
717 transition = "bad"
717 transition = "bad"
718 ctx = scmutil.revsingle(repo, rev, node)
718 ctx = scmutil.revsingle(repo, rev, node)
719 rev = None # clear for future iterations
719 rev = None # clear for future iterations
720 state[transition].append(ctx.node())
720 state[transition].append(ctx.node())
721 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
721 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
722 check_state(state, interactive=False)
722 check_state(state, interactive=False)
723 # bisect
723 # bisect
724 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
724 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
725 # update to next check
725 # update to next check
726 node = nodes[0]
726 node = nodes[0]
727 if not noupdate:
727 if not noupdate:
728 cmdutil.bailifchanged(repo)
728 cmdutil.bailifchanged(repo)
729 hg.clean(repo, node, show_stats=False)
729 hg.clean(repo, node, show_stats=False)
730 finally:
730 finally:
731 state['current'] = [node]
731 state['current'] = [node]
732 hbisect.save_state(repo, state)
732 hbisect.save_state(repo, state)
733 print_result(nodes, bgood)
733 print_result(nodes, bgood)
734 return
734 return
735
735
736 # update state
736 # update state
737
737
738 if rev:
738 if rev:
739 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
739 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
740 else:
740 else:
741 nodes = [repo.lookup('.')]
741 nodes = [repo.lookup('.')]
742
742
743 if good or bad or skip:
743 if good or bad or skip:
744 if good:
744 if good:
745 state['good'] += nodes
745 state['good'] += nodes
746 elif bad:
746 elif bad:
747 state['bad'] += nodes
747 state['bad'] += nodes
748 elif skip:
748 elif skip:
749 state['skip'] += nodes
749 state['skip'] += nodes
750 hbisect.save_state(repo, state)
750 hbisect.save_state(repo, state)
751
751
752 if not check_state(state):
752 if not check_state(state):
753 return
753 return
754
754
755 # actually bisect
755 # actually bisect
756 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
756 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
757 if extend:
757 if extend:
758 if not changesets:
758 if not changesets:
759 extendnode = extendbisectrange(nodes, good)
759 extendnode = extendbisectrange(nodes, good)
760 if extendnode is not None:
760 if extendnode is not None:
761 ui.write(_("Extending search to changeset %d:%s\n")
761 ui.write(_("Extending search to changeset %d:%s\n")
762 % (extendnode.rev(), extendnode))
762 % (extendnode.rev(), extendnode))
763 state['current'] = [extendnode.node()]
763 state['current'] = [extendnode.node()]
764 hbisect.save_state(repo, state)
764 hbisect.save_state(repo, state)
765 if noupdate:
765 if noupdate:
766 return
766 return
767 cmdutil.bailifchanged(repo)
767 cmdutil.bailifchanged(repo)
768 return hg.clean(repo, extendnode.node())
768 return hg.clean(repo, extendnode.node())
769 raise util.Abort(_("nothing to extend"))
769 raise util.Abort(_("nothing to extend"))
770
770
771 if changesets == 0:
771 if changesets == 0:
772 print_result(nodes, good)
772 print_result(nodes, good)
773 else:
773 else:
774 assert len(nodes) == 1 # only a single node can be tested next
774 assert len(nodes) == 1 # only a single node can be tested next
775 node = nodes[0]
775 node = nodes[0]
776 # compute the approximate number of remaining tests
776 # compute the approximate number of remaining tests
777 tests, size = 0, 2
777 tests, size = 0, 2
778 while size <= changesets:
778 while size <= changesets:
779 tests, size = tests + 1, size * 2
779 tests, size = tests + 1, size * 2
780 rev = repo.changelog.rev(node)
780 rev = repo.changelog.rev(node)
781 ui.write(_("Testing changeset %d:%s "
781 ui.write(_("Testing changeset %d:%s "
782 "(%d changesets remaining, ~%d tests)\n")
782 "(%d changesets remaining, ~%d tests)\n")
783 % (rev, short(node), changesets, tests))
783 % (rev, short(node), changesets, tests))
784 state['current'] = [node]
784 state['current'] = [node]
785 hbisect.save_state(repo, state)
785 hbisect.save_state(repo, state)
786 if not noupdate:
786 if not noupdate:
787 cmdutil.bailifchanged(repo)
787 cmdutil.bailifchanged(repo)
788 return hg.clean(repo, node)
788 return hg.clean(repo, node)
789
789
790 @command('bookmarks|bookmark',
790 @command('bookmarks|bookmark',
791 [('f', 'force', False, _('force')),
791 [('f', 'force', False, _('force')),
792 ('r', 'rev', '', _('revision'), _('REV')),
792 ('r', 'rev', '', _('revision'), _('REV')),
793 ('d', 'delete', False, _('delete a given bookmark')),
793 ('d', 'delete', False, _('delete a given bookmark')),
794 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
794 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
795 ('i', 'inactive', False, _('mark a bookmark inactive'))],
795 ('i', 'inactive', False, _('mark a bookmark inactive'))],
796 _('hg bookmarks [OPTIONS]... [NAME]...'))
796 _('hg bookmarks [OPTIONS]... [NAME]...'))
797 def bookmark(ui, repo, *names, **opts):
797 def bookmark(ui, repo, *names, **opts):
798 '''track a line of development with movable markers
798 '''track a line of development with movable markers
799
799
800 Bookmarks are pointers to certain commits that move when committing.
800 Bookmarks are pointers to certain commits that move when committing.
801 Bookmarks are local. They can be renamed, copied and deleted. It is
801 Bookmarks are local. They can be renamed, copied and deleted. It is
802 possible to use :hg:`merge NAME` to merge from a given bookmark, and
802 possible to use :hg:`merge NAME` to merge from a given bookmark, and
803 :hg:`update NAME` to update to a given bookmark.
803 :hg:`update NAME` to update to a given bookmark.
804
804
805 You can use :hg:`bookmark NAME` to set a bookmark on the working
805 You can use :hg:`bookmark NAME` to set a bookmark on the working
806 directory's parent revision with the given name. If you specify
806 directory's parent revision with the given name. If you specify
807 a revision using -r REV (where REV may be an existing bookmark),
807 a revision using -r REV (where REV may be an existing bookmark),
808 the bookmark is assigned to that revision.
808 the bookmark is assigned to that revision.
809
809
810 Bookmarks can be pushed and pulled between repositories (see :hg:`help
810 Bookmarks can be pushed and pulled between repositories (see :hg:`help
811 push` and :hg:`help pull`). This requires both the local and remote
811 push` and :hg:`help pull`). This requires both the local and remote
812 repositories to support bookmarks. For versions prior to 1.8, this means
812 repositories to support bookmarks. For versions prior to 1.8, this means
813 the bookmarks extension must be enabled.
813 the bookmarks extension must be enabled.
814
814
815 If you set a bookmark called '@', new clones of the repository will
815 If you set a bookmark called '@', new clones of the repository will
816 have that revision checked out (and the bookmark made active) by
816 have that revision checked out (and the bookmark made active) by
817 default.
817 default.
818
818
819 With -i/--inactive, the new bookmark will not be made the active
819 With -i/--inactive, the new bookmark will not be made the active
820 bookmark. If -r/--rev is given, the new bookmark will not be made
820 bookmark. If -r/--rev is given, the new bookmark will not be made
821 active even if -i/--inactive is not given. If no NAME is given, the
821 active even if -i/--inactive is not given. If no NAME is given, the
822 current active bookmark will be marked inactive.
822 current active bookmark will be marked inactive.
823 '''
823 '''
824 force = opts.get('force')
824 force = opts.get('force')
825 rev = opts.get('rev')
825 rev = opts.get('rev')
826 delete = opts.get('delete')
826 delete = opts.get('delete')
827 rename = opts.get('rename')
827 rename = opts.get('rename')
828 inactive = opts.get('inactive')
828 inactive = opts.get('inactive')
829
829
830 def checkformat(mark):
830 def checkformat(mark):
831 mark = mark.strip()
831 mark = mark.strip()
832 if not mark:
832 if not mark:
833 raise util.Abort(_("bookmark names cannot consist entirely of "
833 raise util.Abort(_("bookmark names cannot consist entirely of "
834 "whitespace"))
834 "whitespace"))
835 scmutil.checknewlabel(repo, mark, 'bookmark')
835 scmutil.checknewlabel(repo, mark, 'bookmark')
836 return mark
836 return mark
837
837
838 def checkconflict(repo, mark, cur, force=False, target=None):
838 def checkconflict(repo, mark, cur, force=False, target=None):
839 if mark in marks and not force:
839 if mark in marks and not force:
840 if target:
840 if target:
841 if marks[mark] == target and target == cur:
841 if marks[mark] == target and target == cur:
842 # re-activating a bookmark
842 # re-activating a bookmark
843 return
843 return
844 anc = repo.changelog.ancestors([repo[target].rev()])
844 anc = repo.changelog.ancestors([repo[target].rev()])
845 bmctx = repo[marks[mark]]
845 bmctx = repo[marks[mark]]
846 divs = [repo[b].node() for b in marks
846 divs = [repo[b].node() for b in marks
847 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
847 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
848
848
849 # allow resolving a single divergent bookmark even if moving
849 # allow resolving a single divergent bookmark even if moving
850 # the bookmark across branches when a revision is specified
850 # the bookmark across branches when a revision is specified
851 # that contains a divergent bookmark
851 # that contains a divergent bookmark
852 if bmctx.rev() not in anc and target in divs:
852 if bmctx.rev() not in anc and target in divs:
853 bookmarks.deletedivergent(repo, [target], mark)
853 bookmarks.deletedivergent(repo, [target], mark)
854 return
854 return
855
855
856 deletefrom = [b for b in divs
856 deletefrom = [b for b in divs
857 if repo[b].rev() in anc or b == target]
857 if repo[b].rev() in anc or b == target]
858 bookmarks.deletedivergent(repo, deletefrom, mark)
858 bookmarks.deletedivergent(repo, deletefrom, mark)
859 if bookmarks.validdest(repo, bmctx, repo[target]):
859 if bookmarks.validdest(repo, bmctx, repo[target]):
860 ui.status(_("moving bookmark '%s' forward from %s\n") %
860 ui.status(_("moving bookmark '%s' forward from %s\n") %
861 (mark, short(bmctx.node())))
861 (mark, short(bmctx.node())))
862 return
862 return
863 raise util.Abort(_("bookmark '%s' already exists "
863 raise util.Abort(_("bookmark '%s' already exists "
864 "(use -f to force)") % mark)
864 "(use -f to force)") % mark)
865 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
865 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
866 and not force):
866 and not force):
867 raise util.Abort(
867 raise util.Abort(
868 _("a bookmark cannot have the name of an existing branch"))
868 _("a bookmark cannot have the name of an existing branch"))
869
869
870 if delete and rename:
870 if delete and rename:
871 raise util.Abort(_("--delete and --rename are incompatible"))
871 raise util.Abort(_("--delete and --rename are incompatible"))
872 if delete and rev:
872 if delete and rev:
873 raise util.Abort(_("--rev is incompatible with --delete"))
873 raise util.Abort(_("--rev is incompatible with --delete"))
874 if rename and rev:
874 if rename and rev:
875 raise util.Abort(_("--rev is incompatible with --rename"))
875 raise util.Abort(_("--rev is incompatible with --rename"))
876 if not names and (delete or rev):
876 if not names and (delete or rev):
877 raise util.Abort(_("bookmark name required"))
877 raise util.Abort(_("bookmark name required"))
878
878
879 if delete or rename or names or inactive:
879 if delete or rename or names or inactive:
880 wlock = repo.wlock()
880 wlock = repo.wlock()
881 try:
881 try:
882 cur = repo.changectx('.').node()
882 cur = repo.changectx('.').node()
883 marks = repo._bookmarks
883 marks = repo._bookmarks
884 if delete:
884 if delete:
885 for mark in names:
885 for mark in names:
886 if mark not in marks:
886 if mark not in marks:
887 raise util.Abort(_("bookmark '%s' does not exist") %
887 raise util.Abort(_("bookmark '%s' does not exist") %
888 mark)
888 mark)
889 if mark == repo._bookmarkcurrent:
889 if mark == repo._bookmarkcurrent:
890 bookmarks.unsetcurrent(repo)
890 bookmarks.unsetcurrent(repo)
891 del marks[mark]
891 del marks[mark]
892 marks.write()
892 marks.write()
893
893
894 elif rename:
894 elif rename:
895 if not names:
895 if not names:
896 raise util.Abort(_("new bookmark name required"))
896 raise util.Abort(_("new bookmark name required"))
897 elif len(names) > 1:
897 elif len(names) > 1:
898 raise util.Abort(_("only one new bookmark name allowed"))
898 raise util.Abort(_("only one new bookmark name allowed"))
899 mark = checkformat(names[0])
899 mark = checkformat(names[0])
900 if rename not in marks:
900 if rename not in marks:
901 raise util.Abort(_("bookmark '%s' does not exist") % rename)
901 raise util.Abort(_("bookmark '%s' does not exist") % rename)
902 checkconflict(repo, mark, cur, force)
902 checkconflict(repo, mark, cur, force)
903 marks[mark] = marks[rename]
903 marks[mark] = marks[rename]
904 if repo._bookmarkcurrent == rename and not inactive:
904 if repo._bookmarkcurrent == rename and not inactive:
905 bookmarks.setcurrent(repo, mark)
905 bookmarks.setcurrent(repo, mark)
906 del marks[rename]
906 del marks[rename]
907 marks.write()
907 marks.write()
908
908
909 elif names:
909 elif names:
910 newact = None
910 newact = None
911 for mark in names:
911 for mark in names:
912 mark = checkformat(mark)
912 mark = checkformat(mark)
913 if newact is None:
913 if newact is None:
914 newact = mark
914 newact = mark
915 if inactive and mark == repo._bookmarkcurrent:
915 if inactive and mark == repo._bookmarkcurrent:
916 bookmarks.unsetcurrent(repo)
916 bookmarks.unsetcurrent(repo)
917 return
917 return
918 tgt = cur
918 tgt = cur
919 if rev:
919 if rev:
920 tgt = scmutil.revsingle(repo, rev).node()
920 tgt = scmutil.revsingle(repo, rev).node()
921 checkconflict(repo, mark, cur, force, tgt)
921 checkconflict(repo, mark, cur, force, tgt)
922 marks[mark] = tgt
922 marks[mark] = tgt
923 if not inactive and cur == marks[newact] and not rev:
923 if not inactive and cur == marks[newact] and not rev:
924 bookmarks.setcurrent(repo, newact)
924 bookmarks.setcurrent(repo, newact)
925 elif cur != tgt and newact == repo._bookmarkcurrent:
925 elif cur != tgt and newact == repo._bookmarkcurrent:
926 bookmarks.unsetcurrent(repo)
926 bookmarks.unsetcurrent(repo)
927 marks.write()
927 marks.write()
928
928
929 elif inactive:
929 elif inactive:
930 if len(marks) == 0:
930 if len(marks) == 0:
931 ui.status(_("no bookmarks set\n"))
931 ui.status(_("no bookmarks set\n"))
932 elif not repo._bookmarkcurrent:
932 elif not repo._bookmarkcurrent:
933 ui.status(_("no active bookmark\n"))
933 ui.status(_("no active bookmark\n"))
934 else:
934 else:
935 bookmarks.unsetcurrent(repo)
935 bookmarks.unsetcurrent(repo)
936 finally:
936 finally:
937 wlock.release()
937 wlock.release()
938 else: # show bookmarks
938 else: # show bookmarks
939 hexfn = ui.debugflag and hex or short
939 hexfn = ui.debugflag and hex or short
940 marks = repo._bookmarks
940 marks = repo._bookmarks
941 if len(marks) == 0:
941 if len(marks) == 0:
942 ui.status(_("no bookmarks set\n"))
942 ui.status(_("no bookmarks set\n"))
943 else:
943 else:
944 for bmark, n in sorted(marks.iteritems()):
944 for bmark, n in sorted(marks.iteritems()):
945 current = repo._bookmarkcurrent
945 current = repo._bookmarkcurrent
946 if bmark == current:
946 if bmark == current:
947 prefix, label = '*', 'bookmarks.current'
947 prefix, label = '*', 'bookmarks.current'
948 else:
948 else:
949 prefix, label = ' ', ''
949 prefix, label = ' ', ''
950
950
951 if ui.quiet:
951 if ui.quiet:
952 ui.write("%s\n" % bmark, label=label)
952 ui.write("%s\n" % bmark, label=label)
953 else:
953 else:
954 ui.write(" %s %-25s %d:%s\n" % (
954 ui.write(" %s %-25s %d:%s\n" % (
955 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
955 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
956 label=label)
956 label=label)
957
957
958 @command('branch',
958 @command('branch',
959 [('f', 'force', None,
959 [('f', 'force', None,
960 _('set branch name even if it shadows an existing branch')),
960 _('set branch name even if it shadows an existing branch')),
961 ('C', 'clean', None, _('reset branch name to parent branch name'))],
961 ('C', 'clean', None, _('reset branch name to parent branch name'))],
962 _('[-fC] [NAME]'))
962 _('[-fC] [NAME]'))
963 def branch(ui, repo, label=None, **opts):
963 def branch(ui, repo, label=None, **opts):
964 """set or show the current branch name
964 """set or show the current branch name
965
965
966 .. note::
966 .. note::
967
967
968 Branch names are permanent and global. Use :hg:`bookmark` to create a
968 Branch names are permanent and global. Use :hg:`bookmark` to create a
969 light-weight bookmark instead. See :hg:`help glossary` for more
969 light-weight bookmark instead. See :hg:`help glossary` for more
970 information about named branches and bookmarks.
970 information about named branches and bookmarks.
971
971
972 With no argument, show the current branch name. With one argument,
972 With no argument, show the current branch name. With one argument,
973 set the working directory branch name (the branch will not exist
973 set the working directory branch name (the branch will not exist
974 in the repository until the next commit). Standard practice
974 in the repository until the next commit). Standard practice
975 recommends that primary development take place on the 'default'
975 recommends that primary development take place on the 'default'
976 branch.
976 branch.
977
977
978 Unless -f/--force is specified, branch will not let you set a
978 Unless -f/--force is specified, branch will not let you set a
979 branch name that already exists, even if it's inactive.
979 branch name that already exists, even if it's inactive.
980
980
981 Use -C/--clean to reset the working directory branch to that of
981 Use -C/--clean to reset the working directory branch to that of
982 the parent of the working directory, negating a previous branch
982 the parent of the working directory, negating a previous branch
983 change.
983 change.
984
984
985 Use the command :hg:`update` to switch to an existing branch. Use
985 Use the command :hg:`update` to switch to an existing branch. Use
986 :hg:`commit --close-branch` to mark this branch as closed.
986 :hg:`commit --close-branch` to mark this branch as closed.
987
987
988 Returns 0 on success.
988 Returns 0 on success.
989 """
989 """
990 if label:
990 if label:
991 label = label.strip()
991 label = label.strip()
992
992
993 if not opts.get('clean') and not label:
993 if not opts.get('clean') and not label:
994 ui.write("%s\n" % repo.dirstate.branch())
994 ui.write("%s\n" % repo.dirstate.branch())
995 return
995 return
996
996
997 wlock = repo.wlock()
997 wlock = repo.wlock()
998 try:
998 try:
999 if opts.get('clean'):
999 if opts.get('clean'):
1000 label = repo[None].p1().branch()
1000 label = repo[None].p1().branch()
1001 repo.dirstate.setbranch(label)
1001 repo.dirstate.setbranch(label)
1002 ui.status(_('reset working directory to branch %s\n') % label)
1002 ui.status(_('reset working directory to branch %s\n') % label)
1003 elif label:
1003 elif label:
1004 if not opts.get('force') and label in repo.branchmap():
1004 if not opts.get('force') and label in repo.branchmap():
1005 if label not in [p.branch() for p in repo.parents()]:
1005 if label not in [p.branch() for p in repo.parents()]:
1006 raise util.Abort(_('a branch of the same name already'
1006 raise util.Abort(_('a branch of the same name already'
1007 ' exists'),
1007 ' exists'),
1008 # i18n: "it" refers to an existing branch
1008 # i18n: "it" refers to an existing branch
1009 hint=_("use 'hg update' to switch to it"))
1009 hint=_("use 'hg update' to switch to it"))
1010 scmutil.checknewlabel(repo, label, 'branch')
1010 scmutil.checknewlabel(repo, label, 'branch')
1011 repo.dirstate.setbranch(label)
1011 repo.dirstate.setbranch(label)
1012 ui.status(_('marked working directory as branch %s\n') % label)
1012 ui.status(_('marked working directory as branch %s\n') % label)
1013 ui.status(_('(branches are permanent and global, '
1013 ui.status(_('(branches are permanent and global, '
1014 'did you want a bookmark?)\n'))
1014 'did you want a bookmark?)\n'))
1015 finally:
1015 finally:
1016 wlock.release()
1016 wlock.release()
1017
1017
1018 @command('branches',
1018 @command('branches',
1019 [('a', 'active', False, _('show only branches that have unmerged heads')),
1019 [('a', 'active', False, _('show only branches that have unmerged heads')),
1020 ('c', 'closed', False, _('show normal and closed branches'))],
1020 ('c', 'closed', False, _('show normal and closed branches'))],
1021 _('[-ac]'))
1021 _('[-ac]'))
1022 def branches(ui, repo, active=False, closed=False):
1022 def branches(ui, repo, active=False, closed=False):
1023 """list repository named branches
1023 """list repository named branches
1024
1024
1025 List the repository's named branches, indicating which ones are
1025 List the repository's named branches, indicating which ones are
1026 inactive. If -c/--closed is specified, also list branches which have
1026 inactive. If -c/--closed is specified, also list branches which have
1027 been marked closed (see :hg:`commit --close-branch`).
1027 been marked closed (see :hg:`commit --close-branch`).
1028
1028
1029 If -a/--active is specified, only show active branches. A branch
1029 If -a/--active is specified, only show active branches. A branch
1030 is considered active if it contains repository heads.
1030 is considered active if it contains repository heads.
1031
1031
1032 Use the command :hg:`update` to switch to an existing branch.
1032 Use the command :hg:`update` to switch to an existing branch.
1033
1033
1034 Returns 0.
1034 Returns 0.
1035 """
1035 """
1036
1036
1037 hexfunc = ui.debugflag and hex or short
1037 hexfunc = ui.debugflag and hex or short
1038
1038
1039 allheads = set(repo.heads())
1039 allheads = set(repo.heads())
1040 branches = []
1040 branches = []
1041 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1041 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1042 isactive = not isclosed and bool(set(heads) & allheads)
1042 isactive = not isclosed and bool(set(heads) & allheads)
1043 branches.append((tag, repo[tip], isactive, not isclosed))
1043 branches.append((tag, repo[tip], isactive, not isclosed))
1044 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1044 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1045 reverse=True)
1045 reverse=True)
1046
1046
1047 for tag, ctx, isactive, isopen in branches:
1047 for tag, ctx, isactive, isopen in branches:
1048 if (not active) or isactive:
1048 if (not active) or isactive:
1049 if isactive:
1049 if isactive:
1050 label = 'branches.active'
1050 label = 'branches.active'
1051 notice = ''
1051 notice = ''
1052 elif not isopen:
1052 elif not isopen:
1053 if not closed:
1053 if not closed:
1054 continue
1054 continue
1055 label = 'branches.closed'
1055 label = 'branches.closed'
1056 notice = _(' (closed)')
1056 notice = _(' (closed)')
1057 else:
1057 else:
1058 label = 'branches.inactive'
1058 label = 'branches.inactive'
1059 notice = _(' (inactive)')
1059 notice = _(' (inactive)')
1060 if tag == repo.dirstate.branch():
1060 if tag == repo.dirstate.branch():
1061 label = 'branches.current'
1061 label = 'branches.current'
1062 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1062 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1063 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1063 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1064 'log.changeset changeset.%s' % ctx.phasestr())
1064 'log.changeset changeset.%s' % ctx.phasestr())
1065 labeledtag = ui.label(tag, label)
1065 labeledtag = ui.label(tag, label)
1066 if ui.quiet:
1066 if ui.quiet:
1067 ui.write("%s\n" % labeledtag)
1067 ui.write("%s\n" % labeledtag)
1068 else:
1068 else:
1069 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1069 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1070
1070
1071 @command('bundle',
1071 @command('bundle',
1072 [('f', 'force', None, _('run even when the destination is unrelated')),
1072 [('f', 'force', None, _('run even when the destination is unrelated')),
1073 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1073 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1074 _('REV')),
1074 _('REV')),
1075 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1075 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1076 _('BRANCH')),
1076 _('BRANCH')),
1077 ('', 'base', [],
1077 ('', 'base', [],
1078 _('a base changeset assumed to be available at the destination'),
1078 _('a base changeset assumed to be available at the destination'),
1079 _('REV')),
1079 _('REV')),
1080 ('a', 'all', None, _('bundle all changesets in the repository')),
1080 ('a', 'all', None, _('bundle all changesets in the repository')),
1081 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1081 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1082 ] + remoteopts,
1082 ] + remoteopts,
1083 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1083 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1084 def bundle(ui, repo, fname, dest=None, **opts):
1084 def bundle(ui, repo, fname, dest=None, **opts):
1085 """create a changegroup file
1085 """create a changegroup file
1086
1086
1087 Generate a compressed changegroup file collecting changesets not
1087 Generate a compressed changegroup file collecting changesets not
1088 known to be in another repository.
1088 known to be in another repository.
1089
1089
1090 If you omit the destination repository, then hg assumes the
1090 If you omit the destination repository, then hg assumes the
1091 destination will have all the nodes you specify with --base
1091 destination will have all the nodes you specify with --base
1092 parameters. To create a bundle containing all changesets, use
1092 parameters. To create a bundle containing all changesets, use
1093 -a/--all (or --base null).
1093 -a/--all (or --base null).
1094
1094
1095 You can change compression method with the -t/--type option.
1095 You can change compression method with the -t/--type option.
1096 The available compression methods are: none, bzip2, and
1096 The available compression methods are: none, bzip2, and
1097 gzip (by default, bundles are compressed using bzip2).
1097 gzip (by default, bundles are compressed using bzip2).
1098
1098
1099 The bundle file can then be transferred using conventional means
1099 The bundle file can then be transferred using conventional means
1100 and applied to another repository with the unbundle or pull
1100 and applied to another repository with the unbundle or pull
1101 command. This is useful when direct push and pull are not
1101 command. This is useful when direct push and pull are not
1102 available or when exporting an entire repository is undesirable.
1102 available or when exporting an entire repository is undesirable.
1103
1103
1104 Applying bundles preserves all changeset contents including
1104 Applying bundles preserves all changeset contents including
1105 permissions, copy/rename information, and revision history.
1105 permissions, copy/rename information, and revision history.
1106
1106
1107 Returns 0 on success, 1 if no changes found.
1107 Returns 0 on success, 1 if no changes found.
1108 """
1108 """
1109 revs = None
1109 revs = None
1110 if 'rev' in opts:
1110 if 'rev' in opts:
1111 revs = scmutil.revrange(repo, opts['rev'])
1111 revs = scmutil.revrange(repo, opts['rev'])
1112
1112
1113 bundletype = opts.get('type', 'bzip2').lower()
1113 bundletype = opts.get('type', 'bzip2').lower()
1114 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1114 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1115 bundletype = btypes.get(bundletype)
1115 bundletype = btypes.get(bundletype)
1116 if bundletype not in changegroup.bundletypes:
1116 if bundletype not in changegroup.bundletypes:
1117 raise util.Abort(_('unknown bundle type specified with --type'))
1117 raise util.Abort(_('unknown bundle type specified with --type'))
1118
1118
1119 if opts.get('all'):
1119 if opts.get('all'):
1120 base = ['null']
1120 base = ['null']
1121 else:
1121 else:
1122 base = scmutil.revrange(repo, opts.get('base'))
1122 base = scmutil.revrange(repo, opts.get('base'))
1123 # TODO: get desired bundlecaps from command line.
1123 # TODO: get desired bundlecaps from command line.
1124 bundlecaps = None
1124 bundlecaps = None
1125 if base:
1125 if base:
1126 if dest:
1126 if dest:
1127 raise util.Abort(_("--base is incompatible with specifying "
1127 raise util.Abort(_("--base is incompatible with specifying "
1128 "a destination"))
1128 "a destination"))
1129 common = [repo.lookup(rev) for rev in base]
1129 common = [repo.lookup(rev) for rev in base]
1130 heads = revs and map(repo.lookup, revs) or revs
1130 heads = revs and map(repo.lookup, revs) or revs
1131 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1131 cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common,
1132 bundlecaps=bundlecaps)
1132 bundlecaps=bundlecaps)
1133 outgoing = None
1133 outgoing = None
1134 else:
1134 else:
1135 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1135 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1136 dest, branches = hg.parseurl(dest, opts.get('branch'))
1136 dest, branches = hg.parseurl(dest, opts.get('branch'))
1137 other = hg.peer(repo, opts, dest)
1137 other = hg.peer(repo, opts, dest)
1138 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1138 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1139 heads = revs and map(repo.lookup, revs) or revs
1139 heads = revs and map(repo.lookup, revs) or revs
1140 outgoing = discovery.findcommonoutgoing(repo, other,
1140 outgoing = discovery.findcommonoutgoing(repo, other,
1141 onlyheads=heads,
1141 onlyheads=heads,
1142 force=opts.get('force'),
1142 force=opts.get('force'),
1143 portable=True)
1143 portable=True)
1144 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1144 cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps)
1145 if not cg:
1145 if not cg:
1146 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1146 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1147 return 1
1147 return 1
1148
1148
1149 changegroup.writebundle(cg, fname, bundletype)
1149 changegroup.writebundle(cg, fname, bundletype)
1150
1150
1151 @command('cat',
1151 @command('cat',
1152 [('o', 'output', '',
1152 [('o', 'output', '',
1153 _('print output to file with formatted name'), _('FORMAT')),
1153 _('print output to file with formatted name'), _('FORMAT')),
1154 ('r', 'rev', '', _('print the given revision'), _('REV')),
1154 ('r', 'rev', '', _('print the given revision'), _('REV')),
1155 ('', 'decode', None, _('apply any matching decode filter')),
1155 ('', 'decode', None, _('apply any matching decode filter')),
1156 ] + walkopts,
1156 ] + walkopts,
1157 _('[OPTION]... FILE...'))
1157 _('[OPTION]... FILE...'))
1158 def cat(ui, repo, file1, *pats, **opts):
1158 def cat(ui, repo, file1, *pats, **opts):
1159 """output the current or given revision of files
1159 """output the current or given revision of files
1160
1160
1161 Print the specified files as they were at the given revision. If
1161 Print the specified files as they were at the given revision. If
1162 no revision is given, the parent of the working directory is used.
1162 no revision is given, the parent of the working directory is used.
1163
1163
1164 Output may be to a file, in which case the name of the file is
1164 Output may be to a file, in which case the name of the file is
1165 given using a format string. The formatting rules are the same as
1165 given using a format string. The formatting rules are the same as
1166 for the export command, with the following additions:
1166 for the export command, with the following additions:
1167
1167
1168 :``%s``: basename of file being printed
1168 :``%s``: basename of file being printed
1169 :``%d``: dirname of file being printed, or '.' if in repository root
1169 :``%d``: dirname of file being printed, or '.' if in repository root
1170 :``%p``: root-relative path name of file being printed
1170 :``%p``: root-relative path name of file being printed
1171
1171
1172 Returns 0 on success.
1172 Returns 0 on success.
1173 """
1173 """
1174 ctx = scmutil.revsingle(repo, opts.get('rev'))
1174 ctx = scmutil.revsingle(repo, opts.get('rev'))
1175 err = 1
1175 err = 1
1176 m = scmutil.match(ctx, (file1,) + pats, opts)
1176 m = scmutil.match(ctx, (file1,) + pats, opts)
1177
1177
1178 def write(path):
1178 def write(path):
1179 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1179 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1180 pathname=path)
1180 pathname=path)
1181 data = ctx[path].data()
1181 data = ctx[path].data()
1182 if opts.get('decode'):
1182 if opts.get('decode'):
1183 data = repo.wwritedata(path, data)
1183 data = repo.wwritedata(path, data)
1184 fp.write(data)
1184 fp.write(data)
1185 fp.close()
1185 fp.close()
1186
1186
1187 # Automation often uses hg cat on single files, so special case it
1187 # Automation often uses hg cat on single files, so special case it
1188 # for performance to avoid the cost of parsing the manifest.
1188 # for performance to avoid the cost of parsing the manifest.
1189 if len(m.files()) == 1 and not m.anypats():
1189 if len(m.files()) == 1 and not m.anypats():
1190 file = m.files()[0]
1190 file = m.files()[0]
1191 mf = repo.manifest
1191 mf = repo.manifest
1192 mfnode = ctx._changeset[0]
1192 mfnode = ctx._changeset[0]
1193 if mf.find(mfnode, file)[0]:
1193 if mf.find(mfnode, file)[0]:
1194 write(file)
1194 write(file)
1195 return 0
1195 return 0
1196
1196
1197 for abs in ctx.walk(m):
1197 for abs in ctx.walk(m):
1198 write(abs)
1198 write(abs)
1199 err = 0
1199 err = 0
1200 return err
1200 return err
1201
1201
1202 @command('^clone',
1202 @command('^clone',
1203 [('U', 'noupdate', None,
1203 [('U', 'noupdate', None,
1204 _('the clone will include an empty working copy (only a repository)')),
1204 _('the clone will include an empty working copy (only a repository)')),
1205 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1205 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1206 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1206 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1207 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1207 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1208 ('', 'pull', None, _('use pull protocol to copy metadata')),
1208 ('', 'pull', None, _('use pull protocol to copy metadata')),
1209 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1209 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1210 ] + remoteopts,
1210 ] + remoteopts,
1211 _('[OPTION]... SOURCE [DEST]'))
1211 _('[OPTION]... SOURCE [DEST]'))
1212 def clone(ui, source, dest=None, **opts):
1212 def clone(ui, source, dest=None, **opts):
1213 """make a copy of an existing repository
1213 """make a copy of an existing repository
1214
1214
1215 Create a copy of an existing repository in a new directory.
1215 Create a copy of an existing repository in a new directory.
1216
1216
1217 If no destination directory name is specified, it defaults to the
1217 If no destination directory name is specified, it defaults to the
1218 basename of the source.
1218 basename of the source.
1219
1219
1220 The location of the source is added to the new repository's
1220 The location of the source is added to the new repository's
1221 ``.hg/hgrc`` file, as the default to be used for future pulls.
1221 ``.hg/hgrc`` file, as the default to be used for future pulls.
1222
1222
1223 Only local paths and ``ssh://`` URLs are supported as
1223 Only local paths and ``ssh://`` URLs are supported as
1224 destinations. For ``ssh://`` destinations, no working directory or
1224 destinations. For ``ssh://`` destinations, no working directory or
1225 ``.hg/hgrc`` will be created on the remote side.
1225 ``.hg/hgrc`` will be created on the remote side.
1226
1226
1227 To pull only a subset of changesets, specify one or more revisions
1227 To pull only a subset of changesets, specify one or more revisions
1228 identifiers with -r/--rev or branches with -b/--branch. The
1228 identifiers with -r/--rev or branches with -b/--branch. The
1229 resulting clone will contain only the specified changesets and
1229 resulting clone will contain only the specified changesets and
1230 their ancestors. These options (or 'clone src#rev dest') imply
1230 their ancestors. These options (or 'clone src#rev dest') imply
1231 --pull, even for local source repositories. Note that specifying a
1231 --pull, even for local source repositories. Note that specifying a
1232 tag will include the tagged changeset but not the changeset
1232 tag will include the tagged changeset but not the changeset
1233 containing the tag.
1233 containing the tag.
1234
1234
1235 If the source repository has a bookmark called '@' set, that
1235 If the source repository has a bookmark called '@' set, that
1236 revision will be checked out in the new repository by default.
1236 revision will be checked out in the new repository by default.
1237
1237
1238 To check out a particular version, use -u/--update, or
1238 To check out a particular version, use -u/--update, or
1239 -U/--noupdate to create a clone with no working directory.
1239 -U/--noupdate to create a clone with no working directory.
1240
1240
1241 .. container:: verbose
1241 .. container:: verbose
1242
1242
1243 For efficiency, hardlinks are used for cloning whenever the
1243 For efficiency, hardlinks are used for cloning whenever the
1244 source and destination are on the same filesystem (note this
1244 source and destination are on the same filesystem (note this
1245 applies only to the repository data, not to the working
1245 applies only to the repository data, not to the working
1246 directory). Some filesystems, such as AFS, implement hardlinking
1246 directory). Some filesystems, such as AFS, implement hardlinking
1247 incorrectly, but do not report errors. In these cases, use the
1247 incorrectly, but do not report errors. In these cases, use the
1248 --pull option to avoid hardlinking.
1248 --pull option to avoid hardlinking.
1249
1249
1250 In some cases, you can clone repositories and the working
1250 In some cases, you can clone repositories and the working
1251 directory using full hardlinks with ::
1251 directory using full hardlinks with ::
1252
1252
1253 $ cp -al REPO REPOCLONE
1253 $ cp -al REPO REPOCLONE
1254
1254
1255 This is the fastest way to clone, but it is not always safe. The
1255 This is the fastest way to clone, but it is not always safe. The
1256 operation is not atomic (making sure REPO is not modified during
1256 operation is not atomic (making sure REPO is not modified during
1257 the operation is up to you) and you have to make sure your
1257 the operation is up to you) and you have to make sure your
1258 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1258 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1259 so). Also, this is not compatible with certain extensions that
1259 so). Also, this is not compatible with certain extensions that
1260 place their metadata under the .hg directory, such as mq.
1260 place their metadata under the .hg directory, such as mq.
1261
1261
1262 Mercurial will update the working directory to the first applicable
1262 Mercurial will update the working directory to the first applicable
1263 revision from this list:
1263 revision from this list:
1264
1264
1265 a) null if -U or the source repository has no changesets
1265 a) null if -U or the source repository has no changesets
1266 b) if -u . and the source repository is local, the first parent of
1266 b) if -u . and the source repository is local, the first parent of
1267 the source repository's working directory
1267 the source repository's working directory
1268 c) the changeset specified with -u (if a branch name, this means the
1268 c) the changeset specified with -u (if a branch name, this means the
1269 latest head of that branch)
1269 latest head of that branch)
1270 d) the changeset specified with -r
1270 d) the changeset specified with -r
1271 e) the tipmost head specified with -b
1271 e) the tipmost head specified with -b
1272 f) the tipmost head specified with the url#branch source syntax
1272 f) the tipmost head specified with the url#branch source syntax
1273 g) the revision marked with the '@' bookmark, if present
1273 g) the revision marked with the '@' bookmark, if present
1274 h) the tipmost head of the default branch
1274 h) the tipmost head of the default branch
1275 i) tip
1275 i) tip
1276
1276
1277 Examples:
1277 Examples:
1278
1278
1279 - clone a remote repository to a new directory named hg/::
1279 - clone a remote repository to a new directory named hg/::
1280
1280
1281 hg clone http://selenic.com/hg
1281 hg clone http://selenic.com/hg
1282
1282
1283 - create a lightweight local clone::
1283 - create a lightweight local clone::
1284
1284
1285 hg clone project/ project-feature/
1285 hg clone project/ project-feature/
1286
1286
1287 - clone from an absolute path on an ssh server (note double-slash)::
1287 - clone from an absolute path on an ssh server (note double-slash)::
1288
1288
1289 hg clone ssh://user@server//home/projects/alpha/
1289 hg clone ssh://user@server//home/projects/alpha/
1290
1290
1291 - do a high-speed clone over a LAN while checking out a
1291 - do a high-speed clone over a LAN while checking out a
1292 specified version::
1292 specified version::
1293
1293
1294 hg clone --uncompressed http://server/repo -u 1.5
1294 hg clone --uncompressed http://server/repo -u 1.5
1295
1295
1296 - create a repository without changesets after a particular revision::
1296 - create a repository without changesets after a particular revision::
1297
1297
1298 hg clone -r 04e544 experimental/ good/
1298 hg clone -r 04e544 experimental/ good/
1299
1299
1300 - clone (and track) a particular named branch::
1300 - clone (and track) a particular named branch::
1301
1301
1302 hg clone http://selenic.com/hg#stable
1302 hg clone http://selenic.com/hg#stable
1303
1303
1304 See :hg:`help urls` for details on specifying URLs.
1304 See :hg:`help urls` for details on specifying URLs.
1305
1305
1306 Returns 0 on success.
1306 Returns 0 on success.
1307 """
1307 """
1308 if opts.get('noupdate') and opts.get('updaterev'):
1308 if opts.get('noupdate') and opts.get('updaterev'):
1309 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1309 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1310
1310
1311 r = hg.clone(ui, opts, source, dest,
1311 r = hg.clone(ui, opts, source, dest,
1312 pull=opts.get('pull'),
1312 pull=opts.get('pull'),
1313 stream=opts.get('uncompressed'),
1313 stream=opts.get('uncompressed'),
1314 rev=opts.get('rev'),
1314 rev=opts.get('rev'),
1315 update=opts.get('updaterev') or not opts.get('noupdate'),
1315 update=opts.get('updaterev') or not opts.get('noupdate'),
1316 branch=opts.get('branch'))
1316 branch=opts.get('branch'))
1317
1317
1318 return r is None
1318 return r is None
1319
1319
1320 @command('^commit|ci',
1320 @command('^commit|ci',
1321 [('A', 'addremove', None,
1321 [('A', 'addremove', None,
1322 _('mark new/missing files as added/removed before committing')),
1322 _('mark new/missing files as added/removed before committing')),
1323 ('', 'close-branch', None,
1323 ('', 'close-branch', None,
1324 _('mark a branch as closed, hiding it from the branch list')),
1324 _('mark a branch as closed, hiding it from the branch list')),
1325 ('', 'amend', None, _('amend the parent of the working dir')),
1325 ('', 'amend', None, _('amend the parent of the working dir')),
1326 ('s', 'secret', None, _('use the secret phase for committing')),
1326 ('s', 'secret', None, _('use the secret phase for committing')),
1327 ('e', 'edit', None,
1327 ('e', 'edit', None,
1328 _('further edit commit message already specified')),
1328 _('further edit commit message already specified')),
1329 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1329 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1330 _('[OPTION]... [FILE]...'))
1330 _('[OPTION]... [FILE]...'))
1331 def commit(ui, repo, *pats, **opts):
1331 def commit(ui, repo, *pats, **opts):
1332 """commit the specified files or all outstanding changes
1332 """commit the specified files or all outstanding changes
1333
1333
1334 Commit changes to the given files into the repository. Unlike a
1334 Commit changes to the given files into the repository. Unlike a
1335 centralized SCM, this operation is a local operation. See
1335 centralized SCM, this operation is a local operation. See
1336 :hg:`push` for a way to actively distribute your changes.
1336 :hg:`push` for a way to actively distribute your changes.
1337
1337
1338 If a list of files is omitted, all changes reported by :hg:`status`
1338 If a list of files is omitted, all changes reported by :hg:`status`
1339 will be committed.
1339 will be committed.
1340
1340
1341 If you are committing the result of a merge, do not provide any
1341 If you are committing the result of a merge, do not provide any
1342 filenames or -I/-X filters.
1342 filenames or -I/-X filters.
1343
1343
1344 If no commit message is specified, Mercurial starts your
1344 If no commit message is specified, Mercurial starts your
1345 configured editor where you can enter a message. In case your
1345 configured editor where you can enter a message. In case your
1346 commit fails, you will find a backup of your message in
1346 commit fails, you will find a backup of your message in
1347 ``.hg/last-message.txt``.
1347 ``.hg/last-message.txt``.
1348
1348
1349 The --amend flag can be used to amend the parent of the
1349 The --amend flag can be used to amend the parent of the
1350 working directory with a new commit that contains the changes
1350 working directory with a new commit that contains the changes
1351 in the parent in addition to those currently reported by :hg:`status`,
1351 in the parent in addition to those currently reported by :hg:`status`,
1352 if there are any. The old commit is stored in a backup bundle in
1352 if there are any. The old commit is stored in a backup bundle in
1353 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1353 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1354 on how to restore it).
1354 on how to restore it).
1355
1355
1356 Message, user and date are taken from the amended commit unless
1356 Message, user and date are taken from the amended commit unless
1357 specified. When a message isn't specified on the command line,
1357 specified. When a message isn't specified on the command line,
1358 the editor will open with the message of the amended commit.
1358 the editor will open with the message of the amended commit.
1359
1359
1360 It is not possible to amend public changesets (see :hg:`help phases`)
1360 It is not possible to amend public changesets (see :hg:`help phases`)
1361 or changesets that have children.
1361 or changesets that have children.
1362
1362
1363 See :hg:`help dates` for a list of formats valid for -d/--date.
1363 See :hg:`help dates` for a list of formats valid for -d/--date.
1364
1364
1365 Returns 0 on success, 1 if nothing changed.
1365 Returns 0 on success, 1 if nothing changed.
1366 """
1366 """
1367 forceeditor = opts.get('force_editor') or opts.get('edit')
1367 forceeditor = opts.get('force_editor') or opts.get('edit')
1368
1368
1369 if opts.get('subrepos'):
1369 if opts.get('subrepos'):
1370 if opts.get('amend'):
1370 if opts.get('amend'):
1371 raise util.Abort(_('cannot amend with --subrepos'))
1371 raise util.Abort(_('cannot amend with --subrepos'))
1372 # Let --subrepos on the command line override config setting.
1372 # Let --subrepos on the command line override config setting.
1373 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1373 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1374
1374
1375 # Save this for restoring it later
1375 # Save this for restoring it later
1376 oldcommitphase = ui.config('phases', 'new-commit')
1376 oldcommitphase = ui.config('phases', 'new-commit')
1377
1377
1378 cmdutil.checkunfinished(repo, commit=True)
1378 cmdutil.checkunfinished(repo, commit=True)
1379
1379
1380 branch = repo[None].branch()
1380 branch = repo[None].branch()
1381 bheads = repo.branchheads(branch)
1381 bheads = repo.branchheads(branch)
1382
1382
1383 extra = {}
1383 extra = {}
1384 if opts.get('close_branch'):
1384 if opts.get('close_branch'):
1385 extra['close'] = 1
1385 extra['close'] = 1
1386
1386
1387 if not bheads:
1387 if not bheads:
1388 raise util.Abort(_('can only close branch heads'))
1388 raise util.Abort(_('can only close branch heads'))
1389 elif opts.get('amend'):
1389 elif opts.get('amend'):
1390 if repo.parents()[0].p1().branch() != branch and \
1390 if repo.parents()[0].p1().branch() != branch and \
1391 repo.parents()[0].p2().branch() != branch:
1391 repo.parents()[0].p2().branch() != branch:
1392 raise util.Abort(_('can only close branch heads'))
1392 raise util.Abort(_('can only close branch heads'))
1393
1393
1394 if opts.get('amend'):
1394 if opts.get('amend'):
1395 if ui.configbool('ui', 'commitsubrepos'):
1395 if ui.configbool('ui', 'commitsubrepos'):
1396 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1396 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1397
1397
1398 old = repo['.']
1398 old = repo['.']
1399 if old.phase() == phases.public:
1399 if old.phase() == phases.public:
1400 raise util.Abort(_('cannot amend public changesets'))
1400 raise util.Abort(_('cannot amend public changesets'))
1401 if len(repo[None].parents()) > 1:
1401 if len(repo[None].parents()) > 1:
1402 raise util.Abort(_('cannot amend while merging'))
1402 raise util.Abort(_('cannot amend while merging'))
1403 if (not obsolete._enabled) and old.children():
1403 if (not obsolete._enabled) and old.children():
1404 raise util.Abort(_('cannot amend changeset with children'))
1404 raise util.Abort(_('cannot amend changeset with children'))
1405
1405
1406 e = cmdutil.commiteditor
1406 e = cmdutil.commiteditor
1407 if forceeditor:
1407 if forceeditor:
1408 e = cmdutil.commitforceeditor
1408 e = cmdutil.commitforceeditor
1409
1409
1410 # commitfunc is used only for temporary amend commit by cmdutil.amend
1410 # commitfunc is used only for temporary amend commit by cmdutil.amend
1411 def commitfunc(ui, repo, message, match, opts):
1411 def commitfunc(ui, repo, message, match, opts):
1412 editor = e
1412 editor = e
1413 # message contains text from -m or -l, if it's empty,
1413 # message contains text from -m or -l, if it's empty,
1414 # open the editor with the old message
1414 # open the editor with the old message
1415 if not message:
1415 if not message:
1416 message = old.description()
1416 message = old.description()
1417 editor = cmdutil.commitforceeditor
1417 editor = cmdutil.commitforceeditor
1418 return repo.commit(message,
1418 return repo.commit(message,
1419 opts.get('user') or old.user(),
1419 opts.get('user') or old.user(),
1420 opts.get('date') or old.date(),
1420 opts.get('date') or old.date(),
1421 match,
1421 match,
1422 editor=editor,
1422 editor=editor,
1423 extra=extra)
1423 extra=extra)
1424
1424
1425 current = repo._bookmarkcurrent
1425 current = repo._bookmarkcurrent
1426 marks = old.bookmarks()
1426 marks = old.bookmarks()
1427 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1427 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1428 if node == old.node():
1428 if node == old.node():
1429 ui.status(_("nothing changed\n"))
1429 ui.status(_("nothing changed\n"))
1430 return 1
1430 return 1
1431 elif marks:
1431 elif marks:
1432 ui.debug('moving bookmarks %r from %s to %s\n' %
1432 ui.debug('moving bookmarks %r from %s to %s\n' %
1433 (marks, old.hex(), hex(node)))
1433 (marks, old.hex(), hex(node)))
1434 newmarks = repo._bookmarks
1434 newmarks = repo._bookmarks
1435 for bm in marks:
1435 for bm in marks:
1436 newmarks[bm] = node
1436 newmarks[bm] = node
1437 if bm == current:
1437 if bm == current:
1438 bookmarks.setcurrent(repo, bm)
1438 bookmarks.setcurrent(repo, bm)
1439 newmarks.write()
1439 newmarks.write()
1440 else:
1440 else:
1441 e = cmdutil.commiteditor
1441 e = cmdutil.commiteditor
1442 if forceeditor:
1442 if forceeditor:
1443 e = cmdutil.commitforceeditor
1443 e = cmdutil.commitforceeditor
1444
1444
1445 def commitfunc(ui, repo, message, match, opts):
1445 def commitfunc(ui, repo, message, match, opts):
1446 try:
1446 try:
1447 if opts.get('secret'):
1447 if opts.get('secret'):
1448 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1448 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1449 # Propagate to subrepos
1449 # Propagate to subrepos
1450 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1450 repo.baseui.setconfig('phases', 'new-commit', 'secret',
1451 'commit')
1451 'commit')
1452
1452
1453 return repo.commit(message, opts.get('user'), opts.get('date'),
1453 return repo.commit(message, opts.get('user'), opts.get('date'),
1454 match, editor=e, extra=extra)
1454 match, editor=e, extra=extra)
1455 finally:
1455 finally:
1456 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1456 ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit')
1457 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1457 repo.baseui.setconfig('phases', 'new-commit', oldcommitphase,
1458 'commit')
1458 'commit')
1459
1459
1460
1460
1461 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1461 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1462
1462
1463 if not node:
1463 if not node:
1464 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1464 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1465 if stat[3]:
1465 if stat[3]:
1466 ui.status(_("nothing changed (%d missing files, see "
1466 ui.status(_("nothing changed (%d missing files, see "
1467 "'hg status')\n") % len(stat[3]))
1467 "'hg status')\n") % len(stat[3]))
1468 else:
1468 else:
1469 ui.status(_("nothing changed\n"))
1469 ui.status(_("nothing changed\n"))
1470 return 1
1470 return 1
1471
1471
1472 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1472 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1473
1473
1474 @command('config|showconfig|debugconfig',
1474 @command('config|showconfig|debugconfig',
1475 [('u', 'untrusted', None, _('show untrusted configuration options')),
1475 [('u', 'untrusted', None, _('show untrusted configuration options')),
1476 ('e', 'edit', None, _('edit user config')),
1476 ('e', 'edit', None, _('edit user config')),
1477 ('l', 'local', None, _('edit repository config')),
1477 ('l', 'local', None, _('edit repository config')),
1478 ('g', 'global', None, _('edit global config'))],
1478 ('g', 'global', None, _('edit global config'))],
1479 _('[-u] [NAME]...'))
1479 _('[-u] [NAME]...'))
1480 def config(ui, repo, *values, **opts):
1480 def config(ui, repo, *values, **opts):
1481 """show combined config settings from all hgrc files
1481 """show combined config settings from all hgrc files
1482
1482
1483 With no arguments, print names and values of all config items.
1483 With no arguments, print names and values of all config items.
1484
1484
1485 With one argument of the form section.name, print just the value
1485 With one argument of the form section.name, print just the value
1486 of that config item.
1486 of that config item.
1487
1487
1488 With multiple arguments, print names and values of all config
1488 With multiple arguments, print names and values of all config
1489 items with matching section names.
1489 items with matching section names.
1490
1490
1491 With --edit, start an editor on the user-level config file. With
1491 With --edit, start an editor on the user-level config file. With
1492 --global, edit the system-wide config file. With --local, edit the
1492 --global, edit the system-wide config file. With --local, edit the
1493 repository-level config file.
1493 repository-level config file.
1494
1494
1495 With --debug, the source (filename and line number) is printed
1495 With --debug, the source (filename and line number) is printed
1496 for each config item.
1496 for each config item.
1497
1497
1498 See :hg:`help config` for more information about config files.
1498 See :hg:`help config` for more information about config files.
1499
1499
1500 Returns 0 on success.
1500 Returns 0 on success.
1501
1501
1502 """
1502 """
1503
1503
1504 if opts.get('edit') or opts.get('local') or opts.get('global'):
1504 if opts.get('edit') or opts.get('local') or opts.get('global'):
1505 if opts.get('local') and opts.get('global'):
1505 if opts.get('local') and opts.get('global'):
1506 raise util.Abort(_("can't use --local and --global together"))
1506 raise util.Abort(_("can't use --local and --global together"))
1507
1507
1508 if opts.get('local'):
1508 if opts.get('local'):
1509 if not repo:
1509 if not repo:
1510 raise util.Abort(_("can't use --local outside a repository"))
1510 raise util.Abort(_("can't use --local outside a repository"))
1511 paths = [repo.join('hgrc')]
1511 paths = [repo.join('hgrc')]
1512 elif opts.get('global'):
1512 elif opts.get('global'):
1513 paths = scmutil.systemrcpath()
1513 paths = scmutil.systemrcpath()
1514 else:
1514 else:
1515 paths = scmutil.userrcpath()
1515 paths = scmutil.userrcpath()
1516
1516
1517 for f in paths:
1517 for f in paths:
1518 if os.path.exists(f):
1518 if os.path.exists(f):
1519 break
1519 break
1520 else:
1520 else:
1521 f = paths[0]
1521 f = paths[0]
1522 fp = open(f, "w")
1522 fp = open(f, "w")
1523 fp.write(
1523 fp.write(
1524 '# example config (see "hg help config" for more info)\n'
1524 '# example config (see "hg help config" for more info)\n'
1525 '\n'
1525 '\n'
1526 '[ui]\n'
1526 '[ui]\n'
1527 '# name and email, e.g.\n'
1527 '# name and email, e.g.\n'
1528 '# username = Jane Doe <jdoe@example.com>\n'
1528 '# username = Jane Doe <jdoe@example.com>\n'
1529 'username =\n'
1529 'username =\n'
1530 '\n'
1530 '\n'
1531 '[extensions]\n'
1531 '[extensions]\n'
1532 '# uncomment these lines to enable some popular extensions\n'
1532 '# uncomment these lines to enable some popular extensions\n'
1533 '# (see "hg help extensions" for more info)\n'
1533 '# (see "hg help extensions" for more info)\n'
1534 '# pager =\n'
1534 '# pager =\n'
1535 '# progress =\n'
1535 '# progress =\n'
1536 '# color =\n')
1536 '# color =\n')
1537 fp.close()
1537 fp.close()
1538
1538
1539 editor = ui.geteditor()
1539 editor = ui.geteditor()
1540 util.system("%s \"%s\"" % (editor, f),
1540 util.system("%s \"%s\"" % (editor, f),
1541 onerr=util.Abort, errprefix=_("edit failed"),
1541 onerr=util.Abort, errprefix=_("edit failed"),
1542 out=ui.fout)
1542 out=ui.fout)
1543 return
1543 return
1544
1544
1545 for f in scmutil.rcpath():
1545 for f in scmutil.rcpath():
1546 ui.debug('read config from: %s\n' % f)
1546 ui.debug('read config from: %s\n' % f)
1547 untrusted = bool(opts.get('untrusted'))
1547 untrusted = bool(opts.get('untrusted'))
1548 if values:
1548 if values:
1549 sections = [v for v in values if '.' not in v]
1549 sections = [v for v in values if '.' not in v]
1550 items = [v for v in values if '.' in v]
1550 items = [v for v in values if '.' in v]
1551 if len(items) > 1 or items and sections:
1551 if len(items) > 1 or items and sections:
1552 raise util.Abort(_('only one config item permitted'))
1552 raise util.Abort(_('only one config item permitted'))
1553 for section, name, value in ui.walkconfig(untrusted=untrusted):
1553 for section, name, value in ui.walkconfig(untrusted=untrusted):
1554 value = str(value).replace('\n', '\\n')
1554 value = str(value).replace('\n', '\\n')
1555 sectname = section + '.' + name
1555 sectname = section + '.' + name
1556 if values:
1556 if values:
1557 for v in values:
1557 for v in values:
1558 if v == section:
1558 if v == section:
1559 ui.debug('%s: ' %
1559 ui.debug('%s: ' %
1560 ui.configsource(section, name, untrusted))
1560 ui.configsource(section, name, untrusted))
1561 ui.write('%s=%s\n' % (sectname, value))
1561 ui.write('%s=%s\n' % (sectname, value))
1562 elif v == sectname:
1562 elif v == sectname:
1563 ui.debug('%s: ' %
1563 ui.debug('%s: ' %
1564 ui.configsource(section, name, untrusted))
1564 ui.configsource(section, name, untrusted))
1565 ui.write(value, '\n')
1565 ui.write(value, '\n')
1566 else:
1566 else:
1567 ui.debug('%s: ' %
1567 ui.debug('%s: ' %
1568 ui.configsource(section, name, untrusted))
1568 ui.configsource(section, name, untrusted))
1569 ui.write('%s=%s\n' % (sectname, value))
1569 ui.write('%s=%s\n' % (sectname, value))
1570
1570
1571 @command('copy|cp',
1571 @command('copy|cp',
1572 [('A', 'after', None, _('record a copy that has already occurred')),
1572 [('A', 'after', None, _('record a copy that has already occurred')),
1573 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1573 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1574 ] + walkopts + dryrunopts,
1574 ] + walkopts + dryrunopts,
1575 _('[OPTION]... [SOURCE]... DEST'))
1575 _('[OPTION]... [SOURCE]... DEST'))
1576 def copy(ui, repo, *pats, **opts):
1576 def copy(ui, repo, *pats, **opts):
1577 """mark files as copied for the next commit
1577 """mark files as copied for the next commit
1578
1578
1579 Mark dest as having copies of source files. If dest is a
1579 Mark dest as having copies of source files. If dest is a
1580 directory, copies are put in that directory. If dest is a file,
1580 directory, copies are put in that directory. If dest is a file,
1581 the source must be a single file.
1581 the source must be a single file.
1582
1582
1583 By default, this command copies the contents of files as they
1583 By default, this command copies the contents of files as they
1584 exist in the working directory. If invoked with -A/--after, the
1584 exist in the working directory. If invoked with -A/--after, the
1585 operation is recorded, but no copying is performed.
1585 operation is recorded, but no copying is performed.
1586
1586
1587 This command takes effect with the next commit. To undo a copy
1587 This command takes effect with the next commit. To undo a copy
1588 before that, see :hg:`revert`.
1588 before that, see :hg:`revert`.
1589
1589
1590 Returns 0 on success, 1 if errors are encountered.
1590 Returns 0 on success, 1 if errors are encountered.
1591 """
1591 """
1592 wlock = repo.wlock(False)
1592 wlock = repo.wlock(False)
1593 try:
1593 try:
1594 return cmdutil.copy(ui, repo, pats, opts)
1594 return cmdutil.copy(ui, repo, pats, opts)
1595 finally:
1595 finally:
1596 wlock.release()
1596 wlock.release()
1597
1597
1598 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1598 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1599 def debugancestor(ui, repo, *args):
1599 def debugancestor(ui, repo, *args):
1600 """find the ancestor revision of two revisions in a given index"""
1600 """find the ancestor revision of two revisions in a given index"""
1601 if len(args) == 3:
1601 if len(args) == 3:
1602 index, rev1, rev2 = args
1602 index, rev1, rev2 = args
1603 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1603 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1604 lookup = r.lookup
1604 lookup = r.lookup
1605 elif len(args) == 2:
1605 elif len(args) == 2:
1606 if not repo:
1606 if not repo:
1607 raise util.Abort(_("there is no Mercurial repository here "
1607 raise util.Abort(_("there is no Mercurial repository here "
1608 "(.hg not found)"))
1608 "(.hg not found)"))
1609 rev1, rev2 = args
1609 rev1, rev2 = args
1610 r = repo.changelog
1610 r = repo.changelog
1611 lookup = repo.lookup
1611 lookup = repo.lookup
1612 else:
1612 else:
1613 raise util.Abort(_('either two or three arguments required'))
1613 raise util.Abort(_('either two or three arguments required'))
1614 a = r.ancestor(lookup(rev1), lookup(rev2))
1614 a = r.ancestor(lookup(rev1), lookup(rev2))
1615 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1615 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1616
1616
1617 @command('debugbuilddag',
1617 @command('debugbuilddag',
1618 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1618 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1619 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1619 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1620 ('n', 'new-file', None, _('add new file at each rev'))],
1620 ('n', 'new-file', None, _('add new file at each rev'))],
1621 _('[OPTION]... [TEXT]'))
1621 _('[OPTION]... [TEXT]'))
1622 def debugbuilddag(ui, repo, text=None,
1622 def debugbuilddag(ui, repo, text=None,
1623 mergeable_file=False,
1623 mergeable_file=False,
1624 overwritten_file=False,
1624 overwritten_file=False,
1625 new_file=False):
1625 new_file=False):
1626 """builds a repo with a given DAG from scratch in the current empty repo
1626 """builds a repo with a given DAG from scratch in the current empty repo
1627
1627
1628 The description of the DAG is read from stdin if not given on the
1628 The description of the DAG is read from stdin if not given on the
1629 command line.
1629 command line.
1630
1630
1631 Elements:
1631 Elements:
1632
1632
1633 - "+n" is a linear run of n nodes based on the current default parent
1633 - "+n" is a linear run of n nodes based on the current default parent
1634 - "." is a single node based on the current default parent
1634 - "." is a single node based on the current default parent
1635 - "$" resets the default parent to null (implied at the start);
1635 - "$" resets the default parent to null (implied at the start);
1636 otherwise the default parent is always the last node created
1636 otherwise the default parent is always the last node created
1637 - "<p" sets the default parent to the backref p
1637 - "<p" sets the default parent to the backref p
1638 - "*p" is a fork at parent p, which is a backref
1638 - "*p" is a fork at parent p, which is a backref
1639 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1639 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1640 - "/p2" is a merge of the preceding node and p2
1640 - "/p2" is a merge of the preceding node and p2
1641 - ":tag" defines a local tag for the preceding node
1641 - ":tag" defines a local tag for the preceding node
1642 - "@branch" sets the named branch for subsequent nodes
1642 - "@branch" sets the named branch for subsequent nodes
1643 - "#...\\n" is a comment up to the end of the line
1643 - "#...\\n" is a comment up to the end of the line
1644
1644
1645 Whitespace between the above elements is ignored.
1645 Whitespace between the above elements is ignored.
1646
1646
1647 A backref is either
1647 A backref is either
1648
1648
1649 - a number n, which references the node curr-n, where curr is the current
1649 - a number n, which references the node curr-n, where curr is the current
1650 node, or
1650 node, or
1651 - the name of a local tag you placed earlier using ":tag", or
1651 - the name of a local tag you placed earlier using ":tag", or
1652 - empty to denote the default parent.
1652 - empty to denote the default parent.
1653
1653
1654 All string valued-elements are either strictly alphanumeric, or must
1654 All string valued-elements are either strictly alphanumeric, or must
1655 be enclosed in double quotes ("..."), with "\\" as escape character.
1655 be enclosed in double quotes ("..."), with "\\" as escape character.
1656 """
1656 """
1657
1657
1658 if text is None:
1658 if text is None:
1659 ui.status(_("reading DAG from stdin\n"))
1659 ui.status(_("reading DAG from stdin\n"))
1660 text = ui.fin.read()
1660 text = ui.fin.read()
1661
1661
1662 cl = repo.changelog
1662 cl = repo.changelog
1663 if len(cl) > 0:
1663 if len(cl) > 0:
1664 raise util.Abort(_('repository is not empty'))
1664 raise util.Abort(_('repository is not empty'))
1665
1665
1666 # determine number of revs in DAG
1666 # determine number of revs in DAG
1667 total = 0
1667 total = 0
1668 for type, data in dagparser.parsedag(text):
1668 for type, data in dagparser.parsedag(text):
1669 if type == 'n':
1669 if type == 'n':
1670 total += 1
1670 total += 1
1671
1671
1672 if mergeable_file:
1672 if mergeable_file:
1673 linesperrev = 2
1673 linesperrev = 2
1674 # make a file with k lines per rev
1674 # make a file with k lines per rev
1675 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1675 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1676 initialmergedlines.append("")
1676 initialmergedlines.append("")
1677
1677
1678 tags = []
1678 tags = []
1679
1679
1680 lock = tr = None
1680 lock = tr = None
1681 try:
1681 try:
1682 lock = repo.lock()
1682 lock = repo.lock()
1683 tr = repo.transaction("builddag")
1683 tr = repo.transaction("builddag")
1684
1684
1685 at = -1
1685 at = -1
1686 atbranch = 'default'
1686 atbranch = 'default'
1687 nodeids = []
1687 nodeids = []
1688 id = 0
1688 id = 0
1689 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1689 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1690 for type, data in dagparser.parsedag(text):
1690 for type, data in dagparser.parsedag(text):
1691 if type == 'n':
1691 if type == 'n':
1692 ui.note(('node %s\n' % str(data)))
1692 ui.note(('node %s\n' % str(data)))
1693 id, ps = data
1693 id, ps = data
1694
1694
1695 files = []
1695 files = []
1696 fctxs = {}
1696 fctxs = {}
1697
1697
1698 p2 = None
1698 p2 = None
1699 if mergeable_file:
1699 if mergeable_file:
1700 fn = "mf"
1700 fn = "mf"
1701 p1 = repo[ps[0]]
1701 p1 = repo[ps[0]]
1702 if len(ps) > 1:
1702 if len(ps) > 1:
1703 p2 = repo[ps[1]]
1703 p2 = repo[ps[1]]
1704 pa = p1.ancestor(p2)
1704 pa = p1.ancestor(p2)
1705 base, local, other = [x[fn].data() for x in (pa, p1,
1705 base, local, other = [x[fn].data() for x in (pa, p1,
1706 p2)]
1706 p2)]
1707 m3 = simplemerge.Merge3Text(base, local, other)
1707 m3 = simplemerge.Merge3Text(base, local, other)
1708 ml = [l.strip() for l in m3.merge_lines()]
1708 ml = [l.strip() for l in m3.merge_lines()]
1709 ml.append("")
1709 ml.append("")
1710 elif at > 0:
1710 elif at > 0:
1711 ml = p1[fn].data().split("\n")
1711 ml = p1[fn].data().split("\n")
1712 else:
1712 else:
1713 ml = initialmergedlines
1713 ml = initialmergedlines
1714 ml[id * linesperrev] += " r%i" % id
1714 ml[id * linesperrev] += " r%i" % id
1715 mergedtext = "\n".join(ml)
1715 mergedtext = "\n".join(ml)
1716 files.append(fn)
1716 files.append(fn)
1717 fctxs[fn] = context.memfilectx(fn, mergedtext)
1717 fctxs[fn] = context.memfilectx(fn, mergedtext)
1718
1718
1719 if overwritten_file:
1719 if overwritten_file:
1720 fn = "of"
1720 fn = "of"
1721 files.append(fn)
1721 files.append(fn)
1722 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1722 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1723
1723
1724 if new_file:
1724 if new_file:
1725 fn = "nf%i" % id
1725 fn = "nf%i" % id
1726 files.append(fn)
1726 files.append(fn)
1727 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1727 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1728 if len(ps) > 1:
1728 if len(ps) > 1:
1729 if not p2:
1729 if not p2:
1730 p2 = repo[ps[1]]
1730 p2 = repo[ps[1]]
1731 for fn in p2:
1731 for fn in p2:
1732 if fn.startswith("nf"):
1732 if fn.startswith("nf"):
1733 files.append(fn)
1733 files.append(fn)
1734 fctxs[fn] = p2[fn]
1734 fctxs[fn] = p2[fn]
1735
1735
1736 def fctxfn(repo, cx, path):
1736 def fctxfn(repo, cx, path):
1737 return fctxs.get(path)
1737 return fctxs.get(path)
1738
1738
1739 if len(ps) == 0 or ps[0] < 0:
1739 if len(ps) == 0 or ps[0] < 0:
1740 pars = [None, None]
1740 pars = [None, None]
1741 elif len(ps) == 1:
1741 elif len(ps) == 1:
1742 pars = [nodeids[ps[0]], None]
1742 pars = [nodeids[ps[0]], None]
1743 else:
1743 else:
1744 pars = [nodeids[p] for p in ps]
1744 pars = [nodeids[p] for p in ps]
1745 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1745 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1746 date=(id, 0),
1746 date=(id, 0),
1747 user="debugbuilddag",
1747 user="debugbuilddag",
1748 extra={'branch': atbranch})
1748 extra={'branch': atbranch})
1749 nodeid = repo.commitctx(cx)
1749 nodeid = repo.commitctx(cx)
1750 nodeids.append(nodeid)
1750 nodeids.append(nodeid)
1751 at = id
1751 at = id
1752 elif type == 'l':
1752 elif type == 'l':
1753 id, name = data
1753 id, name = data
1754 ui.note(('tag %s\n' % name))
1754 ui.note(('tag %s\n' % name))
1755 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1755 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1756 elif type == 'a':
1756 elif type == 'a':
1757 ui.note(('branch %s\n' % data))
1757 ui.note(('branch %s\n' % data))
1758 atbranch = data
1758 atbranch = data
1759 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1759 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1760 tr.close()
1760 tr.close()
1761
1761
1762 if tags:
1762 if tags:
1763 repo.opener.write("localtags", "".join(tags))
1763 repo.opener.write("localtags", "".join(tags))
1764 finally:
1764 finally:
1765 ui.progress(_('building'), None)
1765 ui.progress(_('building'), None)
1766 release(tr, lock)
1766 release(tr, lock)
1767
1767
1768 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1768 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1769 def debugbundle(ui, bundlepath, all=None, **opts):
1769 def debugbundle(ui, bundlepath, all=None, **opts):
1770 """lists the contents of a bundle"""
1770 """lists the contents of a bundle"""
1771 f = hg.openpath(ui, bundlepath)
1771 f = hg.openpath(ui, bundlepath)
1772 try:
1772 try:
1773 gen = changegroup.readbundle(f, bundlepath)
1773 gen = changegroup.readbundle(f, bundlepath)
1774 if all:
1774 if all:
1775 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1775 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1776
1776
1777 def showchunks(named):
1777 def showchunks(named):
1778 ui.write("\n%s\n" % named)
1778 ui.write("\n%s\n" % named)
1779 chain = None
1779 chain = None
1780 while True:
1780 while True:
1781 chunkdata = gen.deltachunk(chain)
1781 chunkdata = gen.deltachunk(chain)
1782 if not chunkdata:
1782 if not chunkdata:
1783 break
1783 break
1784 node = chunkdata['node']
1784 node = chunkdata['node']
1785 p1 = chunkdata['p1']
1785 p1 = chunkdata['p1']
1786 p2 = chunkdata['p2']
1786 p2 = chunkdata['p2']
1787 cs = chunkdata['cs']
1787 cs = chunkdata['cs']
1788 deltabase = chunkdata['deltabase']
1788 deltabase = chunkdata['deltabase']
1789 delta = chunkdata['delta']
1789 delta = chunkdata['delta']
1790 ui.write("%s %s %s %s %s %s\n" %
1790 ui.write("%s %s %s %s %s %s\n" %
1791 (hex(node), hex(p1), hex(p2),
1791 (hex(node), hex(p1), hex(p2),
1792 hex(cs), hex(deltabase), len(delta)))
1792 hex(cs), hex(deltabase), len(delta)))
1793 chain = node
1793 chain = node
1794
1794
1795 chunkdata = gen.changelogheader()
1795 chunkdata = gen.changelogheader()
1796 showchunks("changelog")
1796 showchunks("changelog")
1797 chunkdata = gen.manifestheader()
1797 chunkdata = gen.manifestheader()
1798 showchunks("manifest")
1798 showchunks("manifest")
1799 while True:
1799 while True:
1800 chunkdata = gen.filelogheader()
1800 chunkdata = gen.filelogheader()
1801 if not chunkdata:
1801 if not chunkdata:
1802 break
1802 break
1803 fname = chunkdata['filename']
1803 fname = chunkdata['filename']
1804 showchunks(fname)
1804 showchunks(fname)
1805 else:
1805 else:
1806 chunkdata = gen.changelogheader()
1806 chunkdata = gen.changelogheader()
1807 chain = None
1807 chain = None
1808 while True:
1808 while True:
1809 chunkdata = gen.deltachunk(chain)
1809 chunkdata = gen.deltachunk(chain)
1810 if not chunkdata:
1810 if not chunkdata:
1811 break
1811 break
1812 node = chunkdata['node']
1812 node = chunkdata['node']
1813 ui.write("%s\n" % hex(node))
1813 ui.write("%s\n" % hex(node))
1814 chain = node
1814 chain = node
1815 finally:
1815 finally:
1816 f.close()
1816 f.close()
1817
1817
1818 @command('debugcheckstate', [], '')
1818 @command('debugcheckstate', [], '')
1819 def debugcheckstate(ui, repo):
1819 def debugcheckstate(ui, repo):
1820 """validate the correctness of the current dirstate"""
1820 """validate the correctness of the current dirstate"""
1821 parent1, parent2 = repo.dirstate.parents()
1821 parent1, parent2 = repo.dirstate.parents()
1822 m1 = repo[parent1].manifest()
1822 m1 = repo[parent1].manifest()
1823 m2 = repo[parent2].manifest()
1823 m2 = repo[parent2].manifest()
1824 errors = 0
1824 errors = 0
1825 for f in repo.dirstate:
1825 for f in repo.dirstate:
1826 state = repo.dirstate[f]
1826 state = repo.dirstate[f]
1827 if state in "nr" and f not in m1:
1827 if state in "nr" and f not in m1:
1828 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1828 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1829 errors += 1
1829 errors += 1
1830 if state in "a" and f in m1:
1830 if state in "a" and f in m1:
1831 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1831 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1832 errors += 1
1832 errors += 1
1833 if state in "m" and f not in m1 and f not in m2:
1833 if state in "m" and f not in m1 and f not in m2:
1834 ui.warn(_("%s in state %s, but not in either manifest\n") %
1834 ui.warn(_("%s in state %s, but not in either manifest\n") %
1835 (f, state))
1835 (f, state))
1836 errors += 1
1836 errors += 1
1837 for f in m1:
1837 for f in m1:
1838 state = repo.dirstate[f]
1838 state = repo.dirstate[f]
1839 if state not in "nrm":
1839 if state not in "nrm":
1840 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1840 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1841 errors += 1
1841 errors += 1
1842 if errors:
1842 if errors:
1843 error = _(".hg/dirstate inconsistent with current parent's manifest")
1843 error = _(".hg/dirstate inconsistent with current parent's manifest")
1844 raise util.Abort(error)
1844 raise util.Abort(error)
1845
1845
1846 @command('debugcommands', [], _('[COMMAND]'))
1846 @command('debugcommands', [], _('[COMMAND]'))
1847 def debugcommands(ui, cmd='', *args):
1847 def debugcommands(ui, cmd='', *args):
1848 """list all available commands and options"""
1848 """list all available commands and options"""
1849 for cmd, vals in sorted(table.iteritems()):
1849 for cmd, vals in sorted(table.iteritems()):
1850 cmd = cmd.split('|')[0].strip('^')
1850 cmd = cmd.split('|')[0].strip('^')
1851 opts = ', '.join([i[1] for i in vals[1]])
1851 opts = ', '.join([i[1] for i in vals[1]])
1852 ui.write('%s: %s\n' % (cmd, opts))
1852 ui.write('%s: %s\n' % (cmd, opts))
1853
1853
1854 @command('debugcomplete',
1854 @command('debugcomplete',
1855 [('o', 'options', None, _('show the command options'))],
1855 [('o', 'options', None, _('show the command options'))],
1856 _('[-o] CMD'))
1856 _('[-o] CMD'))
1857 def debugcomplete(ui, cmd='', **opts):
1857 def debugcomplete(ui, cmd='', **opts):
1858 """returns the completion list associated with the given command"""
1858 """returns the completion list associated with the given command"""
1859
1859
1860 if opts.get('options'):
1860 if opts.get('options'):
1861 options = []
1861 options = []
1862 otables = [globalopts]
1862 otables = [globalopts]
1863 if cmd:
1863 if cmd:
1864 aliases, entry = cmdutil.findcmd(cmd, table, False)
1864 aliases, entry = cmdutil.findcmd(cmd, table, False)
1865 otables.append(entry[1])
1865 otables.append(entry[1])
1866 for t in otables:
1866 for t in otables:
1867 for o in t:
1867 for o in t:
1868 if "(DEPRECATED)" in o[3]:
1868 if "(DEPRECATED)" in o[3]:
1869 continue
1869 continue
1870 if o[0]:
1870 if o[0]:
1871 options.append('-%s' % o[0])
1871 options.append('-%s' % o[0])
1872 options.append('--%s' % o[1])
1872 options.append('--%s' % o[1])
1873 ui.write("%s\n" % "\n".join(options))
1873 ui.write("%s\n" % "\n".join(options))
1874 return
1874 return
1875
1875
1876 cmdlist = cmdutil.findpossible(cmd, table)
1876 cmdlist = cmdutil.findpossible(cmd, table)
1877 if ui.verbose:
1877 if ui.verbose:
1878 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1878 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1879 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1879 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1880
1880
1881 @command('debugdag',
1881 @command('debugdag',
1882 [('t', 'tags', None, _('use tags as labels')),
1882 [('t', 'tags', None, _('use tags as labels')),
1883 ('b', 'branches', None, _('annotate with branch names')),
1883 ('b', 'branches', None, _('annotate with branch names')),
1884 ('', 'dots', None, _('use dots for runs')),
1884 ('', 'dots', None, _('use dots for runs')),
1885 ('s', 'spaces', None, _('separate elements by spaces'))],
1885 ('s', 'spaces', None, _('separate elements by spaces'))],
1886 _('[OPTION]... [FILE [REV]...]'))
1886 _('[OPTION]... [FILE [REV]...]'))
1887 def debugdag(ui, repo, file_=None, *revs, **opts):
1887 def debugdag(ui, repo, file_=None, *revs, **opts):
1888 """format the changelog or an index DAG as a concise textual description
1888 """format the changelog or an index DAG as a concise textual description
1889
1889
1890 If you pass a revlog index, the revlog's DAG is emitted. If you list
1890 If you pass a revlog index, the revlog's DAG is emitted. If you list
1891 revision numbers, they get labeled in the output as rN.
1891 revision numbers, they get labeled in the output as rN.
1892
1892
1893 Otherwise, the changelog DAG of the current repo is emitted.
1893 Otherwise, the changelog DAG of the current repo is emitted.
1894 """
1894 """
1895 spaces = opts.get('spaces')
1895 spaces = opts.get('spaces')
1896 dots = opts.get('dots')
1896 dots = opts.get('dots')
1897 if file_:
1897 if file_:
1898 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1898 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1899 revs = set((int(r) for r in revs))
1899 revs = set((int(r) for r in revs))
1900 def events():
1900 def events():
1901 for r in rlog:
1901 for r in rlog:
1902 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1902 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1903 if p != -1)))
1903 if p != -1)))
1904 if r in revs:
1904 if r in revs:
1905 yield 'l', (r, "r%i" % r)
1905 yield 'l', (r, "r%i" % r)
1906 elif repo:
1906 elif repo:
1907 cl = repo.changelog
1907 cl = repo.changelog
1908 tags = opts.get('tags')
1908 tags = opts.get('tags')
1909 branches = opts.get('branches')
1909 branches = opts.get('branches')
1910 if tags:
1910 if tags:
1911 labels = {}
1911 labels = {}
1912 for l, n in repo.tags().items():
1912 for l, n in repo.tags().items():
1913 labels.setdefault(cl.rev(n), []).append(l)
1913 labels.setdefault(cl.rev(n), []).append(l)
1914 def events():
1914 def events():
1915 b = "default"
1915 b = "default"
1916 for r in cl:
1916 for r in cl:
1917 if branches:
1917 if branches:
1918 newb = cl.read(cl.node(r))[5]['branch']
1918 newb = cl.read(cl.node(r))[5]['branch']
1919 if newb != b:
1919 if newb != b:
1920 yield 'a', newb
1920 yield 'a', newb
1921 b = newb
1921 b = newb
1922 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1922 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1923 if p != -1)))
1923 if p != -1)))
1924 if tags:
1924 if tags:
1925 ls = labels.get(r)
1925 ls = labels.get(r)
1926 if ls:
1926 if ls:
1927 for l in ls:
1927 for l in ls:
1928 yield 'l', (r, l)
1928 yield 'l', (r, l)
1929 else:
1929 else:
1930 raise util.Abort(_('need repo for changelog dag'))
1930 raise util.Abort(_('need repo for changelog dag'))
1931
1931
1932 for line in dagparser.dagtextlines(events(),
1932 for line in dagparser.dagtextlines(events(),
1933 addspaces=spaces,
1933 addspaces=spaces,
1934 wraplabels=True,
1934 wraplabels=True,
1935 wrapannotations=True,
1935 wrapannotations=True,
1936 wrapnonlinear=dots,
1936 wrapnonlinear=dots,
1937 usedots=dots,
1937 usedots=dots,
1938 maxlinewidth=70):
1938 maxlinewidth=70):
1939 ui.write(line)
1939 ui.write(line)
1940 ui.write("\n")
1940 ui.write("\n")
1941
1941
1942 @command('debugdata',
1942 @command('debugdata',
1943 [('c', 'changelog', False, _('open changelog')),
1943 [('c', 'changelog', False, _('open changelog')),
1944 ('m', 'manifest', False, _('open manifest'))],
1944 ('m', 'manifest', False, _('open manifest'))],
1945 _('-c|-m|FILE REV'))
1945 _('-c|-m|FILE REV'))
1946 def debugdata(ui, repo, file_, rev=None, **opts):
1946 def debugdata(ui, repo, file_, rev=None, **opts):
1947 """dump the contents of a data file revision"""
1947 """dump the contents of a data file revision"""
1948 if opts.get('changelog') or opts.get('manifest'):
1948 if opts.get('changelog') or opts.get('manifest'):
1949 file_, rev = None, file_
1949 file_, rev = None, file_
1950 elif rev is None:
1950 elif rev is None:
1951 raise error.CommandError('debugdata', _('invalid arguments'))
1951 raise error.CommandError('debugdata', _('invalid arguments'))
1952 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1952 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1953 try:
1953 try:
1954 ui.write(r.revision(r.lookup(rev)))
1954 ui.write(r.revision(r.lookup(rev)))
1955 except KeyError:
1955 except KeyError:
1956 raise util.Abort(_('invalid revision identifier %s') % rev)
1956 raise util.Abort(_('invalid revision identifier %s') % rev)
1957
1957
1958 @command('debugdate',
1958 @command('debugdate',
1959 [('e', 'extended', None, _('try extended date formats'))],
1959 [('e', 'extended', None, _('try extended date formats'))],
1960 _('[-e] DATE [RANGE]'))
1960 _('[-e] DATE [RANGE]'))
1961 def debugdate(ui, date, range=None, **opts):
1961 def debugdate(ui, date, range=None, **opts):
1962 """parse and display a date"""
1962 """parse and display a date"""
1963 if opts["extended"]:
1963 if opts["extended"]:
1964 d = util.parsedate(date, util.extendeddateformats)
1964 d = util.parsedate(date, util.extendeddateformats)
1965 else:
1965 else:
1966 d = util.parsedate(date)
1966 d = util.parsedate(date)
1967 ui.write(("internal: %s %s\n") % d)
1967 ui.write(("internal: %s %s\n") % d)
1968 ui.write(("standard: %s\n") % util.datestr(d))
1968 ui.write(("standard: %s\n") % util.datestr(d))
1969 if range:
1969 if range:
1970 m = util.matchdate(range)
1970 m = util.matchdate(range)
1971 ui.write(("match: %s\n") % m(d[0]))
1971 ui.write(("match: %s\n") % m(d[0]))
1972
1972
1973 @command('debugdiscovery',
1973 @command('debugdiscovery',
1974 [('', 'old', None, _('use old-style discovery')),
1974 [('', 'old', None, _('use old-style discovery')),
1975 ('', 'nonheads', None,
1975 ('', 'nonheads', None,
1976 _('use old-style discovery with non-heads included')),
1976 _('use old-style discovery with non-heads included')),
1977 ] + remoteopts,
1977 ] + remoteopts,
1978 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1978 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1979 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1979 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1980 """runs the changeset discovery protocol in isolation"""
1980 """runs the changeset discovery protocol in isolation"""
1981 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1981 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1982 opts.get('branch'))
1982 opts.get('branch'))
1983 remote = hg.peer(repo, opts, remoteurl)
1983 remote = hg.peer(repo, opts, remoteurl)
1984 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1984 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1985
1985
1986 # make sure tests are repeatable
1986 # make sure tests are repeatable
1987 random.seed(12323)
1987 random.seed(12323)
1988
1988
1989 def doit(localheads, remoteheads, remote=remote):
1989 def doit(localheads, remoteheads, remote=remote):
1990 if opts.get('old'):
1990 if opts.get('old'):
1991 if localheads:
1991 if localheads:
1992 raise util.Abort('cannot use localheads with old style '
1992 raise util.Abort('cannot use localheads with old style '
1993 'discovery')
1993 'discovery')
1994 if not util.safehasattr(remote, 'branches'):
1994 if not util.safehasattr(remote, 'branches'):
1995 # enable in-client legacy support
1995 # enable in-client legacy support
1996 remote = localrepo.locallegacypeer(remote.local())
1996 remote = localrepo.locallegacypeer(remote.local())
1997 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1997 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1998 force=True)
1998 force=True)
1999 common = set(common)
1999 common = set(common)
2000 if not opts.get('nonheads'):
2000 if not opts.get('nonheads'):
2001 ui.write(("unpruned common: %s\n") %
2001 ui.write(("unpruned common: %s\n") %
2002 " ".join(sorted(short(n) for n in common)))
2002 " ".join(sorted(short(n) for n in common)))
2003 dag = dagutil.revlogdag(repo.changelog)
2003 dag = dagutil.revlogdag(repo.changelog)
2004 all = dag.ancestorset(dag.internalizeall(common))
2004 all = dag.ancestorset(dag.internalizeall(common))
2005 common = dag.externalizeall(dag.headsetofconnecteds(all))
2005 common = dag.externalizeall(dag.headsetofconnecteds(all))
2006 else:
2006 else:
2007 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2007 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2008 common = set(common)
2008 common = set(common)
2009 rheads = set(hds)
2009 rheads = set(hds)
2010 lheads = set(repo.heads())
2010 lheads = set(repo.heads())
2011 ui.write(("common heads: %s\n") %
2011 ui.write(("common heads: %s\n") %
2012 " ".join(sorted(short(n) for n in common)))
2012 " ".join(sorted(short(n) for n in common)))
2013 if lheads <= common:
2013 if lheads <= common:
2014 ui.write(("local is subset\n"))
2014 ui.write(("local is subset\n"))
2015 elif rheads <= common:
2015 elif rheads <= common:
2016 ui.write(("remote is subset\n"))
2016 ui.write(("remote is subset\n"))
2017
2017
2018 serverlogs = opts.get('serverlog')
2018 serverlogs = opts.get('serverlog')
2019 if serverlogs:
2019 if serverlogs:
2020 for filename in serverlogs:
2020 for filename in serverlogs:
2021 logfile = open(filename, 'r')
2021 logfile = open(filename, 'r')
2022 try:
2022 try:
2023 line = logfile.readline()
2023 line = logfile.readline()
2024 while line:
2024 while line:
2025 parts = line.strip().split(';')
2025 parts = line.strip().split(';')
2026 op = parts[1]
2026 op = parts[1]
2027 if op == 'cg':
2027 if op == 'cg':
2028 pass
2028 pass
2029 elif op == 'cgss':
2029 elif op == 'cgss':
2030 doit(parts[2].split(' '), parts[3].split(' '))
2030 doit(parts[2].split(' '), parts[3].split(' '))
2031 elif op == 'unb':
2031 elif op == 'unb':
2032 doit(parts[3].split(' '), parts[2].split(' '))
2032 doit(parts[3].split(' '), parts[2].split(' '))
2033 line = logfile.readline()
2033 line = logfile.readline()
2034 finally:
2034 finally:
2035 logfile.close()
2035 logfile.close()
2036
2036
2037 else:
2037 else:
2038 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2038 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2039 opts.get('remote_head'))
2039 opts.get('remote_head'))
2040 localrevs = opts.get('local_head')
2040 localrevs = opts.get('local_head')
2041 doit(localrevs, remoterevs)
2041 doit(localrevs, remoterevs)
2042
2042
2043 @command('debugfileset',
2043 @command('debugfileset',
2044 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2044 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2045 _('[-r REV] FILESPEC'))
2045 _('[-r REV] FILESPEC'))
2046 def debugfileset(ui, repo, expr, **opts):
2046 def debugfileset(ui, repo, expr, **opts):
2047 '''parse and apply a fileset specification'''
2047 '''parse and apply a fileset specification'''
2048 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2048 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2049 if ui.verbose:
2049 if ui.verbose:
2050 tree = fileset.parse(expr)[0]
2050 tree = fileset.parse(expr)[0]
2051 ui.note(tree, "\n")
2051 ui.note(tree, "\n")
2052
2052
2053 for f in ctx.getfileset(expr):
2053 for f in ctx.getfileset(expr):
2054 ui.write("%s\n" % f)
2054 ui.write("%s\n" % f)
2055
2055
2056 @command('debugfsinfo', [], _('[PATH]'))
2056 @command('debugfsinfo', [], _('[PATH]'))
2057 def debugfsinfo(ui, path="."):
2057 def debugfsinfo(ui, path="."):
2058 """show information detected about current filesystem"""
2058 """show information detected about current filesystem"""
2059 util.writefile('.debugfsinfo', '')
2059 util.writefile('.debugfsinfo', '')
2060 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2060 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2061 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2061 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2062 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2062 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2063 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2063 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2064 and 'yes' or 'no'))
2064 and 'yes' or 'no'))
2065 os.unlink('.debugfsinfo')
2065 os.unlink('.debugfsinfo')
2066
2066
2067 @command('debuggetbundle',
2067 @command('debuggetbundle',
2068 [('H', 'head', [], _('id of head node'), _('ID')),
2068 [('H', 'head', [], _('id of head node'), _('ID')),
2069 ('C', 'common', [], _('id of common node'), _('ID')),
2069 ('C', 'common', [], _('id of common node'), _('ID')),
2070 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2070 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2071 _('REPO FILE [-H|-C ID]...'))
2071 _('REPO FILE [-H|-C ID]...'))
2072 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2072 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2073 """retrieves a bundle from a repo
2073 """retrieves a bundle from a repo
2074
2074
2075 Every ID must be a full-length hex node id string. Saves the bundle to the
2075 Every ID must be a full-length hex node id string. Saves the bundle to the
2076 given file.
2076 given file.
2077 """
2077 """
2078 repo = hg.peer(ui, opts, repopath)
2078 repo = hg.peer(ui, opts, repopath)
2079 if not repo.capable('getbundle'):
2079 if not repo.capable('getbundle'):
2080 raise util.Abort("getbundle() not supported by target repository")
2080 raise util.Abort("getbundle() not supported by target repository")
2081 args = {}
2081 args = {}
2082 if common:
2082 if common:
2083 args['common'] = [bin(s) for s in common]
2083 args['common'] = [bin(s) for s in common]
2084 if head:
2084 if head:
2085 args['heads'] = [bin(s) for s in head]
2085 args['heads'] = [bin(s) for s in head]
2086 # TODO: get desired bundlecaps from command line.
2086 # TODO: get desired bundlecaps from command line.
2087 args['bundlecaps'] = None
2087 args['bundlecaps'] = None
2088 bundle = repo.getbundle('debug', **args)
2088 bundle = repo.getbundle('debug', **args)
2089
2089
2090 bundletype = opts.get('type', 'bzip2').lower()
2090 bundletype = opts.get('type', 'bzip2').lower()
2091 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2091 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2092 bundletype = btypes.get(bundletype)
2092 bundletype = btypes.get(bundletype)
2093 if bundletype not in changegroup.bundletypes:
2093 if bundletype not in changegroup.bundletypes:
2094 raise util.Abort(_('unknown bundle type specified with --type'))
2094 raise util.Abort(_('unknown bundle type specified with --type'))
2095 changegroup.writebundle(bundle, bundlepath, bundletype)
2095 changegroup.writebundle(bundle, bundlepath, bundletype)
2096
2096
2097 @command('debugignore', [], '')
2097 @command('debugignore', [], '')
2098 def debugignore(ui, repo, *values, **opts):
2098 def debugignore(ui, repo, *values, **opts):
2099 """display the combined ignore pattern"""
2099 """display the combined ignore pattern"""
2100 ignore = repo.dirstate._ignore
2100 ignore = repo.dirstate._ignore
2101 includepat = getattr(ignore, 'includepat', None)
2101 includepat = getattr(ignore, 'includepat', None)
2102 if includepat is not None:
2102 if includepat is not None:
2103 ui.write("%s\n" % includepat)
2103 ui.write("%s\n" % includepat)
2104 else:
2104 else:
2105 raise util.Abort(_("no ignore patterns found"))
2105 raise util.Abort(_("no ignore patterns found"))
2106
2106
2107 @command('debugindex',
2107 @command('debugindex',
2108 [('c', 'changelog', False, _('open changelog')),
2108 [('c', 'changelog', False, _('open changelog')),
2109 ('m', 'manifest', False, _('open manifest')),
2109 ('m', 'manifest', False, _('open manifest')),
2110 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2110 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2111 _('[-f FORMAT] -c|-m|FILE'))
2111 _('[-f FORMAT] -c|-m|FILE'))
2112 def debugindex(ui, repo, file_=None, **opts):
2112 def debugindex(ui, repo, file_=None, **opts):
2113 """dump the contents of an index file"""
2113 """dump the contents of an index file"""
2114 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2114 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2115 format = opts.get('format', 0)
2115 format = opts.get('format', 0)
2116 if format not in (0, 1):
2116 if format not in (0, 1):
2117 raise util.Abort(_("unknown format %d") % format)
2117 raise util.Abort(_("unknown format %d") % format)
2118
2118
2119 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2119 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2120 if generaldelta:
2120 if generaldelta:
2121 basehdr = ' delta'
2121 basehdr = ' delta'
2122 else:
2122 else:
2123 basehdr = ' base'
2123 basehdr = ' base'
2124
2124
2125 if format == 0:
2125 if format == 0:
2126 ui.write(" rev offset length " + basehdr + " linkrev"
2126 ui.write(" rev offset length " + basehdr + " linkrev"
2127 " nodeid p1 p2\n")
2127 " nodeid p1 p2\n")
2128 elif format == 1:
2128 elif format == 1:
2129 ui.write(" rev flag offset length"
2129 ui.write(" rev flag offset length"
2130 " size " + basehdr + " link p1 p2"
2130 " size " + basehdr + " link p1 p2"
2131 " nodeid\n")
2131 " nodeid\n")
2132
2132
2133 for i in r:
2133 for i in r:
2134 node = r.node(i)
2134 node = r.node(i)
2135 if generaldelta:
2135 if generaldelta:
2136 base = r.deltaparent(i)
2136 base = r.deltaparent(i)
2137 else:
2137 else:
2138 base = r.chainbase(i)
2138 base = r.chainbase(i)
2139 if format == 0:
2139 if format == 0:
2140 try:
2140 try:
2141 pp = r.parents(node)
2141 pp = r.parents(node)
2142 except Exception:
2142 except Exception:
2143 pp = [nullid, nullid]
2143 pp = [nullid, nullid]
2144 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2144 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2145 i, r.start(i), r.length(i), base, r.linkrev(i),
2145 i, r.start(i), r.length(i), base, r.linkrev(i),
2146 short(node), short(pp[0]), short(pp[1])))
2146 short(node), short(pp[0]), short(pp[1])))
2147 elif format == 1:
2147 elif format == 1:
2148 pr = r.parentrevs(i)
2148 pr = r.parentrevs(i)
2149 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2149 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2150 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2150 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2151 base, r.linkrev(i), pr[0], pr[1], short(node)))
2151 base, r.linkrev(i), pr[0], pr[1], short(node)))
2152
2152
2153 @command('debugindexdot', [], _('FILE'))
2153 @command('debugindexdot', [], _('FILE'))
2154 def debugindexdot(ui, repo, file_):
2154 def debugindexdot(ui, repo, file_):
2155 """dump an index DAG as a graphviz dot file"""
2155 """dump an index DAG as a graphviz dot file"""
2156 r = None
2156 r = None
2157 if repo:
2157 if repo:
2158 filelog = repo.file(file_)
2158 filelog = repo.file(file_)
2159 if len(filelog):
2159 if len(filelog):
2160 r = filelog
2160 r = filelog
2161 if not r:
2161 if not r:
2162 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2162 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2163 ui.write(("digraph G {\n"))
2163 ui.write(("digraph G {\n"))
2164 for i in r:
2164 for i in r:
2165 node = r.node(i)
2165 node = r.node(i)
2166 pp = r.parents(node)
2166 pp = r.parents(node)
2167 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2167 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2168 if pp[1] != nullid:
2168 if pp[1] != nullid:
2169 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2169 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2170 ui.write("}\n")
2170 ui.write("}\n")
2171
2171
2172 @command('debuginstall', [], '')
2172 @command('debuginstall', [], '')
2173 def debuginstall(ui):
2173 def debuginstall(ui):
2174 '''test Mercurial installation
2174 '''test Mercurial installation
2175
2175
2176 Returns 0 on success.
2176 Returns 0 on success.
2177 '''
2177 '''
2178
2178
2179 def writetemp(contents):
2179 def writetemp(contents):
2180 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2180 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2181 f = os.fdopen(fd, "wb")
2181 f = os.fdopen(fd, "wb")
2182 f.write(contents)
2182 f.write(contents)
2183 f.close()
2183 f.close()
2184 return name
2184 return name
2185
2185
2186 problems = 0
2186 problems = 0
2187
2187
2188 # encoding
2188 # encoding
2189 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2189 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2190 try:
2190 try:
2191 encoding.fromlocal("test")
2191 encoding.fromlocal("test")
2192 except util.Abort, inst:
2192 except util.Abort, inst:
2193 ui.write(" %s\n" % inst)
2193 ui.write(" %s\n" % inst)
2194 ui.write(_(" (check that your locale is properly set)\n"))
2194 ui.write(_(" (check that your locale is properly set)\n"))
2195 problems += 1
2195 problems += 1
2196
2196
2197 # Python
2197 # Python
2198 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2198 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2199 ui.status(_("checking Python version (%s)\n")
2199 ui.status(_("checking Python version (%s)\n")
2200 % ("%s.%s.%s" % sys.version_info[:3]))
2200 % ("%s.%s.%s" % sys.version_info[:3]))
2201 ui.status(_("checking Python lib (%s)...\n")
2201 ui.status(_("checking Python lib (%s)...\n")
2202 % os.path.dirname(os.__file__))
2202 % os.path.dirname(os.__file__))
2203
2203
2204 # compiled modules
2204 # compiled modules
2205 ui.status(_("checking installed modules (%s)...\n")
2205 ui.status(_("checking installed modules (%s)...\n")
2206 % os.path.dirname(__file__))
2206 % os.path.dirname(__file__))
2207 try:
2207 try:
2208 import bdiff, mpatch, base85, osutil
2208 import bdiff, mpatch, base85, osutil
2209 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2209 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2210 except Exception, inst:
2210 except Exception, inst:
2211 ui.write(" %s\n" % inst)
2211 ui.write(" %s\n" % inst)
2212 ui.write(_(" One or more extensions could not be found"))
2212 ui.write(_(" One or more extensions could not be found"))
2213 ui.write(_(" (check that you compiled the extensions)\n"))
2213 ui.write(_(" (check that you compiled the extensions)\n"))
2214 problems += 1
2214 problems += 1
2215
2215
2216 # templates
2216 # templates
2217 import templater
2217 import templater
2218 p = templater.templatepath()
2218 p = templater.templatepath()
2219 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2219 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2220 if p:
2220 if p:
2221 m = templater.templatepath("map-cmdline.default")
2221 m = templater.templatepath("map-cmdline.default")
2222 if m:
2222 if m:
2223 # template found, check if it is working
2223 # template found, check if it is working
2224 try:
2224 try:
2225 templater.templater(m)
2225 templater.templater(m)
2226 except Exception, inst:
2226 except Exception, inst:
2227 ui.write(" %s\n" % inst)
2227 ui.write(" %s\n" % inst)
2228 p = None
2228 p = None
2229 else:
2229 else:
2230 ui.write(_(" template 'default' not found\n"))
2230 ui.write(_(" template 'default' not found\n"))
2231 p = None
2231 p = None
2232 else:
2232 else:
2233 ui.write(_(" no template directories found\n"))
2233 ui.write(_(" no template directories found\n"))
2234 if not p:
2234 if not p:
2235 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2235 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2236 problems += 1
2236 problems += 1
2237
2237
2238 # editor
2238 # editor
2239 ui.status(_("checking commit editor...\n"))
2239 ui.status(_("checking commit editor...\n"))
2240 editor = ui.geteditor()
2240 editor = ui.geteditor()
2241 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2241 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2242 if not cmdpath:
2242 if not cmdpath:
2243 if editor == 'vi':
2243 if editor == 'vi':
2244 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2244 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2245 ui.write(_(" (specify a commit editor in your configuration"
2245 ui.write(_(" (specify a commit editor in your configuration"
2246 " file)\n"))
2246 " file)\n"))
2247 else:
2247 else:
2248 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2248 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2249 ui.write(_(" (specify a commit editor in your configuration"
2249 ui.write(_(" (specify a commit editor in your configuration"
2250 " file)\n"))
2250 " file)\n"))
2251 problems += 1
2251 problems += 1
2252
2252
2253 # check username
2253 # check username
2254 ui.status(_("checking username...\n"))
2254 ui.status(_("checking username...\n"))
2255 try:
2255 try:
2256 ui.username()
2256 ui.username()
2257 except util.Abort, e:
2257 except util.Abort, e:
2258 ui.write(" %s\n" % e)
2258 ui.write(" %s\n" % e)
2259 ui.write(_(" (specify a username in your configuration file)\n"))
2259 ui.write(_(" (specify a username in your configuration file)\n"))
2260 problems += 1
2260 problems += 1
2261
2261
2262 if not problems:
2262 if not problems:
2263 ui.status(_("no problems detected\n"))
2263 ui.status(_("no problems detected\n"))
2264 else:
2264 else:
2265 ui.write(_("%s problems detected,"
2265 ui.write(_("%s problems detected,"
2266 " please check your install!\n") % problems)
2266 " please check your install!\n") % problems)
2267
2267
2268 return problems
2268 return problems
2269
2269
2270 @command('debugknown', [], _('REPO ID...'))
2270 @command('debugknown', [], _('REPO ID...'))
2271 def debugknown(ui, repopath, *ids, **opts):
2271 def debugknown(ui, repopath, *ids, **opts):
2272 """test whether node ids are known to a repo
2272 """test whether node ids are known to a repo
2273
2273
2274 Every ID must be a full-length hex node id string. Returns a list of 0s
2274 Every ID must be a full-length hex node id string. Returns a list of 0s
2275 and 1s indicating unknown/known.
2275 and 1s indicating unknown/known.
2276 """
2276 """
2277 repo = hg.peer(ui, opts, repopath)
2277 repo = hg.peer(ui, opts, repopath)
2278 if not repo.capable('known'):
2278 if not repo.capable('known'):
2279 raise util.Abort("known() not supported by target repository")
2279 raise util.Abort("known() not supported by target repository")
2280 flags = repo.known([bin(s) for s in ids])
2280 flags = repo.known([bin(s) for s in ids])
2281 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2281 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2282
2282
2283 @command('debuglabelcomplete', [], _('LABEL...'))
2283 @command('debuglabelcomplete', [], _('LABEL...'))
2284 def debuglabelcomplete(ui, repo, *args):
2284 def debuglabelcomplete(ui, repo, *args):
2285 '''complete "labels" - tags, open branch names, bookmark names'''
2285 '''complete "labels" - tags, open branch names, bookmark names'''
2286
2286
2287 labels = set()
2287 labels = set()
2288 labels.update(t[0] for t in repo.tagslist())
2288 labels.update(t[0] for t in repo.tagslist())
2289 labels.update(repo._bookmarks.keys())
2289 labels.update(repo._bookmarks.keys())
2290 labels.update(tag for (tag, heads, tip, closed)
2290 labels.update(tag for (tag, heads, tip, closed)
2291 in repo.branchmap().iterbranches() if not closed)
2291 in repo.branchmap().iterbranches() if not closed)
2292 completions = set()
2292 completions = set()
2293 if not args:
2293 if not args:
2294 args = ['']
2294 args = ['']
2295 for a in args:
2295 for a in args:
2296 completions.update(l for l in labels if l.startswith(a))
2296 completions.update(l for l in labels if l.startswith(a))
2297 ui.write('\n'.join(sorted(completions)))
2297 ui.write('\n'.join(sorted(completions)))
2298 ui.write('\n')
2298 ui.write('\n')
2299
2299
2300 @command('debugobsolete',
2300 @command('debugobsolete',
2301 [('', 'flags', 0, _('markers flag')),
2301 [('', 'flags', 0, _('markers flag')),
2302 ] + commitopts2,
2302 ] + commitopts2,
2303 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2303 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2304 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2304 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2305 """create arbitrary obsolete marker
2305 """create arbitrary obsolete marker
2306
2306
2307 With no arguments, displays the list of obsolescence markers."""
2307 With no arguments, displays the list of obsolescence markers."""
2308 def parsenodeid(s):
2308 def parsenodeid(s):
2309 try:
2309 try:
2310 # We do not use revsingle/revrange functions here to accept
2310 # We do not use revsingle/revrange functions here to accept
2311 # arbitrary node identifiers, possibly not present in the
2311 # arbitrary node identifiers, possibly not present in the
2312 # local repository.
2312 # local repository.
2313 n = bin(s)
2313 n = bin(s)
2314 if len(n) != len(nullid):
2314 if len(n) != len(nullid):
2315 raise TypeError()
2315 raise TypeError()
2316 return n
2316 return n
2317 except TypeError:
2317 except TypeError:
2318 raise util.Abort('changeset references must be full hexadecimal '
2318 raise util.Abort('changeset references must be full hexadecimal '
2319 'node identifiers')
2319 'node identifiers')
2320
2320
2321 if precursor is not None:
2321 if precursor is not None:
2322 metadata = {}
2322 metadata = {}
2323 if 'date' in opts:
2323 if 'date' in opts:
2324 metadata['date'] = opts['date']
2324 metadata['date'] = opts['date']
2325 metadata['user'] = opts['user'] or ui.username()
2325 metadata['user'] = opts['user'] or ui.username()
2326 succs = tuple(parsenodeid(succ) for succ in successors)
2326 succs = tuple(parsenodeid(succ) for succ in successors)
2327 l = repo.lock()
2327 l = repo.lock()
2328 try:
2328 try:
2329 tr = repo.transaction('debugobsolete')
2329 tr = repo.transaction('debugobsolete')
2330 try:
2330 try:
2331 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2331 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2332 opts['flags'], metadata)
2332 opts['flags'], metadata)
2333 tr.close()
2333 tr.close()
2334 finally:
2334 finally:
2335 tr.release()
2335 tr.release()
2336 finally:
2336 finally:
2337 l.release()
2337 l.release()
2338 else:
2338 else:
2339 for m in obsolete.allmarkers(repo):
2339 for m in obsolete.allmarkers(repo):
2340 cmdutil.showmarker(ui, m)
2340 cmdutil.showmarker(ui, m)
2341
2341
2342 @command('debugpathcomplete',
2342 @command('debugpathcomplete',
2343 [('f', 'full', None, _('complete an entire path')),
2343 [('f', 'full', None, _('complete an entire path')),
2344 ('n', 'normal', None, _('show only normal files')),
2344 ('n', 'normal', None, _('show only normal files')),
2345 ('a', 'added', None, _('show only added files')),
2345 ('a', 'added', None, _('show only added files')),
2346 ('r', 'removed', None, _('show only removed files'))],
2346 ('r', 'removed', None, _('show only removed files'))],
2347 _('FILESPEC...'))
2347 _('FILESPEC...'))
2348 def debugpathcomplete(ui, repo, *specs, **opts):
2348 def debugpathcomplete(ui, repo, *specs, **opts):
2349 '''complete part or all of a tracked path
2349 '''complete part or all of a tracked path
2350
2350
2351 This command supports shells that offer path name completion. It
2351 This command supports shells that offer path name completion. It
2352 currently completes only files already known to the dirstate.
2352 currently completes only files already known to the dirstate.
2353
2353
2354 Completion extends only to the next path segment unless
2354 Completion extends only to the next path segment unless
2355 --full is specified, in which case entire paths are used.'''
2355 --full is specified, in which case entire paths are used.'''
2356
2356
2357 def complete(path, acceptable):
2357 def complete(path, acceptable):
2358 dirstate = repo.dirstate
2358 dirstate = repo.dirstate
2359 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2359 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2360 rootdir = repo.root + os.sep
2360 rootdir = repo.root + os.sep
2361 if spec != repo.root and not spec.startswith(rootdir):
2361 if spec != repo.root and not spec.startswith(rootdir):
2362 return [], []
2362 return [], []
2363 if os.path.isdir(spec):
2363 if os.path.isdir(spec):
2364 spec += '/'
2364 spec += '/'
2365 spec = spec[len(rootdir):]
2365 spec = spec[len(rootdir):]
2366 fixpaths = os.sep != '/'
2366 fixpaths = os.sep != '/'
2367 if fixpaths:
2367 if fixpaths:
2368 spec = spec.replace(os.sep, '/')
2368 spec = spec.replace(os.sep, '/')
2369 speclen = len(spec)
2369 speclen = len(spec)
2370 fullpaths = opts['full']
2370 fullpaths = opts['full']
2371 files, dirs = set(), set()
2371 files, dirs = set(), set()
2372 adddir, addfile = dirs.add, files.add
2372 adddir, addfile = dirs.add, files.add
2373 for f, st in dirstate.iteritems():
2373 for f, st in dirstate.iteritems():
2374 if f.startswith(spec) and st[0] in acceptable:
2374 if f.startswith(spec) and st[0] in acceptable:
2375 if fixpaths:
2375 if fixpaths:
2376 f = f.replace('/', os.sep)
2376 f = f.replace('/', os.sep)
2377 if fullpaths:
2377 if fullpaths:
2378 addfile(f)
2378 addfile(f)
2379 continue
2379 continue
2380 s = f.find(os.sep, speclen)
2380 s = f.find(os.sep, speclen)
2381 if s >= 0:
2381 if s >= 0:
2382 adddir(f[:s])
2382 adddir(f[:s])
2383 else:
2383 else:
2384 addfile(f)
2384 addfile(f)
2385 return files, dirs
2385 return files, dirs
2386
2386
2387 acceptable = ''
2387 acceptable = ''
2388 if opts['normal']:
2388 if opts['normal']:
2389 acceptable += 'nm'
2389 acceptable += 'nm'
2390 if opts['added']:
2390 if opts['added']:
2391 acceptable += 'a'
2391 acceptable += 'a'
2392 if opts['removed']:
2392 if opts['removed']:
2393 acceptable += 'r'
2393 acceptable += 'r'
2394 cwd = repo.getcwd()
2394 cwd = repo.getcwd()
2395 if not specs:
2395 if not specs:
2396 specs = ['.']
2396 specs = ['.']
2397
2397
2398 files, dirs = set(), set()
2398 files, dirs = set(), set()
2399 for spec in specs:
2399 for spec in specs:
2400 f, d = complete(spec, acceptable or 'nmar')
2400 f, d = complete(spec, acceptable or 'nmar')
2401 files.update(f)
2401 files.update(f)
2402 dirs.update(d)
2402 dirs.update(d)
2403 files.update(dirs)
2403 files.update(dirs)
2404 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2404 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2405 ui.write('\n')
2405 ui.write('\n')
2406
2406
2407 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2407 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2408 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2408 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2409 '''access the pushkey key/value protocol
2409 '''access the pushkey key/value protocol
2410
2410
2411 With two args, list the keys in the given namespace.
2411 With two args, list the keys in the given namespace.
2412
2412
2413 With five args, set a key to new if it currently is set to old.
2413 With five args, set a key to new if it currently is set to old.
2414 Reports success or failure.
2414 Reports success or failure.
2415 '''
2415 '''
2416
2416
2417 target = hg.peer(ui, {}, repopath)
2417 target = hg.peer(ui, {}, repopath)
2418 if keyinfo:
2418 if keyinfo:
2419 key, old, new = keyinfo
2419 key, old, new = keyinfo
2420 r = target.pushkey(namespace, key, old, new)
2420 r = target.pushkey(namespace, key, old, new)
2421 ui.status(str(r) + '\n')
2421 ui.status(str(r) + '\n')
2422 return not r
2422 return not r
2423 else:
2423 else:
2424 for k, v in sorted(target.listkeys(namespace).iteritems()):
2424 for k, v in sorted(target.listkeys(namespace).iteritems()):
2425 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2425 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2426 v.encode('string-escape')))
2426 v.encode('string-escape')))
2427
2427
2428 @command('debugpvec', [], _('A B'))
2428 @command('debugpvec', [], _('A B'))
2429 def debugpvec(ui, repo, a, b=None):
2429 def debugpvec(ui, repo, a, b=None):
2430 ca = scmutil.revsingle(repo, a)
2430 ca = scmutil.revsingle(repo, a)
2431 cb = scmutil.revsingle(repo, b)
2431 cb = scmutil.revsingle(repo, b)
2432 pa = pvec.ctxpvec(ca)
2432 pa = pvec.ctxpvec(ca)
2433 pb = pvec.ctxpvec(cb)
2433 pb = pvec.ctxpvec(cb)
2434 if pa == pb:
2434 if pa == pb:
2435 rel = "="
2435 rel = "="
2436 elif pa > pb:
2436 elif pa > pb:
2437 rel = ">"
2437 rel = ">"
2438 elif pa < pb:
2438 elif pa < pb:
2439 rel = "<"
2439 rel = "<"
2440 elif pa | pb:
2440 elif pa | pb:
2441 rel = "|"
2441 rel = "|"
2442 ui.write(_("a: %s\n") % pa)
2442 ui.write(_("a: %s\n") % pa)
2443 ui.write(_("b: %s\n") % pb)
2443 ui.write(_("b: %s\n") % pb)
2444 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2444 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2445 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2445 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2446 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2446 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2447 pa.distance(pb), rel))
2447 pa.distance(pb), rel))
2448
2448
2449 @command('debugrebuilddirstate|debugrebuildstate',
2449 @command('debugrebuilddirstate|debugrebuildstate',
2450 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2450 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2451 _('[-r REV]'))
2451 _('[-r REV]'))
2452 def debugrebuilddirstate(ui, repo, rev):
2452 def debugrebuilddirstate(ui, repo, rev):
2453 """rebuild the dirstate as it would look like for the given revision
2453 """rebuild the dirstate as it would look like for the given revision
2454
2454
2455 If no revision is specified the first current parent will be used.
2455 If no revision is specified the first current parent will be used.
2456
2456
2457 The dirstate will be set to the files of the given revision.
2457 The dirstate will be set to the files of the given revision.
2458 The actual working directory content or existing dirstate
2458 The actual working directory content or existing dirstate
2459 information such as adds or removes is not considered.
2459 information such as adds or removes is not considered.
2460
2460
2461 One use of this command is to make the next :hg:`status` invocation
2461 One use of this command is to make the next :hg:`status` invocation
2462 check the actual file content.
2462 check the actual file content.
2463 """
2463 """
2464 ctx = scmutil.revsingle(repo, rev)
2464 ctx = scmutil.revsingle(repo, rev)
2465 wlock = repo.wlock()
2465 wlock = repo.wlock()
2466 try:
2466 try:
2467 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2467 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2468 finally:
2468 finally:
2469 wlock.release()
2469 wlock.release()
2470
2470
2471 @command('debugrename',
2471 @command('debugrename',
2472 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2472 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2473 _('[-r REV] FILE'))
2473 _('[-r REV] FILE'))
2474 def debugrename(ui, repo, file1, *pats, **opts):
2474 def debugrename(ui, repo, file1, *pats, **opts):
2475 """dump rename information"""
2475 """dump rename information"""
2476
2476
2477 ctx = scmutil.revsingle(repo, opts.get('rev'))
2477 ctx = scmutil.revsingle(repo, opts.get('rev'))
2478 m = scmutil.match(ctx, (file1,) + pats, opts)
2478 m = scmutil.match(ctx, (file1,) + pats, opts)
2479 for abs in ctx.walk(m):
2479 for abs in ctx.walk(m):
2480 fctx = ctx[abs]
2480 fctx = ctx[abs]
2481 o = fctx.filelog().renamed(fctx.filenode())
2481 o = fctx.filelog().renamed(fctx.filenode())
2482 rel = m.rel(abs)
2482 rel = m.rel(abs)
2483 if o:
2483 if o:
2484 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2484 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2485 else:
2485 else:
2486 ui.write(_("%s not renamed\n") % rel)
2486 ui.write(_("%s not renamed\n") % rel)
2487
2487
2488 @command('debugrevlog',
2488 @command('debugrevlog',
2489 [('c', 'changelog', False, _('open changelog')),
2489 [('c', 'changelog', False, _('open changelog')),
2490 ('m', 'manifest', False, _('open manifest')),
2490 ('m', 'manifest', False, _('open manifest')),
2491 ('d', 'dump', False, _('dump index data'))],
2491 ('d', 'dump', False, _('dump index data'))],
2492 _('-c|-m|FILE'))
2492 _('-c|-m|FILE'))
2493 def debugrevlog(ui, repo, file_=None, **opts):
2493 def debugrevlog(ui, repo, file_=None, **opts):
2494 """show data and statistics about a revlog"""
2494 """show data and statistics about a revlog"""
2495 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2495 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2496
2496
2497 if opts.get("dump"):
2497 if opts.get("dump"):
2498 numrevs = len(r)
2498 numrevs = len(r)
2499 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2499 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2500 " rawsize totalsize compression heads\n")
2500 " rawsize totalsize compression heads\n")
2501 ts = 0
2501 ts = 0
2502 heads = set()
2502 heads = set()
2503 for rev in xrange(numrevs):
2503 for rev in xrange(numrevs):
2504 dbase = r.deltaparent(rev)
2504 dbase = r.deltaparent(rev)
2505 if dbase == -1:
2505 if dbase == -1:
2506 dbase = rev
2506 dbase = rev
2507 cbase = r.chainbase(rev)
2507 cbase = r.chainbase(rev)
2508 p1, p2 = r.parentrevs(rev)
2508 p1, p2 = r.parentrevs(rev)
2509 rs = r.rawsize(rev)
2509 rs = r.rawsize(rev)
2510 ts = ts + rs
2510 ts = ts + rs
2511 heads -= set(r.parentrevs(rev))
2511 heads -= set(r.parentrevs(rev))
2512 heads.add(rev)
2512 heads.add(rev)
2513 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2513 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" %
2514 (rev, p1, p2, r.start(rev), r.end(rev),
2514 (rev, p1, p2, r.start(rev), r.end(rev),
2515 r.start(dbase), r.start(cbase),
2515 r.start(dbase), r.start(cbase),
2516 r.start(p1), r.start(p2),
2516 r.start(p1), r.start(p2),
2517 rs, ts, ts / r.end(rev), len(heads)))
2517 rs, ts, ts / r.end(rev), len(heads)))
2518 return 0
2518 return 0
2519
2519
2520 v = r.version
2520 v = r.version
2521 format = v & 0xFFFF
2521 format = v & 0xFFFF
2522 flags = []
2522 flags = []
2523 gdelta = False
2523 gdelta = False
2524 if v & revlog.REVLOGNGINLINEDATA:
2524 if v & revlog.REVLOGNGINLINEDATA:
2525 flags.append('inline')
2525 flags.append('inline')
2526 if v & revlog.REVLOGGENERALDELTA:
2526 if v & revlog.REVLOGGENERALDELTA:
2527 gdelta = True
2527 gdelta = True
2528 flags.append('generaldelta')
2528 flags.append('generaldelta')
2529 if not flags:
2529 if not flags:
2530 flags = ['(none)']
2530 flags = ['(none)']
2531
2531
2532 nummerges = 0
2532 nummerges = 0
2533 numfull = 0
2533 numfull = 0
2534 numprev = 0
2534 numprev = 0
2535 nump1 = 0
2535 nump1 = 0
2536 nump2 = 0
2536 nump2 = 0
2537 numother = 0
2537 numother = 0
2538 nump1prev = 0
2538 nump1prev = 0
2539 nump2prev = 0
2539 nump2prev = 0
2540 chainlengths = []
2540 chainlengths = []
2541
2541
2542 datasize = [None, 0, 0L]
2542 datasize = [None, 0, 0L]
2543 fullsize = [None, 0, 0L]
2543 fullsize = [None, 0, 0L]
2544 deltasize = [None, 0, 0L]
2544 deltasize = [None, 0, 0L]
2545
2545
2546 def addsize(size, l):
2546 def addsize(size, l):
2547 if l[0] is None or size < l[0]:
2547 if l[0] is None or size < l[0]:
2548 l[0] = size
2548 l[0] = size
2549 if size > l[1]:
2549 if size > l[1]:
2550 l[1] = size
2550 l[1] = size
2551 l[2] += size
2551 l[2] += size
2552
2552
2553 numrevs = len(r)
2553 numrevs = len(r)
2554 for rev in xrange(numrevs):
2554 for rev in xrange(numrevs):
2555 p1, p2 = r.parentrevs(rev)
2555 p1, p2 = r.parentrevs(rev)
2556 delta = r.deltaparent(rev)
2556 delta = r.deltaparent(rev)
2557 if format > 0:
2557 if format > 0:
2558 addsize(r.rawsize(rev), datasize)
2558 addsize(r.rawsize(rev), datasize)
2559 if p2 != nullrev:
2559 if p2 != nullrev:
2560 nummerges += 1
2560 nummerges += 1
2561 size = r.length(rev)
2561 size = r.length(rev)
2562 if delta == nullrev:
2562 if delta == nullrev:
2563 chainlengths.append(0)
2563 chainlengths.append(0)
2564 numfull += 1
2564 numfull += 1
2565 addsize(size, fullsize)
2565 addsize(size, fullsize)
2566 else:
2566 else:
2567 chainlengths.append(chainlengths[delta] + 1)
2567 chainlengths.append(chainlengths[delta] + 1)
2568 addsize(size, deltasize)
2568 addsize(size, deltasize)
2569 if delta == rev - 1:
2569 if delta == rev - 1:
2570 numprev += 1
2570 numprev += 1
2571 if delta == p1:
2571 if delta == p1:
2572 nump1prev += 1
2572 nump1prev += 1
2573 elif delta == p2:
2573 elif delta == p2:
2574 nump2prev += 1
2574 nump2prev += 1
2575 elif delta == p1:
2575 elif delta == p1:
2576 nump1 += 1
2576 nump1 += 1
2577 elif delta == p2:
2577 elif delta == p2:
2578 nump2 += 1
2578 nump2 += 1
2579 elif delta != nullrev:
2579 elif delta != nullrev:
2580 numother += 1
2580 numother += 1
2581
2581
2582 # Adjust size min value for empty cases
2582 # Adjust size min value for empty cases
2583 for size in (datasize, fullsize, deltasize):
2583 for size in (datasize, fullsize, deltasize):
2584 if size[0] is None:
2584 if size[0] is None:
2585 size[0] = 0
2585 size[0] = 0
2586
2586
2587 numdeltas = numrevs - numfull
2587 numdeltas = numrevs - numfull
2588 numoprev = numprev - nump1prev - nump2prev
2588 numoprev = numprev - nump1prev - nump2prev
2589 totalrawsize = datasize[2]
2589 totalrawsize = datasize[2]
2590 datasize[2] /= numrevs
2590 datasize[2] /= numrevs
2591 fulltotal = fullsize[2]
2591 fulltotal = fullsize[2]
2592 fullsize[2] /= numfull
2592 fullsize[2] /= numfull
2593 deltatotal = deltasize[2]
2593 deltatotal = deltasize[2]
2594 if numrevs - numfull > 0:
2594 if numrevs - numfull > 0:
2595 deltasize[2] /= numrevs - numfull
2595 deltasize[2] /= numrevs - numfull
2596 totalsize = fulltotal + deltatotal
2596 totalsize = fulltotal + deltatotal
2597 avgchainlen = sum(chainlengths) / numrevs
2597 avgchainlen = sum(chainlengths) / numrevs
2598 compratio = totalrawsize / totalsize
2598 compratio = totalrawsize / totalsize
2599
2599
2600 basedfmtstr = '%%%dd\n'
2600 basedfmtstr = '%%%dd\n'
2601 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2601 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2602
2602
2603 def dfmtstr(max):
2603 def dfmtstr(max):
2604 return basedfmtstr % len(str(max))
2604 return basedfmtstr % len(str(max))
2605 def pcfmtstr(max, padding=0):
2605 def pcfmtstr(max, padding=0):
2606 return basepcfmtstr % (len(str(max)), ' ' * padding)
2606 return basepcfmtstr % (len(str(max)), ' ' * padding)
2607
2607
2608 def pcfmt(value, total):
2608 def pcfmt(value, total):
2609 return (value, 100 * float(value) / total)
2609 return (value, 100 * float(value) / total)
2610
2610
2611 ui.write(('format : %d\n') % format)
2611 ui.write(('format : %d\n') % format)
2612 ui.write(('flags : %s\n') % ', '.join(flags))
2612 ui.write(('flags : %s\n') % ', '.join(flags))
2613
2613
2614 ui.write('\n')
2614 ui.write('\n')
2615 fmt = pcfmtstr(totalsize)
2615 fmt = pcfmtstr(totalsize)
2616 fmt2 = dfmtstr(totalsize)
2616 fmt2 = dfmtstr(totalsize)
2617 ui.write(('revisions : ') + fmt2 % numrevs)
2617 ui.write(('revisions : ') + fmt2 % numrevs)
2618 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2618 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2619 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2619 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2620 ui.write(('revisions : ') + fmt2 % numrevs)
2620 ui.write(('revisions : ') + fmt2 % numrevs)
2621 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2621 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2622 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2622 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2623 ui.write(('revision size : ') + fmt2 % totalsize)
2623 ui.write(('revision size : ') + fmt2 % totalsize)
2624 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2624 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2625 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2625 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2626
2626
2627 ui.write('\n')
2627 ui.write('\n')
2628 fmt = dfmtstr(max(avgchainlen, compratio))
2628 fmt = dfmtstr(max(avgchainlen, compratio))
2629 ui.write(('avg chain length : ') + fmt % avgchainlen)
2629 ui.write(('avg chain length : ') + fmt % avgchainlen)
2630 ui.write(('compression ratio : ') + fmt % compratio)
2630 ui.write(('compression ratio : ') + fmt % compratio)
2631
2631
2632 if format > 0:
2632 if format > 0:
2633 ui.write('\n')
2633 ui.write('\n')
2634 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2634 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2635 % tuple(datasize))
2635 % tuple(datasize))
2636 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2636 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2637 % tuple(fullsize))
2637 % tuple(fullsize))
2638 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2638 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2639 % tuple(deltasize))
2639 % tuple(deltasize))
2640
2640
2641 if numdeltas > 0:
2641 if numdeltas > 0:
2642 ui.write('\n')
2642 ui.write('\n')
2643 fmt = pcfmtstr(numdeltas)
2643 fmt = pcfmtstr(numdeltas)
2644 fmt2 = pcfmtstr(numdeltas, 4)
2644 fmt2 = pcfmtstr(numdeltas, 4)
2645 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2645 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2646 if numprev > 0:
2646 if numprev > 0:
2647 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2647 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2648 numprev))
2648 numprev))
2649 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2649 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2650 numprev))
2650 numprev))
2651 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2651 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2652 numprev))
2652 numprev))
2653 if gdelta:
2653 if gdelta:
2654 ui.write(('deltas against p1 : ')
2654 ui.write(('deltas against p1 : ')
2655 + fmt % pcfmt(nump1, numdeltas))
2655 + fmt % pcfmt(nump1, numdeltas))
2656 ui.write(('deltas against p2 : ')
2656 ui.write(('deltas against p2 : ')
2657 + fmt % pcfmt(nump2, numdeltas))
2657 + fmt % pcfmt(nump2, numdeltas))
2658 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2658 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2659 numdeltas))
2659 numdeltas))
2660
2660
2661 @command('debugrevspec',
2661 @command('debugrevspec',
2662 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2662 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2663 ('REVSPEC'))
2663 ('REVSPEC'))
2664 def debugrevspec(ui, repo, expr, **opts):
2664 def debugrevspec(ui, repo, expr, **opts):
2665 """parse and apply a revision specification
2665 """parse and apply a revision specification
2666
2666
2667 Use --verbose to print the parsed tree before and after aliases
2667 Use --verbose to print the parsed tree before and after aliases
2668 expansion.
2668 expansion.
2669 """
2669 """
2670 if ui.verbose:
2670 if ui.verbose:
2671 tree = revset.parse(expr)[0]
2671 tree = revset.parse(expr)[0]
2672 ui.note(revset.prettyformat(tree), "\n")
2672 ui.note(revset.prettyformat(tree), "\n")
2673 newtree = revset.findaliases(ui, tree)
2673 newtree = revset.findaliases(ui, tree)
2674 if newtree != tree:
2674 if newtree != tree:
2675 ui.note(revset.prettyformat(newtree), "\n")
2675 ui.note(revset.prettyformat(newtree), "\n")
2676 if opts["optimize"]:
2676 if opts["optimize"]:
2677 weight, optimizedtree = revset.optimize(newtree, True)
2677 weight, optimizedtree = revset.optimize(newtree, True)
2678 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2678 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2679 func = revset.match(ui, expr)
2679 func = revset.match(ui, expr)
2680 for c in func(repo, revset.spanset(repo)):
2680 for c in func(repo, revset.spanset(repo)):
2681 ui.write("%s\n" % c)
2681 ui.write("%s\n" % c)
2682
2682
2683 @command('debugsetparents', [], _('REV1 [REV2]'))
2683 @command('debugsetparents', [], _('REV1 [REV2]'))
2684 def debugsetparents(ui, repo, rev1, rev2=None):
2684 def debugsetparents(ui, repo, rev1, rev2=None):
2685 """manually set the parents of the current working directory
2685 """manually set the parents of the current working directory
2686
2686
2687 This is useful for writing repository conversion tools, but should
2687 This is useful for writing repository conversion tools, but should
2688 be used with care.
2688 be used with care.
2689
2689
2690 Returns 0 on success.
2690 Returns 0 on success.
2691 """
2691 """
2692
2692
2693 r1 = scmutil.revsingle(repo, rev1).node()
2693 r1 = scmutil.revsingle(repo, rev1).node()
2694 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2694 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2695
2695
2696 wlock = repo.wlock()
2696 wlock = repo.wlock()
2697 try:
2697 try:
2698 repo.setparents(r1, r2)
2698 repo.setparents(r1, r2)
2699 finally:
2699 finally:
2700 wlock.release()
2700 wlock.release()
2701
2701
2702 @command('debugdirstate|debugstate',
2702 @command('debugdirstate|debugstate',
2703 [('', 'nodates', None, _('do not display the saved mtime')),
2703 [('', 'nodates', None, _('do not display the saved mtime')),
2704 ('', 'datesort', None, _('sort by saved mtime'))],
2704 ('', 'datesort', None, _('sort by saved mtime'))],
2705 _('[OPTION]...'))
2705 _('[OPTION]...'))
2706 def debugstate(ui, repo, nodates=None, datesort=None):
2706 def debugstate(ui, repo, nodates=None, datesort=None):
2707 """show the contents of the current dirstate"""
2707 """show the contents of the current dirstate"""
2708 timestr = ""
2708 timestr = ""
2709 showdate = not nodates
2709 showdate = not nodates
2710 if datesort:
2710 if datesort:
2711 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2711 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2712 else:
2712 else:
2713 keyfunc = None # sort by filename
2713 keyfunc = None # sort by filename
2714 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2714 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2715 if showdate:
2715 if showdate:
2716 if ent[3] == -1:
2716 if ent[3] == -1:
2717 # Pad or slice to locale representation
2717 # Pad or slice to locale representation
2718 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2718 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2719 time.localtime(0)))
2719 time.localtime(0)))
2720 timestr = 'unset'
2720 timestr = 'unset'
2721 timestr = (timestr[:locale_len] +
2721 timestr = (timestr[:locale_len] +
2722 ' ' * (locale_len - len(timestr)))
2722 ' ' * (locale_len - len(timestr)))
2723 else:
2723 else:
2724 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2724 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2725 time.localtime(ent[3]))
2725 time.localtime(ent[3]))
2726 if ent[1] & 020000:
2726 if ent[1] & 020000:
2727 mode = 'lnk'
2727 mode = 'lnk'
2728 else:
2728 else:
2729 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2729 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2730 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2730 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2731 for f in repo.dirstate.copies():
2731 for f in repo.dirstate.copies():
2732 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2732 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2733
2733
2734 @command('debugsub',
2734 @command('debugsub',
2735 [('r', 'rev', '',
2735 [('r', 'rev', '',
2736 _('revision to check'), _('REV'))],
2736 _('revision to check'), _('REV'))],
2737 _('[-r REV] [REV]'))
2737 _('[-r REV] [REV]'))
2738 def debugsub(ui, repo, rev=None):
2738 def debugsub(ui, repo, rev=None):
2739 ctx = scmutil.revsingle(repo, rev, None)
2739 ctx = scmutil.revsingle(repo, rev, None)
2740 for k, v in sorted(ctx.substate.items()):
2740 for k, v in sorted(ctx.substate.items()):
2741 ui.write(('path %s\n') % k)
2741 ui.write(('path %s\n') % k)
2742 ui.write((' source %s\n') % v[0])
2742 ui.write((' source %s\n') % v[0])
2743 ui.write((' revision %s\n') % v[1])
2743 ui.write((' revision %s\n') % v[1])
2744
2744
2745 @command('debugsuccessorssets',
2745 @command('debugsuccessorssets',
2746 [],
2746 [],
2747 _('[REV]'))
2747 _('[REV]'))
2748 def debugsuccessorssets(ui, repo, *revs):
2748 def debugsuccessorssets(ui, repo, *revs):
2749 """show set of successors for revision
2749 """show set of successors for revision
2750
2750
2751 A successors set of changeset A is a consistent group of revisions that
2751 A successors set of changeset A is a consistent group of revisions that
2752 succeed A. It contains non-obsolete changesets only.
2752 succeed A. It contains non-obsolete changesets only.
2753
2753
2754 In most cases a changeset A has a single successors set containing a single
2754 In most cases a changeset A has a single successors set containing a single
2755 successor (changeset A replaced by A').
2755 successor (changeset A replaced by A').
2756
2756
2757 A changeset that is made obsolete with no successors are called "pruned".
2757 A changeset that is made obsolete with no successors are called "pruned".
2758 Such changesets have no successors sets at all.
2758 Such changesets have no successors sets at all.
2759
2759
2760 A changeset that has been "split" will have a successors set containing
2760 A changeset that has been "split" will have a successors set containing
2761 more than one successor.
2761 more than one successor.
2762
2762
2763 A changeset that has been rewritten in multiple different ways is called
2763 A changeset that has been rewritten in multiple different ways is called
2764 "divergent". Such changesets have multiple successor sets (each of which
2764 "divergent". Such changesets have multiple successor sets (each of which
2765 may also be split, i.e. have multiple successors).
2765 may also be split, i.e. have multiple successors).
2766
2766
2767 Results are displayed as follows::
2767 Results are displayed as follows::
2768
2768
2769 <rev1>
2769 <rev1>
2770 <successors-1A>
2770 <successors-1A>
2771 <rev2>
2771 <rev2>
2772 <successors-2A>
2772 <successors-2A>
2773 <successors-2B1> <successors-2B2> <successors-2B3>
2773 <successors-2B1> <successors-2B2> <successors-2B3>
2774
2774
2775 Here rev2 has two possible (i.e. divergent) successors sets. The first
2775 Here rev2 has two possible (i.e. divergent) successors sets. The first
2776 holds one element, whereas the second holds three (i.e. the changeset has
2776 holds one element, whereas the second holds three (i.e. the changeset has
2777 been split).
2777 been split).
2778 """
2778 """
2779 # passed to successorssets caching computation from one call to another
2779 # passed to successorssets caching computation from one call to another
2780 cache = {}
2780 cache = {}
2781 ctx2str = str
2781 ctx2str = str
2782 node2str = short
2782 node2str = short
2783 if ui.debug():
2783 if ui.debug():
2784 def ctx2str(ctx):
2784 def ctx2str(ctx):
2785 return ctx.hex()
2785 return ctx.hex()
2786 node2str = hex
2786 node2str = hex
2787 for rev in scmutil.revrange(repo, revs):
2787 for rev in scmutil.revrange(repo, revs):
2788 ctx = repo[rev]
2788 ctx = repo[rev]
2789 ui.write('%s\n'% ctx2str(ctx))
2789 ui.write('%s\n'% ctx2str(ctx))
2790 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2790 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2791 if succsset:
2791 if succsset:
2792 ui.write(' ')
2792 ui.write(' ')
2793 ui.write(node2str(succsset[0]))
2793 ui.write(node2str(succsset[0]))
2794 for node in succsset[1:]:
2794 for node in succsset[1:]:
2795 ui.write(' ')
2795 ui.write(' ')
2796 ui.write(node2str(node))
2796 ui.write(node2str(node))
2797 ui.write('\n')
2797 ui.write('\n')
2798
2798
2799 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2799 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2800 def debugwalk(ui, repo, *pats, **opts):
2800 def debugwalk(ui, repo, *pats, **opts):
2801 """show how files match on given patterns"""
2801 """show how files match on given patterns"""
2802 m = scmutil.match(repo[None], pats, opts)
2802 m = scmutil.match(repo[None], pats, opts)
2803 items = list(repo.walk(m))
2803 items = list(repo.walk(m))
2804 if not items:
2804 if not items:
2805 return
2805 return
2806 f = lambda fn: fn
2806 f = lambda fn: fn
2807 if ui.configbool('ui', 'slash') and os.sep != '/':
2807 if ui.configbool('ui', 'slash') and os.sep != '/':
2808 f = lambda fn: util.normpath(fn)
2808 f = lambda fn: util.normpath(fn)
2809 fmt = 'f %%-%ds %%-%ds %%s' % (
2809 fmt = 'f %%-%ds %%-%ds %%s' % (
2810 max([len(abs) for abs in items]),
2810 max([len(abs) for abs in items]),
2811 max([len(m.rel(abs)) for abs in items]))
2811 max([len(m.rel(abs)) for abs in items]))
2812 for abs in items:
2812 for abs in items:
2813 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2813 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2814 ui.write("%s\n" % line.rstrip())
2814 ui.write("%s\n" % line.rstrip())
2815
2815
2816 @command('debugwireargs',
2816 @command('debugwireargs',
2817 [('', 'three', '', 'three'),
2817 [('', 'three', '', 'three'),
2818 ('', 'four', '', 'four'),
2818 ('', 'four', '', 'four'),
2819 ('', 'five', '', 'five'),
2819 ('', 'five', '', 'five'),
2820 ] + remoteopts,
2820 ] + remoteopts,
2821 _('REPO [OPTIONS]... [ONE [TWO]]'))
2821 _('REPO [OPTIONS]... [ONE [TWO]]'))
2822 def debugwireargs(ui, repopath, *vals, **opts):
2822 def debugwireargs(ui, repopath, *vals, **opts):
2823 repo = hg.peer(ui, opts, repopath)
2823 repo = hg.peer(ui, opts, repopath)
2824 for opt in remoteopts:
2824 for opt in remoteopts:
2825 del opts[opt[1]]
2825 del opts[opt[1]]
2826 args = {}
2826 args = {}
2827 for k, v in opts.iteritems():
2827 for k, v in opts.iteritems():
2828 if v:
2828 if v:
2829 args[k] = v
2829 args[k] = v
2830 # run twice to check that we don't mess up the stream for the next command
2830 # run twice to check that we don't mess up the stream for the next command
2831 res1 = repo.debugwireargs(*vals, **args)
2831 res1 = repo.debugwireargs(*vals, **args)
2832 res2 = repo.debugwireargs(*vals, **args)
2832 res2 = repo.debugwireargs(*vals, **args)
2833 ui.write("%s\n" % res1)
2833 ui.write("%s\n" % res1)
2834 if res1 != res2:
2834 if res1 != res2:
2835 ui.warn("%s\n" % res2)
2835 ui.warn("%s\n" % res2)
2836
2836
2837 @command('^diff',
2837 @command('^diff',
2838 [('r', 'rev', [], _('revision'), _('REV')),
2838 [('r', 'rev', [], _('revision'), _('REV')),
2839 ('c', 'change', '', _('change made by revision'), _('REV'))
2839 ('c', 'change', '', _('change made by revision'), _('REV'))
2840 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2840 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2841 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2841 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2842 def diff(ui, repo, *pats, **opts):
2842 def diff(ui, repo, *pats, **opts):
2843 """diff repository (or selected files)
2843 """diff repository (or selected files)
2844
2844
2845 Show differences between revisions for the specified files.
2845 Show differences between revisions for the specified files.
2846
2846
2847 Differences between files are shown using the unified diff format.
2847 Differences between files are shown using the unified diff format.
2848
2848
2849 .. note::
2849 .. note::
2850
2850
2851 diff may generate unexpected results for merges, as it will
2851 diff may generate unexpected results for merges, as it will
2852 default to comparing against the working directory's first
2852 default to comparing against the working directory's first
2853 parent changeset if no revisions are specified.
2853 parent changeset if no revisions are specified.
2854
2854
2855 When two revision arguments are given, then changes are shown
2855 When two revision arguments are given, then changes are shown
2856 between those revisions. If only one revision is specified then
2856 between those revisions. If only one revision is specified then
2857 that revision is compared to the working directory, and, when no
2857 that revision is compared to the working directory, and, when no
2858 revisions are specified, the working directory files are compared
2858 revisions are specified, the working directory files are compared
2859 to its parent.
2859 to its parent.
2860
2860
2861 Alternatively you can specify -c/--change with a revision to see
2861 Alternatively you can specify -c/--change with a revision to see
2862 the changes in that changeset relative to its first parent.
2862 the changes in that changeset relative to its first parent.
2863
2863
2864 Without the -a/--text option, diff will avoid generating diffs of
2864 Without the -a/--text option, diff will avoid generating diffs of
2865 files it detects as binary. With -a, diff will generate a diff
2865 files it detects as binary. With -a, diff will generate a diff
2866 anyway, probably with undesirable results.
2866 anyway, probably with undesirable results.
2867
2867
2868 Use the -g/--git option to generate diffs in the git extended diff
2868 Use the -g/--git option to generate diffs in the git extended diff
2869 format. For more information, read :hg:`help diffs`.
2869 format. For more information, read :hg:`help diffs`.
2870
2870
2871 .. container:: verbose
2871 .. container:: verbose
2872
2872
2873 Examples:
2873 Examples:
2874
2874
2875 - compare a file in the current working directory to its parent::
2875 - compare a file in the current working directory to its parent::
2876
2876
2877 hg diff foo.c
2877 hg diff foo.c
2878
2878
2879 - compare two historical versions of a directory, with rename info::
2879 - compare two historical versions of a directory, with rename info::
2880
2880
2881 hg diff --git -r 1.0:1.2 lib/
2881 hg diff --git -r 1.0:1.2 lib/
2882
2882
2883 - get change stats relative to the last change on some date::
2883 - get change stats relative to the last change on some date::
2884
2884
2885 hg diff --stat -r "date('may 2')"
2885 hg diff --stat -r "date('may 2')"
2886
2886
2887 - diff all newly-added files that contain a keyword::
2887 - diff all newly-added files that contain a keyword::
2888
2888
2889 hg diff "set:added() and grep(GNU)"
2889 hg diff "set:added() and grep(GNU)"
2890
2890
2891 - compare a revision and its parents::
2891 - compare a revision and its parents::
2892
2892
2893 hg diff -c 9353 # compare against first parent
2893 hg diff -c 9353 # compare against first parent
2894 hg diff -r 9353^:9353 # same using revset syntax
2894 hg diff -r 9353^:9353 # same using revset syntax
2895 hg diff -r 9353^2:9353 # compare against the second parent
2895 hg diff -r 9353^2:9353 # compare against the second parent
2896
2896
2897 Returns 0 on success.
2897 Returns 0 on success.
2898 """
2898 """
2899
2899
2900 revs = opts.get('rev')
2900 revs = opts.get('rev')
2901 change = opts.get('change')
2901 change = opts.get('change')
2902 stat = opts.get('stat')
2902 stat = opts.get('stat')
2903 reverse = opts.get('reverse')
2903 reverse = opts.get('reverse')
2904
2904
2905 if revs and change:
2905 if revs and change:
2906 msg = _('cannot specify --rev and --change at the same time')
2906 msg = _('cannot specify --rev and --change at the same time')
2907 raise util.Abort(msg)
2907 raise util.Abort(msg)
2908 elif change:
2908 elif change:
2909 node2 = scmutil.revsingle(repo, change, None).node()
2909 node2 = scmutil.revsingle(repo, change, None).node()
2910 node1 = repo[node2].p1().node()
2910 node1 = repo[node2].p1().node()
2911 else:
2911 else:
2912 node1, node2 = scmutil.revpair(repo, revs)
2912 node1, node2 = scmutil.revpair(repo, revs)
2913
2913
2914 if reverse:
2914 if reverse:
2915 node1, node2 = node2, node1
2915 node1, node2 = node2, node1
2916
2916
2917 diffopts = patch.diffopts(ui, opts)
2917 diffopts = patch.diffopts(ui, opts)
2918 m = scmutil.match(repo[node2], pats, opts)
2918 m = scmutil.match(repo[node2], pats, opts)
2919 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2919 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2920 listsubrepos=opts.get('subrepos'))
2920 listsubrepos=opts.get('subrepos'))
2921
2921
2922 @command('^export',
2922 @command('^export',
2923 [('o', 'output', '',
2923 [('o', 'output', '',
2924 _('print output to file with formatted name'), _('FORMAT')),
2924 _('print output to file with formatted name'), _('FORMAT')),
2925 ('', 'switch-parent', None, _('diff against the second parent')),
2925 ('', 'switch-parent', None, _('diff against the second parent')),
2926 ('r', 'rev', [], _('revisions to export'), _('REV')),
2926 ('r', 'rev', [], _('revisions to export'), _('REV')),
2927 ] + diffopts,
2927 ] + diffopts,
2928 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2928 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2929 def export(ui, repo, *changesets, **opts):
2929 def export(ui, repo, *changesets, **opts):
2930 """dump the header and diffs for one or more changesets
2930 """dump the header and diffs for one or more changesets
2931
2931
2932 Print the changeset header and diffs for one or more revisions.
2932 Print the changeset header and diffs for one or more revisions.
2933 If no revision is given, the parent of the working directory is used.
2933 If no revision is given, the parent of the working directory is used.
2934
2934
2935 The information shown in the changeset header is: author, date,
2935 The information shown in the changeset header is: author, date,
2936 branch name (if non-default), changeset hash, parent(s) and commit
2936 branch name (if non-default), changeset hash, parent(s) and commit
2937 comment.
2937 comment.
2938
2938
2939 .. note::
2939 .. note::
2940
2940
2941 export may generate unexpected diff output for merge
2941 export may generate unexpected diff output for merge
2942 changesets, as it will compare the merge changeset against its
2942 changesets, as it will compare the merge changeset against its
2943 first parent only.
2943 first parent only.
2944
2944
2945 Output may be to a file, in which case the name of the file is
2945 Output may be to a file, in which case the name of the file is
2946 given using a format string. The formatting rules are as follows:
2946 given using a format string. The formatting rules are as follows:
2947
2947
2948 :``%%``: literal "%" character
2948 :``%%``: literal "%" character
2949 :``%H``: changeset hash (40 hexadecimal digits)
2949 :``%H``: changeset hash (40 hexadecimal digits)
2950 :``%N``: number of patches being generated
2950 :``%N``: number of patches being generated
2951 :``%R``: changeset revision number
2951 :``%R``: changeset revision number
2952 :``%b``: basename of the exporting repository
2952 :``%b``: basename of the exporting repository
2953 :``%h``: short-form changeset hash (12 hexadecimal digits)
2953 :``%h``: short-form changeset hash (12 hexadecimal digits)
2954 :``%m``: first line of the commit message (only alphanumeric characters)
2954 :``%m``: first line of the commit message (only alphanumeric characters)
2955 :``%n``: zero-padded sequence number, starting at 1
2955 :``%n``: zero-padded sequence number, starting at 1
2956 :``%r``: zero-padded changeset revision number
2956 :``%r``: zero-padded changeset revision number
2957
2957
2958 Without the -a/--text option, export will avoid generating diffs
2958 Without the -a/--text option, export will avoid generating diffs
2959 of files it detects as binary. With -a, export will generate a
2959 of files it detects as binary. With -a, export will generate a
2960 diff anyway, probably with undesirable results.
2960 diff anyway, probably with undesirable results.
2961
2961
2962 Use the -g/--git option to generate diffs in the git extended diff
2962 Use the -g/--git option to generate diffs in the git extended diff
2963 format. See :hg:`help diffs` for more information.
2963 format. See :hg:`help diffs` for more information.
2964
2964
2965 With the --switch-parent option, the diff will be against the
2965 With the --switch-parent option, the diff will be against the
2966 second parent. It can be useful to review a merge.
2966 second parent. It can be useful to review a merge.
2967
2967
2968 .. container:: verbose
2968 .. container:: verbose
2969
2969
2970 Examples:
2970 Examples:
2971
2971
2972 - use export and import to transplant a bugfix to the current
2972 - use export and import to transplant a bugfix to the current
2973 branch::
2973 branch::
2974
2974
2975 hg export -r 9353 | hg import -
2975 hg export -r 9353 | hg import -
2976
2976
2977 - export all the changesets between two revisions to a file with
2977 - export all the changesets between two revisions to a file with
2978 rename information::
2978 rename information::
2979
2979
2980 hg export --git -r 123:150 > changes.txt
2980 hg export --git -r 123:150 > changes.txt
2981
2981
2982 - split outgoing changes into a series of patches with
2982 - split outgoing changes into a series of patches with
2983 descriptive names::
2983 descriptive names::
2984
2984
2985 hg export -r "outgoing()" -o "%n-%m.patch"
2985 hg export -r "outgoing()" -o "%n-%m.patch"
2986
2986
2987 Returns 0 on success.
2987 Returns 0 on success.
2988 """
2988 """
2989 changesets += tuple(opts.get('rev', []))
2989 changesets += tuple(opts.get('rev', []))
2990 if not changesets:
2990 if not changesets:
2991 changesets = ['.']
2991 changesets = ['.']
2992 revs = scmutil.revrange(repo, changesets)
2992 revs = scmutil.revrange(repo, changesets)
2993 if not revs:
2993 if not revs:
2994 raise util.Abort(_("export requires at least one changeset"))
2994 raise util.Abort(_("export requires at least one changeset"))
2995 if len(revs) > 1:
2995 if len(revs) > 1:
2996 ui.note(_('exporting patches:\n'))
2996 ui.note(_('exporting patches:\n'))
2997 else:
2997 else:
2998 ui.note(_('exporting patch:\n'))
2998 ui.note(_('exporting patch:\n'))
2999 cmdutil.export(repo, revs, template=opts.get('output'),
2999 cmdutil.export(repo, revs, template=opts.get('output'),
3000 switch_parent=opts.get('switch_parent'),
3000 switch_parent=opts.get('switch_parent'),
3001 opts=patch.diffopts(ui, opts))
3001 opts=patch.diffopts(ui, opts))
3002
3002
3003 @command('^forget', walkopts, _('[OPTION]... FILE...'))
3003 @command('^forget', walkopts, _('[OPTION]... FILE...'))
3004 def forget(ui, repo, *pats, **opts):
3004 def forget(ui, repo, *pats, **opts):
3005 """forget the specified files on the next commit
3005 """forget the specified files on the next commit
3006
3006
3007 Mark the specified files so they will no longer be tracked
3007 Mark the specified files so they will no longer be tracked
3008 after the next commit.
3008 after the next commit.
3009
3009
3010 This only removes files from the current branch, not from the
3010 This only removes files from the current branch, not from the
3011 entire project history, and it does not delete them from the
3011 entire project history, and it does not delete them from the
3012 working directory.
3012 working directory.
3013
3013
3014 To undo a forget before the next commit, see :hg:`add`.
3014 To undo a forget before the next commit, see :hg:`add`.
3015
3015
3016 .. container:: verbose
3016 .. container:: verbose
3017
3017
3018 Examples:
3018 Examples:
3019
3019
3020 - forget newly-added binary files::
3020 - forget newly-added binary files::
3021
3021
3022 hg forget "set:added() and binary()"
3022 hg forget "set:added() and binary()"
3023
3023
3024 - forget files that would be excluded by .hgignore::
3024 - forget files that would be excluded by .hgignore::
3025
3025
3026 hg forget "set:hgignore()"
3026 hg forget "set:hgignore()"
3027
3027
3028 Returns 0 on success.
3028 Returns 0 on success.
3029 """
3029 """
3030
3030
3031 if not pats:
3031 if not pats:
3032 raise util.Abort(_('no files specified'))
3032 raise util.Abort(_('no files specified'))
3033
3033
3034 m = scmutil.match(repo[None], pats, opts)
3034 m = scmutil.match(repo[None], pats, opts)
3035 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3035 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3036 return rejected and 1 or 0
3036 return rejected and 1 or 0
3037
3037
3038 @command(
3038 @command(
3039 'graft',
3039 'graft',
3040 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3040 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3041 ('c', 'continue', False, _('resume interrupted graft')),
3041 ('c', 'continue', False, _('resume interrupted graft')),
3042 ('e', 'edit', False, _('invoke editor on commit messages')),
3042 ('e', 'edit', False, _('invoke editor on commit messages')),
3043 ('', 'log', None, _('append graft info to log message')),
3043 ('', 'log', None, _('append graft info to log message')),
3044 ('D', 'currentdate', False,
3044 ('D', 'currentdate', False,
3045 _('record the current date as commit date')),
3045 _('record the current date as commit date')),
3046 ('U', 'currentuser', False,
3046 ('U', 'currentuser', False,
3047 _('record the current user as committer'), _('DATE'))]
3047 _('record the current user as committer'), _('DATE'))]
3048 + commitopts2 + mergetoolopts + dryrunopts,
3048 + commitopts2 + mergetoolopts + dryrunopts,
3049 _('[OPTION]... [-r] REV...'))
3049 _('[OPTION]... [-r] REV...'))
3050 def graft(ui, repo, *revs, **opts):
3050 def graft(ui, repo, *revs, **opts):
3051 '''copy changes from other branches onto the current branch
3051 '''copy changes from other branches onto the current branch
3052
3052
3053 This command uses Mercurial's merge logic to copy individual
3053 This command uses Mercurial's merge logic to copy individual
3054 changes from other branches without merging branches in the
3054 changes from other branches without merging branches in the
3055 history graph. This is sometimes known as 'backporting' or
3055 history graph. This is sometimes known as 'backporting' or
3056 'cherry-picking'. By default, graft will copy user, date, and
3056 'cherry-picking'. By default, graft will copy user, date, and
3057 description from the source changesets.
3057 description from the source changesets.
3058
3058
3059 Changesets that are ancestors of the current revision, that have
3059 Changesets that are ancestors of the current revision, that have
3060 already been grafted, or that are merges will be skipped.
3060 already been grafted, or that are merges will be skipped.
3061
3061
3062 If --log is specified, log messages will have a comment appended
3062 If --log is specified, log messages will have a comment appended
3063 of the form::
3063 of the form::
3064
3064
3065 (grafted from CHANGESETHASH)
3065 (grafted from CHANGESETHASH)
3066
3066
3067 If a graft merge results in conflicts, the graft process is
3067 If a graft merge results in conflicts, the graft process is
3068 interrupted so that the current merge can be manually resolved.
3068 interrupted so that the current merge can be manually resolved.
3069 Once all conflicts are addressed, the graft process can be
3069 Once all conflicts are addressed, the graft process can be
3070 continued with the -c/--continue option.
3070 continued with the -c/--continue option.
3071
3071
3072 .. note::
3072 .. note::
3073
3073
3074 The -c/--continue option does not reapply earlier options.
3074 The -c/--continue option does not reapply earlier options.
3075
3075
3076 .. container:: verbose
3076 .. container:: verbose
3077
3077
3078 Examples:
3078 Examples:
3079
3079
3080 - copy a single change to the stable branch and edit its description::
3080 - copy a single change to the stable branch and edit its description::
3081
3081
3082 hg update stable
3082 hg update stable
3083 hg graft --edit 9393
3083 hg graft --edit 9393
3084
3084
3085 - graft a range of changesets with one exception, updating dates::
3085 - graft a range of changesets with one exception, updating dates::
3086
3086
3087 hg graft -D "2085::2093 and not 2091"
3087 hg graft -D "2085::2093 and not 2091"
3088
3088
3089 - continue a graft after resolving conflicts::
3089 - continue a graft after resolving conflicts::
3090
3090
3091 hg graft -c
3091 hg graft -c
3092
3092
3093 - show the source of a grafted changeset::
3093 - show the source of a grafted changeset::
3094
3094
3095 hg log --debug -r .
3095 hg log --debug -r .
3096
3096
3097 Returns 0 on successful completion.
3097 Returns 0 on successful completion.
3098 '''
3098 '''
3099
3099
3100 revs = list(revs)
3100 revs = list(revs)
3101 revs.extend(opts['rev'])
3101 revs.extend(opts['rev'])
3102
3102
3103 if not opts.get('user') and opts.get('currentuser'):
3103 if not opts.get('user') and opts.get('currentuser'):
3104 opts['user'] = ui.username()
3104 opts['user'] = ui.username()
3105 if not opts.get('date') and opts.get('currentdate'):
3105 if not opts.get('date') and opts.get('currentdate'):
3106 opts['date'] = "%d %d" % util.makedate()
3106 opts['date'] = "%d %d" % util.makedate()
3107
3107
3108 editor = None
3108 editor = None
3109 if opts.get('edit'):
3109 if opts.get('edit'):
3110 editor = cmdutil.commitforceeditor
3110 editor = cmdutil.commitforceeditor
3111
3111
3112 cont = False
3112 cont = False
3113 if opts['continue']:
3113 if opts['continue']:
3114 cont = True
3114 cont = True
3115 if revs:
3115 if revs:
3116 raise util.Abort(_("can't specify --continue and revisions"))
3116 raise util.Abort(_("can't specify --continue and revisions"))
3117 # read in unfinished revisions
3117 # read in unfinished revisions
3118 try:
3118 try:
3119 nodes = repo.opener.read('graftstate').splitlines()
3119 nodes = repo.opener.read('graftstate').splitlines()
3120 revs = [repo[node].rev() for node in nodes]
3120 revs = [repo[node].rev() for node in nodes]
3121 except IOError, inst:
3121 except IOError, inst:
3122 if inst.errno != errno.ENOENT:
3122 if inst.errno != errno.ENOENT:
3123 raise
3123 raise
3124 raise util.Abort(_("no graft state found, can't continue"))
3124 raise util.Abort(_("no graft state found, can't continue"))
3125 else:
3125 else:
3126 cmdutil.checkunfinished(repo)
3126 cmdutil.checkunfinished(repo)
3127 cmdutil.bailifchanged(repo)
3127 cmdutil.bailifchanged(repo)
3128 if not revs:
3128 if not revs:
3129 raise util.Abort(_('no revisions specified'))
3129 raise util.Abort(_('no revisions specified'))
3130 revs = scmutil.revrange(repo, revs)
3130 revs = scmutil.revrange(repo, revs)
3131
3131
3132 # check for merges
3132 # check for merges
3133 for rev in repo.revs('%ld and merge()', revs):
3133 for rev in repo.revs('%ld and merge()', revs):
3134 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3134 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3135 revs.remove(rev)
3135 revs.remove(rev)
3136 if not revs:
3136 if not revs:
3137 return -1
3137 return -1
3138
3138
3139 # check for ancestors of dest branch
3139 # check for ancestors of dest branch
3140 crev = repo['.'].rev()
3140 crev = repo['.'].rev()
3141 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3141 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3142 # don't mutate while iterating, create a copy
3142 # don't mutate while iterating, create a copy
3143 for rev in list(revs):
3143 for rev in list(revs):
3144 if rev in ancestors:
3144 if rev in ancestors:
3145 ui.warn(_('skipping ancestor revision %s\n') % rev)
3145 ui.warn(_('skipping ancestor revision %s\n') % rev)
3146 revs.remove(rev)
3146 revs.remove(rev)
3147 if not revs:
3147 if not revs:
3148 return -1
3148 return -1
3149
3149
3150 # analyze revs for earlier grafts
3150 # analyze revs for earlier grafts
3151 ids = {}
3151 ids = {}
3152 for ctx in repo.set("%ld", revs):
3152 for ctx in repo.set("%ld", revs):
3153 ids[ctx.hex()] = ctx.rev()
3153 ids[ctx.hex()] = ctx.rev()
3154 n = ctx.extra().get('source')
3154 n = ctx.extra().get('source')
3155 if n:
3155 if n:
3156 ids[n] = ctx.rev()
3156 ids[n] = ctx.rev()
3157
3157
3158 # check ancestors for earlier grafts
3158 # check ancestors for earlier grafts
3159 ui.debug('scanning for duplicate grafts\n')
3159 ui.debug('scanning for duplicate grafts\n')
3160
3160
3161 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3161 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3162 ctx = repo[rev]
3162 ctx = repo[rev]
3163 n = ctx.extra().get('source')
3163 n = ctx.extra().get('source')
3164 if n in ids:
3164 if n in ids:
3165 r = repo[n].rev()
3165 r = repo[n].rev()
3166 if r in revs:
3166 if r in revs:
3167 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3167 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3168 % (r, rev))
3168 % (r, rev))
3169 revs.remove(r)
3169 revs.remove(r)
3170 elif ids[n] in revs:
3170 elif ids[n] in revs:
3171 ui.warn(_('skipping already grafted revision %s '
3171 ui.warn(_('skipping already grafted revision %s '
3172 '(%s also has origin %d)\n') % (ids[n], rev, r))
3172 '(%s also has origin %d)\n') % (ids[n], rev, r))
3173 revs.remove(ids[n])
3173 revs.remove(ids[n])
3174 elif ctx.hex() in ids:
3174 elif ctx.hex() in ids:
3175 r = ids[ctx.hex()]
3175 r = ids[ctx.hex()]
3176 ui.warn(_('skipping already grafted revision %s '
3176 ui.warn(_('skipping already grafted revision %s '
3177 '(was grafted from %d)\n') % (r, rev))
3177 '(was grafted from %d)\n') % (r, rev))
3178 revs.remove(r)
3178 revs.remove(r)
3179 if not revs:
3179 if not revs:
3180 return -1
3180 return -1
3181
3181
3182 wlock = repo.wlock()
3182 wlock = repo.wlock()
3183 try:
3183 try:
3184 current = repo['.']
3184 current = repo['.']
3185 for pos, ctx in enumerate(repo.set("%ld", revs)):
3185 for pos, ctx in enumerate(repo.set("%ld", revs)):
3186
3186
3187 ui.status(_('grafting revision %s\n') % ctx.rev())
3187 ui.status(_('grafting revision %s\n') % ctx.rev())
3188 if opts.get('dry_run'):
3188 if opts.get('dry_run'):
3189 continue
3189 continue
3190
3190
3191 source = ctx.extra().get('source')
3191 source = ctx.extra().get('source')
3192 if not source:
3192 if not source:
3193 source = ctx.hex()
3193 source = ctx.hex()
3194 extra = {'source': source}
3194 extra = {'source': source}
3195 user = ctx.user()
3195 user = ctx.user()
3196 if opts.get('user'):
3196 if opts.get('user'):
3197 user = opts['user']
3197 user = opts['user']
3198 date = ctx.date()
3198 date = ctx.date()
3199 if opts.get('date'):
3199 if opts.get('date'):
3200 date = opts['date']
3200 date = opts['date']
3201 message = ctx.description()
3201 message = ctx.description()
3202 if opts.get('log'):
3202 if opts.get('log'):
3203 message += '\n(grafted from %s)' % ctx.hex()
3203 message += '\n(grafted from %s)' % ctx.hex()
3204
3204
3205 # we don't merge the first commit when continuing
3205 # we don't merge the first commit when continuing
3206 if not cont:
3206 if not cont:
3207 # perform the graft merge with p1(rev) as 'ancestor'
3207 # perform the graft merge with p1(rev) as 'ancestor'
3208 try:
3208 try:
3209 # ui.forcemerge is an internal variable, do not document
3209 # ui.forcemerge is an internal variable, do not document
3210 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3210 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3211 'graft')
3211 'graft')
3212 stats = mergemod.update(repo, ctx.node(), True, True, False,
3212 stats = mergemod.update(repo, ctx.node(), True, True, False,
3213 ctx.p1().node())
3213 ctx.p1().node())
3214 finally:
3214 finally:
3215 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3215 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3216 # report any conflicts
3216 # report any conflicts
3217 if stats and stats[3] > 0:
3217 if stats and stats[3] > 0:
3218 # write out state for --continue
3218 # write out state for --continue
3219 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3219 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3220 repo.opener.write('graftstate', ''.join(nodelines))
3220 repo.opener.write('graftstate', ''.join(nodelines))
3221 raise util.Abort(
3221 raise util.Abort(
3222 _("unresolved conflicts, can't continue"),
3222 _("unresolved conflicts, can't continue"),
3223 hint=_('use hg resolve and hg graft --continue'))
3223 hint=_('use hg resolve and hg graft --continue'))
3224 else:
3224 else:
3225 cont = False
3225 cont = False
3226
3226
3227 # drop the second merge parent
3227 # drop the second merge parent
3228 repo.setparents(current.node(), nullid)
3228 repo.setparents(current.node(), nullid)
3229 repo.dirstate.write()
3229 repo.dirstate.write()
3230 # fix up dirstate for copies and renames
3230 # fix up dirstate for copies and renames
3231 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3231 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3232
3232
3233 # commit
3233 # commit
3234 node = repo.commit(text=message, user=user,
3234 node = repo.commit(text=message, user=user,
3235 date=date, extra=extra, editor=editor)
3235 date=date, extra=extra, editor=editor)
3236 if node is None:
3236 if node is None:
3237 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3237 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3238 else:
3238 else:
3239 current = repo[node]
3239 current = repo[node]
3240 finally:
3240 finally:
3241 wlock.release()
3241 wlock.release()
3242
3242
3243 # remove state when we complete successfully
3243 # remove state when we complete successfully
3244 if not opts.get('dry_run'):
3244 if not opts.get('dry_run'):
3245 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3245 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3246
3246
3247 return 0
3247 return 0
3248
3248
3249 @command('grep',
3249 @command('grep',
3250 [('0', 'print0', None, _('end fields with NUL')),
3250 [('0', 'print0', None, _('end fields with NUL')),
3251 ('', 'all', None, _('print all revisions that match')),
3251 ('', 'all', None, _('print all revisions that match')),
3252 ('a', 'text', None, _('treat all files as text')),
3252 ('a', 'text', None, _('treat all files as text')),
3253 ('f', 'follow', None,
3253 ('f', 'follow', None,
3254 _('follow changeset history,'
3254 _('follow changeset history,'
3255 ' or file history across copies and renames')),
3255 ' or file history across copies and renames')),
3256 ('i', 'ignore-case', None, _('ignore case when matching')),
3256 ('i', 'ignore-case', None, _('ignore case when matching')),
3257 ('l', 'files-with-matches', None,
3257 ('l', 'files-with-matches', None,
3258 _('print only filenames and revisions that match')),
3258 _('print only filenames and revisions that match')),
3259 ('n', 'line-number', None, _('print matching line numbers')),
3259 ('n', 'line-number', None, _('print matching line numbers')),
3260 ('r', 'rev', [],
3260 ('r', 'rev', [],
3261 _('only search files changed within revision range'), _('REV')),
3261 _('only search files changed within revision range'), _('REV')),
3262 ('u', 'user', None, _('list the author (long with -v)')),
3262 ('u', 'user', None, _('list the author (long with -v)')),
3263 ('d', 'date', None, _('list the date (short with -q)')),
3263 ('d', 'date', None, _('list the date (short with -q)')),
3264 ] + walkopts,
3264 ] + walkopts,
3265 _('[OPTION]... PATTERN [FILE]...'))
3265 _('[OPTION]... PATTERN [FILE]...'))
3266 def grep(ui, repo, pattern, *pats, **opts):
3266 def grep(ui, repo, pattern, *pats, **opts):
3267 """search for a pattern in specified files and revisions
3267 """search for a pattern in specified files and revisions
3268
3268
3269 Search revisions of files for a regular expression.
3269 Search revisions of files for a regular expression.
3270
3270
3271 This command behaves differently than Unix grep. It only accepts
3271 This command behaves differently than Unix grep. It only accepts
3272 Python/Perl regexps. It searches repository history, not the
3272 Python/Perl regexps. It searches repository history, not the
3273 working directory. It always prints the revision number in which a
3273 working directory. It always prints the revision number in which a
3274 match appears.
3274 match appears.
3275
3275
3276 By default, grep only prints output for the first revision of a
3276 By default, grep only prints output for the first revision of a
3277 file in which it finds a match. To get it to print every revision
3277 file in which it finds a match. To get it to print every revision
3278 that contains a change in match status ("-" for a match that
3278 that contains a change in match status ("-" for a match that
3279 becomes a non-match, or "+" for a non-match that becomes a match),
3279 becomes a non-match, or "+" for a non-match that becomes a match),
3280 use the --all flag.
3280 use the --all flag.
3281
3281
3282 Returns 0 if a match is found, 1 otherwise.
3282 Returns 0 if a match is found, 1 otherwise.
3283 """
3283 """
3284 reflags = re.M
3284 reflags = re.M
3285 if opts.get('ignore_case'):
3285 if opts.get('ignore_case'):
3286 reflags |= re.I
3286 reflags |= re.I
3287 try:
3287 try:
3288 regexp = util.compilere(pattern, reflags)
3288 regexp = util.compilere(pattern, reflags)
3289 except re.error, inst:
3289 except re.error, inst:
3290 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3290 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3291 return 1
3291 return 1
3292 sep, eol = ':', '\n'
3292 sep, eol = ':', '\n'
3293 if opts.get('print0'):
3293 if opts.get('print0'):
3294 sep = eol = '\0'
3294 sep = eol = '\0'
3295
3295
3296 getfile = util.lrucachefunc(repo.file)
3296 getfile = util.lrucachefunc(repo.file)
3297
3297
3298 def matchlines(body):
3298 def matchlines(body):
3299 begin = 0
3299 begin = 0
3300 linenum = 0
3300 linenum = 0
3301 while begin < len(body):
3301 while begin < len(body):
3302 match = regexp.search(body, begin)
3302 match = regexp.search(body, begin)
3303 if not match:
3303 if not match:
3304 break
3304 break
3305 mstart, mend = match.span()
3305 mstart, mend = match.span()
3306 linenum += body.count('\n', begin, mstart) + 1
3306 linenum += body.count('\n', begin, mstart) + 1
3307 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3307 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3308 begin = body.find('\n', mend) + 1 or len(body) + 1
3308 begin = body.find('\n', mend) + 1 or len(body) + 1
3309 lend = begin - 1
3309 lend = begin - 1
3310 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3310 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3311
3311
3312 class linestate(object):
3312 class linestate(object):
3313 def __init__(self, line, linenum, colstart, colend):
3313 def __init__(self, line, linenum, colstart, colend):
3314 self.line = line
3314 self.line = line
3315 self.linenum = linenum
3315 self.linenum = linenum
3316 self.colstart = colstart
3316 self.colstart = colstart
3317 self.colend = colend
3317 self.colend = colend
3318
3318
3319 def __hash__(self):
3319 def __hash__(self):
3320 return hash((self.linenum, self.line))
3320 return hash((self.linenum, self.line))
3321
3321
3322 def __eq__(self, other):
3322 def __eq__(self, other):
3323 return self.line == other.line
3323 return self.line == other.line
3324
3324
3325 def __iter__(self):
3325 def __iter__(self):
3326 yield (self.line[:self.colstart], '')
3326 yield (self.line[:self.colstart], '')
3327 yield (self.line[self.colstart:self.colend], 'grep.match')
3327 yield (self.line[self.colstart:self.colend], 'grep.match')
3328 rest = self.line[self.colend:]
3328 rest = self.line[self.colend:]
3329 while rest != '':
3329 while rest != '':
3330 match = regexp.search(rest)
3330 match = regexp.search(rest)
3331 if not match:
3331 if not match:
3332 yield (rest, '')
3332 yield (rest, '')
3333 break
3333 break
3334 mstart, mend = match.span()
3334 mstart, mend = match.span()
3335 yield (rest[:mstart], '')
3335 yield (rest[:mstart], '')
3336 yield (rest[mstart:mend], 'grep.match')
3336 yield (rest[mstart:mend], 'grep.match')
3337 rest = rest[mend:]
3337 rest = rest[mend:]
3338
3338
3339 matches = {}
3339 matches = {}
3340 copies = {}
3340 copies = {}
3341 def grepbody(fn, rev, body):
3341 def grepbody(fn, rev, body):
3342 matches[rev].setdefault(fn, [])
3342 matches[rev].setdefault(fn, [])
3343 m = matches[rev][fn]
3343 m = matches[rev][fn]
3344 for lnum, cstart, cend, line in matchlines(body):
3344 for lnum, cstart, cend, line in matchlines(body):
3345 s = linestate(line, lnum, cstart, cend)
3345 s = linestate(line, lnum, cstart, cend)
3346 m.append(s)
3346 m.append(s)
3347
3347
3348 def difflinestates(a, b):
3348 def difflinestates(a, b):
3349 sm = difflib.SequenceMatcher(None, a, b)
3349 sm = difflib.SequenceMatcher(None, a, b)
3350 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3350 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3351 if tag == 'insert':
3351 if tag == 'insert':
3352 for i in xrange(blo, bhi):
3352 for i in xrange(blo, bhi):
3353 yield ('+', b[i])
3353 yield ('+', b[i])
3354 elif tag == 'delete':
3354 elif tag == 'delete':
3355 for i in xrange(alo, ahi):
3355 for i in xrange(alo, ahi):
3356 yield ('-', a[i])
3356 yield ('-', a[i])
3357 elif tag == 'replace':
3357 elif tag == 'replace':
3358 for i in xrange(alo, ahi):
3358 for i in xrange(alo, ahi):
3359 yield ('-', a[i])
3359 yield ('-', a[i])
3360 for i in xrange(blo, bhi):
3360 for i in xrange(blo, bhi):
3361 yield ('+', b[i])
3361 yield ('+', b[i])
3362
3362
3363 def display(fn, ctx, pstates, states):
3363 def display(fn, ctx, pstates, states):
3364 rev = ctx.rev()
3364 rev = ctx.rev()
3365 datefunc = ui.quiet and util.shortdate or util.datestr
3365 datefunc = ui.quiet and util.shortdate or util.datestr
3366 found = False
3366 found = False
3367 @util.cachefunc
3367 @util.cachefunc
3368 def binary():
3368 def binary():
3369 flog = getfile(fn)
3369 flog = getfile(fn)
3370 return util.binary(flog.read(ctx.filenode(fn)))
3370 return util.binary(flog.read(ctx.filenode(fn)))
3371
3371
3372 if opts.get('all'):
3372 if opts.get('all'):
3373 iter = difflinestates(pstates, states)
3373 iter = difflinestates(pstates, states)
3374 else:
3374 else:
3375 iter = [('', l) for l in states]
3375 iter = [('', l) for l in states]
3376 for change, l in iter:
3376 for change, l in iter:
3377 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3377 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3378
3378
3379 if opts.get('line_number'):
3379 if opts.get('line_number'):
3380 cols.append((str(l.linenum), 'grep.linenumber'))
3380 cols.append((str(l.linenum), 'grep.linenumber'))
3381 if opts.get('all'):
3381 if opts.get('all'):
3382 cols.append((change, 'grep.change'))
3382 cols.append((change, 'grep.change'))
3383 if opts.get('user'):
3383 if opts.get('user'):
3384 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3384 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3385 if opts.get('date'):
3385 if opts.get('date'):
3386 cols.append((datefunc(ctx.date()), 'grep.date'))
3386 cols.append((datefunc(ctx.date()), 'grep.date'))
3387 for col, label in cols[:-1]:
3387 for col, label in cols[:-1]:
3388 ui.write(col, label=label)
3388 ui.write(col, label=label)
3389 ui.write(sep, label='grep.sep')
3389 ui.write(sep, label='grep.sep')
3390 ui.write(cols[-1][0], label=cols[-1][1])
3390 ui.write(cols[-1][0], label=cols[-1][1])
3391 if not opts.get('files_with_matches'):
3391 if not opts.get('files_with_matches'):
3392 ui.write(sep, label='grep.sep')
3392 ui.write(sep, label='grep.sep')
3393 if not opts.get('text') and binary():
3393 if not opts.get('text') and binary():
3394 ui.write(" Binary file matches")
3394 ui.write(" Binary file matches")
3395 else:
3395 else:
3396 for s, label in l:
3396 for s, label in l:
3397 ui.write(s, label=label)
3397 ui.write(s, label=label)
3398 ui.write(eol)
3398 ui.write(eol)
3399 found = True
3399 found = True
3400 if opts.get('files_with_matches'):
3400 if opts.get('files_with_matches'):
3401 break
3401 break
3402 return found
3402 return found
3403
3403
3404 skip = {}
3404 skip = {}
3405 revfiles = {}
3405 revfiles = {}
3406 matchfn = scmutil.match(repo[None], pats, opts)
3406 matchfn = scmutil.match(repo[None], pats, opts)
3407 found = False
3407 found = False
3408 follow = opts.get('follow')
3408 follow = opts.get('follow')
3409
3409
3410 def prep(ctx, fns):
3410 def prep(ctx, fns):
3411 rev = ctx.rev()
3411 rev = ctx.rev()
3412 pctx = ctx.p1()
3412 pctx = ctx.p1()
3413 parent = pctx.rev()
3413 parent = pctx.rev()
3414 matches.setdefault(rev, {})
3414 matches.setdefault(rev, {})
3415 matches.setdefault(parent, {})
3415 matches.setdefault(parent, {})
3416 files = revfiles.setdefault(rev, [])
3416 files = revfiles.setdefault(rev, [])
3417 for fn in fns:
3417 for fn in fns:
3418 flog = getfile(fn)
3418 flog = getfile(fn)
3419 try:
3419 try:
3420 fnode = ctx.filenode(fn)
3420 fnode = ctx.filenode(fn)
3421 except error.LookupError:
3421 except error.LookupError:
3422 continue
3422 continue
3423
3423
3424 copied = flog.renamed(fnode)
3424 copied = flog.renamed(fnode)
3425 copy = follow and copied and copied[0]
3425 copy = follow and copied and copied[0]
3426 if copy:
3426 if copy:
3427 copies.setdefault(rev, {})[fn] = copy
3427 copies.setdefault(rev, {})[fn] = copy
3428 if fn in skip:
3428 if fn in skip:
3429 if copy:
3429 if copy:
3430 skip[copy] = True
3430 skip[copy] = True
3431 continue
3431 continue
3432 files.append(fn)
3432 files.append(fn)
3433
3433
3434 if fn not in matches[rev]:
3434 if fn not in matches[rev]:
3435 grepbody(fn, rev, flog.read(fnode))
3435 grepbody(fn, rev, flog.read(fnode))
3436
3436
3437 pfn = copy or fn
3437 pfn = copy or fn
3438 if pfn not in matches[parent]:
3438 if pfn not in matches[parent]:
3439 try:
3439 try:
3440 fnode = pctx.filenode(pfn)
3440 fnode = pctx.filenode(pfn)
3441 grepbody(pfn, parent, flog.read(fnode))
3441 grepbody(pfn, parent, flog.read(fnode))
3442 except error.LookupError:
3442 except error.LookupError:
3443 pass
3443 pass
3444
3444
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3446 rev = ctx.rev()
3446 rev = ctx.rev()
3447 parent = ctx.p1().rev()
3447 parent = ctx.p1().rev()
3448 for fn in sorted(revfiles.get(rev, [])):
3448 for fn in sorted(revfiles.get(rev, [])):
3449 states = matches[rev][fn]
3449 states = matches[rev][fn]
3450 copy = copies.get(rev, {}).get(fn)
3450 copy = copies.get(rev, {}).get(fn)
3451 if fn in skip:
3451 if fn in skip:
3452 if copy:
3452 if copy:
3453 skip[copy] = True
3453 skip[copy] = True
3454 continue
3454 continue
3455 pstates = matches.get(parent, {}).get(copy or fn, [])
3455 pstates = matches.get(parent, {}).get(copy or fn, [])
3456 if pstates or states:
3456 if pstates or states:
3457 r = display(fn, ctx, pstates, states)
3457 r = display(fn, ctx, pstates, states)
3458 found = found or r
3458 found = found or r
3459 if r and not opts.get('all'):
3459 if r and not opts.get('all'):
3460 skip[fn] = True
3460 skip[fn] = True
3461 if copy:
3461 if copy:
3462 skip[copy] = True
3462 skip[copy] = True
3463 del matches[rev]
3463 del matches[rev]
3464 del revfiles[rev]
3464 del revfiles[rev]
3465
3465
3466 return not found
3466 return not found
3467
3467
3468 @command('heads',
3468 @command('heads',
3469 [('r', 'rev', '',
3469 [('r', 'rev', '',
3470 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3470 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3471 ('t', 'topo', False, _('show topological heads only')),
3471 ('t', 'topo', False, _('show topological heads only')),
3472 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3472 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3473 ('c', 'closed', False, _('show normal and closed branch heads')),
3473 ('c', 'closed', False, _('show normal and closed branch heads')),
3474 ] + templateopts,
3474 ] + templateopts,
3475 _('[-ct] [-r STARTREV] [REV]...'))
3475 _('[-ct] [-r STARTREV] [REV]...'))
3476 def heads(ui, repo, *branchrevs, **opts):
3476 def heads(ui, repo, *branchrevs, **opts):
3477 """show branch heads
3477 """show branch heads
3478
3478
3479 With no arguments, show all open branch heads in the repository.
3479 With no arguments, show all open branch heads in the repository.
3480 Branch heads are changesets that have no descendants on the
3480 Branch heads are changesets that have no descendants on the
3481 same branch. They are where development generally takes place and
3481 same branch. They are where development generally takes place and
3482 are the usual targets for update and merge operations.
3482 are the usual targets for update and merge operations.
3483
3483
3484 If one or more REVs are given, only open branch heads on the
3484 If one or more REVs are given, only open branch heads on the
3485 branches associated with the specified changesets are shown. This
3485 branches associated with the specified changesets are shown. This
3486 means that you can use :hg:`heads .` to see the heads on the
3486 means that you can use :hg:`heads .` to see the heads on the
3487 currently checked-out branch.
3487 currently checked-out branch.
3488
3488
3489 If -c/--closed is specified, also show branch heads marked closed
3489 If -c/--closed is specified, also show branch heads marked closed
3490 (see :hg:`commit --close-branch`).
3490 (see :hg:`commit --close-branch`).
3491
3491
3492 If STARTREV is specified, only those heads that are descendants of
3492 If STARTREV is specified, only those heads that are descendants of
3493 STARTREV will be displayed.
3493 STARTREV will be displayed.
3494
3494
3495 If -t/--topo is specified, named branch mechanics will be ignored and only
3495 If -t/--topo is specified, named branch mechanics will be ignored and only
3496 topological heads (changesets with no children) will be shown.
3496 topological heads (changesets with no children) will be shown.
3497
3497
3498 Returns 0 if matching heads are found, 1 if not.
3498 Returns 0 if matching heads are found, 1 if not.
3499 """
3499 """
3500
3500
3501 start = None
3501 start = None
3502 if 'rev' in opts:
3502 if 'rev' in opts:
3503 start = scmutil.revsingle(repo, opts['rev'], None).node()
3503 start = scmutil.revsingle(repo, opts['rev'], None).node()
3504
3504
3505 if opts.get('topo'):
3505 if opts.get('topo'):
3506 heads = [repo[h] for h in repo.heads(start)]
3506 heads = [repo[h] for h in repo.heads(start)]
3507 else:
3507 else:
3508 heads = []
3508 heads = []
3509 for branch in repo.branchmap():
3509 for branch in repo.branchmap():
3510 heads += repo.branchheads(branch, start, opts.get('closed'))
3510 heads += repo.branchheads(branch, start, opts.get('closed'))
3511 heads = [repo[h] for h in heads]
3511 heads = [repo[h] for h in heads]
3512
3512
3513 if branchrevs:
3513 if branchrevs:
3514 branches = set(repo[br].branch() for br in branchrevs)
3514 branches = set(repo[br].branch() for br in branchrevs)
3515 heads = [h for h in heads if h.branch() in branches]
3515 heads = [h for h in heads if h.branch() in branches]
3516
3516
3517 if opts.get('active') and branchrevs:
3517 if opts.get('active') and branchrevs:
3518 dagheads = repo.heads(start)
3518 dagheads = repo.heads(start)
3519 heads = [h for h in heads if h.node() in dagheads]
3519 heads = [h for h in heads if h.node() in dagheads]
3520
3520
3521 if branchrevs:
3521 if branchrevs:
3522 haveheads = set(h.branch() for h in heads)
3522 haveheads = set(h.branch() for h in heads)
3523 if branches - haveheads:
3523 if branches - haveheads:
3524 headless = ', '.join(b for b in branches - haveheads)
3524 headless = ', '.join(b for b in branches - haveheads)
3525 msg = _('no open branch heads found on branches %s')
3525 msg = _('no open branch heads found on branches %s')
3526 if opts.get('rev'):
3526 if opts.get('rev'):
3527 msg += _(' (started at %s)') % opts['rev']
3527 msg += _(' (started at %s)') % opts['rev']
3528 ui.warn((msg + '\n') % headless)
3528 ui.warn((msg + '\n') % headless)
3529
3529
3530 if not heads:
3530 if not heads:
3531 return 1
3531 return 1
3532
3532
3533 heads = sorted(heads, key=lambda x: -x.rev())
3533 heads = sorted(heads, key=lambda x: -x.rev())
3534 displayer = cmdutil.show_changeset(ui, repo, opts)
3534 displayer = cmdutil.show_changeset(ui, repo, opts)
3535 for ctx in heads:
3535 for ctx in heads:
3536 displayer.show(ctx)
3536 displayer.show(ctx)
3537 displayer.close()
3537 displayer.close()
3538
3538
3539 @command('help',
3539 @command('help',
3540 [('e', 'extension', None, _('show only help for extensions')),
3540 [('e', 'extension', None, _('show only help for extensions')),
3541 ('c', 'command', None, _('show only help for commands')),
3541 ('c', 'command', None, _('show only help for commands')),
3542 ('k', 'keyword', '', _('show topics matching keyword')),
3542 ('k', 'keyword', '', _('show topics matching keyword')),
3543 ],
3543 ],
3544 _('[-ec] [TOPIC]'))
3544 _('[-ec] [TOPIC]'))
3545 def help_(ui, name=None, **opts):
3545 def help_(ui, name=None, **opts):
3546 """show help for a given topic or a help overview
3546 """show help for a given topic or a help overview
3547
3547
3548 With no arguments, print a list of commands with short help messages.
3548 With no arguments, print a list of commands with short help messages.
3549
3549
3550 Given a topic, extension, or command name, print help for that
3550 Given a topic, extension, or command name, print help for that
3551 topic.
3551 topic.
3552
3552
3553 Returns 0 if successful.
3553 Returns 0 if successful.
3554 """
3554 """
3555
3555
3556 textwidth = min(ui.termwidth(), 80) - 2
3556 textwidth = min(ui.termwidth(), 80) - 2
3557
3557
3558 keep = ui.verbose and ['verbose'] or []
3558 keep = ui.verbose and ['verbose'] or []
3559 text = help.help_(ui, name, **opts)
3559 text = help.help_(ui, name, **opts)
3560
3560
3561 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3561 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3562 if 'verbose' in pruned:
3562 if 'verbose' in pruned:
3563 keep.append('omitted')
3563 keep.append('omitted')
3564 else:
3564 else:
3565 keep.append('notomitted')
3565 keep.append('notomitted')
3566 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3566 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3567 ui.write(formatted)
3567 ui.write(formatted)
3568
3568
3569
3569
3570 @command('identify|id',
3570 @command('identify|id',
3571 [('r', 'rev', '',
3571 [('r', 'rev', '',
3572 _('identify the specified revision'), _('REV')),
3572 _('identify the specified revision'), _('REV')),
3573 ('n', 'num', None, _('show local revision number')),
3573 ('n', 'num', None, _('show local revision number')),
3574 ('i', 'id', None, _('show global revision id')),
3574 ('i', 'id', None, _('show global revision id')),
3575 ('b', 'branch', None, _('show branch')),
3575 ('b', 'branch', None, _('show branch')),
3576 ('t', 'tags', None, _('show tags')),
3576 ('t', 'tags', None, _('show tags')),
3577 ('B', 'bookmarks', None, _('show bookmarks')),
3577 ('B', 'bookmarks', None, _('show bookmarks')),
3578 ] + remoteopts,
3578 ] + remoteopts,
3579 _('[-nibtB] [-r REV] [SOURCE]'))
3579 _('[-nibtB] [-r REV] [SOURCE]'))
3580 def identify(ui, repo, source=None, rev=None,
3580 def identify(ui, repo, source=None, rev=None,
3581 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3581 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3582 """identify the working copy or specified revision
3582 """identify the working copy or specified revision
3583
3583
3584 Print a summary identifying the repository state at REV using one or
3584 Print a summary identifying the repository state at REV using one or
3585 two parent hash identifiers, followed by a "+" if the working
3585 two parent hash identifiers, followed by a "+" if the working
3586 directory has uncommitted changes, the branch name (if not default),
3586 directory has uncommitted changes, the branch name (if not default),
3587 a list of tags, and a list of bookmarks.
3587 a list of tags, and a list of bookmarks.
3588
3588
3589 When REV is not given, print a summary of the current state of the
3589 When REV is not given, print a summary of the current state of the
3590 repository.
3590 repository.
3591
3591
3592 Specifying a path to a repository root or Mercurial bundle will
3592 Specifying a path to a repository root or Mercurial bundle will
3593 cause lookup to operate on that repository/bundle.
3593 cause lookup to operate on that repository/bundle.
3594
3594
3595 .. container:: verbose
3595 .. container:: verbose
3596
3596
3597 Examples:
3597 Examples:
3598
3598
3599 - generate a build identifier for the working directory::
3599 - generate a build identifier for the working directory::
3600
3600
3601 hg id --id > build-id.dat
3601 hg id --id > build-id.dat
3602
3602
3603 - find the revision corresponding to a tag::
3603 - find the revision corresponding to a tag::
3604
3604
3605 hg id -n -r 1.3
3605 hg id -n -r 1.3
3606
3606
3607 - check the most recent revision of a remote repository::
3607 - check the most recent revision of a remote repository::
3608
3608
3609 hg id -r tip http://selenic.com/hg/
3609 hg id -r tip http://selenic.com/hg/
3610
3610
3611 Returns 0 if successful.
3611 Returns 0 if successful.
3612 """
3612 """
3613
3613
3614 if not repo and not source:
3614 if not repo and not source:
3615 raise util.Abort(_("there is no Mercurial repository here "
3615 raise util.Abort(_("there is no Mercurial repository here "
3616 "(.hg not found)"))
3616 "(.hg not found)"))
3617
3617
3618 hexfunc = ui.debugflag and hex or short
3618 hexfunc = ui.debugflag and hex or short
3619 default = not (num or id or branch or tags or bookmarks)
3619 default = not (num or id or branch or tags or bookmarks)
3620 output = []
3620 output = []
3621 revs = []
3621 revs = []
3622
3622
3623 if source:
3623 if source:
3624 source, branches = hg.parseurl(ui.expandpath(source))
3624 source, branches = hg.parseurl(ui.expandpath(source))
3625 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3625 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3626 repo = peer.local()
3626 repo = peer.local()
3627 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3627 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3628
3628
3629 if not repo:
3629 if not repo:
3630 if num or branch or tags:
3630 if num or branch or tags:
3631 raise util.Abort(
3631 raise util.Abort(
3632 _("can't query remote revision number, branch, or tags"))
3632 _("can't query remote revision number, branch, or tags"))
3633 if not rev and revs:
3633 if not rev and revs:
3634 rev = revs[0]
3634 rev = revs[0]
3635 if not rev:
3635 if not rev:
3636 rev = "tip"
3636 rev = "tip"
3637
3637
3638 remoterev = peer.lookup(rev)
3638 remoterev = peer.lookup(rev)
3639 if default or id:
3639 if default or id:
3640 output = [hexfunc(remoterev)]
3640 output = [hexfunc(remoterev)]
3641
3641
3642 def getbms():
3642 def getbms():
3643 bms = []
3643 bms = []
3644
3644
3645 if 'bookmarks' in peer.listkeys('namespaces'):
3645 if 'bookmarks' in peer.listkeys('namespaces'):
3646 hexremoterev = hex(remoterev)
3646 hexremoterev = hex(remoterev)
3647 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3647 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3648 if bmr == hexremoterev]
3648 if bmr == hexremoterev]
3649
3649
3650 return sorted(bms)
3650 return sorted(bms)
3651
3651
3652 if bookmarks:
3652 if bookmarks:
3653 output.extend(getbms())
3653 output.extend(getbms())
3654 elif default and not ui.quiet:
3654 elif default and not ui.quiet:
3655 # multiple bookmarks for a single parent separated by '/'
3655 # multiple bookmarks for a single parent separated by '/'
3656 bm = '/'.join(getbms())
3656 bm = '/'.join(getbms())
3657 if bm:
3657 if bm:
3658 output.append(bm)
3658 output.append(bm)
3659 else:
3659 else:
3660 if not rev:
3660 if not rev:
3661 ctx = repo[None]
3661 ctx = repo[None]
3662 parents = ctx.parents()
3662 parents = ctx.parents()
3663 changed = ""
3663 changed = ""
3664 if default or id or num:
3664 if default or id or num:
3665 if (util.any(repo.status())
3665 if (util.any(repo.status())
3666 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3666 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3667 changed = '+'
3667 changed = '+'
3668 if default or id:
3668 if default or id:
3669 output = ["%s%s" %
3669 output = ["%s%s" %
3670 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3670 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3671 if num:
3671 if num:
3672 output.append("%s%s" %
3672 output.append("%s%s" %
3673 ('+'.join([str(p.rev()) for p in parents]), changed))
3673 ('+'.join([str(p.rev()) for p in parents]), changed))
3674 else:
3674 else:
3675 ctx = scmutil.revsingle(repo, rev)
3675 ctx = scmutil.revsingle(repo, rev)
3676 if default or id:
3676 if default or id:
3677 output = [hexfunc(ctx.node())]
3677 output = [hexfunc(ctx.node())]
3678 if num:
3678 if num:
3679 output.append(str(ctx.rev()))
3679 output.append(str(ctx.rev()))
3680
3680
3681 if default and not ui.quiet:
3681 if default and not ui.quiet:
3682 b = ctx.branch()
3682 b = ctx.branch()
3683 if b != 'default':
3683 if b != 'default':
3684 output.append("(%s)" % b)
3684 output.append("(%s)" % b)
3685
3685
3686 # multiple tags for a single parent separated by '/'
3686 # multiple tags for a single parent separated by '/'
3687 t = '/'.join(ctx.tags())
3687 t = '/'.join(ctx.tags())
3688 if t:
3688 if t:
3689 output.append(t)
3689 output.append(t)
3690
3690
3691 # multiple bookmarks for a single parent separated by '/'
3691 # multiple bookmarks for a single parent separated by '/'
3692 bm = '/'.join(ctx.bookmarks())
3692 bm = '/'.join(ctx.bookmarks())
3693 if bm:
3693 if bm:
3694 output.append(bm)
3694 output.append(bm)
3695 else:
3695 else:
3696 if branch:
3696 if branch:
3697 output.append(ctx.branch())
3697 output.append(ctx.branch())
3698
3698
3699 if tags:
3699 if tags:
3700 output.extend(ctx.tags())
3700 output.extend(ctx.tags())
3701
3701
3702 if bookmarks:
3702 if bookmarks:
3703 output.extend(ctx.bookmarks())
3703 output.extend(ctx.bookmarks())
3704
3704
3705 ui.write("%s\n" % ' '.join(output))
3705 ui.write("%s\n" % ' '.join(output))
3706
3706
3707 @command('import|patch',
3707 @command('import|patch',
3708 [('p', 'strip', 1,
3708 [('p', 'strip', 1,
3709 _('directory strip option for patch. This has the same '
3709 _('directory strip option for patch. This has the same '
3710 'meaning as the corresponding patch option'), _('NUM')),
3710 'meaning as the corresponding patch option'), _('NUM')),
3711 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3711 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3712 ('e', 'edit', False, _('invoke editor on commit messages')),
3712 ('e', 'edit', False, _('invoke editor on commit messages')),
3713 ('f', 'force', None,
3713 ('f', 'force', None,
3714 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3714 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3715 ('', 'no-commit', None,
3715 ('', 'no-commit', None,
3716 _("don't commit, just update the working directory")),
3716 _("don't commit, just update the working directory")),
3717 ('', 'bypass', None,
3717 ('', 'bypass', None,
3718 _("apply patch without touching the working directory")),
3718 _("apply patch without touching the working directory")),
3719 ('', 'exact', None,
3719 ('', 'exact', None,
3720 _('apply patch to the nodes from which it was generated')),
3720 _('apply patch to the nodes from which it was generated')),
3721 ('', 'import-branch', None,
3721 ('', 'import-branch', None,
3722 _('use any branch information in patch (implied by --exact)'))] +
3722 _('use any branch information in patch (implied by --exact)'))] +
3723 commitopts + commitopts2 + similarityopts,
3723 commitopts + commitopts2 + similarityopts,
3724 _('[OPTION]... PATCH...'))
3724 _('[OPTION]... PATCH...'))
3725 def import_(ui, repo, patch1=None, *patches, **opts):
3725 def import_(ui, repo, patch1=None, *patches, **opts):
3726 """import an ordered set of patches
3726 """import an ordered set of patches
3727
3727
3728 Import a list of patches and commit them individually (unless
3728 Import a list of patches and commit them individually (unless
3729 --no-commit is specified).
3729 --no-commit is specified).
3730
3730
3731 Because import first applies changes to the working directory,
3731 Because import first applies changes to the working directory,
3732 import will abort if there are outstanding changes.
3732 import will abort if there are outstanding changes.
3733
3733
3734 You can import a patch straight from a mail message. Even patches
3734 You can import a patch straight from a mail message. Even patches
3735 as attachments work (to use the body part, it must have type
3735 as attachments work (to use the body part, it must have type
3736 text/plain or text/x-patch). From and Subject headers of email
3736 text/plain or text/x-patch). From and Subject headers of email
3737 message are used as default committer and commit message. All
3737 message are used as default committer and commit message. All
3738 text/plain body parts before first diff are added to commit
3738 text/plain body parts before first diff are added to commit
3739 message.
3739 message.
3740
3740
3741 If the imported patch was generated by :hg:`export`, user and
3741 If the imported patch was generated by :hg:`export`, user and
3742 description from patch override values from message headers and
3742 description from patch override values from message headers and
3743 body. Values given on command line with -m/--message and -u/--user
3743 body. Values given on command line with -m/--message and -u/--user
3744 override these.
3744 override these.
3745
3745
3746 If --exact is specified, import will set the working directory to
3746 If --exact is specified, import will set the working directory to
3747 the parent of each patch before applying it, and will abort if the
3747 the parent of each patch before applying it, and will abort if the
3748 resulting changeset has a different ID than the one recorded in
3748 resulting changeset has a different ID than the one recorded in
3749 the patch. This may happen due to character set problems or other
3749 the patch. This may happen due to character set problems or other
3750 deficiencies in the text patch format.
3750 deficiencies in the text patch format.
3751
3751
3752 Use --bypass to apply and commit patches directly to the
3752 Use --bypass to apply and commit patches directly to the
3753 repository, not touching the working directory. Without --exact,
3753 repository, not touching the working directory. Without --exact,
3754 patches will be applied on top of the working directory parent
3754 patches will be applied on top of the working directory parent
3755 revision.
3755 revision.
3756
3756
3757 With -s/--similarity, hg will attempt to discover renames and
3757 With -s/--similarity, hg will attempt to discover renames and
3758 copies in the patch in the same way as :hg:`addremove`.
3758 copies in the patch in the same way as :hg:`addremove`.
3759
3759
3760 To read a patch from standard input, use "-" as the patch name. If
3760 To read a patch from standard input, use "-" as the patch name. If
3761 a URL is specified, the patch will be downloaded from it.
3761 a URL is specified, the patch will be downloaded from it.
3762 See :hg:`help dates` for a list of formats valid for -d/--date.
3762 See :hg:`help dates` for a list of formats valid for -d/--date.
3763
3763
3764 .. container:: verbose
3764 .. container:: verbose
3765
3765
3766 Examples:
3766 Examples:
3767
3767
3768 - import a traditional patch from a website and detect renames::
3768 - import a traditional patch from a website and detect renames::
3769
3769
3770 hg import -s 80 http://example.com/bugfix.patch
3770 hg import -s 80 http://example.com/bugfix.patch
3771
3771
3772 - import a changeset from an hgweb server::
3772 - import a changeset from an hgweb server::
3773
3773
3774 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3774 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3775
3775
3776 - import all the patches in an Unix-style mbox::
3776 - import all the patches in an Unix-style mbox::
3777
3777
3778 hg import incoming-patches.mbox
3778 hg import incoming-patches.mbox
3779
3779
3780 - attempt to exactly restore an exported changeset (not always
3780 - attempt to exactly restore an exported changeset (not always
3781 possible)::
3781 possible)::
3782
3782
3783 hg import --exact proposed-fix.patch
3783 hg import --exact proposed-fix.patch
3784
3784
3785 Returns 0 on success.
3785 Returns 0 on success.
3786 """
3786 """
3787
3787
3788 if not patch1:
3788 if not patch1:
3789 raise util.Abort(_('need at least one patch to import'))
3789 raise util.Abort(_('need at least one patch to import'))
3790
3790
3791 patches = (patch1,) + patches
3791 patches = (patch1,) + patches
3792
3792
3793 date = opts.get('date')
3793 date = opts.get('date')
3794 if date:
3794 if date:
3795 opts['date'] = util.parsedate(date)
3795 opts['date'] = util.parsedate(date)
3796
3796
3797 update = not opts.get('bypass')
3797 update = not opts.get('bypass')
3798 if not update and opts.get('no_commit'):
3798 if not update and opts.get('no_commit'):
3799 raise util.Abort(_('cannot use --no-commit with --bypass'))
3799 raise util.Abort(_('cannot use --no-commit with --bypass'))
3800 try:
3800 try:
3801 sim = float(opts.get('similarity') or 0)
3801 sim = float(opts.get('similarity') or 0)
3802 except ValueError:
3802 except ValueError:
3803 raise util.Abort(_('similarity must be a number'))
3803 raise util.Abort(_('similarity must be a number'))
3804 if sim < 0 or sim > 100:
3804 if sim < 0 or sim > 100:
3805 raise util.Abort(_('similarity must be between 0 and 100'))
3805 raise util.Abort(_('similarity must be between 0 and 100'))
3806 if sim and not update:
3806 if sim and not update:
3807 raise util.Abort(_('cannot use --similarity with --bypass'))
3807 raise util.Abort(_('cannot use --similarity with --bypass'))
3808
3808
3809 if update:
3809 if update:
3810 cmdutil.checkunfinished(repo)
3810 cmdutil.checkunfinished(repo)
3811 if (opts.get('exact') or not opts.get('force')) and update:
3811 if (opts.get('exact') or not opts.get('force')) and update:
3812 cmdutil.bailifchanged(repo)
3812 cmdutil.bailifchanged(repo)
3813
3813
3814 base = opts["base"]
3814 base = opts["base"]
3815 wlock = lock = tr = None
3815 wlock = lock = tr = None
3816 msgs = []
3816 msgs = []
3817
3817
3818
3818
3819 try:
3819 try:
3820 try:
3820 try:
3821 wlock = repo.wlock()
3821 wlock = repo.wlock()
3822 if not opts.get('no_commit'):
3822 if not opts.get('no_commit'):
3823 lock = repo.lock()
3823 lock = repo.lock()
3824 tr = repo.transaction('import')
3824 tr = repo.transaction('import')
3825 parents = repo.parents()
3825 parents = repo.parents()
3826 for patchurl in patches:
3826 for patchurl in patches:
3827 if patchurl == '-':
3827 if patchurl == '-':
3828 ui.status(_('applying patch from stdin\n'))
3828 ui.status(_('applying patch from stdin\n'))
3829 patchfile = ui.fin
3829 patchfile = ui.fin
3830 patchurl = 'stdin' # for error message
3830 patchurl = 'stdin' # for error message
3831 else:
3831 else:
3832 patchurl = os.path.join(base, patchurl)
3832 patchurl = os.path.join(base, patchurl)
3833 ui.status(_('applying %s\n') % patchurl)
3833 ui.status(_('applying %s\n') % patchurl)
3834 patchfile = hg.openpath(ui, patchurl)
3834 patchfile = hg.openpath(ui, patchurl)
3835
3835
3836 haspatch = False
3836 haspatch = False
3837 for hunk in patch.split(patchfile):
3837 for hunk in patch.split(patchfile):
3838 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents,
3838 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents,
3839 opts, msgs, hg.clean)
3839 opts, msgs, hg.clean)
3840 if msg:
3840 if msg:
3841 haspatch = True
3841 haspatch = True
3842 ui.note(msg + '\n')
3842 ui.note(msg + '\n')
3843 if update or opts.get('exact'):
3843 if update or opts.get('exact'):
3844 parents = repo.parents()
3844 parents = repo.parents()
3845 else:
3845 else:
3846 parents = [repo[node]]
3846 parents = [repo[node]]
3847
3847
3848 if not haspatch:
3848 if not haspatch:
3849 raise util.Abort(_('%s: no diffs found') % patchurl)
3849 raise util.Abort(_('%s: no diffs found') % patchurl)
3850
3850
3851 if tr:
3851 if tr:
3852 tr.close()
3852 tr.close()
3853 if msgs:
3853 if msgs:
3854 repo.savecommitmessage('\n* * *\n'.join(msgs))
3854 repo.savecommitmessage('\n* * *\n'.join(msgs))
3855 except: # re-raises
3855 except: # re-raises
3856 # wlock.release() indirectly calls dirstate.write(): since
3856 # wlock.release() indirectly calls dirstate.write(): since
3857 # we're crashing, we do not want to change the working dir
3857 # we're crashing, we do not want to change the working dir
3858 # parent after all, so make sure it writes nothing
3858 # parent after all, so make sure it writes nothing
3859 repo.dirstate.invalidate()
3859 repo.dirstate.invalidate()
3860 raise
3860 raise
3861 finally:
3861 finally:
3862 if tr:
3862 if tr:
3863 tr.release()
3863 tr.release()
3864 release(lock, wlock)
3864 release(lock, wlock)
3865
3865
3866 @command('incoming|in',
3866 @command('incoming|in',
3867 [('f', 'force', None,
3867 [('f', 'force', None,
3868 _('run even if remote repository is unrelated')),
3868 _('run even if remote repository is unrelated')),
3869 ('n', 'newest-first', None, _('show newest record first')),
3869 ('n', 'newest-first', None, _('show newest record first')),
3870 ('', 'bundle', '',
3870 ('', 'bundle', '',
3871 _('file to store the bundles into'), _('FILE')),
3871 _('file to store the bundles into'), _('FILE')),
3872 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3872 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3873 ('B', 'bookmarks', False, _("compare bookmarks")),
3873 ('B', 'bookmarks', False, _("compare bookmarks")),
3874 ('b', 'branch', [],
3874 ('b', 'branch', [],
3875 _('a specific branch you would like to pull'), _('BRANCH')),
3875 _('a specific branch you would like to pull'), _('BRANCH')),
3876 ] + logopts + remoteopts + subrepoopts,
3876 ] + logopts + remoteopts + subrepoopts,
3877 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3877 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3878 def incoming(ui, repo, source="default", **opts):
3878 def incoming(ui, repo, source="default", **opts):
3879 """show new changesets found in source
3879 """show new changesets found in source
3880
3880
3881 Show new changesets found in the specified path/URL or the default
3881 Show new changesets found in the specified path/URL or the default
3882 pull location. These are the changesets that would have been pulled
3882 pull location. These are the changesets that would have been pulled
3883 if a pull at the time you issued this command.
3883 if a pull at the time you issued this command.
3884
3884
3885 For remote repository, using --bundle avoids downloading the
3885 For remote repository, using --bundle avoids downloading the
3886 changesets twice if the incoming is followed by a pull.
3886 changesets twice if the incoming is followed by a pull.
3887
3887
3888 See pull for valid source format details.
3888 See pull for valid source format details.
3889
3889
3890 .. container:: verbose
3890 .. container:: verbose
3891
3891
3892 Examples:
3892 Examples:
3893
3893
3894 - show incoming changes with patches and full description::
3894 - show incoming changes with patches and full description::
3895
3895
3896 hg incoming -vp
3896 hg incoming -vp
3897
3897
3898 - show incoming changes excluding merges, store a bundle::
3898 - show incoming changes excluding merges, store a bundle::
3899
3899
3900 hg in -vpM --bundle incoming.hg
3900 hg in -vpM --bundle incoming.hg
3901 hg pull incoming.hg
3901 hg pull incoming.hg
3902
3902
3903 - briefly list changes inside a bundle::
3903 - briefly list changes inside a bundle::
3904
3904
3905 hg in changes.hg -T "{desc|firstline}\\n"
3905 hg in changes.hg -T "{desc|firstline}\\n"
3906
3906
3907 Returns 0 if there are incoming changes, 1 otherwise.
3907 Returns 0 if there are incoming changes, 1 otherwise.
3908 """
3908 """
3909 if opts.get('graph'):
3909 if opts.get('graph'):
3910 cmdutil.checkunsupportedgraphflags([], opts)
3910 cmdutil.checkunsupportedgraphflags([], opts)
3911 def display(other, chlist, displayer):
3911 def display(other, chlist, displayer):
3912 revdag = cmdutil.graphrevs(other, chlist, opts)
3912 revdag = cmdutil.graphrevs(other, chlist, opts)
3913 showparents = [ctx.node() for ctx in repo[None].parents()]
3913 showparents = [ctx.node() for ctx in repo[None].parents()]
3914 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3914 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3915 graphmod.asciiedges)
3915 graphmod.asciiedges)
3916
3916
3917 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3917 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3918 return 0
3918 return 0
3919
3919
3920 if opts.get('bundle') and opts.get('subrepos'):
3920 if opts.get('bundle') and opts.get('subrepos'):
3921 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3921 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3922
3922
3923 if opts.get('bookmarks'):
3923 if opts.get('bookmarks'):
3924 source, branches = hg.parseurl(ui.expandpath(source),
3924 source, branches = hg.parseurl(ui.expandpath(source),
3925 opts.get('branch'))
3925 opts.get('branch'))
3926 other = hg.peer(repo, opts, source)
3926 other = hg.peer(repo, opts, source)
3927 if 'bookmarks' not in other.listkeys('namespaces'):
3927 if 'bookmarks' not in other.listkeys('namespaces'):
3928 ui.warn(_("remote doesn't support bookmarks\n"))
3928 ui.warn(_("remote doesn't support bookmarks\n"))
3929 return 0
3929 return 0
3930 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3930 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3931 return bookmarks.diff(ui, repo, other)
3931 return bookmarks.diff(ui, repo, other)
3932
3932
3933 repo._subtoppath = ui.expandpath(source)
3933 repo._subtoppath = ui.expandpath(source)
3934 try:
3934 try:
3935 return hg.incoming(ui, repo, source, opts)
3935 return hg.incoming(ui, repo, source, opts)
3936 finally:
3936 finally:
3937 del repo._subtoppath
3937 del repo._subtoppath
3938
3938
3939
3939
3940 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3940 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3941 def init(ui, dest=".", **opts):
3941 def init(ui, dest=".", **opts):
3942 """create a new repository in the given directory
3942 """create a new repository in the given directory
3943
3943
3944 Initialize a new repository in the given directory. If the given
3944 Initialize a new repository in the given directory. If the given
3945 directory does not exist, it will be created.
3945 directory does not exist, it will be created.
3946
3946
3947 If no directory is given, the current directory is used.
3947 If no directory is given, the current directory is used.
3948
3948
3949 It is possible to specify an ``ssh://`` URL as the destination.
3949 It is possible to specify an ``ssh://`` URL as the destination.
3950 See :hg:`help urls` for more information.
3950 See :hg:`help urls` for more information.
3951
3951
3952 Returns 0 on success.
3952 Returns 0 on success.
3953 """
3953 """
3954 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3954 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3955
3955
3956 @command('locate',
3956 @command('locate',
3957 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3957 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3958 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3958 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3959 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3959 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3960 ] + walkopts,
3960 ] + walkopts,
3961 _('[OPTION]... [PATTERN]...'))
3961 _('[OPTION]... [PATTERN]...'))
3962 def locate(ui, repo, *pats, **opts):
3962 def locate(ui, repo, *pats, **opts):
3963 """locate files matching specific patterns
3963 """locate files matching specific patterns
3964
3964
3965 Print files under Mercurial control in the working directory whose
3965 Print files under Mercurial control in the working directory whose
3966 names match the given patterns.
3966 names match the given patterns.
3967
3967
3968 By default, this command searches all directories in the working
3968 By default, this command searches all directories in the working
3969 directory. To search just the current directory and its
3969 directory. To search just the current directory and its
3970 subdirectories, use "--include .".
3970 subdirectories, use "--include .".
3971
3971
3972 If no patterns are given to match, this command prints the names
3972 If no patterns are given to match, this command prints the names
3973 of all files under Mercurial control in the working directory.
3973 of all files under Mercurial control in the working directory.
3974
3974
3975 If you want to feed the output of this command into the "xargs"
3975 If you want to feed the output of this command into the "xargs"
3976 command, use the -0 option to both this command and "xargs". This
3976 command, use the -0 option to both this command and "xargs". This
3977 will avoid the problem of "xargs" treating single filenames that
3977 will avoid the problem of "xargs" treating single filenames that
3978 contain whitespace as multiple filenames.
3978 contain whitespace as multiple filenames.
3979
3979
3980 Returns 0 if a match is found, 1 otherwise.
3980 Returns 0 if a match is found, 1 otherwise.
3981 """
3981 """
3982 end = opts.get('print0') and '\0' or '\n'
3982 end = opts.get('print0') and '\0' or '\n'
3983 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3983 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3984
3984
3985 ret = 1
3985 ret = 1
3986 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3986 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3987 m.bad = lambda x, y: False
3987 m.bad = lambda x, y: False
3988 for abs in repo[rev].walk(m):
3988 for abs in repo[rev].walk(m):
3989 if not rev and abs not in repo.dirstate:
3989 if not rev and abs not in repo.dirstate:
3990 continue
3990 continue
3991 if opts.get('fullpath'):
3991 if opts.get('fullpath'):
3992 ui.write(repo.wjoin(abs), end)
3992 ui.write(repo.wjoin(abs), end)
3993 else:
3993 else:
3994 ui.write(((pats and m.rel(abs)) or abs), end)
3994 ui.write(((pats and m.rel(abs)) or abs), end)
3995 ret = 0
3995 ret = 0
3996
3996
3997 return ret
3997 return ret
3998
3998
3999 @command('^log|history',
3999 @command('^log|history',
4000 [('f', 'follow', None,
4000 [('f', 'follow', None,
4001 _('follow changeset history, or file history across copies and renames')),
4001 _('follow changeset history, or file history across copies and renames')),
4002 ('', 'follow-first', None,
4002 ('', 'follow-first', None,
4003 _('only follow the first parent of merge changesets (DEPRECATED)')),
4003 _('only follow the first parent of merge changesets (DEPRECATED)')),
4004 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4004 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4005 ('C', 'copies', None, _('show copied files')),
4005 ('C', 'copies', None, _('show copied files')),
4006 ('k', 'keyword', [],
4006 ('k', 'keyword', [],
4007 _('do case-insensitive search for a given text'), _('TEXT')),
4007 _('do case-insensitive search for a given text'), _('TEXT')),
4008 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4008 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4009 ('', 'removed', None, _('include revisions where files were removed')),
4009 ('', 'removed', None, _('include revisions where files were removed')),
4010 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4010 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4011 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4011 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4012 ('', 'only-branch', [],
4012 ('', 'only-branch', [],
4013 _('show only changesets within the given named branch (DEPRECATED)'),
4013 _('show only changesets within the given named branch (DEPRECATED)'),
4014 _('BRANCH')),
4014 _('BRANCH')),
4015 ('b', 'branch', [],
4015 ('b', 'branch', [],
4016 _('show changesets within the given named branch'), _('BRANCH')),
4016 _('show changesets within the given named branch'), _('BRANCH')),
4017 ('P', 'prune', [],
4017 ('P', 'prune', [],
4018 _('do not display revision or any of its ancestors'), _('REV')),
4018 _('do not display revision or any of its ancestors'), _('REV')),
4019 ] + logopts + walkopts,
4019 ] + logopts + walkopts,
4020 _('[OPTION]... [FILE]'))
4020 _('[OPTION]... [FILE]'))
4021 def log(ui, repo, *pats, **opts):
4021 def log(ui, repo, *pats, **opts):
4022 """show revision history of entire repository or files
4022 """show revision history of entire repository or files
4023
4023
4024 Print the revision history of the specified files or the entire
4024 Print the revision history of the specified files or the entire
4025 project.
4025 project.
4026
4026
4027 If no revision range is specified, the default is ``tip:0`` unless
4027 If no revision range is specified, the default is ``tip:0`` unless
4028 --follow is set, in which case the working directory parent is
4028 --follow is set, in which case the working directory parent is
4029 used as the starting revision.
4029 used as the starting revision.
4030
4030
4031 File history is shown without following rename or copy history of
4031 File history is shown without following rename or copy history of
4032 files. Use -f/--follow with a filename to follow history across
4032 files. Use -f/--follow with a filename to follow history across
4033 renames and copies. --follow without a filename will only show
4033 renames and copies. --follow without a filename will only show
4034 ancestors or descendants of the starting revision.
4034 ancestors or descendants of the starting revision.
4035
4035
4036 By default this command prints revision number and changeset id,
4036 By default this command prints revision number and changeset id,
4037 tags, non-trivial parents, user, date and time, and a summary for
4037 tags, non-trivial parents, user, date and time, and a summary for
4038 each commit. When the -v/--verbose switch is used, the list of
4038 each commit. When the -v/--verbose switch is used, the list of
4039 changed files and full commit message are shown.
4039 changed files and full commit message are shown.
4040
4040
4041 With --graph the revisions are shown as an ASCII art DAG with the most
4041 With --graph the revisions are shown as an ASCII art DAG with the most
4042 recent changeset at the top.
4042 recent changeset at the top.
4043 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4043 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4044 and '+' represents a fork where the changeset from the lines below is a
4044 and '+' represents a fork where the changeset from the lines below is a
4045 parent of the 'o' merge on the same same line.
4045 parent of the 'o' merge on the same same line.
4046
4046
4047 .. note::
4047 .. note::
4048
4048
4049 log -p/--patch may generate unexpected diff output for merge
4049 log -p/--patch may generate unexpected diff output for merge
4050 changesets, as it will only compare the merge changeset against
4050 changesets, as it will only compare the merge changeset against
4051 its first parent. Also, only files different from BOTH parents
4051 its first parent. Also, only files different from BOTH parents
4052 will appear in files:.
4052 will appear in files:.
4053
4053
4054 .. note::
4054 .. note::
4055
4055
4056 for performance reasons, log FILE may omit duplicate changes
4056 for performance reasons, log FILE may omit duplicate changes
4057 made on branches and will not show deletions. To see all
4057 made on branches and will not show deletions. To see all
4058 changes including duplicates and deletions, use the --removed
4058 changes including duplicates and deletions, use the --removed
4059 switch.
4059 switch.
4060
4060
4061 .. container:: verbose
4061 .. container:: verbose
4062
4062
4063 Some examples:
4063 Some examples:
4064
4064
4065 - changesets with full descriptions and file lists::
4065 - changesets with full descriptions and file lists::
4066
4066
4067 hg log -v
4067 hg log -v
4068
4068
4069 - changesets ancestral to the working directory::
4069 - changesets ancestral to the working directory::
4070
4070
4071 hg log -f
4071 hg log -f
4072
4072
4073 - last 10 commits on the current branch::
4073 - last 10 commits on the current branch::
4074
4074
4075 hg log -l 10 -b .
4075 hg log -l 10 -b .
4076
4076
4077 - changesets showing all modifications of a file, including removals::
4077 - changesets showing all modifications of a file, including removals::
4078
4078
4079 hg log --removed file.c
4079 hg log --removed file.c
4080
4080
4081 - all changesets that touch a directory, with diffs, excluding merges::
4081 - all changesets that touch a directory, with diffs, excluding merges::
4082
4082
4083 hg log -Mp lib/
4083 hg log -Mp lib/
4084
4084
4085 - all revision numbers that match a keyword::
4085 - all revision numbers that match a keyword::
4086
4086
4087 hg log -k bug --template "{rev}\\n"
4087 hg log -k bug --template "{rev}\\n"
4088
4088
4089 - check if a given changeset is included is a tagged release::
4089 - check if a given changeset is included is a tagged release::
4090
4090
4091 hg log -r "a21ccf and ancestor(1.9)"
4091 hg log -r "a21ccf and ancestor(1.9)"
4092
4092
4093 - find all changesets by some user in a date range::
4093 - find all changesets by some user in a date range::
4094
4094
4095 hg log -k alice -d "may 2008 to jul 2008"
4095 hg log -k alice -d "may 2008 to jul 2008"
4096
4096
4097 - summary of all changesets after the last tag::
4097 - summary of all changesets after the last tag::
4098
4098
4099 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4099 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4100
4100
4101 See :hg:`help dates` for a list of formats valid for -d/--date.
4101 See :hg:`help dates` for a list of formats valid for -d/--date.
4102
4102
4103 See :hg:`help revisions` and :hg:`help revsets` for more about
4103 See :hg:`help revisions` and :hg:`help revsets` for more about
4104 specifying revisions.
4104 specifying revisions.
4105
4105
4106 See :hg:`help templates` for more about pre-packaged styles and
4106 See :hg:`help templates` for more about pre-packaged styles and
4107 specifying custom templates.
4107 specifying custom templates.
4108
4108
4109 Returns 0 on success.
4109 Returns 0 on success.
4110 """
4110 """
4111 if opts.get('graph'):
4111 if opts.get('graph'):
4112 return cmdutil.graphlog(ui, repo, *pats, **opts)
4112 return cmdutil.graphlog(ui, repo, *pats, **opts)
4113
4113
4114 matchfn = scmutil.match(repo[None], pats, opts)
4114 matchfn = scmutil.match(repo[None], pats, opts)
4115 limit = cmdutil.loglimit(opts)
4115 limit = cmdutil.loglimit(opts)
4116 count = 0
4116 count = 0
4117
4117
4118 getrenamed, endrev = None, None
4118 getrenamed, endrev = None, None
4119 if opts.get('copies'):
4119 if opts.get('copies'):
4120 if opts.get('rev'):
4120 if opts.get('rev'):
4121 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4121 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4122 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4122 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4123
4123
4124 df = False
4124 df = False
4125 if opts.get("date"):
4125 if opts.get("date"):
4126 df = util.matchdate(opts["date"])
4126 df = util.matchdate(opts["date"])
4127
4127
4128 branches = opts.get('branch', []) + opts.get('only_branch', [])
4128 branches = opts.get('branch', []) + opts.get('only_branch', [])
4129 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4129 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4130
4130
4131 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4131 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4132 def prep(ctx, fns):
4132 def prep(ctx, fns):
4133 rev = ctx.rev()
4133 rev = ctx.rev()
4134 parents = [p for p in repo.changelog.parentrevs(rev)
4134 parents = [p for p in repo.changelog.parentrevs(rev)
4135 if p != nullrev]
4135 if p != nullrev]
4136 if opts.get('no_merges') and len(parents) == 2:
4136 if opts.get('no_merges') and len(parents) == 2:
4137 return
4137 return
4138 if opts.get('only_merges') and len(parents) != 2:
4138 if opts.get('only_merges') and len(parents) != 2:
4139 return
4139 return
4140 if opts.get('branch') and ctx.branch() not in opts['branch']:
4140 if opts.get('branch') and ctx.branch() not in opts['branch']:
4141 return
4141 return
4142 if df and not df(ctx.date()[0]):
4142 if df and not df(ctx.date()[0]):
4143 return
4143 return
4144
4144
4145 lower = encoding.lower
4145 lower = encoding.lower
4146 if opts.get('user'):
4146 if opts.get('user'):
4147 luser = lower(ctx.user())
4147 luser = lower(ctx.user())
4148 for k in [lower(x) for x in opts['user']]:
4148 for k in [lower(x) for x in opts['user']]:
4149 if (k in luser):
4149 if (k in luser):
4150 break
4150 break
4151 else:
4151 else:
4152 return
4152 return
4153 if opts.get('keyword'):
4153 if opts.get('keyword'):
4154 luser = lower(ctx.user())
4154 luser = lower(ctx.user())
4155 ldesc = lower(ctx.description())
4155 ldesc = lower(ctx.description())
4156 lfiles = lower(" ".join(ctx.files()))
4156 lfiles = lower(" ".join(ctx.files()))
4157 for k in [lower(x) for x in opts['keyword']]:
4157 for k in [lower(x) for x in opts['keyword']]:
4158 if (k in luser or k in ldesc or k in lfiles):
4158 if (k in luser or k in ldesc or k in lfiles):
4159 break
4159 break
4160 else:
4160 else:
4161 return
4161 return
4162
4162
4163 copies = None
4163 copies = None
4164 if getrenamed is not None and rev:
4164 if getrenamed is not None and rev:
4165 copies = []
4165 copies = []
4166 for fn in ctx.files():
4166 for fn in ctx.files():
4167 rename = getrenamed(fn, rev)
4167 rename = getrenamed(fn, rev)
4168 if rename:
4168 if rename:
4169 copies.append((fn, rename[0]))
4169 copies.append((fn, rename[0]))
4170
4170
4171 revmatchfn = None
4171 revmatchfn = None
4172 if opts.get('patch') or opts.get('stat'):
4172 if opts.get('patch') or opts.get('stat'):
4173 if opts.get('follow') or opts.get('follow_first'):
4173 if opts.get('follow') or opts.get('follow_first'):
4174 # note: this might be wrong when following through merges
4174 # note: this might be wrong when following through merges
4175 revmatchfn = scmutil.match(repo[None], fns, default='path')
4175 revmatchfn = scmutil.match(repo[None], fns, default='path')
4176 else:
4176 else:
4177 revmatchfn = matchfn
4177 revmatchfn = matchfn
4178
4178
4179 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4179 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4180
4180
4181 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4181 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4182 if displayer.flush(ctx.rev()):
4182 if displayer.flush(ctx.rev()):
4183 count += 1
4183 count += 1
4184 if count == limit:
4184 if count == limit:
4185 break
4185 break
4186 displayer.close()
4186 displayer.close()
4187
4187
4188 @command('manifest',
4188 @command('manifest',
4189 [('r', 'rev', '', _('revision to display'), _('REV')),
4189 [('r', 'rev', '', _('revision to display'), _('REV')),
4190 ('', 'all', False, _("list files from all revisions"))],
4190 ('', 'all', False, _("list files from all revisions"))],
4191 _('[-r REV]'))
4191 _('[-r REV]'))
4192 def manifest(ui, repo, node=None, rev=None, **opts):
4192 def manifest(ui, repo, node=None, rev=None, **opts):
4193 """output the current or given revision of the project manifest
4193 """output the current or given revision of the project manifest
4194
4194
4195 Print a list of version controlled files for the given revision.
4195 Print a list of version controlled files for the given revision.
4196 If no revision is given, the first parent of the working directory
4196 If no revision is given, the first parent of the working directory
4197 is used, or the null revision if no revision is checked out.
4197 is used, or the null revision if no revision is checked out.
4198
4198
4199 With -v, print file permissions, symlink and executable bits.
4199 With -v, print file permissions, symlink and executable bits.
4200 With --debug, print file revision hashes.
4200 With --debug, print file revision hashes.
4201
4201
4202 If option --all is specified, the list of all files from all revisions
4202 If option --all is specified, the list of all files from all revisions
4203 is printed. This includes deleted and renamed files.
4203 is printed. This includes deleted and renamed files.
4204
4204
4205 Returns 0 on success.
4205 Returns 0 on success.
4206 """
4206 """
4207
4207
4208 fm = ui.formatter('manifest', opts)
4208 fm = ui.formatter('manifest', opts)
4209
4209
4210 if opts.get('all'):
4210 if opts.get('all'):
4211 if rev or node:
4211 if rev or node:
4212 raise util.Abort(_("can't specify a revision with --all"))
4212 raise util.Abort(_("can't specify a revision with --all"))
4213
4213
4214 res = []
4214 res = []
4215 prefix = "data/"
4215 prefix = "data/"
4216 suffix = ".i"
4216 suffix = ".i"
4217 plen = len(prefix)
4217 plen = len(prefix)
4218 slen = len(suffix)
4218 slen = len(suffix)
4219 lock = repo.lock()
4219 lock = repo.lock()
4220 try:
4220 try:
4221 for fn, b, size in repo.store.datafiles():
4221 for fn, b, size in repo.store.datafiles():
4222 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4222 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4223 res.append(fn[plen:-slen])
4223 res.append(fn[plen:-slen])
4224 finally:
4224 finally:
4225 lock.release()
4225 lock.release()
4226 for f in res:
4226 for f in res:
4227 fm.startitem()
4227 fm.startitem()
4228 fm.write("path", '%s\n', f)
4228 fm.write("path", '%s\n', f)
4229 fm.end()
4229 fm.end()
4230 return
4230 return
4231
4231
4232 if rev and node:
4232 if rev and node:
4233 raise util.Abort(_("please specify just one revision"))
4233 raise util.Abort(_("please specify just one revision"))
4234
4234
4235 if not node:
4235 if not node:
4236 node = rev
4236 node = rev
4237
4237
4238 char = {'l': '@', 'x': '*', '': ''}
4238 char = {'l': '@', 'x': '*', '': ''}
4239 mode = {'l': '644', 'x': '755', '': '644'}
4239 mode = {'l': '644', 'x': '755', '': '644'}
4240 ctx = scmutil.revsingle(repo, node)
4240 ctx = scmutil.revsingle(repo, node)
4241 mf = ctx.manifest()
4241 mf = ctx.manifest()
4242 for f in ctx:
4242 for f in ctx:
4243 fm.startitem()
4243 fm.startitem()
4244 fl = ctx[f].flags()
4244 fl = ctx[f].flags()
4245 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4245 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4246 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4246 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4247 fm.write('path', '%s\n', f)
4247 fm.write('path', '%s\n', f)
4248 fm.end()
4248 fm.end()
4249
4249
4250 @command('^merge',
4250 @command('^merge',
4251 [('f', 'force', None,
4251 [('f', 'force', None,
4252 _('force a merge including outstanding changes (DEPRECATED)')),
4252 _('force a merge including outstanding changes (DEPRECATED)')),
4253 ('r', 'rev', '', _('revision to merge'), _('REV')),
4253 ('r', 'rev', '', _('revision to merge'), _('REV')),
4254 ('P', 'preview', None,
4254 ('P', 'preview', None,
4255 _('review revisions to merge (no merge is performed)'))
4255 _('review revisions to merge (no merge is performed)'))
4256 ] + mergetoolopts,
4256 ] + mergetoolopts,
4257 _('[-P] [-f] [[-r] REV]'))
4257 _('[-P] [-f] [[-r] REV]'))
4258 def merge(ui, repo, node=None, **opts):
4258 def merge(ui, repo, node=None, **opts):
4259 """merge working directory with another revision
4259 """merge working directory with another revision
4260
4260
4261 The current working directory is updated with all changes made in
4261 The current working directory is updated with all changes made in
4262 the requested revision since the last common predecessor revision.
4262 the requested revision since the last common predecessor revision.
4263
4263
4264 Files that changed between either parent are marked as changed for
4264 Files that changed between either parent are marked as changed for
4265 the next commit and a commit must be performed before any further
4265 the next commit and a commit must be performed before any further
4266 updates to the repository are allowed. The next commit will have
4266 updates to the repository are allowed. The next commit will have
4267 two parents.
4267 two parents.
4268
4268
4269 ``--tool`` can be used to specify the merge tool used for file
4269 ``--tool`` can be used to specify the merge tool used for file
4270 merges. It overrides the HGMERGE environment variable and your
4270 merges. It overrides the HGMERGE environment variable and your
4271 configuration files. See :hg:`help merge-tools` for options.
4271 configuration files. See :hg:`help merge-tools` for options.
4272
4272
4273 If no revision is specified, the working directory's parent is a
4273 If no revision is specified, the working directory's parent is a
4274 head revision, and the current branch contains exactly one other
4274 head revision, and the current branch contains exactly one other
4275 head, the other head is merged with by default. Otherwise, an
4275 head, the other head is merged with by default. Otherwise, an
4276 explicit revision with which to merge with must be provided.
4276 explicit revision with which to merge with must be provided.
4277
4277
4278 :hg:`resolve` must be used to resolve unresolved files.
4278 :hg:`resolve` must be used to resolve unresolved files.
4279
4279
4280 To undo an uncommitted merge, use :hg:`update --clean .` which
4280 To undo an uncommitted merge, use :hg:`update --clean .` which
4281 will check out a clean copy of the original merge parent, losing
4281 will check out a clean copy of the original merge parent, losing
4282 all changes.
4282 all changes.
4283
4283
4284 Returns 0 on success, 1 if there are unresolved files.
4284 Returns 0 on success, 1 if there are unresolved files.
4285 """
4285 """
4286
4286
4287 if opts.get('rev') and node:
4287 if opts.get('rev') and node:
4288 raise util.Abort(_("please specify just one revision"))
4288 raise util.Abort(_("please specify just one revision"))
4289 if not node:
4289 if not node:
4290 node = opts.get('rev')
4290 node = opts.get('rev')
4291
4291
4292 if node:
4292 if node:
4293 node = scmutil.revsingle(repo, node).node()
4293 node = scmutil.revsingle(repo, node).node()
4294
4294
4295 if not node and repo._bookmarkcurrent:
4295 if not node and repo._bookmarkcurrent:
4296 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4296 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4297 curhead = repo[repo._bookmarkcurrent].node()
4297 curhead = repo[repo._bookmarkcurrent].node()
4298 if len(bmheads) == 2:
4298 if len(bmheads) == 2:
4299 if curhead == bmheads[0]:
4299 if curhead == bmheads[0]:
4300 node = bmheads[1]
4300 node = bmheads[1]
4301 else:
4301 else:
4302 node = bmheads[0]
4302 node = bmheads[0]
4303 elif len(bmheads) > 2:
4303 elif len(bmheads) > 2:
4304 raise util.Abort(_("multiple matching bookmarks to merge - "
4304 raise util.Abort(_("multiple matching bookmarks to merge - "
4305 "please merge with an explicit rev or bookmark"),
4305 "please merge with an explicit rev or bookmark"),
4306 hint=_("run 'hg heads' to see all heads"))
4306 hint=_("run 'hg heads' to see all heads"))
4307 elif len(bmheads) <= 1:
4307 elif len(bmheads) <= 1:
4308 raise util.Abort(_("no matching bookmark to merge - "
4308 raise util.Abort(_("no matching bookmark to merge - "
4309 "please merge with an explicit rev or bookmark"),
4309 "please merge with an explicit rev or bookmark"),
4310 hint=_("run 'hg heads' to see all heads"))
4310 hint=_("run 'hg heads' to see all heads"))
4311
4311
4312 if not node and not repo._bookmarkcurrent:
4312 if not node and not repo._bookmarkcurrent:
4313 branch = repo[None].branch()
4313 branch = repo[None].branch()
4314 bheads = repo.branchheads(branch)
4314 bheads = repo.branchheads(branch)
4315 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4315 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4316
4316
4317 if len(nbhs) > 2:
4317 if len(nbhs) > 2:
4318 raise util.Abort(_("branch '%s' has %d heads - "
4318 raise util.Abort(_("branch '%s' has %d heads - "
4319 "please merge with an explicit rev")
4319 "please merge with an explicit rev")
4320 % (branch, len(bheads)),
4320 % (branch, len(bheads)),
4321 hint=_("run 'hg heads .' to see heads"))
4321 hint=_("run 'hg heads .' to see heads"))
4322
4322
4323 parent = repo.dirstate.p1()
4323 parent = repo.dirstate.p1()
4324 if len(nbhs) <= 1:
4324 if len(nbhs) <= 1:
4325 if len(bheads) > 1:
4325 if len(bheads) > 1:
4326 raise util.Abort(_("heads are bookmarked - "
4326 raise util.Abort(_("heads are bookmarked - "
4327 "please merge with an explicit rev"),
4327 "please merge with an explicit rev"),
4328 hint=_("run 'hg heads' to see all heads"))
4328 hint=_("run 'hg heads' to see all heads"))
4329 if len(repo.heads()) > 1:
4329 if len(repo.heads()) > 1:
4330 raise util.Abort(_("branch '%s' has one head - "
4330 raise util.Abort(_("branch '%s' has one head - "
4331 "please merge with an explicit rev")
4331 "please merge with an explicit rev")
4332 % branch,
4332 % branch,
4333 hint=_("run 'hg heads' to see all heads"))
4333 hint=_("run 'hg heads' to see all heads"))
4334 msg, hint = _('nothing to merge'), None
4334 msg, hint = _('nothing to merge'), None
4335 if parent != repo.lookup(branch):
4335 if parent != repo.lookup(branch):
4336 hint = _("use 'hg update' instead")
4336 hint = _("use 'hg update' instead")
4337 raise util.Abort(msg, hint=hint)
4337 raise util.Abort(msg, hint=hint)
4338
4338
4339 if parent not in bheads:
4339 if parent not in bheads:
4340 raise util.Abort(_('working directory not at a head revision'),
4340 raise util.Abort(_('working directory not at a head revision'),
4341 hint=_("use 'hg update' or merge with an "
4341 hint=_("use 'hg update' or merge with an "
4342 "explicit revision"))
4342 "explicit revision"))
4343 if parent == nbhs[0]:
4343 if parent == nbhs[0]:
4344 node = nbhs[-1]
4344 node = nbhs[-1]
4345 else:
4345 else:
4346 node = nbhs[0]
4346 node = nbhs[0]
4347
4347
4348 if opts.get('preview'):
4348 if opts.get('preview'):
4349 # find nodes that are ancestors of p2 but not of p1
4349 # find nodes that are ancestors of p2 but not of p1
4350 p1 = repo.lookup('.')
4350 p1 = repo.lookup('.')
4351 p2 = repo.lookup(node)
4351 p2 = repo.lookup(node)
4352 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4352 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4353
4353
4354 displayer = cmdutil.show_changeset(ui, repo, opts)
4354 displayer = cmdutil.show_changeset(ui, repo, opts)
4355 for node in nodes:
4355 for node in nodes:
4356 displayer.show(repo[node])
4356 displayer.show(repo[node])
4357 displayer.close()
4357 displayer.close()
4358 return 0
4358 return 0
4359
4359
4360 try:
4360 try:
4361 # ui.forcemerge is an internal variable, do not document
4361 # ui.forcemerge is an internal variable, do not document
4362 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4362 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4363 return hg.merge(repo, node, force=opts.get('force'))
4363 return hg.merge(repo, node, force=opts.get('force'))
4364 finally:
4364 finally:
4365 ui.setconfig('ui', 'forcemerge', '', 'merge')
4365 ui.setconfig('ui', 'forcemerge', '', 'merge')
4366
4366
4367 @command('outgoing|out',
4367 @command('outgoing|out',
4368 [('f', 'force', None, _('run even when the destination is unrelated')),
4368 [('f', 'force', None, _('run even when the destination is unrelated')),
4369 ('r', 'rev', [],
4369 ('r', 'rev', [],
4370 _('a changeset intended to be included in the destination'), _('REV')),
4370 _('a changeset intended to be included in the destination'), _('REV')),
4371 ('n', 'newest-first', None, _('show newest record first')),
4371 ('n', 'newest-first', None, _('show newest record first')),
4372 ('B', 'bookmarks', False, _('compare bookmarks')),
4372 ('B', 'bookmarks', False, _('compare bookmarks')),
4373 ('b', 'branch', [], _('a specific branch you would like to push'),
4373 ('b', 'branch', [], _('a specific branch you would like to push'),
4374 _('BRANCH')),
4374 _('BRANCH')),
4375 ] + logopts + remoteopts + subrepoopts,
4375 ] + logopts + remoteopts + subrepoopts,
4376 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4376 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4377 def outgoing(ui, repo, dest=None, **opts):
4377 def outgoing(ui, repo, dest=None, **opts):
4378 """show changesets not found in the destination
4378 """show changesets not found in the destination
4379
4379
4380 Show changesets not found in the specified destination repository
4380 Show changesets not found in the specified destination repository
4381 or the default push location. These are the changesets that would
4381 or the default push location. These are the changesets that would
4382 be pushed if a push was requested.
4382 be pushed if a push was requested.
4383
4383
4384 See pull for details of valid destination formats.
4384 See pull for details of valid destination formats.
4385
4385
4386 Returns 0 if there are outgoing changes, 1 otherwise.
4386 Returns 0 if there are outgoing changes, 1 otherwise.
4387 """
4387 """
4388 if opts.get('graph'):
4388 if opts.get('graph'):
4389 cmdutil.checkunsupportedgraphflags([], opts)
4389 cmdutil.checkunsupportedgraphflags([], opts)
4390 o = hg._outgoing(ui, repo, dest, opts)
4390 o = hg._outgoing(ui, repo, dest, opts)
4391 if o is None:
4391 if o is None:
4392 return
4392 return
4393
4393
4394 revdag = cmdutil.graphrevs(repo, o, opts)
4394 revdag = cmdutil.graphrevs(repo, o, opts)
4395 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4395 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4396 showparents = [ctx.node() for ctx in repo[None].parents()]
4396 showparents = [ctx.node() for ctx in repo[None].parents()]
4397 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4397 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4398 graphmod.asciiedges)
4398 graphmod.asciiedges)
4399 return 0
4399 return 0
4400
4400
4401 if opts.get('bookmarks'):
4401 if opts.get('bookmarks'):
4402 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4402 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4403 dest, branches = hg.parseurl(dest, opts.get('branch'))
4403 dest, branches = hg.parseurl(dest, opts.get('branch'))
4404 other = hg.peer(repo, opts, dest)
4404 other = hg.peer(repo, opts, dest)
4405 if 'bookmarks' not in other.listkeys('namespaces'):
4405 if 'bookmarks' not in other.listkeys('namespaces'):
4406 ui.warn(_("remote doesn't support bookmarks\n"))
4406 ui.warn(_("remote doesn't support bookmarks\n"))
4407 return 0
4407 return 0
4408 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4408 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4409 return bookmarks.diff(ui, other, repo)
4409 return bookmarks.diff(ui, other, repo)
4410
4410
4411 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4411 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4412 try:
4412 try:
4413 return hg.outgoing(ui, repo, dest, opts)
4413 return hg.outgoing(ui, repo, dest, opts)
4414 finally:
4414 finally:
4415 del repo._subtoppath
4415 del repo._subtoppath
4416
4416
4417 @command('parents',
4417 @command('parents',
4418 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4418 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4419 ] + templateopts,
4419 ] + templateopts,
4420 _('[-r REV] [FILE]'))
4420 _('[-r REV] [FILE]'))
4421 def parents(ui, repo, file_=None, **opts):
4421 def parents(ui, repo, file_=None, **opts):
4422 """show the parents of the working directory or revision
4422 """show the parents of the working directory or revision
4423
4423
4424 Print the working directory's parent revisions. If a revision is
4424 Print the working directory's parent revisions. If a revision is
4425 given via -r/--rev, the parent of that revision will be printed.
4425 given via -r/--rev, the parent of that revision will be printed.
4426 If a file argument is given, the revision in which the file was
4426 If a file argument is given, the revision in which the file was
4427 last changed (before the working directory revision or the
4427 last changed (before the working directory revision or the
4428 argument to --rev if given) is printed.
4428 argument to --rev if given) is printed.
4429
4429
4430 Returns 0 on success.
4430 Returns 0 on success.
4431 """
4431 """
4432
4432
4433 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4433 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4434
4434
4435 if file_:
4435 if file_:
4436 m = scmutil.match(ctx, (file_,), opts)
4436 m = scmutil.match(ctx, (file_,), opts)
4437 if m.anypats() or len(m.files()) != 1:
4437 if m.anypats() or len(m.files()) != 1:
4438 raise util.Abort(_('can only specify an explicit filename'))
4438 raise util.Abort(_('can only specify an explicit filename'))
4439 file_ = m.files()[0]
4439 file_ = m.files()[0]
4440 filenodes = []
4440 filenodes = []
4441 for cp in ctx.parents():
4441 for cp in ctx.parents():
4442 if not cp:
4442 if not cp:
4443 continue
4443 continue
4444 try:
4444 try:
4445 filenodes.append(cp.filenode(file_))
4445 filenodes.append(cp.filenode(file_))
4446 except error.LookupError:
4446 except error.LookupError:
4447 pass
4447 pass
4448 if not filenodes:
4448 if not filenodes:
4449 raise util.Abort(_("'%s' not found in manifest!") % file_)
4449 raise util.Abort(_("'%s' not found in manifest!") % file_)
4450 p = []
4450 p = []
4451 for fn in filenodes:
4451 for fn in filenodes:
4452 fctx = repo.filectx(file_, fileid=fn)
4452 fctx = repo.filectx(file_, fileid=fn)
4453 p.append(fctx.node())
4453 p.append(fctx.node())
4454 else:
4454 else:
4455 p = [cp.node() for cp in ctx.parents()]
4455 p = [cp.node() for cp in ctx.parents()]
4456
4456
4457 displayer = cmdutil.show_changeset(ui, repo, opts)
4457 displayer = cmdutil.show_changeset(ui, repo, opts)
4458 for n in p:
4458 for n in p:
4459 if n != nullid:
4459 if n != nullid:
4460 displayer.show(repo[n])
4460 displayer.show(repo[n])
4461 displayer.close()
4461 displayer.close()
4462
4462
4463 @command('paths', [], _('[NAME]'))
4463 @command('paths', [], _('[NAME]'))
4464 def paths(ui, repo, search=None):
4464 def paths(ui, repo, search=None):
4465 """show aliases for remote repositories
4465 """show aliases for remote repositories
4466
4466
4467 Show definition of symbolic path name NAME. If no name is given,
4467 Show definition of symbolic path name NAME. If no name is given,
4468 show definition of all available names.
4468 show definition of all available names.
4469
4469
4470 Option -q/--quiet suppresses all output when searching for NAME
4470 Option -q/--quiet suppresses all output when searching for NAME
4471 and shows only the path names when listing all definitions.
4471 and shows only the path names when listing all definitions.
4472
4472
4473 Path names are defined in the [paths] section of your
4473 Path names are defined in the [paths] section of your
4474 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4474 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4475 repository, ``.hg/hgrc`` is used, too.
4475 repository, ``.hg/hgrc`` is used, too.
4476
4476
4477 The path names ``default`` and ``default-push`` have a special
4477 The path names ``default`` and ``default-push`` have a special
4478 meaning. When performing a push or pull operation, they are used
4478 meaning. When performing a push or pull operation, they are used
4479 as fallbacks if no location is specified on the command-line.
4479 as fallbacks if no location is specified on the command-line.
4480 When ``default-push`` is set, it will be used for push and
4480 When ``default-push`` is set, it will be used for push and
4481 ``default`` will be used for pull; otherwise ``default`` is used
4481 ``default`` will be used for pull; otherwise ``default`` is used
4482 as the fallback for both. When cloning a repository, the clone
4482 as the fallback for both. When cloning a repository, the clone
4483 source is written as ``default`` in ``.hg/hgrc``. Note that
4483 source is written as ``default`` in ``.hg/hgrc``. Note that
4484 ``default`` and ``default-push`` apply to all inbound (e.g.
4484 ``default`` and ``default-push`` apply to all inbound (e.g.
4485 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4485 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4486 :hg:`bundle`) operations.
4486 :hg:`bundle`) operations.
4487
4487
4488 See :hg:`help urls` for more information.
4488 See :hg:`help urls` for more information.
4489
4489
4490 Returns 0 on success.
4490 Returns 0 on success.
4491 """
4491 """
4492 if search:
4492 if search:
4493 for name, path in ui.configitems("paths"):
4493 for name, path in ui.configitems("paths"):
4494 if name == search:
4494 if name == search:
4495 ui.status("%s\n" % util.hidepassword(path))
4495 ui.status("%s\n" % util.hidepassword(path))
4496 return
4496 return
4497 if not ui.quiet:
4497 if not ui.quiet:
4498 ui.warn(_("not found!\n"))
4498 ui.warn(_("not found!\n"))
4499 return 1
4499 return 1
4500 else:
4500 else:
4501 for name, path in ui.configitems("paths"):
4501 for name, path in ui.configitems("paths"):
4502 if ui.quiet:
4502 if ui.quiet:
4503 ui.write("%s\n" % name)
4503 ui.write("%s\n" % name)
4504 else:
4504 else:
4505 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4505 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4506
4506
4507 @command('phase',
4507 @command('phase',
4508 [('p', 'public', False, _('set changeset phase to public')),
4508 [('p', 'public', False, _('set changeset phase to public')),
4509 ('d', 'draft', False, _('set changeset phase to draft')),
4509 ('d', 'draft', False, _('set changeset phase to draft')),
4510 ('s', 'secret', False, _('set changeset phase to secret')),
4510 ('s', 'secret', False, _('set changeset phase to secret')),
4511 ('f', 'force', False, _('allow to move boundary backward')),
4511 ('f', 'force', False, _('allow to move boundary backward')),
4512 ('r', 'rev', [], _('target revision'), _('REV')),
4512 ('r', 'rev', [], _('target revision'), _('REV')),
4513 ],
4513 ],
4514 _('[-p|-d|-s] [-f] [-r] REV...'))
4514 _('[-p|-d|-s] [-f] [-r] REV...'))
4515 def phase(ui, repo, *revs, **opts):
4515 def phase(ui, repo, *revs, **opts):
4516 """set or show the current phase name
4516 """set or show the current phase name
4517
4517
4518 With no argument, show the phase name of specified revisions.
4518 With no argument, show the phase name of specified revisions.
4519
4519
4520 With one of -p/--public, -d/--draft or -s/--secret, change the
4520 With one of -p/--public, -d/--draft or -s/--secret, change the
4521 phase value of the specified revisions.
4521 phase value of the specified revisions.
4522
4522
4523 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4523 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4524 lower phase to an higher phase. Phases are ordered as follows::
4524 lower phase to an higher phase. Phases are ordered as follows::
4525
4525
4526 public < draft < secret
4526 public < draft < secret
4527
4527
4528 Returns 0 on success, 1 if no phases were changed or some could not
4528 Returns 0 on success, 1 if no phases were changed or some could not
4529 be changed.
4529 be changed.
4530 """
4530 """
4531 # search for a unique phase argument
4531 # search for a unique phase argument
4532 targetphase = None
4532 targetphase = None
4533 for idx, name in enumerate(phases.phasenames):
4533 for idx, name in enumerate(phases.phasenames):
4534 if opts[name]:
4534 if opts[name]:
4535 if targetphase is not None:
4535 if targetphase is not None:
4536 raise util.Abort(_('only one phase can be specified'))
4536 raise util.Abort(_('only one phase can be specified'))
4537 targetphase = idx
4537 targetphase = idx
4538
4538
4539 # look for specified revision
4539 # look for specified revision
4540 revs = list(revs)
4540 revs = list(revs)
4541 revs.extend(opts['rev'])
4541 revs.extend(opts['rev'])
4542 if not revs:
4542 if not revs:
4543 raise util.Abort(_('no revisions specified'))
4543 raise util.Abort(_('no revisions specified'))
4544
4544
4545 revs = scmutil.revrange(repo, revs)
4545 revs = scmutil.revrange(repo, revs)
4546
4546
4547 lock = None
4547 lock = None
4548 ret = 0
4548 ret = 0
4549 if targetphase is None:
4549 if targetphase is None:
4550 # display
4550 # display
4551 for r in revs:
4551 for r in revs:
4552 ctx = repo[r]
4552 ctx = repo[r]
4553 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4553 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4554 else:
4554 else:
4555 lock = repo.lock()
4555 lock = repo.lock()
4556 try:
4556 try:
4557 # set phase
4557 # set phase
4558 if not revs:
4558 if not revs:
4559 raise util.Abort(_('empty revision set'))
4559 raise util.Abort(_('empty revision set'))
4560 nodes = [repo[r].node() for r in revs]
4560 nodes = [repo[r].node() for r in revs]
4561 olddata = repo._phasecache.getphaserevs(repo)[:]
4561 olddata = repo._phasecache.getphaserevs(repo)[:]
4562 phases.advanceboundary(repo, targetphase, nodes)
4562 phases.advanceboundary(repo, targetphase, nodes)
4563 if opts['force']:
4563 if opts['force']:
4564 phases.retractboundary(repo, targetphase, nodes)
4564 phases.retractboundary(repo, targetphase, nodes)
4565 finally:
4565 finally:
4566 lock.release()
4566 lock.release()
4567 # moving revision from public to draft may hide them
4567 # moving revision from public to draft may hide them
4568 # We have to check result on an unfiltered repository
4568 # We have to check result on an unfiltered repository
4569 unfi = repo.unfiltered()
4569 unfi = repo.unfiltered()
4570 newdata = repo._phasecache.getphaserevs(unfi)
4570 newdata = repo._phasecache.getphaserevs(unfi)
4571 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4571 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4572 cl = unfi.changelog
4572 cl = unfi.changelog
4573 rejected = [n for n in nodes
4573 rejected = [n for n in nodes
4574 if newdata[cl.rev(n)] < targetphase]
4574 if newdata[cl.rev(n)] < targetphase]
4575 if rejected:
4575 if rejected:
4576 ui.warn(_('cannot move %i changesets to a higher '
4576 ui.warn(_('cannot move %i changesets to a higher '
4577 'phase, use --force\n') % len(rejected))
4577 'phase, use --force\n') % len(rejected))
4578 ret = 1
4578 ret = 1
4579 if changes:
4579 if changes:
4580 msg = _('phase changed for %i changesets\n') % changes
4580 msg = _('phase changed for %i changesets\n') % changes
4581 if ret:
4581 if ret:
4582 ui.status(msg)
4582 ui.status(msg)
4583 else:
4583 else:
4584 ui.note(msg)
4584 ui.note(msg)
4585 else:
4585 else:
4586 ui.warn(_('no phases changed\n'))
4586 ui.warn(_('no phases changed\n'))
4587 ret = 1
4587 ret = 1
4588 return ret
4588 return ret
4589
4589
4590 def postincoming(ui, repo, modheads, optupdate, checkout):
4590 def postincoming(ui, repo, modheads, optupdate, checkout):
4591 if modheads == 0:
4591 if modheads == 0:
4592 return
4592 return
4593 if optupdate:
4593 if optupdate:
4594 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4594 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4595 try:
4595 try:
4596 ret = hg.update(repo, checkout)
4596 ret = hg.update(repo, checkout)
4597 except util.Abort, inst:
4597 except util.Abort, inst:
4598 ui.warn(_("not updating: %s\n") % str(inst))
4598 ui.warn(_("not updating: %s\n") % str(inst))
4599 if inst.hint:
4599 if inst.hint:
4600 ui.warn(_("(%s)\n") % inst.hint)
4600 ui.warn(_("(%s)\n") % inst.hint)
4601 return 0
4601 return 0
4602 if not ret and not checkout:
4602 if not ret and not checkout:
4603 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4603 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4604 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4604 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4605 return ret
4605 return ret
4606 if modheads > 1:
4606 if modheads > 1:
4607 currentbranchheads = len(repo.branchheads())
4607 currentbranchheads = len(repo.branchheads())
4608 if currentbranchheads == modheads:
4608 if currentbranchheads == modheads:
4609 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4609 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4610 elif currentbranchheads > 1:
4610 elif currentbranchheads > 1:
4611 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4611 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4612 "merge)\n"))
4612 "merge)\n"))
4613 else:
4613 else:
4614 ui.status(_("(run 'hg heads' to see heads)\n"))
4614 ui.status(_("(run 'hg heads' to see heads)\n"))
4615 else:
4615 else:
4616 ui.status(_("(run 'hg update' to get a working copy)\n"))
4616 ui.status(_("(run 'hg update' to get a working copy)\n"))
4617
4617
4618 @command('^pull',
4618 @command('^pull',
4619 [('u', 'update', None,
4619 [('u', 'update', None,
4620 _('update to new branch head if changesets were pulled')),
4620 _('update to new branch head if changesets were pulled')),
4621 ('f', 'force', None, _('run even when remote repository is unrelated')),
4621 ('f', 'force', None, _('run even when remote repository is unrelated')),
4622 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4622 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4623 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4623 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4624 ('b', 'branch', [], _('a specific branch you would like to pull'),
4624 ('b', 'branch', [], _('a specific branch you would like to pull'),
4625 _('BRANCH')),
4625 _('BRANCH')),
4626 ] + remoteopts,
4626 ] + remoteopts,
4627 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4627 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4628 def pull(ui, repo, source="default", **opts):
4628 def pull(ui, repo, source="default", **opts):
4629 """pull changes from the specified source
4629 """pull changes from the specified source
4630
4630
4631 Pull changes from a remote repository to a local one.
4631 Pull changes from a remote repository to a local one.
4632
4632
4633 This finds all changes from the repository at the specified path
4633 This finds all changes from the repository at the specified path
4634 or URL and adds them to a local repository (the current one unless
4634 or URL and adds them to a local repository (the current one unless
4635 -R is specified). By default, this does not update the copy of the
4635 -R is specified). By default, this does not update the copy of the
4636 project in the working directory.
4636 project in the working directory.
4637
4637
4638 Use :hg:`incoming` if you want to see what would have been added
4638 Use :hg:`incoming` if you want to see what would have been added
4639 by a pull at the time you issued this command. If you then decide
4639 by a pull at the time you issued this command. If you then decide
4640 to add those changes to the repository, you should use :hg:`pull
4640 to add those changes to the repository, you should use :hg:`pull
4641 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4641 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4642
4642
4643 If SOURCE is omitted, the 'default' path will be used.
4643 If SOURCE is omitted, the 'default' path will be used.
4644 See :hg:`help urls` for more information.
4644 See :hg:`help urls` for more information.
4645
4645
4646 Returns 0 on success, 1 if an update had unresolved files.
4646 Returns 0 on success, 1 if an update had unresolved files.
4647 """
4647 """
4648 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4648 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4649 other = hg.peer(repo, opts, source)
4649 other = hg.peer(repo, opts, source)
4650 try:
4650 try:
4651 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4651 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4652 revs, checkout = hg.addbranchrevs(repo, other, branches,
4652 revs, checkout = hg.addbranchrevs(repo, other, branches,
4653 opts.get('rev'))
4653 opts.get('rev'))
4654
4654
4655 remotebookmarks = other.listkeys('bookmarks')
4655 remotebookmarks = other.listkeys('bookmarks')
4656
4656
4657 if opts.get('bookmark'):
4657 if opts.get('bookmark'):
4658 if not revs:
4658 if not revs:
4659 revs = []
4659 revs = []
4660 for b in opts['bookmark']:
4660 for b in opts['bookmark']:
4661 if b not in remotebookmarks:
4661 if b not in remotebookmarks:
4662 raise util.Abort(_('remote bookmark %s not found!') % b)
4662 raise util.Abort(_('remote bookmark %s not found!') % b)
4663 revs.append(remotebookmarks[b])
4663 revs.append(remotebookmarks[b])
4664
4664
4665 if revs:
4665 if revs:
4666 try:
4666 try:
4667 revs = [other.lookup(rev) for rev in revs]
4667 revs = [other.lookup(rev) for rev in revs]
4668 except error.CapabilityError:
4668 except error.CapabilityError:
4669 err = _("other repository doesn't support revision lookup, "
4669 err = _("other repository doesn't support revision lookup, "
4670 "so a rev cannot be specified.")
4670 "so a rev cannot be specified.")
4671 raise util.Abort(err)
4671 raise util.Abort(err)
4672
4672
4673 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4673 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4674 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4674 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4675 if checkout:
4675 if checkout:
4676 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4676 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4677 repo._subtoppath = source
4677 repo._subtoppath = source
4678 try:
4678 try:
4679 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4679 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4680
4680
4681 finally:
4681 finally:
4682 del repo._subtoppath
4682 del repo._subtoppath
4683
4683
4684 # update specified bookmarks
4684 # update specified bookmarks
4685 if opts.get('bookmark'):
4685 if opts.get('bookmark'):
4686 marks = repo._bookmarks
4686 marks = repo._bookmarks
4687 for b in opts['bookmark']:
4687 for b in opts['bookmark']:
4688 # explicit pull overrides local bookmark if any
4688 # explicit pull overrides local bookmark if any
4689 ui.status(_("importing bookmark %s\n") % b)
4689 ui.status(_("importing bookmark %s\n") % b)
4690 marks[b] = repo[remotebookmarks[b]].node()
4690 marks[b] = repo[remotebookmarks[b]].node()
4691 marks.write()
4691 marks.write()
4692 finally:
4692 finally:
4693 other.close()
4693 other.close()
4694 return ret
4694 return ret
4695
4695
4696 @command('^push',
4696 @command('^push',
4697 [('f', 'force', None, _('force push')),
4697 [('f', 'force', None, _('force push')),
4698 ('r', 'rev', [],
4698 ('r', 'rev', [],
4699 _('a changeset intended to be included in the destination'),
4699 _('a changeset intended to be included in the destination'),
4700 _('REV')),
4700 _('REV')),
4701 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4701 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4702 ('b', 'branch', [],
4702 ('b', 'branch', [],
4703 _('a specific branch you would like to push'), _('BRANCH')),
4703 _('a specific branch you would like to push'), _('BRANCH')),
4704 ('', 'new-branch', False, _('allow pushing a new branch')),
4704 ('', 'new-branch', False, _('allow pushing a new branch')),
4705 ] + remoteopts,
4705 ] + remoteopts,
4706 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4706 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4707 def push(ui, repo, dest=None, **opts):
4707 def push(ui, repo, dest=None, **opts):
4708 """push changes to the specified destination
4708 """push changes to the specified destination
4709
4709
4710 Push changesets from the local repository to the specified
4710 Push changesets from the local repository to the specified
4711 destination.
4711 destination.
4712
4712
4713 This operation is symmetrical to pull: it is identical to a pull
4713 This operation is symmetrical to pull: it is identical to a pull
4714 in the destination repository from the current one.
4714 in the destination repository from the current one.
4715
4715
4716 By default, push will not allow creation of new heads at the
4716 By default, push will not allow creation of new heads at the
4717 destination, since multiple heads would make it unclear which head
4717 destination, since multiple heads would make it unclear which head
4718 to use. In this situation, it is recommended to pull and merge
4718 to use. In this situation, it is recommended to pull and merge
4719 before pushing.
4719 before pushing.
4720
4720
4721 Use --new-branch if you want to allow push to create a new named
4721 Use --new-branch if you want to allow push to create a new named
4722 branch that is not present at the destination. This allows you to
4722 branch that is not present at the destination. This allows you to
4723 only create a new branch without forcing other changes.
4723 only create a new branch without forcing other changes.
4724
4724
4725 .. note::
4725 .. note::
4726
4726
4727 Extra care should be taken with the -f/--force option,
4727 Extra care should be taken with the -f/--force option,
4728 which will push all new heads on all branches, an action which will
4728 which will push all new heads on all branches, an action which will
4729 almost always cause confusion for collaborators.
4729 almost always cause confusion for collaborators.
4730
4730
4731 If -r/--rev is used, the specified revision and all its ancestors
4731 If -r/--rev is used, the specified revision and all its ancestors
4732 will be pushed to the remote repository.
4732 will be pushed to the remote repository.
4733
4733
4734 If -B/--bookmark is used, the specified bookmarked revision, its
4734 If -B/--bookmark is used, the specified bookmarked revision, its
4735 ancestors, and the bookmark will be pushed to the remote
4735 ancestors, and the bookmark will be pushed to the remote
4736 repository.
4736 repository.
4737
4737
4738 Please see :hg:`help urls` for important details about ``ssh://``
4738 Please see :hg:`help urls` for important details about ``ssh://``
4739 URLs. If DESTINATION is omitted, a default path will be used.
4739 URLs. If DESTINATION is omitted, a default path will be used.
4740
4740
4741 Returns 0 if push was successful, 1 if nothing to push.
4741 Returns 0 if push was successful, 1 if nothing to push.
4742 """
4742 """
4743
4743
4744 if opts.get('bookmark'):
4744 if opts.get('bookmark'):
4745 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4745 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4746 for b in opts['bookmark']:
4746 for b in opts['bookmark']:
4747 # translate -B options to -r so changesets get pushed
4747 # translate -B options to -r so changesets get pushed
4748 if b in repo._bookmarks:
4748 if b in repo._bookmarks:
4749 opts.setdefault('rev', []).append(b)
4749 opts.setdefault('rev', []).append(b)
4750 else:
4750 else:
4751 # if we try to push a deleted bookmark, translate it to null
4751 # if we try to push a deleted bookmark, translate it to null
4752 # this lets simultaneous -r, -b options continue working
4752 # this lets simultaneous -r, -b options continue working
4753 opts.setdefault('rev', []).append("null")
4753 opts.setdefault('rev', []).append("null")
4754
4754
4755 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4755 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4756 dest, branches = hg.parseurl(dest, opts.get('branch'))
4756 dest, branches = hg.parseurl(dest, opts.get('branch'))
4757 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4757 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4758 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4758 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4759 try:
4759 try:
4760 other = hg.peer(repo, opts, dest)
4760 other = hg.peer(repo, opts, dest)
4761 except error.RepoError:
4761 except error.RepoError:
4762 if dest == "default-push":
4762 if dest == "default-push":
4763 raise util.Abort(_("default repository not configured!"),
4763 raise util.Abort(_("default repository not configured!"),
4764 hint=_('see the "path" section in "hg help config"'))
4764 hint=_('see the "path" section in "hg help config"'))
4765 else:
4765 else:
4766 raise
4766 raise
4767
4767
4768 if revs:
4768 if revs:
4769 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4769 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4770
4770
4771 repo._subtoppath = dest
4771 repo._subtoppath = dest
4772 try:
4772 try:
4773 # push subrepos depth-first for coherent ordering
4773 # push subrepos depth-first for coherent ordering
4774 c = repo['']
4774 c = repo['']
4775 subs = c.substate # only repos that are committed
4775 subs = c.substate # only repos that are committed
4776 for s in sorted(subs):
4776 for s in sorted(subs):
4777 if c.sub(s).push(opts) == 0:
4777 if c.sub(s).push(opts) == 0:
4778 return False
4778 return False
4779 finally:
4779 finally:
4780 del repo._subtoppath
4780 del repo._subtoppath
4781 result = repo.push(other, opts.get('force'), revs=revs,
4781 result = repo.push(other, opts.get('force'), revs=revs,
4782 newbranch=opts.get('new_branch'))
4782 newbranch=opts.get('new_branch'))
4783
4783
4784 result = not result
4784 result = not result
4785
4785
4786 if opts.get('bookmark'):
4786 if opts.get('bookmark'):
4787 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4787 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4788 if bresult == 2:
4788 if bresult == 2:
4789 return 2
4789 return 2
4790 if not result and bresult:
4790 if not result and bresult:
4791 result = 2
4791 result = 2
4792
4792
4793 return result
4793 return result
4794
4794
4795 @command('recover', [])
4795 @command('recover', [])
4796 def recover(ui, repo):
4796 def recover(ui, repo):
4797 """roll back an interrupted transaction
4797 """roll back an interrupted transaction
4798
4798
4799 Recover from an interrupted commit or pull.
4799 Recover from an interrupted commit or pull.
4800
4800
4801 This command tries to fix the repository status after an
4801 This command tries to fix the repository status after an
4802 interrupted operation. It should only be necessary when Mercurial
4802 interrupted operation. It should only be necessary when Mercurial
4803 suggests it.
4803 suggests it.
4804
4804
4805 Returns 0 if successful, 1 if nothing to recover or verify fails.
4805 Returns 0 if successful, 1 if nothing to recover or verify fails.
4806 """
4806 """
4807 if repo.recover():
4807 if repo.recover():
4808 return hg.verify(repo)
4808 return hg.verify(repo)
4809 return 1
4809 return 1
4810
4810
4811 @command('^remove|rm',
4811 @command('^remove|rm',
4812 [('A', 'after', None, _('record delete for missing files')),
4812 [('A', 'after', None, _('record delete for missing files')),
4813 ('f', 'force', None,
4813 ('f', 'force', None,
4814 _('remove (and delete) file even if added or modified')),
4814 _('remove (and delete) file even if added or modified')),
4815 ] + walkopts,
4815 ] + walkopts,
4816 _('[OPTION]... FILE...'))
4816 _('[OPTION]... FILE...'))
4817 def remove(ui, repo, *pats, **opts):
4817 def remove(ui, repo, *pats, **opts):
4818 """remove the specified files on the next commit
4818 """remove the specified files on the next commit
4819
4819
4820 Schedule the indicated files for removal from the current branch.
4820 Schedule the indicated files for removal from the current branch.
4821
4821
4822 This command schedules the files to be removed at the next commit.
4822 This command schedules the files to be removed at the next commit.
4823 To undo a remove before that, see :hg:`revert`. To undo added
4823 To undo a remove before that, see :hg:`revert`. To undo added
4824 files, see :hg:`forget`.
4824 files, see :hg:`forget`.
4825
4825
4826 .. container:: verbose
4826 .. container:: verbose
4827
4827
4828 -A/--after can be used to remove only files that have already
4828 -A/--after can be used to remove only files that have already
4829 been deleted, -f/--force can be used to force deletion, and -Af
4829 been deleted, -f/--force can be used to force deletion, and -Af
4830 can be used to remove files from the next revision without
4830 can be used to remove files from the next revision without
4831 deleting them from the working directory.
4831 deleting them from the working directory.
4832
4832
4833 The following table details the behavior of remove for different
4833 The following table details the behavior of remove for different
4834 file states (columns) and option combinations (rows). The file
4834 file states (columns) and option combinations (rows). The file
4835 states are Added [A], Clean [C], Modified [M] and Missing [!]
4835 states are Added [A], Clean [C], Modified [M] and Missing [!]
4836 (as reported by :hg:`status`). The actions are Warn, Remove
4836 (as reported by :hg:`status`). The actions are Warn, Remove
4837 (from branch) and Delete (from disk):
4837 (from branch) and Delete (from disk):
4838
4838
4839 ========= == == == ==
4839 ========= == == == ==
4840 opt/state A C M !
4840 opt/state A C M !
4841 ========= == == == ==
4841 ========= == == == ==
4842 none W RD W R
4842 none W RD W R
4843 -f R RD RD R
4843 -f R RD RD R
4844 -A W W W R
4844 -A W W W R
4845 -Af R R R R
4845 -Af R R R R
4846 ========= == == == ==
4846 ========= == == == ==
4847
4847
4848 Note that remove never deletes files in Added [A] state from the
4848 Note that remove never deletes files in Added [A] state from the
4849 working directory, not even if option --force is specified.
4849 working directory, not even if option --force is specified.
4850
4850
4851 Returns 0 on success, 1 if any warnings encountered.
4851 Returns 0 on success, 1 if any warnings encountered.
4852 """
4852 """
4853
4853
4854 ret = 0
4854 ret = 0
4855 after, force = opts.get('after'), opts.get('force')
4855 after, force = opts.get('after'), opts.get('force')
4856 if not pats and not after:
4856 if not pats and not after:
4857 raise util.Abort(_('no files specified'))
4857 raise util.Abort(_('no files specified'))
4858
4858
4859 m = scmutil.match(repo[None], pats, opts)
4859 m = scmutil.match(repo[None], pats, opts)
4860 s = repo.status(match=m, clean=True)
4860 s = repo.status(match=m, clean=True)
4861 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4861 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4862
4862
4863 # warn about failure to delete explicit files/dirs
4863 # warn about failure to delete explicit files/dirs
4864 wctx = repo[None]
4864 wctx = repo[None]
4865 for f in m.files():
4865 for f in m.files():
4866 if f in repo.dirstate or f in wctx.dirs():
4866 if f in repo.dirstate or f in wctx.dirs():
4867 continue
4867 continue
4868 if os.path.exists(m.rel(f)):
4868 if os.path.exists(m.rel(f)):
4869 if os.path.isdir(m.rel(f)):
4869 if os.path.isdir(m.rel(f)):
4870 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4870 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4871 else:
4871 else:
4872 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4872 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4873 # missing files will generate a warning elsewhere
4873 # missing files will generate a warning elsewhere
4874 ret = 1
4874 ret = 1
4875
4875
4876 if force:
4876 if force:
4877 list = modified + deleted + clean + added
4877 list = modified + deleted + clean + added
4878 elif after:
4878 elif after:
4879 list = deleted
4879 list = deleted
4880 for f in modified + added + clean:
4880 for f in modified + added + clean:
4881 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4881 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4882 ret = 1
4882 ret = 1
4883 else:
4883 else:
4884 list = deleted + clean
4884 list = deleted + clean
4885 for f in modified:
4885 for f in modified:
4886 ui.warn(_('not removing %s: file is modified (use -f'
4886 ui.warn(_('not removing %s: file is modified (use -f'
4887 ' to force removal)\n') % m.rel(f))
4887 ' to force removal)\n') % m.rel(f))
4888 ret = 1
4888 ret = 1
4889 for f in added:
4889 for f in added:
4890 ui.warn(_('not removing %s: file has been marked for add'
4890 ui.warn(_('not removing %s: file has been marked for add'
4891 ' (use forget to undo)\n') % m.rel(f))
4891 ' (use forget to undo)\n') % m.rel(f))
4892 ret = 1
4892 ret = 1
4893
4893
4894 for f in sorted(list):
4894 for f in sorted(list):
4895 if ui.verbose or not m.exact(f):
4895 if ui.verbose or not m.exact(f):
4896 ui.status(_('removing %s\n') % m.rel(f))
4896 ui.status(_('removing %s\n') % m.rel(f))
4897
4897
4898 wlock = repo.wlock()
4898 wlock = repo.wlock()
4899 try:
4899 try:
4900 if not after:
4900 if not after:
4901 for f in list:
4901 for f in list:
4902 if f in added:
4902 if f in added:
4903 continue # we never unlink added files on remove
4903 continue # we never unlink added files on remove
4904 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4904 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4905 repo[None].forget(list)
4905 repo[None].forget(list)
4906 finally:
4906 finally:
4907 wlock.release()
4907 wlock.release()
4908
4908
4909 return ret
4909 return ret
4910
4910
4911 @command('rename|move|mv',
4911 @command('rename|move|mv',
4912 [('A', 'after', None, _('record a rename that has already occurred')),
4912 [('A', 'after', None, _('record a rename that has already occurred')),
4913 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4913 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4914 ] + walkopts + dryrunopts,
4914 ] + walkopts + dryrunopts,
4915 _('[OPTION]... SOURCE... DEST'))
4915 _('[OPTION]... SOURCE... DEST'))
4916 def rename(ui, repo, *pats, **opts):
4916 def rename(ui, repo, *pats, **opts):
4917 """rename files; equivalent of copy + remove
4917 """rename files; equivalent of copy + remove
4918
4918
4919 Mark dest as copies of sources; mark sources for deletion. If dest
4919 Mark dest as copies of sources; mark sources for deletion. If dest
4920 is a directory, copies are put in that directory. If dest is a
4920 is a directory, copies are put in that directory. If dest is a
4921 file, there can only be one source.
4921 file, there can only be one source.
4922
4922
4923 By default, this command copies the contents of files as they
4923 By default, this command copies the contents of files as they
4924 exist in the working directory. If invoked with -A/--after, the
4924 exist in the working directory. If invoked with -A/--after, the
4925 operation is recorded, but no copying is performed.
4925 operation is recorded, but no copying is performed.
4926
4926
4927 This command takes effect at the next commit. To undo a rename
4927 This command takes effect at the next commit. To undo a rename
4928 before that, see :hg:`revert`.
4928 before that, see :hg:`revert`.
4929
4929
4930 Returns 0 on success, 1 if errors are encountered.
4930 Returns 0 on success, 1 if errors are encountered.
4931 """
4931 """
4932 wlock = repo.wlock(False)
4932 wlock = repo.wlock(False)
4933 try:
4933 try:
4934 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4934 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4935 finally:
4935 finally:
4936 wlock.release()
4936 wlock.release()
4937
4937
4938 @command('resolve',
4938 @command('resolve',
4939 [('a', 'all', None, _('select all unresolved files')),
4939 [('a', 'all', None, _('select all unresolved files')),
4940 ('l', 'list', None, _('list state of files needing merge')),
4940 ('l', 'list', None, _('list state of files needing merge')),
4941 ('m', 'mark', None, _('mark files as resolved')),
4941 ('m', 'mark', None, _('mark files as resolved')),
4942 ('u', 'unmark', None, _('mark files as unresolved')),
4942 ('u', 'unmark', None, _('mark files as unresolved')),
4943 ('n', 'no-status', None, _('hide status prefix'))]
4943 ('n', 'no-status', None, _('hide status prefix'))]
4944 + mergetoolopts + walkopts,
4944 + mergetoolopts + walkopts,
4945 _('[OPTION]... [FILE]...'))
4945 _('[OPTION]... [FILE]...'))
4946 def resolve(ui, repo, *pats, **opts):
4946 def resolve(ui, repo, *pats, **opts):
4947 """redo merges or set/view the merge status of files
4947 """redo merges or set/view the merge status of files
4948
4948
4949 Merges with unresolved conflicts are often the result of
4949 Merges with unresolved conflicts are often the result of
4950 non-interactive merging using the ``internal:merge`` configuration
4950 non-interactive merging using the ``internal:merge`` configuration
4951 setting, or a command-line merge tool like ``diff3``. The resolve
4951 setting, or a command-line merge tool like ``diff3``. The resolve
4952 command is used to manage the files involved in a merge, after
4952 command is used to manage the files involved in a merge, after
4953 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4953 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4954 working directory must have two parents). See :hg:`help
4954 working directory must have two parents). See :hg:`help
4955 merge-tools` for information on configuring merge tools.
4955 merge-tools` for information on configuring merge tools.
4956
4956
4957 The resolve command can be used in the following ways:
4957 The resolve command can be used in the following ways:
4958
4958
4959 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4959 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4960 files, discarding any previous merge attempts. Re-merging is not
4960 files, discarding any previous merge attempts. Re-merging is not
4961 performed for files already marked as resolved. Use ``--all/-a``
4961 performed for files already marked as resolved. Use ``--all/-a``
4962 to select all unresolved files. ``--tool`` can be used to specify
4962 to select all unresolved files. ``--tool`` can be used to specify
4963 the merge tool used for the given files. It overrides the HGMERGE
4963 the merge tool used for the given files. It overrides the HGMERGE
4964 environment variable and your configuration files. Previous file
4964 environment variable and your configuration files. Previous file
4965 contents are saved with a ``.orig`` suffix.
4965 contents are saved with a ``.orig`` suffix.
4966
4966
4967 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4967 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4968 (e.g. after having manually fixed-up the files). The default is
4968 (e.g. after having manually fixed-up the files). The default is
4969 to mark all unresolved files.
4969 to mark all unresolved files.
4970
4970
4971 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4971 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4972 default is to mark all resolved files.
4972 default is to mark all resolved files.
4973
4973
4974 - :hg:`resolve -l`: list files which had or still have conflicts.
4974 - :hg:`resolve -l`: list files which had or still have conflicts.
4975 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4975 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4976
4976
4977 Note that Mercurial will not let you commit files with unresolved
4977 Note that Mercurial will not let you commit files with unresolved
4978 merge conflicts. You must use :hg:`resolve -m ...` before you can
4978 merge conflicts. You must use :hg:`resolve -m ...` before you can
4979 commit after a conflicting merge.
4979 commit after a conflicting merge.
4980
4980
4981 Returns 0 on success, 1 if any files fail a resolve attempt.
4981 Returns 0 on success, 1 if any files fail a resolve attempt.
4982 """
4982 """
4983
4983
4984 all, mark, unmark, show, nostatus = \
4984 all, mark, unmark, show, nostatus = \
4985 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4985 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4986
4986
4987 if (show and (mark or unmark)) or (mark and unmark):
4987 if (show and (mark or unmark)) or (mark and unmark):
4988 raise util.Abort(_("too many options specified"))
4988 raise util.Abort(_("too many options specified"))
4989 if pats and all:
4989 if pats and all:
4990 raise util.Abort(_("can't specify --all and patterns"))
4990 raise util.Abort(_("can't specify --all and patterns"))
4991 if not (all or pats or show or mark or unmark):
4991 if not (all or pats or show or mark or unmark):
4992 raise util.Abort(_('no files or directories specified; '
4992 raise util.Abort(_('no files or directories specified; '
4993 'use --all to remerge all files'))
4993 'use --all to remerge all files'))
4994
4994
4995 ms = mergemod.mergestate(repo)
4995 ms = mergemod.mergestate(repo)
4996 m = scmutil.match(repo[None], pats, opts)
4996 m = scmutil.match(repo[None], pats, opts)
4997 ret = 0
4997 ret = 0
4998
4998
4999 for f in ms:
4999 for f in ms:
5000 if m(f):
5000 if m(f):
5001 if show:
5001 if show:
5002 if nostatus:
5002 if nostatus:
5003 ui.write("%s\n" % f)
5003 ui.write("%s\n" % f)
5004 else:
5004 else:
5005 ui.write("%s %s\n" % (ms[f].upper(), f),
5005 ui.write("%s %s\n" % (ms[f].upper(), f),
5006 label='resolve.' +
5006 label='resolve.' +
5007 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5007 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5008 elif mark:
5008 elif mark:
5009 ms.mark(f, "r")
5009 ms.mark(f, "r")
5010 elif unmark:
5010 elif unmark:
5011 ms.mark(f, "u")
5011 ms.mark(f, "u")
5012 else:
5012 else:
5013 wctx = repo[None]
5013 wctx = repo[None]
5014
5014
5015 # backup pre-resolve (merge uses .orig for its own purposes)
5015 # backup pre-resolve (merge uses .orig for its own purposes)
5016 a = repo.wjoin(f)
5016 a = repo.wjoin(f)
5017 util.copyfile(a, a + ".resolve")
5017 util.copyfile(a, a + ".resolve")
5018
5018
5019 try:
5019 try:
5020 # resolve file
5020 # resolve file
5021 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5021 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5022 'resolve')
5022 'resolve')
5023 if ms.resolve(f, wctx):
5023 if ms.resolve(f, wctx):
5024 ret = 1
5024 ret = 1
5025 finally:
5025 finally:
5026 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5026 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5027 ms.commit()
5027 ms.commit()
5028
5028
5029 # replace filemerge's .orig file with our resolve file
5029 # replace filemerge's .orig file with our resolve file
5030 util.rename(a + ".resolve", a + ".orig")
5030 util.rename(a + ".resolve", a + ".orig")
5031
5031
5032 ms.commit()
5032 ms.commit()
5033 return ret
5033 return ret
5034
5034
5035 @command('revert',
5035 @command('revert',
5036 [('a', 'all', None, _('revert all changes when no arguments given')),
5036 [('a', 'all', None, _('revert all changes when no arguments given')),
5037 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5037 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5038 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5038 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5039 ('C', 'no-backup', None, _('do not save backup copies of files')),
5039 ('C', 'no-backup', None, _('do not save backup copies of files')),
5040 ] + walkopts + dryrunopts,
5040 ] + walkopts + dryrunopts,
5041 _('[OPTION]... [-r REV] [NAME]...'))
5041 _('[OPTION]... [-r REV] [NAME]...'))
5042 def revert(ui, repo, *pats, **opts):
5042 def revert(ui, repo, *pats, **opts):
5043 """restore files to their checkout state
5043 """restore files to their checkout state
5044
5044
5045 .. note::
5045 .. note::
5046
5046
5047 To check out earlier revisions, you should use :hg:`update REV`.
5047 To check out earlier revisions, you should use :hg:`update REV`.
5048 To cancel an uncommitted merge (and lose your changes),
5048 To cancel an uncommitted merge (and lose your changes),
5049 use :hg:`update --clean .`.
5049 use :hg:`update --clean .`.
5050
5050
5051 With no revision specified, revert the specified files or directories
5051 With no revision specified, revert the specified files or directories
5052 to the contents they had in the parent of the working directory.
5052 to the contents they had in the parent of the working directory.
5053 This restores the contents of files to an unmodified
5053 This restores the contents of files to an unmodified
5054 state and unschedules adds, removes, copies, and renames. If the
5054 state and unschedules adds, removes, copies, and renames. If the
5055 working directory has two parents, you must explicitly specify a
5055 working directory has two parents, you must explicitly specify a
5056 revision.
5056 revision.
5057
5057
5058 Using the -r/--rev or -d/--date options, revert the given files or
5058 Using the -r/--rev or -d/--date options, revert the given files or
5059 directories to their states as of a specific revision. Because
5059 directories to their states as of a specific revision. Because
5060 revert does not change the working directory parents, this will
5060 revert does not change the working directory parents, this will
5061 cause these files to appear modified. This can be helpful to "back
5061 cause these files to appear modified. This can be helpful to "back
5062 out" some or all of an earlier change. See :hg:`backout` for a
5062 out" some or all of an earlier change. See :hg:`backout` for a
5063 related method.
5063 related method.
5064
5064
5065 Modified files are saved with a .orig suffix before reverting.
5065 Modified files are saved with a .orig suffix before reverting.
5066 To disable these backups, use --no-backup.
5066 To disable these backups, use --no-backup.
5067
5067
5068 See :hg:`help dates` for a list of formats valid for -d/--date.
5068 See :hg:`help dates` for a list of formats valid for -d/--date.
5069
5069
5070 Returns 0 on success.
5070 Returns 0 on success.
5071 """
5071 """
5072
5072
5073 if opts.get("date"):
5073 if opts.get("date"):
5074 if opts.get("rev"):
5074 if opts.get("rev"):
5075 raise util.Abort(_("you can't specify a revision and a date"))
5075 raise util.Abort(_("you can't specify a revision and a date"))
5076 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5076 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5077
5077
5078 parent, p2 = repo.dirstate.parents()
5078 parent, p2 = repo.dirstate.parents()
5079 if not opts.get('rev') and p2 != nullid:
5079 if not opts.get('rev') and p2 != nullid:
5080 # revert after merge is a trap for new users (issue2915)
5080 # revert after merge is a trap for new users (issue2915)
5081 raise util.Abort(_('uncommitted merge with no revision specified'),
5081 raise util.Abort(_('uncommitted merge with no revision specified'),
5082 hint=_('use "hg update" or see "hg help revert"'))
5082 hint=_('use "hg update" or see "hg help revert"'))
5083
5083
5084 ctx = scmutil.revsingle(repo, opts.get('rev'))
5084 ctx = scmutil.revsingle(repo, opts.get('rev'))
5085
5085
5086 if not pats and not opts.get('all'):
5086 if not pats and not opts.get('all'):
5087 msg = _("no files or directories specified")
5087 msg = _("no files or directories specified")
5088 if p2 != nullid:
5088 if p2 != nullid:
5089 hint = _("uncommitted merge, use --all to discard all changes,"
5089 hint = _("uncommitted merge, use --all to discard all changes,"
5090 " or 'hg update -C .' to abort the merge")
5090 " or 'hg update -C .' to abort the merge")
5091 raise util.Abort(msg, hint=hint)
5091 raise util.Abort(msg, hint=hint)
5092 dirty = util.any(repo.status())
5092 dirty = util.any(repo.status())
5093 node = ctx.node()
5093 node = ctx.node()
5094 if node != parent:
5094 if node != parent:
5095 if dirty:
5095 if dirty:
5096 hint = _("uncommitted changes, use --all to discard all"
5096 hint = _("uncommitted changes, use --all to discard all"
5097 " changes, or 'hg update %s' to update") % ctx.rev()
5097 " changes, or 'hg update %s' to update") % ctx.rev()
5098 else:
5098 else:
5099 hint = _("use --all to revert all files,"
5099 hint = _("use --all to revert all files,"
5100 " or 'hg update %s' to update") % ctx.rev()
5100 " or 'hg update %s' to update") % ctx.rev()
5101 elif dirty:
5101 elif dirty:
5102 hint = _("uncommitted changes, use --all to discard all changes")
5102 hint = _("uncommitted changes, use --all to discard all changes")
5103 else:
5103 else:
5104 hint = _("use --all to revert all files")
5104 hint = _("use --all to revert all files")
5105 raise util.Abort(msg, hint=hint)
5105 raise util.Abort(msg, hint=hint)
5106
5106
5107 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5107 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5108
5108
5109 @command('rollback', dryrunopts +
5109 @command('rollback', dryrunopts +
5110 [('f', 'force', False, _('ignore safety measures'))])
5110 [('f', 'force', False, _('ignore safety measures'))])
5111 def rollback(ui, repo, **opts):
5111 def rollback(ui, repo, **opts):
5112 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5112 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5113
5113
5114 Please use :hg:`commit --amend` instead of rollback to correct
5114 Please use :hg:`commit --amend` instead of rollback to correct
5115 mistakes in the last commit.
5115 mistakes in the last commit.
5116
5116
5117 This command should be used with care. There is only one level of
5117 This command should be used with care. There is only one level of
5118 rollback, and there is no way to undo a rollback. It will also
5118 rollback, and there is no way to undo a rollback. It will also
5119 restore the dirstate at the time of the last transaction, losing
5119 restore the dirstate at the time of the last transaction, losing
5120 any dirstate changes since that time. This command does not alter
5120 any dirstate changes since that time. This command does not alter
5121 the working directory.
5121 the working directory.
5122
5122
5123 Transactions are used to encapsulate the effects of all commands
5123 Transactions are used to encapsulate the effects of all commands
5124 that create new changesets or propagate existing changesets into a
5124 that create new changesets or propagate existing changesets into a
5125 repository.
5125 repository.
5126
5126
5127 .. container:: verbose
5127 .. container:: verbose
5128
5128
5129 For example, the following commands are transactional, and their
5129 For example, the following commands are transactional, and their
5130 effects can be rolled back:
5130 effects can be rolled back:
5131
5131
5132 - commit
5132 - commit
5133 - import
5133 - import
5134 - pull
5134 - pull
5135 - push (with this repository as the destination)
5135 - push (with this repository as the destination)
5136 - unbundle
5136 - unbundle
5137
5137
5138 To avoid permanent data loss, rollback will refuse to rollback a
5138 To avoid permanent data loss, rollback will refuse to rollback a
5139 commit transaction if it isn't checked out. Use --force to
5139 commit transaction if it isn't checked out. Use --force to
5140 override this protection.
5140 override this protection.
5141
5141
5142 This command is not intended for use on public repositories. Once
5142 This command is not intended for use on public repositories. Once
5143 changes are visible for pull by other users, rolling a transaction
5143 changes are visible for pull by other users, rolling a transaction
5144 back locally is ineffective (someone else may already have pulled
5144 back locally is ineffective (someone else may already have pulled
5145 the changes). Furthermore, a race is possible with readers of the
5145 the changes). Furthermore, a race is possible with readers of the
5146 repository; for example an in-progress pull from the repository
5146 repository; for example an in-progress pull from the repository
5147 may fail if a rollback is performed.
5147 may fail if a rollback is performed.
5148
5148
5149 Returns 0 on success, 1 if no rollback data is available.
5149 Returns 0 on success, 1 if no rollback data is available.
5150 """
5150 """
5151 return repo.rollback(dryrun=opts.get('dry_run'),
5151 return repo.rollback(dryrun=opts.get('dry_run'),
5152 force=opts.get('force'))
5152 force=opts.get('force'))
5153
5153
5154 @command('root', [])
5154 @command('root', [])
5155 def root(ui, repo):
5155 def root(ui, repo):
5156 """print the root (top) of the current working directory
5156 """print the root (top) of the current working directory
5157
5157
5158 Print the root directory of the current repository.
5158 Print the root directory of the current repository.
5159
5159
5160 Returns 0 on success.
5160 Returns 0 on success.
5161 """
5161 """
5162 ui.write(repo.root + "\n")
5162 ui.write(repo.root + "\n")
5163
5163
5164 @command('^serve',
5164 @command('^serve',
5165 [('A', 'accesslog', '', _('name of access log file to write to'),
5165 [('A', 'accesslog', '', _('name of access log file to write to'),
5166 _('FILE')),
5166 _('FILE')),
5167 ('d', 'daemon', None, _('run server in background')),
5167 ('d', 'daemon', None, _('run server in background')),
5168 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5168 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5169 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5169 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5170 # use string type, then we can check if something was passed
5170 # use string type, then we can check if something was passed
5171 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5171 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5172 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5172 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5173 _('ADDR')),
5173 _('ADDR')),
5174 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5174 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5175 _('PREFIX')),
5175 _('PREFIX')),
5176 ('n', 'name', '',
5176 ('n', 'name', '',
5177 _('name to show in web pages (default: working directory)'), _('NAME')),
5177 _('name to show in web pages (default: working directory)'), _('NAME')),
5178 ('', 'web-conf', '',
5178 ('', 'web-conf', '',
5179 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5179 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5180 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5180 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5181 _('FILE')),
5181 _('FILE')),
5182 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5182 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5183 ('', 'stdio', None, _('for remote clients')),
5183 ('', 'stdio', None, _('for remote clients')),
5184 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5184 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5185 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5185 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5186 ('', 'style', '', _('template style to use'), _('STYLE')),
5186 ('', 'style', '', _('template style to use'), _('STYLE')),
5187 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5187 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5188 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5188 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5189 _('[OPTION]...'))
5189 _('[OPTION]...'))
5190 def serve(ui, repo, **opts):
5190 def serve(ui, repo, **opts):
5191 """start stand-alone webserver
5191 """start stand-alone webserver
5192
5192
5193 Start a local HTTP repository browser and pull server. You can use
5193 Start a local HTTP repository browser and pull server. You can use
5194 this for ad-hoc sharing and browsing of repositories. It is
5194 this for ad-hoc sharing and browsing of repositories. It is
5195 recommended to use a real web server to serve a repository for
5195 recommended to use a real web server to serve a repository for
5196 longer periods of time.
5196 longer periods of time.
5197
5197
5198 Please note that the server does not implement access control.
5198 Please note that the server does not implement access control.
5199 This means that, by default, anybody can read from the server and
5199 This means that, by default, anybody can read from the server and
5200 nobody can write to it by default. Set the ``web.allow_push``
5200 nobody can write to it by default. Set the ``web.allow_push``
5201 option to ``*`` to allow everybody to push to the server. You
5201 option to ``*`` to allow everybody to push to the server. You
5202 should use a real web server if you need to authenticate users.
5202 should use a real web server if you need to authenticate users.
5203
5203
5204 By default, the server logs accesses to stdout and errors to
5204 By default, the server logs accesses to stdout and errors to
5205 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5205 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5206 files.
5206 files.
5207
5207
5208 To have the server choose a free port number to listen on, specify
5208 To have the server choose a free port number to listen on, specify
5209 a port number of 0; in this case, the server will print the port
5209 a port number of 0; in this case, the server will print the port
5210 number it uses.
5210 number it uses.
5211
5211
5212 Returns 0 on success.
5212 Returns 0 on success.
5213 """
5213 """
5214
5214
5215 if opts["stdio"] and opts["cmdserver"]:
5215 if opts["stdio"] and opts["cmdserver"]:
5216 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5216 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5217
5217
5218 def checkrepo():
5218 def checkrepo():
5219 if repo is None:
5219 if repo is None:
5220 raise error.RepoError(_("there is no Mercurial repository here"
5220 raise error.RepoError(_("there is no Mercurial repository here"
5221 " (.hg not found)"))
5221 " (.hg not found)"))
5222
5222
5223 if opts["stdio"]:
5223 if opts["stdio"]:
5224 checkrepo()
5224 checkrepo()
5225 s = sshserver.sshserver(ui, repo)
5225 s = sshserver.sshserver(ui, repo)
5226 s.serve_forever()
5226 s.serve_forever()
5227
5227
5228 if opts["cmdserver"]:
5228 if opts["cmdserver"]:
5229 s = commandserver.server(ui, repo, opts["cmdserver"])
5229 s = commandserver.server(ui, repo, opts["cmdserver"])
5230 return s.serve()
5230 return s.serve()
5231
5231
5232 # this way we can check if something was given in the command-line
5232 # this way we can check if something was given in the command-line
5233 if opts.get('port'):
5233 if opts.get('port'):
5234 opts['port'] = util.getport(opts.get('port'))
5234 opts['port'] = util.getport(opts.get('port'))
5235
5235
5236 baseui = repo and repo.baseui or ui
5236 baseui = repo and repo.baseui or ui
5237 optlist = ("name templates style address port prefix ipv6"
5237 optlist = ("name templates style address port prefix ipv6"
5238 " accesslog errorlog certificate encoding")
5238 " accesslog errorlog certificate encoding")
5239 for o in optlist.split():
5239 for o in optlist.split():
5240 val = opts.get(o, '')
5240 val = opts.get(o, '')
5241 if val in (None, ''): # should check against default options instead
5241 if val in (None, ''): # should check against default options instead
5242 continue
5242 continue
5243 baseui.setconfig("web", o, val, 'serve')
5243 baseui.setconfig("web", o, val, 'serve')
5244 if repo and repo.ui != baseui:
5244 if repo and repo.ui != baseui:
5245 repo.ui.setconfig("web", o, val, 'serve')
5245 repo.ui.setconfig("web", o, val, 'serve')
5246
5246
5247 o = opts.get('web_conf') or opts.get('webdir_conf')
5247 o = opts.get('web_conf') or opts.get('webdir_conf')
5248 if not o:
5248 if not o:
5249 if not repo:
5249 if not repo:
5250 raise error.RepoError(_("there is no Mercurial repository"
5250 raise error.RepoError(_("there is no Mercurial repository"
5251 " here (.hg not found)"))
5251 " here (.hg not found)"))
5252 o = repo
5252 o = repo
5253
5253
5254 app = hgweb.hgweb(o, baseui=baseui)
5254 app = hgweb.hgweb(o, baseui=baseui)
5255 service = httpservice(ui, app, opts)
5255 service = httpservice(ui, app, opts)
5256 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5256 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5257
5257
5258 class httpservice(object):
5258 class httpservice(object):
5259 def __init__(self, ui, app, opts):
5259 def __init__(self, ui, app, opts):
5260 self.ui = ui
5260 self.ui = ui
5261 self.app = app
5261 self.app = app
5262 self.opts = opts
5262 self.opts = opts
5263
5263
5264 def init(self):
5264 def init(self):
5265 util.setsignalhandler()
5265 util.setsignalhandler()
5266 self.httpd = hgweb_server.create_server(self.ui, self.app)
5266 self.httpd = hgweb_server.create_server(self.ui, self.app)
5267
5267
5268 if self.opts['port'] and not self.ui.verbose:
5268 if self.opts['port'] and not self.ui.verbose:
5269 return
5269 return
5270
5270
5271 if self.httpd.prefix:
5271 if self.httpd.prefix:
5272 prefix = self.httpd.prefix.strip('/') + '/'
5272 prefix = self.httpd.prefix.strip('/') + '/'
5273 else:
5273 else:
5274 prefix = ''
5274 prefix = ''
5275
5275
5276 port = ':%d' % self.httpd.port
5276 port = ':%d' % self.httpd.port
5277 if port == ':80':
5277 if port == ':80':
5278 port = ''
5278 port = ''
5279
5279
5280 bindaddr = self.httpd.addr
5280 bindaddr = self.httpd.addr
5281 if bindaddr == '0.0.0.0':
5281 if bindaddr == '0.0.0.0':
5282 bindaddr = '*'
5282 bindaddr = '*'
5283 elif ':' in bindaddr: # IPv6
5283 elif ':' in bindaddr: # IPv6
5284 bindaddr = '[%s]' % bindaddr
5284 bindaddr = '[%s]' % bindaddr
5285
5285
5286 fqaddr = self.httpd.fqaddr
5286 fqaddr = self.httpd.fqaddr
5287 if ':' in fqaddr:
5287 if ':' in fqaddr:
5288 fqaddr = '[%s]' % fqaddr
5288 fqaddr = '[%s]' % fqaddr
5289 if self.opts['port']:
5289 if self.opts['port']:
5290 write = self.ui.status
5290 write = self.ui.status
5291 else:
5291 else:
5292 write = self.ui.write
5292 write = self.ui.write
5293 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5293 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5294 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5294 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5295
5295
5296 def run(self):
5296 def run(self):
5297 self.httpd.serve_forever()
5297 self.httpd.serve_forever()
5298
5298
5299
5299
5300 @command('^status|st',
5300 @command('^status|st',
5301 [('A', 'all', None, _('show status of all files')),
5301 [('A', 'all', None, _('show status of all files')),
5302 ('m', 'modified', None, _('show only modified files')),
5302 ('m', 'modified', None, _('show only modified files')),
5303 ('a', 'added', None, _('show only added files')),
5303 ('a', 'added', None, _('show only added files')),
5304 ('r', 'removed', None, _('show only removed files')),
5304 ('r', 'removed', None, _('show only removed files')),
5305 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5305 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5306 ('c', 'clean', None, _('show only files without changes')),
5306 ('c', 'clean', None, _('show only files without changes')),
5307 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5307 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5308 ('i', 'ignored', None, _('show only ignored files')),
5308 ('i', 'ignored', None, _('show only ignored files')),
5309 ('n', 'no-status', None, _('hide status prefix')),
5309 ('n', 'no-status', None, _('hide status prefix')),
5310 ('C', 'copies', None, _('show source of copied files')),
5310 ('C', 'copies', None, _('show source of copied files')),
5311 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5311 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5312 ('', 'rev', [], _('show difference from revision'), _('REV')),
5312 ('', 'rev', [], _('show difference from revision'), _('REV')),
5313 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5313 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5314 ] + walkopts + subrepoopts,
5314 ] + walkopts + subrepoopts,
5315 _('[OPTION]... [FILE]...'))
5315 _('[OPTION]... [FILE]...'))
5316 def status(ui, repo, *pats, **opts):
5316 def status(ui, repo, *pats, **opts):
5317 """show changed files in the working directory
5317 """show changed files in the working directory
5318
5318
5319 Show status of files in the repository. If names are given, only
5319 Show status of files in the repository. If names are given, only
5320 files that match are shown. Files that are clean or ignored or
5320 files that match are shown. Files that are clean or ignored or
5321 the source of a copy/move operation, are not listed unless
5321 the source of a copy/move operation, are not listed unless
5322 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5322 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5323 Unless options described with "show only ..." are given, the
5323 Unless options described with "show only ..." are given, the
5324 options -mardu are used.
5324 options -mardu are used.
5325
5325
5326 Option -q/--quiet hides untracked (unknown and ignored) files
5326 Option -q/--quiet hides untracked (unknown and ignored) files
5327 unless explicitly requested with -u/--unknown or -i/--ignored.
5327 unless explicitly requested with -u/--unknown or -i/--ignored.
5328
5328
5329 .. note::
5329 .. note::
5330
5330
5331 status may appear to disagree with diff if permissions have
5331 status may appear to disagree with diff if permissions have
5332 changed or a merge has occurred. The standard diff format does
5332 changed or a merge has occurred. The standard diff format does
5333 not report permission changes and diff only reports changes
5333 not report permission changes and diff only reports changes
5334 relative to one merge parent.
5334 relative to one merge parent.
5335
5335
5336 If one revision is given, it is used as the base revision.
5336 If one revision is given, it is used as the base revision.
5337 If two revisions are given, the differences between them are
5337 If two revisions are given, the differences between them are
5338 shown. The --change option can also be used as a shortcut to list
5338 shown. The --change option can also be used as a shortcut to list
5339 the changed files of a revision from its first parent.
5339 the changed files of a revision from its first parent.
5340
5340
5341 The codes used to show the status of files are::
5341 The codes used to show the status of files are::
5342
5342
5343 M = modified
5343 M = modified
5344 A = added
5344 A = added
5345 R = removed
5345 R = removed
5346 C = clean
5346 C = clean
5347 ! = missing (deleted by non-hg command, but still tracked)
5347 ! = missing (deleted by non-hg command, but still tracked)
5348 ? = not tracked
5348 ? = not tracked
5349 I = ignored
5349 I = ignored
5350 = origin of the previous file (with --copies)
5350 = origin of the previous file (with --copies)
5351
5351
5352 .. container:: verbose
5352 .. container:: verbose
5353
5353
5354 Examples:
5354 Examples:
5355
5355
5356 - show changes in the working directory relative to a
5356 - show changes in the working directory relative to a
5357 changeset::
5357 changeset::
5358
5358
5359 hg status --rev 9353
5359 hg status --rev 9353
5360
5360
5361 - show all changes including copies in an existing changeset::
5361 - show all changes including copies in an existing changeset::
5362
5362
5363 hg status --copies --change 9353
5363 hg status --copies --change 9353
5364
5364
5365 - get a NUL separated list of added files, suitable for xargs::
5365 - get a NUL separated list of added files, suitable for xargs::
5366
5366
5367 hg status -an0
5367 hg status -an0
5368
5368
5369 Returns 0 on success.
5369 Returns 0 on success.
5370 """
5370 """
5371
5371
5372 revs = opts.get('rev')
5372 revs = opts.get('rev')
5373 change = opts.get('change')
5373 change = opts.get('change')
5374
5374
5375 if revs and change:
5375 if revs and change:
5376 msg = _('cannot specify --rev and --change at the same time')
5376 msg = _('cannot specify --rev and --change at the same time')
5377 raise util.Abort(msg)
5377 raise util.Abort(msg)
5378 elif change:
5378 elif change:
5379 node2 = scmutil.revsingle(repo, change, None).node()
5379 node2 = scmutil.revsingle(repo, change, None).node()
5380 node1 = repo[node2].p1().node()
5380 node1 = repo[node2].p1().node()
5381 else:
5381 else:
5382 node1, node2 = scmutil.revpair(repo, revs)
5382 node1, node2 = scmutil.revpair(repo, revs)
5383
5383
5384 cwd = (pats and repo.getcwd()) or ''
5384 cwd = (pats and repo.getcwd()) or ''
5385 end = opts.get('print0') and '\0' or '\n'
5385 end = opts.get('print0') and '\0' or '\n'
5386 copy = {}
5386 copy = {}
5387 states = 'modified added removed deleted unknown ignored clean'.split()
5387 states = 'modified added removed deleted unknown ignored clean'.split()
5388 show = [k for k in states if opts.get(k)]
5388 show = [k for k in states if opts.get(k)]
5389 if opts.get('all'):
5389 if opts.get('all'):
5390 show += ui.quiet and (states[:4] + ['clean']) or states
5390 show += ui.quiet and (states[:4] + ['clean']) or states
5391 if not show:
5391 if not show:
5392 show = ui.quiet and states[:4] or states[:5]
5392 show = ui.quiet and states[:4] or states[:5]
5393
5393
5394 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5394 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5395 'ignored' in show, 'clean' in show, 'unknown' in show,
5395 'ignored' in show, 'clean' in show, 'unknown' in show,
5396 opts.get('subrepos'))
5396 opts.get('subrepos'))
5397 changestates = zip(states, 'MAR!?IC', stat)
5397 changestates = zip(states, 'MAR!?IC', stat)
5398
5398
5399 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5399 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5400 copy = copies.pathcopies(repo[node1], repo[node2])
5400 copy = copies.pathcopies(repo[node1], repo[node2])
5401
5401
5402 fm = ui.formatter('status', opts)
5402 fm = ui.formatter('status', opts)
5403 fmt = '%s' + end
5403 fmt = '%s' + end
5404 showchar = not opts.get('no_status')
5404 showchar = not opts.get('no_status')
5405
5405
5406 for state, char, files in changestates:
5406 for state, char, files in changestates:
5407 if state in show:
5407 if state in show:
5408 label = 'status.' + state
5408 label = 'status.' + state
5409 for f in files:
5409 for f in files:
5410 fm.startitem()
5410 fm.startitem()
5411 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5411 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5412 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5412 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5413 if f in copy:
5413 if f in copy:
5414 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5414 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5415 label='status.copied')
5415 label='status.copied')
5416 fm.end()
5416 fm.end()
5417
5417
5418 @command('^summary|sum',
5418 @command('^summary|sum',
5419 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5419 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5420 def summary(ui, repo, **opts):
5420 def summary(ui, repo, **opts):
5421 """summarize working directory state
5421 """summarize working directory state
5422
5422
5423 This generates a brief summary of the working directory state,
5423 This generates a brief summary of the working directory state,
5424 including parents, branch, commit status, and available updates.
5424 including parents, branch, commit status, and available updates.
5425
5425
5426 With the --remote option, this will check the default paths for
5426 With the --remote option, this will check the default paths for
5427 incoming and outgoing changes. This can be time-consuming.
5427 incoming and outgoing changes. This can be time-consuming.
5428
5428
5429 Returns 0 on success.
5429 Returns 0 on success.
5430 """
5430 """
5431
5431
5432 ctx = repo[None]
5432 ctx = repo[None]
5433 parents = ctx.parents()
5433 parents = ctx.parents()
5434 pnode = parents[0].node()
5434 pnode = parents[0].node()
5435 marks = []
5435 marks = []
5436
5436
5437 for p in parents:
5437 for p in parents:
5438 # label with log.changeset (instead of log.parent) since this
5438 # label with log.changeset (instead of log.parent) since this
5439 # shows a working directory parent *changeset*:
5439 # shows a working directory parent *changeset*:
5440 # i18n: column positioning for "hg summary"
5440 # i18n: column positioning for "hg summary"
5441 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5441 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5442 label='log.changeset changeset.%s' % p.phasestr())
5442 label='log.changeset changeset.%s' % p.phasestr())
5443 ui.write(' '.join(p.tags()), label='log.tag')
5443 ui.write(' '.join(p.tags()), label='log.tag')
5444 if p.bookmarks():
5444 if p.bookmarks():
5445 marks.extend(p.bookmarks())
5445 marks.extend(p.bookmarks())
5446 if p.rev() == -1:
5446 if p.rev() == -1:
5447 if not len(repo):
5447 if not len(repo):
5448 ui.write(_(' (empty repository)'))
5448 ui.write(_(' (empty repository)'))
5449 else:
5449 else:
5450 ui.write(_(' (no revision checked out)'))
5450 ui.write(_(' (no revision checked out)'))
5451 ui.write('\n')
5451 ui.write('\n')
5452 if p.description():
5452 if p.description():
5453 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5453 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5454 label='log.summary')
5454 label='log.summary')
5455
5455
5456 branch = ctx.branch()
5456 branch = ctx.branch()
5457 bheads = repo.branchheads(branch)
5457 bheads = repo.branchheads(branch)
5458 # i18n: column positioning for "hg summary"
5458 # i18n: column positioning for "hg summary"
5459 m = _('branch: %s\n') % branch
5459 m = _('branch: %s\n') % branch
5460 if branch != 'default':
5460 if branch != 'default':
5461 ui.write(m, label='log.branch')
5461 ui.write(m, label='log.branch')
5462 else:
5462 else:
5463 ui.status(m, label='log.branch')
5463 ui.status(m, label='log.branch')
5464
5464
5465 if marks:
5465 if marks:
5466 current = repo._bookmarkcurrent
5466 current = repo._bookmarkcurrent
5467 # i18n: column positioning for "hg summary"
5467 # i18n: column positioning for "hg summary"
5468 ui.write(_('bookmarks:'), label='log.bookmark')
5468 ui.write(_('bookmarks:'), label='log.bookmark')
5469 if current is not None:
5469 if current is not None:
5470 if current in marks:
5470 if current in marks:
5471 ui.write(' *' + current, label='bookmarks.current')
5471 ui.write(' *' + current, label='bookmarks.current')
5472 marks.remove(current)
5472 marks.remove(current)
5473 else:
5473 else:
5474 ui.write(' [%s]' % current, label='bookmarks.current')
5474 ui.write(' [%s]' % current, label='bookmarks.current')
5475 for m in marks:
5475 for m in marks:
5476 ui.write(' ' + m, label='log.bookmark')
5476 ui.write(' ' + m, label='log.bookmark')
5477 ui.write('\n', label='log.bookmark')
5477 ui.write('\n', label='log.bookmark')
5478
5478
5479 st = list(repo.status(unknown=True))[:6]
5479 st = list(repo.status(unknown=True))[:6]
5480
5480
5481 c = repo.dirstate.copies()
5481 c = repo.dirstate.copies()
5482 copied, renamed = [], []
5482 copied, renamed = [], []
5483 for d, s in c.iteritems():
5483 for d, s in c.iteritems():
5484 if s in st[2]:
5484 if s in st[2]:
5485 st[2].remove(s)
5485 st[2].remove(s)
5486 renamed.append(d)
5486 renamed.append(d)
5487 else:
5487 else:
5488 copied.append(d)
5488 copied.append(d)
5489 if d in st[1]:
5489 if d in st[1]:
5490 st[1].remove(d)
5490 st[1].remove(d)
5491 st.insert(3, renamed)
5491 st.insert(3, renamed)
5492 st.insert(4, copied)
5492 st.insert(4, copied)
5493
5493
5494 ms = mergemod.mergestate(repo)
5494 ms = mergemod.mergestate(repo)
5495 st.append([f for f in ms if ms[f] == 'u'])
5495 st.append([f for f in ms if ms[f] == 'u'])
5496
5496
5497 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5497 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5498 st.append(subs)
5498 st.append(subs)
5499
5499
5500 labels = [ui.label(_('%d modified'), 'status.modified'),
5500 labels = [ui.label(_('%d modified'), 'status.modified'),
5501 ui.label(_('%d added'), 'status.added'),
5501 ui.label(_('%d added'), 'status.added'),
5502 ui.label(_('%d removed'), 'status.removed'),
5502 ui.label(_('%d removed'), 'status.removed'),
5503 ui.label(_('%d renamed'), 'status.copied'),
5503 ui.label(_('%d renamed'), 'status.copied'),
5504 ui.label(_('%d copied'), 'status.copied'),
5504 ui.label(_('%d copied'), 'status.copied'),
5505 ui.label(_('%d deleted'), 'status.deleted'),
5505 ui.label(_('%d deleted'), 'status.deleted'),
5506 ui.label(_('%d unknown'), 'status.unknown'),
5506 ui.label(_('%d unknown'), 'status.unknown'),
5507 ui.label(_('%d ignored'), 'status.ignored'),
5507 ui.label(_('%d ignored'), 'status.ignored'),
5508 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5508 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5509 ui.label(_('%d subrepos'), 'status.modified')]
5509 ui.label(_('%d subrepos'), 'status.modified')]
5510 t = []
5510 t = []
5511 for s, l in zip(st, labels):
5511 for s, l in zip(st, labels):
5512 if s:
5512 if s:
5513 t.append(l % len(s))
5513 t.append(l % len(s))
5514
5514
5515 t = ', '.join(t)
5515 t = ', '.join(t)
5516 cleanworkdir = False
5516 cleanworkdir = False
5517
5517
5518 if repo.vfs.exists('updatestate'):
5518 if repo.vfs.exists('updatestate'):
5519 t += _(' (interrupted update)')
5519 t += _(' (interrupted update)')
5520 elif len(parents) > 1:
5520 elif len(parents) > 1:
5521 t += _(' (merge)')
5521 t += _(' (merge)')
5522 elif branch != parents[0].branch():
5522 elif branch != parents[0].branch():
5523 t += _(' (new branch)')
5523 t += _(' (new branch)')
5524 elif (parents[0].closesbranch() and
5524 elif (parents[0].closesbranch() and
5525 pnode in repo.branchheads(branch, closed=True)):
5525 pnode in repo.branchheads(branch, closed=True)):
5526 t += _(' (head closed)')
5526 t += _(' (head closed)')
5527 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5527 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5528 t += _(' (clean)')
5528 t += _(' (clean)')
5529 cleanworkdir = True
5529 cleanworkdir = True
5530 elif pnode not in bheads:
5530 elif pnode not in bheads:
5531 t += _(' (new branch head)')
5531 t += _(' (new branch head)')
5532
5532
5533 if cleanworkdir:
5533 if cleanworkdir:
5534 # i18n: column positioning for "hg summary"
5534 # i18n: column positioning for "hg summary"
5535 ui.status(_('commit: %s\n') % t.strip())
5535 ui.status(_('commit: %s\n') % t.strip())
5536 else:
5536 else:
5537 # i18n: column positioning for "hg summary"
5537 # i18n: column positioning for "hg summary"
5538 ui.write(_('commit: %s\n') % t.strip())
5538 ui.write(_('commit: %s\n') % t.strip())
5539
5539
5540 # all ancestors of branch heads - all ancestors of parent = new csets
5540 # all ancestors of branch heads - all ancestors of parent = new csets
5541 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5541 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5542 bheads))
5542 bheads))
5543
5543
5544 if new == 0:
5544 if new == 0:
5545 # i18n: column positioning for "hg summary"
5545 # i18n: column positioning for "hg summary"
5546 ui.status(_('update: (current)\n'))
5546 ui.status(_('update: (current)\n'))
5547 elif pnode not in bheads:
5547 elif pnode not in bheads:
5548 # i18n: column positioning for "hg summary"
5548 # i18n: column positioning for "hg summary"
5549 ui.write(_('update: %d new changesets (update)\n') % new)
5549 ui.write(_('update: %d new changesets (update)\n') % new)
5550 else:
5550 else:
5551 # i18n: column positioning for "hg summary"
5551 # i18n: column positioning for "hg summary"
5552 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5552 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5553 (new, len(bheads)))
5553 (new, len(bheads)))
5554
5554
5555 cmdutil.summaryhooks(ui, repo)
5555 cmdutil.summaryhooks(ui, repo)
5556
5556
5557 if opts.get('remote'):
5557 if opts.get('remote'):
5558 t = []
5558 t = []
5559 source, branches = hg.parseurl(ui.expandpath('default'))
5559 source, branches = hg.parseurl(ui.expandpath('default'))
5560 sbranch = branches[0]
5560 sbranch = branches[0]
5561 other = hg.peer(repo, {}, source)
5561 other = hg.peer(repo, {}, source)
5562 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5562 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5563 if revs:
5563 if revs:
5564 revs = [other.lookup(rev) for rev in revs]
5564 revs = [other.lookup(rev) for rev in revs]
5565 ui.debug('comparing with %s\n' % util.hidepassword(source))
5565 ui.debug('comparing with %s\n' % util.hidepassword(source))
5566 repo.ui.pushbuffer()
5566 repo.ui.pushbuffer()
5567 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5567 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5568 _common, incoming, _rheads = commoninc
5568 _common, incoming, _rheads = commoninc
5569 repo.ui.popbuffer()
5569 repo.ui.popbuffer()
5570 if incoming:
5570 if incoming:
5571 t.append(_('1 or more incoming'))
5571 t.append(_('1 or more incoming'))
5572
5572
5573 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5573 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5574 dbranch = branches[0]
5574 dbranch = branches[0]
5575 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5575 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5576 if source != dest:
5576 if source != dest:
5577 other = hg.peer(repo, {}, dest)
5577 other = hg.peer(repo, {}, dest)
5578 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5578 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5579 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5579 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5580 commoninc = None
5580 commoninc = None
5581 if revs:
5581 if revs:
5582 revs = [repo.lookup(rev) for rev in revs]
5582 revs = [repo.lookup(rev) for rev in revs]
5583 repo.ui.pushbuffer()
5583 repo.ui.pushbuffer()
5584 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5584 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5585 commoninc=commoninc)
5585 commoninc=commoninc)
5586 repo.ui.popbuffer()
5586 repo.ui.popbuffer()
5587 o = outgoing.missing
5587 o = outgoing.missing
5588 if o:
5588 if o:
5589 t.append(_('%d outgoing') % len(o))
5589 t.append(_('%d outgoing') % len(o))
5590 if 'bookmarks' in other.listkeys('namespaces'):
5590 if 'bookmarks' in other.listkeys('namespaces'):
5591 lmarks = repo.listkeys('bookmarks')
5591 lmarks = repo.listkeys('bookmarks')
5592 rmarks = other.listkeys('bookmarks')
5592 rmarks = other.listkeys('bookmarks')
5593 diff = set(rmarks) - set(lmarks)
5593 diff = set(rmarks) - set(lmarks)
5594 if len(diff) > 0:
5594 if len(diff) > 0:
5595 t.append(_('%d incoming bookmarks') % len(diff))
5595 t.append(_('%d incoming bookmarks') % len(diff))
5596 diff = set(lmarks) - set(rmarks)
5596 diff = set(lmarks) - set(rmarks)
5597 if len(diff) > 0:
5597 if len(diff) > 0:
5598 t.append(_('%d outgoing bookmarks') % len(diff))
5598 t.append(_('%d outgoing bookmarks') % len(diff))
5599
5599
5600 if t:
5600 if t:
5601 # i18n: column positioning for "hg summary"
5601 # i18n: column positioning for "hg summary"
5602 ui.write(_('remote: %s\n') % (', '.join(t)))
5602 ui.write(_('remote: %s\n') % (', '.join(t)))
5603 else:
5603 else:
5604 # i18n: column positioning for "hg summary"
5604 # i18n: column positioning for "hg summary"
5605 ui.status(_('remote: (synced)\n'))
5605 ui.status(_('remote: (synced)\n'))
5606
5606
5607 @command('tag',
5607 @command('tag',
5608 [('f', 'force', None, _('force tag')),
5608 [('f', 'force', None, _('force tag')),
5609 ('l', 'local', None, _('make the tag local')),
5609 ('l', 'local', None, _('make the tag local')),
5610 ('r', 'rev', '', _('revision to tag'), _('REV')),
5610 ('r', 'rev', '', _('revision to tag'), _('REV')),
5611 ('', 'remove', None, _('remove a tag')),
5611 ('', 'remove', None, _('remove a tag')),
5612 # -l/--local is already there, commitopts cannot be used
5612 # -l/--local is already there, commitopts cannot be used
5613 ('e', 'edit', None, _('edit commit message')),
5613 ('e', 'edit', None, _('edit commit message')),
5614 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5614 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5615 ] + commitopts2,
5615 ] + commitopts2,
5616 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5616 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5617 def tag(ui, repo, name1, *names, **opts):
5617 def tag(ui, repo, name1, *names, **opts):
5618 """add one or more tags for the current or given revision
5618 """add one or more tags for the current or given revision
5619
5619
5620 Name a particular revision using <name>.
5620 Name a particular revision using <name>.
5621
5621
5622 Tags are used to name particular revisions of the repository and are
5622 Tags are used to name particular revisions of the repository and are
5623 very useful to compare different revisions, to go back to significant
5623 very useful to compare different revisions, to go back to significant
5624 earlier versions or to mark branch points as releases, etc. Changing
5624 earlier versions or to mark branch points as releases, etc. Changing
5625 an existing tag is normally disallowed; use -f/--force to override.
5625 an existing tag is normally disallowed; use -f/--force to override.
5626
5626
5627 If no revision is given, the parent of the working directory is
5627 If no revision is given, the parent of the working directory is
5628 used.
5628 used.
5629
5629
5630 To facilitate version control, distribution, and merging of tags,
5630 To facilitate version control, distribution, and merging of tags,
5631 they are stored as a file named ".hgtags" which is managed similarly
5631 they are stored as a file named ".hgtags" which is managed similarly
5632 to other project files and can be hand-edited if necessary. This
5632 to other project files and can be hand-edited if necessary. This
5633 also means that tagging creates a new commit. The file
5633 also means that tagging creates a new commit. The file
5634 ".hg/localtags" is used for local tags (not shared among
5634 ".hg/localtags" is used for local tags (not shared among
5635 repositories).
5635 repositories).
5636
5636
5637 Tag commits are usually made at the head of a branch. If the parent
5637 Tag commits are usually made at the head of a branch. If the parent
5638 of the working directory is not a branch head, :hg:`tag` aborts; use
5638 of the working directory is not a branch head, :hg:`tag` aborts; use
5639 -f/--force to force the tag commit to be based on a non-head
5639 -f/--force to force the tag commit to be based on a non-head
5640 changeset.
5640 changeset.
5641
5641
5642 See :hg:`help dates` for a list of formats valid for -d/--date.
5642 See :hg:`help dates` for a list of formats valid for -d/--date.
5643
5643
5644 Since tag names have priority over branch names during revision
5644 Since tag names have priority over branch names during revision
5645 lookup, using an existing branch name as a tag name is discouraged.
5645 lookup, using an existing branch name as a tag name is discouraged.
5646
5646
5647 Returns 0 on success.
5647 Returns 0 on success.
5648 """
5648 """
5649 wlock = lock = None
5649 wlock = lock = None
5650 try:
5650 try:
5651 wlock = repo.wlock()
5651 wlock = repo.wlock()
5652 lock = repo.lock()
5652 lock = repo.lock()
5653 rev_ = "."
5653 rev_ = "."
5654 names = [t.strip() for t in (name1,) + names]
5654 names = [t.strip() for t in (name1,) + names]
5655 if len(names) != len(set(names)):
5655 if len(names) != len(set(names)):
5656 raise util.Abort(_('tag names must be unique'))
5656 raise util.Abort(_('tag names must be unique'))
5657 for n in names:
5657 for n in names:
5658 scmutil.checknewlabel(repo, n, 'tag')
5658 scmutil.checknewlabel(repo, n, 'tag')
5659 if not n:
5659 if not n:
5660 raise util.Abort(_('tag names cannot consist entirely of '
5660 raise util.Abort(_('tag names cannot consist entirely of '
5661 'whitespace'))
5661 'whitespace'))
5662 if opts.get('rev') and opts.get('remove'):
5662 if opts.get('rev') and opts.get('remove'):
5663 raise util.Abort(_("--rev and --remove are incompatible"))
5663 raise util.Abort(_("--rev and --remove are incompatible"))
5664 if opts.get('rev'):
5664 if opts.get('rev'):
5665 rev_ = opts['rev']
5665 rev_ = opts['rev']
5666 message = opts.get('message')
5666 message = opts.get('message')
5667 if opts.get('remove'):
5667 if opts.get('remove'):
5668 expectedtype = opts.get('local') and 'local' or 'global'
5668 expectedtype = opts.get('local') and 'local' or 'global'
5669 for n in names:
5669 for n in names:
5670 if not repo.tagtype(n):
5670 if not repo.tagtype(n):
5671 raise util.Abort(_("tag '%s' does not exist") % n)
5671 raise util.Abort(_("tag '%s' does not exist") % n)
5672 if repo.tagtype(n) != expectedtype:
5672 if repo.tagtype(n) != expectedtype:
5673 if expectedtype == 'global':
5673 if expectedtype == 'global':
5674 raise util.Abort(_("tag '%s' is not a global tag") % n)
5674 raise util.Abort(_("tag '%s' is not a global tag") % n)
5675 else:
5675 else:
5676 raise util.Abort(_("tag '%s' is not a local tag") % n)
5676 raise util.Abort(_("tag '%s' is not a local tag") % n)
5677 rev_ = nullid
5677 rev_ = nullid
5678 if not message:
5678 if not message:
5679 # we don't translate commit messages
5679 # we don't translate commit messages
5680 message = 'Removed tag %s' % ', '.join(names)
5680 message = 'Removed tag %s' % ', '.join(names)
5681 elif not opts.get('force'):
5681 elif not opts.get('force'):
5682 for n in names:
5682 for n in names:
5683 if n in repo.tags():
5683 if n in repo.tags():
5684 raise util.Abort(_("tag '%s' already exists "
5684 raise util.Abort(_("tag '%s' already exists "
5685 "(use -f to force)") % n)
5685 "(use -f to force)") % n)
5686 if not opts.get('local'):
5686 if not opts.get('local'):
5687 p1, p2 = repo.dirstate.parents()
5687 p1, p2 = repo.dirstate.parents()
5688 if p2 != nullid:
5688 if p2 != nullid:
5689 raise util.Abort(_('uncommitted merge'))
5689 raise util.Abort(_('uncommitted merge'))
5690 bheads = repo.branchheads()
5690 bheads = repo.branchheads()
5691 if not opts.get('force') and bheads and p1 not in bheads:
5691 if not opts.get('force') and bheads and p1 not in bheads:
5692 raise util.Abort(_('not at a branch head (use -f to force)'))
5692 raise util.Abort(_('not at a branch head (use -f to force)'))
5693 r = scmutil.revsingle(repo, rev_).node()
5693 r = scmutil.revsingle(repo, rev_).node()
5694
5694
5695 if not message:
5695 if not message:
5696 # we don't translate commit messages
5696 # we don't translate commit messages
5697 message = ('Added tag %s for changeset %s' %
5697 message = ('Added tag %s for changeset %s' %
5698 (', '.join(names), short(r)))
5698 (', '.join(names), short(r)))
5699
5699
5700 date = opts.get('date')
5700 date = opts.get('date')
5701 if date:
5701 if date:
5702 date = util.parsedate(date)
5702 date = util.parsedate(date)
5703
5703
5704 if opts.get('edit'):
5704 if opts.get('edit'):
5705 message = ui.edit(message, ui.username())
5705 message = ui.edit(message, ui.username())
5706 repo.savecommitmessage(message)
5706 repo.savecommitmessage(message)
5707
5707
5708 # don't allow tagging the null rev
5708 # don't allow tagging the null rev
5709 if (not opts.get('remove') and
5709 if (not opts.get('remove') and
5710 scmutil.revsingle(repo, rev_).rev() == nullrev):
5710 scmutil.revsingle(repo, rev_).rev() == nullrev):
5711 raise util.Abort(_("cannot tag null revision"))
5711 raise util.Abort(_("cannot tag null revision"))
5712
5712
5713 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5713 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5714 finally:
5714 finally:
5715 release(lock, wlock)
5715 release(lock, wlock)
5716
5716
5717 @command('tags', [], '')
5717 @command('tags', [], '')
5718 def tags(ui, repo, **opts):
5718 def tags(ui, repo, **opts):
5719 """list repository tags
5719 """list repository tags
5720
5720
5721 This lists both regular and local tags. When the -v/--verbose
5721 This lists both regular and local tags. When the -v/--verbose
5722 switch is used, a third column "local" is printed for local tags.
5722 switch is used, a third column "local" is printed for local tags.
5723
5723
5724 Returns 0 on success.
5724 Returns 0 on success.
5725 """
5725 """
5726
5726
5727 fm = ui.formatter('tags', opts)
5727 fm = ui.formatter('tags', opts)
5728 hexfunc = ui.debugflag and hex or short
5728 hexfunc = ui.debugflag and hex or short
5729 tagtype = ""
5729 tagtype = ""
5730
5730
5731 for t, n in reversed(repo.tagslist()):
5731 for t, n in reversed(repo.tagslist()):
5732 hn = hexfunc(n)
5732 hn = hexfunc(n)
5733 label = 'tags.normal'
5733 label = 'tags.normal'
5734 tagtype = ''
5734 tagtype = ''
5735 if repo.tagtype(t) == 'local':
5735 if repo.tagtype(t) == 'local':
5736 label = 'tags.local'
5736 label = 'tags.local'
5737 tagtype = 'local'
5737 tagtype = 'local'
5738
5738
5739 fm.startitem()
5739 fm.startitem()
5740 fm.write('tag', '%s', t, label=label)
5740 fm.write('tag', '%s', t, label=label)
5741 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5741 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5742 fm.condwrite(not ui.quiet, 'rev id', fmt,
5742 fm.condwrite(not ui.quiet, 'rev id', fmt,
5743 repo.changelog.rev(n), hn, label=label)
5743 repo.changelog.rev(n), hn, label=label)
5744 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5744 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5745 tagtype, label=label)
5745 tagtype, label=label)
5746 fm.plain('\n')
5746 fm.plain('\n')
5747 fm.end()
5747 fm.end()
5748
5748
5749 @command('tip',
5749 @command('tip',
5750 [('p', 'patch', None, _('show patch')),
5750 [('p', 'patch', None, _('show patch')),
5751 ('g', 'git', None, _('use git extended diff format')),
5751 ('g', 'git', None, _('use git extended diff format')),
5752 ] + templateopts,
5752 ] + templateopts,
5753 _('[-p] [-g]'))
5753 _('[-p] [-g]'))
5754 def tip(ui, repo, **opts):
5754 def tip(ui, repo, **opts):
5755 """show the tip revision (DEPRECATED)
5755 """show the tip revision (DEPRECATED)
5756
5756
5757 The tip revision (usually just called the tip) is the changeset
5757 The tip revision (usually just called the tip) is the changeset
5758 most recently added to the repository (and therefore the most
5758 most recently added to the repository (and therefore the most
5759 recently changed head).
5759 recently changed head).
5760
5760
5761 If you have just made a commit, that commit will be the tip. If
5761 If you have just made a commit, that commit will be the tip. If
5762 you have just pulled changes from another repository, the tip of
5762 you have just pulled changes from another repository, the tip of
5763 that repository becomes the current tip. The "tip" tag is special
5763 that repository becomes the current tip. The "tip" tag is special
5764 and cannot be renamed or assigned to a different changeset.
5764 and cannot be renamed or assigned to a different changeset.
5765
5765
5766 This command is deprecated, please use :hg:`heads` instead.
5766 This command is deprecated, please use :hg:`heads` instead.
5767
5767
5768 Returns 0 on success.
5768 Returns 0 on success.
5769 """
5769 """
5770 displayer = cmdutil.show_changeset(ui, repo, opts)
5770 displayer = cmdutil.show_changeset(ui, repo, opts)
5771 displayer.show(repo['tip'])
5771 displayer.show(repo['tip'])
5772 displayer.close()
5772 displayer.close()
5773
5773
5774 @command('unbundle',
5774 @command('unbundle',
5775 [('u', 'update', None,
5775 [('u', 'update', None,
5776 _('update to new branch head if changesets were unbundled'))],
5776 _('update to new branch head if changesets were unbundled'))],
5777 _('[-u] FILE...'))
5777 _('[-u] FILE...'))
5778 def unbundle(ui, repo, fname1, *fnames, **opts):
5778 def unbundle(ui, repo, fname1, *fnames, **opts):
5779 """apply one or more changegroup files
5779 """apply one or more changegroup files
5780
5780
5781 Apply one or more compressed changegroup files generated by the
5781 Apply one or more compressed changegroup files generated by the
5782 bundle command.
5782 bundle command.
5783
5783
5784 Returns 0 on success, 1 if an update has unresolved files.
5784 Returns 0 on success, 1 if an update has unresolved files.
5785 """
5785 """
5786 fnames = (fname1,) + fnames
5786 fnames = (fname1,) + fnames
5787
5787
5788 lock = repo.lock()
5788 lock = repo.lock()
5789 wc = repo['.']
5789 wc = repo['.']
5790 try:
5790 try:
5791 for fname in fnames:
5791 for fname in fnames:
5792 f = hg.openpath(ui, fname)
5792 f = hg.openpath(ui, fname)
5793 gen = changegroup.readbundle(f, fname)
5793 gen = changegroup.readbundle(f, fname)
5794 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5794 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
5795 'bundle:' + fname)
5795 'bundle:' + fname)
5796 finally:
5796 finally:
5797 lock.release()
5797 lock.release()
5798 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5798 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5799 return postincoming(ui, repo, modheads, opts.get('update'), None)
5799 return postincoming(ui, repo, modheads, opts.get('update'), None)
5800
5800
5801 @command('^update|up|checkout|co',
5801 @command('^update|up|checkout|co',
5802 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5802 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5803 ('c', 'check', None,
5803 ('c', 'check', None,
5804 _('update across branches if no uncommitted changes')),
5804 _('update across branches if no uncommitted changes')),
5805 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5805 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5806 ('r', 'rev', '', _('revision'), _('REV'))],
5806 ('r', 'rev', '', _('revision'), _('REV'))],
5807 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5807 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5808 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5808 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5809 """update working directory (or switch revisions)
5809 """update working directory (or switch revisions)
5810
5810
5811 Update the repository's working directory to the specified
5811 Update the repository's working directory to the specified
5812 changeset. If no changeset is specified, update to the tip of the
5812 changeset. If no changeset is specified, update to the tip of the
5813 current named branch and move the current bookmark (see :hg:`help
5813 current named branch and move the current bookmark (see :hg:`help
5814 bookmarks`).
5814 bookmarks`).
5815
5815
5816 Update sets the working directory's parent revision to the specified
5816 Update sets the working directory's parent revision to the specified
5817 changeset (see :hg:`help parents`).
5817 changeset (see :hg:`help parents`).
5818
5818
5819 If the changeset is not a descendant or ancestor of the working
5819 If the changeset is not a descendant or ancestor of the working
5820 directory's parent, the update is aborted. With the -c/--check
5820 directory's parent, the update is aborted. With the -c/--check
5821 option, the working directory is checked for uncommitted changes; if
5821 option, the working directory is checked for uncommitted changes; if
5822 none are found, the working directory is updated to the specified
5822 none are found, the working directory is updated to the specified
5823 changeset.
5823 changeset.
5824
5824
5825 .. container:: verbose
5825 .. container:: verbose
5826
5826
5827 The following rules apply when the working directory contains
5827 The following rules apply when the working directory contains
5828 uncommitted changes:
5828 uncommitted changes:
5829
5829
5830 1. If neither -c/--check nor -C/--clean is specified, and if
5830 1. If neither -c/--check nor -C/--clean is specified, and if
5831 the requested changeset is an ancestor or descendant of
5831 the requested changeset is an ancestor or descendant of
5832 the working directory's parent, the uncommitted changes
5832 the working directory's parent, the uncommitted changes
5833 are merged into the requested changeset and the merged
5833 are merged into the requested changeset and the merged
5834 result is left uncommitted. If the requested changeset is
5834 result is left uncommitted. If the requested changeset is
5835 not an ancestor or descendant (that is, it is on another
5835 not an ancestor or descendant (that is, it is on another
5836 branch), the update is aborted and the uncommitted changes
5836 branch), the update is aborted and the uncommitted changes
5837 are preserved.
5837 are preserved.
5838
5838
5839 2. With the -c/--check option, the update is aborted and the
5839 2. With the -c/--check option, the update is aborted and the
5840 uncommitted changes are preserved.
5840 uncommitted changes are preserved.
5841
5841
5842 3. With the -C/--clean option, uncommitted changes are discarded and
5842 3. With the -C/--clean option, uncommitted changes are discarded and
5843 the working directory is updated to the requested changeset.
5843 the working directory is updated to the requested changeset.
5844
5844
5845 To cancel an uncommitted merge (and lose your changes), use
5845 To cancel an uncommitted merge (and lose your changes), use
5846 :hg:`update --clean .`.
5846 :hg:`update --clean .`.
5847
5847
5848 Use null as the changeset to remove the working directory (like
5848 Use null as the changeset to remove the working directory (like
5849 :hg:`clone -U`).
5849 :hg:`clone -U`).
5850
5850
5851 If you want to revert just one file to an older revision, use
5851 If you want to revert just one file to an older revision, use
5852 :hg:`revert [-r REV] NAME`.
5852 :hg:`revert [-r REV] NAME`.
5853
5853
5854 See :hg:`help dates` for a list of formats valid for -d/--date.
5854 See :hg:`help dates` for a list of formats valid for -d/--date.
5855
5855
5856 Returns 0 on success, 1 if there are unresolved files.
5856 Returns 0 on success, 1 if there are unresolved files.
5857 """
5857 """
5858 if rev and node:
5858 if rev and node:
5859 raise util.Abort(_("please specify just one revision"))
5859 raise util.Abort(_("please specify just one revision"))
5860
5860
5861 if rev is None or rev == '':
5861 if rev is None or rev == '':
5862 rev = node
5862 rev = node
5863
5863
5864 cmdutil.clearunfinished(repo)
5864 cmdutil.clearunfinished(repo)
5865
5865
5866 # with no argument, we also move the current bookmark, if any
5866 # with no argument, we also move the current bookmark, if any
5867 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5867 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5868
5868
5869 # if we defined a bookmark, we have to remember the original bookmark name
5869 # if we defined a bookmark, we have to remember the original bookmark name
5870 brev = rev
5870 brev = rev
5871 rev = scmutil.revsingle(repo, rev, rev).rev()
5871 rev = scmutil.revsingle(repo, rev, rev).rev()
5872
5872
5873 if check and clean:
5873 if check and clean:
5874 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5874 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5875
5875
5876 if date:
5876 if date:
5877 if rev is not None:
5877 if rev is not None:
5878 raise util.Abort(_("you can't specify a revision and a date"))
5878 raise util.Abort(_("you can't specify a revision and a date"))
5879 rev = cmdutil.finddate(ui, repo, date)
5879 rev = cmdutil.finddate(ui, repo, date)
5880
5880
5881 if check:
5881 if check:
5882 c = repo[None]
5882 c = repo[None]
5883 if c.dirty(merge=False, branch=False, missing=True):
5883 if c.dirty(merge=False, branch=False, missing=True):
5884 raise util.Abort(_("uncommitted changes"))
5884 raise util.Abort(_("uncommitted changes"))
5885 if rev is None:
5885 if rev is None:
5886 rev = repo[repo[None].branch()].rev()
5886 rev = repo[repo[None].branch()].rev()
5887 mergemod._checkunknown(repo, repo[None], repo[rev])
5887 mergemod._checkunknown(repo, repo[None], repo[rev])
5888
5888
5889 if clean:
5889 if clean:
5890 ret = hg.clean(repo, rev)
5890 ret = hg.clean(repo, rev)
5891 else:
5891 else:
5892 ret = hg.update(repo, rev)
5892 ret = hg.update(repo, rev)
5893
5893
5894 if not ret and movemarkfrom:
5894 if not ret and movemarkfrom:
5895 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5895 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5896 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5896 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5897 elif brev in repo._bookmarks:
5897 elif brev in repo._bookmarks:
5898 bookmarks.setcurrent(repo, brev)
5898 bookmarks.setcurrent(repo, brev)
5899 elif brev:
5899 elif brev:
5900 bookmarks.unsetcurrent(repo)
5900 bookmarks.unsetcurrent(repo)
5901
5901
5902 return ret
5902 return ret
5903
5903
5904 @command('verify', [])
5904 @command('verify', [])
5905 def verify(ui, repo):
5905 def verify(ui, repo):
5906 """verify the integrity of the repository
5906 """verify the integrity of the repository
5907
5907
5908 Verify the integrity of the current repository.
5908 Verify the integrity of the current repository.
5909
5909
5910 This will perform an extensive check of the repository's
5910 This will perform an extensive check of the repository's
5911 integrity, validating the hashes and checksums of each entry in
5911 integrity, validating the hashes and checksums of each entry in
5912 the changelog, manifest, and tracked files, as well as the
5912 the changelog, manifest, and tracked files, as well as the
5913 integrity of their crosslinks and indices.
5913 integrity of their crosslinks and indices.
5914
5914
5915 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5915 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5916 for more information about recovery from corruption of the
5916 for more information about recovery from corruption of the
5917 repository.
5917 repository.
5918
5918
5919 Returns 0 on success, 1 if errors are encountered.
5919 Returns 0 on success, 1 if errors are encountered.
5920 """
5920 """
5921 return hg.verify(repo)
5921 return hg.verify(repo)
5922
5922
5923 @command('version', [])
5923 @command('version', [])
5924 def version_(ui):
5924 def version_(ui):
5925 """output version and copyright information"""
5925 """output version and copyright information"""
5926 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5926 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5927 % util.version())
5927 % util.version())
5928 ui.status(_(
5928 ui.status(_(
5929 "(see http://mercurial.selenic.com for more information)\n"
5929 "(see http://mercurial.selenic.com for more information)\n"
5930 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5930 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5931 "This is free software; see the source for copying conditions. "
5931 "This is free software; see the source for copying conditions. "
5932 "There is NO\nwarranty; "
5932 "There is NO\nwarranty; "
5933 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5933 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5934 ))
5934 ))
5935
5935
5936 norepo = ("clone init version help debugcommands debugcomplete"
5936 norepo = ("clone init version help debugcommands debugcomplete"
5937 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5937 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5938 " debugknown debuggetbundle debugbundle")
5938 " debugknown debuggetbundle debugbundle")
5939 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
5939 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
5940 " debugdata debugindex debugindexdot debugrevlog")
5940 " debugdata debugindex debugindexdot debugrevlog")
5941 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5941 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5942 " remove resolve status debugwalk")
5942 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now