##// END OF EJS Templates
bookmarks: allow (re-)activating a bookmark on the current changeset...
Kevin Bullock -
r18781:99b78269 default
parent child Browse files
Show More
@@ -1,5736 +1,5739 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 hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 bheads = repo.branchheads(branch)
459 bheads = repo.branchheads(branch)
460 hg.clean(repo, node, show_stats=False)
460 hg.clean(repo, node, show_stats=False)
461 repo.dirstate.setbranch(branch)
461 repo.dirstate.setbranch(branch)
462 rctx = scmutil.revsingle(repo, hex(parent))
462 rctx = scmutil.revsingle(repo, hex(parent))
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
464 if not opts.get('merge') and op1 != node:
464 if not opts.get('merge') and op1 != node:
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.update(repo, op1)
467 return hg.update(repo, op1)
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470
470
471 e = cmdutil.commiteditor
471 e = cmdutil.commiteditor
472 if not opts['message'] and not opts['logfile']:
472 if not opts['message'] and not opts['logfile']:
473 # we don't translate commit messages
473 # we don't translate commit messages
474 opts['message'] = "Backed out changeset %s" % short(node)
474 opts['message'] = "Backed out changeset %s" % short(node)
475 e = cmdutil.commitforceeditor
475 e = cmdutil.commitforceeditor
476
476
477 def commitfunc(ui, repo, message, match, opts):
477 def commitfunc(ui, repo, message, match, opts):
478 return repo.commit(message, opts.get('user'), opts.get('date'),
478 return repo.commit(message, opts.get('user'), opts.get('date'),
479 match, editor=e)
479 match, editor=e)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
482
482
483 def nice(node):
483 def nice(node):
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
485 ui.status(_('changeset %s backs out changeset %s\n') %
485 ui.status(_('changeset %s backs out changeset %s\n') %
486 (nice(repo.changelog.tip()), nice(node)))
486 (nice(repo.changelog.tip()), nice(node)))
487 if opts.get('merge') and op1 != node:
487 if opts.get('merge') and op1 != node:
488 hg.clean(repo, op1, show_stats=False)
488 hg.clean(repo, op1, show_stats=False)
489 ui.status(_('merging with changeset %s\n')
489 ui.status(_('merging with changeset %s\n')
490 % nice(repo.changelog.tip()))
490 % nice(repo.changelog.tip()))
491 try:
491 try:
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
493 return hg.merge(repo, hex(repo.changelog.tip()))
493 return hg.merge(repo, hex(repo.changelog.tip()))
494 finally:
494 finally:
495 ui.setconfig('ui', 'forcemerge', '')
495 ui.setconfig('ui', 'forcemerge', '')
496 finally:
496 finally:
497 wlock.release()
497 wlock.release()
498 return 0
498 return 0
499
499
500 @command('bisect',
500 @command('bisect',
501 [('r', 'reset', False, _('reset bisect state')),
501 [('r', 'reset', False, _('reset bisect state')),
502 ('g', 'good', False, _('mark changeset good')),
502 ('g', 'good', False, _('mark changeset good')),
503 ('b', 'bad', False, _('mark changeset bad')),
503 ('b', 'bad', False, _('mark changeset bad')),
504 ('s', 'skip', False, _('skip testing changeset')),
504 ('s', 'skip', False, _('skip testing changeset')),
505 ('e', 'extend', False, _('extend the bisect range')),
505 ('e', 'extend', False, _('extend the bisect range')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
507 ('U', 'noupdate', False, _('do not update to target'))],
507 ('U', 'noupdate', False, _('do not update to target'))],
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
509 def bisect(ui, repo, rev=None, extra=None, command=None,
509 def bisect(ui, repo, rev=None, extra=None, command=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
511 noupdate=None):
511 noupdate=None):
512 """subdivision search of changesets
512 """subdivision search of changesets
513
513
514 This command helps to find changesets which introduce problems. To
514 This command helps to find changesets which introduce problems. To
515 use, mark the earliest changeset you know exhibits the problem as
515 use, mark the earliest changeset you know exhibits the problem as
516 bad, then mark the latest changeset which is free from the problem
516 bad, then mark the latest changeset which is free from the problem
517 as good. Bisect will update your working directory to a revision
517 as good. Bisect will update your working directory to a revision
518 for testing (unless the -U/--noupdate option is specified). Once
518 for testing (unless the -U/--noupdate option is specified). Once
519 you have performed tests, mark the working directory as good or
519 you have performed tests, mark the working directory as good or
520 bad, and bisect will either update to another candidate changeset
520 bad, and bisect will either update to another candidate changeset
521 or announce that it has found the bad revision.
521 or announce that it has found the bad revision.
522
522
523 As a shortcut, you can also use the revision argument to mark a
523 As a shortcut, you can also use the revision argument to mark a
524 revision as good or bad without checking it out first.
524 revision as good or bad without checking it out first.
525
525
526 If you supply a command, it will be used for automatic bisection.
526 If you supply a command, it will be used for automatic bisection.
527 The environment variable HG_NODE will contain the ID of the
527 The environment variable HG_NODE will contain the ID of the
528 changeset being tested. The exit status of the command will be
528 changeset being tested. The exit status of the command will be
529 used to mark revisions as good or bad: status 0 means good, 125
529 used to mark revisions as good or bad: status 0 means good, 125
530 means to skip the revision, 127 (command not found) will abort the
530 means to skip the revision, 127 (command not found) will abort the
531 bisection, and any other non-zero exit status means the revision
531 bisection, and any other non-zero exit status means the revision
532 is bad.
532 is bad.
533
533
534 .. container:: verbose
534 .. container:: verbose
535
535
536 Some examples:
536 Some examples:
537
537
538 - start a bisection with known bad revision 12, and good revision 34::
538 - start a bisection with known bad revision 12, and good revision 34::
539
539
540 hg bisect --bad 34
540 hg bisect --bad 34
541 hg bisect --good 12
541 hg bisect --good 12
542
542
543 - advance the current bisection by marking current revision as good or
543 - advance the current bisection by marking current revision as good or
544 bad::
544 bad::
545
545
546 hg bisect --good
546 hg bisect --good
547 hg bisect --bad
547 hg bisect --bad
548
548
549 - mark the current revision, or a known revision, to be skipped (e.g. if
549 - mark the current revision, or a known revision, to be skipped (e.g. if
550 that revision is not usable because of another issue)::
550 that revision is not usable because of another issue)::
551
551
552 hg bisect --skip
552 hg bisect --skip
553 hg bisect --skip 23
553 hg bisect --skip 23
554
554
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
556
556
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
558
558
559 - forget the current bisection::
559 - forget the current bisection::
560
560
561 hg bisect --reset
561 hg bisect --reset
562
562
563 - use 'make && make tests' to automatically find the first broken
563 - use 'make && make tests' to automatically find the first broken
564 revision::
564 revision::
565
565
566 hg bisect --reset
566 hg bisect --reset
567 hg bisect --bad 34
567 hg bisect --bad 34
568 hg bisect --good 12
568 hg bisect --good 12
569 hg bisect --command 'make && make tests'
569 hg bisect --command 'make && make tests'
570
570
571 - see all changesets whose states are already known in the current
571 - see all changesets whose states are already known in the current
572 bisection::
572 bisection::
573
573
574 hg log -r "bisect(pruned)"
574 hg log -r "bisect(pruned)"
575
575
576 - see the changeset currently being bisected (especially useful
576 - see the changeset currently being bisected (especially useful
577 if running with -U/--noupdate)::
577 if running with -U/--noupdate)::
578
578
579 hg log -r "bisect(current)"
579 hg log -r "bisect(current)"
580
580
581 - see all changesets that took part in the current bisection::
581 - see all changesets that took part in the current bisection::
582
582
583 hg log -r "bisect(range)"
583 hg log -r "bisect(range)"
584
584
585 - with the graphlog extension, you can even get a nice graph::
585 - with the graphlog extension, you can even get a nice graph::
586
586
587 hg log --graph -r "bisect(range)"
587 hg log --graph -r "bisect(range)"
588
588
589 See :hg:`help revsets` for more about the `bisect()` keyword.
589 See :hg:`help revsets` for more about the `bisect()` keyword.
590
590
591 Returns 0 on success.
591 Returns 0 on success.
592 """
592 """
593 def extendbisectrange(nodes, good):
593 def extendbisectrange(nodes, good):
594 # bisect is incomplete when it ends on a merge node and
594 # bisect is incomplete when it ends on a merge node and
595 # one of the parent was not checked.
595 # one of the parent was not checked.
596 parents = repo[nodes[0]].parents()
596 parents = repo[nodes[0]].parents()
597 if len(parents) > 1:
597 if len(parents) > 1:
598 side = good and state['bad'] or state['good']
598 side = good and state['bad'] or state['good']
599 num = len(set(i.node() for i in parents) & set(side))
599 num = len(set(i.node() for i in parents) & set(side))
600 if num == 1:
600 if num == 1:
601 return parents[0].ancestor(parents[1])
601 return parents[0].ancestor(parents[1])
602 return None
602 return None
603
603
604 def print_result(nodes, good):
604 def print_result(nodes, good):
605 displayer = cmdutil.show_changeset(ui, repo, {})
605 displayer = cmdutil.show_changeset(ui, repo, {})
606 if len(nodes) == 1:
606 if len(nodes) == 1:
607 # narrowed it down to a single revision
607 # narrowed it down to a single revision
608 if good:
608 if good:
609 ui.write(_("The first good revision is:\n"))
609 ui.write(_("The first good revision is:\n"))
610 else:
610 else:
611 ui.write(_("The first bad revision is:\n"))
611 ui.write(_("The first bad revision is:\n"))
612 displayer.show(repo[nodes[0]])
612 displayer.show(repo[nodes[0]])
613 extendnode = extendbisectrange(nodes, good)
613 extendnode = extendbisectrange(nodes, good)
614 if extendnode is not None:
614 if extendnode is not None:
615 ui.write(_('Not all ancestors of this changeset have been'
615 ui.write(_('Not all ancestors of this changeset have been'
616 ' checked.\nUse bisect --extend to continue the '
616 ' checked.\nUse bisect --extend to continue the '
617 'bisection from\nthe common ancestor, %s.\n')
617 'bisection from\nthe common ancestor, %s.\n')
618 % extendnode)
618 % extendnode)
619 else:
619 else:
620 # multiple possible revisions
620 # multiple possible revisions
621 if good:
621 if good:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "good revision could be any of:\n"))
623 "good revision could be any of:\n"))
624 else:
624 else:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "bad revision could be any of:\n"))
626 "bad revision could be any of:\n"))
627 for n in nodes:
627 for n in nodes:
628 displayer.show(repo[n])
628 displayer.show(repo[n])
629 displayer.close()
629 displayer.close()
630
630
631 def check_state(state, interactive=True):
631 def check_state(state, interactive=True):
632 if not state['good'] or not state['bad']:
632 if not state['good'] or not state['bad']:
633 if (good or bad or skip or reset) and interactive:
633 if (good or bad or skip or reset) and interactive:
634 return
634 return
635 if not state['good']:
635 if not state['good']:
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
637 else:
637 else:
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
639 return True
639 return True
640
640
641 # backward compatibility
641 # backward compatibility
642 if rev in "good bad reset init".split():
642 if rev in "good bad reset init".split():
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
644 cmd, rev, extra = rev, extra, None
644 cmd, rev, extra = rev, extra, None
645 if cmd == "good":
645 if cmd == "good":
646 good = True
646 good = True
647 elif cmd == "bad":
647 elif cmd == "bad":
648 bad = True
648 bad = True
649 else:
649 else:
650 reset = True
650 reset = True
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
652 raise util.Abort(_('incompatible arguments'))
652 raise util.Abort(_('incompatible arguments'))
653
653
654 if reset:
654 if reset:
655 p = repo.join("bisect.state")
655 p = repo.join("bisect.state")
656 if os.path.exists(p):
656 if os.path.exists(p):
657 os.unlink(p)
657 os.unlink(p)
658 return
658 return
659
659
660 state = hbisect.load_state(repo)
660 state = hbisect.load_state(repo)
661
661
662 if command:
662 if command:
663 changesets = 1
663 changesets = 1
664 try:
664 try:
665 node = state['current'][0]
665 node = state['current'][0]
666 except LookupError:
666 except LookupError:
667 if noupdate:
667 if noupdate:
668 raise util.Abort(_('current bisect revision is unknown - '
668 raise util.Abort(_('current bisect revision is unknown - '
669 'start a new bisect to fix'))
669 'start a new bisect to fix'))
670 node, p2 = repo.dirstate.parents()
670 node, p2 = repo.dirstate.parents()
671 if p2 != nullid:
671 if p2 != nullid:
672 raise util.Abort(_('current bisect revision is a merge'))
672 raise util.Abort(_('current bisect revision is a merge'))
673 try:
673 try:
674 while changesets:
674 while changesets:
675 # update state
675 # update state
676 state['current'] = [node]
676 state['current'] = [node]
677 hbisect.save_state(repo, state)
677 hbisect.save_state(repo, state)
678 status = util.system(command,
678 status = util.system(command,
679 environ={'HG_NODE': hex(node)},
679 environ={'HG_NODE': hex(node)},
680 out=ui.fout)
680 out=ui.fout)
681 if status == 125:
681 if status == 125:
682 transition = "skip"
682 transition = "skip"
683 elif status == 0:
683 elif status == 0:
684 transition = "good"
684 transition = "good"
685 # status < 0 means process was killed
685 # status < 0 means process was killed
686 elif status == 127:
686 elif status == 127:
687 raise util.Abort(_("failed to execute %s") % command)
687 raise util.Abort(_("failed to execute %s") % command)
688 elif status < 0:
688 elif status < 0:
689 raise util.Abort(_("%s killed") % command)
689 raise util.Abort(_("%s killed") % command)
690 else:
690 else:
691 transition = "bad"
691 transition = "bad"
692 ctx = scmutil.revsingle(repo, rev, node)
692 ctx = scmutil.revsingle(repo, rev, node)
693 rev = None # clear for future iterations
693 rev = None # clear for future iterations
694 state[transition].append(ctx.node())
694 state[transition].append(ctx.node())
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
696 check_state(state, interactive=False)
696 check_state(state, interactive=False)
697 # bisect
697 # bisect
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
699 # update to next check
699 # update to next check
700 node = nodes[0]
700 node = nodes[0]
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 finally:
704 finally:
705 state['current'] = [node]
705 state['current'] = [node]
706 hbisect.save_state(repo, state)
706 hbisect.save_state(repo, state)
707 print_result(nodes, good)
707 print_result(nodes, good)
708 return
708 return
709
709
710 # update state
710 # update state
711
711
712 if rev:
712 if rev:
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
714 else:
714 else:
715 nodes = [repo.lookup('.')]
715 nodes = [repo.lookup('.')]
716
716
717 if good or bad or skip:
717 if good or bad or skip:
718 if good:
718 if good:
719 state['good'] += nodes
719 state['good'] += nodes
720 elif bad:
720 elif bad:
721 state['bad'] += nodes
721 state['bad'] += nodes
722 elif skip:
722 elif skip:
723 state['skip'] += nodes
723 state['skip'] += nodes
724 hbisect.save_state(repo, state)
724 hbisect.save_state(repo, state)
725
725
726 if not check_state(state):
726 if not check_state(state):
727 return
727 return
728
728
729 # actually bisect
729 # actually bisect
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
731 if extend:
731 if extend:
732 if not changesets:
732 if not changesets:
733 extendnode = extendbisectrange(nodes, good)
733 extendnode = extendbisectrange(nodes, good)
734 if extendnode is not None:
734 if extendnode is not None:
735 ui.write(_("Extending search to changeset %d:%s\n"
735 ui.write(_("Extending search to changeset %d:%s\n"
736 % (extendnode.rev(), extendnode)))
736 % (extendnode.rev(), extendnode)))
737 state['current'] = [extendnode.node()]
737 state['current'] = [extendnode.node()]
738 hbisect.save_state(repo, state)
738 hbisect.save_state(repo, state)
739 if noupdate:
739 if noupdate:
740 return
740 return
741 cmdutil.bailifchanged(repo)
741 cmdutil.bailifchanged(repo)
742 return hg.clean(repo, extendnode.node())
742 return hg.clean(repo, extendnode.node())
743 raise util.Abort(_("nothing to extend"))
743 raise util.Abort(_("nothing to extend"))
744
744
745 if changesets == 0:
745 if changesets == 0:
746 print_result(nodes, good)
746 print_result(nodes, good)
747 else:
747 else:
748 assert len(nodes) == 1 # only a single node can be tested next
748 assert len(nodes) == 1 # only a single node can be tested next
749 node = nodes[0]
749 node = nodes[0]
750 # compute the approximate number of remaining tests
750 # compute the approximate number of remaining tests
751 tests, size = 0, 2
751 tests, size = 0, 2
752 while size <= changesets:
752 while size <= changesets:
753 tests, size = tests + 1, size * 2
753 tests, size = tests + 1, size * 2
754 rev = repo.changelog.rev(node)
754 rev = repo.changelog.rev(node)
755 ui.write(_("Testing changeset %d:%s "
755 ui.write(_("Testing changeset %d:%s "
756 "(%d changesets remaining, ~%d tests)\n")
756 "(%d changesets remaining, ~%d tests)\n")
757 % (rev, short(node), changesets, tests))
757 % (rev, short(node), changesets, tests))
758 state['current'] = [node]
758 state['current'] = [node]
759 hbisect.save_state(repo, state)
759 hbisect.save_state(repo, state)
760 if not noupdate:
760 if not noupdate:
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, node)
762 return hg.clean(repo, node)
763
763
764 @command('bookmarks|bookmark',
764 @command('bookmarks|bookmark',
765 [('f', 'force', False, _('force')),
765 [('f', 'force', False, _('force')),
766 ('r', 'rev', '', _('revision'), _('REV')),
766 ('r', 'rev', '', _('revision'), _('REV')),
767 ('d', 'delete', False, _('delete a given bookmark')),
767 ('d', 'delete', False, _('delete a given bookmark')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
772 rename=None, inactive=False):
772 rename=None, inactive=False):
773 '''track a line of development with movable markers
773 '''track a line of development with movable markers
774
774
775 Bookmarks are pointers to certain commits that move when committing.
775 Bookmarks are pointers to certain commits that move when committing.
776 Bookmarks are local. They can be renamed, copied and deleted. It is
776 Bookmarks are local. They can be renamed, copied and deleted. It is
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
778 :hg:`update NAME` to update to a given bookmark.
778 :hg:`update NAME` to update to a given bookmark.
779
779
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
781 directory's parent revision with the given name. If you specify
781 directory's parent revision with the given name. If you specify
782 a revision using -r REV (where REV may be an existing bookmark),
782 a revision using -r REV (where REV may be an existing bookmark),
783 the bookmark is assigned to that revision.
783 the bookmark is assigned to that revision.
784
784
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
786 push` and :hg:`help pull`). This requires both the local and remote
786 push` and :hg:`help pull`). This requires both the local and remote
787 repositories to support bookmarks. For versions prior to 1.8, this means
787 repositories to support bookmarks. For versions prior to 1.8, this means
788 the bookmarks extension must be enabled.
788 the bookmarks extension must be enabled.
789
789
790 If you set a bookmark called '@', new clones of the repository will
790 If you set a bookmark called '@', new clones of the repository will
791 have that revision checked out (and the bookmark made active) by
791 have that revision checked out (and the bookmark made active) by
792 default.
792 default.
793
793
794 With -i/--inactive, the new bookmark will not be made the active
794 With -i/--inactive, the new bookmark will not be made the active
795 bookmark. If -r/--rev is given, the new bookmark will not be made
795 bookmark. If -r/--rev is given, the new bookmark will not be made
796 active even if -i/--inactive is not given. If no NAME is given, the
796 active even if -i/--inactive is not given. If no NAME is given, the
797 current active bookmark will be marked inactive.
797 current active bookmark will be marked inactive.
798 '''
798 '''
799 hexfn = ui.debugflag and hex or short
799 hexfn = ui.debugflag and hex or short
800 marks = repo._bookmarks
800 marks = repo._bookmarks
801 cur = repo.changectx('.').node()
801 cur = repo.changectx('.').node()
802
802
803 def checkformat(mark):
803 def checkformat(mark):
804 mark = mark.strip()
804 mark = mark.strip()
805 if not mark:
805 if not mark:
806 raise util.Abort(_("bookmark names cannot consist entirely of "
806 raise util.Abort(_("bookmark names cannot consist entirely of "
807 "whitespace"))
807 "whitespace"))
808 scmutil.checknewlabel(repo, mark, 'bookmark')
808 scmutil.checknewlabel(repo, mark, 'bookmark')
809 return mark
809 return mark
810
810
811 def checkconflict(repo, mark, force=False, target=None):
811 def checkconflict(repo, mark, force=False, target=None):
812 if mark in marks and not force:
812 if mark in marks and not force:
813 if target:
813 if target:
814 if marks[mark] == target and target == cur:
815 # re-activating a bookmark
816 return
814 anc = repo.changelog.ancestors([repo[target].rev()])
817 anc = repo.changelog.ancestors([repo[target].rev()])
815 bmctx = repo[marks[mark]]
818 bmctx = repo[marks[mark]]
816 if bmctx.rev() in anc:
819 if bmctx.rev() in anc:
817 ui.status(_("moving bookmark '%s' forward from %s\n") %
820 ui.status(_("moving bookmark '%s' forward from %s\n") %
818 (mark, short(bmctx.node())))
821 (mark, short(bmctx.node())))
819 return
822 return
820 raise util.Abort(_("bookmark '%s' already exists "
823 raise util.Abort(_("bookmark '%s' already exists "
821 "(use -f to force)") % mark)
824 "(use -f to force)") % mark)
822 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
825 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
823 and not force):
826 and not force):
824 raise util.Abort(
827 raise util.Abort(
825 _("a bookmark cannot have the name of an existing branch"))
828 _("a bookmark cannot have the name of an existing branch"))
826
829
827 if delete and rename:
830 if delete and rename:
828 raise util.Abort(_("--delete and --rename are incompatible"))
831 raise util.Abort(_("--delete and --rename are incompatible"))
829 if delete and rev:
832 if delete and rev:
830 raise util.Abort(_("--rev is incompatible with --delete"))
833 raise util.Abort(_("--rev is incompatible with --delete"))
831 if rename and rev:
834 if rename and rev:
832 raise util.Abort(_("--rev is incompatible with --rename"))
835 raise util.Abort(_("--rev is incompatible with --rename"))
833 if mark is None and (delete or rev):
836 if mark is None and (delete or rev):
834 raise util.Abort(_("bookmark name required"))
837 raise util.Abort(_("bookmark name required"))
835
838
836 if delete:
839 if delete:
837 if mark not in marks:
840 if mark not in marks:
838 raise util.Abort(_("bookmark '%s' does not exist") % mark)
841 raise util.Abort(_("bookmark '%s' does not exist") % mark)
839 if mark == repo._bookmarkcurrent:
842 if mark == repo._bookmarkcurrent:
840 bookmarks.setcurrent(repo, None)
843 bookmarks.setcurrent(repo, None)
841 del marks[mark]
844 del marks[mark]
842 marks.write()
845 marks.write()
843
846
844 elif rename:
847 elif rename:
845 if mark is None:
848 if mark is None:
846 raise util.Abort(_("new bookmark name required"))
849 raise util.Abort(_("new bookmark name required"))
847 mark = checkformat(mark)
850 mark = checkformat(mark)
848 if rename not in marks:
851 if rename not in marks:
849 raise util.Abort(_("bookmark '%s' does not exist") % rename)
852 raise util.Abort(_("bookmark '%s' does not exist") % rename)
850 checkconflict(repo, mark, force)
853 checkconflict(repo, mark, force)
851 marks[mark] = marks[rename]
854 marks[mark] = marks[rename]
852 if repo._bookmarkcurrent == rename and not inactive:
855 if repo._bookmarkcurrent == rename and not inactive:
853 bookmarks.setcurrent(repo, mark)
856 bookmarks.setcurrent(repo, mark)
854 del marks[rename]
857 del marks[rename]
855 marks.write()
858 marks.write()
856
859
857 elif mark is not None:
860 elif mark is not None:
858 mark = checkformat(mark)
861 mark = checkformat(mark)
859 if inactive and mark == repo._bookmarkcurrent:
862 if inactive and mark == repo._bookmarkcurrent:
860 bookmarks.setcurrent(repo, None)
863 bookmarks.setcurrent(repo, None)
861 return
864 return
862 tgt = cur
865 tgt = cur
863 if rev:
866 if rev:
864 tgt = scmutil.revsingle(repo, rev).node()
867 tgt = scmutil.revsingle(repo, rev).node()
865 checkconflict(repo, mark, force, tgt)
868 checkconflict(repo, mark, force, tgt)
866 marks[mark] = tgt
869 marks[mark] = tgt
867 if not inactive and cur == marks[mark]:
870 if not inactive and cur == marks[mark]:
868 bookmarks.setcurrent(repo, mark)
871 bookmarks.setcurrent(repo, mark)
869 marks.write()
872 marks.write()
870
873
871 # Same message whether trying to deactivate the current bookmark (-i
874 # Same message whether trying to deactivate the current bookmark (-i
872 # with no NAME) or listing bookmarks
875 # with no NAME) or listing bookmarks
873 elif len(marks) == 0:
876 elif len(marks) == 0:
874 ui.status(_("no bookmarks set\n"))
877 ui.status(_("no bookmarks set\n"))
875
878
876 elif inactive:
879 elif inactive:
877 if not repo._bookmarkcurrent:
880 if not repo._bookmarkcurrent:
878 ui.status(_("no active bookmark\n"))
881 ui.status(_("no active bookmark\n"))
879 else:
882 else:
880 bookmarks.setcurrent(repo, None)
883 bookmarks.setcurrent(repo, None)
881
884
882 else: # show bookmarks
885 else: # show bookmarks
883 for bmark, n in sorted(marks.iteritems()):
886 for bmark, n in sorted(marks.iteritems()):
884 current = repo._bookmarkcurrent
887 current = repo._bookmarkcurrent
885 if bmark == current:
888 if bmark == current:
886 prefix, label = '*', 'bookmarks.current'
889 prefix, label = '*', 'bookmarks.current'
887 else:
890 else:
888 prefix, label = ' ', ''
891 prefix, label = ' ', ''
889
892
890 if ui.quiet:
893 if ui.quiet:
891 ui.write("%s\n" % bmark, label=label)
894 ui.write("%s\n" % bmark, label=label)
892 else:
895 else:
893 ui.write(" %s %-25s %d:%s\n" % (
896 ui.write(" %s %-25s %d:%s\n" % (
894 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
897 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
895 label=label)
898 label=label)
896
899
897 @command('branch',
900 @command('branch',
898 [('f', 'force', None,
901 [('f', 'force', None,
899 _('set branch name even if it shadows an existing branch')),
902 _('set branch name even if it shadows an existing branch')),
900 ('C', 'clean', None, _('reset branch name to parent branch name'))],
903 ('C', 'clean', None, _('reset branch name to parent branch name'))],
901 _('[-fC] [NAME]'))
904 _('[-fC] [NAME]'))
902 def branch(ui, repo, label=None, **opts):
905 def branch(ui, repo, label=None, **opts):
903 """set or show the current branch name
906 """set or show the current branch name
904
907
905 .. note::
908 .. note::
906 Branch names are permanent and global. Use :hg:`bookmark` to create a
909 Branch names are permanent and global. Use :hg:`bookmark` to create a
907 light-weight bookmark instead. See :hg:`help glossary` for more
910 light-weight bookmark instead. See :hg:`help glossary` for more
908 information about named branches and bookmarks.
911 information about named branches and bookmarks.
909
912
910 With no argument, show the current branch name. With one argument,
913 With no argument, show the current branch name. With one argument,
911 set the working directory branch name (the branch will not exist
914 set the working directory branch name (the branch will not exist
912 in the repository until the next commit). Standard practice
915 in the repository until the next commit). Standard practice
913 recommends that primary development take place on the 'default'
916 recommends that primary development take place on the 'default'
914 branch.
917 branch.
915
918
916 Unless -f/--force is specified, branch will not let you set a
919 Unless -f/--force is specified, branch will not let you set a
917 branch name that already exists, even if it's inactive.
920 branch name that already exists, even if it's inactive.
918
921
919 Use -C/--clean to reset the working directory branch to that of
922 Use -C/--clean to reset the working directory branch to that of
920 the parent of the working directory, negating a previous branch
923 the parent of the working directory, negating a previous branch
921 change.
924 change.
922
925
923 Use the command :hg:`update` to switch to an existing branch. Use
926 Use the command :hg:`update` to switch to an existing branch. Use
924 :hg:`commit --close-branch` to mark this branch as closed.
927 :hg:`commit --close-branch` to mark this branch as closed.
925
928
926 Returns 0 on success.
929 Returns 0 on success.
927 """
930 """
928 if not opts.get('clean') and not label:
931 if not opts.get('clean') and not label:
929 ui.write("%s\n" % repo.dirstate.branch())
932 ui.write("%s\n" % repo.dirstate.branch())
930 return
933 return
931
934
932 wlock = repo.wlock()
935 wlock = repo.wlock()
933 try:
936 try:
934 if opts.get('clean'):
937 if opts.get('clean'):
935 label = repo[None].p1().branch()
938 label = repo[None].p1().branch()
936 repo.dirstate.setbranch(label)
939 repo.dirstate.setbranch(label)
937 ui.status(_('reset working directory to branch %s\n') % label)
940 ui.status(_('reset working directory to branch %s\n') % label)
938 elif label:
941 elif label:
939 if not opts.get('force') and label in repo.branchmap():
942 if not opts.get('force') and label in repo.branchmap():
940 if label not in [p.branch() for p in repo.parents()]:
943 if label not in [p.branch() for p in repo.parents()]:
941 raise util.Abort(_('a branch of the same name already'
944 raise util.Abort(_('a branch of the same name already'
942 ' exists'),
945 ' exists'),
943 # i18n: "it" refers to an existing branch
946 # i18n: "it" refers to an existing branch
944 hint=_("use 'hg update' to switch to it"))
947 hint=_("use 'hg update' to switch to it"))
945 scmutil.checknewlabel(repo, label, 'branch')
948 scmutil.checknewlabel(repo, label, 'branch')
946 repo.dirstate.setbranch(label)
949 repo.dirstate.setbranch(label)
947 ui.status(_('marked working directory as branch %s\n') % label)
950 ui.status(_('marked working directory as branch %s\n') % label)
948 ui.status(_('(branches are permanent and global, '
951 ui.status(_('(branches are permanent and global, '
949 'did you want a bookmark?)\n'))
952 'did you want a bookmark?)\n'))
950 finally:
953 finally:
951 wlock.release()
954 wlock.release()
952
955
953 @command('branches',
956 @command('branches',
954 [('a', 'active', False, _('show only branches that have unmerged heads')),
957 [('a', 'active', False, _('show only branches that have unmerged heads')),
955 ('c', 'closed', False, _('show normal and closed branches'))],
958 ('c', 'closed', False, _('show normal and closed branches'))],
956 _('[-ac]'))
959 _('[-ac]'))
957 def branches(ui, repo, active=False, closed=False):
960 def branches(ui, repo, active=False, closed=False):
958 """list repository named branches
961 """list repository named branches
959
962
960 List the repository's named branches, indicating which ones are
963 List the repository's named branches, indicating which ones are
961 inactive. If -c/--closed is specified, also list branches which have
964 inactive. If -c/--closed is specified, also list branches which have
962 been marked closed (see :hg:`commit --close-branch`).
965 been marked closed (see :hg:`commit --close-branch`).
963
966
964 If -a/--active is specified, only show active branches. A branch
967 If -a/--active is specified, only show active branches. A branch
965 is considered active if it contains repository heads.
968 is considered active if it contains repository heads.
966
969
967 Use the command :hg:`update` to switch to an existing branch.
970 Use the command :hg:`update` to switch to an existing branch.
968
971
969 Returns 0.
972 Returns 0.
970 """
973 """
971
974
972 hexfunc = ui.debugflag and hex or short
975 hexfunc = ui.debugflag and hex or short
973
976
974 activebranches = set([repo[n].branch() for n in repo.heads()])
977 activebranches = set([repo[n].branch() for n in repo.heads()])
975 branches = []
978 branches = []
976 for tag, heads in repo.branchmap().iteritems():
979 for tag, heads in repo.branchmap().iteritems():
977 for h in reversed(heads):
980 for h in reversed(heads):
978 ctx = repo[h]
981 ctx = repo[h]
979 isopen = not ctx.closesbranch()
982 isopen = not ctx.closesbranch()
980 if isopen:
983 if isopen:
981 tip = ctx
984 tip = ctx
982 break
985 break
983 else:
986 else:
984 tip = repo[heads[-1]]
987 tip = repo[heads[-1]]
985 isactive = tag in activebranches and isopen
988 isactive = tag in activebranches and isopen
986 branches.append((tip, isactive, isopen))
989 branches.append((tip, isactive, isopen))
987 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
990 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
988 reverse=True)
991 reverse=True)
989
992
990 for ctx, isactive, isopen in branches:
993 for ctx, isactive, isopen in branches:
991 if (not active) or isactive:
994 if (not active) or isactive:
992 if isactive:
995 if isactive:
993 label = 'branches.active'
996 label = 'branches.active'
994 notice = ''
997 notice = ''
995 elif not isopen:
998 elif not isopen:
996 if not closed:
999 if not closed:
997 continue
1000 continue
998 label = 'branches.closed'
1001 label = 'branches.closed'
999 notice = _(' (closed)')
1002 notice = _(' (closed)')
1000 else:
1003 else:
1001 label = 'branches.inactive'
1004 label = 'branches.inactive'
1002 notice = _(' (inactive)')
1005 notice = _(' (inactive)')
1003 if ctx.branch() == repo.dirstate.branch():
1006 if ctx.branch() == repo.dirstate.branch():
1004 label = 'branches.current'
1007 label = 'branches.current'
1005 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1008 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1006 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1009 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1007 'log.changeset changeset.%s' % ctx.phasestr())
1010 'log.changeset changeset.%s' % ctx.phasestr())
1008 tag = ui.label(ctx.branch(), label)
1011 tag = ui.label(ctx.branch(), label)
1009 if ui.quiet:
1012 if ui.quiet:
1010 ui.write("%s\n" % tag)
1013 ui.write("%s\n" % tag)
1011 else:
1014 else:
1012 ui.write("%s %s%s\n" % (tag, rev, notice))
1015 ui.write("%s %s%s\n" % (tag, rev, notice))
1013
1016
1014 @command('bundle',
1017 @command('bundle',
1015 [('f', 'force', None, _('run even when the destination is unrelated')),
1018 [('f', 'force', None, _('run even when the destination is unrelated')),
1016 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1019 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1017 _('REV')),
1020 _('REV')),
1018 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1021 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1019 _('BRANCH')),
1022 _('BRANCH')),
1020 ('', 'base', [],
1023 ('', 'base', [],
1021 _('a base changeset assumed to be available at the destination'),
1024 _('a base changeset assumed to be available at the destination'),
1022 _('REV')),
1025 _('REV')),
1023 ('a', 'all', None, _('bundle all changesets in the repository')),
1026 ('a', 'all', None, _('bundle all changesets in the repository')),
1024 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1027 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1025 ] + remoteopts,
1028 ] + remoteopts,
1026 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1029 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1027 def bundle(ui, repo, fname, dest=None, **opts):
1030 def bundle(ui, repo, fname, dest=None, **opts):
1028 """create a changegroup file
1031 """create a changegroup file
1029
1032
1030 Generate a compressed changegroup file collecting changesets not
1033 Generate a compressed changegroup file collecting changesets not
1031 known to be in another repository.
1034 known to be in another repository.
1032
1035
1033 If you omit the destination repository, then hg assumes the
1036 If you omit the destination repository, then hg assumes the
1034 destination will have all the nodes you specify with --base
1037 destination will have all the nodes you specify with --base
1035 parameters. To create a bundle containing all changesets, use
1038 parameters. To create a bundle containing all changesets, use
1036 -a/--all (or --base null).
1039 -a/--all (or --base null).
1037
1040
1038 You can change compression method with the -t/--type option.
1041 You can change compression method with the -t/--type option.
1039 The available compression methods are: none, bzip2, and
1042 The available compression methods are: none, bzip2, and
1040 gzip (by default, bundles are compressed using bzip2).
1043 gzip (by default, bundles are compressed using bzip2).
1041
1044
1042 The bundle file can then be transferred using conventional means
1045 The bundle file can then be transferred using conventional means
1043 and applied to another repository with the unbundle or pull
1046 and applied to another repository with the unbundle or pull
1044 command. This is useful when direct push and pull are not
1047 command. This is useful when direct push and pull are not
1045 available or when exporting an entire repository is undesirable.
1048 available or when exporting an entire repository is undesirable.
1046
1049
1047 Applying bundles preserves all changeset contents including
1050 Applying bundles preserves all changeset contents including
1048 permissions, copy/rename information, and revision history.
1051 permissions, copy/rename information, and revision history.
1049
1052
1050 Returns 0 on success, 1 if no changes found.
1053 Returns 0 on success, 1 if no changes found.
1051 """
1054 """
1052 revs = None
1055 revs = None
1053 if 'rev' in opts:
1056 if 'rev' in opts:
1054 revs = scmutil.revrange(repo, opts['rev'])
1057 revs = scmutil.revrange(repo, opts['rev'])
1055
1058
1056 bundletype = opts.get('type', 'bzip2').lower()
1059 bundletype = opts.get('type', 'bzip2').lower()
1057 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1060 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1058 bundletype = btypes.get(bundletype)
1061 bundletype = btypes.get(bundletype)
1059 if bundletype not in changegroup.bundletypes:
1062 if bundletype not in changegroup.bundletypes:
1060 raise util.Abort(_('unknown bundle type specified with --type'))
1063 raise util.Abort(_('unknown bundle type specified with --type'))
1061
1064
1062 if opts.get('all'):
1065 if opts.get('all'):
1063 base = ['null']
1066 base = ['null']
1064 else:
1067 else:
1065 base = scmutil.revrange(repo, opts.get('base'))
1068 base = scmutil.revrange(repo, opts.get('base'))
1066 if base:
1069 if base:
1067 if dest:
1070 if dest:
1068 raise util.Abort(_("--base is incompatible with specifying "
1071 raise util.Abort(_("--base is incompatible with specifying "
1069 "a destination"))
1072 "a destination"))
1070 common = [repo.lookup(rev) for rev in base]
1073 common = [repo.lookup(rev) for rev in base]
1071 heads = revs and map(repo.lookup, revs) or revs
1074 heads = revs and map(repo.lookup, revs) or revs
1072 cg = repo.getbundle('bundle', heads=heads, common=common)
1075 cg = repo.getbundle('bundle', heads=heads, common=common)
1073 outgoing = None
1076 outgoing = None
1074 else:
1077 else:
1075 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1078 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1076 dest, branches = hg.parseurl(dest, opts.get('branch'))
1079 dest, branches = hg.parseurl(dest, opts.get('branch'))
1077 other = hg.peer(repo, opts, dest)
1080 other = hg.peer(repo, opts, dest)
1078 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1081 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1079 heads = revs and map(repo.lookup, revs) or revs
1082 heads = revs and map(repo.lookup, revs) or revs
1080 outgoing = discovery.findcommonoutgoing(repo, other,
1083 outgoing = discovery.findcommonoutgoing(repo, other,
1081 onlyheads=heads,
1084 onlyheads=heads,
1082 force=opts.get('force'),
1085 force=opts.get('force'),
1083 portable=True)
1086 portable=True)
1084 cg = repo.getlocalbundle('bundle', outgoing)
1087 cg = repo.getlocalbundle('bundle', outgoing)
1085 if not cg:
1088 if not cg:
1086 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1089 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1087 return 1
1090 return 1
1088
1091
1089 changegroup.writebundle(cg, fname, bundletype)
1092 changegroup.writebundle(cg, fname, bundletype)
1090
1093
1091 @command('cat',
1094 @command('cat',
1092 [('o', 'output', '',
1095 [('o', 'output', '',
1093 _('print output to file with formatted name'), _('FORMAT')),
1096 _('print output to file with formatted name'), _('FORMAT')),
1094 ('r', 'rev', '', _('print the given revision'), _('REV')),
1097 ('r', 'rev', '', _('print the given revision'), _('REV')),
1095 ('', 'decode', None, _('apply any matching decode filter')),
1098 ('', 'decode', None, _('apply any matching decode filter')),
1096 ] + walkopts,
1099 ] + walkopts,
1097 _('[OPTION]... FILE...'))
1100 _('[OPTION]... FILE...'))
1098 def cat(ui, repo, file1, *pats, **opts):
1101 def cat(ui, repo, file1, *pats, **opts):
1099 """output the current or given revision of files
1102 """output the current or given revision of files
1100
1103
1101 Print the specified files as they were at the given revision. If
1104 Print the specified files as they were at the given revision. If
1102 no revision is given, the parent of the working directory is used,
1105 no revision is given, the parent of the working directory is used,
1103 or tip if no revision is checked out.
1106 or tip if no revision is checked out.
1104
1107
1105 Output may be to a file, in which case the name of the file is
1108 Output may be to a file, in which case the name of the file is
1106 given using a format string. The formatting rules are the same as
1109 given using a format string. The formatting rules are the same as
1107 for the export command, with the following additions:
1110 for the export command, with the following additions:
1108
1111
1109 :``%s``: basename of file being printed
1112 :``%s``: basename of file being printed
1110 :``%d``: dirname of file being printed, or '.' if in repository root
1113 :``%d``: dirname of file being printed, or '.' if in repository root
1111 :``%p``: root-relative path name of file being printed
1114 :``%p``: root-relative path name of file being printed
1112
1115
1113 Returns 0 on success.
1116 Returns 0 on success.
1114 """
1117 """
1115 ctx = scmutil.revsingle(repo, opts.get('rev'))
1118 ctx = scmutil.revsingle(repo, opts.get('rev'))
1116 err = 1
1119 err = 1
1117 m = scmutil.match(ctx, (file1,) + pats, opts)
1120 m = scmutil.match(ctx, (file1,) + pats, opts)
1118 for abs in ctx.walk(m):
1121 for abs in ctx.walk(m):
1119 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1122 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1120 pathname=abs)
1123 pathname=abs)
1121 data = ctx[abs].data()
1124 data = ctx[abs].data()
1122 if opts.get('decode'):
1125 if opts.get('decode'):
1123 data = repo.wwritedata(abs, data)
1126 data = repo.wwritedata(abs, data)
1124 fp.write(data)
1127 fp.write(data)
1125 fp.close()
1128 fp.close()
1126 err = 0
1129 err = 0
1127 return err
1130 return err
1128
1131
1129 @command('^clone',
1132 @command('^clone',
1130 [('U', 'noupdate', None,
1133 [('U', 'noupdate', None,
1131 _('the clone will include an empty working copy (only a repository)')),
1134 _('the clone will include an empty working copy (only a repository)')),
1132 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1135 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1133 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1136 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1134 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1137 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1135 ('', 'pull', None, _('use pull protocol to copy metadata')),
1138 ('', 'pull', None, _('use pull protocol to copy metadata')),
1136 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1139 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1137 ] + remoteopts,
1140 ] + remoteopts,
1138 _('[OPTION]... SOURCE [DEST]'))
1141 _('[OPTION]... SOURCE [DEST]'))
1139 def clone(ui, source, dest=None, **opts):
1142 def clone(ui, source, dest=None, **opts):
1140 """make a copy of an existing repository
1143 """make a copy of an existing repository
1141
1144
1142 Create a copy of an existing repository in a new directory.
1145 Create a copy of an existing repository in a new directory.
1143
1146
1144 If no destination directory name is specified, it defaults to the
1147 If no destination directory name is specified, it defaults to the
1145 basename of the source.
1148 basename of the source.
1146
1149
1147 The location of the source is added to the new repository's
1150 The location of the source is added to the new repository's
1148 ``.hg/hgrc`` file, as the default to be used for future pulls.
1151 ``.hg/hgrc`` file, as the default to be used for future pulls.
1149
1152
1150 Only local paths and ``ssh://`` URLs are supported as
1153 Only local paths and ``ssh://`` URLs are supported as
1151 destinations. For ``ssh://`` destinations, no working directory or
1154 destinations. For ``ssh://`` destinations, no working directory or
1152 ``.hg/hgrc`` will be created on the remote side.
1155 ``.hg/hgrc`` will be created on the remote side.
1153
1156
1154 To pull only a subset of changesets, specify one or more revisions
1157 To pull only a subset of changesets, specify one or more revisions
1155 identifiers with -r/--rev or branches with -b/--branch. The
1158 identifiers with -r/--rev or branches with -b/--branch. The
1156 resulting clone will contain only the specified changesets and
1159 resulting clone will contain only the specified changesets and
1157 their ancestors. These options (or 'clone src#rev dest') imply
1160 their ancestors. These options (or 'clone src#rev dest') imply
1158 --pull, even for local source repositories. Note that specifying a
1161 --pull, even for local source repositories. Note that specifying a
1159 tag will include the tagged changeset but not the changeset
1162 tag will include the tagged changeset but not the changeset
1160 containing the tag.
1163 containing the tag.
1161
1164
1162 If the source repository has a bookmark called '@' set, that
1165 If the source repository has a bookmark called '@' set, that
1163 revision will be checked out in the new repository by default.
1166 revision will be checked out in the new repository by default.
1164
1167
1165 To check out a particular version, use -u/--update, or
1168 To check out a particular version, use -u/--update, or
1166 -U/--noupdate to create a clone with no working directory.
1169 -U/--noupdate to create a clone with no working directory.
1167
1170
1168 .. container:: verbose
1171 .. container:: verbose
1169
1172
1170 For efficiency, hardlinks are used for cloning whenever the
1173 For efficiency, hardlinks are used for cloning whenever the
1171 source and destination are on the same filesystem (note this
1174 source and destination are on the same filesystem (note this
1172 applies only to the repository data, not to the working
1175 applies only to the repository data, not to the working
1173 directory). Some filesystems, such as AFS, implement hardlinking
1176 directory). Some filesystems, such as AFS, implement hardlinking
1174 incorrectly, but do not report errors. In these cases, use the
1177 incorrectly, but do not report errors. In these cases, use the
1175 --pull option to avoid hardlinking.
1178 --pull option to avoid hardlinking.
1176
1179
1177 In some cases, you can clone repositories and the working
1180 In some cases, you can clone repositories and the working
1178 directory using full hardlinks with ::
1181 directory using full hardlinks with ::
1179
1182
1180 $ cp -al REPO REPOCLONE
1183 $ cp -al REPO REPOCLONE
1181
1184
1182 This is the fastest way to clone, but it is not always safe. The
1185 This is the fastest way to clone, but it is not always safe. The
1183 operation is not atomic (making sure REPO is not modified during
1186 operation is not atomic (making sure REPO is not modified during
1184 the operation is up to you) and you have to make sure your
1187 the operation is up to you) and you have to make sure your
1185 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1188 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1186 so). Also, this is not compatible with certain extensions that
1189 so). Also, this is not compatible with certain extensions that
1187 place their metadata under the .hg directory, such as mq.
1190 place their metadata under the .hg directory, such as mq.
1188
1191
1189 Mercurial will update the working directory to the first applicable
1192 Mercurial will update the working directory to the first applicable
1190 revision from this list:
1193 revision from this list:
1191
1194
1192 a) null if -U or the source repository has no changesets
1195 a) null if -U or the source repository has no changesets
1193 b) if -u . and the source repository is local, the first parent of
1196 b) if -u . and the source repository is local, the first parent of
1194 the source repository's working directory
1197 the source repository's working directory
1195 c) the changeset specified with -u (if a branch name, this means the
1198 c) the changeset specified with -u (if a branch name, this means the
1196 latest head of that branch)
1199 latest head of that branch)
1197 d) the changeset specified with -r
1200 d) the changeset specified with -r
1198 e) the tipmost head specified with -b
1201 e) the tipmost head specified with -b
1199 f) the tipmost head specified with the url#branch source syntax
1202 f) the tipmost head specified with the url#branch source syntax
1200 g) the revision marked with the '@' bookmark, if present
1203 g) the revision marked with the '@' bookmark, if present
1201 h) the tipmost head of the default branch
1204 h) the tipmost head of the default branch
1202 i) tip
1205 i) tip
1203
1206
1204 Examples:
1207 Examples:
1205
1208
1206 - clone a remote repository to a new directory named hg/::
1209 - clone a remote repository to a new directory named hg/::
1207
1210
1208 hg clone http://selenic.com/hg
1211 hg clone http://selenic.com/hg
1209
1212
1210 - create a lightweight local clone::
1213 - create a lightweight local clone::
1211
1214
1212 hg clone project/ project-feature/
1215 hg clone project/ project-feature/
1213
1216
1214 - clone from an absolute path on an ssh server (note double-slash)::
1217 - clone from an absolute path on an ssh server (note double-slash)::
1215
1218
1216 hg clone ssh://user@server//home/projects/alpha/
1219 hg clone ssh://user@server//home/projects/alpha/
1217
1220
1218 - do a high-speed clone over a LAN while checking out a
1221 - do a high-speed clone over a LAN while checking out a
1219 specified version::
1222 specified version::
1220
1223
1221 hg clone --uncompressed http://server/repo -u 1.5
1224 hg clone --uncompressed http://server/repo -u 1.5
1222
1225
1223 - create a repository without changesets after a particular revision::
1226 - create a repository without changesets after a particular revision::
1224
1227
1225 hg clone -r 04e544 experimental/ good/
1228 hg clone -r 04e544 experimental/ good/
1226
1229
1227 - clone (and track) a particular named branch::
1230 - clone (and track) a particular named branch::
1228
1231
1229 hg clone http://selenic.com/hg#stable
1232 hg clone http://selenic.com/hg#stable
1230
1233
1231 See :hg:`help urls` for details on specifying URLs.
1234 See :hg:`help urls` for details on specifying URLs.
1232
1235
1233 Returns 0 on success.
1236 Returns 0 on success.
1234 """
1237 """
1235 if opts.get('noupdate') and opts.get('updaterev'):
1238 if opts.get('noupdate') and opts.get('updaterev'):
1236 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1239 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1237
1240
1238 r = hg.clone(ui, opts, source, dest,
1241 r = hg.clone(ui, opts, source, dest,
1239 pull=opts.get('pull'),
1242 pull=opts.get('pull'),
1240 stream=opts.get('uncompressed'),
1243 stream=opts.get('uncompressed'),
1241 rev=opts.get('rev'),
1244 rev=opts.get('rev'),
1242 update=opts.get('updaterev') or not opts.get('noupdate'),
1245 update=opts.get('updaterev') or not opts.get('noupdate'),
1243 branch=opts.get('branch'))
1246 branch=opts.get('branch'))
1244
1247
1245 return r is None
1248 return r is None
1246
1249
1247 @command('^commit|ci',
1250 @command('^commit|ci',
1248 [('A', 'addremove', None,
1251 [('A', 'addremove', None,
1249 _('mark new/missing files as added/removed before committing')),
1252 _('mark new/missing files as added/removed before committing')),
1250 ('', 'close-branch', None,
1253 ('', 'close-branch', None,
1251 _('mark a branch as closed, hiding it from the branch list')),
1254 _('mark a branch as closed, hiding it from the branch list')),
1252 ('', 'amend', None, _('amend the parent of the working dir')),
1255 ('', 'amend', None, _('amend the parent of the working dir')),
1253 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1256 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1254 _('[OPTION]... [FILE]...'))
1257 _('[OPTION]... [FILE]...'))
1255 def commit(ui, repo, *pats, **opts):
1258 def commit(ui, repo, *pats, **opts):
1256 """commit the specified files or all outstanding changes
1259 """commit the specified files or all outstanding changes
1257
1260
1258 Commit changes to the given files into the repository. Unlike a
1261 Commit changes to the given files into the repository. Unlike a
1259 centralized SCM, this operation is a local operation. See
1262 centralized SCM, this operation is a local operation. See
1260 :hg:`push` for a way to actively distribute your changes.
1263 :hg:`push` for a way to actively distribute your changes.
1261
1264
1262 If a list of files is omitted, all changes reported by :hg:`status`
1265 If a list of files is omitted, all changes reported by :hg:`status`
1263 will be committed.
1266 will be committed.
1264
1267
1265 If you are committing the result of a merge, do not provide any
1268 If you are committing the result of a merge, do not provide any
1266 filenames or -I/-X filters.
1269 filenames or -I/-X filters.
1267
1270
1268 If no commit message is specified, Mercurial starts your
1271 If no commit message is specified, Mercurial starts your
1269 configured editor where you can enter a message. In case your
1272 configured editor where you can enter a message. In case your
1270 commit fails, you will find a backup of your message in
1273 commit fails, you will find a backup of your message in
1271 ``.hg/last-message.txt``.
1274 ``.hg/last-message.txt``.
1272
1275
1273 The --amend flag can be used to amend the parent of the
1276 The --amend flag can be used to amend the parent of the
1274 working directory with a new commit that contains the changes
1277 working directory with a new commit that contains the changes
1275 in the parent in addition to those currently reported by :hg:`status`,
1278 in the parent in addition to those currently reported by :hg:`status`,
1276 if there are any. The old commit is stored in a backup bundle in
1279 if there are any. The old commit is stored in a backup bundle in
1277 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1280 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1278 on how to restore it).
1281 on how to restore it).
1279
1282
1280 Message, user and date are taken from the amended commit unless
1283 Message, user and date are taken from the amended commit unless
1281 specified. When a message isn't specified on the command line,
1284 specified. When a message isn't specified on the command line,
1282 the editor will open with the message of the amended commit.
1285 the editor will open with the message of the amended commit.
1283
1286
1284 It is not possible to amend public changesets (see :hg:`help phases`)
1287 It is not possible to amend public changesets (see :hg:`help phases`)
1285 or changesets that have children.
1288 or changesets that have children.
1286
1289
1287 See :hg:`help dates` for a list of formats valid for -d/--date.
1290 See :hg:`help dates` for a list of formats valid for -d/--date.
1288
1291
1289 Returns 0 on success, 1 if nothing changed.
1292 Returns 0 on success, 1 if nothing changed.
1290 """
1293 """
1291 if opts.get('subrepos'):
1294 if opts.get('subrepos'):
1292 # Let --subrepos on the command line override config setting.
1295 # Let --subrepos on the command line override config setting.
1293 ui.setconfig('ui', 'commitsubrepos', True)
1296 ui.setconfig('ui', 'commitsubrepos', True)
1294
1297
1295 extra = {}
1298 extra = {}
1296 if opts.get('close_branch'):
1299 if opts.get('close_branch'):
1297 if repo['.'].node() not in repo.branchheads():
1300 if repo['.'].node() not in repo.branchheads():
1298 # The topo heads set is included in the branch heads set of the
1301 # The topo heads set is included in the branch heads set of the
1299 # current branch, so it's sufficient to test branchheads
1302 # current branch, so it's sufficient to test branchheads
1300 raise util.Abort(_('can only close branch heads'))
1303 raise util.Abort(_('can only close branch heads'))
1301 extra['close'] = 1
1304 extra['close'] = 1
1302
1305
1303 branch = repo[None].branch()
1306 branch = repo[None].branch()
1304 bheads = repo.branchheads(branch)
1307 bheads = repo.branchheads(branch)
1305
1308
1306 if opts.get('amend'):
1309 if opts.get('amend'):
1307 if ui.configbool('ui', 'commitsubrepos'):
1310 if ui.configbool('ui', 'commitsubrepos'):
1308 raise util.Abort(_('cannot amend recursively'))
1311 raise util.Abort(_('cannot amend recursively'))
1309
1312
1310 old = repo['.']
1313 old = repo['.']
1311 if old.phase() == phases.public:
1314 if old.phase() == phases.public:
1312 raise util.Abort(_('cannot amend public changesets'))
1315 raise util.Abort(_('cannot amend public changesets'))
1313 if len(old.parents()) > 1:
1316 if len(old.parents()) > 1:
1314 raise util.Abort(_('cannot amend merge changesets'))
1317 raise util.Abort(_('cannot amend merge changesets'))
1315 if len(repo[None].parents()) > 1:
1318 if len(repo[None].parents()) > 1:
1316 raise util.Abort(_('cannot amend while merging'))
1319 raise util.Abort(_('cannot amend while merging'))
1317 if (not obsolete._enabled) and old.children():
1320 if (not obsolete._enabled) and old.children():
1318 raise util.Abort(_('cannot amend changeset with children'))
1321 raise util.Abort(_('cannot amend changeset with children'))
1319
1322
1320 e = cmdutil.commiteditor
1323 e = cmdutil.commiteditor
1321 if opts.get('force_editor'):
1324 if opts.get('force_editor'):
1322 e = cmdutil.commitforceeditor
1325 e = cmdutil.commitforceeditor
1323
1326
1324 def commitfunc(ui, repo, message, match, opts):
1327 def commitfunc(ui, repo, message, match, opts):
1325 editor = e
1328 editor = e
1326 # message contains text from -m or -l, if it's empty,
1329 # message contains text from -m or -l, if it's empty,
1327 # open the editor with the old message
1330 # open the editor with the old message
1328 if not message:
1331 if not message:
1329 message = old.description()
1332 message = old.description()
1330 editor = cmdutil.commitforceeditor
1333 editor = cmdutil.commitforceeditor
1331 return repo.commit(message,
1334 return repo.commit(message,
1332 opts.get('user') or old.user(),
1335 opts.get('user') or old.user(),
1333 opts.get('date') or old.date(),
1336 opts.get('date') or old.date(),
1334 match,
1337 match,
1335 editor=editor,
1338 editor=editor,
1336 extra=extra)
1339 extra=extra)
1337
1340
1338 current = repo._bookmarkcurrent
1341 current = repo._bookmarkcurrent
1339 marks = old.bookmarks()
1342 marks = old.bookmarks()
1340 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1343 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1341 if node == old.node():
1344 if node == old.node():
1342 ui.status(_("nothing changed\n"))
1345 ui.status(_("nothing changed\n"))
1343 return 1
1346 return 1
1344 elif marks:
1347 elif marks:
1345 ui.debug('moving bookmarks %r from %s to %s\n' %
1348 ui.debug('moving bookmarks %r from %s to %s\n' %
1346 (marks, old.hex(), hex(node)))
1349 (marks, old.hex(), hex(node)))
1347 newmarks = repo._bookmarks
1350 newmarks = repo._bookmarks
1348 for bm in marks:
1351 for bm in marks:
1349 newmarks[bm] = node
1352 newmarks[bm] = node
1350 if bm == current:
1353 if bm == current:
1351 bookmarks.setcurrent(repo, bm)
1354 bookmarks.setcurrent(repo, bm)
1352 newmarks.write()
1355 newmarks.write()
1353 else:
1356 else:
1354 e = cmdutil.commiteditor
1357 e = cmdutil.commiteditor
1355 if opts.get('force_editor'):
1358 if opts.get('force_editor'):
1356 e = cmdutil.commitforceeditor
1359 e = cmdutil.commitforceeditor
1357
1360
1358 def commitfunc(ui, repo, message, match, opts):
1361 def commitfunc(ui, repo, message, match, opts):
1359 return repo.commit(message, opts.get('user'), opts.get('date'),
1362 return repo.commit(message, opts.get('user'), opts.get('date'),
1360 match, editor=e, extra=extra)
1363 match, editor=e, extra=extra)
1361
1364
1362 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1365 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1363
1366
1364 if not node:
1367 if not node:
1365 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1368 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1366 if stat[3]:
1369 if stat[3]:
1367 ui.status(_("nothing changed (%d missing files, see "
1370 ui.status(_("nothing changed (%d missing files, see "
1368 "'hg status')\n") % len(stat[3]))
1371 "'hg status')\n") % len(stat[3]))
1369 else:
1372 else:
1370 ui.status(_("nothing changed\n"))
1373 ui.status(_("nothing changed\n"))
1371 return 1
1374 return 1
1372
1375
1373 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1376 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1374
1377
1375 @command('copy|cp',
1378 @command('copy|cp',
1376 [('A', 'after', None, _('record a copy that has already occurred')),
1379 [('A', 'after', None, _('record a copy that has already occurred')),
1377 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1380 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1378 ] + walkopts + dryrunopts,
1381 ] + walkopts + dryrunopts,
1379 _('[OPTION]... [SOURCE]... DEST'))
1382 _('[OPTION]... [SOURCE]... DEST'))
1380 def copy(ui, repo, *pats, **opts):
1383 def copy(ui, repo, *pats, **opts):
1381 """mark files as copied for the next commit
1384 """mark files as copied for the next commit
1382
1385
1383 Mark dest as having copies of source files. If dest is a
1386 Mark dest as having copies of source files. If dest is a
1384 directory, copies are put in that directory. If dest is a file,
1387 directory, copies are put in that directory. If dest is a file,
1385 the source must be a single file.
1388 the source must be a single file.
1386
1389
1387 By default, this command copies the contents of files as they
1390 By default, this command copies the contents of files as they
1388 exist in the working directory. If invoked with -A/--after, the
1391 exist in the working directory. If invoked with -A/--after, the
1389 operation is recorded, but no copying is performed.
1392 operation is recorded, but no copying is performed.
1390
1393
1391 This command takes effect with the next commit. To undo a copy
1394 This command takes effect with the next commit. To undo a copy
1392 before that, see :hg:`revert`.
1395 before that, see :hg:`revert`.
1393
1396
1394 Returns 0 on success, 1 if errors are encountered.
1397 Returns 0 on success, 1 if errors are encountered.
1395 """
1398 """
1396 wlock = repo.wlock(False)
1399 wlock = repo.wlock(False)
1397 try:
1400 try:
1398 return cmdutil.copy(ui, repo, pats, opts)
1401 return cmdutil.copy(ui, repo, pats, opts)
1399 finally:
1402 finally:
1400 wlock.release()
1403 wlock.release()
1401
1404
1402 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1405 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1403 def debugancestor(ui, repo, *args):
1406 def debugancestor(ui, repo, *args):
1404 """find the ancestor revision of two revisions in a given index"""
1407 """find the ancestor revision of two revisions in a given index"""
1405 if len(args) == 3:
1408 if len(args) == 3:
1406 index, rev1, rev2 = args
1409 index, rev1, rev2 = args
1407 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1410 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1408 lookup = r.lookup
1411 lookup = r.lookup
1409 elif len(args) == 2:
1412 elif len(args) == 2:
1410 if not repo:
1413 if not repo:
1411 raise util.Abort(_("there is no Mercurial repository here "
1414 raise util.Abort(_("there is no Mercurial repository here "
1412 "(.hg not found)"))
1415 "(.hg not found)"))
1413 rev1, rev2 = args
1416 rev1, rev2 = args
1414 r = repo.changelog
1417 r = repo.changelog
1415 lookup = repo.lookup
1418 lookup = repo.lookup
1416 else:
1419 else:
1417 raise util.Abort(_('either two or three arguments required'))
1420 raise util.Abort(_('either two or three arguments required'))
1418 a = r.ancestor(lookup(rev1), lookup(rev2))
1421 a = r.ancestor(lookup(rev1), lookup(rev2))
1419 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1422 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1420
1423
1421 @command('debugbuilddag',
1424 @command('debugbuilddag',
1422 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1425 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1423 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1426 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1424 ('n', 'new-file', None, _('add new file at each rev'))],
1427 ('n', 'new-file', None, _('add new file at each rev'))],
1425 _('[OPTION]... [TEXT]'))
1428 _('[OPTION]... [TEXT]'))
1426 def debugbuilddag(ui, repo, text=None,
1429 def debugbuilddag(ui, repo, text=None,
1427 mergeable_file=False,
1430 mergeable_file=False,
1428 overwritten_file=False,
1431 overwritten_file=False,
1429 new_file=False):
1432 new_file=False):
1430 """builds a repo with a given DAG from scratch in the current empty repo
1433 """builds a repo with a given DAG from scratch in the current empty repo
1431
1434
1432 The description of the DAG is read from stdin if not given on the
1435 The description of the DAG is read from stdin if not given on the
1433 command line.
1436 command line.
1434
1437
1435 Elements:
1438 Elements:
1436
1439
1437 - "+n" is a linear run of n nodes based on the current default parent
1440 - "+n" is a linear run of n nodes based on the current default parent
1438 - "." is a single node based on the current default parent
1441 - "." is a single node based on the current default parent
1439 - "$" resets the default parent to null (implied at the start);
1442 - "$" resets the default parent to null (implied at the start);
1440 otherwise the default parent is always the last node created
1443 otherwise the default parent is always the last node created
1441 - "<p" sets the default parent to the backref p
1444 - "<p" sets the default parent to the backref p
1442 - "*p" is a fork at parent p, which is a backref
1445 - "*p" is a fork at parent p, which is a backref
1443 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1446 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1444 - "/p2" is a merge of the preceding node and p2
1447 - "/p2" is a merge of the preceding node and p2
1445 - ":tag" defines a local tag for the preceding node
1448 - ":tag" defines a local tag for the preceding node
1446 - "@branch" sets the named branch for subsequent nodes
1449 - "@branch" sets the named branch for subsequent nodes
1447 - "#...\\n" is a comment up to the end of the line
1450 - "#...\\n" is a comment up to the end of the line
1448
1451
1449 Whitespace between the above elements is ignored.
1452 Whitespace between the above elements is ignored.
1450
1453
1451 A backref is either
1454 A backref is either
1452
1455
1453 - a number n, which references the node curr-n, where curr is the current
1456 - a number n, which references the node curr-n, where curr is the current
1454 node, or
1457 node, or
1455 - the name of a local tag you placed earlier using ":tag", or
1458 - the name of a local tag you placed earlier using ":tag", or
1456 - empty to denote the default parent.
1459 - empty to denote the default parent.
1457
1460
1458 All string valued-elements are either strictly alphanumeric, or must
1461 All string valued-elements are either strictly alphanumeric, or must
1459 be enclosed in double quotes ("..."), with "\\" as escape character.
1462 be enclosed in double quotes ("..."), with "\\" as escape character.
1460 """
1463 """
1461
1464
1462 if text is None:
1465 if text is None:
1463 ui.status(_("reading DAG from stdin\n"))
1466 ui.status(_("reading DAG from stdin\n"))
1464 text = ui.fin.read()
1467 text = ui.fin.read()
1465
1468
1466 cl = repo.changelog
1469 cl = repo.changelog
1467 if len(cl) > 0:
1470 if len(cl) > 0:
1468 raise util.Abort(_('repository is not empty'))
1471 raise util.Abort(_('repository is not empty'))
1469
1472
1470 # determine number of revs in DAG
1473 # determine number of revs in DAG
1471 total = 0
1474 total = 0
1472 for type, data in dagparser.parsedag(text):
1475 for type, data in dagparser.parsedag(text):
1473 if type == 'n':
1476 if type == 'n':
1474 total += 1
1477 total += 1
1475
1478
1476 if mergeable_file:
1479 if mergeable_file:
1477 linesperrev = 2
1480 linesperrev = 2
1478 # make a file with k lines per rev
1481 # make a file with k lines per rev
1479 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1482 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1480 initialmergedlines.append("")
1483 initialmergedlines.append("")
1481
1484
1482 tags = []
1485 tags = []
1483
1486
1484 lock = tr = None
1487 lock = tr = None
1485 try:
1488 try:
1486 lock = repo.lock()
1489 lock = repo.lock()
1487 tr = repo.transaction("builddag")
1490 tr = repo.transaction("builddag")
1488
1491
1489 at = -1
1492 at = -1
1490 atbranch = 'default'
1493 atbranch = 'default'
1491 nodeids = []
1494 nodeids = []
1492 id = 0
1495 id = 0
1493 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1496 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1494 for type, data in dagparser.parsedag(text):
1497 for type, data in dagparser.parsedag(text):
1495 if type == 'n':
1498 if type == 'n':
1496 ui.note(('node %s\n' % str(data)))
1499 ui.note(('node %s\n' % str(data)))
1497 id, ps = data
1500 id, ps = data
1498
1501
1499 files = []
1502 files = []
1500 fctxs = {}
1503 fctxs = {}
1501
1504
1502 p2 = None
1505 p2 = None
1503 if mergeable_file:
1506 if mergeable_file:
1504 fn = "mf"
1507 fn = "mf"
1505 p1 = repo[ps[0]]
1508 p1 = repo[ps[0]]
1506 if len(ps) > 1:
1509 if len(ps) > 1:
1507 p2 = repo[ps[1]]
1510 p2 = repo[ps[1]]
1508 pa = p1.ancestor(p2)
1511 pa = p1.ancestor(p2)
1509 base, local, other = [x[fn].data() for x in (pa, p1,
1512 base, local, other = [x[fn].data() for x in (pa, p1,
1510 p2)]
1513 p2)]
1511 m3 = simplemerge.Merge3Text(base, local, other)
1514 m3 = simplemerge.Merge3Text(base, local, other)
1512 ml = [l.strip() for l in m3.merge_lines()]
1515 ml = [l.strip() for l in m3.merge_lines()]
1513 ml.append("")
1516 ml.append("")
1514 elif at > 0:
1517 elif at > 0:
1515 ml = p1[fn].data().split("\n")
1518 ml = p1[fn].data().split("\n")
1516 else:
1519 else:
1517 ml = initialmergedlines
1520 ml = initialmergedlines
1518 ml[id * linesperrev] += " r%i" % id
1521 ml[id * linesperrev] += " r%i" % id
1519 mergedtext = "\n".join(ml)
1522 mergedtext = "\n".join(ml)
1520 files.append(fn)
1523 files.append(fn)
1521 fctxs[fn] = context.memfilectx(fn, mergedtext)
1524 fctxs[fn] = context.memfilectx(fn, mergedtext)
1522
1525
1523 if overwritten_file:
1526 if overwritten_file:
1524 fn = "of"
1527 fn = "of"
1525 files.append(fn)
1528 files.append(fn)
1526 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1529 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1527
1530
1528 if new_file:
1531 if new_file:
1529 fn = "nf%i" % id
1532 fn = "nf%i" % id
1530 files.append(fn)
1533 files.append(fn)
1531 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1534 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1532 if len(ps) > 1:
1535 if len(ps) > 1:
1533 if not p2:
1536 if not p2:
1534 p2 = repo[ps[1]]
1537 p2 = repo[ps[1]]
1535 for fn in p2:
1538 for fn in p2:
1536 if fn.startswith("nf"):
1539 if fn.startswith("nf"):
1537 files.append(fn)
1540 files.append(fn)
1538 fctxs[fn] = p2[fn]
1541 fctxs[fn] = p2[fn]
1539
1542
1540 def fctxfn(repo, cx, path):
1543 def fctxfn(repo, cx, path):
1541 return fctxs.get(path)
1544 return fctxs.get(path)
1542
1545
1543 if len(ps) == 0 or ps[0] < 0:
1546 if len(ps) == 0 or ps[0] < 0:
1544 pars = [None, None]
1547 pars = [None, None]
1545 elif len(ps) == 1:
1548 elif len(ps) == 1:
1546 pars = [nodeids[ps[0]], None]
1549 pars = [nodeids[ps[0]], None]
1547 else:
1550 else:
1548 pars = [nodeids[p] for p in ps]
1551 pars = [nodeids[p] for p in ps]
1549 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1552 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1550 date=(id, 0),
1553 date=(id, 0),
1551 user="debugbuilddag",
1554 user="debugbuilddag",
1552 extra={'branch': atbranch})
1555 extra={'branch': atbranch})
1553 nodeid = repo.commitctx(cx)
1556 nodeid = repo.commitctx(cx)
1554 nodeids.append(nodeid)
1557 nodeids.append(nodeid)
1555 at = id
1558 at = id
1556 elif type == 'l':
1559 elif type == 'l':
1557 id, name = data
1560 id, name = data
1558 ui.note(('tag %s\n' % name))
1561 ui.note(('tag %s\n' % name))
1559 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1562 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1560 elif type == 'a':
1563 elif type == 'a':
1561 ui.note(('branch %s\n' % data))
1564 ui.note(('branch %s\n' % data))
1562 atbranch = data
1565 atbranch = data
1563 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1566 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1564 tr.close()
1567 tr.close()
1565
1568
1566 if tags:
1569 if tags:
1567 repo.opener.write("localtags", "".join(tags))
1570 repo.opener.write("localtags", "".join(tags))
1568 finally:
1571 finally:
1569 ui.progress(_('building'), None)
1572 ui.progress(_('building'), None)
1570 release(tr, lock)
1573 release(tr, lock)
1571
1574
1572 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1575 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1573 def debugbundle(ui, bundlepath, all=None, **opts):
1576 def debugbundle(ui, bundlepath, all=None, **opts):
1574 """lists the contents of a bundle"""
1577 """lists the contents of a bundle"""
1575 f = hg.openpath(ui, bundlepath)
1578 f = hg.openpath(ui, bundlepath)
1576 try:
1579 try:
1577 gen = changegroup.readbundle(f, bundlepath)
1580 gen = changegroup.readbundle(f, bundlepath)
1578 if all:
1581 if all:
1579 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1582 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1580
1583
1581 def showchunks(named):
1584 def showchunks(named):
1582 ui.write("\n%s\n" % named)
1585 ui.write("\n%s\n" % named)
1583 chain = None
1586 chain = None
1584 while True:
1587 while True:
1585 chunkdata = gen.deltachunk(chain)
1588 chunkdata = gen.deltachunk(chain)
1586 if not chunkdata:
1589 if not chunkdata:
1587 break
1590 break
1588 node = chunkdata['node']
1591 node = chunkdata['node']
1589 p1 = chunkdata['p1']
1592 p1 = chunkdata['p1']
1590 p2 = chunkdata['p2']
1593 p2 = chunkdata['p2']
1591 cs = chunkdata['cs']
1594 cs = chunkdata['cs']
1592 deltabase = chunkdata['deltabase']
1595 deltabase = chunkdata['deltabase']
1593 delta = chunkdata['delta']
1596 delta = chunkdata['delta']
1594 ui.write("%s %s %s %s %s %s\n" %
1597 ui.write("%s %s %s %s %s %s\n" %
1595 (hex(node), hex(p1), hex(p2),
1598 (hex(node), hex(p1), hex(p2),
1596 hex(cs), hex(deltabase), len(delta)))
1599 hex(cs), hex(deltabase), len(delta)))
1597 chain = node
1600 chain = node
1598
1601
1599 chunkdata = gen.changelogheader()
1602 chunkdata = gen.changelogheader()
1600 showchunks("changelog")
1603 showchunks("changelog")
1601 chunkdata = gen.manifestheader()
1604 chunkdata = gen.manifestheader()
1602 showchunks("manifest")
1605 showchunks("manifest")
1603 while True:
1606 while True:
1604 chunkdata = gen.filelogheader()
1607 chunkdata = gen.filelogheader()
1605 if not chunkdata:
1608 if not chunkdata:
1606 break
1609 break
1607 fname = chunkdata['filename']
1610 fname = chunkdata['filename']
1608 showchunks(fname)
1611 showchunks(fname)
1609 else:
1612 else:
1610 chunkdata = gen.changelogheader()
1613 chunkdata = gen.changelogheader()
1611 chain = None
1614 chain = None
1612 while True:
1615 while True:
1613 chunkdata = gen.deltachunk(chain)
1616 chunkdata = gen.deltachunk(chain)
1614 if not chunkdata:
1617 if not chunkdata:
1615 break
1618 break
1616 node = chunkdata['node']
1619 node = chunkdata['node']
1617 ui.write("%s\n" % hex(node))
1620 ui.write("%s\n" % hex(node))
1618 chain = node
1621 chain = node
1619 finally:
1622 finally:
1620 f.close()
1623 f.close()
1621
1624
1622 @command('debugcheckstate', [], '')
1625 @command('debugcheckstate', [], '')
1623 def debugcheckstate(ui, repo):
1626 def debugcheckstate(ui, repo):
1624 """validate the correctness of the current dirstate"""
1627 """validate the correctness of the current dirstate"""
1625 parent1, parent2 = repo.dirstate.parents()
1628 parent1, parent2 = repo.dirstate.parents()
1626 m1 = repo[parent1].manifest()
1629 m1 = repo[parent1].manifest()
1627 m2 = repo[parent2].manifest()
1630 m2 = repo[parent2].manifest()
1628 errors = 0
1631 errors = 0
1629 for f in repo.dirstate:
1632 for f in repo.dirstate:
1630 state = repo.dirstate[f]
1633 state = repo.dirstate[f]
1631 if state in "nr" and f not in m1:
1634 if state in "nr" and f not in m1:
1632 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1635 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1633 errors += 1
1636 errors += 1
1634 if state in "a" and f in m1:
1637 if state in "a" and f in m1:
1635 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1638 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1636 errors += 1
1639 errors += 1
1637 if state in "m" and f not in m1 and f not in m2:
1640 if state in "m" and f not in m1 and f not in m2:
1638 ui.warn(_("%s in state %s, but not in either manifest\n") %
1641 ui.warn(_("%s in state %s, but not in either manifest\n") %
1639 (f, state))
1642 (f, state))
1640 errors += 1
1643 errors += 1
1641 for f in m1:
1644 for f in m1:
1642 state = repo.dirstate[f]
1645 state = repo.dirstate[f]
1643 if state not in "nrm":
1646 if state not in "nrm":
1644 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1647 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1645 errors += 1
1648 errors += 1
1646 if errors:
1649 if errors:
1647 error = _(".hg/dirstate inconsistent with current parent's manifest")
1650 error = _(".hg/dirstate inconsistent with current parent's manifest")
1648 raise util.Abort(error)
1651 raise util.Abort(error)
1649
1652
1650 @command('debugcommands', [], _('[COMMAND]'))
1653 @command('debugcommands', [], _('[COMMAND]'))
1651 def debugcommands(ui, cmd='', *args):
1654 def debugcommands(ui, cmd='', *args):
1652 """list all available commands and options"""
1655 """list all available commands and options"""
1653 for cmd, vals in sorted(table.iteritems()):
1656 for cmd, vals in sorted(table.iteritems()):
1654 cmd = cmd.split('|')[0].strip('^')
1657 cmd = cmd.split('|')[0].strip('^')
1655 opts = ', '.join([i[1] for i in vals[1]])
1658 opts = ', '.join([i[1] for i in vals[1]])
1656 ui.write('%s: %s\n' % (cmd, opts))
1659 ui.write('%s: %s\n' % (cmd, opts))
1657
1660
1658 @command('debugcomplete',
1661 @command('debugcomplete',
1659 [('o', 'options', None, _('show the command options'))],
1662 [('o', 'options', None, _('show the command options'))],
1660 _('[-o] CMD'))
1663 _('[-o] CMD'))
1661 def debugcomplete(ui, cmd='', **opts):
1664 def debugcomplete(ui, cmd='', **opts):
1662 """returns the completion list associated with the given command"""
1665 """returns the completion list associated with the given command"""
1663
1666
1664 if opts.get('options'):
1667 if opts.get('options'):
1665 options = []
1668 options = []
1666 otables = [globalopts]
1669 otables = [globalopts]
1667 if cmd:
1670 if cmd:
1668 aliases, entry = cmdutil.findcmd(cmd, table, False)
1671 aliases, entry = cmdutil.findcmd(cmd, table, False)
1669 otables.append(entry[1])
1672 otables.append(entry[1])
1670 for t in otables:
1673 for t in otables:
1671 for o in t:
1674 for o in t:
1672 if "(DEPRECATED)" in o[3]:
1675 if "(DEPRECATED)" in o[3]:
1673 continue
1676 continue
1674 if o[0]:
1677 if o[0]:
1675 options.append('-%s' % o[0])
1678 options.append('-%s' % o[0])
1676 options.append('--%s' % o[1])
1679 options.append('--%s' % o[1])
1677 ui.write("%s\n" % "\n".join(options))
1680 ui.write("%s\n" % "\n".join(options))
1678 return
1681 return
1679
1682
1680 cmdlist = cmdutil.findpossible(cmd, table)
1683 cmdlist = cmdutil.findpossible(cmd, table)
1681 if ui.verbose:
1684 if ui.verbose:
1682 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1685 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1683 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1686 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1684
1687
1685 @command('debugdag',
1688 @command('debugdag',
1686 [('t', 'tags', None, _('use tags as labels')),
1689 [('t', 'tags', None, _('use tags as labels')),
1687 ('b', 'branches', None, _('annotate with branch names')),
1690 ('b', 'branches', None, _('annotate with branch names')),
1688 ('', 'dots', None, _('use dots for runs')),
1691 ('', 'dots', None, _('use dots for runs')),
1689 ('s', 'spaces', None, _('separate elements by spaces'))],
1692 ('s', 'spaces', None, _('separate elements by spaces'))],
1690 _('[OPTION]... [FILE [REV]...]'))
1693 _('[OPTION]... [FILE [REV]...]'))
1691 def debugdag(ui, repo, file_=None, *revs, **opts):
1694 def debugdag(ui, repo, file_=None, *revs, **opts):
1692 """format the changelog or an index DAG as a concise textual description
1695 """format the changelog or an index DAG as a concise textual description
1693
1696
1694 If you pass a revlog index, the revlog's DAG is emitted. If you list
1697 If you pass a revlog index, the revlog's DAG is emitted. If you list
1695 revision numbers, they get labeled in the output as rN.
1698 revision numbers, they get labeled in the output as rN.
1696
1699
1697 Otherwise, the changelog DAG of the current repo is emitted.
1700 Otherwise, the changelog DAG of the current repo is emitted.
1698 """
1701 """
1699 spaces = opts.get('spaces')
1702 spaces = opts.get('spaces')
1700 dots = opts.get('dots')
1703 dots = opts.get('dots')
1701 if file_:
1704 if file_:
1702 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1705 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1703 revs = set((int(r) for r in revs))
1706 revs = set((int(r) for r in revs))
1704 def events():
1707 def events():
1705 for r in rlog:
1708 for r in rlog:
1706 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1709 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1707 if p != -1)))
1710 if p != -1)))
1708 if r in revs:
1711 if r in revs:
1709 yield 'l', (r, "r%i" % r)
1712 yield 'l', (r, "r%i" % r)
1710 elif repo:
1713 elif repo:
1711 cl = repo.changelog
1714 cl = repo.changelog
1712 tags = opts.get('tags')
1715 tags = opts.get('tags')
1713 branches = opts.get('branches')
1716 branches = opts.get('branches')
1714 if tags:
1717 if tags:
1715 labels = {}
1718 labels = {}
1716 for l, n in repo.tags().items():
1719 for l, n in repo.tags().items():
1717 labels.setdefault(cl.rev(n), []).append(l)
1720 labels.setdefault(cl.rev(n), []).append(l)
1718 def events():
1721 def events():
1719 b = "default"
1722 b = "default"
1720 for r in cl:
1723 for r in cl:
1721 if branches:
1724 if branches:
1722 newb = cl.read(cl.node(r))[5]['branch']
1725 newb = cl.read(cl.node(r))[5]['branch']
1723 if newb != b:
1726 if newb != b:
1724 yield 'a', newb
1727 yield 'a', newb
1725 b = newb
1728 b = newb
1726 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1729 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1727 if p != -1)))
1730 if p != -1)))
1728 if tags:
1731 if tags:
1729 ls = labels.get(r)
1732 ls = labels.get(r)
1730 if ls:
1733 if ls:
1731 for l in ls:
1734 for l in ls:
1732 yield 'l', (r, l)
1735 yield 'l', (r, l)
1733 else:
1736 else:
1734 raise util.Abort(_('need repo for changelog dag'))
1737 raise util.Abort(_('need repo for changelog dag'))
1735
1738
1736 for line in dagparser.dagtextlines(events(),
1739 for line in dagparser.dagtextlines(events(),
1737 addspaces=spaces,
1740 addspaces=spaces,
1738 wraplabels=True,
1741 wraplabels=True,
1739 wrapannotations=True,
1742 wrapannotations=True,
1740 wrapnonlinear=dots,
1743 wrapnonlinear=dots,
1741 usedots=dots,
1744 usedots=dots,
1742 maxlinewidth=70):
1745 maxlinewidth=70):
1743 ui.write(line)
1746 ui.write(line)
1744 ui.write("\n")
1747 ui.write("\n")
1745
1748
1746 @command('debugdata',
1749 @command('debugdata',
1747 [('c', 'changelog', False, _('open changelog')),
1750 [('c', 'changelog', False, _('open changelog')),
1748 ('m', 'manifest', False, _('open manifest'))],
1751 ('m', 'manifest', False, _('open manifest'))],
1749 _('-c|-m|FILE REV'))
1752 _('-c|-m|FILE REV'))
1750 def debugdata(ui, repo, file_, rev = None, **opts):
1753 def debugdata(ui, repo, file_, rev = None, **opts):
1751 """dump the contents of a data file revision"""
1754 """dump the contents of a data file revision"""
1752 if opts.get('changelog') or opts.get('manifest'):
1755 if opts.get('changelog') or opts.get('manifest'):
1753 file_, rev = None, file_
1756 file_, rev = None, file_
1754 elif rev is None:
1757 elif rev is None:
1755 raise error.CommandError('debugdata', _('invalid arguments'))
1758 raise error.CommandError('debugdata', _('invalid arguments'))
1756 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1759 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1757 try:
1760 try:
1758 ui.write(r.revision(r.lookup(rev)))
1761 ui.write(r.revision(r.lookup(rev)))
1759 except KeyError:
1762 except KeyError:
1760 raise util.Abort(_('invalid revision identifier %s') % rev)
1763 raise util.Abort(_('invalid revision identifier %s') % rev)
1761
1764
1762 @command('debugdate',
1765 @command('debugdate',
1763 [('e', 'extended', None, _('try extended date formats'))],
1766 [('e', 'extended', None, _('try extended date formats'))],
1764 _('[-e] DATE [RANGE]'))
1767 _('[-e] DATE [RANGE]'))
1765 def debugdate(ui, date, range=None, **opts):
1768 def debugdate(ui, date, range=None, **opts):
1766 """parse and display a date"""
1769 """parse and display a date"""
1767 if opts["extended"]:
1770 if opts["extended"]:
1768 d = util.parsedate(date, util.extendeddateformats)
1771 d = util.parsedate(date, util.extendeddateformats)
1769 else:
1772 else:
1770 d = util.parsedate(date)
1773 d = util.parsedate(date)
1771 ui.write(("internal: %s %s\n") % d)
1774 ui.write(("internal: %s %s\n") % d)
1772 ui.write(("standard: %s\n") % util.datestr(d))
1775 ui.write(("standard: %s\n") % util.datestr(d))
1773 if range:
1776 if range:
1774 m = util.matchdate(range)
1777 m = util.matchdate(range)
1775 ui.write(("match: %s\n") % m(d[0]))
1778 ui.write(("match: %s\n") % m(d[0]))
1776
1779
1777 @command('debugdiscovery',
1780 @command('debugdiscovery',
1778 [('', 'old', None, _('use old-style discovery')),
1781 [('', 'old', None, _('use old-style discovery')),
1779 ('', 'nonheads', None,
1782 ('', 'nonheads', None,
1780 _('use old-style discovery with non-heads included')),
1783 _('use old-style discovery with non-heads included')),
1781 ] + remoteopts,
1784 ] + remoteopts,
1782 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1785 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1783 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1786 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1784 """runs the changeset discovery protocol in isolation"""
1787 """runs the changeset discovery protocol in isolation"""
1785 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1788 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1786 opts.get('branch'))
1789 opts.get('branch'))
1787 remote = hg.peer(repo, opts, remoteurl)
1790 remote = hg.peer(repo, opts, remoteurl)
1788 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1791 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1789
1792
1790 # make sure tests are repeatable
1793 # make sure tests are repeatable
1791 random.seed(12323)
1794 random.seed(12323)
1792
1795
1793 def doit(localheads, remoteheads, remote=remote):
1796 def doit(localheads, remoteheads, remote=remote):
1794 if opts.get('old'):
1797 if opts.get('old'):
1795 if localheads:
1798 if localheads:
1796 raise util.Abort('cannot use localheads with old style '
1799 raise util.Abort('cannot use localheads with old style '
1797 'discovery')
1800 'discovery')
1798 if not util.safehasattr(remote, 'branches'):
1801 if not util.safehasattr(remote, 'branches'):
1799 # enable in-client legacy support
1802 # enable in-client legacy support
1800 remote = localrepo.locallegacypeer(remote.local())
1803 remote = localrepo.locallegacypeer(remote.local())
1801 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1804 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1802 force=True)
1805 force=True)
1803 common = set(common)
1806 common = set(common)
1804 if not opts.get('nonheads'):
1807 if not opts.get('nonheads'):
1805 ui.write(("unpruned common: %s\n") %
1808 ui.write(("unpruned common: %s\n") %
1806 " ".join(sorted(short(n) for n in common)))
1809 " ".join(sorted(short(n) for n in common)))
1807 dag = dagutil.revlogdag(repo.changelog)
1810 dag = dagutil.revlogdag(repo.changelog)
1808 all = dag.ancestorset(dag.internalizeall(common))
1811 all = dag.ancestorset(dag.internalizeall(common))
1809 common = dag.externalizeall(dag.headsetofconnecteds(all))
1812 common = dag.externalizeall(dag.headsetofconnecteds(all))
1810 else:
1813 else:
1811 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1814 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1812 common = set(common)
1815 common = set(common)
1813 rheads = set(hds)
1816 rheads = set(hds)
1814 lheads = set(repo.heads())
1817 lheads = set(repo.heads())
1815 ui.write(("common heads: %s\n") %
1818 ui.write(("common heads: %s\n") %
1816 " ".join(sorted(short(n) for n in common)))
1819 " ".join(sorted(short(n) for n in common)))
1817 if lheads <= common:
1820 if lheads <= common:
1818 ui.write(("local is subset\n"))
1821 ui.write(("local is subset\n"))
1819 elif rheads <= common:
1822 elif rheads <= common:
1820 ui.write(("remote is subset\n"))
1823 ui.write(("remote is subset\n"))
1821
1824
1822 serverlogs = opts.get('serverlog')
1825 serverlogs = opts.get('serverlog')
1823 if serverlogs:
1826 if serverlogs:
1824 for filename in serverlogs:
1827 for filename in serverlogs:
1825 logfile = open(filename, 'r')
1828 logfile = open(filename, 'r')
1826 try:
1829 try:
1827 line = logfile.readline()
1830 line = logfile.readline()
1828 while line:
1831 while line:
1829 parts = line.strip().split(';')
1832 parts = line.strip().split(';')
1830 op = parts[1]
1833 op = parts[1]
1831 if op == 'cg':
1834 if op == 'cg':
1832 pass
1835 pass
1833 elif op == 'cgss':
1836 elif op == 'cgss':
1834 doit(parts[2].split(' '), parts[3].split(' '))
1837 doit(parts[2].split(' '), parts[3].split(' '))
1835 elif op == 'unb':
1838 elif op == 'unb':
1836 doit(parts[3].split(' '), parts[2].split(' '))
1839 doit(parts[3].split(' '), parts[2].split(' '))
1837 line = logfile.readline()
1840 line = logfile.readline()
1838 finally:
1841 finally:
1839 logfile.close()
1842 logfile.close()
1840
1843
1841 else:
1844 else:
1842 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1845 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1843 opts.get('remote_head'))
1846 opts.get('remote_head'))
1844 localrevs = opts.get('local_head')
1847 localrevs = opts.get('local_head')
1845 doit(localrevs, remoterevs)
1848 doit(localrevs, remoterevs)
1846
1849
1847 @command('debugfileset',
1850 @command('debugfileset',
1848 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1851 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1849 _('[-r REV] FILESPEC'))
1852 _('[-r REV] FILESPEC'))
1850 def debugfileset(ui, repo, expr, **opts):
1853 def debugfileset(ui, repo, expr, **opts):
1851 '''parse and apply a fileset specification'''
1854 '''parse and apply a fileset specification'''
1852 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1855 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1853 if ui.verbose:
1856 if ui.verbose:
1854 tree = fileset.parse(expr)[0]
1857 tree = fileset.parse(expr)[0]
1855 ui.note(tree, "\n")
1858 ui.note(tree, "\n")
1856
1859
1857 for f in fileset.getfileset(ctx, expr):
1860 for f in fileset.getfileset(ctx, expr):
1858 ui.write("%s\n" % f)
1861 ui.write("%s\n" % f)
1859
1862
1860 @command('debugfsinfo', [], _('[PATH]'))
1863 @command('debugfsinfo', [], _('[PATH]'))
1861 def debugfsinfo(ui, path = "."):
1864 def debugfsinfo(ui, path = "."):
1862 """show information detected about current filesystem"""
1865 """show information detected about current filesystem"""
1863 util.writefile('.debugfsinfo', '')
1866 util.writefile('.debugfsinfo', '')
1864 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1867 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1865 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1868 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1866 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1869 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1867 and 'yes' or 'no'))
1870 and 'yes' or 'no'))
1868 os.unlink('.debugfsinfo')
1871 os.unlink('.debugfsinfo')
1869
1872
1870 @command('debuggetbundle',
1873 @command('debuggetbundle',
1871 [('H', 'head', [], _('id of head node'), _('ID')),
1874 [('H', 'head', [], _('id of head node'), _('ID')),
1872 ('C', 'common', [], _('id of common node'), _('ID')),
1875 ('C', 'common', [], _('id of common node'), _('ID')),
1873 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1876 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1874 _('REPO FILE [-H|-C ID]...'))
1877 _('REPO FILE [-H|-C ID]...'))
1875 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1878 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1876 """retrieves a bundle from a repo
1879 """retrieves a bundle from a repo
1877
1880
1878 Every ID must be a full-length hex node id string. Saves the bundle to the
1881 Every ID must be a full-length hex node id string. Saves the bundle to the
1879 given file.
1882 given file.
1880 """
1883 """
1881 repo = hg.peer(ui, opts, repopath)
1884 repo = hg.peer(ui, opts, repopath)
1882 if not repo.capable('getbundle'):
1885 if not repo.capable('getbundle'):
1883 raise util.Abort("getbundle() not supported by target repository")
1886 raise util.Abort("getbundle() not supported by target repository")
1884 args = {}
1887 args = {}
1885 if common:
1888 if common:
1886 args['common'] = [bin(s) for s in common]
1889 args['common'] = [bin(s) for s in common]
1887 if head:
1890 if head:
1888 args['heads'] = [bin(s) for s in head]
1891 args['heads'] = [bin(s) for s in head]
1889 bundle = repo.getbundle('debug', **args)
1892 bundle = repo.getbundle('debug', **args)
1890
1893
1891 bundletype = opts.get('type', 'bzip2').lower()
1894 bundletype = opts.get('type', 'bzip2').lower()
1892 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1895 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1893 bundletype = btypes.get(bundletype)
1896 bundletype = btypes.get(bundletype)
1894 if bundletype not in changegroup.bundletypes:
1897 if bundletype not in changegroup.bundletypes:
1895 raise util.Abort(_('unknown bundle type specified with --type'))
1898 raise util.Abort(_('unknown bundle type specified with --type'))
1896 changegroup.writebundle(bundle, bundlepath, bundletype)
1899 changegroup.writebundle(bundle, bundlepath, bundletype)
1897
1900
1898 @command('debugignore', [], '')
1901 @command('debugignore', [], '')
1899 def debugignore(ui, repo, *values, **opts):
1902 def debugignore(ui, repo, *values, **opts):
1900 """display the combined ignore pattern"""
1903 """display the combined ignore pattern"""
1901 ignore = repo.dirstate._ignore
1904 ignore = repo.dirstate._ignore
1902 includepat = getattr(ignore, 'includepat', None)
1905 includepat = getattr(ignore, 'includepat', None)
1903 if includepat is not None:
1906 if includepat is not None:
1904 ui.write("%s\n" % includepat)
1907 ui.write("%s\n" % includepat)
1905 else:
1908 else:
1906 raise util.Abort(_("no ignore patterns found"))
1909 raise util.Abort(_("no ignore patterns found"))
1907
1910
1908 @command('debugindex',
1911 @command('debugindex',
1909 [('c', 'changelog', False, _('open changelog')),
1912 [('c', 'changelog', False, _('open changelog')),
1910 ('m', 'manifest', False, _('open manifest')),
1913 ('m', 'manifest', False, _('open manifest')),
1911 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1914 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1912 _('[-f FORMAT] -c|-m|FILE'))
1915 _('[-f FORMAT] -c|-m|FILE'))
1913 def debugindex(ui, repo, file_ = None, **opts):
1916 def debugindex(ui, repo, file_ = None, **opts):
1914 """dump the contents of an index file"""
1917 """dump the contents of an index file"""
1915 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1918 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1916 format = opts.get('format', 0)
1919 format = opts.get('format', 0)
1917 if format not in (0, 1):
1920 if format not in (0, 1):
1918 raise util.Abort(_("unknown format %d") % format)
1921 raise util.Abort(_("unknown format %d") % format)
1919
1922
1920 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1923 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1921 if generaldelta:
1924 if generaldelta:
1922 basehdr = ' delta'
1925 basehdr = ' delta'
1923 else:
1926 else:
1924 basehdr = ' base'
1927 basehdr = ' base'
1925
1928
1926 if format == 0:
1929 if format == 0:
1927 ui.write(" rev offset length " + basehdr + " linkrev"
1930 ui.write(" rev offset length " + basehdr + " linkrev"
1928 " nodeid p1 p2\n")
1931 " nodeid p1 p2\n")
1929 elif format == 1:
1932 elif format == 1:
1930 ui.write(" rev flag offset length"
1933 ui.write(" rev flag offset length"
1931 " size " + basehdr + " link p1 p2"
1934 " size " + basehdr + " link p1 p2"
1932 " nodeid\n")
1935 " nodeid\n")
1933
1936
1934 for i in r:
1937 for i in r:
1935 node = r.node(i)
1938 node = r.node(i)
1936 if generaldelta:
1939 if generaldelta:
1937 base = r.deltaparent(i)
1940 base = r.deltaparent(i)
1938 else:
1941 else:
1939 base = r.chainbase(i)
1942 base = r.chainbase(i)
1940 if format == 0:
1943 if format == 0:
1941 try:
1944 try:
1942 pp = r.parents(node)
1945 pp = r.parents(node)
1943 except Exception:
1946 except Exception:
1944 pp = [nullid, nullid]
1947 pp = [nullid, nullid]
1945 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1948 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1946 i, r.start(i), r.length(i), base, r.linkrev(i),
1949 i, r.start(i), r.length(i), base, r.linkrev(i),
1947 short(node), short(pp[0]), short(pp[1])))
1950 short(node), short(pp[0]), short(pp[1])))
1948 elif format == 1:
1951 elif format == 1:
1949 pr = r.parentrevs(i)
1952 pr = r.parentrevs(i)
1950 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1953 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1951 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1954 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1952 base, r.linkrev(i), pr[0], pr[1], short(node)))
1955 base, r.linkrev(i), pr[0], pr[1], short(node)))
1953
1956
1954 @command('debugindexdot', [], _('FILE'))
1957 @command('debugindexdot', [], _('FILE'))
1955 def debugindexdot(ui, repo, file_):
1958 def debugindexdot(ui, repo, file_):
1956 """dump an index DAG as a graphviz dot file"""
1959 """dump an index DAG as a graphviz dot file"""
1957 r = None
1960 r = None
1958 if repo:
1961 if repo:
1959 filelog = repo.file(file_)
1962 filelog = repo.file(file_)
1960 if len(filelog):
1963 if len(filelog):
1961 r = filelog
1964 r = filelog
1962 if not r:
1965 if not r:
1963 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1966 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1964 ui.write(("digraph G {\n"))
1967 ui.write(("digraph G {\n"))
1965 for i in r:
1968 for i in r:
1966 node = r.node(i)
1969 node = r.node(i)
1967 pp = r.parents(node)
1970 pp = r.parents(node)
1968 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1971 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1969 if pp[1] != nullid:
1972 if pp[1] != nullid:
1970 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1973 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1971 ui.write("}\n")
1974 ui.write("}\n")
1972
1975
1973 @command('debuginstall', [], '')
1976 @command('debuginstall', [], '')
1974 def debuginstall(ui):
1977 def debuginstall(ui):
1975 '''test Mercurial installation
1978 '''test Mercurial installation
1976
1979
1977 Returns 0 on success.
1980 Returns 0 on success.
1978 '''
1981 '''
1979
1982
1980 def writetemp(contents):
1983 def writetemp(contents):
1981 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1984 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1982 f = os.fdopen(fd, "wb")
1985 f = os.fdopen(fd, "wb")
1983 f.write(contents)
1986 f.write(contents)
1984 f.close()
1987 f.close()
1985 return name
1988 return name
1986
1989
1987 problems = 0
1990 problems = 0
1988
1991
1989 # encoding
1992 # encoding
1990 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1993 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1991 try:
1994 try:
1992 encoding.fromlocal("test")
1995 encoding.fromlocal("test")
1993 except util.Abort, inst:
1996 except util.Abort, inst:
1994 ui.write(" %s\n" % inst)
1997 ui.write(" %s\n" % inst)
1995 ui.write(_(" (check that your locale is properly set)\n"))
1998 ui.write(_(" (check that your locale is properly set)\n"))
1996 problems += 1
1999 problems += 1
1997
2000
1998 # Python lib
2001 # Python lib
1999 ui.status(_("checking Python lib (%s)...\n")
2002 ui.status(_("checking Python lib (%s)...\n")
2000 % os.path.dirname(os.__file__))
2003 % os.path.dirname(os.__file__))
2001
2004
2002 # compiled modules
2005 # compiled modules
2003 ui.status(_("checking installed modules (%s)...\n")
2006 ui.status(_("checking installed modules (%s)...\n")
2004 % os.path.dirname(__file__))
2007 % os.path.dirname(__file__))
2005 try:
2008 try:
2006 import bdiff, mpatch, base85, osutil
2009 import bdiff, mpatch, base85, osutil
2007 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2010 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2008 except Exception, inst:
2011 except Exception, inst:
2009 ui.write(" %s\n" % inst)
2012 ui.write(" %s\n" % inst)
2010 ui.write(_(" One or more extensions could not be found"))
2013 ui.write(_(" One or more extensions could not be found"))
2011 ui.write(_(" (check that you compiled the extensions)\n"))
2014 ui.write(_(" (check that you compiled the extensions)\n"))
2012 problems += 1
2015 problems += 1
2013
2016
2014 # templates
2017 # templates
2015 import templater
2018 import templater
2016 p = templater.templatepath()
2019 p = templater.templatepath()
2017 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2020 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2018 try:
2021 try:
2019 templater.templater(templater.templatepath("map-cmdline.default"))
2022 templater.templater(templater.templatepath("map-cmdline.default"))
2020 except Exception, inst:
2023 except Exception, inst:
2021 ui.write(" %s\n" % inst)
2024 ui.write(" %s\n" % inst)
2022 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2025 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2023 problems += 1
2026 problems += 1
2024
2027
2025 # editor
2028 # editor
2026 ui.status(_("checking commit editor...\n"))
2029 ui.status(_("checking commit editor...\n"))
2027 editor = ui.geteditor()
2030 editor = ui.geteditor()
2028 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2031 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2029 if not cmdpath:
2032 if not cmdpath:
2030 if editor == 'vi':
2033 if editor == 'vi':
2031 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2034 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2032 ui.write(_(" (specify a commit editor in your configuration"
2035 ui.write(_(" (specify a commit editor in your configuration"
2033 " file)\n"))
2036 " file)\n"))
2034 else:
2037 else:
2035 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2038 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2036 ui.write(_(" (specify a commit editor in your configuration"
2039 ui.write(_(" (specify a commit editor in your configuration"
2037 " file)\n"))
2040 " file)\n"))
2038 problems += 1
2041 problems += 1
2039
2042
2040 # check username
2043 # check username
2041 ui.status(_("checking username...\n"))
2044 ui.status(_("checking username...\n"))
2042 try:
2045 try:
2043 ui.username()
2046 ui.username()
2044 except util.Abort, e:
2047 except util.Abort, e:
2045 ui.write(" %s\n" % e)
2048 ui.write(" %s\n" % e)
2046 ui.write(_(" (specify a username in your configuration file)\n"))
2049 ui.write(_(" (specify a username in your configuration file)\n"))
2047 problems += 1
2050 problems += 1
2048
2051
2049 if not problems:
2052 if not problems:
2050 ui.status(_("no problems detected\n"))
2053 ui.status(_("no problems detected\n"))
2051 else:
2054 else:
2052 ui.write(_("%s problems detected,"
2055 ui.write(_("%s problems detected,"
2053 " please check your install!\n") % problems)
2056 " please check your install!\n") % problems)
2054
2057
2055 return problems
2058 return problems
2056
2059
2057 @command('debugknown', [], _('REPO ID...'))
2060 @command('debugknown', [], _('REPO ID...'))
2058 def debugknown(ui, repopath, *ids, **opts):
2061 def debugknown(ui, repopath, *ids, **opts):
2059 """test whether node ids are known to a repo
2062 """test whether node ids are known to a repo
2060
2063
2061 Every ID must be a full-length hex node id string. Returns a list of 0s
2064 Every ID must be a full-length hex node id string. Returns a list of 0s
2062 and 1s indicating unknown/known.
2065 and 1s indicating unknown/known.
2063 """
2066 """
2064 repo = hg.peer(ui, opts, repopath)
2067 repo = hg.peer(ui, opts, repopath)
2065 if not repo.capable('known'):
2068 if not repo.capable('known'):
2066 raise util.Abort("known() not supported by target repository")
2069 raise util.Abort("known() not supported by target repository")
2067 flags = repo.known([bin(s) for s in ids])
2070 flags = repo.known([bin(s) for s in ids])
2068 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2071 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2069
2072
2070 @command('debugobsolete',
2073 @command('debugobsolete',
2071 [('', 'flags', 0, _('markers flag')),
2074 [('', 'flags', 0, _('markers flag')),
2072 ] + commitopts2,
2075 ] + commitopts2,
2073 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2076 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2074 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2077 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2075 """create arbitrary obsolete marker
2078 """create arbitrary obsolete marker
2076
2079
2077 With no arguments it it display the list obsolescence marker."""
2080 With no arguments it it display the list obsolescence marker."""
2078 def parsenodeid(s):
2081 def parsenodeid(s):
2079 try:
2082 try:
2080 # We do not use revsingle/revrange functions here to accept
2083 # We do not use revsingle/revrange functions here to accept
2081 # arbitrary node identifiers, possibly not present in the
2084 # arbitrary node identifiers, possibly not present in the
2082 # local repository.
2085 # local repository.
2083 n = bin(s)
2086 n = bin(s)
2084 if len(n) != len(nullid):
2087 if len(n) != len(nullid):
2085 raise TypeError()
2088 raise TypeError()
2086 return n
2089 return n
2087 except TypeError:
2090 except TypeError:
2088 raise util.Abort('changeset references must be full hexadecimal '
2091 raise util.Abort('changeset references must be full hexadecimal '
2089 'node identifiers')
2092 'node identifiers')
2090
2093
2091 if precursor is not None:
2094 if precursor is not None:
2092 metadata = {}
2095 metadata = {}
2093 if 'date' in opts:
2096 if 'date' in opts:
2094 metadata['date'] = opts['date']
2097 metadata['date'] = opts['date']
2095 metadata['user'] = opts['user'] or ui.username()
2098 metadata['user'] = opts['user'] or ui.username()
2096 succs = tuple(parsenodeid(succ) for succ in successors)
2099 succs = tuple(parsenodeid(succ) for succ in successors)
2097 l = repo.lock()
2100 l = repo.lock()
2098 try:
2101 try:
2099 tr = repo.transaction('debugobsolete')
2102 tr = repo.transaction('debugobsolete')
2100 try:
2103 try:
2101 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2104 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2102 opts['flags'], metadata)
2105 opts['flags'], metadata)
2103 tr.close()
2106 tr.close()
2104 finally:
2107 finally:
2105 tr.release()
2108 tr.release()
2106 finally:
2109 finally:
2107 l.release()
2110 l.release()
2108 else:
2111 else:
2109 for m in obsolete.allmarkers(repo):
2112 for m in obsolete.allmarkers(repo):
2110 ui.write(hex(m.precnode()))
2113 ui.write(hex(m.precnode()))
2111 for repl in m.succnodes():
2114 for repl in m.succnodes():
2112 ui.write(' ')
2115 ui.write(' ')
2113 ui.write(hex(repl))
2116 ui.write(hex(repl))
2114 ui.write(' %X ' % m._data[2])
2117 ui.write(' %X ' % m._data[2])
2115 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2118 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2116 sorted(m.metadata().items()))))
2119 sorted(m.metadata().items()))))
2117 ui.write('\n')
2120 ui.write('\n')
2118
2121
2119 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2122 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2120 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2123 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2121 '''access the pushkey key/value protocol
2124 '''access the pushkey key/value protocol
2122
2125
2123 With two args, list the keys in the given namespace.
2126 With two args, list the keys in the given namespace.
2124
2127
2125 With five args, set a key to new if it currently is set to old.
2128 With five args, set a key to new if it currently is set to old.
2126 Reports success or failure.
2129 Reports success or failure.
2127 '''
2130 '''
2128
2131
2129 target = hg.peer(ui, {}, repopath)
2132 target = hg.peer(ui, {}, repopath)
2130 if keyinfo:
2133 if keyinfo:
2131 key, old, new = keyinfo
2134 key, old, new = keyinfo
2132 r = target.pushkey(namespace, key, old, new)
2135 r = target.pushkey(namespace, key, old, new)
2133 ui.status(str(r) + '\n')
2136 ui.status(str(r) + '\n')
2134 return not r
2137 return not r
2135 else:
2138 else:
2136 for k, v in sorted(target.listkeys(namespace).iteritems()):
2139 for k, v in sorted(target.listkeys(namespace).iteritems()):
2137 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2140 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2138 v.encode('string-escape')))
2141 v.encode('string-escape')))
2139
2142
2140 @command('debugpvec', [], _('A B'))
2143 @command('debugpvec', [], _('A B'))
2141 def debugpvec(ui, repo, a, b=None):
2144 def debugpvec(ui, repo, a, b=None):
2142 ca = scmutil.revsingle(repo, a)
2145 ca = scmutil.revsingle(repo, a)
2143 cb = scmutil.revsingle(repo, b)
2146 cb = scmutil.revsingle(repo, b)
2144 pa = pvec.ctxpvec(ca)
2147 pa = pvec.ctxpvec(ca)
2145 pb = pvec.ctxpvec(cb)
2148 pb = pvec.ctxpvec(cb)
2146 if pa == pb:
2149 if pa == pb:
2147 rel = "="
2150 rel = "="
2148 elif pa > pb:
2151 elif pa > pb:
2149 rel = ">"
2152 rel = ">"
2150 elif pa < pb:
2153 elif pa < pb:
2151 rel = "<"
2154 rel = "<"
2152 elif pa | pb:
2155 elif pa | pb:
2153 rel = "|"
2156 rel = "|"
2154 ui.write(_("a: %s\n") % pa)
2157 ui.write(_("a: %s\n") % pa)
2155 ui.write(_("b: %s\n") % pb)
2158 ui.write(_("b: %s\n") % pb)
2156 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2159 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2157 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2160 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2158 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2161 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2159 pa.distance(pb), rel))
2162 pa.distance(pb), rel))
2160
2163
2161 @command('debugrebuildstate',
2164 @command('debugrebuildstate',
2162 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2165 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2163 _('[-r REV] [REV]'))
2166 _('[-r REV] [REV]'))
2164 def debugrebuildstate(ui, repo, rev="tip"):
2167 def debugrebuildstate(ui, repo, rev="tip"):
2165 """rebuild the dirstate as it would look like for the given revision"""
2168 """rebuild the dirstate as it would look like for the given revision"""
2166 ctx = scmutil.revsingle(repo, rev)
2169 ctx = scmutil.revsingle(repo, rev)
2167 wlock = repo.wlock()
2170 wlock = repo.wlock()
2168 try:
2171 try:
2169 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2172 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2170 finally:
2173 finally:
2171 wlock.release()
2174 wlock.release()
2172
2175
2173 @command('debugrename',
2176 @command('debugrename',
2174 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2177 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2175 _('[-r REV] FILE'))
2178 _('[-r REV] FILE'))
2176 def debugrename(ui, repo, file1, *pats, **opts):
2179 def debugrename(ui, repo, file1, *pats, **opts):
2177 """dump rename information"""
2180 """dump rename information"""
2178
2181
2179 ctx = scmutil.revsingle(repo, opts.get('rev'))
2182 ctx = scmutil.revsingle(repo, opts.get('rev'))
2180 m = scmutil.match(ctx, (file1,) + pats, opts)
2183 m = scmutil.match(ctx, (file1,) + pats, opts)
2181 for abs in ctx.walk(m):
2184 for abs in ctx.walk(m):
2182 fctx = ctx[abs]
2185 fctx = ctx[abs]
2183 o = fctx.filelog().renamed(fctx.filenode())
2186 o = fctx.filelog().renamed(fctx.filenode())
2184 rel = m.rel(abs)
2187 rel = m.rel(abs)
2185 if o:
2188 if o:
2186 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2189 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2187 else:
2190 else:
2188 ui.write(_("%s not renamed\n") % rel)
2191 ui.write(_("%s not renamed\n") % rel)
2189
2192
2190 @command('debugrevlog',
2193 @command('debugrevlog',
2191 [('c', 'changelog', False, _('open changelog')),
2194 [('c', 'changelog', False, _('open changelog')),
2192 ('m', 'manifest', False, _('open manifest')),
2195 ('m', 'manifest', False, _('open manifest')),
2193 ('d', 'dump', False, _('dump index data'))],
2196 ('d', 'dump', False, _('dump index data'))],
2194 _('-c|-m|FILE'))
2197 _('-c|-m|FILE'))
2195 def debugrevlog(ui, repo, file_ = None, **opts):
2198 def debugrevlog(ui, repo, file_ = None, **opts):
2196 """show data and statistics about a revlog"""
2199 """show data and statistics about a revlog"""
2197 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2200 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2198
2201
2199 if opts.get("dump"):
2202 if opts.get("dump"):
2200 numrevs = len(r)
2203 numrevs = len(r)
2201 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2204 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2202 " rawsize totalsize compression heads\n")
2205 " rawsize totalsize compression heads\n")
2203 ts = 0
2206 ts = 0
2204 heads = set()
2207 heads = set()
2205 for rev in xrange(numrevs):
2208 for rev in xrange(numrevs):
2206 dbase = r.deltaparent(rev)
2209 dbase = r.deltaparent(rev)
2207 if dbase == -1:
2210 if dbase == -1:
2208 dbase = rev
2211 dbase = rev
2209 cbase = r.chainbase(rev)
2212 cbase = r.chainbase(rev)
2210 p1, p2 = r.parentrevs(rev)
2213 p1, p2 = r.parentrevs(rev)
2211 rs = r.rawsize(rev)
2214 rs = r.rawsize(rev)
2212 ts = ts + rs
2215 ts = ts + rs
2213 heads -= set(r.parentrevs(rev))
2216 heads -= set(r.parentrevs(rev))
2214 heads.add(rev)
2217 heads.add(rev)
2215 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2218 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2216 (rev, p1, p2, r.start(rev), r.end(rev),
2219 (rev, p1, p2, r.start(rev), r.end(rev),
2217 r.start(dbase), r.start(cbase),
2220 r.start(dbase), r.start(cbase),
2218 r.start(p1), r.start(p2),
2221 r.start(p1), r.start(p2),
2219 rs, ts, ts / r.end(rev), len(heads)))
2222 rs, ts, ts / r.end(rev), len(heads)))
2220 return 0
2223 return 0
2221
2224
2222 v = r.version
2225 v = r.version
2223 format = v & 0xFFFF
2226 format = v & 0xFFFF
2224 flags = []
2227 flags = []
2225 gdelta = False
2228 gdelta = False
2226 if v & revlog.REVLOGNGINLINEDATA:
2229 if v & revlog.REVLOGNGINLINEDATA:
2227 flags.append('inline')
2230 flags.append('inline')
2228 if v & revlog.REVLOGGENERALDELTA:
2231 if v & revlog.REVLOGGENERALDELTA:
2229 gdelta = True
2232 gdelta = True
2230 flags.append('generaldelta')
2233 flags.append('generaldelta')
2231 if not flags:
2234 if not flags:
2232 flags = ['(none)']
2235 flags = ['(none)']
2233
2236
2234 nummerges = 0
2237 nummerges = 0
2235 numfull = 0
2238 numfull = 0
2236 numprev = 0
2239 numprev = 0
2237 nump1 = 0
2240 nump1 = 0
2238 nump2 = 0
2241 nump2 = 0
2239 numother = 0
2242 numother = 0
2240 nump1prev = 0
2243 nump1prev = 0
2241 nump2prev = 0
2244 nump2prev = 0
2242 chainlengths = []
2245 chainlengths = []
2243
2246
2244 datasize = [None, 0, 0L]
2247 datasize = [None, 0, 0L]
2245 fullsize = [None, 0, 0L]
2248 fullsize = [None, 0, 0L]
2246 deltasize = [None, 0, 0L]
2249 deltasize = [None, 0, 0L]
2247
2250
2248 def addsize(size, l):
2251 def addsize(size, l):
2249 if l[0] is None or size < l[0]:
2252 if l[0] is None or size < l[0]:
2250 l[0] = size
2253 l[0] = size
2251 if size > l[1]:
2254 if size > l[1]:
2252 l[1] = size
2255 l[1] = size
2253 l[2] += size
2256 l[2] += size
2254
2257
2255 numrevs = len(r)
2258 numrevs = len(r)
2256 for rev in xrange(numrevs):
2259 for rev in xrange(numrevs):
2257 p1, p2 = r.parentrevs(rev)
2260 p1, p2 = r.parentrevs(rev)
2258 delta = r.deltaparent(rev)
2261 delta = r.deltaparent(rev)
2259 if format > 0:
2262 if format > 0:
2260 addsize(r.rawsize(rev), datasize)
2263 addsize(r.rawsize(rev), datasize)
2261 if p2 != nullrev:
2264 if p2 != nullrev:
2262 nummerges += 1
2265 nummerges += 1
2263 size = r.length(rev)
2266 size = r.length(rev)
2264 if delta == nullrev:
2267 if delta == nullrev:
2265 chainlengths.append(0)
2268 chainlengths.append(0)
2266 numfull += 1
2269 numfull += 1
2267 addsize(size, fullsize)
2270 addsize(size, fullsize)
2268 else:
2271 else:
2269 chainlengths.append(chainlengths[delta] + 1)
2272 chainlengths.append(chainlengths[delta] + 1)
2270 addsize(size, deltasize)
2273 addsize(size, deltasize)
2271 if delta == rev - 1:
2274 if delta == rev - 1:
2272 numprev += 1
2275 numprev += 1
2273 if delta == p1:
2276 if delta == p1:
2274 nump1prev += 1
2277 nump1prev += 1
2275 elif delta == p2:
2278 elif delta == p2:
2276 nump2prev += 1
2279 nump2prev += 1
2277 elif delta == p1:
2280 elif delta == p1:
2278 nump1 += 1
2281 nump1 += 1
2279 elif delta == p2:
2282 elif delta == p2:
2280 nump2 += 1
2283 nump2 += 1
2281 elif delta != nullrev:
2284 elif delta != nullrev:
2282 numother += 1
2285 numother += 1
2283
2286
2284 # Adjust size min value for empty cases
2287 # Adjust size min value for empty cases
2285 for size in (datasize, fullsize, deltasize):
2288 for size in (datasize, fullsize, deltasize):
2286 if size[0] is None:
2289 if size[0] is None:
2287 size[0] = 0
2290 size[0] = 0
2288
2291
2289 numdeltas = numrevs - numfull
2292 numdeltas = numrevs - numfull
2290 numoprev = numprev - nump1prev - nump2prev
2293 numoprev = numprev - nump1prev - nump2prev
2291 totalrawsize = datasize[2]
2294 totalrawsize = datasize[2]
2292 datasize[2] /= numrevs
2295 datasize[2] /= numrevs
2293 fulltotal = fullsize[2]
2296 fulltotal = fullsize[2]
2294 fullsize[2] /= numfull
2297 fullsize[2] /= numfull
2295 deltatotal = deltasize[2]
2298 deltatotal = deltasize[2]
2296 if numrevs - numfull > 0:
2299 if numrevs - numfull > 0:
2297 deltasize[2] /= numrevs - numfull
2300 deltasize[2] /= numrevs - numfull
2298 totalsize = fulltotal + deltatotal
2301 totalsize = fulltotal + deltatotal
2299 avgchainlen = sum(chainlengths) / numrevs
2302 avgchainlen = sum(chainlengths) / numrevs
2300 compratio = totalrawsize / totalsize
2303 compratio = totalrawsize / totalsize
2301
2304
2302 basedfmtstr = '%%%dd\n'
2305 basedfmtstr = '%%%dd\n'
2303 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2306 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2304
2307
2305 def dfmtstr(max):
2308 def dfmtstr(max):
2306 return basedfmtstr % len(str(max))
2309 return basedfmtstr % len(str(max))
2307 def pcfmtstr(max, padding=0):
2310 def pcfmtstr(max, padding=0):
2308 return basepcfmtstr % (len(str(max)), ' ' * padding)
2311 return basepcfmtstr % (len(str(max)), ' ' * padding)
2309
2312
2310 def pcfmt(value, total):
2313 def pcfmt(value, total):
2311 return (value, 100 * float(value) / total)
2314 return (value, 100 * float(value) / total)
2312
2315
2313 ui.write(('format : %d\n') % format)
2316 ui.write(('format : %d\n') % format)
2314 ui.write(('flags : %s\n') % ', '.join(flags))
2317 ui.write(('flags : %s\n') % ', '.join(flags))
2315
2318
2316 ui.write('\n')
2319 ui.write('\n')
2317 fmt = pcfmtstr(totalsize)
2320 fmt = pcfmtstr(totalsize)
2318 fmt2 = dfmtstr(totalsize)
2321 fmt2 = dfmtstr(totalsize)
2319 ui.write(('revisions : ') + fmt2 % numrevs)
2322 ui.write(('revisions : ') + fmt2 % numrevs)
2320 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2323 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2321 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2324 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2322 ui.write(('revisions : ') + fmt2 % numrevs)
2325 ui.write(('revisions : ') + fmt2 % numrevs)
2323 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2326 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2324 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2327 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2325 ui.write(('revision size : ') + fmt2 % totalsize)
2328 ui.write(('revision size : ') + fmt2 % totalsize)
2326 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2329 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2327 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2330 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2328
2331
2329 ui.write('\n')
2332 ui.write('\n')
2330 fmt = dfmtstr(max(avgchainlen, compratio))
2333 fmt = dfmtstr(max(avgchainlen, compratio))
2331 ui.write(('avg chain length : ') + fmt % avgchainlen)
2334 ui.write(('avg chain length : ') + fmt % avgchainlen)
2332 ui.write(('compression ratio : ') + fmt % compratio)
2335 ui.write(('compression ratio : ') + fmt % compratio)
2333
2336
2334 if format > 0:
2337 if format > 0:
2335 ui.write('\n')
2338 ui.write('\n')
2336 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2339 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2337 % tuple(datasize))
2340 % tuple(datasize))
2338 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2341 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2339 % tuple(fullsize))
2342 % tuple(fullsize))
2340 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2343 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2341 % tuple(deltasize))
2344 % tuple(deltasize))
2342
2345
2343 if numdeltas > 0:
2346 if numdeltas > 0:
2344 ui.write('\n')
2347 ui.write('\n')
2345 fmt = pcfmtstr(numdeltas)
2348 fmt = pcfmtstr(numdeltas)
2346 fmt2 = pcfmtstr(numdeltas, 4)
2349 fmt2 = pcfmtstr(numdeltas, 4)
2347 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2350 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2348 if numprev > 0:
2351 if numprev > 0:
2349 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2352 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2350 numprev))
2353 numprev))
2351 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2354 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2352 numprev))
2355 numprev))
2353 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2356 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2354 numprev))
2357 numprev))
2355 if gdelta:
2358 if gdelta:
2356 ui.write(('deltas against p1 : ')
2359 ui.write(('deltas against p1 : ')
2357 + fmt % pcfmt(nump1, numdeltas))
2360 + fmt % pcfmt(nump1, numdeltas))
2358 ui.write(('deltas against p2 : ')
2361 ui.write(('deltas against p2 : ')
2359 + fmt % pcfmt(nump2, numdeltas))
2362 + fmt % pcfmt(nump2, numdeltas))
2360 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2363 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2361 numdeltas))
2364 numdeltas))
2362
2365
2363 @command('debugrevspec', [], ('REVSPEC'))
2366 @command('debugrevspec', [], ('REVSPEC'))
2364 def debugrevspec(ui, repo, expr):
2367 def debugrevspec(ui, repo, expr):
2365 """parse and apply a revision specification
2368 """parse and apply a revision specification
2366
2369
2367 Use --verbose to print the parsed tree before and after aliases
2370 Use --verbose to print the parsed tree before and after aliases
2368 expansion.
2371 expansion.
2369 """
2372 """
2370 if ui.verbose:
2373 if ui.verbose:
2371 tree = revset.parse(expr)[0]
2374 tree = revset.parse(expr)[0]
2372 ui.note(revset.prettyformat(tree), "\n")
2375 ui.note(revset.prettyformat(tree), "\n")
2373 newtree = revset.findaliases(ui, tree)
2376 newtree = revset.findaliases(ui, tree)
2374 if newtree != tree:
2377 if newtree != tree:
2375 ui.note(revset.prettyformat(newtree), "\n")
2378 ui.note(revset.prettyformat(newtree), "\n")
2376 func = revset.match(ui, expr)
2379 func = revset.match(ui, expr)
2377 for c in func(repo, range(len(repo))):
2380 for c in func(repo, range(len(repo))):
2378 ui.write("%s\n" % c)
2381 ui.write("%s\n" % c)
2379
2382
2380 @command('debugsetparents', [], _('REV1 [REV2]'))
2383 @command('debugsetparents', [], _('REV1 [REV2]'))
2381 def debugsetparents(ui, repo, rev1, rev2=None):
2384 def debugsetparents(ui, repo, rev1, rev2=None):
2382 """manually set the parents of the current working directory
2385 """manually set the parents of the current working directory
2383
2386
2384 This is useful for writing repository conversion tools, but should
2387 This is useful for writing repository conversion tools, but should
2385 be used with care.
2388 be used with care.
2386
2389
2387 Returns 0 on success.
2390 Returns 0 on success.
2388 """
2391 """
2389
2392
2390 r1 = scmutil.revsingle(repo, rev1).node()
2393 r1 = scmutil.revsingle(repo, rev1).node()
2391 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2394 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2392
2395
2393 wlock = repo.wlock()
2396 wlock = repo.wlock()
2394 try:
2397 try:
2395 repo.setparents(r1, r2)
2398 repo.setparents(r1, r2)
2396 finally:
2399 finally:
2397 wlock.release()
2400 wlock.release()
2398
2401
2399 @command('debugstate',
2402 @command('debugstate',
2400 [('', 'nodates', None, _('do not display the saved mtime')),
2403 [('', 'nodates', None, _('do not display the saved mtime')),
2401 ('', 'datesort', None, _('sort by saved mtime'))],
2404 ('', 'datesort', None, _('sort by saved mtime'))],
2402 _('[OPTION]...'))
2405 _('[OPTION]...'))
2403 def debugstate(ui, repo, nodates=None, datesort=None):
2406 def debugstate(ui, repo, nodates=None, datesort=None):
2404 """show the contents of the current dirstate"""
2407 """show the contents of the current dirstate"""
2405 timestr = ""
2408 timestr = ""
2406 showdate = not nodates
2409 showdate = not nodates
2407 if datesort:
2410 if datesort:
2408 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2411 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2409 else:
2412 else:
2410 keyfunc = None # sort by filename
2413 keyfunc = None # sort by filename
2411 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2414 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2412 if showdate:
2415 if showdate:
2413 if ent[3] == -1:
2416 if ent[3] == -1:
2414 # Pad or slice to locale representation
2417 # Pad or slice to locale representation
2415 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2418 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2416 time.localtime(0)))
2419 time.localtime(0)))
2417 timestr = 'unset'
2420 timestr = 'unset'
2418 timestr = (timestr[:locale_len] +
2421 timestr = (timestr[:locale_len] +
2419 ' ' * (locale_len - len(timestr)))
2422 ' ' * (locale_len - len(timestr)))
2420 else:
2423 else:
2421 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2424 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2422 time.localtime(ent[3]))
2425 time.localtime(ent[3]))
2423 if ent[1] & 020000:
2426 if ent[1] & 020000:
2424 mode = 'lnk'
2427 mode = 'lnk'
2425 else:
2428 else:
2426 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2429 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2427 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2430 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2428 for f in repo.dirstate.copies():
2431 for f in repo.dirstate.copies():
2429 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2432 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2430
2433
2431 @command('debugsub',
2434 @command('debugsub',
2432 [('r', 'rev', '',
2435 [('r', 'rev', '',
2433 _('revision to check'), _('REV'))],
2436 _('revision to check'), _('REV'))],
2434 _('[-r REV] [REV]'))
2437 _('[-r REV] [REV]'))
2435 def debugsub(ui, repo, rev=None):
2438 def debugsub(ui, repo, rev=None):
2436 ctx = scmutil.revsingle(repo, rev, None)
2439 ctx = scmutil.revsingle(repo, rev, None)
2437 for k, v in sorted(ctx.substate.items()):
2440 for k, v in sorted(ctx.substate.items()):
2438 ui.write(('path %s\n') % k)
2441 ui.write(('path %s\n') % k)
2439 ui.write((' source %s\n') % v[0])
2442 ui.write((' source %s\n') % v[0])
2440 ui.write((' revision %s\n') % v[1])
2443 ui.write((' revision %s\n') % v[1])
2441
2444
2442 @command('debugsuccessorssets',
2445 @command('debugsuccessorssets',
2443 [],
2446 [],
2444 _('[REV]'))
2447 _('[REV]'))
2445 def debugsuccessorssets(ui, repo, *revs):
2448 def debugsuccessorssets(ui, repo, *revs):
2446 """show set of successors for revision
2449 """show set of successors for revision
2447
2450
2448 A successors set of changeset A is a consistent group of revisions that
2451 A successors set of changeset A is a consistent group of revisions that
2449 succeed A. It contains non-obsolete changesets only.
2452 succeed A. It contains non-obsolete changesets only.
2450
2453
2451 In most cases a changeset A has a single successors set containing a single
2454 In most cases a changeset A has a single successors set containing a single
2452 successor (changeset A replaced by A').
2455 successor (changeset A replaced by A').
2453
2456
2454 A changeset that is made obsolete with no successors are called "pruned".
2457 A changeset that is made obsolete with no successors are called "pruned".
2455 Such changesets have no successors sets at all.
2458 Such changesets have no successors sets at all.
2456
2459
2457 A changeset that has been "split" will have a successors set containing
2460 A changeset that has been "split" will have a successors set containing
2458 more than one successor.
2461 more than one successor.
2459
2462
2460 A changeset that has been rewritten in multiple different ways is called
2463 A changeset that has been rewritten in multiple different ways is called
2461 "divergent". Such changesets have multiple successor sets (each of which
2464 "divergent". Such changesets have multiple successor sets (each of which
2462 may also be split, i.e. have multiple successors).
2465 may also be split, i.e. have multiple successors).
2463
2466
2464 Results are displayed as follows::
2467 Results are displayed as follows::
2465
2468
2466 <rev1>
2469 <rev1>
2467 <successors-1A>
2470 <successors-1A>
2468 <rev2>
2471 <rev2>
2469 <successors-2A>
2472 <successors-2A>
2470 <successors-2B1> <successors-2B2> <successors-2B3>
2473 <successors-2B1> <successors-2B2> <successors-2B3>
2471
2474
2472 Here rev2 has two possible (i.e. divergent) successors sets. The first
2475 Here rev2 has two possible (i.e. divergent) successors sets. The first
2473 holds one element, whereas the second holds three (i.e. the changeset has
2476 holds one element, whereas the second holds three (i.e. the changeset has
2474 been split).
2477 been split).
2475 """
2478 """
2476 # passed to successorssets caching computation from one call to another
2479 # passed to successorssets caching computation from one call to another
2477 cache = {}
2480 cache = {}
2478 ctx2str = str
2481 ctx2str = str
2479 node2str = short
2482 node2str = short
2480 if ui.debug():
2483 if ui.debug():
2481 def ctx2str(ctx):
2484 def ctx2str(ctx):
2482 return ctx.hex()
2485 return ctx.hex()
2483 node2str = hex
2486 node2str = hex
2484 for rev in scmutil.revrange(repo, revs):
2487 for rev in scmutil.revrange(repo, revs):
2485 ctx = repo[rev]
2488 ctx = repo[rev]
2486 ui.write('%s\n'% ctx2str(ctx))
2489 ui.write('%s\n'% ctx2str(ctx))
2487 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2490 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2488 if succsset:
2491 if succsset:
2489 ui.write(' ')
2492 ui.write(' ')
2490 ui.write(node2str(succsset[0]))
2493 ui.write(node2str(succsset[0]))
2491 for node in succsset[1:]:
2494 for node in succsset[1:]:
2492 ui.write(' ')
2495 ui.write(' ')
2493 ui.write(node2str(node))
2496 ui.write(node2str(node))
2494 ui.write('\n')
2497 ui.write('\n')
2495
2498
2496 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2499 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2497 def debugwalk(ui, repo, *pats, **opts):
2500 def debugwalk(ui, repo, *pats, **opts):
2498 """show how files match on given patterns"""
2501 """show how files match on given patterns"""
2499 m = scmutil.match(repo[None], pats, opts)
2502 m = scmutil.match(repo[None], pats, opts)
2500 items = list(repo.walk(m))
2503 items = list(repo.walk(m))
2501 if not items:
2504 if not items:
2502 return
2505 return
2503 f = lambda fn: fn
2506 f = lambda fn: fn
2504 if ui.configbool('ui', 'slash') and os.sep != '/':
2507 if ui.configbool('ui', 'slash') and os.sep != '/':
2505 f = lambda fn: util.normpath(fn)
2508 f = lambda fn: util.normpath(fn)
2506 fmt = 'f %%-%ds %%-%ds %%s' % (
2509 fmt = 'f %%-%ds %%-%ds %%s' % (
2507 max([len(abs) for abs in items]),
2510 max([len(abs) for abs in items]),
2508 max([len(m.rel(abs)) for abs in items]))
2511 max([len(m.rel(abs)) for abs in items]))
2509 for abs in items:
2512 for abs in items:
2510 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2513 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2511 ui.write("%s\n" % line.rstrip())
2514 ui.write("%s\n" % line.rstrip())
2512
2515
2513 @command('debugwireargs',
2516 @command('debugwireargs',
2514 [('', 'three', '', 'three'),
2517 [('', 'three', '', 'three'),
2515 ('', 'four', '', 'four'),
2518 ('', 'four', '', 'four'),
2516 ('', 'five', '', 'five'),
2519 ('', 'five', '', 'five'),
2517 ] + remoteopts,
2520 ] + remoteopts,
2518 _('REPO [OPTIONS]... [ONE [TWO]]'))
2521 _('REPO [OPTIONS]... [ONE [TWO]]'))
2519 def debugwireargs(ui, repopath, *vals, **opts):
2522 def debugwireargs(ui, repopath, *vals, **opts):
2520 repo = hg.peer(ui, opts, repopath)
2523 repo = hg.peer(ui, opts, repopath)
2521 for opt in remoteopts:
2524 for opt in remoteopts:
2522 del opts[opt[1]]
2525 del opts[opt[1]]
2523 args = {}
2526 args = {}
2524 for k, v in opts.iteritems():
2527 for k, v in opts.iteritems():
2525 if v:
2528 if v:
2526 args[k] = v
2529 args[k] = v
2527 # run twice to check that we don't mess up the stream for the next command
2530 # run twice to check that we don't mess up the stream for the next command
2528 res1 = repo.debugwireargs(*vals, **args)
2531 res1 = repo.debugwireargs(*vals, **args)
2529 res2 = repo.debugwireargs(*vals, **args)
2532 res2 = repo.debugwireargs(*vals, **args)
2530 ui.write("%s\n" % res1)
2533 ui.write("%s\n" % res1)
2531 if res1 != res2:
2534 if res1 != res2:
2532 ui.warn("%s\n" % res2)
2535 ui.warn("%s\n" % res2)
2533
2536
2534 @command('^diff',
2537 @command('^diff',
2535 [('r', 'rev', [], _('revision'), _('REV')),
2538 [('r', 'rev', [], _('revision'), _('REV')),
2536 ('c', 'change', '', _('change made by revision'), _('REV'))
2539 ('c', 'change', '', _('change made by revision'), _('REV'))
2537 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2540 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2538 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2541 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2539 def diff(ui, repo, *pats, **opts):
2542 def diff(ui, repo, *pats, **opts):
2540 """diff repository (or selected files)
2543 """diff repository (or selected files)
2541
2544
2542 Show differences between revisions for the specified files.
2545 Show differences between revisions for the specified files.
2543
2546
2544 Differences between files are shown using the unified diff format.
2547 Differences between files are shown using the unified diff format.
2545
2548
2546 .. note::
2549 .. note::
2547 diff may generate unexpected results for merges, as it will
2550 diff may generate unexpected results for merges, as it will
2548 default to comparing against the working directory's first
2551 default to comparing against the working directory's first
2549 parent changeset if no revisions are specified.
2552 parent changeset if no revisions are specified.
2550
2553
2551 When two revision arguments are given, then changes are shown
2554 When two revision arguments are given, then changes are shown
2552 between those revisions. If only one revision is specified then
2555 between those revisions. If only one revision is specified then
2553 that revision is compared to the working directory, and, when no
2556 that revision is compared to the working directory, and, when no
2554 revisions are specified, the working directory files are compared
2557 revisions are specified, the working directory files are compared
2555 to its parent.
2558 to its parent.
2556
2559
2557 Alternatively you can specify -c/--change with a revision to see
2560 Alternatively you can specify -c/--change with a revision to see
2558 the changes in that changeset relative to its first parent.
2561 the changes in that changeset relative to its first parent.
2559
2562
2560 Without the -a/--text option, diff will avoid generating diffs of
2563 Without the -a/--text option, diff will avoid generating diffs of
2561 files it detects as binary. With -a, diff will generate a diff
2564 files it detects as binary. With -a, diff will generate a diff
2562 anyway, probably with undesirable results.
2565 anyway, probably with undesirable results.
2563
2566
2564 Use the -g/--git option to generate diffs in the git extended diff
2567 Use the -g/--git option to generate diffs in the git extended diff
2565 format. For more information, read :hg:`help diffs`.
2568 format. For more information, read :hg:`help diffs`.
2566
2569
2567 .. container:: verbose
2570 .. container:: verbose
2568
2571
2569 Examples:
2572 Examples:
2570
2573
2571 - compare a file in the current working directory to its parent::
2574 - compare a file in the current working directory to its parent::
2572
2575
2573 hg diff foo.c
2576 hg diff foo.c
2574
2577
2575 - compare two historical versions of a directory, with rename info::
2578 - compare two historical versions of a directory, with rename info::
2576
2579
2577 hg diff --git -r 1.0:1.2 lib/
2580 hg diff --git -r 1.0:1.2 lib/
2578
2581
2579 - get change stats relative to the last change on some date::
2582 - get change stats relative to the last change on some date::
2580
2583
2581 hg diff --stat -r "date('may 2')"
2584 hg diff --stat -r "date('may 2')"
2582
2585
2583 - diff all newly-added files that contain a keyword::
2586 - diff all newly-added files that contain a keyword::
2584
2587
2585 hg diff "set:added() and grep(GNU)"
2588 hg diff "set:added() and grep(GNU)"
2586
2589
2587 - compare a revision and its parents::
2590 - compare a revision and its parents::
2588
2591
2589 hg diff -c 9353 # compare against first parent
2592 hg diff -c 9353 # compare against first parent
2590 hg diff -r 9353^:9353 # same using revset syntax
2593 hg diff -r 9353^:9353 # same using revset syntax
2591 hg diff -r 9353^2:9353 # compare against the second parent
2594 hg diff -r 9353^2:9353 # compare against the second parent
2592
2595
2593 Returns 0 on success.
2596 Returns 0 on success.
2594 """
2597 """
2595
2598
2596 revs = opts.get('rev')
2599 revs = opts.get('rev')
2597 change = opts.get('change')
2600 change = opts.get('change')
2598 stat = opts.get('stat')
2601 stat = opts.get('stat')
2599 reverse = opts.get('reverse')
2602 reverse = opts.get('reverse')
2600
2603
2601 if revs and change:
2604 if revs and change:
2602 msg = _('cannot specify --rev and --change at the same time')
2605 msg = _('cannot specify --rev and --change at the same time')
2603 raise util.Abort(msg)
2606 raise util.Abort(msg)
2604 elif change:
2607 elif change:
2605 node2 = scmutil.revsingle(repo, change, None).node()
2608 node2 = scmutil.revsingle(repo, change, None).node()
2606 node1 = repo[node2].p1().node()
2609 node1 = repo[node2].p1().node()
2607 else:
2610 else:
2608 node1, node2 = scmutil.revpair(repo, revs)
2611 node1, node2 = scmutil.revpair(repo, revs)
2609
2612
2610 if reverse:
2613 if reverse:
2611 node1, node2 = node2, node1
2614 node1, node2 = node2, node1
2612
2615
2613 diffopts = patch.diffopts(ui, opts)
2616 diffopts = patch.diffopts(ui, opts)
2614 m = scmutil.match(repo[node2], pats, opts)
2617 m = scmutil.match(repo[node2], pats, opts)
2615 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2618 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2616 listsubrepos=opts.get('subrepos'))
2619 listsubrepos=opts.get('subrepos'))
2617
2620
2618 @command('^export',
2621 @command('^export',
2619 [('o', 'output', '',
2622 [('o', 'output', '',
2620 _('print output to file with formatted name'), _('FORMAT')),
2623 _('print output to file with formatted name'), _('FORMAT')),
2621 ('', 'switch-parent', None, _('diff against the second parent')),
2624 ('', 'switch-parent', None, _('diff against the second parent')),
2622 ('r', 'rev', [], _('revisions to export'), _('REV')),
2625 ('r', 'rev', [], _('revisions to export'), _('REV')),
2623 ] + diffopts,
2626 ] + diffopts,
2624 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2627 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2625 def export(ui, repo, *changesets, **opts):
2628 def export(ui, repo, *changesets, **opts):
2626 """dump the header and diffs for one or more changesets
2629 """dump the header and diffs for one or more changesets
2627
2630
2628 Print the changeset header and diffs for one or more revisions.
2631 Print the changeset header and diffs for one or more revisions.
2629
2632
2630 The information shown in the changeset header is: author, date,
2633 The information shown in the changeset header is: author, date,
2631 branch name (if non-default), changeset hash, parent(s) and commit
2634 branch name (if non-default), changeset hash, parent(s) and commit
2632 comment.
2635 comment.
2633
2636
2634 .. note::
2637 .. note::
2635 export may generate unexpected diff output for merge
2638 export may generate unexpected diff output for merge
2636 changesets, as it will compare the merge changeset against its
2639 changesets, as it will compare the merge changeset against its
2637 first parent only.
2640 first parent only.
2638
2641
2639 Output may be to a file, in which case the name of the file is
2642 Output may be to a file, in which case the name of the file is
2640 given using a format string. The formatting rules are as follows:
2643 given using a format string. The formatting rules are as follows:
2641
2644
2642 :``%%``: literal "%" character
2645 :``%%``: literal "%" character
2643 :``%H``: changeset hash (40 hexadecimal digits)
2646 :``%H``: changeset hash (40 hexadecimal digits)
2644 :``%N``: number of patches being generated
2647 :``%N``: number of patches being generated
2645 :``%R``: changeset revision number
2648 :``%R``: changeset revision number
2646 :``%b``: basename of the exporting repository
2649 :``%b``: basename of the exporting repository
2647 :``%h``: short-form changeset hash (12 hexadecimal digits)
2650 :``%h``: short-form changeset hash (12 hexadecimal digits)
2648 :``%m``: first line of the commit message (only alphanumeric characters)
2651 :``%m``: first line of the commit message (only alphanumeric characters)
2649 :``%n``: zero-padded sequence number, starting at 1
2652 :``%n``: zero-padded sequence number, starting at 1
2650 :``%r``: zero-padded changeset revision number
2653 :``%r``: zero-padded changeset revision number
2651
2654
2652 Without the -a/--text option, export will avoid generating diffs
2655 Without the -a/--text option, export will avoid generating diffs
2653 of files it detects as binary. With -a, export will generate a
2656 of files it detects as binary. With -a, export will generate a
2654 diff anyway, probably with undesirable results.
2657 diff anyway, probably with undesirable results.
2655
2658
2656 Use the -g/--git option to generate diffs in the git extended diff
2659 Use the -g/--git option to generate diffs in the git extended diff
2657 format. See :hg:`help diffs` for more information.
2660 format. See :hg:`help diffs` for more information.
2658
2661
2659 With the --switch-parent option, the diff will be against the
2662 With the --switch-parent option, the diff will be against the
2660 second parent. It can be useful to review a merge.
2663 second parent. It can be useful to review a merge.
2661
2664
2662 .. container:: verbose
2665 .. container:: verbose
2663
2666
2664 Examples:
2667 Examples:
2665
2668
2666 - use export and import to transplant a bugfix to the current
2669 - use export and import to transplant a bugfix to the current
2667 branch::
2670 branch::
2668
2671
2669 hg export -r 9353 | hg import -
2672 hg export -r 9353 | hg import -
2670
2673
2671 - export all the changesets between two revisions to a file with
2674 - export all the changesets between two revisions to a file with
2672 rename information::
2675 rename information::
2673
2676
2674 hg export --git -r 123:150 > changes.txt
2677 hg export --git -r 123:150 > changes.txt
2675
2678
2676 - split outgoing changes into a series of patches with
2679 - split outgoing changes into a series of patches with
2677 descriptive names::
2680 descriptive names::
2678
2681
2679 hg export -r "outgoing()" -o "%n-%m.patch"
2682 hg export -r "outgoing()" -o "%n-%m.patch"
2680
2683
2681 Returns 0 on success.
2684 Returns 0 on success.
2682 """
2685 """
2683 changesets += tuple(opts.get('rev', []))
2686 changesets += tuple(opts.get('rev', []))
2684 revs = scmutil.revrange(repo, changesets)
2687 revs = scmutil.revrange(repo, changesets)
2685 if not revs:
2688 if not revs:
2686 raise util.Abort(_("export requires at least one changeset"))
2689 raise util.Abort(_("export requires at least one changeset"))
2687 if len(revs) > 1:
2690 if len(revs) > 1:
2688 ui.note(_('exporting patches:\n'))
2691 ui.note(_('exporting patches:\n'))
2689 else:
2692 else:
2690 ui.note(_('exporting patch:\n'))
2693 ui.note(_('exporting patch:\n'))
2691 cmdutil.export(repo, revs, template=opts.get('output'),
2694 cmdutil.export(repo, revs, template=opts.get('output'),
2692 switch_parent=opts.get('switch_parent'),
2695 switch_parent=opts.get('switch_parent'),
2693 opts=patch.diffopts(ui, opts))
2696 opts=patch.diffopts(ui, opts))
2694
2697
2695 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2698 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2696 def forget(ui, repo, *pats, **opts):
2699 def forget(ui, repo, *pats, **opts):
2697 """forget the specified files on the next commit
2700 """forget the specified files on the next commit
2698
2701
2699 Mark the specified files so they will no longer be tracked
2702 Mark the specified files so they will no longer be tracked
2700 after the next commit.
2703 after the next commit.
2701
2704
2702 This only removes files from the current branch, not from the
2705 This only removes files from the current branch, not from the
2703 entire project history, and it does not delete them from the
2706 entire project history, and it does not delete them from the
2704 working directory.
2707 working directory.
2705
2708
2706 To undo a forget before the next commit, see :hg:`add`.
2709 To undo a forget before the next commit, see :hg:`add`.
2707
2710
2708 .. container:: verbose
2711 .. container:: verbose
2709
2712
2710 Examples:
2713 Examples:
2711
2714
2712 - forget newly-added binary files::
2715 - forget newly-added binary files::
2713
2716
2714 hg forget "set:added() and binary()"
2717 hg forget "set:added() and binary()"
2715
2718
2716 - forget files that would be excluded by .hgignore::
2719 - forget files that would be excluded by .hgignore::
2717
2720
2718 hg forget "set:hgignore()"
2721 hg forget "set:hgignore()"
2719
2722
2720 Returns 0 on success.
2723 Returns 0 on success.
2721 """
2724 """
2722
2725
2723 if not pats:
2726 if not pats:
2724 raise util.Abort(_('no files specified'))
2727 raise util.Abort(_('no files specified'))
2725
2728
2726 m = scmutil.match(repo[None], pats, opts)
2729 m = scmutil.match(repo[None], pats, opts)
2727 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2730 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2728 return rejected and 1 or 0
2731 return rejected and 1 or 0
2729
2732
2730 @command(
2733 @command(
2731 'graft',
2734 'graft',
2732 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2735 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2733 ('c', 'continue', False, _('resume interrupted graft')),
2736 ('c', 'continue', False, _('resume interrupted graft')),
2734 ('e', 'edit', False, _('invoke editor on commit messages')),
2737 ('e', 'edit', False, _('invoke editor on commit messages')),
2735 ('', 'log', None, _('append graft info to log message')),
2738 ('', 'log', None, _('append graft info to log message')),
2736 ('D', 'currentdate', False,
2739 ('D', 'currentdate', False,
2737 _('record the current date as commit date')),
2740 _('record the current date as commit date')),
2738 ('U', 'currentuser', False,
2741 ('U', 'currentuser', False,
2739 _('record the current user as committer'), _('DATE'))]
2742 _('record the current user as committer'), _('DATE'))]
2740 + commitopts2 + mergetoolopts + dryrunopts,
2743 + commitopts2 + mergetoolopts + dryrunopts,
2741 _('[OPTION]... [-r] REV...'))
2744 _('[OPTION]... [-r] REV...'))
2742 def graft(ui, repo, *revs, **opts):
2745 def graft(ui, repo, *revs, **opts):
2743 '''copy changes from other branches onto the current branch
2746 '''copy changes from other branches onto the current branch
2744
2747
2745 This command uses Mercurial's merge logic to copy individual
2748 This command uses Mercurial's merge logic to copy individual
2746 changes from other branches without merging branches in the
2749 changes from other branches without merging branches in the
2747 history graph. This is sometimes known as 'backporting' or
2750 history graph. This is sometimes known as 'backporting' or
2748 'cherry-picking'. By default, graft will copy user, date, and
2751 'cherry-picking'. By default, graft will copy user, date, and
2749 description from the source changesets.
2752 description from the source changesets.
2750
2753
2751 Changesets that are ancestors of the current revision, that have
2754 Changesets that are ancestors of the current revision, that have
2752 already been grafted, or that are merges will be skipped.
2755 already been grafted, or that are merges will be skipped.
2753
2756
2754 If --log is specified, log messages will have a comment appended
2757 If --log is specified, log messages will have a comment appended
2755 of the form::
2758 of the form::
2756
2759
2757 (grafted from CHANGESETHASH)
2760 (grafted from CHANGESETHASH)
2758
2761
2759 If a graft merge results in conflicts, the graft process is
2762 If a graft merge results in conflicts, the graft process is
2760 interrupted so that the current merge can be manually resolved.
2763 interrupted so that the current merge can be manually resolved.
2761 Once all conflicts are addressed, the graft process can be
2764 Once all conflicts are addressed, the graft process can be
2762 continued with the -c/--continue option.
2765 continued with the -c/--continue option.
2763
2766
2764 .. note::
2767 .. note::
2765 The -c/--continue option does not reapply earlier options.
2768 The -c/--continue option does not reapply earlier options.
2766
2769
2767 .. container:: verbose
2770 .. container:: verbose
2768
2771
2769 Examples:
2772 Examples:
2770
2773
2771 - copy a single change to the stable branch and edit its description::
2774 - copy a single change to the stable branch and edit its description::
2772
2775
2773 hg update stable
2776 hg update stable
2774 hg graft --edit 9393
2777 hg graft --edit 9393
2775
2778
2776 - graft a range of changesets with one exception, updating dates::
2779 - graft a range of changesets with one exception, updating dates::
2777
2780
2778 hg graft -D "2085::2093 and not 2091"
2781 hg graft -D "2085::2093 and not 2091"
2779
2782
2780 - continue a graft after resolving conflicts::
2783 - continue a graft after resolving conflicts::
2781
2784
2782 hg graft -c
2785 hg graft -c
2783
2786
2784 - show the source of a grafted changeset::
2787 - show the source of a grafted changeset::
2785
2788
2786 hg log --debug -r tip
2789 hg log --debug -r tip
2787
2790
2788 Returns 0 on successful completion.
2791 Returns 0 on successful completion.
2789 '''
2792 '''
2790
2793
2791 revs = list(revs)
2794 revs = list(revs)
2792 revs.extend(opts['rev'])
2795 revs.extend(opts['rev'])
2793
2796
2794 if not opts.get('user') and opts.get('currentuser'):
2797 if not opts.get('user') and opts.get('currentuser'):
2795 opts['user'] = ui.username()
2798 opts['user'] = ui.username()
2796 if not opts.get('date') and opts.get('currentdate'):
2799 if not opts.get('date') and opts.get('currentdate'):
2797 opts['date'] = "%d %d" % util.makedate()
2800 opts['date'] = "%d %d" % util.makedate()
2798
2801
2799 editor = None
2802 editor = None
2800 if opts.get('edit'):
2803 if opts.get('edit'):
2801 editor = cmdutil.commitforceeditor
2804 editor = cmdutil.commitforceeditor
2802
2805
2803 cont = False
2806 cont = False
2804 if opts['continue']:
2807 if opts['continue']:
2805 cont = True
2808 cont = True
2806 if revs:
2809 if revs:
2807 raise util.Abort(_("can't specify --continue and revisions"))
2810 raise util.Abort(_("can't specify --continue and revisions"))
2808 # read in unfinished revisions
2811 # read in unfinished revisions
2809 try:
2812 try:
2810 nodes = repo.opener.read('graftstate').splitlines()
2813 nodes = repo.opener.read('graftstate').splitlines()
2811 revs = [repo[node].rev() for node in nodes]
2814 revs = [repo[node].rev() for node in nodes]
2812 except IOError, inst:
2815 except IOError, inst:
2813 if inst.errno != errno.ENOENT:
2816 if inst.errno != errno.ENOENT:
2814 raise
2817 raise
2815 raise util.Abort(_("no graft state found, can't continue"))
2818 raise util.Abort(_("no graft state found, can't continue"))
2816 else:
2819 else:
2817 cmdutil.bailifchanged(repo)
2820 cmdutil.bailifchanged(repo)
2818 if not revs:
2821 if not revs:
2819 raise util.Abort(_('no revisions specified'))
2822 raise util.Abort(_('no revisions specified'))
2820 revs = scmutil.revrange(repo, revs)
2823 revs = scmutil.revrange(repo, revs)
2821
2824
2822 # check for merges
2825 # check for merges
2823 for rev in repo.revs('%ld and merge()', revs):
2826 for rev in repo.revs('%ld and merge()', revs):
2824 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2827 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2825 revs.remove(rev)
2828 revs.remove(rev)
2826 if not revs:
2829 if not revs:
2827 return -1
2830 return -1
2828
2831
2829 # check for ancestors of dest branch
2832 # check for ancestors of dest branch
2830 for rev in repo.revs('::. and %ld', revs):
2833 for rev in repo.revs('::. and %ld', revs):
2831 ui.warn(_('skipping ancestor revision %s\n') % rev)
2834 ui.warn(_('skipping ancestor revision %s\n') % rev)
2832 revs.remove(rev)
2835 revs.remove(rev)
2833 if not revs:
2836 if not revs:
2834 return -1
2837 return -1
2835
2838
2836 # analyze revs for earlier grafts
2839 # analyze revs for earlier grafts
2837 ids = {}
2840 ids = {}
2838 for ctx in repo.set("%ld", revs):
2841 for ctx in repo.set("%ld", revs):
2839 ids[ctx.hex()] = ctx.rev()
2842 ids[ctx.hex()] = ctx.rev()
2840 n = ctx.extra().get('source')
2843 n = ctx.extra().get('source')
2841 if n:
2844 if n:
2842 ids[n] = ctx.rev()
2845 ids[n] = ctx.rev()
2843
2846
2844 # check ancestors for earlier grafts
2847 # check ancestors for earlier grafts
2845 ui.debug('scanning for duplicate grafts\n')
2848 ui.debug('scanning for duplicate grafts\n')
2846 for ctx in repo.set("::. - ::%ld", revs):
2849 for ctx in repo.set("::. - ::%ld", revs):
2847 n = ctx.extra().get('source')
2850 n = ctx.extra().get('source')
2848 if n in ids:
2851 if n in ids:
2849 r = repo[n].rev()
2852 r = repo[n].rev()
2850 if r in revs:
2853 if r in revs:
2851 ui.warn(_('skipping already grafted revision %s\n') % r)
2854 ui.warn(_('skipping already grafted revision %s\n') % r)
2852 revs.remove(r)
2855 revs.remove(r)
2853 elif ids[n] in revs:
2856 elif ids[n] in revs:
2854 ui.warn(_('skipping already grafted revision %s '
2857 ui.warn(_('skipping already grafted revision %s '
2855 '(same origin %d)\n') % (ids[n], r))
2858 '(same origin %d)\n') % (ids[n], r))
2856 revs.remove(ids[n])
2859 revs.remove(ids[n])
2857 elif ctx.hex() in ids:
2860 elif ctx.hex() in ids:
2858 r = ids[ctx.hex()]
2861 r = ids[ctx.hex()]
2859 ui.warn(_('skipping already grafted revision %s '
2862 ui.warn(_('skipping already grafted revision %s '
2860 '(was grafted from %d)\n') % (r, ctx.rev()))
2863 '(was grafted from %d)\n') % (r, ctx.rev()))
2861 revs.remove(r)
2864 revs.remove(r)
2862 if not revs:
2865 if not revs:
2863 return -1
2866 return -1
2864
2867
2865 wlock = repo.wlock()
2868 wlock = repo.wlock()
2866 try:
2869 try:
2867 current = repo['.']
2870 current = repo['.']
2868 for pos, ctx in enumerate(repo.set("%ld", revs)):
2871 for pos, ctx in enumerate(repo.set("%ld", revs)):
2869
2872
2870 ui.status(_('grafting revision %s\n') % ctx.rev())
2873 ui.status(_('grafting revision %s\n') % ctx.rev())
2871 if opts.get('dry_run'):
2874 if opts.get('dry_run'):
2872 continue
2875 continue
2873
2876
2874 source = ctx.extra().get('source')
2877 source = ctx.extra().get('source')
2875 if not source:
2878 if not source:
2876 source = ctx.hex()
2879 source = ctx.hex()
2877 extra = {'source': source}
2880 extra = {'source': source}
2878 user = ctx.user()
2881 user = ctx.user()
2879 if opts.get('user'):
2882 if opts.get('user'):
2880 user = opts['user']
2883 user = opts['user']
2881 date = ctx.date()
2884 date = ctx.date()
2882 if opts.get('date'):
2885 if opts.get('date'):
2883 date = opts['date']
2886 date = opts['date']
2884 message = ctx.description()
2887 message = ctx.description()
2885 if opts.get('log'):
2888 if opts.get('log'):
2886 message += '\n(grafted from %s)' % ctx.hex()
2889 message += '\n(grafted from %s)' % ctx.hex()
2887
2890
2888 # we don't merge the first commit when continuing
2891 # we don't merge the first commit when continuing
2889 if not cont:
2892 if not cont:
2890 # perform the graft merge with p1(rev) as 'ancestor'
2893 # perform the graft merge with p1(rev) as 'ancestor'
2891 try:
2894 try:
2892 # ui.forcemerge is an internal variable, do not document
2895 # ui.forcemerge is an internal variable, do not document
2893 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2896 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2894 stats = mergemod.update(repo, ctx.node(), True, True, False,
2897 stats = mergemod.update(repo, ctx.node(), True, True, False,
2895 ctx.p1().node())
2898 ctx.p1().node())
2896 finally:
2899 finally:
2897 repo.ui.setconfig('ui', 'forcemerge', '')
2900 repo.ui.setconfig('ui', 'forcemerge', '')
2898 # report any conflicts
2901 # report any conflicts
2899 if stats and stats[3] > 0:
2902 if stats and stats[3] > 0:
2900 # write out state for --continue
2903 # write out state for --continue
2901 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2904 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2902 repo.opener.write('graftstate', ''.join(nodelines))
2905 repo.opener.write('graftstate', ''.join(nodelines))
2903 raise util.Abort(
2906 raise util.Abort(
2904 _("unresolved conflicts, can't continue"),
2907 _("unresolved conflicts, can't continue"),
2905 hint=_('use hg resolve and hg graft --continue'))
2908 hint=_('use hg resolve and hg graft --continue'))
2906 else:
2909 else:
2907 cont = False
2910 cont = False
2908
2911
2909 # drop the second merge parent
2912 # drop the second merge parent
2910 repo.setparents(current.node(), nullid)
2913 repo.setparents(current.node(), nullid)
2911 repo.dirstate.write()
2914 repo.dirstate.write()
2912 # fix up dirstate for copies and renames
2915 # fix up dirstate for copies and renames
2913 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2916 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2914
2917
2915 # commit
2918 # commit
2916 node = repo.commit(text=message, user=user,
2919 node = repo.commit(text=message, user=user,
2917 date=date, extra=extra, editor=editor)
2920 date=date, extra=extra, editor=editor)
2918 if node is None:
2921 if node is None:
2919 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2922 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2920 else:
2923 else:
2921 current = repo[node]
2924 current = repo[node]
2922 finally:
2925 finally:
2923 wlock.release()
2926 wlock.release()
2924
2927
2925 # remove state when we complete successfully
2928 # remove state when we complete successfully
2926 if not opts.get('dry_run'):
2929 if not opts.get('dry_run'):
2927 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2930 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2928
2931
2929 return 0
2932 return 0
2930
2933
2931 @command('grep',
2934 @command('grep',
2932 [('0', 'print0', None, _('end fields with NUL')),
2935 [('0', 'print0', None, _('end fields with NUL')),
2933 ('', 'all', None, _('print all revisions that match')),
2936 ('', 'all', None, _('print all revisions that match')),
2934 ('a', 'text', None, _('treat all files as text')),
2937 ('a', 'text', None, _('treat all files as text')),
2935 ('f', 'follow', None,
2938 ('f', 'follow', None,
2936 _('follow changeset history,'
2939 _('follow changeset history,'
2937 ' or file history across copies and renames')),
2940 ' or file history across copies and renames')),
2938 ('i', 'ignore-case', None, _('ignore case when matching')),
2941 ('i', 'ignore-case', None, _('ignore case when matching')),
2939 ('l', 'files-with-matches', None,
2942 ('l', 'files-with-matches', None,
2940 _('print only filenames and revisions that match')),
2943 _('print only filenames and revisions that match')),
2941 ('n', 'line-number', None, _('print matching line numbers')),
2944 ('n', 'line-number', None, _('print matching line numbers')),
2942 ('r', 'rev', [],
2945 ('r', 'rev', [],
2943 _('only search files changed within revision range'), _('REV')),
2946 _('only search files changed within revision range'), _('REV')),
2944 ('u', 'user', None, _('list the author (long with -v)')),
2947 ('u', 'user', None, _('list the author (long with -v)')),
2945 ('d', 'date', None, _('list the date (short with -q)')),
2948 ('d', 'date', None, _('list the date (short with -q)')),
2946 ] + walkopts,
2949 ] + walkopts,
2947 _('[OPTION]... PATTERN [FILE]...'))
2950 _('[OPTION]... PATTERN [FILE]...'))
2948 def grep(ui, repo, pattern, *pats, **opts):
2951 def grep(ui, repo, pattern, *pats, **opts):
2949 """search for a pattern in specified files and revisions
2952 """search for a pattern in specified files and revisions
2950
2953
2951 Search revisions of files for a regular expression.
2954 Search revisions of files for a regular expression.
2952
2955
2953 This command behaves differently than Unix grep. It only accepts
2956 This command behaves differently than Unix grep. It only accepts
2954 Python/Perl regexps. It searches repository history, not the
2957 Python/Perl regexps. It searches repository history, not the
2955 working directory. It always prints the revision number in which a
2958 working directory. It always prints the revision number in which a
2956 match appears.
2959 match appears.
2957
2960
2958 By default, grep only prints output for the first revision of a
2961 By default, grep only prints output for the first revision of a
2959 file in which it finds a match. To get it to print every revision
2962 file in which it finds a match. To get it to print every revision
2960 that contains a change in match status ("-" for a match that
2963 that contains a change in match status ("-" for a match that
2961 becomes a non-match, or "+" for a non-match that becomes a match),
2964 becomes a non-match, or "+" for a non-match that becomes a match),
2962 use the --all flag.
2965 use the --all flag.
2963
2966
2964 Returns 0 if a match is found, 1 otherwise.
2967 Returns 0 if a match is found, 1 otherwise.
2965 """
2968 """
2966 reflags = re.M
2969 reflags = re.M
2967 if opts.get('ignore_case'):
2970 if opts.get('ignore_case'):
2968 reflags |= re.I
2971 reflags |= re.I
2969 try:
2972 try:
2970 regexp = re.compile(pattern, reflags)
2973 regexp = re.compile(pattern, reflags)
2971 except re.error, inst:
2974 except re.error, inst:
2972 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2975 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2973 return 1
2976 return 1
2974 sep, eol = ':', '\n'
2977 sep, eol = ':', '\n'
2975 if opts.get('print0'):
2978 if opts.get('print0'):
2976 sep = eol = '\0'
2979 sep = eol = '\0'
2977
2980
2978 getfile = util.lrucachefunc(repo.file)
2981 getfile = util.lrucachefunc(repo.file)
2979
2982
2980 def matchlines(body):
2983 def matchlines(body):
2981 begin = 0
2984 begin = 0
2982 linenum = 0
2985 linenum = 0
2983 while begin < len(body):
2986 while begin < len(body):
2984 match = regexp.search(body, begin)
2987 match = regexp.search(body, begin)
2985 if not match:
2988 if not match:
2986 break
2989 break
2987 mstart, mend = match.span()
2990 mstart, mend = match.span()
2988 linenum += body.count('\n', begin, mstart) + 1
2991 linenum += body.count('\n', begin, mstart) + 1
2989 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2992 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2990 begin = body.find('\n', mend) + 1 or len(body) + 1
2993 begin = body.find('\n', mend) + 1 or len(body) + 1
2991 lend = begin - 1
2994 lend = begin - 1
2992 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2995 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2993
2996
2994 class linestate(object):
2997 class linestate(object):
2995 def __init__(self, line, linenum, colstart, colend):
2998 def __init__(self, line, linenum, colstart, colend):
2996 self.line = line
2999 self.line = line
2997 self.linenum = linenum
3000 self.linenum = linenum
2998 self.colstart = colstart
3001 self.colstart = colstart
2999 self.colend = colend
3002 self.colend = colend
3000
3003
3001 def __hash__(self):
3004 def __hash__(self):
3002 return hash((self.linenum, self.line))
3005 return hash((self.linenum, self.line))
3003
3006
3004 def __eq__(self, other):
3007 def __eq__(self, other):
3005 return self.line == other.line
3008 return self.line == other.line
3006
3009
3007 matches = {}
3010 matches = {}
3008 copies = {}
3011 copies = {}
3009 def grepbody(fn, rev, body):
3012 def grepbody(fn, rev, body):
3010 matches[rev].setdefault(fn, [])
3013 matches[rev].setdefault(fn, [])
3011 m = matches[rev][fn]
3014 m = matches[rev][fn]
3012 for lnum, cstart, cend, line in matchlines(body):
3015 for lnum, cstart, cend, line in matchlines(body):
3013 s = linestate(line, lnum, cstart, cend)
3016 s = linestate(line, lnum, cstart, cend)
3014 m.append(s)
3017 m.append(s)
3015
3018
3016 def difflinestates(a, b):
3019 def difflinestates(a, b):
3017 sm = difflib.SequenceMatcher(None, a, b)
3020 sm = difflib.SequenceMatcher(None, a, b)
3018 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3021 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3019 if tag == 'insert':
3022 if tag == 'insert':
3020 for i in xrange(blo, bhi):
3023 for i in xrange(blo, bhi):
3021 yield ('+', b[i])
3024 yield ('+', b[i])
3022 elif tag == 'delete':
3025 elif tag == 'delete':
3023 for i in xrange(alo, ahi):
3026 for i in xrange(alo, ahi):
3024 yield ('-', a[i])
3027 yield ('-', a[i])
3025 elif tag == 'replace':
3028 elif tag == 'replace':
3026 for i in xrange(alo, ahi):
3029 for i in xrange(alo, ahi):
3027 yield ('-', a[i])
3030 yield ('-', a[i])
3028 for i in xrange(blo, bhi):
3031 for i in xrange(blo, bhi):
3029 yield ('+', b[i])
3032 yield ('+', b[i])
3030
3033
3031 def display(fn, ctx, pstates, states):
3034 def display(fn, ctx, pstates, states):
3032 rev = ctx.rev()
3035 rev = ctx.rev()
3033 datefunc = ui.quiet and util.shortdate or util.datestr
3036 datefunc = ui.quiet and util.shortdate or util.datestr
3034 found = False
3037 found = False
3035 filerevmatches = {}
3038 filerevmatches = {}
3036 def binary():
3039 def binary():
3037 flog = getfile(fn)
3040 flog = getfile(fn)
3038 return util.binary(flog.read(ctx.filenode(fn)))
3041 return util.binary(flog.read(ctx.filenode(fn)))
3039
3042
3040 if opts.get('all'):
3043 if opts.get('all'):
3041 iter = difflinestates(pstates, states)
3044 iter = difflinestates(pstates, states)
3042 else:
3045 else:
3043 iter = [('', l) for l in states]
3046 iter = [('', l) for l in states]
3044 for change, l in iter:
3047 for change, l in iter:
3045 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3048 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3046 before, match, after = None, None, None
3049 before, match, after = None, None, None
3047
3050
3048 if opts.get('line_number'):
3051 if opts.get('line_number'):
3049 cols.append((str(l.linenum), 'grep.linenumber'))
3052 cols.append((str(l.linenum), 'grep.linenumber'))
3050 if opts.get('all'):
3053 if opts.get('all'):
3051 cols.append((change, 'grep.change'))
3054 cols.append((change, 'grep.change'))
3052 if opts.get('user'):
3055 if opts.get('user'):
3053 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3056 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3054 if opts.get('date'):
3057 if opts.get('date'):
3055 cols.append((datefunc(ctx.date()), 'grep.date'))
3058 cols.append((datefunc(ctx.date()), 'grep.date'))
3056 if opts.get('files_with_matches'):
3059 if opts.get('files_with_matches'):
3057 c = (fn, rev)
3060 c = (fn, rev)
3058 if c in filerevmatches:
3061 if c in filerevmatches:
3059 continue
3062 continue
3060 filerevmatches[c] = 1
3063 filerevmatches[c] = 1
3061 else:
3064 else:
3062 before = l.line[:l.colstart]
3065 before = l.line[:l.colstart]
3063 match = l.line[l.colstart:l.colend]
3066 match = l.line[l.colstart:l.colend]
3064 after = l.line[l.colend:]
3067 after = l.line[l.colend:]
3065 for col, label in cols[:-1]:
3068 for col, label in cols[:-1]:
3066 ui.write(col, label=label)
3069 ui.write(col, label=label)
3067 ui.write(sep, label='grep.sep')
3070 ui.write(sep, label='grep.sep')
3068 ui.write(cols[-1][0], label=cols[-1][1])
3071 ui.write(cols[-1][0], label=cols[-1][1])
3069 if before is not None:
3072 if before is not None:
3070 ui.write(sep, label='grep.sep')
3073 ui.write(sep, label='grep.sep')
3071 if not opts.get('text') and binary():
3074 if not opts.get('text') and binary():
3072 ui.write(" Binary file matches")
3075 ui.write(" Binary file matches")
3073 else:
3076 else:
3074 ui.write(before)
3077 ui.write(before)
3075 ui.write(match, label='grep.match')
3078 ui.write(match, label='grep.match')
3076 ui.write(after)
3079 ui.write(after)
3077 ui.write(eol)
3080 ui.write(eol)
3078 found = True
3081 found = True
3079 return found
3082 return found
3080
3083
3081 skip = {}
3084 skip = {}
3082 revfiles = {}
3085 revfiles = {}
3083 matchfn = scmutil.match(repo[None], pats, opts)
3086 matchfn = scmutil.match(repo[None], pats, opts)
3084 found = False
3087 found = False
3085 follow = opts.get('follow')
3088 follow = opts.get('follow')
3086
3089
3087 def prep(ctx, fns):
3090 def prep(ctx, fns):
3088 rev = ctx.rev()
3091 rev = ctx.rev()
3089 pctx = ctx.p1()
3092 pctx = ctx.p1()
3090 parent = pctx.rev()
3093 parent = pctx.rev()
3091 matches.setdefault(rev, {})
3094 matches.setdefault(rev, {})
3092 matches.setdefault(parent, {})
3095 matches.setdefault(parent, {})
3093 files = revfiles.setdefault(rev, [])
3096 files = revfiles.setdefault(rev, [])
3094 for fn in fns:
3097 for fn in fns:
3095 flog = getfile(fn)
3098 flog = getfile(fn)
3096 try:
3099 try:
3097 fnode = ctx.filenode(fn)
3100 fnode = ctx.filenode(fn)
3098 except error.LookupError:
3101 except error.LookupError:
3099 continue
3102 continue
3100
3103
3101 copied = flog.renamed(fnode)
3104 copied = flog.renamed(fnode)
3102 copy = follow and copied and copied[0]
3105 copy = follow and copied and copied[0]
3103 if copy:
3106 if copy:
3104 copies.setdefault(rev, {})[fn] = copy
3107 copies.setdefault(rev, {})[fn] = copy
3105 if fn in skip:
3108 if fn in skip:
3106 if copy:
3109 if copy:
3107 skip[copy] = True
3110 skip[copy] = True
3108 continue
3111 continue
3109 files.append(fn)
3112 files.append(fn)
3110
3113
3111 if fn not in matches[rev]:
3114 if fn not in matches[rev]:
3112 grepbody(fn, rev, flog.read(fnode))
3115 grepbody(fn, rev, flog.read(fnode))
3113
3116
3114 pfn = copy or fn
3117 pfn = copy or fn
3115 if pfn not in matches[parent]:
3118 if pfn not in matches[parent]:
3116 try:
3119 try:
3117 fnode = pctx.filenode(pfn)
3120 fnode = pctx.filenode(pfn)
3118 grepbody(pfn, parent, flog.read(fnode))
3121 grepbody(pfn, parent, flog.read(fnode))
3119 except error.LookupError:
3122 except error.LookupError:
3120 pass
3123 pass
3121
3124
3122 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3125 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3123 rev = ctx.rev()
3126 rev = ctx.rev()
3124 parent = ctx.p1().rev()
3127 parent = ctx.p1().rev()
3125 for fn in sorted(revfiles.get(rev, [])):
3128 for fn in sorted(revfiles.get(rev, [])):
3126 states = matches[rev][fn]
3129 states = matches[rev][fn]
3127 copy = copies.get(rev, {}).get(fn)
3130 copy = copies.get(rev, {}).get(fn)
3128 if fn in skip:
3131 if fn in skip:
3129 if copy:
3132 if copy:
3130 skip[copy] = True
3133 skip[copy] = True
3131 continue
3134 continue
3132 pstates = matches.get(parent, {}).get(copy or fn, [])
3135 pstates = matches.get(parent, {}).get(copy or fn, [])
3133 if pstates or states:
3136 if pstates or states:
3134 r = display(fn, ctx, pstates, states)
3137 r = display(fn, ctx, pstates, states)
3135 found = found or r
3138 found = found or r
3136 if r and not opts.get('all'):
3139 if r and not opts.get('all'):
3137 skip[fn] = True
3140 skip[fn] = True
3138 if copy:
3141 if copy:
3139 skip[copy] = True
3142 skip[copy] = True
3140 del matches[rev]
3143 del matches[rev]
3141 del revfiles[rev]
3144 del revfiles[rev]
3142
3145
3143 return not found
3146 return not found
3144
3147
3145 @command('heads',
3148 @command('heads',
3146 [('r', 'rev', '',
3149 [('r', 'rev', '',
3147 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3150 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3148 ('t', 'topo', False, _('show topological heads only')),
3151 ('t', 'topo', False, _('show topological heads only')),
3149 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3152 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3150 ('c', 'closed', False, _('show normal and closed branch heads')),
3153 ('c', 'closed', False, _('show normal and closed branch heads')),
3151 ] + templateopts,
3154 ] + templateopts,
3152 _('[-ct] [-r STARTREV] [REV]...'))
3155 _('[-ct] [-r STARTREV] [REV]...'))
3153 def heads(ui, repo, *branchrevs, **opts):
3156 def heads(ui, repo, *branchrevs, **opts):
3154 """show current repository heads or show branch heads
3157 """show current repository heads or show branch heads
3155
3158
3156 With no arguments, show all repository branch heads.
3159 With no arguments, show all repository branch heads.
3157
3160
3158 Repository "heads" are changesets with no child changesets. They are
3161 Repository "heads" are changesets with no child changesets. They are
3159 where development generally takes place and are the usual targets
3162 where development generally takes place and are the usual targets
3160 for update and merge operations. Branch heads are changesets that have
3163 for update and merge operations. Branch heads are changesets that have
3161 no child changeset on the same branch.
3164 no child changeset on the same branch.
3162
3165
3163 If one or more REVs are given, only branch heads on the branches
3166 If one or more REVs are given, only branch heads on the branches
3164 associated with the specified changesets are shown. This means
3167 associated with the specified changesets are shown. This means
3165 that you can use :hg:`heads foo` to see the heads on a branch
3168 that you can use :hg:`heads foo` to see the heads on a branch
3166 named ``foo``.
3169 named ``foo``.
3167
3170
3168 If -c/--closed is specified, also show branch heads marked closed
3171 If -c/--closed is specified, also show branch heads marked closed
3169 (see :hg:`commit --close-branch`).
3172 (see :hg:`commit --close-branch`).
3170
3173
3171 If STARTREV is specified, only those heads that are descendants of
3174 If STARTREV is specified, only those heads that are descendants of
3172 STARTREV will be displayed.
3175 STARTREV will be displayed.
3173
3176
3174 If -t/--topo is specified, named branch mechanics will be ignored and only
3177 If -t/--topo is specified, named branch mechanics will be ignored and only
3175 changesets without children will be shown.
3178 changesets without children will be shown.
3176
3179
3177 Returns 0 if matching heads are found, 1 if not.
3180 Returns 0 if matching heads are found, 1 if not.
3178 """
3181 """
3179
3182
3180 start = None
3183 start = None
3181 if 'rev' in opts:
3184 if 'rev' in opts:
3182 start = scmutil.revsingle(repo, opts['rev'], None).node()
3185 start = scmutil.revsingle(repo, opts['rev'], None).node()
3183
3186
3184 if opts.get('topo'):
3187 if opts.get('topo'):
3185 heads = [repo[h] for h in repo.heads(start)]
3188 heads = [repo[h] for h in repo.heads(start)]
3186 else:
3189 else:
3187 heads = []
3190 heads = []
3188 for branch in repo.branchmap():
3191 for branch in repo.branchmap():
3189 heads += repo.branchheads(branch, start, opts.get('closed'))
3192 heads += repo.branchheads(branch, start, opts.get('closed'))
3190 heads = [repo[h] for h in heads]
3193 heads = [repo[h] for h in heads]
3191
3194
3192 if branchrevs:
3195 if branchrevs:
3193 branches = set(repo[br].branch() for br in branchrevs)
3196 branches = set(repo[br].branch() for br in branchrevs)
3194 heads = [h for h in heads if h.branch() in branches]
3197 heads = [h for h in heads if h.branch() in branches]
3195
3198
3196 if opts.get('active') and branchrevs:
3199 if opts.get('active') and branchrevs:
3197 dagheads = repo.heads(start)
3200 dagheads = repo.heads(start)
3198 heads = [h for h in heads if h.node() in dagheads]
3201 heads = [h for h in heads if h.node() in dagheads]
3199
3202
3200 if branchrevs:
3203 if branchrevs:
3201 haveheads = set(h.branch() for h in heads)
3204 haveheads = set(h.branch() for h in heads)
3202 if branches - haveheads:
3205 if branches - haveheads:
3203 headless = ', '.join(b for b in branches - haveheads)
3206 headless = ', '.join(b for b in branches - haveheads)
3204 msg = _('no open branch heads found on branches %s')
3207 msg = _('no open branch heads found on branches %s')
3205 if opts.get('rev'):
3208 if opts.get('rev'):
3206 msg += _(' (started at %s)') % opts['rev']
3209 msg += _(' (started at %s)') % opts['rev']
3207 ui.warn((msg + '\n') % headless)
3210 ui.warn((msg + '\n') % headless)
3208
3211
3209 if not heads:
3212 if not heads:
3210 return 1
3213 return 1
3211
3214
3212 heads = sorted(heads, key=lambda x: -x.rev())
3215 heads = sorted(heads, key=lambda x: -x.rev())
3213 displayer = cmdutil.show_changeset(ui, repo, opts)
3216 displayer = cmdutil.show_changeset(ui, repo, opts)
3214 for ctx in heads:
3217 for ctx in heads:
3215 displayer.show(ctx)
3218 displayer.show(ctx)
3216 displayer.close()
3219 displayer.close()
3217
3220
3218 @command('help',
3221 @command('help',
3219 [('e', 'extension', None, _('show only help for extensions')),
3222 [('e', 'extension', None, _('show only help for extensions')),
3220 ('c', 'command', None, _('show only help for commands')),
3223 ('c', 'command', None, _('show only help for commands')),
3221 ('k', 'keyword', '', _('show topics matching keyword')),
3224 ('k', 'keyword', '', _('show topics matching keyword')),
3222 ],
3225 ],
3223 _('[-ec] [TOPIC]'))
3226 _('[-ec] [TOPIC]'))
3224 def help_(ui, name=None, **opts):
3227 def help_(ui, name=None, **opts):
3225 """show help for a given topic or a help overview
3228 """show help for a given topic or a help overview
3226
3229
3227 With no arguments, print a list of commands with short help messages.
3230 With no arguments, print a list of commands with short help messages.
3228
3231
3229 Given a topic, extension, or command name, print help for that
3232 Given a topic, extension, or command name, print help for that
3230 topic.
3233 topic.
3231
3234
3232 Returns 0 if successful.
3235 Returns 0 if successful.
3233 """
3236 """
3234
3237
3235 textwidth = min(ui.termwidth(), 80) - 2
3238 textwidth = min(ui.termwidth(), 80) - 2
3236
3239
3237 keep = ui.verbose and ['verbose'] or []
3240 keep = ui.verbose and ['verbose'] or []
3238 text = help.help_(ui, name, **opts)
3241 text = help.help_(ui, name, **opts)
3239
3242
3240 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3243 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3241 if 'verbose' in pruned:
3244 if 'verbose' in pruned:
3242 keep.append('omitted')
3245 keep.append('omitted')
3243 else:
3246 else:
3244 keep.append('notomitted')
3247 keep.append('notomitted')
3245 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3248 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3246 ui.write(formatted)
3249 ui.write(formatted)
3247
3250
3248
3251
3249 @command('identify|id',
3252 @command('identify|id',
3250 [('r', 'rev', '',
3253 [('r', 'rev', '',
3251 _('identify the specified revision'), _('REV')),
3254 _('identify the specified revision'), _('REV')),
3252 ('n', 'num', None, _('show local revision number')),
3255 ('n', 'num', None, _('show local revision number')),
3253 ('i', 'id', None, _('show global revision id')),
3256 ('i', 'id', None, _('show global revision id')),
3254 ('b', 'branch', None, _('show branch')),
3257 ('b', 'branch', None, _('show branch')),
3255 ('t', 'tags', None, _('show tags')),
3258 ('t', 'tags', None, _('show tags')),
3256 ('B', 'bookmarks', None, _('show bookmarks')),
3259 ('B', 'bookmarks', None, _('show bookmarks')),
3257 ] + remoteopts,
3260 ] + remoteopts,
3258 _('[-nibtB] [-r REV] [SOURCE]'))
3261 _('[-nibtB] [-r REV] [SOURCE]'))
3259 def identify(ui, repo, source=None, rev=None,
3262 def identify(ui, repo, source=None, rev=None,
3260 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3263 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3261 """identify the working copy or specified revision
3264 """identify the working copy or specified revision
3262
3265
3263 Print a summary identifying the repository state at REV using one or
3266 Print a summary identifying the repository state at REV using one or
3264 two parent hash identifiers, followed by a "+" if the working
3267 two parent hash identifiers, followed by a "+" if the working
3265 directory has uncommitted changes, the branch name (if not default),
3268 directory has uncommitted changes, the branch name (if not default),
3266 a list of tags, and a list of bookmarks.
3269 a list of tags, and a list of bookmarks.
3267
3270
3268 When REV is not given, print a summary of the current state of the
3271 When REV is not given, print a summary of the current state of the
3269 repository.
3272 repository.
3270
3273
3271 Specifying a path to a repository root or Mercurial bundle will
3274 Specifying a path to a repository root or Mercurial bundle will
3272 cause lookup to operate on that repository/bundle.
3275 cause lookup to operate on that repository/bundle.
3273
3276
3274 .. container:: verbose
3277 .. container:: verbose
3275
3278
3276 Examples:
3279 Examples:
3277
3280
3278 - generate a build identifier for the working directory::
3281 - generate a build identifier for the working directory::
3279
3282
3280 hg id --id > build-id.dat
3283 hg id --id > build-id.dat
3281
3284
3282 - find the revision corresponding to a tag::
3285 - find the revision corresponding to a tag::
3283
3286
3284 hg id -n -r 1.3
3287 hg id -n -r 1.3
3285
3288
3286 - check the most recent revision of a remote repository::
3289 - check the most recent revision of a remote repository::
3287
3290
3288 hg id -r tip http://selenic.com/hg/
3291 hg id -r tip http://selenic.com/hg/
3289
3292
3290 Returns 0 if successful.
3293 Returns 0 if successful.
3291 """
3294 """
3292
3295
3293 if not repo and not source:
3296 if not repo and not source:
3294 raise util.Abort(_("there is no Mercurial repository here "
3297 raise util.Abort(_("there is no Mercurial repository here "
3295 "(.hg not found)"))
3298 "(.hg not found)"))
3296
3299
3297 hexfunc = ui.debugflag and hex or short
3300 hexfunc = ui.debugflag and hex or short
3298 default = not (num or id or branch or tags or bookmarks)
3301 default = not (num or id or branch or tags or bookmarks)
3299 output = []
3302 output = []
3300 revs = []
3303 revs = []
3301
3304
3302 if source:
3305 if source:
3303 source, branches = hg.parseurl(ui.expandpath(source))
3306 source, branches = hg.parseurl(ui.expandpath(source))
3304 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3307 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3305 repo = peer.local()
3308 repo = peer.local()
3306 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3309 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3307
3310
3308 if not repo:
3311 if not repo:
3309 if num or branch or tags:
3312 if num or branch or tags:
3310 raise util.Abort(
3313 raise util.Abort(
3311 _("can't query remote revision number, branch, or tags"))
3314 _("can't query remote revision number, branch, or tags"))
3312 if not rev and revs:
3315 if not rev and revs:
3313 rev = revs[0]
3316 rev = revs[0]
3314 if not rev:
3317 if not rev:
3315 rev = "tip"
3318 rev = "tip"
3316
3319
3317 remoterev = peer.lookup(rev)
3320 remoterev = peer.lookup(rev)
3318 if default or id:
3321 if default or id:
3319 output = [hexfunc(remoterev)]
3322 output = [hexfunc(remoterev)]
3320
3323
3321 def getbms():
3324 def getbms():
3322 bms = []
3325 bms = []
3323
3326
3324 if 'bookmarks' in peer.listkeys('namespaces'):
3327 if 'bookmarks' in peer.listkeys('namespaces'):
3325 hexremoterev = hex(remoterev)
3328 hexremoterev = hex(remoterev)
3326 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3329 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3327 if bmr == hexremoterev]
3330 if bmr == hexremoterev]
3328
3331
3329 return sorted(bms)
3332 return sorted(bms)
3330
3333
3331 if bookmarks:
3334 if bookmarks:
3332 output.extend(getbms())
3335 output.extend(getbms())
3333 elif default and not ui.quiet:
3336 elif default and not ui.quiet:
3334 # multiple bookmarks for a single parent separated by '/'
3337 # multiple bookmarks for a single parent separated by '/'
3335 bm = '/'.join(getbms())
3338 bm = '/'.join(getbms())
3336 if bm:
3339 if bm:
3337 output.append(bm)
3340 output.append(bm)
3338 else:
3341 else:
3339 if not rev:
3342 if not rev:
3340 ctx = repo[None]
3343 ctx = repo[None]
3341 parents = ctx.parents()
3344 parents = ctx.parents()
3342 changed = ""
3345 changed = ""
3343 if default or id or num:
3346 if default or id or num:
3344 if (util.any(repo.status())
3347 if (util.any(repo.status())
3345 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3348 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3346 changed = '+'
3349 changed = '+'
3347 if default or id:
3350 if default or id:
3348 output = ["%s%s" %
3351 output = ["%s%s" %
3349 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3352 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3350 if num:
3353 if num:
3351 output.append("%s%s" %
3354 output.append("%s%s" %
3352 ('+'.join([str(p.rev()) for p in parents]), changed))
3355 ('+'.join([str(p.rev()) for p in parents]), changed))
3353 else:
3356 else:
3354 ctx = scmutil.revsingle(repo, rev)
3357 ctx = scmutil.revsingle(repo, rev)
3355 if default or id:
3358 if default or id:
3356 output = [hexfunc(ctx.node())]
3359 output = [hexfunc(ctx.node())]
3357 if num:
3360 if num:
3358 output.append(str(ctx.rev()))
3361 output.append(str(ctx.rev()))
3359
3362
3360 if default and not ui.quiet:
3363 if default and not ui.quiet:
3361 b = ctx.branch()
3364 b = ctx.branch()
3362 if b != 'default':
3365 if b != 'default':
3363 output.append("(%s)" % b)
3366 output.append("(%s)" % b)
3364
3367
3365 # multiple tags for a single parent separated by '/'
3368 # multiple tags for a single parent separated by '/'
3366 t = '/'.join(ctx.tags())
3369 t = '/'.join(ctx.tags())
3367 if t:
3370 if t:
3368 output.append(t)
3371 output.append(t)
3369
3372
3370 # multiple bookmarks for a single parent separated by '/'
3373 # multiple bookmarks for a single parent separated by '/'
3371 bm = '/'.join(ctx.bookmarks())
3374 bm = '/'.join(ctx.bookmarks())
3372 if bm:
3375 if bm:
3373 output.append(bm)
3376 output.append(bm)
3374 else:
3377 else:
3375 if branch:
3378 if branch:
3376 output.append(ctx.branch())
3379 output.append(ctx.branch())
3377
3380
3378 if tags:
3381 if tags:
3379 output.extend(ctx.tags())
3382 output.extend(ctx.tags())
3380
3383
3381 if bookmarks:
3384 if bookmarks:
3382 output.extend(ctx.bookmarks())
3385 output.extend(ctx.bookmarks())
3383
3386
3384 ui.write("%s\n" % ' '.join(output))
3387 ui.write("%s\n" % ' '.join(output))
3385
3388
3386 @command('import|patch',
3389 @command('import|patch',
3387 [('p', 'strip', 1,
3390 [('p', 'strip', 1,
3388 _('directory strip option for patch. This has the same '
3391 _('directory strip option for patch. This has the same '
3389 'meaning as the corresponding patch option'), _('NUM')),
3392 'meaning as the corresponding patch option'), _('NUM')),
3390 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3393 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3391 ('e', 'edit', False, _('invoke editor on commit messages')),
3394 ('e', 'edit', False, _('invoke editor on commit messages')),
3392 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3395 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3393 ('', 'no-commit', None,
3396 ('', 'no-commit', None,
3394 _("don't commit, just update the working directory")),
3397 _("don't commit, just update the working directory")),
3395 ('', 'bypass', None,
3398 ('', 'bypass', None,
3396 _("apply patch without touching the working directory")),
3399 _("apply patch without touching the working directory")),
3397 ('', 'exact', None,
3400 ('', 'exact', None,
3398 _('apply patch to the nodes from which it was generated')),
3401 _('apply patch to the nodes from which it was generated')),
3399 ('', 'import-branch', None,
3402 ('', 'import-branch', None,
3400 _('use any branch information in patch (implied by --exact)'))] +
3403 _('use any branch information in patch (implied by --exact)'))] +
3401 commitopts + commitopts2 + similarityopts,
3404 commitopts + commitopts2 + similarityopts,
3402 _('[OPTION]... PATCH...'))
3405 _('[OPTION]... PATCH...'))
3403 def import_(ui, repo, patch1=None, *patches, **opts):
3406 def import_(ui, repo, patch1=None, *patches, **opts):
3404 """import an ordered set of patches
3407 """import an ordered set of patches
3405
3408
3406 Import a list of patches and commit them individually (unless
3409 Import a list of patches and commit them individually (unless
3407 --no-commit is specified).
3410 --no-commit is specified).
3408
3411
3409 If there are outstanding changes in the working directory, import
3412 If there are outstanding changes in the working directory, import
3410 will abort unless given the -f/--force flag.
3413 will abort unless given the -f/--force flag.
3411
3414
3412 You can import a patch straight from a mail message. Even patches
3415 You can import a patch straight from a mail message. Even patches
3413 as attachments work (to use the body part, it must have type
3416 as attachments work (to use the body part, it must have type
3414 text/plain or text/x-patch). From and Subject headers of email
3417 text/plain or text/x-patch). From and Subject headers of email
3415 message are used as default committer and commit message. All
3418 message are used as default committer and commit message. All
3416 text/plain body parts before first diff are added to commit
3419 text/plain body parts before first diff are added to commit
3417 message.
3420 message.
3418
3421
3419 If the imported patch was generated by :hg:`export`, user and
3422 If the imported patch was generated by :hg:`export`, user and
3420 description from patch override values from message headers and
3423 description from patch override values from message headers and
3421 body. Values given on command line with -m/--message and -u/--user
3424 body. Values given on command line with -m/--message and -u/--user
3422 override these.
3425 override these.
3423
3426
3424 If --exact is specified, import will set the working directory to
3427 If --exact is specified, import will set the working directory to
3425 the parent of each patch before applying it, and will abort if the
3428 the parent of each patch before applying it, and will abort if the
3426 resulting changeset has a different ID than the one recorded in
3429 resulting changeset has a different ID than the one recorded in
3427 the patch. This may happen due to character set problems or other
3430 the patch. This may happen due to character set problems or other
3428 deficiencies in the text patch format.
3431 deficiencies in the text patch format.
3429
3432
3430 Use --bypass to apply and commit patches directly to the
3433 Use --bypass to apply and commit patches directly to the
3431 repository, not touching the working directory. Without --exact,
3434 repository, not touching the working directory. Without --exact,
3432 patches will be applied on top of the working directory parent
3435 patches will be applied on top of the working directory parent
3433 revision.
3436 revision.
3434
3437
3435 With -s/--similarity, hg will attempt to discover renames and
3438 With -s/--similarity, hg will attempt to discover renames and
3436 copies in the patch in the same way as :hg:`addremove`.
3439 copies in the patch in the same way as :hg:`addremove`.
3437
3440
3438 To read a patch from standard input, use "-" as the patch name. If
3441 To read a patch from standard input, use "-" as the patch name. If
3439 a URL is specified, the patch will be downloaded from it.
3442 a URL is specified, the patch will be downloaded from it.
3440 See :hg:`help dates` for a list of formats valid for -d/--date.
3443 See :hg:`help dates` for a list of formats valid for -d/--date.
3441
3444
3442 .. container:: verbose
3445 .. container:: verbose
3443
3446
3444 Examples:
3447 Examples:
3445
3448
3446 - import a traditional patch from a website and detect renames::
3449 - import a traditional patch from a website and detect renames::
3447
3450
3448 hg import -s 80 http://example.com/bugfix.patch
3451 hg import -s 80 http://example.com/bugfix.patch
3449
3452
3450 - import a changeset from an hgweb server::
3453 - import a changeset from an hgweb server::
3451
3454
3452 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3455 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3453
3456
3454 - import all the patches in an Unix-style mbox::
3457 - import all the patches in an Unix-style mbox::
3455
3458
3456 hg import incoming-patches.mbox
3459 hg import incoming-patches.mbox
3457
3460
3458 - attempt to exactly restore an exported changeset (not always
3461 - attempt to exactly restore an exported changeset (not always
3459 possible)::
3462 possible)::
3460
3463
3461 hg import --exact proposed-fix.patch
3464 hg import --exact proposed-fix.patch
3462
3465
3463 Returns 0 on success.
3466 Returns 0 on success.
3464 """
3467 """
3465
3468
3466 if not patch1:
3469 if not patch1:
3467 raise util.Abort(_('need at least one patch to import'))
3470 raise util.Abort(_('need at least one patch to import'))
3468
3471
3469 patches = (patch1,) + patches
3472 patches = (patch1,) + patches
3470
3473
3471 date = opts.get('date')
3474 date = opts.get('date')
3472 if date:
3475 if date:
3473 opts['date'] = util.parsedate(date)
3476 opts['date'] = util.parsedate(date)
3474
3477
3475 editor = cmdutil.commiteditor
3478 editor = cmdutil.commiteditor
3476 if opts.get('edit'):
3479 if opts.get('edit'):
3477 editor = cmdutil.commitforceeditor
3480 editor = cmdutil.commitforceeditor
3478
3481
3479 update = not opts.get('bypass')
3482 update = not opts.get('bypass')
3480 if not update and opts.get('no_commit'):
3483 if not update and opts.get('no_commit'):
3481 raise util.Abort(_('cannot use --no-commit with --bypass'))
3484 raise util.Abort(_('cannot use --no-commit with --bypass'))
3482 try:
3485 try:
3483 sim = float(opts.get('similarity') or 0)
3486 sim = float(opts.get('similarity') or 0)
3484 except ValueError:
3487 except ValueError:
3485 raise util.Abort(_('similarity must be a number'))
3488 raise util.Abort(_('similarity must be a number'))
3486 if sim < 0 or sim > 100:
3489 if sim < 0 or sim > 100:
3487 raise util.Abort(_('similarity must be between 0 and 100'))
3490 raise util.Abort(_('similarity must be between 0 and 100'))
3488 if sim and not update:
3491 if sim and not update:
3489 raise util.Abort(_('cannot use --similarity with --bypass'))
3492 raise util.Abort(_('cannot use --similarity with --bypass'))
3490
3493
3491 if (opts.get('exact') or not opts.get('force')) and update:
3494 if (opts.get('exact') or not opts.get('force')) and update:
3492 cmdutil.bailifchanged(repo)
3495 cmdutil.bailifchanged(repo)
3493
3496
3494 base = opts["base"]
3497 base = opts["base"]
3495 strip = opts["strip"]
3498 strip = opts["strip"]
3496 wlock = lock = tr = None
3499 wlock = lock = tr = None
3497 msgs = []
3500 msgs = []
3498
3501
3499 def checkexact(repo, n, nodeid):
3502 def checkexact(repo, n, nodeid):
3500 if opts.get('exact') and hex(n) != nodeid:
3503 if opts.get('exact') and hex(n) != nodeid:
3501 raise util.Abort(_('patch is damaged or loses information'))
3504 raise util.Abort(_('patch is damaged or loses information'))
3502
3505
3503 def tryone(ui, hunk, parents):
3506 def tryone(ui, hunk, parents):
3504 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3507 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3505 patch.extract(ui, hunk)
3508 patch.extract(ui, hunk)
3506
3509
3507 if not tmpname:
3510 if not tmpname:
3508 return (None, None)
3511 return (None, None)
3509 msg = _('applied to working directory')
3512 msg = _('applied to working directory')
3510
3513
3511 try:
3514 try:
3512 cmdline_message = cmdutil.logmessage(ui, opts)
3515 cmdline_message = cmdutil.logmessage(ui, opts)
3513 if cmdline_message:
3516 if cmdline_message:
3514 # pickup the cmdline msg
3517 # pickup the cmdline msg
3515 message = cmdline_message
3518 message = cmdline_message
3516 elif message:
3519 elif message:
3517 # pickup the patch msg
3520 # pickup the patch msg
3518 message = message.strip()
3521 message = message.strip()
3519 else:
3522 else:
3520 # launch the editor
3523 # launch the editor
3521 message = None
3524 message = None
3522 ui.debug('message:\n%s\n' % message)
3525 ui.debug('message:\n%s\n' % message)
3523
3526
3524 if len(parents) == 1:
3527 if len(parents) == 1:
3525 parents.append(repo[nullid])
3528 parents.append(repo[nullid])
3526 if opts.get('exact'):
3529 if opts.get('exact'):
3527 if not nodeid or not p1:
3530 if not nodeid or not p1:
3528 raise util.Abort(_('not a Mercurial patch'))
3531 raise util.Abort(_('not a Mercurial patch'))
3529 p1 = repo[p1]
3532 p1 = repo[p1]
3530 p2 = repo[p2 or nullid]
3533 p2 = repo[p2 or nullid]
3531 elif p2:
3534 elif p2:
3532 try:
3535 try:
3533 p1 = repo[p1]
3536 p1 = repo[p1]
3534 p2 = repo[p2]
3537 p2 = repo[p2]
3535 # Without any options, consider p2 only if the
3538 # Without any options, consider p2 only if the
3536 # patch is being applied on top of the recorded
3539 # patch is being applied on top of the recorded
3537 # first parent.
3540 # first parent.
3538 if p1 != parents[0]:
3541 if p1 != parents[0]:
3539 p1 = parents[0]
3542 p1 = parents[0]
3540 p2 = repo[nullid]
3543 p2 = repo[nullid]
3541 except error.RepoError:
3544 except error.RepoError:
3542 p1, p2 = parents
3545 p1, p2 = parents
3543 else:
3546 else:
3544 p1, p2 = parents
3547 p1, p2 = parents
3545
3548
3546 n = None
3549 n = None
3547 if update:
3550 if update:
3548 if p1 != parents[0]:
3551 if p1 != parents[0]:
3549 hg.clean(repo, p1.node())
3552 hg.clean(repo, p1.node())
3550 if p2 != parents[1]:
3553 if p2 != parents[1]:
3551 repo.setparents(p1.node(), p2.node())
3554 repo.setparents(p1.node(), p2.node())
3552
3555
3553 if opts.get('exact') or opts.get('import_branch'):
3556 if opts.get('exact') or opts.get('import_branch'):
3554 repo.dirstate.setbranch(branch or 'default')
3557 repo.dirstate.setbranch(branch or 'default')
3555
3558
3556 files = set()
3559 files = set()
3557 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3560 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3558 eolmode=None, similarity=sim / 100.0)
3561 eolmode=None, similarity=sim / 100.0)
3559 files = list(files)
3562 files = list(files)
3560 if opts.get('no_commit'):
3563 if opts.get('no_commit'):
3561 if message:
3564 if message:
3562 msgs.append(message)
3565 msgs.append(message)
3563 else:
3566 else:
3564 if opts.get('exact') or p2:
3567 if opts.get('exact') or p2:
3565 # If you got here, you either use --force and know what
3568 # If you got here, you either use --force and know what
3566 # you are doing or used --exact or a merge patch while
3569 # you are doing or used --exact or a merge patch while
3567 # being updated to its first parent.
3570 # being updated to its first parent.
3568 m = None
3571 m = None
3569 else:
3572 else:
3570 m = scmutil.matchfiles(repo, files or [])
3573 m = scmutil.matchfiles(repo, files or [])
3571 n = repo.commit(message, opts.get('user') or user,
3574 n = repo.commit(message, opts.get('user') or user,
3572 opts.get('date') or date, match=m,
3575 opts.get('date') or date, match=m,
3573 editor=editor)
3576 editor=editor)
3574 checkexact(repo, n, nodeid)
3577 checkexact(repo, n, nodeid)
3575 else:
3578 else:
3576 if opts.get('exact') or opts.get('import_branch'):
3579 if opts.get('exact') or opts.get('import_branch'):
3577 branch = branch or 'default'
3580 branch = branch or 'default'
3578 else:
3581 else:
3579 branch = p1.branch()
3582 branch = p1.branch()
3580 store = patch.filestore()
3583 store = patch.filestore()
3581 try:
3584 try:
3582 files = set()
3585 files = set()
3583 try:
3586 try:
3584 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3587 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3585 files, eolmode=None)
3588 files, eolmode=None)
3586 except patch.PatchError, e:
3589 except patch.PatchError, e:
3587 raise util.Abort(str(e))
3590 raise util.Abort(str(e))
3588 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3591 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3589 message,
3592 message,
3590 opts.get('user') or user,
3593 opts.get('user') or user,
3591 opts.get('date') or date,
3594 opts.get('date') or date,
3592 branch, files, store,
3595 branch, files, store,
3593 editor=cmdutil.commiteditor)
3596 editor=cmdutil.commiteditor)
3594 repo.savecommitmessage(memctx.description())
3597 repo.savecommitmessage(memctx.description())
3595 n = memctx.commit()
3598 n = memctx.commit()
3596 checkexact(repo, n, nodeid)
3599 checkexact(repo, n, nodeid)
3597 finally:
3600 finally:
3598 store.close()
3601 store.close()
3599 if n:
3602 if n:
3600 # i18n: refers to a short changeset id
3603 # i18n: refers to a short changeset id
3601 msg = _('created %s') % short(n)
3604 msg = _('created %s') % short(n)
3602 return (msg, n)
3605 return (msg, n)
3603 finally:
3606 finally:
3604 os.unlink(tmpname)
3607 os.unlink(tmpname)
3605
3608
3606 try:
3609 try:
3607 try:
3610 try:
3608 wlock = repo.wlock()
3611 wlock = repo.wlock()
3609 if not opts.get('no_commit'):
3612 if not opts.get('no_commit'):
3610 lock = repo.lock()
3613 lock = repo.lock()
3611 tr = repo.transaction('import')
3614 tr = repo.transaction('import')
3612 parents = repo.parents()
3615 parents = repo.parents()
3613 for patchurl in patches:
3616 for patchurl in patches:
3614 if patchurl == '-':
3617 if patchurl == '-':
3615 ui.status(_('applying patch from stdin\n'))
3618 ui.status(_('applying patch from stdin\n'))
3616 patchfile = ui.fin
3619 patchfile = ui.fin
3617 patchurl = 'stdin' # for error message
3620 patchurl = 'stdin' # for error message
3618 else:
3621 else:
3619 patchurl = os.path.join(base, patchurl)
3622 patchurl = os.path.join(base, patchurl)
3620 ui.status(_('applying %s\n') % patchurl)
3623 ui.status(_('applying %s\n') % patchurl)
3621 patchfile = hg.openpath(ui, patchurl)
3624 patchfile = hg.openpath(ui, patchurl)
3622
3625
3623 haspatch = False
3626 haspatch = False
3624 for hunk in patch.split(patchfile):
3627 for hunk in patch.split(patchfile):
3625 (msg, node) = tryone(ui, hunk, parents)
3628 (msg, node) = tryone(ui, hunk, parents)
3626 if msg:
3629 if msg:
3627 haspatch = True
3630 haspatch = True
3628 ui.note(msg + '\n')
3631 ui.note(msg + '\n')
3629 if update or opts.get('exact'):
3632 if update or opts.get('exact'):
3630 parents = repo.parents()
3633 parents = repo.parents()
3631 else:
3634 else:
3632 parents = [repo[node]]
3635 parents = [repo[node]]
3633
3636
3634 if not haspatch:
3637 if not haspatch:
3635 raise util.Abort(_('%s: no diffs found') % patchurl)
3638 raise util.Abort(_('%s: no diffs found') % patchurl)
3636
3639
3637 if tr:
3640 if tr:
3638 tr.close()
3641 tr.close()
3639 if msgs:
3642 if msgs:
3640 repo.savecommitmessage('\n* * *\n'.join(msgs))
3643 repo.savecommitmessage('\n* * *\n'.join(msgs))
3641 except: # re-raises
3644 except: # re-raises
3642 # wlock.release() indirectly calls dirstate.write(): since
3645 # wlock.release() indirectly calls dirstate.write(): since
3643 # we're crashing, we do not want to change the working dir
3646 # we're crashing, we do not want to change the working dir
3644 # parent after all, so make sure it writes nothing
3647 # parent after all, so make sure it writes nothing
3645 repo.dirstate.invalidate()
3648 repo.dirstate.invalidate()
3646 raise
3649 raise
3647 finally:
3650 finally:
3648 if tr:
3651 if tr:
3649 tr.release()
3652 tr.release()
3650 release(lock, wlock)
3653 release(lock, wlock)
3651
3654
3652 @command('incoming|in',
3655 @command('incoming|in',
3653 [('f', 'force', None,
3656 [('f', 'force', None,
3654 _('run even if remote repository is unrelated')),
3657 _('run even if remote repository is unrelated')),
3655 ('n', 'newest-first', None, _('show newest record first')),
3658 ('n', 'newest-first', None, _('show newest record first')),
3656 ('', 'bundle', '',
3659 ('', 'bundle', '',
3657 _('file to store the bundles into'), _('FILE')),
3660 _('file to store the bundles into'), _('FILE')),
3658 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3661 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3659 ('B', 'bookmarks', False, _("compare bookmarks")),
3662 ('B', 'bookmarks', False, _("compare bookmarks")),
3660 ('b', 'branch', [],
3663 ('b', 'branch', [],
3661 _('a specific branch you would like to pull'), _('BRANCH')),
3664 _('a specific branch you would like to pull'), _('BRANCH')),
3662 ] + logopts + remoteopts + subrepoopts,
3665 ] + logopts + remoteopts + subrepoopts,
3663 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3666 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3664 def incoming(ui, repo, source="default", **opts):
3667 def incoming(ui, repo, source="default", **opts):
3665 """show new changesets found in source
3668 """show new changesets found in source
3666
3669
3667 Show new changesets found in the specified path/URL or the default
3670 Show new changesets found in the specified path/URL or the default
3668 pull location. These are the changesets that would have been pulled
3671 pull location. These are the changesets that would have been pulled
3669 if a pull at the time you issued this command.
3672 if a pull at the time you issued this command.
3670
3673
3671 For remote repository, using --bundle avoids downloading the
3674 For remote repository, using --bundle avoids downloading the
3672 changesets twice if the incoming is followed by a pull.
3675 changesets twice if the incoming is followed by a pull.
3673
3676
3674 See pull for valid source format details.
3677 See pull for valid source format details.
3675
3678
3676 Returns 0 if there are incoming changes, 1 otherwise.
3679 Returns 0 if there are incoming changes, 1 otherwise.
3677 """
3680 """
3678 if opts.get('graph'):
3681 if opts.get('graph'):
3679 cmdutil.checkunsupportedgraphflags([], opts)
3682 cmdutil.checkunsupportedgraphflags([], opts)
3680 def display(other, chlist, displayer):
3683 def display(other, chlist, displayer):
3681 revdag = cmdutil.graphrevs(other, chlist, opts)
3684 revdag = cmdutil.graphrevs(other, chlist, opts)
3682 showparents = [ctx.node() for ctx in repo[None].parents()]
3685 showparents = [ctx.node() for ctx in repo[None].parents()]
3683 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3686 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3684 graphmod.asciiedges)
3687 graphmod.asciiedges)
3685
3688
3686 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3689 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3687 return 0
3690 return 0
3688
3691
3689 if opts.get('bundle') and opts.get('subrepos'):
3692 if opts.get('bundle') and opts.get('subrepos'):
3690 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3693 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3691
3694
3692 if opts.get('bookmarks'):
3695 if opts.get('bookmarks'):
3693 source, branches = hg.parseurl(ui.expandpath(source),
3696 source, branches = hg.parseurl(ui.expandpath(source),
3694 opts.get('branch'))
3697 opts.get('branch'))
3695 other = hg.peer(repo, opts, source)
3698 other = hg.peer(repo, opts, source)
3696 if 'bookmarks' not in other.listkeys('namespaces'):
3699 if 'bookmarks' not in other.listkeys('namespaces'):
3697 ui.warn(_("remote doesn't support bookmarks\n"))
3700 ui.warn(_("remote doesn't support bookmarks\n"))
3698 return 0
3701 return 0
3699 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3702 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3700 return bookmarks.diff(ui, repo, other)
3703 return bookmarks.diff(ui, repo, other)
3701
3704
3702 repo._subtoppath = ui.expandpath(source)
3705 repo._subtoppath = ui.expandpath(source)
3703 try:
3706 try:
3704 return hg.incoming(ui, repo, source, opts)
3707 return hg.incoming(ui, repo, source, opts)
3705 finally:
3708 finally:
3706 del repo._subtoppath
3709 del repo._subtoppath
3707
3710
3708
3711
3709 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3712 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3710 def init(ui, dest=".", **opts):
3713 def init(ui, dest=".", **opts):
3711 """create a new repository in the given directory
3714 """create a new repository in the given directory
3712
3715
3713 Initialize a new repository in the given directory. If the given
3716 Initialize a new repository in the given directory. If the given
3714 directory does not exist, it will be created.
3717 directory does not exist, it will be created.
3715
3718
3716 If no directory is given, the current directory is used.
3719 If no directory is given, the current directory is used.
3717
3720
3718 It is possible to specify an ``ssh://`` URL as the destination.
3721 It is possible to specify an ``ssh://`` URL as the destination.
3719 See :hg:`help urls` for more information.
3722 See :hg:`help urls` for more information.
3720
3723
3721 Returns 0 on success.
3724 Returns 0 on success.
3722 """
3725 """
3723 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3726 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3724
3727
3725 @command('locate',
3728 @command('locate',
3726 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3729 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3727 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3730 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3728 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3731 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3729 ] + walkopts,
3732 ] + walkopts,
3730 _('[OPTION]... [PATTERN]...'))
3733 _('[OPTION]... [PATTERN]...'))
3731 def locate(ui, repo, *pats, **opts):
3734 def locate(ui, repo, *pats, **opts):
3732 """locate files matching specific patterns
3735 """locate files matching specific patterns
3733
3736
3734 Print files under Mercurial control in the working directory whose
3737 Print files under Mercurial control in the working directory whose
3735 names match the given patterns.
3738 names match the given patterns.
3736
3739
3737 By default, this command searches all directories in the working
3740 By default, this command searches all directories in the working
3738 directory. To search just the current directory and its
3741 directory. To search just the current directory and its
3739 subdirectories, use "--include .".
3742 subdirectories, use "--include .".
3740
3743
3741 If no patterns are given to match, this command prints the names
3744 If no patterns are given to match, this command prints the names
3742 of all files under Mercurial control in the working directory.
3745 of all files under Mercurial control in the working directory.
3743
3746
3744 If you want to feed the output of this command into the "xargs"
3747 If you want to feed the output of this command into the "xargs"
3745 command, use the -0 option to both this command and "xargs". This
3748 command, use the -0 option to both this command and "xargs". This
3746 will avoid the problem of "xargs" treating single filenames that
3749 will avoid the problem of "xargs" treating single filenames that
3747 contain whitespace as multiple filenames.
3750 contain whitespace as multiple filenames.
3748
3751
3749 Returns 0 if a match is found, 1 otherwise.
3752 Returns 0 if a match is found, 1 otherwise.
3750 """
3753 """
3751 end = opts.get('print0') and '\0' or '\n'
3754 end = opts.get('print0') and '\0' or '\n'
3752 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3755 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3753
3756
3754 ret = 1
3757 ret = 1
3755 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3758 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3756 m.bad = lambda x, y: False
3759 m.bad = lambda x, y: False
3757 for abs in repo[rev].walk(m):
3760 for abs in repo[rev].walk(m):
3758 if not rev and abs not in repo.dirstate:
3761 if not rev and abs not in repo.dirstate:
3759 continue
3762 continue
3760 if opts.get('fullpath'):
3763 if opts.get('fullpath'):
3761 ui.write(repo.wjoin(abs), end)
3764 ui.write(repo.wjoin(abs), end)
3762 else:
3765 else:
3763 ui.write(((pats and m.rel(abs)) or abs), end)
3766 ui.write(((pats and m.rel(abs)) or abs), end)
3764 ret = 0
3767 ret = 0
3765
3768
3766 return ret
3769 return ret
3767
3770
3768 @command('^log|history',
3771 @command('^log|history',
3769 [('f', 'follow', None,
3772 [('f', 'follow', None,
3770 _('follow changeset history, or file history across copies and renames')),
3773 _('follow changeset history, or file history across copies and renames')),
3771 ('', 'follow-first', None,
3774 ('', 'follow-first', None,
3772 _('only follow the first parent of merge changesets (DEPRECATED)')),
3775 _('only follow the first parent of merge changesets (DEPRECATED)')),
3773 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3776 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3774 ('C', 'copies', None, _('show copied files')),
3777 ('C', 'copies', None, _('show copied files')),
3775 ('k', 'keyword', [],
3778 ('k', 'keyword', [],
3776 _('do case-insensitive search for a given text'), _('TEXT')),
3779 _('do case-insensitive search for a given text'), _('TEXT')),
3777 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3780 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3778 ('', 'removed', None, _('include revisions where files were removed')),
3781 ('', 'removed', None, _('include revisions where files were removed')),
3779 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3782 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3780 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3783 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3781 ('', 'only-branch', [],
3784 ('', 'only-branch', [],
3782 _('show only changesets within the given named branch (DEPRECATED)'),
3785 _('show only changesets within the given named branch (DEPRECATED)'),
3783 _('BRANCH')),
3786 _('BRANCH')),
3784 ('b', 'branch', [],
3787 ('b', 'branch', [],
3785 _('show changesets within the given named branch'), _('BRANCH')),
3788 _('show changesets within the given named branch'), _('BRANCH')),
3786 ('P', 'prune', [],
3789 ('P', 'prune', [],
3787 _('do not display revision or any of its ancestors'), _('REV')),
3790 _('do not display revision or any of its ancestors'), _('REV')),
3788 ] + logopts + walkopts,
3791 ] + logopts + walkopts,
3789 _('[OPTION]... [FILE]'))
3792 _('[OPTION]... [FILE]'))
3790 def log(ui, repo, *pats, **opts):
3793 def log(ui, repo, *pats, **opts):
3791 """show revision history of entire repository or files
3794 """show revision history of entire repository or files
3792
3795
3793 Print the revision history of the specified files or the entire
3796 Print the revision history of the specified files or the entire
3794 project.
3797 project.
3795
3798
3796 If no revision range is specified, the default is ``tip:0`` unless
3799 If no revision range is specified, the default is ``tip:0`` unless
3797 --follow is set, in which case the working directory parent is
3800 --follow is set, in which case the working directory parent is
3798 used as the starting revision.
3801 used as the starting revision.
3799
3802
3800 File history is shown without following rename or copy history of
3803 File history is shown without following rename or copy history of
3801 files. Use -f/--follow with a filename to follow history across
3804 files. Use -f/--follow with a filename to follow history across
3802 renames and copies. --follow without a filename will only show
3805 renames and copies. --follow without a filename will only show
3803 ancestors or descendants of the starting revision.
3806 ancestors or descendants of the starting revision.
3804
3807
3805 By default this command prints revision number and changeset id,
3808 By default this command prints revision number and changeset id,
3806 tags, non-trivial parents, user, date and time, and a summary for
3809 tags, non-trivial parents, user, date and time, and a summary for
3807 each commit. When the -v/--verbose switch is used, the list of
3810 each commit. When the -v/--verbose switch is used, the list of
3808 changed files and full commit message are shown.
3811 changed files and full commit message are shown.
3809
3812
3810 .. note::
3813 .. note::
3811 log -p/--patch may generate unexpected diff output for merge
3814 log -p/--patch may generate unexpected diff output for merge
3812 changesets, as it will only compare the merge changeset against
3815 changesets, as it will only compare the merge changeset against
3813 its first parent. Also, only files different from BOTH parents
3816 its first parent. Also, only files different from BOTH parents
3814 will appear in files:.
3817 will appear in files:.
3815
3818
3816 .. note::
3819 .. note::
3817 for performance reasons, log FILE may omit duplicate changes
3820 for performance reasons, log FILE may omit duplicate changes
3818 made on branches and will not show deletions. To see all
3821 made on branches and will not show deletions. To see all
3819 changes including duplicates and deletions, use the --removed
3822 changes including duplicates and deletions, use the --removed
3820 switch.
3823 switch.
3821
3824
3822 .. container:: verbose
3825 .. container:: verbose
3823
3826
3824 Some examples:
3827 Some examples:
3825
3828
3826 - changesets with full descriptions and file lists::
3829 - changesets with full descriptions and file lists::
3827
3830
3828 hg log -v
3831 hg log -v
3829
3832
3830 - changesets ancestral to the working directory::
3833 - changesets ancestral to the working directory::
3831
3834
3832 hg log -f
3835 hg log -f
3833
3836
3834 - last 10 commits on the current branch::
3837 - last 10 commits on the current branch::
3835
3838
3836 hg log -l 10 -b .
3839 hg log -l 10 -b .
3837
3840
3838 - changesets showing all modifications of a file, including removals::
3841 - changesets showing all modifications of a file, including removals::
3839
3842
3840 hg log --removed file.c
3843 hg log --removed file.c
3841
3844
3842 - all changesets that touch a directory, with diffs, excluding merges::
3845 - all changesets that touch a directory, with diffs, excluding merges::
3843
3846
3844 hg log -Mp lib/
3847 hg log -Mp lib/
3845
3848
3846 - all revision numbers that match a keyword::
3849 - all revision numbers that match a keyword::
3847
3850
3848 hg log -k bug --template "{rev}\\n"
3851 hg log -k bug --template "{rev}\\n"
3849
3852
3850 - check if a given changeset is included is a tagged release::
3853 - check if a given changeset is included is a tagged release::
3851
3854
3852 hg log -r "a21ccf and ancestor(1.9)"
3855 hg log -r "a21ccf and ancestor(1.9)"
3853
3856
3854 - find all changesets by some user in a date range::
3857 - find all changesets by some user in a date range::
3855
3858
3856 hg log -k alice -d "may 2008 to jul 2008"
3859 hg log -k alice -d "may 2008 to jul 2008"
3857
3860
3858 - summary of all changesets after the last tag::
3861 - summary of all changesets after the last tag::
3859
3862
3860 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3863 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3861
3864
3862 See :hg:`help dates` for a list of formats valid for -d/--date.
3865 See :hg:`help dates` for a list of formats valid for -d/--date.
3863
3866
3864 See :hg:`help revisions` and :hg:`help revsets` for more about
3867 See :hg:`help revisions` and :hg:`help revsets` for more about
3865 specifying revisions.
3868 specifying revisions.
3866
3869
3867 See :hg:`help templates` for more about pre-packaged styles and
3870 See :hg:`help templates` for more about pre-packaged styles and
3868 specifying custom templates.
3871 specifying custom templates.
3869
3872
3870 Returns 0 on success.
3873 Returns 0 on success.
3871 """
3874 """
3872 if opts.get('graph'):
3875 if opts.get('graph'):
3873 return cmdutil.graphlog(ui, repo, *pats, **opts)
3876 return cmdutil.graphlog(ui, repo, *pats, **opts)
3874
3877
3875 matchfn = scmutil.match(repo[None], pats, opts)
3878 matchfn = scmutil.match(repo[None], pats, opts)
3876 limit = cmdutil.loglimit(opts)
3879 limit = cmdutil.loglimit(opts)
3877 count = 0
3880 count = 0
3878
3881
3879 getrenamed, endrev = None, None
3882 getrenamed, endrev = None, None
3880 if opts.get('copies'):
3883 if opts.get('copies'):
3881 if opts.get('rev'):
3884 if opts.get('rev'):
3882 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3885 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3883 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3886 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3884
3887
3885 df = False
3888 df = False
3886 if opts.get("date"):
3889 if opts.get("date"):
3887 df = util.matchdate(opts["date"])
3890 df = util.matchdate(opts["date"])
3888
3891
3889 branches = opts.get('branch', []) + opts.get('only_branch', [])
3892 branches = opts.get('branch', []) + opts.get('only_branch', [])
3890 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3893 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3891
3894
3892 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3895 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3893 def prep(ctx, fns):
3896 def prep(ctx, fns):
3894 rev = ctx.rev()
3897 rev = ctx.rev()
3895 parents = [p for p in repo.changelog.parentrevs(rev)
3898 parents = [p for p in repo.changelog.parentrevs(rev)
3896 if p != nullrev]
3899 if p != nullrev]
3897 if opts.get('no_merges') and len(parents) == 2:
3900 if opts.get('no_merges') and len(parents) == 2:
3898 return
3901 return
3899 if opts.get('only_merges') and len(parents) != 2:
3902 if opts.get('only_merges') and len(parents) != 2:
3900 return
3903 return
3901 if opts.get('branch') and ctx.branch() not in opts['branch']:
3904 if opts.get('branch') and ctx.branch() not in opts['branch']:
3902 return
3905 return
3903 if df and not df(ctx.date()[0]):
3906 if df and not df(ctx.date()[0]):
3904 return
3907 return
3905
3908
3906 lower = encoding.lower
3909 lower = encoding.lower
3907 if opts.get('user'):
3910 if opts.get('user'):
3908 luser = lower(ctx.user())
3911 luser = lower(ctx.user())
3909 for k in [lower(x) for x in opts['user']]:
3912 for k in [lower(x) for x in opts['user']]:
3910 if (k in luser):
3913 if (k in luser):
3911 break
3914 break
3912 else:
3915 else:
3913 return
3916 return
3914 if opts.get('keyword'):
3917 if opts.get('keyword'):
3915 luser = lower(ctx.user())
3918 luser = lower(ctx.user())
3916 ldesc = lower(ctx.description())
3919 ldesc = lower(ctx.description())
3917 lfiles = lower(" ".join(ctx.files()))
3920 lfiles = lower(" ".join(ctx.files()))
3918 for k in [lower(x) for x in opts['keyword']]:
3921 for k in [lower(x) for x in opts['keyword']]:
3919 if (k in luser or k in ldesc or k in lfiles):
3922 if (k in luser or k in ldesc or k in lfiles):
3920 break
3923 break
3921 else:
3924 else:
3922 return
3925 return
3923
3926
3924 copies = None
3927 copies = None
3925 if getrenamed is not None and rev:
3928 if getrenamed is not None and rev:
3926 copies = []
3929 copies = []
3927 for fn in ctx.files():
3930 for fn in ctx.files():
3928 rename = getrenamed(fn, rev)
3931 rename = getrenamed(fn, rev)
3929 if rename:
3932 if rename:
3930 copies.append((fn, rename[0]))
3933 copies.append((fn, rename[0]))
3931
3934
3932 revmatchfn = None
3935 revmatchfn = None
3933 if opts.get('patch') or opts.get('stat'):
3936 if opts.get('patch') or opts.get('stat'):
3934 if opts.get('follow') or opts.get('follow_first'):
3937 if opts.get('follow') or opts.get('follow_first'):
3935 # note: this might be wrong when following through merges
3938 # note: this might be wrong when following through merges
3936 revmatchfn = scmutil.match(repo[None], fns, default='path')
3939 revmatchfn = scmutil.match(repo[None], fns, default='path')
3937 else:
3940 else:
3938 revmatchfn = matchfn
3941 revmatchfn = matchfn
3939
3942
3940 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3943 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3941
3944
3942 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3945 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3943 if displayer.flush(ctx.rev()):
3946 if displayer.flush(ctx.rev()):
3944 count += 1
3947 count += 1
3945 if count == limit:
3948 if count == limit:
3946 break
3949 break
3947 displayer.close()
3950 displayer.close()
3948
3951
3949 @command('manifest',
3952 @command('manifest',
3950 [('r', 'rev', '', _('revision to display'), _('REV')),
3953 [('r', 'rev', '', _('revision to display'), _('REV')),
3951 ('', 'all', False, _("list files from all revisions"))],
3954 ('', 'all', False, _("list files from all revisions"))],
3952 _('[-r REV]'))
3955 _('[-r REV]'))
3953 def manifest(ui, repo, node=None, rev=None, **opts):
3956 def manifest(ui, repo, node=None, rev=None, **opts):
3954 """output the current or given revision of the project manifest
3957 """output the current or given revision of the project manifest
3955
3958
3956 Print a list of version controlled files for the given revision.
3959 Print a list of version controlled files for the given revision.
3957 If no revision is given, the first parent of the working directory
3960 If no revision is given, the first parent of the working directory
3958 is used, or the null revision if no revision is checked out.
3961 is used, or the null revision if no revision is checked out.
3959
3962
3960 With -v, print file permissions, symlink and executable bits.
3963 With -v, print file permissions, symlink and executable bits.
3961 With --debug, print file revision hashes.
3964 With --debug, print file revision hashes.
3962
3965
3963 If option --all is specified, the list of all files from all revisions
3966 If option --all is specified, the list of all files from all revisions
3964 is printed. This includes deleted and renamed files.
3967 is printed. This includes deleted and renamed files.
3965
3968
3966 Returns 0 on success.
3969 Returns 0 on success.
3967 """
3970 """
3968
3971
3969 fm = ui.formatter('manifest', opts)
3972 fm = ui.formatter('manifest', opts)
3970
3973
3971 if opts.get('all'):
3974 if opts.get('all'):
3972 if rev or node:
3975 if rev or node:
3973 raise util.Abort(_("can't specify a revision with --all"))
3976 raise util.Abort(_("can't specify a revision with --all"))
3974
3977
3975 res = []
3978 res = []
3976 prefix = "data/"
3979 prefix = "data/"
3977 suffix = ".i"
3980 suffix = ".i"
3978 plen = len(prefix)
3981 plen = len(prefix)
3979 slen = len(suffix)
3982 slen = len(suffix)
3980 lock = repo.lock()
3983 lock = repo.lock()
3981 try:
3984 try:
3982 for fn, b, size in repo.store.datafiles():
3985 for fn, b, size in repo.store.datafiles():
3983 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3986 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3984 res.append(fn[plen:-slen])
3987 res.append(fn[plen:-slen])
3985 finally:
3988 finally:
3986 lock.release()
3989 lock.release()
3987 for f in res:
3990 for f in res:
3988 fm.startitem()
3991 fm.startitem()
3989 fm.write("path", '%s\n', f)
3992 fm.write("path", '%s\n', f)
3990 fm.end()
3993 fm.end()
3991 return
3994 return
3992
3995
3993 if rev and node:
3996 if rev and node:
3994 raise util.Abort(_("please specify just one revision"))
3997 raise util.Abort(_("please specify just one revision"))
3995
3998
3996 if not node:
3999 if not node:
3997 node = rev
4000 node = rev
3998
4001
3999 char = {'l': '@', 'x': '*', '': ''}
4002 char = {'l': '@', 'x': '*', '': ''}
4000 mode = {'l': '644', 'x': '755', '': '644'}
4003 mode = {'l': '644', 'x': '755', '': '644'}
4001 ctx = scmutil.revsingle(repo, node)
4004 ctx = scmutil.revsingle(repo, node)
4002 mf = ctx.manifest()
4005 mf = ctx.manifest()
4003 for f in ctx:
4006 for f in ctx:
4004 fm.startitem()
4007 fm.startitem()
4005 fl = ctx[f].flags()
4008 fl = ctx[f].flags()
4006 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4009 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4007 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4010 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4008 fm.write('path', '%s\n', f)
4011 fm.write('path', '%s\n', f)
4009 fm.end()
4012 fm.end()
4010
4013
4011 @command('^merge',
4014 @command('^merge',
4012 [('f', 'force', None, _('force a merge with outstanding changes')),
4015 [('f', 'force', None, _('force a merge with outstanding changes')),
4013 ('r', 'rev', '', _('revision to merge'), _('REV')),
4016 ('r', 'rev', '', _('revision to merge'), _('REV')),
4014 ('P', 'preview', None,
4017 ('P', 'preview', None,
4015 _('review revisions to merge (no merge is performed)'))
4018 _('review revisions to merge (no merge is performed)'))
4016 ] + mergetoolopts,
4019 ] + mergetoolopts,
4017 _('[-P] [-f] [[-r] REV]'))
4020 _('[-P] [-f] [[-r] REV]'))
4018 def merge(ui, repo, node=None, **opts):
4021 def merge(ui, repo, node=None, **opts):
4019 """merge working directory with another revision
4022 """merge working directory with another revision
4020
4023
4021 The current working directory is updated with all changes made in
4024 The current working directory is updated with all changes made in
4022 the requested revision since the last common predecessor revision.
4025 the requested revision since the last common predecessor revision.
4023
4026
4024 Files that changed between either parent are marked as changed for
4027 Files that changed between either parent are marked as changed for
4025 the next commit and a commit must be performed before any further
4028 the next commit and a commit must be performed before any further
4026 updates to the repository are allowed. The next commit will have
4029 updates to the repository are allowed. The next commit will have
4027 two parents.
4030 two parents.
4028
4031
4029 ``--tool`` can be used to specify the merge tool used for file
4032 ``--tool`` can be used to specify the merge tool used for file
4030 merges. It overrides the HGMERGE environment variable and your
4033 merges. It overrides the HGMERGE environment variable and your
4031 configuration files. See :hg:`help merge-tools` for options.
4034 configuration files. See :hg:`help merge-tools` for options.
4032
4035
4033 If no revision is specified, the working directory's parent is a
4036 If no revision is specified, the working directory's parent is a
4034 head revision, and the current branch contains exactly one other
4037 head revision, and the current branch contains exactly one other
4035 head, the other head is merged with by default. Otherwise, an
4038 head, the other head is merged with by default. Otherwise, an
4036 explicit revision with which to merge with must be provided.
4039 explicit revision with which to merge with must be provided.
4037
4040
4038 :hg:`resolve` must be used to resolve unresolved files.
4041 :hg:`resolve` must be used to resolve unresolved files.
4039
4042
4040 To undo an uncommitted merge, use :hg:`update --clean .` which
4043 To undo an uncommitted merge, use :hg:`update --clean .` which
4041 will check out a clean copy of the original merge parent, losing
4044 will check out a clean copy of the original merge parent, losing
4042 all changes.
4045 all changes.
4043
4046
4044 Returns 0 on success, 1 if there are unresolved files.
4047 Returns 0 on success, 1 if there are unresolved files.
4045 """
4048 """
4046
4049
4047 if opts.get('rev') and node:
4050 if opts.get('rev') and node:
4048 raise util.Abort(_("please specify just one revision"))
4051 raise util.Abort(_("please specify just one revision"))
4049 if not node:
4052 if not node:
4050 node = opts.get('rev')
4053 node = opts.get('rev')
4051
4054
4052 if node:
4055 if node:
4053 node = scmutil.revsingle(repo, node).node()
4056 node = scmutil.revsingle(repo, node).node()
4054
4057
4055 if not node and repo._bookmarkcurrent:
4058 if not node and repo._bookmarkcurrent:
4056 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4059 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4057 curhead = repo[repo._bookmarkcurrent].node()
4060 curhead = repo[repo._bookmarkcurrent].node()
4058 if len(bmheads) == 2:
4061 if len(bmheads) == 2:
4059 if curhead == bmheads[0]:
4062 if curhead == bmheads[0]:
4060 node = bmheads[1]
4063 node = bmheads[1]
4061 else:
4064 else:
4062 node = bmheads[0]
4065 node = bmheads[0]
4063 elif len(bmheads) > 2:
4066 elif len(bmheads) > 2:
4064 raise util.Abort(_("multiple matching bookmarks to merge - "
4067 raise util.Abort(_("multiple matching bookmarks to merge - "
4065 "please merge with an explicit rev or bookmark"),
4068 "please merge with an explicit rev or bookmark"),
4066 hint=_("run 'hg heads' to see all heads"))
4069 hint=_("run 'hg heads' to see all heads"))
4067 elif len(bmheads) <= 1:
4070 elif len(bmheads) <= 1:
4068 raise util.Abort(_("no matching bookmark to merge - "
4071 raise util.Abort(_("no matching bookmark to merge - "
4069 "please merge with an explicit rev or bookmark"),
4072 "please merge with an explicit rev or bookmark"),
4070 hint=_("run 'hg heads' to see all heads"))
4073 hint=_("run 'hg heads' to see all heads"))
4071
4074
4072 if not node and not repo._bookmarkcurrent:
4075 if not node and not repo._bookmarkcurrent:
4073 branch = repo[None].branch()
4076 branch = repo[None].branch()
4074 bheads = repo.branchheads(branch)
4077 bheads = repo.branchheads(branch)
4075 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4078 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4076
4079
4077 if len(nbhs) > 2:
4080 if len(nbhs) > 2:
4078 raise util.Abort(_("branch '%s' has %d heads - "
4081 raise util.Abort(_("branch '%s' has %d heads - "
4079 "please merge with an explicit rev")
4082 "please merge with an explicit rev")
4080 % (branch, len(bheads)),
4083 % (branch, len(bheads)),
4081 hint=_("run 'hg heads .' to see heads"))
4084 hint=_("run 'hg heads .' to see heads"))
4082
4085
4083 parent = repo.dirstate.p1()
4086 parent = repo.dirstate.p1()
4084 if len(nbhs) <= 1:
4087 if len(nbhs) <= 1:
4085 if len(bheads) > 1:
4088 if len(bheads) > 1:
4086 raise util.Abort(_("heads are bookmarked - "
4089 raise util.Abort(_("heads are bookmarked - "
4087 "please merge with an explicit rev"),
4090 "please merge with an explicit rev"),
4088 hint=_("run 'hg heads' to see all heads"))
4091 hint=_("run 'hg heads' to see all heads"))
4089 if len(repo.heads()) > 1:
4092 if len(repo.heads()) > 1:
4090 raise util.Abort(_("branch '%s' has one head - "
4093 raise util.Abort(_("branch '%s' has one head - "
4091 "please merge with an explicit rev")
4094 "please merge with an explicit rev")
4092 % branch,
4095 % branch,
4093 hint=_("run 'hg heads' to see all heads"))
4096 hint=_("run 'hg heads' to see all heads"))
4094 msg, hint = _('nothing to merge'), None
4097 msg, hint = _('nothing to merge'), None
4095 if parent != repo.lookup(branch):
4098 if parent != repo.lookup(branch):
4096 hint = _("use 'hg update' instead")
4099 hint = _("use 'hg update' instead")
4097 raise util.Abort(msg, hint=hint)
4100 raise util.Abort(msg, hint=hint)
4098
4101
4099 if parent not in bheads:
4102 if parent not in bheads:
4100 raise util.Abort(_('working directory not at a head revision'),
4103 raise util.Abort(_('working directory not at a head revision'),
4101 hint=_("use 'hg update' or merge with an "
4104 hint=_("use 'hg update' or merge with an "
4102 "explicit revision"))
4105 "explicit revision"))
4103 if parent == nbhs[0]:
4106 if parent == nbhs[0]:
4104 node = nbhs[-1]
4107 node = nbhs[-1]
4105 else:
4108 else:
4106 node = nbhs[0]
4109 node = nbhs[0]
4107
4110
4108 if opts.get('preview'):
4111 if opts.get('preview'):
4109 # find nodes that are ancestors of p2 but not of p1
4112 # find nodes that are ancestors of p2 but not of p1
4110 p1 = repo.lookup('.')
4113 p1 = repo.lookup('.')
4111 p2 = repo.lookup(node)
4114 p2 = repo.lookup(node)
4112 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4115 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4113
4116
4114 displayer = cmdutil.show_changeset(ui, repo, opts)
4117 displayer = cmdutil.show_changeset(ui, repo, opts)
4115 for node in nodes:
4118 for node in nodes:
4116 displayer.show(repo[node])
4119 displayer.show(repo[node])
4117 displayer.close()
4120 displayer.close()
4118 return 0
4121 return 0
4119
4122
4120 try:
4123 try:
4121 # ui.forcemerge is an internal variable, do not document
4124 # ui.forcemerge is an internal variable, do not document
4122 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4125 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4123 return hg.merge(repo, node, force=opts.get('force'))
4126 return hg.merge(repo, node, force=opts.get('force'))
4124 finally:
4127 finally:
4125 ui.setconfig('ui', 'forcemerge', '')
4128 ui.setconfig('ui', 'forcemerge', '')
4126
4129
4127 @command('outgoing|out',
4130 @command('outgoing|out',
4128 [('f', 'force', None, _('run even when the destination is unrelated')),
4131 [('f', 'force', None, _('run even when the destination is unrelated')),
4129 ('r', 'rev', [],
4132 ('r', 'rev', [],
4130 _('a changeset intended to be included in the destination'), _('REV')),
4133 _('a changeset intended to be included in the destination'), _('REV')),
4131 ('n', 'newest-first', None, _('show newest record first')),
4134 ('n', 'newest-first', None, _('show newest record first')),
4132 ('B', 'bookmarks', False, _('compare bookmarks')),
4135 ('B', 'bookmarks', False, _('compare bookmarks')),
4133 ('b', 'branch', [], _('a specific branch you would like to push'),
4136 ('b', 'branch', [], _('a specific branch you would like to push'),
4134 _('BRANCH')),
4137 _('BRANCH')),
4135 ] + logopts + remoteopts + subrepoopts,
4138 ] + logopts + remoteopts + subrepoopts,
4136 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4139 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4137 def outgoing(ui, repo, dest=None, **opts):
4140 def outgoing(ui, repo, dest=None, **opts):
4138 """show changesets not found in the destination
4141 """show changesets not found in the destination
4139
4142
4140 Show changesets not found in the specified destination repository
4143 Show changesets not found in the specified destination repository
4141 or the default push location. These are the changesets that would
4144 or the default push location. These are the changesets that would
4142 be pushed if a push was requested.
4145 be pushed if a push was requested.
4143
4146
4144 See pull for details of valid destination formats.
4147 See pull for details of valid destination formats.
4145
4148
4146 Returns 0 if there are outgoing changes, 1 otherwise.
4149 Returns 0 if there are outgoing changes, 1 otherwise.
4147 """
4150 """
4148 if opts.get('graph'):
4151 if opts.get('graph'):
4149 cmdutil.checkunsupportedgraphflags([], opts)
4152 cmdutil.checkunsupportedgraphflags([], opts)
4150 o = hg._outgoing(ui, repo, dest, opts)
4153 o = hg._outgoing(ui, repo, dest, opts)
4151 if o is None:
4154 if o is None:
4152 return
4155 return
4153
4156
4154 revdag = cmdutil.graphrevs(repo, o, opts)
4157 revdag = cmdutil.graphrevs(repo, o, opts)
4155 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4158 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4156 showparents = [ctx.node() for ctx in repo[None].parents()]
4159 showparents = [ctx.node() for ctx in repo[None].parents()]
4157 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4160 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4158 graphmod.asciiedges)
4161 graphmod.asciiedges)
4159 return 0
4162 return 0
4160
4163
4161 if opts.get('bookmarks'):
4164 if opts.get('bookmarks'):
4162 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4165 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4163 dest, branches = hg.parseurl(dest, opts.get('branch'))
4166 dest, branches = hg.parseurl(dest, opts.get('branch'))
4164 other = hg.peer(repo, opts, dest)
4167 other = hg.peer(repo, opts, dest)
4165 if 'bookmarks' not in other.listkeys('namespaces'):
4168 if 'bookmarks' not in other.listkeys('namespaces'):
4166 ui.warn(_("remote doesn't support bookmarks\n"))
4169 ui.warn(_("remote doesn't support bookmarks\n"))
4167 return 0
4170 return 0
4168 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4171 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4169 return bookmarks.diff(ui, other, repo)
4172 return bookmarks.diff(ui, other, repo)
4170
4173
4171 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4174 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4172 try:
4175 try:
4173 return hg.outgoing(ui, repo, dest, opts)
4176 return hg.outgoing(ui, repo, dest, opts)
4174 finally:
4177 finally:
4175 del repo._subtoppath
4178 del repo._subtoppath
4176
4179
4177 @command('parents',
4180 @command('parents',
4178 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4181 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4179 ] + templateopts,
4182 ] + templateopts,
4180 _('[-r REV] [FILE]'))
4183 _('[-r REV] [FILE]'))
4181 def parents(ui, repo, file_=None, **opts):
4184 def parents(ui, repo, file_=None, **opts):
4182 """show the parents of the working directory or revision
4185 """show the parents of the working directory or revision
4183
4186
4184 Print the working directory's parent revisions. If a revision is
4187 Print the working directory's parent revisions. If a revision is
4185 given via -r/--rev, the parent of that revision will be printed.
4188 given via -r/--rev, the parent of that revision will be printed.
4186 If a file argument is given, the revision in which the file was
4189 If a file argument is given, the revision in which the file was
4187 last changed (before the working directory revision or the
4190 last changed (before the working directory revision or the
4188 argument to --rev if given) is printed.
4191 argument to --rev if given) is printed.
4189
4192
4190 Returns 0 on success.
4193 Returns 0 on success.
4191 """
4194 """
4192
4195
4193 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4196 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4194
4197
4195 if file_:
4198 if file_:
4196 m = scmutil.match(ctx, (file_,), opts)
4199 m = scmutil.match(ctx, (file_,), opts)
4197 if m.anypats() or len(m.files()) != 1:
4200 if m.anypats() or len(m.files()) != 1:
4198 raise util.Abort(_('can only specify an explicit filename'))
4201 raise util.Abort(_('can only specify an explicit filename'))
4199 file_ = m.files()[0]
4202 file_ = m.files()[0]
4200 filenodes = []
4203 filenodes = []
4201 for cp in ctx.parents():
4204 for cp in ctx.parents():
4202 if not cp:
4205 if not cp:
4203 continue
4206 continue
4204 try:
4207 try:
4205 filenodes.append(cp.filenode(file_))
4208 filenodes.append(cp.filenode(file_))
4206 except error.LookupError:
4209 except error.LookupError:
4207 pass
4210 pass
4208 if not filenodes:
4211 if not filenodes:
4209 raise util.Abort(_("'%s' not found in manifest!") % file_)
4212 raise util.Abort(_("'%s' not found in manifest!") % file_)
4210 fl = repo.file(file_)
4213 fl = repo.file(file_)
4211 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4214 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4212 else:
4215 else:
4213 p = [cp.node() for cp in ctx.parents()]
4216 p = [cp.node() for cp in ctx.parents()]
4214
4217
4215 displayer = cmdutil.show_changeset(ui, repo, opts)
4218 displayer = cmdutil.show_changeset(ui, repo, opts)
4216 for n in p:
4219 for n in p:
4217 if n != nullid:
4220 if n != nullid:
4218 displayer.show(repo[n])
4221 displayer.show(repo[n])
4219 displayer.close()
4222 displayer.close()
4220
4223
4221 @command('paths', [], _('[NAME]'))
4224 @command('paths', [], _('[NAME]'))
4222 def paths(ui, repo, search=None):
4225 def paths(ui, repo, search=None):
4223 """show aliases for remote repositories
4226 """show aliases for remote repositories
4224
4227
4225 Show definition of symbolic path name NAME. If no name is given,
4228 Show definition of symbolic path name NAME. If no name is given,
4226 show definition of all available names.
4229 show definition of all available names.
4227
4230
4228 Option -q/--quiet suppresses all output when searching for NAME
4231 Option -q/--quiet suppresses all output when searching for NAME
4229 and shows only the path names when listing all definitions.
4232 and shows only the path names when listing all definitions.
4230
4233
4231 Path names are defined in the [paths] section of your
4234 Path names are defined in the [paths] section of your
4232 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4235 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4233 repository, ``.hg/hgrc`` is used, too.
4236 repository, ``.hg/hgrc`` is used, too.
4234
4237
4235 The path names ``default`` and ``default-push`` have a special
4238 The path names ``default`` and ``default-push`` have a special
4236 meaning. When performing a push or pull operation, they are used
4239 meaning. When performing a push or pull operation, they are used
4237 as fallbacks if no location is specified on the command-line.
4240 as fallbacks if no location is specified on the command-line.
4238 When ``default-push`` is set, it will be used for push and
4241 When ``default-push`` is set, it will be used for push and
4239 ``default`` will be used for pull; otherwise ``default`` is used
4242 ``default`` will be used for pull; otherwise ``default`` is used
4240 as the fallback for both. When cloning a repository, the clone
4243 as the fallback for both. When cloning a repository, the clone
4241 source is written as ``default`` in ``.hg/hgrc``. Note that
4244 source is written as ``default`` in ``.hg/hgrc``. Note that
4242 ``default`` and ``default-push`` apply to all inbound (e.g.
4245 ``default`` and ``default-push`` apply to all inbound (e.g.
4243 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4246 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4244 :hg:`bundle`) operations.
4247 :hg:`bundle`) operations.
4245
4248
4246 See :hg:`help urls` for more information.
4249 See :hg:`help urls` for more information.
4247
4250
4248 Returns 0 on success.
4251 Returns 0 on success.
4249 """
4252 """
4250 if search:
4253 if search:
4251 for name, path in ui.configitems("paths"):
4254 for name, path in ui.configitems("paths"):
4252 if name == search:
4255 if name == search:
4253 ui.status("%s\n" % util.hidepassword(path))
4256 ui.status("%s\n" % util.hidepassword(path))
4254 return
4257 return
4255 if not ui.quiet:
4258 if not ui.quiet:
4256 ui.warn(_("not found!\n"))
4259 ui.warn(_("not found!\n"))
4257 return 1
4260 return 1
4258 else:
4261 else:
4259 for name, path in ui.configitems("paths"):
4262 for name, path in ui.configitems("paths"):
4260 if ui.quiet:
4263 if ui.quiet:
4261 ui.write("%s\n" % name)
4264 ui.write("%s\n" % name)
4262 else:
4265 else:
4263 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4266 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4264
4267
4265 @command('phase',
4268 @command('phase',
4266 [('p', 'public', False, _('set changeset phase to public')),
4269 [('p', 'public', False, _('set changeset phase to public')),
4267 ('d', 'draft', False, _('set changeset phase to draft')),
4270 ('d', 'draft', False, _('set changeset phase to draft')),
4268 ('s', 'secret', False, _('set changeset phase to secret')),
4271 ('s', 'secret', False, _('set changeset phase to secret')),
4269 ('f', 'force', False, _('allow to move boundary backward')),
4272 ('f', 'force', False, _('allow to move boundary backward')),
4270 ('r', 'rev', [], _('target revision'), _('REV')),
4273 ('r', 'rev', [], _('target revision'), _('REV')),
4271 ],
4274 ],
4272 _('[-p|-d|-s] [-f] [-r] REV...'))
4275 _('[-p|-d|-s] [-f] [-r] REV...'))
4273 def phase(ui, repo, *revs, **opts):
4276 def phase(ui, repo, *revs, **opts):
4274 """set or show the current phase name
4277 """set or show the current phase name
4275
4278
4276 With no argument, show the phase name of specified revisions.
4279 With no argument, show the phase name of specified revisions.
4277
4280
4278 With one of -p/--public, -d/--draft or -s/--secret, change the
4281 With one of -p/--public, -d/--draft or -s/--secret, change the
4279 phase value of the specified revisions.
4282 phase value of the specified revisions.
4280
4283
4281 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4284 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4282 lower phase to an higher phase. Phases are ordered as follows::
4285 lower phase to an higher phase. Phases are ordered as follows::
4283
4286
4284 public < draft < secret
4287 public < draft < secret
4285
4288
4286 Return 0 on success, 1 if no phases were changed or some could not
4289 Return 0 on success, 1 if no phases were changed or some could not
4287 be changed.
4290 be changed.
4288 """
4291 """
4289 # search for a unique phase argument
4292 # search for a unique phase argument
4290 targetphase = None
4293 targetphase = None
4291 for idx, name in enumerate(phases.phasenames):
4294 for idx, name in enumerate(phases.phasenames):
4292 if opts[name]:
4295 if opts[name]:
4293 if targetphase is not None:
4296 if targetphase is not None:
4294 raise util.Abort(_('only one phase can be specified'))
4297 raise util.Abort(_('only one phase can be specified'))
4295 targetphase = idx
4298 targetphase = idx
4296
4299
4297 # look for specified revision
4300 # look for specified revision
4298 revs = list(revs)
4301 revs = list(revs)
4299 revs.extend(opts['rev'])
4302 revs.extend(opts['rev'])
4300 if not revs:
4303 if not revs:
4301 raise util.Abort(_('no revisions specified'))
4304 raise util.Abort(_('no revisions specified'))
4302
4305
4303 revs = scmutil.revrange(repo, revs)
4306 revs = scmutil.revrange(repo, revs)
4304
4307
4305 lock = None
4308 lock = None
4306 ret = 0
4309 ret = 0
4307 if targetphase is None:
4310 if targetphase is None:
4308 # display
4311 # display
4309 for r in revs:
4312 for r in revs:
4310 ctx = repo[r]
4313 ctx = repo[r]
4311 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4314 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4312 else:
4315 else:
4313 lock = repo.lock()
4316 lock = repo.lock()
4314 try:
4317 try:
4315 # set phase
4318 # set phase
4316 if not revs:
4319 if not revs:
4317 raise util.Abort(_('empty revision set'))
4320 raise util.Abort(_('empty revision set'))
4318 nodes = [repo[r].node() for r in revs]
4321 nodes = [repo[r].node() for r in revs]
4319 olddata = repo._phasecache.getphaserevs(repo)[:]
4322 olddata = repo._phasecache.getphaserevs(repo)[:]
4320 phases.advanceboundary(repo, targetphase, nodes)
4323 phases.advanceboundary(repo, targetphase, nodes)
4321 if opts['force']:
4324 if opts['force']:
4322 phases.retractboundary(repo, targetphase, nodes)
4325 phases.retractboundary(repo, targetphase, nodes)
4323 finally:
4326 finally:
4324 lock.release()
4327 lock.release()
4325 # moving revision from public to draft may hide them
4328 # moving revision from public to draft may hide them
4326 # We have to check result on an unfiltered repository
4329 # We have to check result on an unfiltered repository
4327 unfi = repo.unfiltered()
4330 unfi = repo.unfiltered()
4328 newdata = repo._phasecache.getphaserevs(unfi)
4331 newdata = repo._phasecache.getphaserevs(unfi)
4329 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4332 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4330 cl = unfi.changelog
4333 cl = unfi.changelog
4331 rejected = [n for n in nodes
4334 rejected = [n for n in nodes
4332 if newdata[cl.rev(n)] < targetphase]
4335 if newdata[cl.rev(n)] < targetphase]
4333 if rejected:
4336 if rejected:
4334 ui.warn(_('cannot move %i changesets to a more permissive '
4337 ui.warn(_('cannot move %i changesets to a more permissive '
4335 'phase, use --force\n') % len(rejected))
4338 'phase, use --force\n') % len(rejected))
4336 ret = 1
4339 ret = 1
4337 if changes:
4340 if changes:
4338 msg = _('phase changed for %i changesets\n') % changes
4341 msg = _('phase changed for %i changesets\n') % changes
4339 if ret:
4342 if ret:
4340 ui.status(msg)
4343 ui.status(msg)
4341 else:
4344 else:
4342 ui.note(msg)
4345 ui.note(msg)
4343 else:
4346 else:
4344 ui.warn(_('no phases changed\n'))
4347 ui.warn(_('no phases changed\n'))
4345 ret = 1
4348 ret = 1
4346 return ret
4349 return ret
4347
4350
4348 def postincoming(ui, repo, modheads, optupdate, checkout):
4351 def postincoming(ui, repo, modheads, optupdate, checkout):
4349 if modheads == 0:
4352 if modheads == 0:
4350 return
4353 return
4351 if optupdate:
4354 if optupdate:
4352 movemarkfrom = repo['.'].node()
4355 movemarkfrom = repo['.'].node()
4353 try:
4356 try:
4354 ret = hg.update(repo, checkout)
4357 ret = hg.update(repo, checkout)
4355 except util.Abort, inst:
4358 except util.Abort, inst:
4356 ui.warn(_("not updating: %s\n") % str(inst))
4359 ui.warn(_("not updating: %s\n") % str(inst))
4357 return 0
4360 return 0
4358 if not ret and not checkout:
4361 if not ret and not checkout:
4359 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4362 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4360 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4363 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4361 return ret
4364 return ret
4362 if modheads > 1:
4365 if modheads > 1:
4363 currentbranchheads = len(repo.branchheads())
4366 currentbranchheads = len(repo.branchheads())
4364 if currentbranchheads == modheads:
4367 if currentbranchheads == modheads:
4365 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4368 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4366 elif currentbranchheads > 1:
4369 elif currentbranchheads > 1:
4367 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4370 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4368 "merge)\n"))
4371 "merge)\n"))
4369 else:
4372 else:
4370 ui.status(_("(run 'hg heads' to see heads)\n"))
4373 ui.status(_("(run 'hg heads' to see heads)\n"))
4371 else:
4374 else:
4372 ui.status(_("(run 'hg update' to get a working copy)\n"))
4375 ui.status(_("(run 'hg update' to get a working copy)\n"))
4373
4376
4374 @command('^pull',
4377 @command('^pull',
4375 [('u', 'update', None,
4378 [('u', 'update', None,
4376 _('update to new branch head if changesets were pulled')),
4379 _('update to new branch head if changesets were pulled')),
4377 ('f', 'force', None, _('run even when remote repository is unrelated')),
4380 ('f', 'force', None, _('run even when remote repository is unrelated')),
4378 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4381 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4379 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4382 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4380 ('b', 'branch', [], _('a specific branch you would like to pull'),
4383 ('b', 'branch', [], _('a specific branch you would like to pull'),
4381 _('BRANCH')),
4384 _('BRANCH')),
4382 ] + remoteopts,
4385 ] + remoteopts,
4383 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4386 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4384 def pull(ui, repo, source="default", **opts):
4387 def pull(ui, repo, source="default", **opts):
4385 """pull changes from the specified source
4388 """pull changes from the specified source
4386
4389
4387 Pull changes from a remote repository to a local one.
4390 Pull changes from a remote repository to a local one.
4388
4391
4389 This finds all changes from the repository at the specified path
4392 This finds all changes from the repository at the specified path
4390 or URL and adds them to a local repository (the current one unless
4393 or URL and adds them to a local repository (the current one unless
4391 -R is specified). By default, this does not update the copy of the
4394 -R is specified). By default, this does not update the copy of the
4392 project in the working directory.
4395 project in the working directory.
4393
4396
4394 Use :hg:`incoming` if you want to see what would have been added
4397 Use :hg:`incoming` if you want to see what would have been added
4395 by a pull at the time you issued this command. If you then decide
4398 by a pull at the time you issued this command. If you then decide
4396 to add those changes to the repository, you should use :hg:`pull
4399 to add those changes to the repository, you should use :hg:`pull
4397 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4400 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4398
4401
4399 If SOURCE is omitted, the 'default' path will be used.
4402 If SOURCE is omitted, the 'default' path will be used.
4400 See :hg:`help urls` for more information.
4403 See :hg:`help urls` for more information.
4401
4404
4402 Returns 0 on success, 1 if an update had unresolved files.
4405 Returns 0 on success, 1 if an update had unresolved files.
4403 """
4406 """
4404 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4407 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4405 other = hg.peer(repo, opts, source)
4408 other = hg.peer(repo, opts, source)
4406 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4409 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4407 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4410 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4408
4411
4409 if opts.get('bookmark'):
4412 if opts.get('bookmark'):
4410 if not revs:
4413 if not revs:
4411 revs = []
4414 revs = []
4412 rb = other.listkeys('bookmarks')
4415 rb = other.listkeys('bookmarks')
4413 for b in opts['bookmark']:
4416 for b in opts['bookmark']:
4414 if b not in rb:
4417 if b not in rb:
4415 raise util.Abort(_('remote bookmark %s not found!') % b)
4418 raise util.Abort(_('remote bookmark %s not found!') % b)
4416 revs.append(rb[b])
4419 revs.append(rb[b])
4417
4420
4418 if revs:
4421 if revs:
4419 try:
4422 try:
4420 revs = [other.lookup(rev) for rev in revs]
4423 revs = [other.lookup(rev) for rev in revs]
4421 except error.CapabilityError:
4424 except error.CapabilityError:
4422 err = _("other repository doesn't support revision lookup, "
4425 err = _("other repository doesn't support revision lookup, "
4423 "so a rev cannot be specified.")
4426 "so a rev cannot be specified.")
4424 raise util.Abort(err)
4427 raise util.Abort(err)
4425
4428
4426 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4429 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4427 bookmarks.updatefromremote(ui, repo, other, source)
4430 bookmarks.updatefromremote(ui, repo, other, source)
4428 if checkout:
4431 if checkout:
4429 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4432 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4430 repo._subtoppath = source
4433 repo._subtoppath = source
4431 try:
4434 try:
4432 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4435 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4433
4436
4434 finally:
4437 finally:
4435 del repo._subtoppath
4438 del repo._subtoppath
4436
4439
4437 # update specified bookmarks
4440 # update specified bookmarks
4438 if opts.get('bookmark'):
4441 if opts.get('bookmark'):
4439 marks = repo._bookmarks
4442 marks = repo._bookmarks
4440 for b in opts['bookmark']:
4443 for b in opts['bookmark']:
4441 # explicit pull overrides local bookmark if any
4444 # explicit pull overrides local bookmark if any
4442 ui.status(_("importing bookmark %s\n") % b)
4445 ui.status(_("importing bookmark %s\n") % b)
4443 marks[b] = repo[rb[b]].node()
4446 marks[b] = repo[rb[b]].node()
4444 marks.write()
4447 marks.write()
4445
4448
4446 return ret
4449 return ret
4447
4450
4448 @command('^push',
4451 @command('^push',
4449 [('f', 'force', None, _('force push')),
4452 [('f', 'force', None, _('force push')),
4450 ('r', 'rev', [],
4453 ('r', 'rev', [],
4451 _('a changeset intended to be included in the destination'),
4454 _('a changeset intended to be included in the destination'),
4452 _('REV')),
4455 _('REV')),
4453 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4456 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4454 ('b', 'branch', [],
4457 ('b', 'branch', [],
4455 _('a specific branch you would like to push'), _('BRANCH')),
4458 _('a specific branch you would like to push'), _('BRANCH')),
4456 ('', 'new-branch', False, _('allow pushing a new branch')),
4459 ('', 'new-branch', False, _('allow pushing a new branch')),
4457 ] + remoteopts,
4460 ] + remoteopts,
4458 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4461 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4459 def push(ui, repo, dest=None, **opts):
4462 def push(ui, repo, dest=None, **opts):
4460 """push changes to the specified destination
4463 """push changes to the specified destination
4461
4464
4462 Push changesets from the local repository to the specified
4465 Push changesets from the local repository to the specified
4463 destination.
4466 destination.
4464
4467
4465 This operation is symmetrical to pull: it is identical to a pull
4468 This operation is symmetrical to pull: it is identical to a pull
4466 in the destination repository from the current one.
4469 in the destination repository from the current one.
4467
4470
4468 By default, push will not allow creation of new heads at the
4471 By default, push will not allow creation of new heads at the
4469 destination, since multiple heads would make it unclear which head
4472 destination, since multiple heads would make it unclear which head
4470 to use. In this situation, it is recommended to pull and merge
4473 to use. In this situation, it is recommended to pull and merge
4471 before pushing.
4474 before pushing.
4472
4475
4473 Use --new-branch if you want to allow push to create a new named
4476 Use --new-branch if you want to allow push to create a new named
4474 branch that is not present at the destination. This allows you to
4477 branch that is not present at the destination. This allows you to
4475 only create a new branch without forcing other changes.
4478 only create a new branch without forcing other changes.
4476
4479
4477 Use -f/--force to override the default behavior and push all
4480 Use -f/--force to override the default behavior and push all
4478 changesets on all branches.
4481 changesets on all branches.
4479
4482
4480 If -r/--rev is used, the specified revision and all its ancestors
4483 If -r/--rev is used, the specified revision and all its ancestors
4481 will be pushed to the remote repository.
4484 will be pushed to the remote repository.
4482
4485
4483 If -B/--bookmark is used, the specified bookmarked revision, its
4486 If -B/--bookmark is used, the specified bookmarked revision, its
4484 ancestors, and the bookmark will be pushed to the remote
4487 ancestors, and the bookmark will be pushed to the remote
4485 repository.
4488 repository.
4486
4489
4487 Please see :hg:`help urls` for important details about ``ssh://``
4490 Please see :hg:`help urls` for important details about ``ssh://``
4488 URLs. If DESTINATION is omitted, a default path will be used.
4491 URLs. If DESTINATION is omitted, a default path will be used.
4489
4492
4490 Returns 0 if push was successful, 1 if nothing to push.
4493 Returns 0 if push was successful, 1 if nothing to push.
4491 """
4494 """
4492
4495
4493 if opts.get('bookmark'):
4496 if opts.get('bookmark'):
4494 for b in opts['bookmark']:
4497 for b in opts['bookmark']:
4495 # translate -B options to -r so changesets get pushed
4498 # translate -B options to -r so changesets get pushed
4496 if b in repo._bookmarks:
4499 if b in repo._bookmarks:
4497 opts.setdefault('rev', []).append(b)
4500 opts.setdefault('rev', []).append(b)
4498 else:
4501 else:
4499 # if we try to push a deleted bookmark, translate it to null
4502 # if we try to push a deleted bookmark, translate it to null
4500 # this lets simultaneous -r, -b options continue working
4503 # this lets simultaneous -r, -b options continue working
4501 opts.setdefault('rev', []).append("null")
4504 opts.setdefault('rev', []).append("null")
4502
4505
4503 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4506 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4504 dest, branches = hg.parseurl(dest, opts.get('branch'))
4507 dest, branches = hg.parseurl(dest, opts.get('branch'))
4505 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4508 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4506 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4509 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4507 other = hg.peer(repo, opts, dest)
4510 other = hg.peer(repo, opts, dest)
4508 if revs:
4511 if revs:
4509 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4512 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4510
4513
4511 repo._subtoppath = dest
4514 repo._subtoppath = dest
4512 try:
4515 try:
4513 # push subrepos depth-first for coherent ordering
4516 # push subrepos depth-first for coherent ordering
4514 c = repo['']
4517 c = repo['']
4515 subs = c.substate # only repos that are committed
4518 subs = c.substate # only repos that are committed
4516 for s in sorted(subs):
4519 for s in sorted(subs):
4517 if c.sub(s).push(opts) == 0:
4520 if c.sub(s).push(opts) == 0:
4518 return False
4521 return False
4519 finally:
4522 finally:
4520 del repo._subtoppath
4523 del repo._subtoppath
4521 result = repo.push(other, opts.get('force'), revs=revs,
4524 result = repo.push(other, opts.get('force'), revs=revs,
4522 newbranch=opts.get('new_branch'))
4525 newbranch=opts.get('new_branch'))
4523
4526
4524 result = not result
4527 result = not result
4525
4528
4526 if opts.get('bookmark'):
4529 if opts.get('bookmark'):
4527 rb = other.listkeys('bookmarks')
4530 rb = other.listkeys('bookmarks')
4528 for b in opts['bookmark']:
4531 for b in opts['bookmark']:
4529 # explicit push overrides remote bookmark if any
4532 # explicit push overrides remote bookmark if any
4530 if b in repo._bookmarks:
4533 if b in repo._bookmarks:
4531 ui.status(_("exporting bookmark %s\n") % b)
4534 ui.status(_("exporting bookmark %s\n") % b)
4532 new = repo[b].hex()
4535 new = repo[b].hex()
4533 elif b in rb:
4536 elif b in rb:
4534 ui.status(_("deleting remote bookmark %s\n") % b)
4537 ui.status(_("deleting remote bookmark %s\n") % b)
4535 new = '' # delete
4538 new = '' # delete
4536 else:
4539 else:
4537 ui.warn(_('bookmark %s does not exist on the local '
4540 ui.warn(_('bookmark %s does not exist on the local '
4538 'or remote repository!\n') % b)
4541 'or remote repository!\n') % b)
4539 return 2
4542 return 2
4540 old = rb.get(b, '')
4543 old = rb.get(b, '')
4541 r = other.pushkey('bookmarks', b, old, new)
4544 r = other.pushkey('bookmarks', b, old, new)
4542 if not r:
4545 if not r:
4543 ui.warn(_('updating bookmark %s failed!\n') % b)
4546 ui.warn(_('updating bookmark %s failed!\n') % b)
4544 if not result:
4547 if not result:
4545 result = 2
4548 result = 2
4546
4549
4547 return result
4550 return result
4548
4551
4549 @command('recover', [])
4552 @command('recover', [])
4550 def recover(ui, repo):
4553 def recover(ui, repo):
4551 """roll back an interrupted transaction
4554 """roll back an interrupted transaction
4552
4555
4553 Recover from an interrupted commit or pull.
4556 Recover from an interrupted commit or pull.
4554
4557
4555 This command tries to fix the repository status after an
4558 This command tries to fix the repository status after an
4556 interrupted operation. It should only be necessary when Mercurial
4559 interrupted operation. It should only be necessary when Mercurial
4557 suggests it.
4560 suggests it.
4558
4561
4559 Returns 0 if successful, 1 if nothing to recover or verify fails.
4562 Returns 0 if successful, 1 if nothing to recover or verify fails.
4560 """
4563 """
4561 if repo.recover():
4564 if repo.recover():
4562 return hg.verify(repo)
4565 return hg.verify(repo)
4563 return 1
4566 return 1
4564
4567
4565 @command('^remove|rm',
4568 @command('^remove|rm',
4566 [('A', 'after', None, _('record delete for missing files')),
4569 [('A', 'after', None, _('record delete for missing files')),
4567 ('f', 'force', None,
4570 ('f', 'force', None,
4568 _('remove (and delete) file even if added or modified')),
4571 _('remove (and delete) file even if added or modified')),
4569 ] + walkopts,
4572 ] + walkopts,
4570 _('[OPTION]... FILE...'))
4573 _('[OPTION]... FILE...'))
4571 def remove(ui, repo, *pats, **opts):
4574 def remove(ui, repo, *pats, **opts):
4572 """remove the specified files on the next commit
4575 """remove the specified files on the next commit
4573
4576
4574 Schedule the indicated files for removal from the current branch.
4577 Schedule the indicated files for removal from the current branch.
4575
4578
4576 This command schedules the files to be removed at the next commit.
4579 This command schedules the files to be removed at the next commit.
4577 To undo a remove before that, see :hg:`revert`. To undo added
4580 To undo a remove before that, see :hg:`revert`. To undo added
4578 files, see :hg:`forget`.
4581 files, see :hg:`forget`.
4579
4582
4580 .. container:: verbose
4583 .. container:: verbose
4581
4584
4582 -A/--after can be used to remove only files that have already
4585 -A/--after can be used to remove only files that have already
4583 been deleted, -f/--force can be used to force deletion, and -Af
4586 been deleted, -f/--force can be used to force deletion, and -Af
4584 can be used to remove files from the next revision without
4587 can be used to remove files from the next revision without
4585 deleting them from the working directory.
4588 deleting them from the working directory.
4586
4589
4587 The following table details the behavior of remove for different
4590 The following table details the behavior of remove for different
4588 file states (columns) and option combinations (rows). The file
4591 file states (columns) and option combinations (rows). The file
4589 states are Added [A], Clean [C], Modified [M] and Missing [!]
4592 states are Added [A], Clean [C], Modified [M] and Missing [!]
4590 (as reported by :hg:`status`). The actions are Warn, Remove
4593 (as reported by :hg:`status`). The actions are Warn, Remove
4591 (from branch) and Delete (from disk):
4594 (from branch) and Delete (from disk):
4592
4595
4593 ======= == == == ==
4596 ======= == == == ==
4594 A C M !
4597 A C M !
4595 ======= == == == ==
4598 ======= == == == ==
4596 none W RD W R
4599 none W RD W R
4597 -f R RD RD R
4600 -f R RD RD R
4598 -A W W W R
4601 -A W W W R
4599 -Af R R R R
4602 -Af R R R R
4600 ======= == == == ==
4603 ======= == == == ==
4601
4604
4602 Note that remove never deletes files in Added [A] state from the
4605 Note that remove never deletes files in Added [A] state from the
4603 working directory, not even if option --force is specified.
4606 working directory, not even if option --force is specified.
4604
4607
4605 Returns 0 on success, 1 if any warnings encountered.
4608 Returns 0 on success, 1 if any warnings encountered.
4606 """
4609 """
4607
4610
4608 ret = 0
4611 ret = 0
4609 after, force = opts.get('after'), opts.get('force')
4612 after, force = opts.get('after'), opts.get('force')
4610 if not pats and not after:
4613 if not pats and not after:
4611 raise util.Abort(_('no files specified'))
4614 raise util.Abort(_('no files specified'))
4612
4615
4613 m = scmutil.match(repo[None], pats, opts)
4616 m = scmutil.match(repo[None], pats, opts)
4614 s = repo.status(match=m, clean=True)
4617 s = repo.status(match=m, clean=True)
4615 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4618 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4616
4619
4617 # warn about failure to delete explicit files/dirs
4620 # warn about failure to delete explicit files/dirs
4618 wctx = repo[None]
4621 wctx = repo[None]
4619 for f in m.files():
4622 for f in m.files():
4620 if f in repo.dirstate or f in wctx.dirs():
4623 if f in repo.dirstate or f in wctx.dirs():
4621 continue
4624 continue
4622 if os.path.exists(m.rel(f)):
4625 if os.path.exists(m.rel(f)):
4623 if os.path.isdir(m.rel(f)):
4626 if os.path.isdir(m.rel(f)):
4624 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4627 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4625 else:
4628 else:
4626 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4629 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4627 # missing files will generate a warning elsewhere
4630 # missing files will generate a warning elsewhere
4628 ret = 1
4631 ret = 1
4629
4632
4630 if force:
4633 if force:
4631 list = modified + deleted + clean + added
4634 list = modified + deleted + clean + added
4632 elif after:
4635 elif after:
4633 list = deleted
4636 list = deleted
4634 for f in modified + added + clean:
4637 for f in modified + added + clean:
4635 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4638 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4636 ret = 1
4639 ret = 1
4637 else:
4640 else:
4638 list = deleted + clean
4641 list = deleted + clean
4639 for f in modified:
4642 for f in modified:
4640 ui.warn(_('not removing %s: file is modified (use -f'
4643 ui.warn(_('not removing %s: file is modified (use -f'
4641 ' to force removal)\n') % m.rel(f))
4644 ' to force removal)\n') % m.rel(f))
4642 ret = 1
4645 ret = 1
4643 for f in added:
4646 for f in added:
4644 ui.warn(_('not removing %s: file has been marked for add'
4647 ui.warn(_('not removing %s: file has been marked for add'
4645 ' (use forget to undo)\n') % m.rel(f))
4648 ' (use forget to undo)\n') % m.rel(f))
4646 ret = 1
4649 ret = 1
4647
4650
4648 for f in sorted(list):
4651 for f in sorted(list):
4649 if ui.verbose or not m.exact(f):
4652 if ui.verbose or not m.exact(f):
4650 ui.status(_('removing %s\n') % m.rel(f))
4653 ui.status(_('removing %s\n') % m.rel(f))
4651
4654
4652 wlock = repo.wlock()
4655 wlock = repo.wlock()
4653 try:
4656 try:
4654 if not after:
4657 if not after:
4655 for f in list:
4658 for f in list:
4656 if f in added:
4659 if f in added:
4657 continue # we never unlink added files on remove
4660 continue # we never unlink added files on remove
4658 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4661 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4659 repo[None].forget(list)
4662 repo[None].forget(list)
4660 finally:
4663 finally:
4661 wlock.release()
4664 wlock.release()
4662
4665
4663 return ret
4666 return ret
4664
4667
4665 @command('rename|move|mv',
4668 @command('rename|move|mv',
4666 [('A', 'after', None, _('record a rename that has already occurred')),
4669 [('A', 'after', None, _('record a rename that has already occurred')),
4667 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4670 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4668 ] + walkopts + dryrunopts,
4671 ] + walkopts + dryrunopts,
4669 _('[OPTION]... SOURCE... DEST'))
4672 _('[OPTION]... SOURCE... DEST'))
4670 def rename(ui, repo, *pats, **opts):
4673 def rename(ui, repo, *pats, **opts):
4671 """rename files; equivalent of copy + remove
4674 """rename files; equivalent of copy + remove
4672
4675
4673 Mark dest as copies of sources; mark sources for deletion. If dest
4676 Mark dest as copies of sources; mark sources for deletion. If dest
4674 is a directory, copies are put in that directory. If dest is a
4677 is a directory, copies are put in that directory. If dest is a
4675 file, there can only be one source.
4678 file, there can only be one source.
4676
4679
4677 By default, this command copies the contents of files as they
4680 By default, this command copies the contents of files as they
4678 exist in the working directory. If invoked with -A/--after, the
4681 exist in the working directory. If invoked with -A/--after, the
4679 operation is recorded, but no copying is performed.
4682 operation is recorded, but no copying is performed.
4680
4683
4681 This command takes effect at the next commit. To undo a rename
4684 This command takes effect at the next commit. To undo a rename
4682 before that, see :hg:`revert`.
4685 before that, see :hg:`revert`.
4683
4686
4684 Returns 0 on success, 1 if errors are encountered.
4687 Returns 0 on success, 1 if errors are encountered.
4685 """
4688 """
4686 wlock = repo.wlock(False)
4689 wlock = repo.wlock(False)
4687 try:
4690 try:
4688 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4691 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4689 finally:
4692 finally:
4690 wlock.release()
4693 wlock.release()
4691
4694
4692 @command('resolve',
4695 @command('resolve',
4693 [('a', 'all', None, _('select all unresolved files')),
4696 [('a', 'all', None, _('select all unresolved files')),
4694 ('l', 'list', None, _('list state of files needing merge')),
4697 ('l', 'list', None, _('list state of files needing merge')),
4695 ('m', 'mark', None, _('mark files as resolved')),
4698 ('m', 'mark', None, _('mark files as resolved')),
4696 ('u', 'unmark', None, _('mark files as unresolved')),
4699 ('u', 'unmark', None, _('mark files as unresolved')),
4697 ('n', 'no-status', None, _('hide status prefix'))]
4700 ('n', 'no-status', None, _('hide status prefix'))]
4698 + mergetoolopts + walkopts,
4701 + mergetoolopts + walkopts,
4699 _('[OPTION]... [FILE]...'))
4702 _('[OPTION]... [FILE]...'))
4700 def resolve(ui, repo, *pats, **opts):
4703 def resolve(ui, repo, *pats, **opts):
4701 """redo merges or set/view the merge status of files
4704 """redo merges or set/view the merge status of files
4702
4705
4703 Merges with unresolved conflicts are often the result of
4706 Merges with unresolved conflicts are often the result of
4704 non-interactive merging using the ``internal:merge`` configuration
4707 non-interactive merging using the ``internal:merge`` configuration
4705 setting, or a command-line merge tool like ``diff3``. The resolve
4708 setting, or a command-line merge tool like ``diff3``. The resolve
4706 command is used to manage the files involved in a merge, after
4709 command is used to manage the files involved in a merge, after
4707 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4710 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4708 working directory must have two parents). See :hg:`help
4711 working directory must have two parents). See :hg:`help
4709 merge-tools` for information on configuring merge tools.
4712 merge-tools` for information on configuring merge tools.
4710
4713
4711 The resolve command can be used in the following ways:
4714 The resolve command can be used in the following ways:
4712
4715
4713 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4716 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4714 files, discarding any previous merge attempts. Re-merging is not
4717 files, discarding any previous merge attempts. Re-merging is not
4715 performed for files already marked as resolved. Use ``--all/-a``
4718 performed for files already marked as resolved. Use ``--all/-a``
4716 to select all unresolved files. ``--tool`` can be used to specify
4719 to select all unresolved files. ``--tool`` can be used to specify
4717 the merge tool used for the given files. It overrides the HGMERGE
4720 the merge tool used for the given files. It overrides the HGMERGE
4718 environment variable and your configuration files. Previous file
4721 environment variable and your configuration files. Previous file
4719 contents are saved with a ``.orig`` suffix.
4722 contents are saved with a ``.orig`` suffix.
4720
4723
4721 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4724 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4722 (e.g. after having manually fixed-up the files). The default is
4725 (e.g. after having manually fixed-up the files). The default is
4723 to mark all unresolved files.
4726 to mark all unresolved files.
4724
4727
4725 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4728 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4726 default is to mark all resolved files.
4729 default is to mark all resolved files.
4727
4730
4728 - :hg:`resolve -l`: list files which had or still have conflicts.
4731 - :hg:`resolve -l`: list files which had or still have conflicts.
4729 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4732 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4730
4733
4731 Note that Mercurial will not let you commit files with unresolved
4734 Note that Mercurial will not let you commit files with unresolved
4732 merge conflicts. You must use :hg:`resolve -m ...` before you can
4735 merge conflicts. You must use :hg:`resolve -m ...` before you can
4733 commit after a conflicting merge.
4736 commit after a conflicting merge.
4734
4737
4735 Returns 0 on success, 1 if any files fail a resolve attempt.
4738 Returns 0 on success, 1 if any files fail a resolve attempt.
4736 """
4739 """
4737
4740
4738 all, mark, unmark, show, nostatus = \
4741 all, mark, unmark, show, nostatus = \
4739 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4742 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4740
4743
4741 if (show and (mark or unmark)) or (mark and unmark):
4744 if (show and (mark or unmark)) or (mark and unmark):
4742 raise util.Abort(_("too many options specified"))
4745 raise util.Abort(_("too many options specified"))
4743 if pats and all:
4746 if pats and all:
4744 raise util.Abort(_("can't specify --all and patterns"))
4747 raise util.Abort(_("can't specify --all and patterns"))
4745 if not (all or pats or show or mark or unmark):
4748 if not (all or pats or show or mark or unmark):
4746 raise util.Abort(_('no files or directories specified; '
4749 raise util.Abort(_('no files or directories specified; '
4747 'use --all to remerge all files'))
4750 'use --all to remerge all files'))
4748
4751
4749 ms = mergemod.mergestate(repo)
4752 ms = mergemod.mergestate(repo)
4750 m = scmutil.match(repo[None], pats, opts)
4753 m = scmutil.match(repo[None], pats, opts)
4751 ret = 0
4754 ret = 0
4752
4755
4753 for f in ms:
4756 for f in ms:
4754 if m(f):
4757 if m(f):
4755 if show:
4758 if show:
4756 if nostatus:
4759 if nostatus:
4757 ui.write("%s\n" % f)
4760 ui.write("%s\n" % f)
4758 else:
4761 else:
4759 ui.write("%s %s\n" % (ms[f].upper(), f),
4762 ui.write("%s %s\n" % (ms[f].upper(), f),
4760 label='resolve.' +
4763 label='resolve.' +
4761 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4764 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4762 elif mark:
4765 elif mark:
4763 ms.mark(f, "r")
4766 ms.mark(f, "r")
4764 elif unmark:
4767 elif unmark:
4765 ms.mark(f, "u")
4768 ms.mark(f, "u")
4766 else:
4769 else:
4767 wctx = repo[None]
4770 wctx = repo[None]
4768 mctx = wctx.parents()[-1]
4771 mctx = wctx.parents()[-1]
4769
4772
4770 # backup pre-resolve (merge uses .orig for its own purposes)
4773 # backup pre-resolve (merge uses .orig for its own purposes)
4771 a = repo.wjoin(f)
4774 a = repo.wjoin(f)
4772 util.copyfile(a, a + ".resolve")
4775 util.copyfile(a, a + ".resolve")
4773
4776
4774 try:
4777 try:
4775 # resolve file
4778 # resolve file
4776 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4779 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4777 if ms.resolve(f, wctx, mctx):
4780 if ms.resolve(f, wctx, mctx):
4778 ret = 1
4781 ret = 1
4779 finally:
4782 finally:
4780 ui.setconfig('ui', 'forcemerge', '')
4783 ui.setconfig('ui', 'forcemerge', '')
4781 ms.commit()
4784 ms.commit()
4782
4785
4783 # replace filemerge's .orig file with our resolve file
4786 # replace filemerge's .orig file with our resolve file
4784 util.rename(a + ".resolve", a + ".orig")
4787 util.rename(a + ".resolve", a + ".orig")
4785
4788
4786 ms.commit()
4789 ms.commit()
4787 return ret
4790 return ret
4788
4791
4789 @command('revert',
4792 @command('revert',
4790 [('a', 'all', None, _('revert all changes when no arguments given')),
4793 [('a', 'all', None, _('revert all changes when no arguments given')),
4791 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4794 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4792 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4795 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4793 ('C', 'no-backup', None, _('do not save backup copies of files')),
4796 ('C', 'no-backup', None, _('do not save backup copies of files')),
4794 ] + walkopts + dryrunopts,
4797 ] + walkopts + dryrunopts,
4795 _('[OPTION]... [-r REV] [NAME]...'))
4798 _('[OPTION]... [-r REV] [NAME]...'))
4796 def revert(ui, repo, *pats, **opts):
4799 def revert(ui, repo, *pats, **opts):
4797 """restore files to their checkout state
4800 """restore files to their checkout state
4798
4801
4799 .. note::
4802 .. note::
4800
4803
4801 To check out earlier revisions, you should use :hg:`update REV`.
4804 To check out earlier revisions, you should use :hg:`update REV`.
4802 To cancel an uncommitted merge (and lose your changes), use
4805 To cancel an uncommitted merge (and lose your changes), use
4803 :hg:`update --clean .`.
4806 :hg:`update --clean .`.
4804
4807
4805 With no revision specified, revert the specified files or directories
4808 With no revision specified, revert the specified files or directories
4806 to the contents they had in the parent of the working directory.
4809 to the contents they had in the parent of the working directory.
4807 This restores the contents of files to an unmodified
4810 This restores the contents of files to an unmodified
4808 state and unschedules adds, removes, copies, and renames. If the
4811 state and unschedules adds, removes, copies, and renames. If the
4809 working directory has two parents, you must explicitly specify a
4812 working directory has two parents, you must explicitly specify a
4810 revision.
4813 revision.
4811
4814
4812 Using the -r/--rev or -d/--date options, revert the given files or
4815 Using the -r/--rev or -d/--date options, revert the given files or
4813 directories to their states as of a specific revision. Because
4816 directories to their states as of a specific revision. Because
4814 revert does not change the working directory parents, this will
4817 revert does not change the working directory parents, this will
4815 cause these files to appear modified. This can be helpful to "back
4818 cause these files to appear modified. This can be helpful to "back
4816 out" some or all of an earlier change. See :hg:`backout` for a
4819 out" some or all of an earlier change. See :hg:`backout` for a
4817 related method.
4820 related method.
4818
4821
4819 Modified files are saved with a .orig suffix before reverting.
4822 Modified files are saved with a .orig suffix before reverting.
4820 To disable these backups, use --no-backup.
4823 To disable these backups, use --no-backup.
4821
4824
4822 See :hg:`help dates` for a list of formats valid for -d/--date.
4825 See :hg:`help dates` for a list of formats valid for -d/--date.
4823
4826
4824 Returns 0 on success.
4827 Returns 0 on success.
4825 """
4828 """
4826
4829
4827 if opts.get("date"):
4830 if opts.get("date"):
4828 if opts.get("rev"):
4831 if opts.get("rev"):
4829 raise util.Abort(_("you can't specify a revision and a date"))
4832 raise util.Abort(_("you can't specify a revision and a date"))
4830 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4833 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4831
4834
4832 parent, p2 = repo.dirstate.parents()
4835 parent, p2 = repo.dirstate.parents()
4833 if not opts.get('rev') and p2 != nullid:
4836 if not opts.get('rev') and p2 != nullid:
4834 # revert after merge is a trap for new users (issue2915)
4837 # revert after merge is a trap for new users (issue2915)
4835 raise util.Abort(_('uncommitted merge with no revision specified'),
4838 raise util.Abort(_('uncommitted merge with no revision specified'),
4836 hint=_('use "hg update" or see "hg help revert"'))
4839 hint=_('use "hg update" or see "hg help revert"'))
4837
4840
4838 ctx = scmutil.revsingle(repo, opts.get('rev'))
4841 ctx = scmutil.revsingle(repo, opts.get('rev'))
4839
4842
4840 if not pats and not opts.get('all'):
4843 if not pats and not opts.get('all'):
4841 msg = _("no files or directories specified")
4844 msg = _("no files or directories specified")
4842 if p2 != nullid:
4845 if p2 != nullid:
4843 hint = _("uncommitted merge, use --all to discard all changes,"
4846 hint = _("uncommitted merge, use --all to discard all changes,"
4844 " or 'hg update -C .' to abort the merge")
4847 " or 'hg update -C .' to abort the merge")
4845 raise util.Abort(msg, hint=hint)
4848 raise util.Abort(msg, hint=hint)
4846 dirty = util.any(repo.status())
4849 dirty = util.any(repo.status())
4847 node = ctx.node()
4850 node = ctx.node()
4848 if node != parent:
4851 if node != parent:
4849 if dirty:
4852 if dirty:
4850 hint = _("uncommitted changes, use --all to discard all"
4853 hint = _("uncommitted changes, use --all to discard all"
4851 " changes, or 'hg update %s' to update") % ctx.rev()
4854 " changes, or 'hg update %s' to update") % ctx.rev()
4852 else:
4855 else:
4853 hint = _("use --all to revert all files,"
4856 hint = _("use --all to revert all files,"
4854 " or 'hg update %s' to update") % ctx.rev()
4857 " or 'hg update %s' to update") % ctx.rev()
4855 elif dirty:
4858 elif dirty:
4856 hint = _("uncommitted changes, use --all to discard all changes")
4859 hint = _("uncommitted changes, use --all to discard all changes")
4857 else:
4860 else:
4858 hint = _("use --all to revert all files")
4861 hint = _("use --all to revert all files")
4859 raise util.Abort(msg, hint=hint)
4862 raise util.Abort(msg, hint=hint)
4860
4863
4861 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4864 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4862
4865
4863 @command('rollback', dryrunopts +
4866 @command('rollback', dryrunopts +
4864 [('f', 'force', False, _('ignore safety measures'))])
4867 [('f', 'force', False, _('ignore safety measures'))])
4865 def rollback(ui, repo, **opts):
4868 def rollback(ui, repo, **opts):
4866 """roll back the last transaction (dangerous)
4869 """roll back the last transaction (dangerous)
4867
4870
4868 This command should be used with care. There is only one level of
4871 This command should be used with care. There is only one level of
4869 rollback, and there is no way to undo a rollback. It will also
4872 rollback, and there is no way to undo a rollback. It will also
4870 restore the dirstate at the time of the last transaction, losing
4873 restore the dirstate at the time of the last transaction, losing
4871 any dirstate changes since that time. This command does not alter
4874 any dirstate changes since that time. This command does not alter
4872 the working directory.
4875 the working directory.
4873
4876
4874 Transactions are used to encapsulate the effects of all commands
4877 Transactions are used to encapsulate the effects of all commands
4875 that create new changesets or propagate existing changesets into a
4878 that create new changesets or propagate existing changesets into a
4876 repository.
4879 repository.
4877
4880
4878 .. container:: verbose
4881 .. container:: verbose
4879
4882
4880 For example, the following commands are transactional, and their
4883 For example, the following commands are transactional, and their
4881 effects can be rolled back:
4884 effects can be rolled back:
4882
4885
4883 - commit
4886 - commit
4884 - import
4887 - import
4885 - pull
4888 - pull
4886 - push (with this repository as the destination)
4889 - push (with this repository as the destination)
4887 - unbundle
4890 - unbundle
4888
4891
4889 To avoid permanent data loss, rollback will refuse to rollback a
4892 To avoid permanent data loss, rollback will refuse to rollback a
4890 commit transaction if it isn't checked out. Use --force to
4893 commit transaction if it isn't checked out. Use --force to
4891 override this protection.
4894 override this protection.
4892
4895
4893 This command is not intended for use on public repositories. Once
4896 This command is not intended for use on public repositories. Once
4894 changes are visible for pull by other users, rolling a transaction
4897 changes are visible for pull by other users, rolling a transaction
4895 back locally is ineffective (someone else may already have pulled
4898 back locally is ineffective (someone else may already have pulled
4896 the changes). Furthermore, a race is possible with readers of the
4899 the changes). Furthermore, a race is possible with readers of the
4897 repository; for example an in-progress pull from the repository
4900 repository; for example an in-progress pull from the repository
4898 may fail if a rollback is performed.
4901 may fail if a rollback is performed.
4899
4902
4900 Returns 0 on success, 1 if no rollback data is available.
4903 Returns 0 on success, 1 if no rollback data is available.
4901 """
4904 """
4902 return repo.rollback(dryrun=opts.get('dry_run'),
4905 return repo.rollback(dryrun=opts.get('dry_run'),
4903 force=opts.get('force'))
4906 force=opts.get('force'))
4904
4907
4905 @command('root', [])
4908 @command('root', [])
4906 def root(ui, repo):
4909 def root(ui, repo):
4907 """print the root (top) of the current working directory
4910 """print the root (top) of the current working directory
4908
4911
4909 Print the root directory of the current repository.
4912 Print the root directory of the current repository.
4910
4913
4911 Returns 0 on success.
4914 Returns 0 on success.
4912 """
4915 """
4913 ui.write(repo.root + "\n")
4916 ui.write(repo.root + "\n")
4914
4917
4915 @command('^serve',
4918 @command('^serve',
4916 [('A', 'accesslog', '', _('name of access log file to write to'),
4919 [('A', 'accesslog', '', _('name of access log file to write to'),
4917 _('FILE')),
4920 _('FILE')),
4918 ('d', 'daemon', None, _('run server in background')),
4921 ('d', 'daemon', None, _('run server in background')),
4919 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4922 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4920 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4923 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4921 # use string type, then we can check if something was passed
4924 # use string type, then we can check if something was passed
4922 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4925 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4923 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4926 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4924 _('ADDR')),
4927 _('ADDR')),
4925 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4928 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4926 _('PREFIX')),
4929 _('PREFIX')),
4927 ('n', 'name', '',
4930 ('n', 'name', '',
4928 _('name to show in web pages (default: working directory)'), _('NAME')),
4931 _('name to show in web pages (default: working directory)'), _('NAME')),
4929 ('', 'web-conf', '',
4932 ('', 'web-conf', '',
4930 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4933 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4931 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4934 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4932 _('FILE')),
4935 _('FILE')),
4933 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4936 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4934 ('', 'stdio', None, _('for remote clients')),
4937 ('', 'stdio', None, _('for remote clients')),
4935 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4938 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4936 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4939 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4937 ('', 'style', '', _('template style to use'), _('STYLE')),
4940 ('', 'style', '', _('template style to use'), _('STYLE')),
4938 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4941 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4939 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4942 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4940 _('[OPTION]...'))
4943 _('[OPTION]...'))
4941 def serve(ui, repo, **opts):
4944 def serve(ui, repo, **opts):
4942 """start stand-alone webserver
4945 """start stand-alone webserver
4943
4946
4944 Start a local HTTP repository browser and pull server. You can use
4947 Start a local HTTP repository browser and pull server. You can use
4945 this for ad-hoc sharing and browsing of repositories. It is
4948 this for ad-hoc sharing and browsing of repositories. It is
4946 recommended to use a real web server to serve a repository for
4949 recommended to use a real web server to serve a repository for
4947 longer periods of time.
4950 longer periods of time.
4948
4951
4949 Please note that the server does not implement access control.
4952 Please note that the server does not implement access control.
4950 This means that, by default, anybody can read from the server and
4953 This means that, by default, anybody can read from the server and
4951 nobody can write to it by default. Set the ``web.allow_push``
4954 nobody can write to it by default. Set the ``web.allow_push``
4952 option to ``*`` to allow everybody to push to the server. You
4955 option to ``*`` to allow everybody to push to the server. You
4953 should use a real web server if you need to authenticate users.
4956 should use a real web server if you need to authenticate users.
4954
4957
4955 By default, the server logs accesses to stdout and errors to
4958 By default, the server logs accesses to stdout and errors to
4956 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4959 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4957 files.
4960 files.
4958
4961
4959 To have the server choose a free port number to listen on, specify
4962 To have the server choose a free port number to listen on, specify
4960 a port number of 0; in this case, the server will print the port
4963 a port number of 0; in this case, the server will print the port
4961 number it uses.
4964 number it uses.
4962
4965
4963 Returns 0 on success.
4966 Returns 0 on success.
4964 """
4967 """
4965
4968
4966 if opts["stdio"] and opts["cmdserver"]:
4969 if opts["stdio"] and opts["cmdserver"]:
4967 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4970 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4968
4971
4969 def checkrepo():
4972 def checkrepo():
4970 if repo is None:
4973 if repo is None:
4971 raise error.RepoError(_("there is no Mercurial repository here"
4974 raise error.RepoError(_("there is no Mercurial repository here"
4972 " (.hg not found)"))
4975 " (.hg not found)"))
4973
4976
4974 if opts["stdio"]:
4977 if opts["stdio"]:
4975 checkrepo()
4978 checkrepo()
4976 s = sshserver.sshserver(ui, repo)
4979 s = sshserver.sshserver(ui, repo)
4977 s.serve_forever()
4980 s.serve_forever()
4978
4981
4979 if opts["cmdserver"]:
4982 if opts["cmdserver"]:
4980 checkrepo()
4983 checkrepo()
4981 s = commandserver.server(ui, repo, opts["cmdserver"])
4984 s = commandserver.server(ui, repo, opts["cmdserver"])
4982 return s.serve()
4985 return s.serve()
4983
4986
4984 # this way we can check if something was given in the command-line
4987 # this way we can check if something was given in the command-line
4985 if opts.get('port'):
4988 if opts.get('port'):
4986 opts['port'] = util.getport(opts.get('port'))
4989 opts['port'] = util.getport(opts.get('port'))
4987
4990
4988 baseui = repo and repo.baseui or ui
4991 baseui = repo and repo.baseui or ui
4989 optlist = ("name templates style address port prefix ipv6"
4992 optlist = ("name templates style address port prefix ipv6"
4990 " accesslog errorlog certificate encoding")
4993 " accesslog errorlog certificate encoding")
4991 for o in optlist.split():
4994 for o in optlist.split():
4992 val = opts.get(o, '')
4995 val = opts.get(o, '')
4993 if val in (None, ''): # should check against default options instead
4996 if val in (None, ''): # should check against default options instead
4994 continue
4997 continue
4995 baseui.setconfig("web", o, val)
4998 baseui.setconfig("web", o, val)
4996 if repo and repo.ui != baseui:
4999 if repo and repo.ui != baseui:
4997 repo.ui.setconfig("web", o, val)
5000 repo.ui.setconfig("web", o, val)
4998
5001
4999 o = opts.get('web_conf') or opts.get('webdir_conf')
5002 o = opts.get('web_conf') or opts.get('webdir_conf')
5000 if not o:
5003 if not o:
5001 if not repo:
5004 if not repo:
5002 raise error.RepoError(_("there is no Mercurial repository"
5005 raise error.RepoError(_("there is no Mercurial repository"
5003 " here (.hg not found)"))
5006 " here (.hg not found)"))
5004 o = repo.root
5007 o = repo.root
5005
5008
5006 app = hgweb.hgweb(o, baseui=ui)
5009 app = hgweb.hgweb(o, baseui=ui)
5007
5010
5008 class service(object):
5011 class service(object):
5009 def init(self):
5012 def init(self):
5010 util.setsignalhandler()
5013 util.setsignalhandler()
5011 self.httpd = hgweb.server.create_server(ui, app)
5014 self.httpd = hgweb.server.create_server(ui, app)
5012
5015
5013 if opts['port'] and not ui.verbose:
5016 if opts['port'] and not ui.verbose:
5014 return
5017 return
5015
5018
5016 if self.httpd.prefix:
5019 if self.httpd.prefix:
5017 prefix = self.httpd.prefix.strip('/') + '/'
5020 prefix = self.httpd.prefix.strip('/') + '/'
5018 else:
5021 else:
5019 prefix = ''
5022 prefix = ''
5020
5023
5021 port = ':%d' % self.httpd.port
5024 port = ':%d' % self.httpd.port
5022 if port == ':80':
5025 if port == ':80':
5023 port = ''
5026 port = ''
5024
5027
5025 bindaddr = self.httpd.addr
5028 bindaddr = self.httpd.addr
5026 if bindaddr == '0.0.0.0':
5029 if bindaddr == '0.0.0.0':
5027 bindaddr = '*'
5030 bindaddr = '*'
5028 elif ':' in bindaddr: # IPv6
5031 elif ':' in bindaddr: # IPv6
5029 bindaddr = '[%s]' % bindaddr
5032 bindaddr = '[%s]' % bindaddr
5030
5033
5031 fqaddr = self.httpd.fqaddr
5034 fqaddr = self.httpd.fqaddr
5032 if ':' in fqaddr:
5035 if ':' in fqaddr:
5033 fqaddr = '[%s]' % fqaddr
5036 fqaddr = '[%s]' % fqaddr
5034 if opts['port']:
5037 if opts['port']:
5035 write = ui.status
5038 write = ui.status
5036 else:
5039 else:
5037 write = ui.write
5040 write = ui.write
5038 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5041 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5039 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5042 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5040
5043
5041 def run(self):
5044 def run(self):
5042 self.httpd.serve_forever()
5045 self.httpd.serve_forever()
5043
5046
5044 service = service()
5047 service = service()
5045
5048
5046 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5049 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5047
5050
5048 @command('showconfig|debugconfig',
5051 @command('showconfig|debugconfig',
5049 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5052 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5050 _('[-u] [NAME]...'))
5053 _('[-u] [NAME]...'))
5051 def showconfig(ui, repo, *values, **opts):
5054 def showconfig(ui, repo, *values, **opts):
5052 """show combined config settings from all hgrc files
5055 """show combined config settings from all hgrc files
5053
5056
5054 With no arguments, print names and values of all config items.
5057 With no arguments, print names and values of all config items.
5055
5058
5056 With one argument of the form section.name, print just the value
5059 With one argument of the form section.name, print just the value
5057 of that config item.
5060 of that config item.
5058
5061
5059 With multiple arguments, print names and values of all config
5062 With multiple arguments, print names and values of all config
5060 items with matching section names.
5063 items with matching section names.
5061
5064
5062 With --debug, the source (filename and line number) is printed
5065 With --debug, the source (filename and line number) is printed
5063 for each config item.
5066 for each config item.
5064
5067
5065 Returns 0 on success.
5068 Returns 0 on success.
5066 """
5069 """
5067
5070
5068 for f in scmutil.rcpath():
5071 for f in scmutil.rcpath():
5069 ui.debug('read config from: %s\n' % f)
5072 ui.debug('read config from: %s\n' % f)
5070 untrusted = bool(opts.get('untrusted'))
5073 untrusted = bool(opts.get('untrusted'))
5071 if values:
5074 if values:
5072 sections = [v for v in values if '.' not in v]
5075 sections = [v for v in values if '.' not in v]
5073 items = [v for v in values if '.' in v]
5076 items = [v for v in values if '.' in v]
5074 if len(items) > 1 or items and sections:
5077 if len(items) > 1 or items and sections:
5075 raise util.Abort(_('only one config item permitted'))
5078 raise util.Abort(_('only one config item permitted'))
5076 for section, name, value in ui.walkconfig(untrusted=untrusted):
5079 for section, name, value in ui.walkconfig(untrusted=untrusted):
5077 value = str(value).replace('\n', '\\n')
5080 value = str(value).replace('\n', '\\n')
5078 sectname = section + '.' + name
5081 sectname = section + '.' + name
5079 if values:
5082 if values:
5080 for v in values:
5083 for v in values:
5081 if v == section:
5084 if v == section:
5082 ui.debug('%s: ' %
5085 ui.debug('%s: ' %
5083 ui.configsource(section, name, untrusted))
5086 ui.configsource(section, name, untrusted))
5084 ui.write('%s=%s\n' % (sectname, value))
5087 ui.write('%s=%s\n' % (sectname, value))
5085 elif v == sectname:
5088 elif v == sectname:
5086 ui.debug('%s: ' %
5089 ui.debug('%s: ' %
5087 ui.configsource(section, name, untrusted))
5090 ui.configsource(section, name, untrusted))
5088 ui.write(value, '\n')
5091 ui.write(value, '\n')
5089 else:
5092 else:
5090 ui.debug('%s: ' %
5093 ui.debug('%s: ' %
5091 ui.configsource(section, name, untrusted))
5094 ui.configsource(section, name, untrusted))
5092 ui.write('%s=%s\n' % (sectname, value))
5095 ui.write('%s=%s\n' % (sectname, value))
5093
5096
5094 @command('^status|st',
5097 @command('^status|st',
5095 [('A', 'all', None, _('show status of all files')),
5098 [('A', 'all', None, _('show status of all files')),
5096 ('m', 'modified', None, _('show only modified files')),
5099 ('m', 'modified', None, _('show only modified files')),
5097 ('a', 'added', None, _('show only added files')),
5100 ('a', 'added', None, _('show only added files')),
5098 ('r', 'removed', None, _('show only removed files')),
5101 ('r', 'removed', None, _('show only removed files')),
5099 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5102 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5100 ('c', 'clean', None, _('show only files without changes')),
5103 ('c', 'clean', None, _('show only files without changes')),
5101 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5104 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5102 ('i', 'ignored', None, _('show only ignored files')),
5105 ('i', 'ignored', None, _('show only ignored files')),
5103 ('n', 'no-status', None, _('hide status prefix')),
5106 ('n', 'no-status', None, _('hide status prefix')),
5104 ('C', 'copies', None, _('show source of copied files')),
5107 ('C', 'copies', None, _('show source of copied files')),
5105 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5108 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5106 ('', 'rev', [], _('show difference from revision'), _('REV')),
5109 ('', 'rev', [], _('show difference from revision'), _('REV')),
5107 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5110 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5108 ] + walkopts + subrepoopts,
5111 ] + walkopts + subrepoopts,
5109 _('[OPTION]... [FILE]...'))
5112 _('[OPTION]... [FILE]...'))
5110 def status(ui, repo, *pats, **opts):
5113 def status(ui, repo, *pats, **opts):
5111 """show changed files in the working directory
5114 """show changed files in the working directory
5112
5115
5113 Show status of files in the repository. If names are given, only
5116 Show status of files in the repository. If names are given, only
5114 files that match are shown. Files that are clean or ignored or
5117 files that match are shown. Files that are clean or ignored or
5115 the source of a copy/move operation, are not listed unless
5118 the source of a copy/move operation, are not listed unless
5116 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5119 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5117 Unless options described with "show only ..." are given, the
5120 Unless options described with "show only ..." are given, the
5118 options -mardu are used.
5121 options -mardu are used.
5119
5122
5120 Option -q/--quiet hides untracked (unknown and ignored) files
5123 Option -q/--quiet hides untracked (unknown and ignored) files
5121 unless explicitly requested with -u/--unknown or -i/--ignored.
5124 unless explicitly requested with -u/--unknown or -i/--ignored.
5122
5125
5123 .. note::
5126 .. note::
5124 status may appear to disagree with diff if permissions have
5127 status may appear to disagree with diff if permissions have
5125 changed or a merge has occurred. The standard diff format does
5128 changed or a merge has occurred. The standard diff format does
5126 not report permission changes and diff only reports changes
5129 not report permission changes and diff only reports changes
5127 relative to one merge parent.
5130 relative to one merge parent.
5128
5131
5129 If one revision is given, it is used as the base revision.
5132 If one revision is given, it is used as the base revision.
5130 If two revisions are given, the differences between them are
5133 If two revisions are given, the differences between them are
5131 shown. The --change option can also be used as a shortcut to list
5134 shown. The --change option can also be used as a shortcut to list
5132 the changed files of a revision from its first parent.
5135 the changed files of a revision from its first parent.
5133
5136
5134 The codes used to show the status of files are::
5137 The codes used to show the status of files are::
5135
5138
5136 M = modified
5139 M = modified
5137 A = added
5140 A = added
5138 R = removed
5141 R = removed
5139 C = clean
5142 C = clean
5140 ! = missing (deleted by non-hg command, but still tracked)
5143 ! = missing (deleted by non-hg command, but still tracked)
5141 ? = not tracked
5144 ? = not tracked
5142 I = ignored
5145 I = ignored
5143 = origin of the previous file listed as A (added)
5146 = origin of the previous file listed as A (added)
5144
5147
5145 .. container:: verbose
5148 .. container:: verbose
5146
5149
5147 Examples:
5150 Examples:
5148
5151
5149 - show changes in the working directory relative to a
5152 - show changes in the working directory relative to a
5150 changeset::
5153 changeset::
5151
5154
5152 hg status --rev 9353
5155 hg status --rev 9353
5153
5156
5154 - show all changes including copies in an existing changeset::
5157 - show all changes including copies in an existing changeset::
5155
5158
5156 hg status --copies --change 9353
5159 hg status --copies --change 9353
5157
5160
5158 - get a NUL separated list of added files, suitable for xargs::
5161 - get a NUL separated list of added files, suitable for xargs::
5159
5162
5160 hg status -an0
5163 hg status -an0
5161
5164
5162 Returns 0 on success.
5165 Returns 0 on success.
5163 """
5166 """
5164
5167
5165 revs = opts.get('rev')
5168 revs = opts.get('rev')
5166 change = opts.get('change')
5169 change = opts.get('change')
5167
5170
5168 if revs and change:
5171 if revs and change:
5169 msg = _('cannot specify --rev and --change at the same time')
5172 msg = _('cannot specify --rev and --change at the same time')
5170 raise util.Abort(msg)
5173 raise util.Abort(msg)
5171 elif change:
5174 elif change:
5172 node2 = scmutil.revsingle(repo, change, None).node()
5175 node2 = scmutil.revsingle(repo, change, None).node()
5173 node1 = repo[node2].p1().node()
5176 node1 = repo[node2].p1().node()
5174 else:
5177 else:
5175 node1, node2 = scmutil.revpair(repo, revs)
5178 node1, node2 = scmutil.revpair(repo, revs)
5176
5179
5177 cwd = (pats and repo.getcwd()) or ''
5180 cwd = (pats and repo.getcwd()) or ''
5178 end = opts.get('print0') and '\0' or '\n'
5181 end = opts.get('print0') and '\0' or '\n'
5179 copy = {}
5182 copy = {}
5180 states = 'modified added removed deleted unknown ignored clean'.split()
5183 states = 'modified added removed deleted unknown ignored clean'.split()
5181 show = [k for k in states if opts.get(k)]
5184 show = [k for k in states if opts.get(k)]
5182 if opts.get('all'):
5185 if opts.get('all'):
5183 show += ui.quiet and (states[:4] + ['clean']) or states
5186 show += ui.quiet and (states[:4] + ['clean']) or states
5184 if not show:
5187 if not show:
5185 show = ui.quiet and states[:4] or states[:5]
5188 show = ui.quiet and states[:4] or states[:5]
5186
5189
5187 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5190 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5188 'ignored' in show, 'clean' in show, 'unknown' in show,
5191 'ignored' in show, 'clean' in show, 'unknown' in show,
5189 opts.get('subrepos'))
5192 opts.get('subrepos'))
5190 changestates = zip(states, 'MAR!?IC', stat)
5193 changestates = zip(states, 'MAR!?IC', stat)
5191
5194
5192 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5195 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5193 copy = copies.pathcopies(repo[node1], repo[node2])
5196 copy = copies.pathcopies(repo[node1], repo[node2])
5194
5197
5195 fm = ui.formatter('status', opts)
5198 fm = ui.formatter('status', opts)
5196 fmt = '%s' + end
5199 fmt = '%s' + end
5197 showchar = not opts.get('no_status')
5200 showchar = not opts.get('no_status')
5198
5201
5199 for state, char, files in changestates:
5202 for state, char, files in changestates:
5200 if state in show:
5203 if state in show:
5201 label = 'status.' + state
5204 label = 'status.' + state
5202 for f in files:
5205 for f in files:
5203 fm.startitem()
5206 fm.startitem()
5204 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5207 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5205 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5208 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5206 if f in copy:
5209 if f in copy:
5207 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5210 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5208 label='status.copied')
5211 label='status.copied')
5209 fm.end()
5212 fm.end()
5210
5213
5211 @command('^summary|sum',
5214 @command('^summary|sum',
5212 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5215 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5213 def summary(ui, repo, **opts):
5216 def summary(ui, repo, **opts):
5214 """summarize working directory state
5217 """summarize working directory state
5215
5218
5216 This generates a brief summary of the working directory state,
5219 This generates a brief summary of the working directory state,
5217 including parents, branch, commit status, and available updates.
5220 including parents, branch, commit status, and available updates.
5218
5221
5219 With the --remote option, this will check the default paths for
5222 With the --remote option, this will check the default paths for
5220 incoming and outgoing changes. This can be time-consuming.
5223 incoming and outgoing changes. This can be time-consuming.
5221
5224
5222 Returns 0 on success.
5225 Returns 0 on success.
5223 """
5226 """
5224
5227
5225 ctx = repo[None]
5228 ctx = repo[None]
5226 parents = ctx.parents()
5229 parents = ctx.parents()
5227 pnode = parents[0].node()
5230 pnode = parents[0].node()
5228 marks = []
5231 marks = []
5229
5232
5230 for p in parents:
5233 for p in parents:
5231 # label with log.changeset (instead of log.parent) since this
5234 # label with log.changeset (instead of log.parent) since this
5232 # shows a working directory parent *changeset*:
5235 # shows a working directory parent *changeset*:
5233 # i18n: column positioning for "hg summary"
5236 # i18n: column positioning for "hg summary"
5234 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5237 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5235 label='log.changeset changeset.%s' % p.phasestr())
5238 label='log.changeset changeset.%s' % p.phasestr())
5236 ui.write(' '.join(p.tags()), label='log.tag')
5239 ui.write(' '.join(p.tags()), label='log.tag')
5237 if p.bookmarks():
5240 if p.bookmarks():
5238 marks.extend(p.bookmarks())
5241 marks.extend(p.bookmarks())
5239 if p.rev() == -1:
5242 if p.rev() == -1:
5240 if not len(repo):
5243 if not len(repo):
5241 ui.write(_(' (empty repository)'))
5244 ui.write(_(' (empty repository)'))
5242 else:
5245 else:
5243 ui.write(_(' (no revision checked out)'))
5246 ui.write(_(' (no revision checked out)'))
5244 ui.write('\n')
5247 ui.write('\n')
5245 if p.description():
5248 if p.description():
5246 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5249 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5247 label='log.summary')
5250 label='log.summary')
5248
5251
5249 branch = ctx.branch()
5252 branch = ctx.branch()
5250 bheads = repo.branchheads(branch)
5253 bheads = repo.branchheads(branch)
5251 # i18n: column positioning for "hg summary"
5254 # i18n: column positioning for "hg summary"
5252 m = _('branch: %s\n') % branch
5255 m = _('branch: %s\n') % branch
5253 if branch != 'default':
5256 if branch != 'default':
5254 ui.write(m, label='log.branch')
5257 ui.write(m, label='log.branch')
5255 else:
5258 else:
5256 ui.status(m, label='log.branch')
5259 ui.status(m, label='log.branch')
5257
5260
5258 if marks:
5261 if marks:
5259 current = repo._bookmarkcurrent
5262 current = repo._bookmarkcurrent
5260 # i18n: column positioning for "hg summary"
5263 # i18n: column positioning for "hg summary"
5261 ui.write(_('bookmarks:'), label='log.bookmark')
5264 ui.write(_('bookmarks:'), label='log.bookmark')
5262 if current is not None:
5265 if current is not None:
5263 if current in marks:
5266 if current in marks:
5264 ui.write(' *' + current, label='bookmarks.current')
5267 ui.write(' *' + current, label='bookmarks.current')
5265 marks.remove(current)
5268 marks.remove(current)
5266 else:
5269 else:
5267 ui.write(' [%s]' % current, label='bookmarks.current')
5270 ui.write(' [%s]' % current, label='bookmarks.current')
5268 for m in marks:
5271 for m in marks:
5269 ui.write(' ' + m, label='log.bookmark')
5272 ui.write(' ' + m, label='log.bookmark')
5270 ui.write('\n', label='log.bookmark')
5273 ui.write('\n', label='log.bookmark')
5271
5274
5272 st = list(repo.status(unknown=True))[:6]
5275 st = list(repo.status(unknown=True))[:6]
5273
5276
5274 c = repo.dirstate.copies()
5277 c = repo.dirstate.copies()
5275 copied, renamed = [], []
5278 copied, renamed = [], []
5276 for d, s in c.iteritems():
5279 for d, s in c.iteritems():
5277 if s in st[2]:
5280 if s in st[2]:
5278 st[2].remove(s)
5281 st[2].remove(s)
5279 renamed.append(d)
5282 renamed.append(d)
5280 else:
5283 else:
5281 copied.append(d)
5284 copied.append(d)
5282 if d in st[1]:
5285 if d in st[1]:
5283 st[1].remove(d)
5286 st[1].remove(d)
5284 st.insert(3, renamed)
5287 st.insert(3, renamed)
5285 st.insert(4, copied)
5288 st.insert(4, copied)
5286
5289
5287 ms = mergemod.mergestate(repo)
5290 ms = mergemod.mergestate(repo)
5288 st.append([f for f in ms if ms[f] == 'u'])
5291 st.append([f for f in ms if ms[f] == 'u'])
5289
5292
5290 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5293 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5291 st.append(subs)
5294 st.append(subs)
5292
5295
5293 labels = [ui.label(_('%d modified'), 'status.modified'),
5296 labels = [ui.label(_('%d modified'), 'status.modified'),
5294 ui.label(_('%d added'), 'status.added'),
5297 ui.label(_('%d added'), 'status.added'),
5295 ui.label(_('%d removed'), 'status.removed'),
5298 ui.label(_('%d removed'), 'status.removed'),
5296 ui.label(_('%d renamed'), 'status.copied'),
5299 ui.label(_('%d renamed'), 'status.copied'),
5297 ui.label(_('%d copied'), 'status.copied'),
5300 ui.label(_('%d copied'), 'status.copied'),
5298 ui.label(_('%d deleted'), 'status.deleted'),
5301 ui.label(_('%d deleted'), 'status.deleted'),
5299 ui.label(_('%d unknown'), 'status.unknown'),
5302 ui.label(_('%d unknown'), 'status.unknown'),
5300 ui.label(_('%d ignored'), 'status.ignored'),
5303 ui.label(_('%d ignored'), 'status.ignored'),
5301 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5304 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5302 ui.label(_('%d subrepos'), 'status.modified')]
5305 ui.label(_('%d subrepos'), 'status.modified')]
5303 t = []
5306 t = []
5304 for s, l in zip(st, labels):
5307 for s, l in zip(st, labels):
5305 if s:
5308 if s:
5306 t.append(l % len(s))
5309 t.append(l % len(s))
5307
5310
5308 t = ', '.join(t)
5311 t = ', '.join(t)
5309 cleanworkdir = False
5312 cleanworkdir = False
5310
5313
5311 if len(parents) > 1:
5314 if len(parents) > 1:
5312 t += _(' (merge)')
5315 t += _(' (merge)')
5313 elif branch != parents[0].branch():
5316 elif branch != parents[0].branch():
5314 t += _(' (new branch)')
5317 t += _(' (new branch)')
5315 elif (parents[0].closesbranch() and
5318 elif (parents[0].closesbranch() and
5316 pnode in repo.branchheads(branch, closed=True)):
5319 pnode in repo.branchheads(branch, closed=True)):
5317 t += _(' (head closed)')
5320 t += _(' (head closed)')
5318 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5321 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5319 t += _(' (clean)')
5322 t += _(' (clean)')
5320 cleanworkdir = True
5323 cleanworkdir = True
5321 elif pnode not in bheads:
5324 elif pnode not in bheads:
5322 t += _(' (new branch head)')
5325 t += _(' (new branch head)')
5323
5326
5324 if cleanworkdir:
5327 if cleanworkdir:
5325 # i18n: column positioning for "hg summary"
5328 # i18n: column positioning for "hg summary"
5326 ui.status(_('commit: %s\n') % t.strip())
5329 ui.status(_('commit: %s\n') % t.strip())
5327 else:
5330 else:
5328 # i18n: column positioning for "hg summary"
5331 # i18n: column positioning for "hg summary"
5329 ui.write(_('commit: %s\n') % t.strip())
5332 ui.write(_('commit: %s\n') % t.strip())
5330
5333
5331 # all ancestors of branch heads - all ancestors of parent = new csets
5334 # all ancestors of branch heads - all ancestors of parent = new csets
5332 new = [0] * len(repo)
5335 new = [0] * len(repo)
5333 cl = repo.changelog
5336 cl = repo.changelog
5334 for a in [cl.rev(n) for n in bheads]:
5337 for a in [cl.rev(n) for n in bheads]:
5335 new[a] = 1
5338 new[a] = 1
5336 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5339 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5337 new[a] = 1
5340 new[a] = 1
5338 for a in [p.rev() for p in parents]:
5341 for a in [p.rev() for p in parents]:
5339 if a >= 0:
5342 if a >= 0:
5340 new[a] = 0
5343 new[a] = 0
5341 for a in cl.ancestors([p.rev() for p in parents]):
5344 for a in cl.ancestors([p.rev() for p in parents]):
5342 new[a] = 0
5345 new[a] = 0
5343 new = sum(new)
5346 new = sum(new)
5344
5347
5345 if new == 0:
5348 if new == 0:
5346 # i18n: column positioning for "hg summary"
5349 # i18n: column positioning for "hg summary"
5347 ui.status(_('update: (current)\n'))
5350 ui.status(_('update: (current)\n'))
5348 elif pnode not in bheads:
5351 elif pnode not in bheads:
5349 # i18n: column positioning for "hg summary"
5352 # i18n: column positioning for "hg summary"
5350 ui.write(_('update: %d new changesets (update)\n') % new)
5353 ui.write(_('update: %d new changesets (update)\n') % new)
5351 else:
5354 else:
5352 # i18n: column positioning for "hg summary"
5355 # i18n: column positioning for "hg summary"
5353 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5356 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5354 (new, len(bheads)))
5357 (new, len(bheads)))
5355
5358
5356 if opts.get('remote'):
5359 if opts.get('remote'):
5357 t = []
5360 t = []
5358 source, branches = hg.parseurl(ui.expandpath('default'))
5361 source, branches = hg.parseurl(ui.expandpath('default'))
5359 other = hg.peer(repo, {}, source)
5362 other = hg.peer(repo, {}, source)
5360 revs, checkout = hg.addbranchrevs(repo, other, branches,
5363 revs, checkout = hg.addbranchrevs(repo, other, branches,
5361 opts.get('rev'))
5364 opts.get('rev'))
5362 ui.debug('comparing with %s\n' % util.hidepassword(source))
5365 ui.debug('comparing with %s\n' % util.hidepassword(source))
5363 repo.ui.pushbuffer()
5366 repo.ui.pushbuffer()
5364 commoninc = discovery.findcommonincoming(repo, other)
5367 commoninc = discovery.findcommonincoming(repo, other)
5365 _common, incoming, _rheads = commoninc
5368 _common, incoming, _rheads = commoninc
5366 repo.ui.popbuffer()
5369 repo.ui.popbuffer()
5367 if incoming:
5370 if incoming:
5368 t.append(_('1 or more incoming'))
5371 t.append(_('1 or more incoming'))
5369
5372
5370 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5373 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5371 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5374 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5372 if source != dest:
5375 if source != dest:
5373 other = hg.peer(repo, {}, dest)
5376 other = hg.peer(repo, {}, dest)
5374 commoninc = None
5377 commoninc = None
5375 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5378 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5376 repo.ui.pushbuffer()
5379 repo.ui.pushbuffer()
5377 outgoing = discovery.findcommonoutgoing(repo, other,
5380 outgoing = discovery.findcommonoutgoing(repo, other,
5378 commoninc=commoninc)
5381 commoninc=commoninc)
5379 repo.ui.popbuffer()
5382 repo.ui.popbuffer()
5380 o = outgoing.missing
5383 o = outgoing.missing
5381 if o:
5384 if o:
5382 t.append(_('%d outgoing') % len(o))
5385 t.append(_('%d outgoing') % len(o))
5383 if 'bookmarks' in other.listkeys('namespaces'):
5386 if 'bookmarks' in other.listkeys('namespaces'):
5384 lmarks = repo.listkeys('bookmarks')
5387 lmarks = repo.listkeys('bookmarks')
5385 rmarks = other.listkeys('bookmarks')
5388 rmarks = other.listkeys('bookmarks')
5386 diff = set(rmarks) - set(lmarks)
5389 diff = set(rmarks) - set(lmarks)
5387 if len(diff) > 0:
5390 if len(diff) > 0:
5388 t.append(_('%d incoming bookmarks') % len(diff))
5391 t.append(_('%d incoming bookmarks') % len(diff))
5389 diff = set(lmarks) - set(rmarks)
5392 diff = set(lmarks) - set(rmarks)
5390 if len(diff) > 0:
5393 if len(diff) > 0:
5391 t.append(_('%d outgoing bookmarks') % len(diff))
5394 t.append(_('%d outgoing bookmarks') % len(diff))
5392
5395
5393 if t:
5396 if t:
5394 # i18n: column positioning for "hg summary"
5397 # i18n: column positioning for "hg summary"
5395 ui.write(_('remote: %s\n') % (', '.join(t)))
5398 ui.write(_('remote: %s\n') % (', '.join(t)))
5396 else:
5399 else:
5397 # i18n: column positioning for "hg summary"
5400 # i18n: column positioning for "hg summary"
5398 ui.status(_('remote: (synced)\n'))
5401 ui.status(_('remote: (synced)\n'))
5399
5402
5400 @command('tag',
5403 @command('tag',
5401 [('f', 'force', None, _('force tag')),
5404 [('f', 'force', None, _('force tag')),
5402 ('l', 'local', None, _('make the tag local')),
5405 ('l', 'local', None, _('make the tag local')),
5403 ('r', 'rev', '', _('revision to tag'), _('REV')),
5406 ('r', 'rev', '', _('revision to tag'), _('REV')),
5404 ('', 'remove', None, _('remove a tag')),
5407 ('', 'remove', None, _('remove a tag')),
5405 # -l/--local is already there, commitopts cannot be used
5408 # -l/--local is already there, commitopts cannot be used
5406 ('e', 'edit', None, _('edit commit message')),
5409 ('e', 'edit', None, _('edit commit message')),
5407 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5410 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5408 ] + commitopts2,
5411 ] + commitopts2,
5409 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5412 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5410 def tag(ui, repo, name1, *names, **opts):
5413 def tag(ui, repo, name1, *names, **opts):
5411 """add one or more tags for the current or given revision
5414 """add one or more tags for the current or given revision
5412
5415
5413 Name a particular revision using <name>.
5416 Name a particular revision using <name>.
5414
5417
5415 Tags are used to name particular revisions of the repository and are
5418 Tags are used to name particular revisions of the repository and are
5416 very useful to compare different revisions, to go back to significant
5419 very useful to compare different revisions, to go back to significant
5417 earlier versions or to mark branch points as releases, etc. Changing
5420 earlier versions or to mark branch points as releases, etc. Changing
5418 an existing tag is normally disallowed; use -f/--force to override.
5421 an existing tag is normally disallowed; use -f/--force to override.
5419
5422
5420 If no revision is given, the parent of the working directory is
5423 If no revision is given, the parent of the working directory is
5421 used, or tip if no revision is checked out.
5424 used, or tip if no revision is checked out.
5422
5425
5423 To facilitate version control, distribution, and merging of tags,
5426 To facilitate version control, distribution, and merging of tags,
5424 they are stored as a file named ".hgtags" which is managed similarly
5427 they are stored as a file named ".hgtags" which is managed similarly
5425 to other project files and can be hand-edited if necessary. This
5428 to other project files and can be hand-edited if necessary. This
5426 also means that tagging creates a new commit. The file
5429 also means that tagging creates a new commit. The file
5427 ".hg/localtags" is used for local tags (not shared among
5430 ".hg/localtags" is used for local tags (not shared among
5428 repositories).
5431 repositories).
5429
5432
5430 Tag commits are usually made at the head of a branch. If the parent
5433 Tag commits are usually made at the head of a branch. If the parent
5431 of the working directory is not a branch head, :hg:`tag` aborts; use
5434 of the working directory is not a branch head, :hg:`tag` aborts; use
5432 -f/--force to force the tag commit to be based on a non-head
5435 -f/--force to force the tag commit to be based on a non-head
5433 changeset.
5436 changeset.
5434
5437
5435 See :hg:`help dates` for a list of formats valid for -d/--date.
5438 See :hg:`help dates` for a list of formats valid for -d/--date.
5436
5439
5437 Since tag names have priority over branch names during revision
5440 Since tag names have priority over branch names during revision
5438 lookup, using an existing branch name as a tag name is discouraged.
5441 lookup, using an existing branch name as a tag name is discouraged.
5439
5442
5440 Returns 0 on success.
5443 Returns 0 on success.
5441 """
5444 """
5442 wlock = lock = None
5445 wlock = lock = None
5443 try:
5446 try:
5444 wlock = repo.wlock()
5447 wlock = repo.wlock()
5445 lock = repo.lock()
5448 lock = repo.lock()
5446 rev_ = "."
5449 rev_ = "."
5447 names = [t.strip() for t in (name1,) + names]
5450 names = [t.strip() for t in (name1,) + names]
5448 if len(names) != len(set(names)):
5451 if len(names) != len(set(names)):
5449 raise util.Abort(_('tag names must be unique'))
5452 raise util.Abort(_('tag names must be unique'))
5450 for n in names:
5453 for n in names:
5451 scmutil.checknewlabel(repo, n, 'tag')
5454 scmutil.checknewlabel(repo, n, 'tag')
5452 if not n:
5455 if not n:
5453 raise util.Abort(_('tag names cannot consist entirely of '
5456 raise util.Abort(_('tag names cannot consist entirely of '
5454 'whitespace'))
5457 'whitespace'))
5455 if opts.get('rev') and opts.get('remove'):
5458 if opts.get('rev') and opts.get('remove'):
5456 raise util.Abort(_("--rev and --remove are incompatible"))
5459 raise util.Abort(_("--rev and --remove are incompatible"))
5457 if opts.get('rev'):
5460 if opts.get('rev'):
5458 rev_ = opts['rev']
5461 rev_ = opts['rev']
5459 message = opts.get('message')
5462 message = opts.get('message')
5460 if opts.get('remove'):
5463 if opts.get('remove'):
5461 expectedtype = opts.get('local') and 'local' or 'global'
5464 expectedtype = opts.get('local') and 'local' or 'global'
5462 for n in names:
5465 for n in names:
5463 if not repo.tagtype(n):
5466 if not repo.tagtype(n):
5464 raise util.Abort(_("tag '%s' does not exist") % n)
5467 raise util.Abort(_("tag '%s' does not exist") % n)
5465 if repo.tagtype(n) != expectedtype:
5468 if repo.tagtype(n) != expectedtype:
5466 if expectedtype == 'global':
5469 if expectedtype == 'global':
5467 raise util.Abort(_("tag '%s' is not a global tag") % n)
5470 raise util.Abort(_("tag '%s' is not a global tag") % n)
5468 else:
5471 else:
5469 raise util.Abort(_("tag '%s' is not a local tag") % n)
5472 raise util.Abort(_("tag '%s' is not a local tag") % n)
5470 rev_ = nullid
5473 rev_ = nullid
5471 if not message:
5474 if not message:
5472 # we don't translate commit messages
5475 # we don't translate commit messages
5473 message = 'Removed tag %s' % ', '.join(names)
5476 message = 'Removed tag %s' % ', '.join(names)
5474 elif not opts.get('force'):
5477 elif not opts.get('force'):
5475 for n in names:
5478 for n in names:
5476 if n in repo.tags():
5479 if n in repo.tags():
5477 raise util.Abort(_("tag '%s' already exists "
5480 raise util.Abort(_("tag '%s' already exists "
5478 "(use -f to force)") % n)
5481 "(use -f to force)") % n)
5479 if not opts.get('local'):
5482 if not opts.get('local'):
5480 p1, p2 = repo.dirstate.parents()
5483 p1, p2 = repo.dirstate.parents()
5481 if p2 != nullid:
5484 if p2 != nullid:
5482 raise util.Abort(_('uncommitted merge'))
5485 raise util.Abort(_('uncommitted merge'))
5483 bheads = repo.branchheads()
5486 bheads = repo.branchheads()
5484 if not opts.get('force') and bheads and p1 not in bheads:
5487 if not opts.get('force') and bheads and p1 not in bheads:
5485 raise util.Abort(_('not at a branch head (use -f to force)'))
5488 raise util.Abort(_('not at a branch head (use -f to force)'))
5486 r = scmutil.revsingle(repo, rev_).node()
5489 r = scmutil.revsingle(repo, rev_).node()
5487
5490
5488 if not message:
5491 if not message:
5489 # we don't translate commit messages
5492 # we don't translate commit messages
5490 message = ('Added tag %s for changeset %s' %
5493 message = ('Added tag %s for changeset %s' %
5491 (', '.join(names), short(r)))
5494 (', '.join(names), short(r)))
5492
5495
5493 date = opts.get('date')
5496 date = opts.get('date')
5494 if date:
5497 if date:
5495 date = util.parsedate(date)
5498 date = util.parsedate(date)
5496
5499
5497 if opts.get('edit'):
5500 if opts.get('edit'):
5498 message = ui.edit(message, ui.username())
5501 message = ui.edit(message, ui.username())
5499
5502
5500 # don't allow tagging the null rev
5503 # don't allow tagging the null rev
5501 if (not opts.get('remove') and
5504 if (not opts.get('remove') and
5502 scmutil.revsingle(repo, rev_).rev() == nullrev):
5505 scmutil.revsingle(repo, rev_).rev() == nullrev):
5503 raise util.Abort(_("null revision specified"))
5506 raise util.Abort(_("null revision specified"))
5504
5507
5505 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5508 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5506 finally:
5509 finally:
5507 release(lock, wlock)
5510 release(lock, wlock)
5508
5511
5509 @command('tags', [], '')
5512 @command('tags', [], '')
5510 def tags(ui, repo, **opts):
5513 def tags(ui, repo, **opts):
5511 """list repository tags
5514 """list repository tags
5512
5515
5513 This lists both regular and local tags. When the -v/--verbose
5516 This lists both regular and local tags. When the -v/--verbose
5514 switch is used, a third column "local" is printed for local tags.
5517 switch is used, a third column "local" is printed for local tags.
5515
5518
5516 Returns 0 on success.
5519 Returns 0 on success.
5517 """
5520 """
5518
5521
5519 fm = ui.formatter('tags', opts)
5522 fm = ui.formatter('tags', opts)
5520 hexfunc = ui.debugflag and hex or short
5523 hexfunc = ui.debugflag and hex or short
5521 tagtype = ""
5524 tagtype = ""
5522
5525
5523 for t, n in reversed(repo.tagslist()):
5526 for t, n in reversed(repo.tagslist()):
5524 hn = hexfunc(n)
5527 hn = hexfunc(n)
5525 label = 'tags.normal'
5528 label = 'tags.normal'
5526 tagtype = ''
5529 tagtype = ''
5527 if repo.tagtype(t) == 'local':
5530 if repo.tagtype(t) == 'local':
5528 label = 'tags.local'
5531 label = 'tags.local'
5529 tagtype = 'local'
5532 tagtype = 'local'
5530
5533
5531 fm.startitem()
5534 fm.startitem()
5532 fm.write('tag', '%s', t, label=label)
5535 fm.write('tag', '%s', t, label=label)
5533 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5536 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5534 fm.condwrite(not ui.quiet, 'rev id', fmt,
5537 fm.condwrite(not ui.quiet, 'rev id', fmt,
5535 repo.changelog.rev(n), hn, label=label)
5538 repo.changelog.rev(n), hn, label=label)
5536 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5539 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5537 tagtype, label=label)
5540 tagtype, label=label)
5538 fm.plain('\n')
5541 fm.plain('\n')
5539 fm.end()
5542 fm.end()
5540
5543
5541 @command('tip',
5544 @command('tip',
5542 [('p', 'patch', None, _('show patch')),
5545 [('p', 'patch', None, _('show patch')),
5543 ('g', 'git', None, _('use git extended diff format')),
5546 ('g', 'git', None, _('use git extended diff format')),
5544 ] + templateopts,
5547 ] + templateopts,
5545 _('[-p] [-g]'))
5548 _('[-p] [-g]'))
5546 def tip(ui, repo, **opts):
5549 def tip(ui, repo, **opts):
5547 """show the tip revision
5550 """show the tip revision
5548
5551
5549 The tip revision (usually just called the tip) is the changeset
5552 The tip revision (usually just called the tip) is the changeset
5550 most recently added to the repository (and therefore the most
5553 most recently added to the repository (and therefore the most
5551 recently changed head).
5554 recently changed head).
5552
5555
5553 If you have just made a commit, that commit will be the tip. If
5556 If you have just made a commit, that commit will be the tip. If
5554 you have just pulled changes from another repository, the tip of
5557 you have just pulled changes from another repository, the tip of
5555 that repository becomes the current tip. The "tip" tag is special
5558 that repository becomes the current tip. The "tip" tag is special
5556 and cannot be renamed or assigned to a different changeset.
5559 and cannot be renamed or assigned to a different changeset.
5557
5560
5558 Returns 0 on success.
5561 Returns 0 on success.
5559 """
5562 """
5560 displayer = cmdutil.show_changeset(ui, repo, opts)
5563 displayer = cmdutil.show_changeset(ui, repo, opts)
5561 displayer.show(repo['tip'])
5564 displayer.show(repo['tip'])
5562 displayer.close()
5565 displayer.close()
5563
5566
5564 @command('unbundle',
5567 @command('unbundle',
5565 [('u', 'update', None,
5568 [('u', 'update', None,
5566 _('update to new branch head if changesets were unbundled'))],
5569 _('update to new branch head if changesets were unbundled'))],
5567 _('[-u] FILE...'))
5570 _('[-u] FILE...'))
5568 def unbundle(ui, repo, fname1, *fnames, **opts):
5571 def unbundle(ui, repo, fname1, *fnames, **opts):
5569 """apply one or more changegroup files
5572 """apply one or more changegroup files
5570
5573
5571 Apply one or more compressed changegroup files generated by the
5574 Apply one or more compressed changegroup files generated by the
5572 bundle command.
5575 bundle command.
5573
5576
5574 Returns 0 on success, 1 if an update has unresolved files.
5577 Returns 0 on success, 1 if an update has unresolved files.
5575 """
5578 """
5576 fnames = (fname1,) + fnames
5579 fnames = (fname1,) + fnames
5577
5580
5578 lock = repo.lock()
5581 lock = repo.lock()
5579 wc = repo['.']
5582 wc = repo['.']
5580 try:
5583 try:
5581 for fname in fnames:
5584 for fname in fnames:
5582 f = hg.openpath(ui, fname)
5585 f = hg.openpath(ui, fname)
5583 gen = changegroup.readbundle(f, fname)
5586 gen = changegroup.readbundle(f, fname)
5584 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5587 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5585 finally:
5588 finally:
5586 lock.release()
5589 lock.release()
5587 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5590 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5588 return postincoming(ui, repo, modheads, opts.get('update'), None)
5591 return postincoming(ui, repo, modheads, opts.get('update'), None)
5589
5592
5590 @command('^update|up|checkout|co',
5593 @command('^update|up|checkout|co',
5591 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5594 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5592 ('c', 'check', None,
5595 ('c', 'check', None,
5593 _('update across branches if no uncommitted changes')),
5596 _('update across branches if no uncommitted changes')),
5594 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5597 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5595 ('r', 'rev', '', _('revision'), _('REV'))],
5598 ('r', 'rev', '', _('revision'), _('REV'))],
5596 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5599 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5597 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5600 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5598 """update working directory (or switch revisions)
5601 """update working directory (or switch revisions)
5599
5602
5600 Update the repository's working directory to the specified
5603 Update the repository's working directory to the specified
5601 changeset. If no changeset is specified, update to the tip of the
5604 changeset. If no changeset is specified, update to the tip of the
5602 current named branch and move the current bookmark (see :hg:`help
5605 current named branch and move the current bookmark (see :hg:`help
5603 bookmarks`).
5606 bookmarks`).
5604
5607
5605 Update sets the working directory's parent revision to the specified
5608 Update sets the working directory's parent revision to the specified
5606 changeset (see :hg:`help parents`).
5609 changeset (see :hg:`help parents`).
5607
5610
5608 If the changeset is not a descendant or ancestor of the working
5611 If the changeset is not a descendant or ancestor of the working
5609 directory's parent, the update is aborted. With the -c/--check
5612 directory's parent, the update is aborted. With the -c/--check
5610 option, the working directory is checked for uncommitted changes; if
5613 option, the working directory is checked for uncommitted changes; if
5611 none are found, the working directory is updated to the specified
5614 none are found, the working directory is updated to the specified
5612 changeset.
5615 changeset.
5613
5616
5614 .. container:: verbose
5617 .. container:: verbose
5615
5618
5616 The following rules apply when the working directory contains
5619 The following rules apply when the working directory contains
5617 uncommitted changes:
5620 uncommitted changes:
5618
5621
5619 1. If neither -c/--check nor -C/--clean is specified, and if
5622 1. If neither -c/--check nor -C/--clean is specified, and if
5620 the requested changeset is an ancestor or descendant of
5623 the requested changeset is an ancestor or descendant of
5621 the working directory's parent, the uncommitted changes
5624 the working directory's parent, the uncommitted changes
5622 are merged into the requested changeset and the merged
5625 are merged into the requested changeset and the merged
5623 result is left uncommitted. If the requested changeset is
5626 result is left uncommitted. If the requested changeset is
5624 not an ancestor or descendant (that is, it is on another
5627 not an ancestor or descendant (that is, it is on another
5625 branch), the update is aborted and the uncommitted changes
5628 branch), the update is aborted and the uncommitted changes
5626 are preserved.
5629 are preserved.
5627
5630
5628 2. With the -c/--check option, the update is aborted and the
5631 2. With the -c/--check option, the update is aborted and the
5629 uncommitted changes are preserved.
5632 uncommitted changes are preserved.
5630
5633
5631 3. With the -C/--clean option, uncommitted changes are discarded and
5634 3. With the -C/--clean option, uncommitted changes are discarded and
5632 the working directory is updated to the requested changeset.
5635 the working directory is updated to the requested changeset.
5633
5636
5634 To cancel an uncommitted merge (and lose your changes), use
5637 To cancel an uncommitted merge (and lose your changes), use
5635 :hg:`update --clean .`.
5638 :hg:`update --clean .`.
5636
5639
5637 Use null as the changeset to remove the working directory (like
5640 Use null as the changeset to remove the working directory (like
5638 :hg:`clone -U`).
5641 :hg:`clone -U`).
5639
5642
5640 If you want to revert just one file to an older revision, use
5643 If you want to revert just one file to an older revision, use
5641 :hg:`revert [-r REV] NAME`.
5644 :hg:`revert [-r REV] NAME`.
5642
5645
5643 See :hg:`help dates` for a list of formats valid for -d/--date.
5646 See :hg:`help dates` for a list of formats valid for -d/--date.
5644
5647
5645 Returns 0 on success, 1 if there are unresolved files.
5648 Returns 0 on success, 1 if there are unresolved files.
5646 """
5649 """
5647 if rev and node:
5650 if rev and node:
5648 raise util.Abort(_("please specify just one revision"))
5651 raise util.Abort(_("please specify just one revision"))
5649
5652
5650 if rev is None or rev == '':
5653 if rev is None or rev == '':
5651 rev = node
5654 rev = node
5652
5655
5653 # with no argument, we also move the current bookmark, if any
5656 # with no argument, we also move the current bookmark, if any
5654 movemarkfrom = None
5657 movemarkfrom = None
5655 if rev is None:
5658 if rev is None:
5656 curmark = repo._bookmarkcurrent
5659 curmark = repo._bookmarkcurrent
5657 if bookmarks.iscurrent(repo):
5660 if bookmarks.iscurrent(repo):
5658 movemarkfrom = repo['.'].node()
5661 movemarkfrom = repo['.'].node()
5659 elif curmark:
5662 elif curmark:
5660 ui.status(_("updating to active bookmark %s\n") % curmark)
5663 ui.status(_("updating to active bookmark %s\n") % curmark)
5661 rev = curmark
5664 rev = curmark
5662
5665
5663 # if we defined a bookmark, we have to remember the original bookmark name
5666 # if we defined a bookmark, we have to remember the original bookmark name
5664 brev = rev
5667 brev = rev
5665 rev = scmutil.revsingle(repo, rev, rev).rev()
5668 rev = scmutil.revsingle(repo, rev, rev).rev()
5666
5669
5667 if check and clean:
5670 if check and clean:
5668 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5671 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5669
5672
5670 if date:
5673 if date:
5671 if rev is not None:
5674 if rev is not None:
5672 raise util.Abort(_("you can't specify a revision and a date"))
5675 raise util.Abort(_("you can't specify a revision and a date"))
5673 rev = cmdutil.finddate(ui, repo, date)
5676 rev = cmdutil.finddate(ui, repo, date)
5674
5677
5675 if check:
5678 if check:
5676 c = repo[None]
5679 c = repo[None]
5677 if c.dirty(merge=False, branch=False, missing=True):
5680 if c.dirty(merge=False, branch=False, missing=True):
5678 raise util.Abort(_("uncommitted local changes"))
5681 raise util.Abort(_("uncommitted local changes"))
5679 if rev is None:
5682 if rev is None:
5680 rev = repo[repo[None].branch()].rev()
5683 rev = repo[repo[None].branch()].rev()
5681 mergemod._checkunknown(repo, repo[None], repo[rev])
5684 mergemod._checkunknown(repo, repo[None], repo[rev])
5682
5685
5683 if clean:
5686 if clean:
5684 ret = hg.clean(repo, rev)
5687 ret = hg.clean(repo, rev)
5685 else:
5688 else:
5686 ret = hg.update(repo, rev)
5689 ret = hg.update(repo, rev)
5687
5690
5688 if not ret and movemarkfrom:
5691 if not ret and movemarkfrom:
5689 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5692 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5690 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5693 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5691 elif brev in repo._bookmarks:
5694 elif brev in repo._bookmarks:
5692 bookmarks.setcurrent(repo, brev)
5695 bookmarks.setcurrent(repo, brev)
5693 elif brev:
5696 elif brev:
5694 bookmarks.unsetcurrent(repo)
5697 bookmarks.unsetcurrent(repo)
5695
5698
5696 return ret
5699 return ret
5697
5700
5698 @command('verify', [])
5701 @command('verify', [])
5699 def verify(ui, repo):
5702 def verify(ui, repo):
5700 """verify the integrity of the repository
5703 """verify the integrity of the repository
5701
5704
5702 Verify the integrity of the current repository.
5705 Verify the integrity of the current repository.
5703
5706
5704 This will perform an extensive check of the repository's
5707 This will perform an extensive check of the repository's
5705 integrity, validating the hashes and checksums of each entry in
5708 integrity, validating the hashes and checksums of each entry in
5706 the changelog, manifest, and tracked files, as well as the
5709 the changelog, manifest, and tracked files, as well as the
5707 integrity of their crosslinks and indices.
5710 integrity of their crosslinks and indices.
5708
5711
5709 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5712 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5710 for more information about recovery from corruption of the
5713 for more information about recovery from corruption of the
5711 repository.
5714 repository.
5712
5715
5713 Returns 0 on success, 1 if errors are encountered.
5716 Returns 0 on success, 1 if errors are encountered.
5714 """
5717 """
5715 return hg.verify(repo)
5718 return hg.verify(repo)
5716
5719
5717 @command('version', [])
5720 @command('version', [])
5718 def version_(ui):
5721 def version_(ui):
5719 """output version and copyright information"""
5722 """output version and copyright information"""
5720 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5723 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5721 % util.version())
5724 % util.version())
5722 ui.status(_(
5725 ui.status(_(
5723 "(see http://mercurial.selenic.com for more information)\n"
5726 "(see http://mercurial.selenic.com for more information)\n"
5724 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5727 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5725 "This is free software; see the source for copying conditions. "
5728 "This is free software; see the source for copying conditions. "
5726 "There is NO\nwarranty; "
5729 "There is NO\nwarranty; "
5727 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5730 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5728 ))
5731 ))
5729
5732
5730 norepo = ("clone init version help debugcommands debugcomplete"
5733 norepo = ("clone init version help debugcommands debugcomplete"
5731 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5734 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5732 " debugknown debuggetbundle debugbundle")
5735 " debugknown debuggetbundle debugbundle")
5733 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5736 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5734 " debugdata debugindex debugindexdot debugrevlog")
5737 " debugdata debugindex debugindexdot debugrevlog")
5735 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5738 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5736 " remove resolve status debugwalk")
5739 " remove resolve status debugwalk")
@@ -1,579 +1,584 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 bookmark rev -1
8 bookmark rev -1
9
9
10 $ hg bookmark X
10 $ hg bookmark X
11
11
12 list bookmarks
12 list bookmarks
13
13
14 $ hg bookmarks
14 $ hg bookmarks
15 * X -1:000000000000
15 * X -1:000000000000
16
16
17 list bookmarks with color
17 list bookmarks with color
18
18
19 $ hg --config extensions.color= --config color.mode=ansi \
19 $ hg --config extensions.color= --config color.mode=ansi \
20 > bookmarks --color=always
20 > bookmarks --color=always
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
22
22
23 $ echo a > a
23 $ echo a > a
24 $ hg add a
24 $ hg add a
25 $ hg commit -m 0
25 $ hg commit -m 0
26
26
27 bookmark X moved to rev 0
27 bookmark X moved to rev 0
28
28
29 $ hg bookmarks
29 $ hg bookmarks
30 * X 0:f7b1eb17ad24
30 * X 0:f7b1eb17ad24
31
31
32 look up bookmark
32 look up bookmark
33
33
34 $ hg log -r X
34 $ hg log -r X
35 changeset: 0:f7b1eb17ad24
35 changeset: 0:f7b1eb17ad24
36 bookmark: X
36 bookmark: X
37 tag: tip
37 tag: tip
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 0
40 summary: 0
41
41
42
42
43 second bookmark for rev 0, command should work even with ui.strict on
43 second bookmark for rev 0, command should work even with ui.strict on
44
44
45 $ hg --config ui.strict=1 bookmark X2
45 $ hg --config ui.strict=1 bookmark X2
46
46
47 bookmark rev -1 again
47 bookmark rev -1 again
48
48
49 $ hg bookmark -r null Y
49 $ hg bookmark -r null Y
50
50
51 list bookmarks
51 list bookmarks
52
52
53 $ hg bookmarks
53 $ hg bookmarks
54 X 0:f7b1eb17ad24
54 X 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
56 Y -1:000000000000
56 Y -1:000000000000
57
57
58 $ echo b > b
58 $ echo b > b
59 $ hg add b
59 $ hg add b
60 $ hg commit -m 1
60 $ hg commit -m 1
61
61
62 bookmarks revset
62 bookmarks revset
63
63
64 $ hg log -r 'bookmark()'
64 $ hg log -r 'bookmark()'
65 changeset: 0:f7b1eb17ad24
65 changeset: 0:f7b1eb17ad24
66 bookmark: X
66 bookmark: X
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:00 1970 +0000
68 date: Thu Jan 01 00:00:00 1970 +0000
69 summary: 0
69 summary: 0
70
70
71 changeset: 1:925d80f479bb
71 changeset: 1:925d80f479bb
72 bookmark: X2
72 bookmark: X2
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: 1
76 summary: 1
77
77
78 $ hg log -r 'bookmark(Y)'
78 $ hg log -r 'bookmark(Y)'
79 $ hg log -r 'bookmark(X2)'
79 $ hg log -r 'bookmark(X2)'
80 changeset: 1:925d80f479bb
80 changeset: 1:925d80f479bb
81 bookmark: X2
81 bookmark: X2
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85 summary: 1
85 summary: 1
86
86
87 $ hg log -r 'bookmark("re:X")'
87 $ hg log -r 'bookmark("re:X")'
88 changeset: 0:f7b1eb17ad24
88 changeset: 0:f7b1eb17ad24
89 bookmark: X
89 bookmark: X
90 user: test
90 user: test
91 date: Thu Jan 01 00:00:00 1970 +0000
91 date: Thu Jan 01 00:00:00 1970 +0000
92 summary: 0
92 summary: 0
93
93
94 changeset: 1:925d80f479bb
94 changeset: 1:925d80f479bb
95 bookmark: X2
95 bookmark: X2
96 tag: tip
96 tag: tip
97 user: test
97 user: test
98 date: Thu Jan 01 00:00:00 1970 +0000
98 date: Thu Jan 01 00:00:00 1970 +0000
99 summary: 1
99 summary: 1
100
100
101 $ hg log -r 'bookmark(unknown)'
101 $ hg log -r 'bookmark(unknown)'
102 abort: bookmark 'unknown' does not exist
102 abort: bookmark 'unknown' does not exist
103 [255]
103 [255]
104
104
105 $ hg help revsets | grep 'bookmark('
105 $ hg help revsets | grep 'bookmark('
106 "bookmark([name])"
106 "bookmark([name])"
107
107
108 bookmarks X and X2 moved to rev 1, Y at rev -1
108 bookmarks X and X2 moved to rev 1, Y at rev -1
109
109
110 $ hg bookmarks
110 $ hg bookmarks
111 X 0:f7b1eb17ad24
111 X 0:f7b1eb17ad24
112 * X2 1:925d80f479bb
112 * X2 1:925d80f479bb
113 Y -1:000000000000
113 Y -1:000000000000
114
114
115 bookmark rev 0 again
115 bookmark rev 0 again
116
116
117 $ hg bookmark -r 0 Z
117 $ hg bookmark -r 0 Z
118
118
119 $ hg update X
119 $ hg update X
120 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
121 $ echo c > c
121 $ echo c > c
122 $ hg add c
122 $ hg add c
123 $ hg commit -m 2
123 $ hg commit -m 2
124 created new head
124 created new head
125
125
126 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
126 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
127
127
128 $ hg bookmarks
128 $ hg bookmarks
129 * X 2:db815d6d32e6
129 * X 2:db815d6d32e6
130 X2 1:925d80f479bb
130 X2 1:925d80f479bb
131 Y -1:000000000000
131 Y -1:000000000000
132 Z 0:f7b1eb17ad24
132 Z 0:f7b1eb17ad24
133
133
134 rename nonexistent bookmark
134 rename nonexistent bookmark
135
135
136 $ hg bookmark -m A B
136 $ hg bookmark -m A B
137 abort: bookmark 'A' does not exist
137 abort: bookmark 'A' does not exist
138 [255]
138 [255]
139
139
140 rename to existent bookmark
140 rename to existent bookmark
141
141
142 $ hg bookmark -m X Y
142 $ hg bookmark -m X Y
143 abort: bookmark 'Y' already exists (use -f to force)
143 abort: bookmark 'Y' already exists (use -f to force)
144 [255]
144 [255]
145
145
146 force rename to existent bookmark
146 force rename to existent bookmark
147
147
148 $ hg bookmark -f -m X Y
148 $ hg bookmark -f -m X Y
149
149
150 list bookmarks
150 list bookmarks
151
151
152 $ hg bookmark
152 $ hg bookmark
153 X2 1:925d80f479bb
153 X2 1:925d80f479bb
154 * Y 2:db815d6d32e6
154 * Y 2:db815d6d32e6
155 Z 0:f7b1eb17ad24
155 Z 0:f7b1eb17ad24
156
156
157 bookmarks from a revset
157 bookmarks from a revset
158 $ hg bookmark -r '.^1' REVSET
158 $ hg bookmark -r '.^1' REVSET
159 $ hg bookmark -r ':tip' TIP
159 $ hg bookmark -r ':tip' TIP
160 $ hg bookmarks
160 $ hg bookmarks
161 REVSET 0:f7b1eb17ad24
161 REVSET 0:f7b1eb17ad24
162 * TIP 2:db815d6d32e6
162 * TIP 2:db815d6d32e6
163 X2 1:925d80f479bb
163 X2 1:925d80f479bb
164 Y 2:db815d6d32e6
164 Y 2:db815d6d32e6
165 Z 0:f7b1eb17ad24
165 Z 0:f7b1eb17ad24
166
166
167 $ hg bookmark -d REVSET
167 $ hg bookmark -d REVSET
168 $ hg bookmark -d TIP
168 $ hg bookmark -d TIP
169
169
170 rename without new name
170 rename without new name
171
171
172 $ hg bookmark -m Y
172 $ hg bookmark -m Y
173 abort: new bookmark name required
173 abort: new bookmark name required
174 [255]
174 [255]
175
175
176 delete without name
176 delete without name
177
177
178 $ hg bookmark -d
178 $ hg bookmark -d
179 abort: bookmark name required
179 abort: bookmark name required
180 [255]
180 [255]
181
181
182 delete nonexistent bookmark
182 delete nonexistent bookmark
183
183
184 $ hg bookmark -d A
184 $ hg bookmark -d A
185 abort: bookmark 'A' does not exist
185 abort: bookmark 'A' does not exist
186 [255]
186 [255]
187
187
188 bookmark name with spaces should be stripped
188 bookmark name with spaces should be stripped
189
189
190 $ hg bookmark ' x y '
190 $ hg bookmark ' x y '
191
191
192 list bookmarks
192 list bookmarks
193
193
194 $ hg bookmarks
194 $ hg bookmarks
195 X2 1:925d80f479bb
195 X2 1:925d80f479bb
196 Y 2:db815d6d32e6
196 Y 2:db815d6d32e6
197 Z 0:f7b1eb17ad24
197 Z 0:f7b1eb17ad24
198 * x y 2:db815d6d32e6
198 * x y 2:db815d6d32e6
199
199
200 look up stripped bookmark name
200 look up stripped bookmark name
201
201
202 $ hg log -r '"x y"'
202 $ hg log -r '"x y"'
203 changeset: 2:db815d6d32e6
203 changeset: 2:db815d6d32e6
204 bookmark: Y
204 bookmark: Y
205 bookmark: x y
205 bookmark: x y
206 tag: tip
206 tag: tip
207 parent: 0:f7b1eb17ad24
207 parent: 0:f7b1eb17ad24
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:00 1970 +0000
209 date: Thu Jan 01 00:00:00 1970 +0000
210 summary: 2
210 summary: 2
211
211
212
212
213 reject bookmark name with newline
213 reject bookmark name with newline
214
214
215 $ hg bookmark '
215 $ hg bookmark '
216 > '
216 > '
217 abort: bookmark names cannot consist entirely of whitespace
217 abort: bookmark names cannot consist entirely of whitespace
218 [255]
218 [255]
219
219
220 $ hg bookmark -m Z '
220 $ hg bookmark -m Z '
221 > '
221 > '
222 abort: bookmark names cannot consist entirely of whitespace
222 abort: bookmark names cannot consist entirely of whitespace
223 [255]
223 [255]
224
224
225 bookmark with reserved name
225 bookmark with reserved name
226
226
227 $ hg bookmark tip
227 $ hg bookmark tip
228 abort: the name 'tip' is reserved
228 abort: the name 'tip' is reserved
229 [255]
229 [255]
230
230
231 $ hg bookmark .
231 $ hg bookmark .
232 abort: the name '.' is reserved
232 abort: the name '.' is reserved
233 [255]
233 [255]
234
234
235 $ hg bookmark null
235 $ hg bookmark null
236 abort: the name 'null' is reserved
236 abort: the name 'null' is reserved
237 [255]
237 [255]
238
238
239
239
240 bookmark with existing name
240 bookmark with existing name
241
241
242 $ hg bookmark X2
242 $ hg bookmark X2
243 abort: bookmark 'X2' already exists (use -f to force)
243 abort: bookmark 'X2' already exists (use -f to force)
244 [255]
244 [255]
245
245
246 $ hg bookmark -m Y Z
246 $ hg bookmark -m Y Z
247 abort: bookmark 'Z' already exists (use -f to force)
247 abort: bookmark 'Z' already exists (use -f to force)
248 [255]
248 [255]
249
249
250 bookmark with name of branch
250 bookmark with name of branch
251
251
252 $ hg bookmark default
252 $ hg bookmark default
253 abort: a bookmark cannot have the name of an existing branch
253 abort: a bookmark cannot have the name of an existing branch
254 [255]
254 [255]
255
255
256 $ hg bookmark -m Y default
256 $ hg bookmark -m Y default
257 abort: a bookmark cannot have the name of an existing branch
257 abort: a bookmark cannot have the name of an existing branch
258 [255]
258 [255]
259
259
260 bookmark with integer name
260 bookmark with integer name
261
261
262 $ hg bookmark 10
262 $ hg bookmark 10
263 abort: a bookmark cannot have an integer as its name
263 abort: a bookmark cannot have an integer as its name
264 [255]
264 [255]
265
265
266 incompatible options
266 incompatible options
267
267
268 $ hg bookmark -m Y -d Z
268 $ hg bookmark -m Y -d Z
269 abort: --delete and --rename are incompatible
269 abort: --delete and --rename are incompatible
270 [255]
270 [255]
271
271
272 $ hg bookmark -r 1 -d Z
272 $ hg bookmark -r 1 -d Z
273 abort: --rev is incompatible with --delete
273 abort: --rev is incompatible with --delete
274 [255]
274 [255]
275
275
276 $ hg bookmark -r 1 -m Z Y
276 $ hg bookmark -r 1 -m Z Y
277 abort: --rev is incompatible with --rename
277 abort: --rev is incompatible with --rename
278 [255]
278 [255]
279
279
280 force bookmark with existing name
280 force bookmark with existing name
281
281
282 $ hg bookmark -f X2
282 $ hg bookmark -f X2
283 $ hg bookmark -fr1 X2
283 $ hg bookmark -fr1 X2
284
284
285 forward bookmark to descendant without --force
285 forward bookmark to descendant without --force
286
286
287 $ hg bookmark Z
287 $ hg bookmark Z
288 moving bookmark 'Z' forward from f7b1eb17ad24
288 moving bookmark 'Z' forward from f7b1eb17ad24
289
289
290 list bookmarks
290 list bookmarks
291
291
292 $ hg bookmark
292 $ hg bookmark
293 X2 1:925d80f479bb
293 X2 1:925d80f479bb
294 Y 2:db815d6d32e6
294 Y 2:db815d6d32e6
295 * Z 2:db815d6d32e6
295 * Z 2:db815d6d32e6
296 x y 2:db815d6d32e6
296 x y 2:db815d6d32e6
297
297
298 revision but no bookmark name
298 revision but no bookmark name
299
299
300 $ hg bookmark -r .
300 $ hg bookmark -r .
301 abort: bookmark name required
301 abort: bookmark name required
302 [255]
302 [255]
303
303
304 bookmark name with whitespace only
304 bookmark name with whitespace only
305
305
306 $ hg bookmark ' '
306 $ hg bookmark ' '
307 abort: bookmark names cannot consist entirely of whitespace
307 abort: bookmark names cannot consist entirely of whitespace
308 [255]
308 [255]
309
309
310 $ hg bookmark -m Y ' '
310 $ hg bookmark -m Y ' '
311 abort: bookmark names cannot consist entirely of whitespace
311 abort: bookmark names cannot consist entirely of whitespace
312 [255]
312 [255]
313
313
314 invalid bookmark
314 invalid bookmark
315
315
316 $ hg bookmark 'foo:bar'
316 $ hg bookmark 'foo:bar'
317 abort: ':' cannot be used in a name
317 abort: ':' cannot be used in a name
318 [255]
318 [255]
319
319
320 $ hg bookmark 'foo
320 $ hg bookmark 'foo
321 > bar'
321 > bar'
322 abort: '\n' cannot be used in a name
322 abort: '\n' cannot be used in a name
323 [255]
323 [255]
324
324
325 the bookmark extension should be ignored now that it is part of core
325 the bookmark extension should be ignored now that it is part of core
326
326
327 $ echo "[extensions]" >> $HGRCPATH
327 $ echo "[extensions]" >> $HGRCPATH
328 $ echo "bookmarks=" >> $HGRCPATH
328 $ echo "bookmarks=" >> $HGRCPATH
329 $ hg bookmarks
329 $ hg bookmarks
330 X2 1:925d80f479bb
330 X2 1:925d80f479bb
331 Y 2:db815d6d32e6
331 Y 2:db815d6d32e6
332 * Z 2:db815d6d32e6
332 * Z 2:db815d6d32e6
333 x y 2:db815d6d32e6
333 x y 2:db815d6d32e6
334
334
335 test summary
335 test summary
336
336
337 $ hg summary
337 $ hg summary
338 parent: 2:db815d6d32e6 tip
338 parent: 2:db815d6d32e6 tip
339 2
339 2
340 branch: default
340 branch: default
341 bookmarks: *Z Y x y
341 bookmarks: *Z Y x y
342 commit: (clean)
342 commit: (clean)
343 update: 1 new changesets, 2 branch heads (merge)
343 update: 1 new changesets, 2 branch heads (merge)
344
344
345 test id
345 test id
346
346
347 $ hg id
347 $ hg id
348 db815d6d32e6 tip Y/Z/x y
348 db815d6d32e6 tip Y/Z/x y
349
349
350 test rollback
350 test rollback
351
351
352 $ echo foo > f1
352 $ echo foo > f1
353 $ hg ci -Amr
353 $ hg ci -Amr
354 adding f1
354 adding f1
355 $ hg bookmark -f Y -r 1
355 $ hg bookmark -f Y -r 1
356 $ hg bookmark -f Z -r 1
356 $ hg bookmark -f Z -r 1
357 $ hg rollback
357 $ hg rollback
358 repository tip rolled back to revision 2 (undo commit)
358 repository tip rolled back to revision 2 (undo commit)
359 working directory now based on revision 2
359 working directory now based on revision 2
360 $ hg bookmarks
360 $ hg bookmarks
361 X2 1:925d80f479bb
361 X2 1:925d80f479bb
362 Y 2:db815d6d32e6
362 Y 2:db815d6d32e6
363 * Z 2:db815d6d32e6
363 * Z 2:db815d6d32e6
364 x y 2:db815d6d32e6
364 x y 2:db815d6d32e6
365
365
366 activate bookmark on working dir parent without --force
367
368 $ hg bookmark --inactive Z
369 $ hg bookmark Z
370
366 test clone
371 test clone
367
372
368 $ hg bookmark -r 2 -i @
373 $ hg bookmark -r 2 -i @
369 $ hg bookmark -r 2 -i a@
374 $ hg bookmark -r 2 -i a@
370 $ hg bookmarks
375 $ hg bookmarks
371 @ 2:db815d6d32e6
376 @ 2:db815d6d32e6
372 X2 1:925d80f479bb
377 X2 1:925d80f479bb
373 Y 2:db815d6d32e6
378 Y 2:db815d6d32e6
374 * Z 2:db815d6d32e6
379 * Z 2:db815d6d32e6
375 a@ 2:db815d6d32e6
380 a@ 2:db815d6d32e6
376 x y 2:db815d6d32e6
381 x y 2:db815d6d32e6
377 $ hg clone . cloned-bookmarks
382 $ hg clone . cloned-bookmarks
378 updating to bookmark @
383 updating to bookmark @
379 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
380 $ hg -R cloned-bookmarks bookmarks
385 $ hg -R cloned-bookmarks bookmarks
381 * @ 2:db815d6d32e6
386 * @ 2:db815d6d32e6
382 X2 1:925d80f479bb
387 X2 1:925d80f479bb
383 Y 2:db815d6d32e6
388 Y 2:db815d6d32e6
384 Z 2:db815d6d32e6
389 Z 2:db815d6d32e6
385 a@ 2:db815d6d32e6
390 a@ 2:db815d6d32e6
386 x y 2:db815d6d32e6
391 x y 2:db815d6d32e6
387
392
388 test clone with pull protocol
393 test clone with pull protocol
389
394
390 $ hg clone --pull . cloned-bookmarks-pull
395 $ hg clone --pull . cloned-bookmarks-pull
391 requesting all changes
396 requesting all changes
392 adding changesets
397 adding changesets
393 adding manifests
398 adding manifests
394 adding file changes
399 adding file changes
395 added 3 changesets with 3 changes to 3 files (+1 heads)
400 added 3 changesets with 3 changes to 3 files (+1 heads)
396 updating to bookmark @
401 updating to bookmark @
397 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 $ hg -R cloned-bookmarks-pull bookmarks
403 $ hg -R cloned-bookmarks-pull bookmarks
399 * @ 2:db815d6d32e6
404 * @ 2:db815d6d32e6
400 X2 1:925d80f479bb
405 X2 1:925d80f479bb
401 Y 2:db815d6d32e6
406 Y 2:db815d6d32e6
402 Z 2:db815d6d32e6
407 Z 2:db815d6d32e6
403 a@ 2:db815d6d32e6
408 a@ 2:db815d6d32e6
404 x y 2:db815d6d32e6
409 x y 2:db815d6d32e6
405
410
406 $ hg bookmark -d @
411 $ hg bookmark -d @
407 $ hg bookmark -d a@
412 $ hg bookmark -d a@
408
413
409 test clone with a bookmark named "default" (issue3677)
414 test clone with a bookmark named "default" (issue3677)
410
415
411 $ hg bookmark -r 1 -f -i default
416 $ hg bookmark -r 1 -f -i default
412 $ hg clone . cloned-bookmark-default
417 $ hg clone . cloned-bookmark-default
413 updating to branch default
418 updating to branch default
414 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
415 $ hg -R cloned-bookmark-default bookmarks
420 $ hg -R cloned-bookmark-default bookmarks
416 X2 1:925d80f479bb
421 X2 1:925d80f479bb
417 Y 2:db815d6d32e6
422 Y 2:db815d6d32e6
418 Z 2:db815d6d32e6
423 Z 2:db815d6d32e6
419 default 1:925d80f479bb
424 default 1:925d80f479bb
420 x y 2:db815d6d32e6
425 x y 2:db815d6d32e6
421 $ hg -R cloned-bookmark-default parents -q
426 $ hg -R cloned-bookmark-default parents -q
422 2:db815d6d32e6
427 2:db815d6d32e6
423 $ hg bookmark -d default
428 $ hg bookmark -d default
424
429
425 test clone with a specific revision
430 test clone with a specific revision
426
431
427 $ hg clone -r 925d80 . cloned-bookmarks-rev
432 $ hg clone -r 925d80 . cloned-bookmarks-rev
428 adding changesets
433 adding changesets
429 adding manifests
434 adding manifests
430 adding file changes
435 adding file changes
431 added 2 changesets with 2 changes to 2 files
436 added 2 changesets with 2 changes to 2 files
432 updating to branch default
437 updating to branch default
433 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
434 $ hg -R cloned-bookmarks-rev bookmarks
439 $ hg -R cloned-bookmarks-rev bookmarks
435 X2 1:925d80f479bb
440 X2 1:925d80f479bb
436
441
437 test clone with update to a bookmark
442 test clone with update to a bookmark
438
443
439 $ hg clone -u Z . cloned-bookmarks-update
444 $ hg clone -u Z . cloned-bookmarks-update
440 updating to branch default
445 updating to branch default
441 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
446 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
442 $ hg -R cloned-bookmarks-update bookmarks
447 $ hg -R cloned-bookmarks-update bookmarks
443 X2 1:925d80f479bb
448 X2 1:925d80f479bb
444 Y 2:db815d6d32e6
449 Y 2:db815d6d32e6
445 * Z 2:db815d6d32e6
450 * Z 2:db815d6d32e6
446 x y 2:db815d6d32e6
451 x y 2:db815d6d32e6
447
452
448 create bundle with two heads
453 create bundle with two heads
449
454
450 $ hg clone . tobundle
455 $ hg clone . tobundle
451 updating to branch default
456 updating to branch default
452 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 $ echo x > tobundle/x
458 $ echo x > tobundle/x
454 $ hg -R tobundle add tobundle/x
459 $ hg -R tobundle add tobundle/x
455 $ hg -R tobundle commit -m'x'
460 $ hg -R tobundle commit -m'x'
456 $ hg -R tobundle update -r -2
461 $ hg -R tobundle update -r -2
457 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
462 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
458 $ echo y > tobundle/y
463 $ echo y > tobundle/y
459 $ hg -R tobundle branch test
464 $ hg -R tobundle branch test
460 marked working directory as branch test
465 marked working directory as branch test
461 (branches are permanent and global, did you want a bookmark?)
466 (branches are permanent and global, did you want a bookmark?)
462 $ hg -R tobundle add tobundle/y
467 $ hg -R tobundle add tobundle/y
463 $ hg -R tobundle commit -m'y'
468 $ hg -R tobundle commit -m'y'
464 $ hg -R tobundle bundle tobundle.hg
469 $ hg -R tobundle bundle tobundle.hg
465 searching for changes
470 searching for changes
466 2 changesets found
471 2 changesets found
467 $ hg unbundle tobundle.hg
472 $ hg unbundle tobundle.hg
468 adding changesets
473 adding changesets
469 adding manifests
474 adding manifests
470 adding file changes
475 adding file changes
471 added 2 changesets with 2 changes to 2 files (+1 heads)
476 added 2 changesets with 2 changes to 2 files (+1 heads)
472 (run 'hg heads' to see heads, 'hg merge' to merge)
477 (run 'hg heads' to see heads, 'hg merge' to merge)
473
478
474 update to current bookmark if it's not the parent
479 update to current bookmark if it's not the parent
475
480
476 $ hg summary
481 $ hg summary
477 parent: 2:db815d6d32e6
482 parent: 2:db815d6d32e6
478 2
483 2
479 branch: default
484 branch: default
480 bookmarks: [Z] Y x y
485 bookmarks: [Z] Y x y
481 commit: 1 added, 1 unknown (new branch head)
486 commit: 1 added, 1 unknown (new branch head)
482 update: 2 new changesets (update)
487 update: 2 new changesets (update)
483 $ hg update
488 $ hg update
484 updating to active bookmark Z
489 updating to active bookmark Z
485 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
490 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 $ hg bookmarks
491 $ hg bookmarks
487 X2 1:925d80f479bb
492 X2 1:925d80f479bb
488 Y 2:db815d6d32e6
493 Y 2:db815d6d32e6
489 * Z 3:125c9a1d6df6
494 * Z 3:125c9a1d6df6
490 x y 2:db815d6d32e6
495 x y 2:db815d6d32e6
491
496
492 test wrongly formated bookmark
497 test wrongly formated bookmark
493
498
494 $ echo '' >> .hg/bookmarks
499 $ echo '' >> .hg/bookmarks
495 $ hg bookmarks
500 $ hg bookmarks
496 X2 1:925d80f479bb
501 X2 1:925d80f479bb
497 Y 2:db815d6d32e6
502 Y 2:db815d6d32e6
498 * Z 3:125c9a1d6df6
503 * Z 3:125c9a1d6df6
499 x y 2:db815d6d32e6
504 x y 2:db815d6d32e6
500 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
505 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
501 $ hg bookmarks
506 $ hg bookmarks
502 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
507 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
503 X2 1:925d80f479bb
508 X2 1:925d80f479bb
504 Y 2:db815d6d32e6
509 Y 2:db815d6d32e6
505 * Z 3:125c9a1d6df6
510 * Z 3:125c9a1d6df6
506 x y 2:db815d6d32e6
511 x y 2:db815d6d32e6
507
512
508 test missing revisions
513 test missing revisions
509
514
510 $ echo "925d80f479bc z" > .hg/bookmarks
515 $ echo "925d80f479bc z" > .hg/bookmarks
511 $ hg book
516 $ hg book
512 no bookmarks set
517 no bookmarks set
513
518
514 test stripping a non-checked-out but bookmarked revision
519 test stripping a non-checked-out but bookmarked revision
515
520
516 $ hg --config extensions.graphlog= log --graph
521 $ hg --config extensions.graphlog= log --graph
517 o changeset: 4:9ba5f110a0b3
522 o changeset: 4:9ba5f110a0b3
518 | branch: test
523 | branch: test
519 | tag: tip
524 | tag: tip
520 | parent: 2:db815d6d32e6
525 | parent: 2:db815d6d32e6
521 | user: test
526 | user: test
522 | date: Thu Jan 01 00:00:00 1970 +0000
527 | date: Thu Jan 01 00:00:00 1970 +0000
523 | summary: y
528 | summary: y
524 |
529 |
525 | @ changeset: 3:125c9a1d6df6
530 | @ changeset: 3:125c9a1d6df6
526 |/ user: test
531 |/ user: test
527 | date: Thu Jan 01 00:00:00 1970 +0000
532 | date: Thu Jan 01 00:00:00 1970 +0000
528 | summary: x
533 | summary: x
529 |
534 |
530 o changeset: 2:db815d6d32e6
535 o changeset: 2:db815d6d32e6
531 | parent: 0:f7b1eb17ad24
536 | parent: 0:f7b1eb17ad24
532 | user: test
537 | user: test
533 | date: Thu Jan 01 00:00:00 1970 +0000
538 | date: Thu Jan 01 00:00:00 1970 +0000
534 | summary: 2
539 | summary: 2
535 |
540 |
536 | o changeset: 1:925d80f479bb
541 | o changeset: 1:925d80f479bb
537 |/ user: test
542 |/ user: test
538 | date: Thu Jan 01 00:00:00 1970 +0000
543 | date: Thu Jan 01 00:00:00 1970 +0000
539 | summary: 1
544 | summary: 1
540 |
545 |
541 o changeset: 0:f7b1eb17ad24
546 o changeset: 0:f7b1eb17ad24
542 user: test
547 user: test
543 date: Thu Jan 01 00:00:00 1970 +0000
548 date: Thu Jan 01 00:00:00 1970 +0000
544 summary: 0
549 summary: 0
545
550
546 $ hg book should-end-on-two
551 $ hg book should-end-on-two
547 $ hg co --clean 4
552 $ hg co --clean 4
548 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
553 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
549 $ hg book four
554 $ hg book four
550 $ hg --config extensions.mq= strip 3
555 $ hg --config extensions.mq= strip 3
551 saved backup bundle to * (glob)
556 saved backup bundle to * (glob)
552 should-end-on-two should end up pointing to revision 2, as that's the
557 should-end-on-two should end up pointing to revision 2, as that's the
553 tipmost surviving ancestor of the stripped revision.
558 tipmost surviving ancestor of the stripped revision.
554 $ hg --config extensions.graphlog= log --graph
559 $ hg --config extensions.graphlog= log --graph
555 @ changeset: 3:9ba5f110a0b3
560 @ changeset: 3:9ba5f110a0b3
556 | branch: test
561 | branch: test
557 | bookmark: four
562 | bookmark: four
558 | tag: tip
563 | tag: tip
559 | user: test
564 | user: test
560 | date: Thu Jan 01 00:00:00 1970 +0000
565 | date: Thu Jan 01 00:00:00 1970 +0000
561 | summary: y
566 | summary: y
562 |
567 |
563 o changeset: 2:db815d6d32e6
568 o changeset: 2:db815d6d32e6
564 | bookmark: should-end-on-two
569 | bookmark: should-end-on-two
565 | parent: 0:f7b1eb17ad24
570 | parent: 0:f7b1eb17ad24
566 | user: test
571 | user: test
567 | date: Thu Jan 01 00:00:00 1970 +0000
572 | date: Thu Jan 01 00:00:00 1970 +0000
568 | summary: 2
573 | summary: 2
569 |
574 |
570 | o changeset: 1:925d80f479bb
575 | o changeset: 1:925d80f479bb
571 |/ user: test
576 |/ user: test
572 | date: Thu Jan 01 00:00:00 1970 +0000
577 | date: Thu Jan 01 00:00:00 1970 +0000
573 | summary: 1
578 | summary: 1
574 |
579 |
575 o changeset: 0:f7b1eb17ad24
580 o changeset: 0:f7b1eb17ad24
576 user: test
581 user: test
577 date: Thu Jan 01 00:00:00 1970 +0000
582 date: Thu Jan 01 00:00:00 1970 +0000
578 summary: 0
583 summary: 0
579
584
General Comments 0
You need to be logged in to leave comments. Login now