##// END OF EJS Templates
debugcommands: move 'debugrevspec' in the new module
Pierre-Yves David -
r30952:85c3c879 default
parent child Browse files
Show More
@@ -1,5743 +1,5649
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import time
14 import time
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 destutil,
30 destutil,
31 dirstateguard,
31 dirstateguard,
32 discovery,
32 discovery,
33 encoding,
33 encoding,
34 error,
34 error,
35 exchange,
35 exchange,
36 extensions,
36 extensions,
37 formatter,
37 formatter,
38 graphmod,
38 graphmod,
39 hbisect,
39 hbisect,
40 help,
40 help,
41 hg,
41 hg,
42 lock as lockmod,
42 lock as lockmod,
43 merge as mergemod,
43 merge as mergemod,
44 minirst,
44 minirst,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 revset,
49 revset,
50 scmutil,
50 scmutil,
51 server,
51 server,
52 smartset,
53 sshserver,
52 sshserver,
54 streamclone,
53 streamclone,
55 templatekw,
54 templatekw,
56 templater,
55 templater,
57 ui as uimod,
56 ui as uimod,
58 util,
57 util,
59 )
58 )
60
59
61 release = lockmod.release
60 release = lockmod.release
62
61
63 table = {}
62 table = {}
64
63
65 command = cmdutil.command(table)
64 command = cmdutil.command(table)
66
65
67 # label constants
66 # label constants
68 # until 3.5, bookmarks.current was the advertised name, not
67 # until 3.5, bookmarks.current was the advertised name, not
69 # bookmarks.active, so we must use both to avoid breaking old
68 # bookmarks.active, so we must use both to avoid breaking old
70 # custom styles
69 # custom styles
71 activebookmarklabel = 'bookmarks.active bookmarks.current'
70 activebookmarklabel = 'bookmarks.active bookmarks.current'
72
71
73 # common command options
72 # common command options
74
73
75 globalopts = [
74 globalopts = [
76 ('R', 'repository', '',
75 ('R', 'repository', '',
77 _('repository root directory or name of overlay bundle file'),
76 _('repository root directory or name of overlay bundle file'),
78 _('REPO')),
77 _('REPO')),
79 ('', 'cwd', '',
78 ('', 'cwd', '',
80 _('change working directory'), _('DIR')),
79 _('change working directory'), _('DIR')),
81 ('y', 'noninteractive', None,
80 ('y', 'noninteractive', None,
82 _('do not prompt, automatically pick the first choice for all prompts')),
81 _('do not prompt, automatically pick the first choice for all prompts')),
83 ('q', 'quiet', None, _('suppress output')),
82 ('q', 'quiet', None, _('suppress output')),
84 ('v', 'verbose', None, _('enable additional output')),
83 ('v', 'verbose', None, _('enable additional output')),
85 ('', 'config', [],
84 ('', 'config', [],
86 _('set/override config option (use \'section.name=value\')'),
85 _('set/override config option (use \'section.name=value\')'),
87 _('CONFIG')),
86 _('CONFIG')),
88 ('', 'debug', None, _('enable debugging output')),
87 ('', 'debug', None, _('enable debugging output')),
89 ('', 'debugger', None, _('start debugger')),
88 ('', 'debugger', None, _('start debugger')),
90 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
89 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
91 _('ENCODE')),
90 _('ENCODE')),
92 ('', 'encodingmode', encoding.encodingmode,
91 ('', 'encodingmode', encoding.encodingmode,
93 _('set the charset encoding mode'), _('MODE')),
92 _('set the charset encoding mode'), _('MODE')),
94 ('', 'traceback', None, _('always print a traceback on exception')),
93 ('', 'traceback', None, _('always print a traceback on exception')),
95 ('', 'time', None, _('time how long the command takes')),
94 ('', 'time', None, _('time how long the command takes')),
96 ('', 'profile', None, _('print command execution profile')),
95 ('', 'profile', None, _('print command execution profile')),
97 ('', 'version', None, _('output version information and exit')),
96 ('', 'version', None, _('output version information and exit')),
98 ('h', 'help', None, _('display help and exit')),
97 ('h', 'help', None, _('display help and exit')),
99 ('', 'hidden', False, _('consider hidden changesets')),
98 ('', 'hidden', False, _('consider hidden changesets')),
100 ]
99 ]
101
100
102 dryrunopts = [('n', 'dry-run', None,
101 dryrunopts = [('n', 'dry-run', None,
103 _('do not perform actions, just print output'))]
102 _('do not perform actions, just print output'))]
104
103
105 remoteopts = [
104 remoteopts = [
106 ('e', 'ssh', '',
105 ('e', 'ssh', '',
107 _('specify ssh command to use'), _('CMD')),
106 _('specify ssh command to use'), _('CMD')),
108 ('', 'remotecmd', '',
107 ('', 'remotecmd', '',
109 _('specify hg command to run on the remote side'), _('CMD')),
108 _('specify hg command to run on the remote side'), _('CMD')),
110 ('', 'insecure', None,
109 ('', 'insecure', None,
111 _('do not verify server certificate (ignoring web.cacerts config)')),
110 _('do not verify server certificate (ignoring web.cacerts config)')),
112 ]
111 ]
113
112
114 walkopts = [
113 walkopts = [
115 ('I', 'include', [],
114 ('I', 'include', [],
116 _('include names matching the given patterns'), _('PATTERN')),
115 _('include names matching the given patterns'), _('PATTERN')),
117 ('X', 'exclude', [],
116 ('X', 'exclude', [],
118 _('exclude names matching the given patterns'), _('PATTERN')),
117 _('exclude names matching the given patterns'), _('PATTERN')),
119 ]
118 ]
120
119
121 commitopts = [
120 commitopts = [
122 ('m', 'message', '',
121 ('m', 'message', '',
123 _('use text as commit message'), _('TEXT')),
122 _('use text as commit message'), _('TEXT')),
124 ('l', 'logfile', '',
123 ('l', 'logfile', '',
125 _('read commit message from file'), _('FILE')),
124 _('read commit message from file'), _('FILE')),
126 ]
125 ]
127
126
128 commitopts2 = [
127 commitopts2 = [
129 ('d', 'date', '',
128 ('d', 'date', '',
130 _('record the specified date as commit date'), _('DATE')),
129 _('record the specified date as commit date'), _('DATE')),
131 ('u', 'user', '',
130 ('u', 'user', '',
132 _('record the specified user as committer'), _('USER')),
131 _('record the specified user as committer'), _('USER')),
133 ]
132 ]
134
133
135 # hidden for now
134 # hidden for now
136 formatteropts = [
135 formatteropts = [
137 ('T', 'template', '',
136 ('T', 'template', '',
138 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
137 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
139 ]
138 ]
140
139
141 templateopts = [
140 templateopts = [
142 ('', 'style', '',
141 ('', 'style', '',
143 _('display using template map file (DEPRECATED)'), _('STYLE')),
142 _('display using template map file (DEPRECATED)'), _('STYLE')),
144 ('T', 'template', '',
143 ('T', 'template', '',
145 _('display with template'), _('TEMPLATE')),
144 _('display with template'), _('TEMPLATE')),
146 ]
145 ]
147
146
148 logopts = [
147 logopts = [
149 ('p', 'patch', None, _('show patch')),
148 ('p', 'patch', None, _('show patch')),
150 ('g', 'git', None, _('use git extended diff format')),
149 ('g', 'git', None, _('use git extended diff format')),
151 ('l', 'limit', '',
150 ('l', 'limit', '',
152 _('limit number of changes displayed'), _('NUM')),
151 _('limit number of changes displayed'), _('NUM')),
153 ('M', 'no-merges', None, _('do not show merges')),
152 ('M', 'no-merges', None, _('do not show merges')),
154 ('', 'stat', None, _('output diffstat-style summary of changes')),
153 ('', 'stat', None, _('output diffstat-style summary of changes')),
155 ('G', 'graph', None, _("show the revision DAG")),
154 ('G', 'graph', None, _("show the revision DAG")),
156 ] + templateopts
155 ] + templateopts
157
156
158 diffopts = [
157 diffopts = [
159 ('a', 'text', None, _('treat all files as text')),
158 ('a', 'text', None, _('treat all files as text')),
160 ('g', 'git', None, _('use git extended diff format')),
159 ('g', 'git', None, _('use git extended diff format')),
161 ('', 'nodates', None, _('omit dates from diff headers'))
160 ('', 'nodates', None, _('omit dates from diff headers'))
162 ]
161 ]
163
162
164 diffwsopts = [
163 diffwsopts = [
165 ('w', 'ignore-all-space', None,
164 ('w', 'ignore-all-space', None,
166 _('ignore white space when comparing lines')),
165 _('ignore white space when comparing lines')),
167 ('b', 'ignore-space-change', None,
166 ('b', 'ignore-space-change', None,
168 _('ignore changes in the amount of white space')),
167 _('ignore changes in the amount of white space')),
169 ('B', 'ignore-blank-lines', None,
168 ('B', 'ignore-blank-lines', None,
170 _('ignore changes whose lines are all blank')),
169 _('ignore changes whose lines are all blank')),
171 ]
170 ]
172
171
173 diffopts2 = [
172 diffopts2 = [
174 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
173 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
175 ('p', 'show-function', None, _('show which function each change is in')),
174 ('p', 'show-function', None, _('show which function each change is in')),
176 ('', 'reverse', None, _('produce a diff that undoes the changes')),
175 ('', 'reverse', None, _('produce a diff that undoes the changes')),
177 ] + diffwsopts + [
176 ] + diffwsopts + [
178 ('U', 'unified', '',
177 ('U', 'unified', '',
179 _('number of lines of context to show'), _('NUM')),
178 _('number of lines of context to show'), _('NUM')),
180 ('', 'stat', None, _('output diffstat-style summary of changes')),
179 ('', 'stat', None, _('output diffstat-style summary of changes')),
181 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
180 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
182 ]
181 ]
183
182
184 mergetoolopts = [
183 mergetoolopts = [
185 ('t', 'tool', '', _('specify merge tool')),
184 ('t', 'tool', '', _('specify merge tool')),
186 ]
185 ]
187
186
188 similarityopts = [
187 similarityopts = [
189 ('s', 'similarity', '',
188 ('s', 'similarity', '',
190 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
189 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
191 ]
190 ]
192
191
193 subrepoopts = [
192 subrepoopts = [
194 ('S', 'subrepos', None,
193 ('S', 'subrepos', None,
195 _('recurse into subrepositories'))
194 _('recurse into subrepositories'))
196 ]
195 ]
197
196
198 debugrevlogopts = [
197 debugrevlogopts = [
199 ('c', 'changelog', False, _('open changelog')),
198 ('c', 'changelog', False, _('open changelog')),
200 ('m', 'manifest', False, _('open manifest')),
199 ('m', 'manifest', False, _('open manifest')),
201 ('', 'dir', '', _('open directory manifest')),
200 ('', 'dir', '', _('open directory manifest')),
202 ]
201 ]
203
202
204 # Commands start here, listed alphabetically
203 # Commands start here, listed alphabetically
205
204
206 @command('^add',
205 @command('^add',
207 walkopts + subrepoopts + dryrunopts,
206 walkopts + subrepoopts + dryrunopts,
208 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
209 inferrepo=True)
208 inferrepo=True)
210 def add(ui, repo, *pats, **opts):
209 def add(ui, repo, *pats, **opts):
211 """add the specified files on the next commit
210 """add the specified files on the next commit
212
211
213 Schedule files to be version controlled and added to the
212 Schedule files to be version controlled and added to the
214 repository.
213 repository.
215
214
216 The files will be added to the repository at the next commit. To
215 The files will be added to the repository at the next commit. To
217 undo an add before that, see :hg:`forget`.
216 undo an add before that, see :hg:`forget`.
218
217
219 If no names are given, add all files to the repository (except
218 If no names are given, add all files to the repository (except
220 files matching ``.hgignore``).
219 files matching ``.hgignore``).
221
220
222 .. container:: verbose
221 .. container:: verbose
223
222
224 Examples:
223 Examples:
225
224
226 - New (unknown) files are added
225 - New (unknown) files are added
227 automatically by :hg:`add`::
226 automatically by :hg:`add`::
228
227
229 $ ls
228 $ ls
230 foo.c
229 foo.c
231 $ hg status
230 $ hg status
232 ? foo.c
231 ? foo.c
233 $ hg add
232 $ hg add
234 adding foo.c
233 adding foo.c
235 $ hg status
234 $ hg status
236 A foo.c
235 A foo.c
237
236
238 - Specific files to be added can be specified::
237 - Specific files to be added can be specified::
239
238
240 $ ls
239 $ ls
241 bar.c foo.c
240 bar.c foo.c
242 $ hg status
241 $ hg status
243 ? bar.c
242 ? bar.c
244 ? foo.c
243 ? foo.c
245 $ hg add bar.c
244 $ hg add bar.c
246 $ hg status
245 $ hg status
247 A bar.c
246 A bar.c
248 ? foo.c
247 ? foo.c
249
248
250 Returns 0 if all files are successfully added.
249 Returns 0 if all files are successfully added.
251 """
250 """
252
251
253 m = scmutil.match(repo[None], pats, opts)
252 m = scmutil.match(repo[None], pats, opts)
254 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
253 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
255 return rejected and 1 or 0
254 return rejected and 1 or 0
256
255
257 @command('addremove',
256 @command('addremove',
258 similarityopts + subrepoopts + walkopts + dryrunopts,
257 similarityopts + subrepoopts + walkopts + dryrunopts,
259 _('[OPTION]... [FILE]...'),
258 _('[OPTION]... [FILE]...'),
260 inferrepo=True)
259 inferrepo=True)
261 def addremove(ui, repo, *pats, **opts):
260 def addremove(ui, repo, *pats, **opts):
262 """add all new files, delete all missing files
261 """add all new files, delete all missing files
263
262
264 Add all new files and remove all missing files from the
263 Add all new files and remove all missing files from the
265 repository.
264 repository.
266
265
267 Unless names are given, new files are ignored if they match any of
266 Unless names are given, new files are ignored if they match any of
268 the patterns in ``.hgignore``. As with add, these changes take
267 the patterns in ``.hgignore``. As with add, these changes take
269 effect at the next commit.
268 effect at the next commit.
270
269
271 Use the -s/--similarity option to detect renamed files. This
270 Use the -s/--similarity option to detect renamed files. This
272 option takes a percentage between 0 (disabled) and 100 (files must
271 option takes a percentage between 0 (disabled) and 100 (files must
273 be identical) as its parameter. With a parameter greater than 0,
272 be identical) as its parameter. With a parameter greater than 0,
274 this compares every removed file with every added file and records
273 this compares every removed file with every added file and records
275 those similar enough as renames. Detecting renamed files this way
274 those similar enough as renames. Detecting renamed files this way
276 can be expensive. After using this option, :hg:`status -C` can be
275 can be expensive. After using this option, :hg:`status -C` can be
277 used to check which files were identified as moved or renamed. If
276 used to check which files were identified as moved or renamed. If
278 not specified, -s/--similarity defaults to 100 and only renames of
277 not specified, -s/--similarity defaults to 100 and only renames of
279 identical files are detected.
278 identical files are detected.
280
279
281 .. container:: verbose
280 .. container:: verbose
282
281
283 Examples:
282 Examples:
284
283
285 - A number of files (bar.c and foo.c) are new,
284 - A number of files (bar.c and foo.c) are new,
286 while foobar.c has been removed (without using :hg:`remove`)
285 while foobar.c has been removed (without using :hg:`remove`)
287 from the repository::
286 from the repository::
288
287
289 $ ls
288 $ ls
290 bar.c foo.c
289 bar.c foo.c
291 $ hg status
290 $ hg status
292 ! foobar.c
291 ! foobar.c
293 ? bar.c
292 ? bar.c
294 ? foo.c
293 ? foo.c
295 $ hg addremove
294 $ hg addremove
296 adding bar.c
295 adding bar.c
297 adding foo.c
296 adding foo.c
298 removing foobar.c
297 removing foobar.c
299 $ hg status
298 $ hg status
300 A bar.c
299 A bar.c
301 A foo.c
300 A foo.c
302 R foobar.c
301 R foobar.c
303
302
304 - A file foobar.c was moved to foo.c without using :hg:`rename`.
303 - A file foobar.c was moved to foo.c without using :hg:`rename`.
305 Afterwards, it was edited slightly::
304 Afterwards, it was edited slightly::
306
305
307 $ ls
306 $ ls
308 foo.c
307 foo.c
309 $ hg status
308 $ hg status
310 ! foobar.c
309 ! foobar.c
311 ? foo.c
310 ? foo.c
312 $ hg addremove --similarity 90
311 $ hg addremove --similarity 90
313 removing foobar.c
312 removing foobar.c
314 adding foo.c
313 adding foo.c
315 recording removal of foobar.c as rename to foo.c (94% similar)
314 recording removal of foobar.c as rename to foo.c (94% similar)
316 $ hg status -C
315 $ hg status -C
317 A foo.c
316 A foo.c
318 foobar.c
317 foobar.c
319 R foobar.c
318 R foobar.c
320
319
321 Returns 0 if all files are successfully added.
320 Returns 0 if all files are successfully added.
322 """
321 """
323 try:
322 try:
324 sim = float(opts.get('similarity') or 100)
323 sim = float(opts.get('similarity') or 100)
325 except ValueError:
324 except ValueError:
326 raise error.Abort(_('similarity must be a number'))
325 raise error.Abort(_('similarity must be a number'))
327 if sim < 0 or sim > 100:
326 if sim < 0 or sim > 100:
328 raise error.Abort(_('similarity must be between 0 and 100'))
327 raise error.Abort(_('similarity must be between 0 and 100'))
329 matcher = scmutil.match(repo[None], pats, opts)
328 matcher = scmutil.match(repo[None], pats, opts)
330 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
329 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
331
330
332 @command('^annotate|blame',
331 @command('^annotate|blame',
333 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
332 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
334 ('', 'follow', None,
333 ('', 'follow', None,
335 _('follow copies/renames and list the filename (DEPRECATED)')),
334 _('follow copies/renames and list the filename (DEPRECATED)')),
336 ('', 'no-follow', None, _("don't follow copies and renames")),
335 ('', 'no-follow', None, _("don't follow copies and renames")),
337 ('a', 'text', None, _('treat all files as text')),
336 ('a', 'text', None, _('treat all files as text')),
338 ('u', 'user', None, _('list the author (long with -v)')),
337 ('u', 'user', None, _('list the author (long with -v)')),
339 ('f', 'file', None, _('list the filename')),
338 ('f', 'file', None, _('list the filename')),
340 ('d', 'date', None, _('list the date (short with -q)')),
339 ('d', 'date', None, _('list the date (short with -q)')),
341 ('n', 'number', None, _('list the revision number (default)')),
340 ('n', 'number', None, _('list the revision number (default)')),
342 ('c', 'changeset', None, _('list the changeset')),
341 ('c', 'changeset', None, _('list the changeset')),
343 ('l', 'line-number', None, _('show line number at the first appearance'))
342 ('l', 'line-number', None, _('show line number at the first appearance'))
344 ] + diffwsopts + walkopts + formatteropts,
343 ] + diffwsopts + walkopts + formatteropts,
345 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
344 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
346 inferrepo=True)
345 inferrepo=True)
347 def annotate(ui, repo, *pats, **opts):
346 def annotate(ui, repo, *pats, **opts):
348 """show changeset information by line for each file
347 """show changeset information by line for each file
349
348
350 List changes in files, showing the revision id responsible for
349 List changes in files, showing the revision id responsible for
351 each line.
350 each line.
352
351
353 This command is useful for discovering when a change was made and
352 This command is useful for discovering when a change was made and
354 by whom.
353 by whom.
355
354
356 If you include --file, --user, or --date, the revision number is
355 If you include --file, --user, or --date, the revision number is
357 suppressed unless you also include --number.
356 suppressed unless you also include --number.
358
357
359 Without the -a/--text option, annotate will avoid processing files
358 Without the -a/--text option, annotate will avoid processing files
360 it detects as binary. With -a, annotate will annotate the file
359 it detects as binary. With -a, annotate will annotate the file
361 anyway, although the results will probably be neither useful
360 anyway, although the results will probably be neither useful
362 nor desirable.
361 nor desirable.
363
362
364 Returns 0 on success.
363 Returns 0 on success.
365 """
364 """
366 if not pats:
365 if not pats:
367 raise error.Abort(_('at least one filename or pattern is required'))
366 raise error.Abort(_('at least one filename or pattern is required'))
368
367
369 if opts.get('follow'):
368 if opts.get('follow'):
370 # --follow is deprecated and now just an alias for -f/--file
369 # --follow is deprecated and now just an alias for -f/--file
371 # to mimic the behavior of Mercurial before version 1.5
370 # to mimic the behavior of Mercurial before version 1.5
372 opts['file'] = True
371 opts['file'] = True
373
372
374 ctx = scmutil.revsingle(repo, opts.get('rev'))
373 ctx = scmutil.revsingle(repo, opts.get('rev'))
375
374
376 fm = ui.formatter('annotate', opts)
375 fm = ui.formatter('annotate', opts)
377 if ui.quiet:
376 if ui.quiet:
378 datefunc = util.shortdate
377 datefunc = util.shortdate
379 else:
378 else:
380 datefunc = util.datestr
379 datefunc = util.datestr
381 if ctx.rev() is None:
380 if ctx.rev() is None:
382 def hexfn(node):
381 def hexfn(node):
383 if node is None:
382 if node is None:
384 return None
383 return None
385 else:
384 else:
386 return fm.hexfunc(node)
385 return fm.hexfunc(node)
387 if opts.get('changeset'):
386 if opts.get('changeset'):
388 # omit "+" suffix which is appended to node hex
387 # omit "+" suffix which is appended to node hex
389 def formatrev(rev):
388 def formatrev(rev):
390 if rev is None:
389 if rev is None:
391 return '%d' % ctx.p1().rev()
390 return '%d' % ctx.p1().rev()
392 else:
391 else:
393 return '%d' % rev
392 return '%d' % rev
394 else:
393 else:
395 def formatrev(rev):
394 def formatrev(rev):
396 if rev is None:
395 if rev is None:
397 return '%d+' % ctx.p1().rev()
396 return '%d+' % ctx.p1().rev()
398 else:
397 else:
399 return '%d ' % rev
398 return '%d ' % rev
400 def formathex(hex):
399 def formathex(hex):
401 if hex is None:
400 if hex is None:
402 return '%s+' % fm.hexfunc(ctx.p1().node())
401 return '%s+' % fm.hexfunc(ctx.p1().node())
403 else:
402 else:
404 return '%s ' % hex
403 return '%s ' % hex
405 else:
404 else:
406 hexfn = fm.hexfunc
405 hexfn = fm.hexfunc
407 formatrev = formathex = str
406 formatrev = formathex = str
408
407
409 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
408 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
410 ('number', ' ', lambda x: x[0].rev(), formatrev),
409 ('number', ' ', lambda x: x[0].rev(), formatrev),
411 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
410 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
412 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
411 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
413 ('file', ' ', lambda x: x[0].path(), str),
412 ('file', ' ', lambda x: x[0].path(), str),
414 ('line_number', ':', lambda x: x[1], str),
413 ('line_number', ':', lambda x: x[1], str),
415 ]
414 ]
416 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
415 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
417
416
418 if (not opts.get('user') and not opts.get('changeset')
417 if (not opts.get('user') and not opts.get('changeset')
419 and not opts.get('date') and not opts.get('file')):
418 and not opts.get('date') and not opts.get('file')):
420 opts['number'] = True
419 opts['number'] = True
421
420
422 linenumber = opts.get('line_number') is not None
421 linenumber = opts.get('line_number') is not None
423 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
422 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
424 raise error.Abort(_('at least one of -n/-c is required for -l'))
423 raise error.Abort(_('at least one of -n/-c is required for -l'))
425
424
426 if fm.isplain():
425 if fm.isplain():
427 def makefunc(get, fmt):
426 def makefunc(get, fmt):
428 return lambda x: fmt(get(x))
427 return lambda x: fmt(get(x))
429 else:
428 else:
430 def makefunc(get, fmt):
429 def makefunc(get, fmt):
431 return get
430 return get
432 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
431 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
433 if opts.get(op)]
432 if opts.get(op)]
434 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
433 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
435 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
434 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
436 if opts.get(op))
435 if opts.get(op))
437
436
438 def bad(x, y):
437 def bad(x, y):
439 raise error.Abort("%s: %s" % (x, y))
438 raise error.Abort("%s: %s" % (x, y))
440
439
441 m = scmutil.match(ctx, pats, opts, badfn=bad)
440 m = scmutil.match(ctx, pats, opts, badfn=bad)
442
441
443 follow = not opts.get('no_follow')
442 follow = not opts.get('no_follow')
444 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
443 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
445 whitespace=True)
444 whitespace=True)
446 for abs in ctx.walk(m):
445 for abs in ctx.walk(m):
447 fctx = ctx[abs]
446 fctx = ctx[abs]
448 if not opts.get('text') and util.binary(fctx.data()):
447 if not opts.get('text') and util.binary(fctx.data()):
449 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
448 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
450 continue
449 continue
451
450
452 lines = fctx.annotate(follow=follow, linenumber=linenumber,
451 lines = fctx.annotate(follow=follow, linenumber=linenumber,
453 diffopts=diffopts)
452 diffopts=diffopts)
454 if not lines:
453 if not lines:
455 continue
454 continue
456 formats = []
455 formats = []
457 pieces = []
456 pieces = []
458
457
459 for f, sep in funcmap:
458 for f, sep in funcmap:
460 l = [f(n) for n, dummy in lines]
459 l = [f(n) for n, dummy in lines]
461 if fm.isplain():
460 if fm.isplain():
462 sizes = [encoding.colwidth(x) for x in l]
461 sizes = [encoding.colwidth(x) for x in l]
463 ml = max(sizes)
462 ml = max(sizes)
464 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
463 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
465 else:
464 else:
466 formats.append(['%s' for x in l])
465 formats.append(['%s' for x in l])
467 pieces.append(l)
466 pieces.append(l)
468
467
469 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
468 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
470 fm.startitem()
469 fm.startitem()
471 fm.write(fields, "".join(f), *p)
470 fm.write(fields, "".join(f), *p)
472 fm.write('line', ": %s", l[1])
471 fm.write('line', ": %s", l[1])
473
472
474 if not lines[-1][1].endswith('\n'):
473 if not lines[-1][1].endswith('\n'):
475 fm.plain('\n')
474 fm.plain('\n')
476
475
477 fm.end()
476 fm.end()
478
477
479 @command('archive',
478 @command('archive',
480 [('', 'no-decode', None, _('do not pass files through decoders')),
479 [('', 'no-decode', None, _('do not pass files through decoders')),
481 ('p', 'prefix', '', _('directory prefix for files in archive'),
480 ('p', 'prefix', '', _('directory prefix for files in archive'),
482 _('PREFIX')),
481 _('PREFIX')),
483 ('r', 'rev', '', _('revision to distribute'), _('REV')),
482 ('r', 'rev', '', _('revision to distribute'), _('REV')),
484 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
483 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
485 ] + subrepoopts + walkopts,
484 ] + subrepoopts + walkopts,
486 _('[OPTION]... DEST'))
485 _('[OPTION]... DEST'))
487 def archive(ui, repo, dest, **opts):
486 def archive(ui, repo, dest, **opts):
488 '''create an unversioned archive of a repository revision
487 '''create an unversioned archive of a repository revision
489
488
490 By default, the revision used is the parent of the working
489 By default, the revision used is the parent of the working
491 directory; use -r/--rev to specify a different revision.
490 directory; use -r/--rev to specify a different revision.
492
491
493 The archive type is automatically detected based on file
492 The archive type is automatically detected based on file
494 extension (to override, use -t/--type).
493 extension (to override, use -t/--type).
495
494
496 .. container:: verbose
495 .. container:: verbose
497
496
498 Examples:
497 Examples:
499
498
500 - create a zip file containing the 1.0 release::
499 - create a zip file containing the 1.0 release::
501
500
502 hg archive -r 1.0 project-1.0.zip
501 hg archive -r 1.0 project-1.0.zip
503
502
504 - create a tarball excluding .hg files::
503 - create a tarball excluding .hg files::
505
504
506 hg archive project.tar.gz -X ".hg*"
505 hg archive project.tar.gz -X ".hg*"
507
506
508 Valid types are:
507 Valid types are:
509
508
510 :``files``: a directory full of files (default)
509 :``files``: a directory full of files (default)
511 :``tar``: tar archive, uncompressed
510 :``tar``: tar archive, uncompressed
512 :``tbz2``: tar archive, compressed using bzip2
511 :``tbz2``: tar archive, compressed using bzip2
513 :``tgz``: tar archive, compressed using gzip
512 :``tgz``: tar archive, compressed using gzip
514 :``uzip``: zip archive, uncompressed
513 :``uzip``: zip archive, uncompressed
515 :``zip``: zip archive, compressed using deflate
514 :``zip``: zip archive, compressed using deflate
516
515
517 The exact name of the destination archive or directory is given
516 The exact name of the destination archive or directory is given
518 using a format string; see :hg:`help export` for details.
517 using a format string; see :hg:`help export` for details.
519
518
520 Each member added to an archive file has a directory prefix
519 Each member added to an archive file has a directory prefix
521 prepended. Use -p/--prefix to specify a format string for the
520 prepended. Use -p/--prefix to specify a format string for the
522 prefix. The default is the basename of the archive, with suffixes
521 prefix. The default is the basename of the archive, with suffixes
523 removed.
522 removed.
524
523
525 Returns 0 on success.
524 Returns 0 on success.
526 '''
525 '''
527
526
528 ctx = scmutil.revsingle(repo, opts.get('rev'))
527 ctx = scmutil.revsingle(repo, opts.get('rev'))
529 if not ctx:
528 if not ctx:
530 raise error.Abort(_('no working directory: please specify a revision'))
529 raise error.Abort(_('no working directory: please specify a revision'))
531 node = ctx.node()
530 node = ctx.node()
532 dest = cmdutil.makefilename(repo, dest, node)
531 dest = cmdutil.makefilename(repo, dest, node)
533 if os.path.realpath(dest) == repo.root:
532 if os.path.realpath(dest) == repo.root:
534 raise error.Abort(_('repository root cannot be destination'))
533 raise error.Abort(_('repository root cannot be destination'))
535
534
536 kind = opts.get('type') or archival.guesskind(dest) or 'files'
535 kind = opts.get('type') or archival.guesskind(dest) or 'files'
537 prefix = opts.get('prefix')
536 prefix = opts.get('prefix')
538
537
539 if dest == '-':
538 if dest == '-':
540 if kind == 'files':
539 if kind == 'files':
541 raise error.Abort(_('cannot archive plain files to stdout'))
540 raise error.Abort(_('cannot archive plain files to stdout'))
542 dest = cmdutil.makefileobj(repo, dest)
541 dest = cmdutil.makefileobj(repo, dest)
543 if not prefix:
542 if not prefix:
544 prefix = os.path.basename(repo.root) + '-%h'
543 prefix = os.path.basename(repo.root) + '-%h'
545
544
546 prefix = cmdutil.makefilename(repo, prefix, node)
545 prefix = cmdutil.makefilename(repo, prefix, node)
547 matchfn = scmutil.match(ctx, [], opts)
546 matchfn = scmutil.match(ctx, [], opts)
548 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
547 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
549 matchfn, prefix, subrepos=opts.get('subrepos'))
548 matchfn, prefix, subrepos=opts.get('subrepos'))
550
549
551 @command('backout',
550 @command('backout',
552 [('', 'merge', None, _('merge with old dirstate parent after backout')),
551 [('', 'merge', None, _('merge with old dirstate parent after backout')),
553 ('', 'commit', None,
552 ('', 'commit', None,
554 _('commit if no conflicts were encountered (DEPRECATED)')),
553 _('commit if no conflicts were encountered (DEPRECATED)')),
555 ('', 'no-commit', None, _('do not commit')),
554 ('', 'no-commit', None, _('do not commit')),
556 ('', 'parent', '',
555 ('', 'parent', '',
557 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
556 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
558 ('r', 'rev', '', _('revision to backout'), _('REV')),
557 ('r', 'rev', '', _('revision to backout'), _('REV')),
559 ('e', 'edit', False, _('invoke editor on commit messages')),
558 ('e', 'edit', False, _('invoke editor on commit messages')),
560 ] + mergetoolopts + walkopts + commitopts + commitopts2,
559 ] + mergetoolopts + walkopts + commitopts + commitopts2,
561 _('[OPTION]... [-r] REV'))
560 _('[OPTION]... [-r] REV'))
562 def backout(ui, repo, node=None, rev=None, **opts):
561 def backout(ui, repo, node=None, rev=None, **opts):
563 '''reverse effect of earlier changeset
562 '''reverse effect of earlier changeset
564
563
565 Prepare a new changeset with the effect of REV undone in the
564 Prepare a new changeset with the effect of REV undone in the
566 current working directory. If no conflicts were encountered,
565 current working directory. If no conflicts were encountered,
567 it will be committed immediately.
566 it will be committed immediately.
568
567
569 If REV is the parent of the working directory, then this new changeset
568 If REV is the parent of the working directory, then this new changeset
570 is committed automatically (unless --no-commit is specified).
569 is committed automatically (unless --no-commit is specified).
571
570
572 .. note::
571 .. note::
573
572
574 :hg:`backout` cannot be used to fix either an unwanted or
573 :hg:`backout` cannot be used to fix either an unwanted or
575 incorrect merge.
574 incorrect merge.
576
575
577 .. container:: verbose
576 .. container:: verbose
578
577
579 Examples:
578 Examples:
580
579
581 - Reverse the effect of the parent of the working directory.
580 - Reverse the effect of the parent of the working directory.
582 This backout will be committed immediately::
581 This backout will be committed immediately::
583
582
584 hg backout -r .
583 hg backout -r .
585
584
586 - Reverse the effect of previous bad revision 23::
585 - Reverse the effect of previous bad revision 23::
587
586
588 hg backout -r 23
587 hg backout -r 23
589
588
590 - Reverse the effect of previous bad revision 23 and
589 - Reverse the effect of previous bad revision 23 and
591 leave changes uncommitted::
590 leave changes uncommitted::
592
591
593 hg backout -r 23 --no-commit
592 hg backout -r 23 --no-commit
594 hg commit -m "Backout revision 23"
593 hg commit -m "Backout revision 23"
595
594
596 By default, the pending changeset will have one parent,
595 By default, the pending changeset will have one parent,
597 maintaining a linear history. With --merge, the pending
596 maintaining a linear history. With --merge, the pending
598 changeset will instead have two parents: the old parent of the
597 changeset will instead have two parents: the old parent of the
599 working directory and a new child of REV that simply undoes REV.
598 working directory and a new child of REV that simply undoes REV.
600
599
601 Before version 1.7, the behavior without --merge was equivalent
600 Before version 1.7, the behavior without --merge was equivalent
602 to specifying --merge followed by :hg:`update --clean .` to
601 to specifying --merge followed by :hg:`update --clean .` to
603 cancel the merge and leave the child of REV as a head to be
602 cancel the merge and leave the child of REV as a head to be
604 merged separately.
603 merged separately.
605
604
606 See :hg:`help dates` for a list of formats valid for -d/--date.
605 See :hg:`help dates` for a list of formats valid for -d/--date.
607
606
608 See :hg:`help revert` for a way to restore files to the state
607 See :hg:`help revert` for a way to restore files to the state
609 of another revision.
608 of another revision.
610
609
611 Returns 0 on success, 1 if nothing to backout or there are unresolved
610 Returns 0 on success, 1 if nothing to backout or there are unresolved
612 files.
611 files.
613 '''
612 '''
614 wlock = lock = None
613 wlock = lock = None
615 try:
614 try:
616 wlock = repo.wlock()
615 wlock = repo.wlock()
617 lock = repo.lock()
616 lock = repo.lock()
618 return _dobackout(ui, repo, node, rev, **opts)
617 return _dobackout(ui, repo, node, rev, **opts)
619 finally:
618 finally:
620 release(lock, wlock)
619 release(lock, wlock)
621
620
622 def _dobackout(ui, repo, node=None, rev=None, **opts):
621 def _dobackout(ui, repo, node=None, rev=None, **opts):
623 if opts.get('commit') and opts.get('no_commit'):
622 if opts.get('commit') and opts.get('no_commit'):
624 raise error.Abort(_("cannot use --commit with --no-commit"))
623 raise error.Abort(_("cannot use --commit with --no-commit"))
625 if opts.get('merge') and opts.get('no_commit'):
624 if opts.get('merge') and opts.get('no_commit'):
626 raise error.Abort(_("cannot use --merge with --no-commit"))
625 raise error.Abort(_("cannot use --merge with --no-commit"))
627
626
628 if rev and node:
627 if rev and node:
629 raise error.Abort(_("please specify just one revision"))
628 raise error.Abort(_("please specify just one revision"))
630
629
631 if not rev:
630 if not rev:
632 rev = node
631 rev = node
633
632
634 if not rev:
633 if not rev:
635 raise error.Abort(_("please specify a revision to backout"))
634 raise error.Abort(_("please specify a revision to backout"))
636
635
637 date = opts.get('date')
636 date = opts.get('date')
638 if date:
637 if date:
639 opts['date'] = util.parsedate(date)
638 opts['date'] = util.parsedate(date)
640
639
641 cmdutil.checkunfinished(repo)
640 cmdutil.checkunfinished(repo)
642 cmdutil.bailifchanged(repo)
641 cmdutil.bailifchanged(repo)
643 node = scmutil.revsingle(repo, rev).node()
642 node = scmutil.revsingle(repo, rev).node()
644
643
645 op1, op2 = repo.dirstate.parents()
644 op1, op2 = repo.dirstate.parents()
646 if not repo.changelog.isancestor(node, op1):
645 if not repo.changelog.isancestor(node, op1):
647 raise error.Abort(_('cannot backout change that is not an ancestor'))
646 raise error.Abort(_('cannot backout change that is not an ancestor'))
648
647
649 p1, p2 = repo.changelog.parents(node)
648 p1, p2 = repo.changelog.parents(node)
650 if p1 == nullid:
649 if p1 == nullid:
651 raise error.Abort(_('cannot backout a change with no parents'))
650 raise error.Abort(_('cannot backout a change with no parents'))
652 if p2 != nullid:
651 if p2 != nullid:
653 if not opts.get('parent'):
652 if not opts.get('parent'):
654 raise error.Abort(_('cannot backout a merge changeset'))
653 raise error.Abort(_('cannot backout a merge changeset'))
655 p = repo.lookup(opts['parent'])
654 p = repo.lookup(opts['parent'])
656 if p not in (p1, p2):
655 if p not in (p1, p2):
657 raise error.Abort(_('%s is not a parent of %s') %
656 raise error.Abort(_('%s is not a parent of %s') %
658 (short(p), short(node)))
657 (short(p), short(node)))
659 parent = p
658 parent = p
660 else:
659 else:
661 if opts.get('parent'):
660 if opts.get('parent'):
662 raise error.Abort(_('cannot use --parent on non-merge changeset'))
661 raise error.Abort(_('cannot use --parent on non-merge changeset'))
663 parent = p1
662 parent = p1
664
663
665 # the backout should appear on the same branch
664 # the backout should appear on the same branch
666 branch = repo.dirstate.branch()
665 branch = repo.dirstate.branch()
667 bheads = repo.branchheads(branch)
666 bheads = repo.branchheads(branch)
668 rctx = scmutil.revsingle(repo, hex(parent))
667 rctx = scmutil.revsingle(repo, hex(parent))
669 if not opts.get('merge') and op1 != node:
668 if not opts.get('merge') and op1 != node:
670 dsguard = dirstateguard.dirstateguard(repo, 'backout')
669 dsguard = dirstateguard.dirstateguard(repo, 'backout')
671 try:
670 try:
672 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
673 'backout')
672 'backout')
674 stats = mergemod.update(repo, parent, True, True, node, False)
673 stats = mergemod.update(repo, parent, True, True, node, False)
675 repo.setparents(op1, op2)
674 repo.setparents(op1, op2)
676 dsguard.close()
675 dsguard.close()
677 hg._showstats(repo, stats)
676 hg._showstats(repo, stats)
678 if stats[3]:
677 if stats[3]:
679 repo.ui.status(_("use 'hg resolve' to retry unresolved "
678 repo.ui.status(_("use 'hg resolve' to retry unresolved "
680 "file merges\n"))
679 "file merges\n"))
681 return 1
680 return 1
682 finally:
681 finally:
683 ui.setconfig('ui', 'forcemerge', '', '')
682 ui.setconfig('ui', 'forcemerge', '', '')
684 lockmod.release(dsguard)
683 lockmod.release(dsguard)
685 else:
684 else:
686 hg.clean(repo, node, show_stats=False)
685 hg.clean(repo, node, show_stats=False)
687 repo.dirstate.setbranch(branch)
686 repo.dirstate.setbranch(branch)
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
687 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
689
688
690 if opts.get('no_commit'):
689 if opts.get('no_commit'):
691 msg = _("changeset %s backed out, "
690 msg = _("changeset %s backed out, "
692 "don't forget to commit.\n")
691 "don't forget to commit.\n")
693 ui.status(msg % short(node))
692 ui.status(msg % short(node))
694 return 0
693 return 0
695
694
696 def commitfunc(ui, repo, message, match, opts):
695 def commitfunc(ui, repo, message, match, opts):
697 editform = 'backout'
696 editform = 'backout'
698 e = cmdutil.getcommiteditor(editform=editform, **opts)
697 e = cmdutil.getcommiteditor(editform=editform, **opts)
699 if not message:
698 if not message:
700 # we don't translate commit messages
699 # we don't translate commit messages
701 message = "Backed out changeset %s" % short(node)
700 message = "Backed out changeset %s" % short(node)
702 e = cmdutil.getcommiteditor(edit=True, editform=editform)
701 e = cmdutil.getcommiteditor(edit=True, editform=editform)
703 return repo.commit(message, opts.get('user'), opts.get('date'),
702 return repo.commit(message, opts.get('user'), opts.get('date'),
704 match, editor=e)
703 match, editor=e)
705 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
704 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
706 if not newnode:
705 if not newnode:
707 ui.status(_("nothing changed\n"))
706 ui.status(_("nothing changed\n"))
708 return 1
707 return 1
709 cmdutil.commitstatus(repo, newnode, branch, bheads)
708 cmdutil.commitstatus(repo, newnode, branch, bheads)
710
709
711 def nice(node):
710 def nice(node):
712 return '%d:%s' % (repo.changelog.rev(node), short(node))
711 return '%d:%s' % (repo.changelog.rev(node), short(node))
713 ui.status(_('changeset %s backs out changeset %s\n') %
712 ui.status(_('changeset %s backs out changeset %s\n') %
714 (nice(repo.changelog.tip()), nice(node)))
713 (nice(repo.changelog.tip()), nice(node)))
715 if opts.get('merge') and op1 != node:
714 if opts.get('merge') and op1 != node:
716 hg.clean(repo, op1, show_stats=False)
715 hg.clean(repo, op1, show_stats=False)
717 ui.status(_('merging with changeset %s\n')
716 ui.status(_('merging with changeset %s\n')
718 % nice(repo.changelog.tip()))
717 % nice(repo.changelog.tip()))
719 try:
718 try:
720 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
719 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
721 'backout')
720 'backout')
722 return hg.merge(repo, hex(repo.changelog.tip()))
721 return hg.merge(repo, hex(repo.changelog.tip()))
723 finally:
722 finally:
724 ui.setconfig('ui', 'forcemerge', '', '')
723 ui.setconfig('ui', 'forcemerge', '', '')
725 return 0
724 return 0
726
725
727 @command('bisect',
726 @command('bisect',
728 [('r', 'reset', False, _('reset bisect state')),
727 [('r', 'reset', False, _('reset bisect state')),
729 ('g', 'good', False, _('mark changeset good')),
728 ('g', 'good', False, _('mark changeset good')),
730 ('b', 'bad', False, _('mark changeset bad')),
729 ('b', 'bad', False, _('mark changeset bad')),
731 ('s', 'skip', False, _('skip testing changeset')),
730 ('s', 'skip', False, _('skip testing changeset')),
732 ('e', 'extend', False, _('extend the bisect range')),
731 ('e', 'extend', False, _('extend the bisect range')),
733 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
732 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
734 ('U', 'noupdate', False, _('do not update to target'))],
733 ('U', 'noupdate', False, _('do not update to target'))],
735 _("[-gbsr] [-U] [-c CMD] [REV]"))
734 _("[-gbsr] [-U] [-c CMD] [REV]"))
736 def bisect(ui, repo, rev=None, extra=None, command=None,
735 def bisect(ui, repo, rev=None, extra=None, command=None,
737 reset=None, good=None, bad=None, skip=None, extend=None,
736 reset=None, good=None, bad=None, skip=None, extend=None,
738 noupdate=None):
737 noupdate=None):
739 """subdivision search of changesets
738 """subdivision search of changesets
740
739
741 This command helps to find changesets which introduce problems. To
740 This command helps to find changesets which introduce problems. To
742 use, mark the earliest changeset you know exhibits the problem as
741 use, mark the earliest changeset you know exhibits the problem as
743 bad, then mark the latest changeset which is free from the problem
742 bad, then mark the latest changeset which is free from the problem
744 as good. Bisect will update your working directory to a revision
743 as good. Bisect will update your working directory to a revision
745 for testing (unless the -U/--noupdate option is specified). Once
744 for testing (unless the -U/--noupdate option is specified). Once
746 you have performed tests, mark the working directory as good or
745 you have performed tests, mark the working directory as good or
747 bad, and bisect will either update to another candidate changeset
746 bad, and bisect will either update to another candidate changeset
748 or announce that it has found the bad revision.
747 or announce that it has found the bad revision.
749
748
750 As a shortcut, you can also use the revision argument to mark a
749 As a shortcut, you can also use the revision argument to mark a
751 revision as good or bad without checking it out first.
750 revision as good or bad without checking it out first.
752
751
753 If you supply a command, it will be used for automatic bisection.
752 If you supply a command, it will be used for automatic bisection.
754 The environment variable HG_NODE will contain the ID of the
753 The environment variable HG_NODE will contain the ID of the
755 changeset being tested. The exit status of the command will be
754 changeset being tested. The exit status of the command will be
756 used to mark revisions as good or bad: status 0 means good, 125
755 used to mark revisions as good or bad: status 0 means good, 125
757 means to skip the revision, 127 (command not found) will abort the
756 means to skip the revision, 127 (command not found) will abort the
758 bisection, and any other non-zero exit status means the revision
757 bisection, and any other non-zero exit status means the revision
759 is bad.
758 is bad.
760
759
761 .. container:: verbose
760 .. container:: verbose
762
761
763 Some examples:
762 Some examples:
764
763
765 - start a bisection with known bad revision 34, and good revision 12::
764 - start a bisection with known bad revision 34, and good revision 12::
766
765
767 hg bisect --bad 34
766 hg bisect --bad 34
768 hg bisect --good 12
767 hg bisect --good 12
769
768
770 - advance the current bisection by marking current revision as good or
769 - advance the current bisection by marking current revision as good or
771 bad::
770 bad::
772
771
773 hg bisect --good
772 hg bisect --good
774 hg bisect --bad
773 hg bisect --bad
775
774
776 - mark the current revision, or a known revision, to be skipped (e.g. if
775 - mark the current revision, or a known revision, to be skipped (e.g. if
777 that revision is not usable because of another issue)::
776 that revision is not usable because of another issue)::
778
777
779 hg bisect --skip
778 hg bisect --skip
780 hg bisect --skip 23
779 hg bisect --skip 23
781
780
782 - skip all revisions that do not touch directories ``foo`` or ``bar``::
781 - skip all revisions that do not touch directories ``foo`` or ``bar``::
783
782
784 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
783 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
785
784
786 - forget the current bisection::
785 - forget the current bisection::
787
786
788 hg bisect --reset
787 hg bisect --reset
789
788
790 - use 'make && make tests' to automatically find the first broken
789 - use 'make && make tests' to automatically find the first broken
791 revision::
790 revision::
792
791
793 hg bisect --reset
792 hg bisect --reset
794 hg bisect --bad 34
793 hg bisect --bad 34
795 hg bisect --good 12
794 hg bisect --good 12
796 hg bisect --command "make && make tests"
795 hg bisect --command "make && make tests"
797
796
798 - see all changesets whose states are already known in the current
797 - see all changesets whose states are already known in the current
799 bisection::
798 bisection::
800
799
801 hg log -r "bisect(pruned)"
800 hg log -r "bisect(pruned)"
802
801
803 - see the changeset currently being bisected (especially useful
802 - see the changeset currently being bisected (especially useful
804 if running with -U/--noupdate)::
803 if running with -U/--noupdate)::
805
804
806 hg log -r "bisect(current)"
805 hg log -r "bisect(current)"
807
806
808 - see all changesets that took part in the current bisection::
807 - see all changesets that took part in the current bisection::
809
808
810 hg log -r "bisect(range)"
809 hg log -r "bisect(range)"
811
810
812 - you can even get a nice graph::
811 - you can even get a nice graph::
813
812
814 hg log --graph -r "bisect(range)"
813 hg log --graph -r "bisect(range)"
815
814
816 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
815 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
817
816
818 Returns 0 on success.
817 Returns 0 on success.
819 """
818 """
820 # backward compatibility
819 # backward compatibility
821 if rev in "good bad reset init".split():
820 if rev in "good bad reset init".split():
822 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
821 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
823 cmd, rev, extra = rev, extra, None
822 cmd, rev, extra = rev, extra, None
824 if cmd == "good":
823 if cmd == "good":
825 good = True
824 good = True
826 elif cmd == "bad":
825 elif cmd == "bad":
827 bad = True
826 bad = True
828 else:
827 else:
829 reset = True
828 reset = True
830 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
829 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
831 raise error.Abort(_('incompatible arguments'))
830 raise error.Abort(_('incompatible arguments'))
832
831
833 cmdutil.checkunfinished(repo)
832 cmdutil.checkunfinished(repo)
834
833
835 if reset:
834 if reset:
836 hbisect.resetstate(repo)
835 hbisect.resetstate(repo)
837 return
836 return
838
837
839 state = hbisect.load_state(repo)
838 state = hbisect.load_state(repo)
840
839
841 # update state
840 # update state
842 if good or bad or skip:
841 if good or bad or skip:
843 if rev:
842 if rev:
844 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
843 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
845 else:
844 else:
846 nodes = [repo.lookup('.')]
845 nodes = [repo.lookup('.')]
847 if good:
846 if good:
848 state['good'] += nodes
847 state['good'] += nodes
849 elif bad:
848 elif bad:
850 state['bad'] += nodes
849 state['bad'] += nodes
851 elif skip:
850 elif skip:
852 state['skip'] += nodes
851 state['skip'] += nodes
853 hbisect.save_state(repo, state)
852 hbisect.save_state(repo, state)
854 if not (state['good'] and state['bad']):
853 if not (state['good'] and state['bad']):
855 return
854 return
856
855
857 def mayupdate(repo, node, show_stats=True):
856 def mayupdate(repo, node, show_stats=True):
858 """common used update sequence"""
857 """common used update sequence"""
859 if noupdate:
858 if noupdate:
860 return
859 return
861 cmdutil.bailifchanged(repo)
860 cmdutil.bailifchanged(repo)
862 return hg.clean(repo, node, show_stats=show_stats)
861 return hg.clean(repo, node, show_stats=show_stats)
863
862
864 displayer = cmdutil.show_changeset(ui, repo, {})
863 displayer = cmdutil.show_changeset(ui, repo, {})
865
864
866 if command:
865 if command:
867 changesets = 1
866 changesets = 1
868 if noupdate:
867 if noupdate:
869 try:
868 try:
870 node = state['current'][0]
869 node = state['current'][0]
871 except LookupError:
870 except LookupError:
872 raise error.Abort(_('current bisect revision is unknown - '
871 raise error.Abort(_('current bisect revision is unknown - '
873 'start a new bisect to fix'))
872 'start a new bisect to fix'))
874 else:
873 else:
875 node, p2 = repo.dirstate.parents()
874 node, p2 = repo.dirstate.parents()
876 if p2 != nullid:
875 if p2 != nullid:
877 raise error.Abort(_('current bisect revision is a merge'))
876 raise error.Abort(_('current bisect revision is a merge'))
878 if rev:
877 if rev:
879 node = repo[scmutil.revsingle(repo, rev, node)].node()
878 node = repo[scmutil.revsingle(repo, rev, node)].node()
880 try:
879 try:
881 while changesets:
880 while changesets:
882 # update state
881 # update state
883 state['current'] = [node]
882 state['current'] = [node]
884 hbisect.save_state(repo, state)
883 hbisect.save_state(repo, state)
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
884 status = ui.system(command, environ={'HG_NODE': hex(node)})
886 if status == 125:
885 if status == 125:
887 transition = "skip"
886 transition = "skip"
888 elif status == 0:
887 elif status == 0:
889 transition = "good"
888 transition = "good"
890 # status < 0 means process was killed
889 # status < 0 means process was killed
891 elif status == 127:
890 elif status == 127:
892 raise error.Abort(_("failed to execute %s") % command)
891 raise error.Abort(_("failed to execute %s") % command)
893 elif status < 0:
892 elif status < 0:
894 raise error.Abort(_("%s killed") % command)
893 raise error.Abort(_("%s killed") % command)
895 else:
894 else:
896 transition = "bad"
895 transition = "bad"
897 state[transition].append(node)
896 state[transition].append(node)
898 ctx = repo[node]
897 ctx = repo[node]
899 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
898 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
900 hbisect.checkstate(state)
899 hbisect.checkstate(state)
901 # bisect
900 # bisect
902 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
901 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
903 # update to next check
902 # update to next check
904 node = nodes[0]
903 node = nodes[0]
905 mayupdate(repo, node, show_stats=False)
904 mayupdate(repo, node, show_stats=False)
906 finally:
905 finally:
907 state['current'] = [node]
906 state['current'] = [node]
908 hbisect.save_state(repo, state)
907 hbisect.save_state(repo, state)
909 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
908 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
910 return
909 return
911
910
912 hbisect.checkstate(state)
911 hbisect.checkstate(state)
913
912
914 # actually bisect
913 # actually bisect
915 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
914 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
916 if extend:
915 if extend:
917 if not changesets:
916 if not changesets:
918 extendnode = hbisect.extendrange(repo, state, nodes, good)
917 extendnode = hbisect.extendrange(repo, state, nodes, good)
919 if extendnode is not None:
918 if extendnode is not None:
920 ui.write(_("Extending search to changeset %d:%s\n")
919 ui.write(_("Extending search to changeset %d:%s\n")
921 % (extendnode.rev(), extendnode))
920 % (extendnode.rev(), extendnode))
922 state['current'] = [extendnode.node()]
921 state['current'] = [extendnode.node()]
923 hbisect.save_state(repo, state)
922 hbisect.save_state(repo, state)
924 return mayupdate(repo, extendnode.node())
923 return mayupdate(repo, extendnode.node())
925 raise error.Abort(_("nothing to extend"))
924 raise error.Abort(_("nothing to extend"))
926
925
927 if changesets == 0:
926 if changesets == 0:
928 hbisect.printresult(ui, repo, state, displayer, nodes, good)
927 hbisect.printresult(ui, repo, state, displayer, nodes, good)
929 else:
928 else:
930 assert len(nodes) == 1 # only a single node can be tested next
929 assert len(nodes) == 1 # only a single node can be tested next
931 node = nodes[0]
930 node = nodes[0]
932 # compute the approximate number of remaining tests
931 # compute the approximate number of remaining tests
933 tests, size = 0, 2
932 tests, size = 0, 2
934 while size <= changesets:
933 while size <= changesets:
935 tests, size = tests + 1, size * 2
934 tests, size = tests + 1, size * 2
936 rev = repo.changelog.rev(node)
935 rev = repo.changelog.rev(node)
937 ui.write(_("Testing changeset %d:%s "
936 ui.write(_("Testing changeset %d:%s "
938 "(%d changesets remaining, ~%d tests)\n")
937 "(%d changesets remaining, ~%d tests)\n")
939 % (rev, short(node), changesets, tests))
938 % (rev, short(node), changesets, tests))
940 state['current'] = [node]
939 state['current'] = [node]
941 hbisect.save_state(repo, state)
940 hbisect.save_state(repo, state)
942 return mayupdate(repo, node)
941 return mayupdate(repo, node)
943
942
944 @command('bookmarks|bookmark',
943 @command('bookmarks|bookmark',
945 [('f', 'force', False, _('force')),
944 [('f', 'force', False, _('force')),
946 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
945 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
947 ('d', 'delete', False, _('delete a given bookmark')),
946 ('d', 'delete', False, _('delete a given bookmark')),
948 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
947 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
949 ('i', 'inactive', False, _('mark a bookmark inactive')),
948 ('i', 'inactive', False, _('mark a bookmark inactive')),
950 ] + formatteropts,
949 ] + formatteropts,
951 _('hg bookmarks [OPTIONS]... [NAME]...'))
950 _('hg bookmarks [OPTIONS]... [NAME]...'))
952 def bookmark(ui, repo, *names, **opts):
951 def bookmark(ui, repo, *names, **opts):
953 '''create a new bookmark or list existing bookmarks
952 '''create a new bookmark or list existing bookmarks
954
953
955 Bookmarks are labels on changesets to help track lines of development.
954 Bookmarks are labels on changesets to help track lines of development.
956 Bookmarks are unversioned and can be moved, renamed and deleted.
955 Bookmarks are unversioned and can be moved, renamed and deleted.
957 Deleting or moving a bookmark has no effect on the associated changesets.
956 Deleting or moving a bookmark has no effect on the associated changesets.
958
957
959 Creating or updating to a bookmark causes it to be marked as 'active'.
958 Creating or updating to a bookmark causes it to be marked as 'active'.
960 The active bookmark is indicated with a '*'.
959 The active bookmark is indicated with a '*'.
961 When a commit is made, the active bookmark will advance to the new commit.
960 When a commit is made, the active bookmark will advance to the new commit.
962 A plain :hg:`update` will also advance an active bookmark, if possible.
961 A plain :hg:`update` will also advance an active bookmark, if possible.
963 Updating away from a bookmark will cause it to be deactivated.
962 Updating away from a bookmark will cause it to be deactivated.
964
963
965 Bookmarks can be pushed and pulled between repositories (see
964 Bookmarks can be pushed and pulled between repositories (see
966 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
965 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
967 diverged, a new 'divergent bookmark' of the form 'name@path' will
966 diverged, a new 'divergent bookmark' of the form 'name@path' will
968 be created. Using :hg:`merge` will resolve the divergence.
967 be created. Using :hg:`merge` will resolve the divergence.
969
968
970 A bookmark named '@' has the special property that :hg:`clone` will
969 A bookmark named '@' has the special property that :hg:`clone` will
971 check it out by default if it exists.
970 check it out by default if it exists.
972
971
973 .. container:: verbose
972 .. container:: verbose
974
973
975 Examples:
974 Examples:
976
975
977 - create an active bookmark for a new line of development::
976 - create an active bookmark for a new line of development::
978
977
979 hg book new-feature
978 hg book new-feature
980
979
981 - create an inactive bookmark as a place marker::
980 - create an inactive bookmark as a place marker::
982
981
983 hg book -i reviewed
982 hg book -i reviewed
984
983
985 - create an inactive bookmark on another changeset::
984 - create an inactive bookmark on another changeset::
986
985
987 hg book -r .^ tested
986 hg book -r .^ tested
988
987
989 - rename bookmark turkey to dinner::
988 - rename bookmark turkey to dinner::
990
989
991 hg book -m turkey dinner
990 hg book -m turkey dinner
992
991
993 - move the '@' bookmark from another branch::
992 - move the '@' bookmark from another branch::
994
993
995 hg book -f @
994 hg book -f @
996 '''
995 '''
997 force = opts.get('force')
996 force = opts.get('force')
998 rev = opts.get('rev')
997 rev = opts.get('rev')
999 delete = opts.get('delete')
998 delete = opts.get('delete')
1000 rename = opts.get('rename')
999 rename = opts.get('rename')
1001 inactive = opts.get('inactive')
1000 inactive = opts.get('inactive')
1002
1001
1003 def checkformat(mark):
1002 def checkformat(mark):
1004 mark = mark.strip()
1003 mark = mark.strip()
1005 if not mark:
1004 if not mark:
1006 raise error.Abort(_("bookmark names cannot consist entirely of "
1005 raise error.Abort(_("bookmark names cannot consist entirely of "
1007 "whitespace"))
1006 "whitespace"))
1008 scmutil.checknewlabel(repo, mark, 'bookmark')
1007 scmutil.checknewlabel(repo, mark, 'bookmark')
1009 return mark
1008 return mark
1010
1009
1011 def checkconflict(repo, mark, cur, force=False, target=None):
1010 def checkconflict(repo, mark, cur, force=False, target=None):
1012 if mark in marks and not force:
1011 if mark in marks and not force:
1013 if target:
1012 if target:
1014 if marks[mark] == target and target == cur:
1013 if marks[mark] == target and target == cur:
1015 # re-activating a bookmark
1014 # re-activating a bookmark
1016 return
1015 return
1017 anc = repo.changelog.ancestors([repo[target].rev()])
1016 anc = repo.changelog.ancestors([repo[target].rev()])
1018 bmctx = repo[marks[mark]]
1017 bmctx = repo[marks[mark]]
1019 divs = [repo[b].node() for b in marks
1018 divs = [repo[b].node() for b in marks
1020 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1019 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1021
1020
1022 # allow resolving a single divergent bookmark even if moving
1021 # allow resolving a single divergent bookmark even if moving
1023 # the bookmark across branches when a revision is specified
1022 # the bookmark across branches when a revision is specified
1024 # that contains a divergent bookmark
1023 # that contains a divergent bookmark
1025 if bmctx.rev() not in anc and target in divs:
1024 if bmctx.rev() not in anc and target in divs:
1026 bookmarks.deletedivergent(repo, [target], mark)
1025 bookmarks.deletedivergent(repo, [target], mark)
1027 return
1026 return
1028
1027
1029 deletefrom = [b for b in divs
1028 deletefrom = [b for b in divs
1030 if repo[b].rev() in anc or b == target]
1029 if repo[b].rev() in anc or b == target]
1031 bookmarks.deletedivergent(repo, deletefrom, mark)
1030 bookmarks.deletedivergent(repo, deletefrom, mark)
1032 if bookmarks.validdest(repo, bmctx, repo[target]):
1031 if bookmarks.validdest(repo, bmctx, repo[target]):
1033 ui.status(_("moving bookmark '%s' forward from %s\n") %
1032 ui.status(_("moving bookmark '%s' forward from %s\n") %
1034 (mark, short(bmctx.node())))
1033 (mark, short(bmctx.node())))
1035 return
1034 return
1036 raise error.Abort(_("bookmark '%s' already exists "
1035 raise error.Abort(_("bookmark '%s' already exists "
1037 "(use -f to force)") % mark)
1036 "(use -f to force)") % mark)
1038 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1037 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1039 and not force):
1038 and not force):
1040 raise error.Abort(
1039 raise error.Abort(
1041 _("a bookmark cannot have the name of an existing branch"))
1040 _("a bookmark cannot have the name of an existing branch"))
1042
1041
1043 if delete and rename:
1042 if delete and rename:
1044 raise error.Abort(_("--delete and --rename are incompatible"))
1043 raise error.Abort(_("--delete and --rename are incompatible"))
1045 if delete and rev:
1044 if delete and rev:
1046 raise error.Abort(_("--rev is incompatible with --delete"))
1045 raise error.Abort(_("--rev is incompatible with --delete"))
1047 if rename and rev:
1046 if rename and rev:
1048 raise error.Abort(_("--rev is incompatible with --rename"))
1047 raise error.Abort(_("--rev is incompatible with --rename"))
1049 if not names and (delete or rev):
1048 if not names and (delete or rev):
1050 raise error.Abort(_("bookmark name required"))
1049 raise error.Abort(_("bookmark name required"))
1051
1050
1052 if delete or rename or names or inactive:
1051 if delete or rename or names or inactive:
1053 wlock = lock = tr = None
1052 wlock = lock = tr = None
1054 try:
1053 try:
1055 wlock = repo.wlock()
1054 wlock = repo.wlock()
1056 lock = repo.lock()
1055 lock = repo.lock()
1057 cur = repo.changectx('.').node()
1056 cur = repo.changectx('.').node()
1058 marks = repo._bookmarks
1057 marks = repo._bookmarks
1059 if delete:
1058 if delete:
1060 tr = repo.transaction('bookmark')
1059 tr = repo.transaction('bookmark')
1061 for mark in names:
1060 for mark in names:
1062 if mark not in marks:
1061 if mark not in marks:
1063 raise error.Abort(_("bookmark '%s' does not exist") %
1062 raise error.Abort(_("bookmark '%s' does not exist") %
1064 mark)
1063 mark)
1065 if mark == repo._activebookmark:
1064 if mark == repo._activebookmark:
1066 bookmarks.deactivate(repo)
1065 bookmarks.deactivate(repo)
1067 del marks[mark]
1066 del marks[mark]
1068
1067
1069 elif rename:
1068 elif rename:
1070 tr = repo.transaction('bookmark')
1069 tr = repo.transaction('bookmark')
1071 if not names:
1070 if not names:
1072 raise error.Abort(_("new bookmark name required"))
1071 raise error.Abort(_("new bookmark name required"))
1073 elif len(names) > 1:
1072 elif len(names) > 1:
1074 raise error.Abort(_("only one new bookmark name allowed"))
1073 raise error.Abort(_("only one new bookmark name allowed"))
1075 mark = checkformat(names[0])
1074 mark = checkformat(names[0])
1076 if rename not in marks:
1075 if rename not in marks:
1077 raise error.Abort(_("bookmark '%s' does not exist")
1076 raise error.Abort(_("bookmark '%s' does not exist")
1078 % rename)
1077 % rename)
1079 checkconflict(repo, mark, cur, force)
1078 checkconflict(repo, mark, cur, force)
1080 marks[mark] = marks[rename]
1079 marks[mark] = marks[rename]
1081 if repo._activebookmark == rename and not inactive:
1080 if repo._activebookmark == rename and not inactive:
1082 bookmarks.activate(repo, mark)
1081 bookmarks.activate(repo, mark)
1083 del marks[rename]
1082 del marks[rename]
1084 elif names:
1083 elif names:
1085 tr = repo.transaction('bookmark')
1084 tr = repo.transaction('bookmark')
1086 newact = None
1085 newact = None
1087 for mark in names:
1086 for mark in names:
1088 mark = checkformat(mark)
1087 mark = checkformat(mark)
1089 if newact is None:
1088 if newact is None:
1090 newact = mark
1089 newact = mark
1091 if inactive and mark == repo._activebookmark:
1090 if inactive and mark == repo._activebookmark:
1092 bookmarks.deactivate(repo)
1091 bookmarks.deactivate(repo)
1093 return
1092 return
1094 tgt = cur
1093 tgt = cur
1095 if rev:
1094 if rev:
1096 tgt = scmutil.revsingle(repo, rev).node()
1095 tgt = scmutil.revsingle(repo, rev).node()
1097 checkconflict(repo, mark, cur, force, tgt)
1096 checkconflict(repo, mark, cur, force, tgt)
1098 marks[mark] = tgt
1097 marks[mark] = tgt
1099 if not inactive and cur == marks[newact] and not rev:
1098 if not inactive and cur == marks[newact] and not rev:
1100 bookmarks.activate(repo, newact)
1099 bookmarks.activate(repo, newact)
1101 elif cur != tgt and newact == repo._activebookmark:
1100 elif cur != tgt and newact == repo._activebookmark:
1102 bookmarks.deactivate(repo)
1101 bookmarks.deactivate(repo)
1103 elif inactive:
1102 elif inactive:
1104 if len(marks) == 0:
1103 if len(marks) == 0:
1105 ui.status(_("no bookmarks set\n"))
1104 ui.status(_("no bookmarks set\n"))
1106 elif not repo._activebookmark:
1105 elif not repo._activebookmark:
1107 ui.status(_("no active bookmark\n"))
1106 ui.status(_("no active bookmark\n"))
1108 else:
1107 else:
1109 bookmarks.deactivate(repo)
1108 bookmarks.deactivate(repo)
1110 if tr is not None:
1109 if tr is not None:
1111 marks.recordchange(tr)
1110 marks.recordchange(tr)
1112 tr.close()
1111 tr.close()
1113 finally:
1112 finally:
1114 lockmod.release(tr, lock, wlock)
1113 lockmod.release(tr, lock, wlock)
1115 else: # show bookmarks
1114 else: # show bookmarks
1116 fm = ui.formatter('bookmarks', opts)
1115 fm = ui.formatter('bookmarks', opts)
1117 hexfn = fm.hexfunc
1116 hexfn = fm.hexfunc
1118 marks = repo._bookmarks
1117 marks = repo._bookmarks
1119 if len(marks) == 0 and fm.isplain():
1118 if len(marks) == 0 and fm.isplain():
1120 ui.status(_("no bookmarks set\n"))
1119 ui.status(_("no bookmarks set\n"))
1121 for bmark, n in sorted(marks.iteritems()):
1120 for bmark, n in sorted(marks.iteritems()):
1122 active = repo._activebookmark
1121 active = repo._activebookmark
1123 if bmark == active:
1122 if bmark == active:
1124 prefix, label = '*', activebookmarklabel
1123 prefix, label = '*', activebookmarklabel
1125 else:
1124 else:
1126 prefix, label = ' ', ''
1125 prefix, label = ' ', ''
1127
1126
1128 fm.startitem()
1127 fm.startitem()
1129 if not ui.quiet:
1128 if not ui.quiet:
1130 fm.plain(' %s ' % prefix, label=label)
1129 fm.plain(' %s ' % prefix, label=label)
1131 fm.write('bookmark', '%s', bmark, label=label)
1130 fm.write('bookmark', '%s', bmark, label=label)
1132 pad = " " * (25 - encoding.colwidth(bmark))
1131 pad = " " * (25 - encoding.colwidth(bmark))
1133 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1132 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1134 repo.changelog.rev(n), hexfn(n), label=label)
1133 repo.changelog.rev(n), hexfn(n), label=label)
1135 fm.data(active=(bmark == active))
1134 fm.data(active=(bmark == active))
1136 fm.plain('\n')
1135 fm.plain('\n')
1137 fm.end()
1136 fm.end()
1138
1137
1139 @command('branch',
1138 @command('branch',
1140 [('f', 'force', None,
1139 [('f', 'force', None,
1141 _('set branch name even if it shadows an existing branch')),
1140 _('set branch name even if it shadows an existing branch')),
1142 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1141 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1143 _('[-fC] [NAME]'))
1142 _('[-fC] [NAME]'))
1144 def branch(ui, repo, label=None, **opts):
1143 def branch(ui, repo, label=None, **opts):
1145 """set or show the current branch name
1144 """set or show the current branch name
1146
1145
1147 .. note::
1146 .. note::
1148
1147
1149 Branch names are permanent and global. Use :hg:`bookmark` to create a
1148 Branch names are permanent and global. Use :hg:`bookmark` to create a
1150 light-weight bookmark instead. See :hg:`help glossary` for more
1149 light-weight bookmark instead. See :hg:`help glossary` for more
1151 information about named branches and bookmarks.
1150 information about named branches and bookmarks.
1152
1151
1153 With no argument, show the current branch name. With one argument,
1152 With no argument, show the current branch name. With one argument,
1154 set the working directory branch name (the branch will not exist
1153 set the working directory branch name (the branch will not exist
1155 in the repository until the next commit). Standard practice
1154 in the repository until the next commit). Standard practice
1156 recommends that primary development take place on the 'default'
1155 recommends that primary development take place on the 'default'
1157 branch.
1156 branch.
1158
1157
1159 Unless -f/--force is specified, branch will not let you set a
1158 Unless -f/--force is specified, branch will not let you set a
1160 branch name that already exists.
1159 branch name that already exists.
1161
1160
1162 Use -C/--clean to reset the working directory branch to that of
1161 Use -C/--clean to reset the working directory branch to that of
1163 the parent of the working directory, negating a previous branch
1162 the parent of the working directory, negating a previous branch
1164 change.
1163 change.
1165
1164
1166 Use the command :hg:`update` to switch to an existing branch. Use
1165 Use the command :hg:`update` to switch to an existing branch. Use
1167 :hg:`commit --close-branch` to mark this branch head as closed.
1166 :hg:`commit --close-branch` to mark this branch head as closed.
1168 When all heads of a branch are closed, the branch will be
1167 When all heads of a branch are closed, the branch will be
1169 considered closed.
1168 considered closed.
1170
1169
1171 Returns 0 on success.
1170 Returns 0 on success.
1172 """
1171 """
1173 if label:
1172 if label:
1174 label = label.strip()
1173 label = label.strip()
1175
1174
1176 if not opts.get('clean') and not label:
1175 if not opts.get('clean') and not label:
1177 ui.write("%s\n" % repo.dirstate.branch())
1176 ui.write("%s\n" % repo.dirstate.branch())
1178 return
1177 return
1179
1178
1180 with repo.wlock():
1179 with repo.wlock():
1181 if opts.get('clean'):
1180 if opts.get('clean'):
1182 label = repo[None].p1().branch()
1181 label = repo[None].p1().branch()
1183 repo.dirstate.setbranch(label)
1182 repo.dirstate.setbranch(label)
1184 ui.status(_('reset working directory to branch %s\n') % label)
1183 ui.status(_('reset working directory to branch %s\n') % label)
1185 elif label:
1184 elif label:
1186 if not opts.get('force') and label in repo.branchmap():
1185 if not opts.get('force') and label in repo.branchmap():
1187 if label not in [p.branch() for p in repo[None].parents()]:
1186 if label not in [p.branch() for p in repo[None].parents()]:
1188 raise error.Abort(_('a branch of the same name already'
1187 raise error.Abort(_('a branch of the same name already'
1189 ' exists'),
1188 ' exists'),
1190 # i18n: "it" refers to an existing branch
1189 # i18n: "it" refers to an existing branch
1191 hint=_("use 'hg update' to switch to it"))
1190 hint=_("use 'hg update' to switch to it"))
1192 scmutil.checknewlabel(repo, label, 'branch')
1191 scmutil.checknewlabel(repo, label, 'branch')
1193 repo.dirstate.setbranch(label)
1192 repo.dirstate.setbranch(label)
1194 ui.status(_('marked working directory as branch %s\n') % label)
1193 ui.status(_('marked working directory as branch %s\n') % label)
1195
1194
1196 # find any open named branches aside from default
1195 # find any open named branches aside from default
1197 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1196 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1198 if n != "default" and not c]
1197 if n != "default" and not c]
1199 if not others:
1198 if not others:
1200 ui.status(_('(branches are permanent and global, '
1199 ui.status(_('(branches are permanent and global, '
1201 'did you want a bookmark?)\n'))
1200 'did you want a bookmark?)\n'))
1202
1201
1203 @command('branches',
1202 @command('branches',
1204 [('a', 'active', False,
1203 [('a', 'active', False,
1205 _('show only branches that have unmerged heads (DEPRECATED)')),
1204 _('show only branches that have unmerged heads (DEPRECATED)')),
1206 ('c', 'closed', False, _('show normal and closed branches')),
1205 ('c', 'closed', False, _('show normal and closed branches')),
1207 ] + formatteropts,
1206 ] + formatteropts,
1208 _('[-c]'))
1207 _('[-c]'))
1209 def branches(ui, repo, active=False, closed=False, **opts):
1208 def branches(ui, repo, active=False, closed=False, **opts):
1210 """list repository named branches
1209 """list repository named branches
1211
1210
1212 List the repository's named branches, indicating which ones are
1211 List the repository's named branches, indicating which ones are
1213 inactive. If -c/--closed is specified, also list branches which have
1212 inactive. If -c/--closed is specified, also list branches which have
1214 been marked closed (see :hg:`commit --close-branch`).
1213 been marked closed (see :hg:`commit --close-branch`).
1215
1214
1216 Use the command :hg:`update` to switch to an existing branch.
1215 Use the command :hg:`update` to switch to an existing branch.
1217
1216
1218 Returns 0.
1217 Returns 0.
1219 """
1218 """
1220
1219
1221 fm = ui.formatter('branches', opts)
1220 fm = ui.formatter('branches', opts)
1222 hexfunc = fm.hexfunc
1221 hexfunc = fm.hexfunc
1223
1222
1224 allheads = set(repo.heads())
1223 allheads = set(repo.heads())
1225 branches = []
1224 branches = []
1226 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1225 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1227 isactive = not isclosed and bool(set(heads) & allheads)
1226 isactive = not isclosed and bool(set(heads) & allheads)
1228 branches.append((tag, repo[tip], isactive, not isclosed))
1227 branches.append((tag, repo[tip], isactive, not isclosed))
1229 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1228 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1230 reverse=True)
1229 reverse=True)
1231
1230
1232 for tag, ctx, isactive, isopen in branches:
1231 for tag, ctx, isactive, isopen in branches:
1233 if active and not isactive:
1232 if active and not isactive:
1234 continue
1233 continue
1235 if isactive:
1234 if isactive:
1236 label = 'branches.active'
1235 label = 'branches.active'
1237 notice = ''
1236 notice = ''
1238 elif not isopen:
1237 elif not isopen:
1239 if not closed:
1238 if not closed:
1240 continue
1239 continue
1241 label = 'branches.closed'
1240 label = 'branches.closed'
1242 notice = _(' (closed)')
1241 notice = _(' (closed)')
1243 else:
1242 else:
1244 label = 'branches.inactive'
1243 label = 'branches.inactive'
1245 notice = _(' (inactive)')
1244 notice = _(' (inactive)')
1246 current = (tag == repo.dirstate.branch())
1245 current = (tag == repo.dirstate.branch())
1247 if current:
1246 if current:
1248 label = 'branches.current'
1247 label = 'branches.current'
1249
1248
1250 fm.startitem()
1249 fm.startitem()
1251 fm.write('branch', '%s', tag, label=label)
1250 fm.write('branch', '%s', tag, label=label)
1252 rev = ctx.rev()
1251 rev = ctx.rev()
1253 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1252 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1254 fmt = ' ' * padsize + ' %d:%s'
1253 fmt = ' ' * padsize + ' %d:%s'
1255 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1254 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1256 label='log.changeset changeset.%s' % ctx.phasestr())
1255 label='log.changeset changeset.%s' % ctx.phasestr())
1257 fm.data(active=isactive, closed=not isopen, current=current)
1256 fm.data(active=isactive, closed=not isopen, current=current)
1258 if not ui.quiet:
1257 if not ui.quiet:
1259 fm.plain(notice)
1258 fm.plain(notice)
1260 fm.plain('\n')
1259 fm.plain('\n')
1261 fm.end()
1260 fm.end()
1262
1261
1263 @command('bundle',
1262 @command('bundle',
1264 [('f', 'force', None, _('run even when the destination is unrelated')),
1263 [('f', 'force', None, _('run even when the destination is unrelated')),
1265 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1264 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1266 _('REV')),
1265 _('REV')),
1267 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1266 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1268 _('BRANCH')),
1267 _('BRANCH')),
1269 ('', 'base', [],
1268 ('', 'base', [],
1270 _('a base changeset assumed to be available at the destination'),
1269 _('a base changeset assumed to be available at the destination'),
1271 _('REV')),
1270 _('REV')),
1272 ('a', 'all', None, _('bundle all changesets in the repository')),
1271 ('a', 'all', None, _('bundle all changesets in the repository')),
1273 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1272 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1274 ] + remoteopts,
1273 ] + remoteopts,
1275 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1274 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1276 def bundle(ui, repo, fname, dest=None, **opts):
1275 def bundle(ui, repo, fname, dest=None, **opts):
1277 """create a changegroup file
1276 """create a changegroup file
1278
1277
1279 Generate a changegroup file collecting changesets to be added
1278 Generate a changegroup file collecting changesets to be added
1280 to a repository.
1279 to a repository.
1281
1280
1282 To create a bundle containing all changesets, use -a/--all
1281 To create a bundle containing all changesets, use -a/--all
1283 (or --base null). Otherwise, hg assumes the destination will have
1282 (or --base null). Otherwise, hg assumes the destination will have
1284 all the nodes you specify with --base parameters. Otherwise, hg
1283 all the nodes you specify with --base parameters. Otherwise, hg
1285 will assume the repository has all the nodes in destination, or
1284 will assume the repository has all the nodes in destination, or
1286 default-push/default if no destination is specified.
1285 default-push/default if no destination is specified.
1287
1286
1288 You can change bundle format with the -t/--type option. You can
1287 You can change bundle format with the -t/--type option. You can
1289 specify a compression, a bundle version or both using a dash
1288 specify a compression, a bundle version or both using a dash
1290 (comp-version). The available compression methods are: none, bzip2,
1289 (comp-version). The available compression methods are: none, bzip2,
1291 and gzip (by default, bundles are compressed using bzip2). The
1290 and gzip (by default, bundles are compressed using bzip2). The
1292 available formats are: v1, v2 (default to most suitable).
1291 available formats are: v1, v2 (default to most suitable).
1293
1292
1294 The bundle file can then be transferred using conventional means
1293 The bundle file can then be transferred using conventional means
1295 and applied to another repository with the unbundle or pull
1294 and applied to another repository with the unbundle or pull
1296 command. This is useful when direct push and pull are not
1295 command. This is useful when direct push and pull are not
1297 available or when exporting an entire repository is undesirable.
1296 available or when exporting an entire repository is undesirable.
1298
1297
1299 Applying bundles preserves all changeset contents including
1298 Applying bundles preserves all changeset contents including
1300 permissions, copy/rename information, and revision history.
1299 permissions, copy/rename information, and revision history.
1301
1300
1302 Returns 0 on success, 1 if no changes found.
1301 Returns 0 on success, 1 if no changes found.
1303 """
1302 """
1304 revs = None
1303 revs = None
1305 if 'rev' in opts:
1304 if 'rev' in opts:
1306 revstrings = opts['rev']
1305 revstrings = opts['rev']
1307 revs = scmutil.revrange(repo, revstrings)
1306 revs = scmutil.revrange(repo, revstrings)
1308 if revstrings and not revs:
1307 if revstrings and not revs:
1309 raise error.Abort(_('no commits to bundle'))
1308 raise error.Abort(_('no commits to bundle'))
1310
1309
1311 bundletype = opts.get('type', 'bzip2').lower()
1310 bundletype = opts.get('type', 'bzip2').lower()
1312 try:
1311 try:
1313 bcompression, cgversion, params = exchange.parsebundlespec(
1312 bcompression, cgversion, params = exchange.parsebundlespec(
1314 repo, bundletype, strict=False)
1313 repo, bundletype, strict=False)
1315 except error.UnsupportedBundleSpecification as e:
1314 except error.UnsupportedBundleSpecification as e:
1316 raise error.Abort(str(e),
1315 raise error.Abort(str(e),
1317 hint=_("see 'hg help bundle' for supported "
1316 hint=_("see 'hg help bundle' for supported "
1318 "values for --type"))
1317 "values for --type"))
1319
1318
1320 # Packed bundles are a pseudo bundle format for now.
1319 # Packed bundles are a pseudo bundle format for now.
1321 if cgversion == 's1':
1320 if cgversion == 's1':
1322 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1321 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1323 hint=_("use 'hg debugcreatestreamclonebundle'"))
1322 hint=_("use 'hg debugcreatestreamclonebundle'"))
1324
1323
1325 if opts.get('all'):
1324 if opts.get('all'):
1326 if dest:
1325 if dest:
1327 raise error.Abort(_("--all is incompatible with specifying "
1326 raise error.Abort(_("--all is incompatible with specifying "
1328 "a destination"))
1327 "a destination"))
1329 if opts.get('base'):
1328 if opts.get('base'):
1330 ui.warn(_("ignoring --base because --all was specified\n"))
1329 ui.warn(_("ignoring --base because --all was specified\n"))
1331 base = ['null']
1330 base = ['null']
1332 else:
1331 else:
1333 base = scmutil.revrange(repo, opts.get('base'))
1332 base = scmutil.revrange(repo, opts.get('base'))
1334 # TODO: get desired bundlecaps from command line.
1333 # TODO: get desired bundlecaps from command line.
1335 bundlecaps = None
1334 bundlecaps = None
1336 if cgversion not in changegroup.supportedoutgoingversions(repo):
1335 if cgversion not in changegroup.supportedoutgoingversions(repo):
1337 raise error.Abort(_("repository does not support bundle version %s") %
1336 raise error.Abort(_("repository does not support bundle version %s") %
1338 cgversion)
1337 cgversion)
1339
1338
1340 if base:
1339 if base:
1341 if dest:
1340 if dest:
1342 raise error.Abort(_("--base is incompatible with specifying "
1341 raise error.Abort(_("--base is incompatible with specifying "
1343 "a destination"))
1342 "a destination"))
1344 common = [repo.lookup(rev) for rev in base]
1343 common = [repo.lookup(rev) for rev in base]
1345 heads = revs and map(repo.lookup, revs) or None
1344 heads = revs and map(repo.lookup, revs) or None
1346 outgoing = discovery.outgoing(repo, common, heads)
1345 outgoing = discovery.outgoing(repo, common, heads)
1347 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1346 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1348 bundlecaps=bundlecaps,
1347 bundlecaps=bundlecaps,
1349 version=cgversion)
1348 version=cgversion)
1350 outgoing = None
1349 outgoing = None
1351 else:
1350 else:
1352 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1351 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1353 dest, branches = hg.parseurl(dest, opts.get('branch'))
1352 dest, branches = hg.parseurl(dest, opts.get('branch'))
1354 other = hg.peer(repo, opts, dest)
1353 other = hg.peer(repo, opts, dest)
1355 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1354 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1356 heads = revs and map(repo.lookup, revs) or revs
1355 heads = revs and map(repo.lookup, revs) or revs
1357 outgoing = discovery.findcommonoutgoing(repo, other,
1356 outgoing = discovery.findcommonoutgoing(repo, other,
1358 onlyheads=heads,
1357 onlyheads=heads,
1359 force=opts.get('force'),
1358 force=opts.get('force'),
1360 portable=True)
1359 portable=True)
1361 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1360 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1362 bundlecaps, version=cgversion)
1361 bundlecaps, version=cgversion)
1363 if not cg:
1362 if not cg:
1364 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1363 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1365 return 1
1364 return 1
1366
1365
1367 if cgversion == '01': #bundle1
1366 if cgversion == '01': #bundle1
1368 if bcompression is None:
1367 if bcompression is None:
1369 bcompression = 'UN'
1368 bcompression = 'UN'
1370 bversion = 'HG10' + bcompression
1369 bversion = 'HG10' + bcompression
1371 bcompression = None
1370 bcompression = None
1372 else:
1371 else:
1373 assert cgversion == '02'
1372 assert cgversion == '02'
1374 bversion = 'HG20'
1373 bversion = 'HG20'
1375
1374
1376 # TODO compression options should be derived from bundlespec parsing.
1375 # TODO compression options should be derived from bundlespec parsing.
1377 # This is a temporary hack to allow adjusting bundle compression
1376 # This is a temporary hack to allow adjusting bundle compression
1378 # level without a) formalizing the bundlespec changes to declare it
1377 # level without a) formalizing the bundlespec changes to declare it
1379 # b) introducing a command flag.
1378 # b) introducing a command flag.
1380 compopts = {}
1379 compopts = {}
1381 complevel = ui.configint('experimental', 'bundlecomplevel')
1380 complevel = ui.configint('experimental', 'bundlecomplevel')
1382 if complevel is not None:
1381 if complevel is not None:
1383 compopts['level'] = complevel
1382 compopts['level'] = complevel
1384
1383
1385 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1384 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1386 compopts=compopts)
1385 compopts=compopts)
1387
1386
1388 @command('cat',
1387 @command('cat',
1389 [('o', 'output', '',
1388 [('o', 'output', '',
1390 _('print output to file with formatted name'), _('FORMAT')),
1389 _('print output to file with formatted name'), _('FORMAT')),
1391 ('r', 'rev', '', _('print the given revision'), _('REV')),
1390 ('r', 'rev', '', _('print the given revision'), _('REV')),
1392 ('', 'decode', None, _('apply any matching decode filter')),
1391 ('', 'decode', None, _('apply any matching decode filter')),
1393 ] + walkopts,
1392 ] + walkopts,
1394 _('[OPTION]... FILE...'),
1393 _('[OPTION]... FILE...'),
1395 inferrepo=True)
1394 inferrepo=True)
1396 def cat(ui, repo, file1, *pats, **opts):
1395 def cat(ui, repo, file1, *pats, **opts):
1397 """output the current or given revision of files
1396 """output the current or given revision of files
1398
1397
1399 Print the specified files as they were at the given revision. If
1398 Print the specified files as they were at the given revision. If
1400 no revision is given, the parent of the working directory is used.
1399 no revision is given, the parent of the working directory is used.
1401
1400
1402 Output may be to a file, in which case the name of the file is
1401 Output may be to a file, in which case the name of the file is
1403 given using a format string. The formatting rules as follows:
1402 given using a format string. The formatting rules as follows:
1404
1403
1405 :``%%``: literal "%" character
1404 :``%%``: literal "%" character
1406 :``%s``: basename of file being printed
1405 :``%s``: basename of file being printed
1407 :``%d``: dirname of file being printed, or '.' if in repository root
1406 :``%d``: dirname of file being printed, or '.' if in repository root
1408 :``%p``: root-relative path name of file being printed
1407 :``%p``: root-relative path name of file being printed
1409 :``%H``: changeset hash (40 hexadecimal digits)
1408 :``%H``: changeset hash (40 hexadecimal digits)
1410 :``%R``: changeset revision number
1409 :``%R``: changeset revision number
1411 :``%h``: short-form changeset hash (12 hexadecimal digits)
1410 :``%h``: short-form changeset hash (12 hexadecimal digits)
1412 :``%r``: zero-padded changeset revision number
1411 :``%r``: zero-padded changeset revision number
1413 :``%b``: basename of the exporting repository
1412 :``%b``: basename of the exporting repository
1414
1413
1415 Returns 0 on success.
1414 Returns 0 on success.
1416 """
1415 """
1417 ctx = scmutil.revsingle(repo, opts.get('rev'))
1416 ctx = scmutil.revsingle(repo, opts.get('rev'))
1418 m = scmutil.match(ctx, (file1,) + pats, opts)
1417 m = scmutil.match(ctx, (file1,) + pats, opts)
1419
1418
1420 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1419 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1421
1420
1422 @command('^clone',
1421 @command('^clone',
1423 [('U', 'noupdate', None, _('the clone will include an empty working '
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1424 'directory (only a repository)')),
1423 'directory (only a repository)')),
1425 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1426 _('REV')),
1425 _('REV')),
1427 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1426 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1428 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1427 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1429 ('', 'pull', None, _('use pull protocol to copy metadata')),
1428 ('', 'pull', None, _('use pull protocol to copy metadata')),
1430 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1429 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1431 ] + remoteopts,
1430 ] + remoteopts,
1432 _('[OPTION]... SOURCE [DEST]'),
1431 _('[OPTION]... SOURCE [DEST]'),
1433 norepo=True)
1432 norepo=True)
1434 def clone(ui, source, dest=None, **opts):
1433 def clone(ui, source, dest=None, **opts):
1435 """make a copy of an existing repository
1434 """make a copy of an existing repository
1436
1435
1437 Create a copy of an existing repository in a new directory.
1436 Create a copy of an existing repository in a new directory.
1438
1437
1439 If no destination directory name is specified, it defaults to the
1438 If no destination directory name is specified, it defaults to the
1440 basename of the source.
1439 basename of the source.
1441
1440
1442 The location of the source is added to the new repository's
1441 The location of the source is added to the new repository's
1443 ``.hg/hgrc`` file, as the default to be used for future pulls.
1442 ``.hg/hgrc`` file, as the default to be used for future pulls.
1444
1443
1445 Only local paths and ``ssh://`` URLs are supported as
1444 Only local paths and ``ssh://`` URLs are supported as
1446 destinations. For ``ssh://`` destinations, no working directory or
1445 destinations. For ``ssh://`` destinations, no working directory or
1447 ``.hg/hgrc`` will be created on the remote side.
1446 ``.hg/hgrc`` will be created on the remote side.
1448
1447
1449 If the source repository has a bookmark called '@' set, that
1448 If the source repository has a bookmark called '@' set, that
1450 revision will be checked out in the new repository by default.
1449 revision will be checked out in the new repository by default.
1451
1450
1452 To check out a particular version, use -u/--update, or
1451 To check out a particular version, use -u/--update, or
1453 -U/--noupdate to create a clone with no working directory.
1452 -U/--noupdate to create a clone with no working directory.
1454
1453
1455 To pull only a subset of changesets, specify one or more revisions
1454 To pull only a subset of changesets, specify one or more revisions
1456 identifiers with -r/--rev or branches with -b/--branch. The
1455 identifiers with -r/--rev or branches with -b/--branch. The
1457 resulting clone will contain only the specified changesets and
1456 resulting clone will contain only the specified changesets and
1458 their ancestors. These options (or 'clone src#rev dest') imply
1457 their ancestors. These options (or 'clone src#rev dest') imply
1459 --pull, even for local source repositories.
1458 --pull, even for local source repositories.
1460
1459
1461 .. note::
1460 .. note::
1462
1461
1463 Specifying a tag will include the tagged changeset but not the
1462 Specifying a tag will include the tagged changeset but not the
1464 changeset containing the tag.
1463 changeset containing the tag.
1465
1464
1466 .. container:: verbose
1465 .. container:: verbose
1467
1466
1468 For efficiency, hardlinks are used for cloning whenever the
1467 For efficiency, hardlinks are used for cloning whenever the
1469 source and destination are on the same filesystem (note this
1468 source and destination are on the same filesystem (note this
1470 applies only to the repository data, not to the working
1469 applies only to the repository data, not to the working
1471 directory). Some filesystems, such as AFS, implement hardlinking
1470 directory). Some filesystems, such as AFS, implement hardlinking
1472 incorrectly, but do not report errors. In these cases, use the
1471 incorrectly, but do not report errors. In these cases, use the
1473 --pull option to avoid hardlinking.
1472 --pull option to avoid hardlinking.
1474
1473
1475 In some cases, you can clone repositories and the working
1474 In some cases, you can clone repositories and the working
1476 directory using full hardlinks with ::
1475 directory using full hardlinks with ::
1477
1476
1478 $ cp -al REPO REPOCLONE
1477 $ cp -al REPO REPOCLONE
1479
1478
1480 This is the fastest way to clone, but it is not always safe. The
1479 This is the fastest way to clone, but it is not always safe. The
1481 operation is not atomic (making sure REPO is not modified during
1480 operation is not atomic (making sure REPO is not modified during
1482 the operation is up to you) and you have to make sure your
1481 the operation is up to you) and you have to make sure your
1483 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1482 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1484 so). Also, this is not compatible with certain extensions that
1483 so). Also, this is not compatible with certain extensions that
1485 place their metadata under the .hg directory, such as mq.
1484 place their metadata under the .hg directory, such as mq.
1486
1485
1487 Mercurial will update the working directory to the first applicable
1486 Mercurial will update the working directory to the first applicable
1488 revision from this list:
1487 revision from this list:
1489
1488
1490 a) null if -U or the source repository has no changesets
1489 a) null if -U or the source repository has no changesets
1491 b) if -u . and the source repository is local, the first parent of
1490 b) if -u . and the source repository is local, the first parent of
1492 the source repository's working directory
1491 the source repository's working directory
1493 c) the changeset specified with -u (if a branch name, this means the
1492 c) the changeset specified with -u (if a branch name, this means the
1494 latest head of that branch)
1493 latest head of that branch)
1495 d) the changeset specified with -r
1494 d) the changeset specified with -r
1496 e) the tipmost head specified with -b
1495 e) the tipmost head specified with -b
1497 f) the tipmost head specified with the url#branch source syntax
1496 f) the tipmost head specified with the url#branch source syntax
1498 g) the revision marked with the '@' bookmark, if present
1497 g) the revision marked with the '@' bookmark, if present
1499 h) the tipmost head of the default branch
1498 h) the tipmost head of the default branch
1500 i) tip
1499 i) tip
1501
1500
1502 When cloning from servers that support it, Mercurial may fetch
1501 When cloning from servers that support it, Mercurial may fetch
1503 pre-generated data from a server-advertised URL. When this is done,
1502 pre-generated data from a server-advertised URL. When this is done,
1504 hooks operating on incoming changesets and changegroups may fire twice,
1503 hooks operating on incoming changesets and changegroups may fire twice,
1505 once for the bundle fetched from the URL and another for any additional
1504 once for the bundle fetched from the URL and another for any additional
1506 data not fetched from this URL. In addition, if an error occurs, the
1505 data not fetched from this URL. In addition, if an error occurs, the
1507 repository may be rolled back to a partial clone. This behavior may
1506 repository may be rolled back to a partial clone. This behavior may
1508 change in future releases. See :hg:`help -e clonebundles` for more.
1507 change in future releases. See :hg:`help -e clonebundles` for more.
1509
1508
1510 Examples:
1509 Examples:
1511
1510
1512 - clone a remote repository to a new directory named hg/::
1511 - clone a remote repository to a new directory named hg/::
1513
1512
1514 hg clone https://www.mercurial-scm.org/repo/hg/
1513 hg clone https://www.mercurial-scm.org/repo/hg/
1515
1514
1516 - create a lightweight local clone::
1515 - create a lightweight local clone::
1517
1516
1518 hg clone project/ project-feature/
1517 hg clone project/ project-feature/
1519
1518
1520 - clone from an absolute path on an ssh server (note double-slash)::
1519 - clone from an absolute path on an ssh server (note double-slash)::
1521
1520
1522 hg clone ssh://user@server//home/projects/alpha/
1521 hg clone ssh://user@server//home/projects/alpha/
1523
1522
1524 - do a high-speed clone over a LAN while checking out a
1523 - do a high-speed clone over a LAN while checking out a
1525 specified version::
1524 specified version::
1526
1525
1527 hg clone --uncompressed http://server/repo -u 1.5
1526 hg clone --uncompressed http://server/repo -u 1.5
1528
1527
1529 - create a repository without changesets after a particular revision::
1528 - create a repository without changesets after a particular revision::
1530
1529
1531 hg clone -r 04e544 experimental/ good/
1530 hg clone -r 04e544 experimental/ good/
1532
1531
1533 - clone (and track) a particular named branch::
1532 - clone (and track) a particular named branch::
1534
1533
1535 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1534 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1536
1535
1537 See :hg:`help urls` for details on specifying URLs.
1536 See :hg:`help urls` for details on specifying URLs.
1538
1537
1539 Returns 0 on success.
1538 Returns 0 on success.
1540 """
1539 """
1541 if opts.get('noupdate') and opts.get('updaterev'):
1540 if opts.get('noupdate') and opts.get('updaterev'):
1542 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1541 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1543
1542
1544 r = hg.clone(ui, opts, source, dest,
1543 r = hg.clone(ui, opts, source, dest,
1545 pull=opts.get('pull'),
1544 pull=opts.get('pull'),
1546 stream=opts.get('uncompressed'),
1545 stream=opts.get('uncompressed'),
1547 rev=opts.get('rev'),
1546 rev=opts.get('rev'),
1548 update=opts.get('updaterev') or not opts.get('noupdate'),
1547 update=opts.get('updaterev') or not opts.get('noupdate'),
1549 branch=opts.get('branch'),
1548 branch=opts.get('branch'),
1550 shareopts=opts.get('shareopts'))
1549 shareopts=opts.get('shareopts'))
1551
1550
1552 return r is None
1551 return r is None
1553
1552
1554 @command('^commit|ci',
1553 @command('^commit|ci',
1555 [('A', 'addremove', None,
1554 [('A', 'addremove', None,
1556 _('mark new/missing files as added/removed before committing')),
1555 _('mark new/missing files as added/removed before committing')),
1557 ('', 'close-branch', None,
1556 ('', 'close-branch', None,
1558 _('mark a branch head as closed')),
1557 _('mark a branch head as closed')),
1559 ('', 'amend', None, _('amend the parent of the working directory')),
1558 ('', 'amend', None, _('amend the parent of the working directory')),
1560 ('s', 'secret', None, _('use the secret phase for committing')),
1559 ('s', 'secret', None, _('use the secret phase for committing')),
1561 ('e', 'edit', None, _('invoke editor on commit messages')),
1560 ('e', 'edit', None, _('invoke editor on commit messages')),
1562 ('i', 'interactive', None, _('use interactive mode')),
1561 ('i', 'interactive', None, _('use interactive mode')),
1563 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1562 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1564 _('[OPTION]... [FILE]...'),
1563 _('[OPTION]... [FILE]...'),
1565 inferrepo=True)
1564 inferrepo=True)
1566 def commit(ui, repo, *pats, **opts):
1565 def commit(ui, repo, *pats, **opts):
1567 """commit the specified files or all outstanding changes
1566 """commit the specified files or all outstanding changes
1568
1567
1569 Commit changes to the given files into the repository. Unlike a
1568 Commit changes to the given files into the repository. Unlike a
1570 centralized SCM, this operation is a local operation. See
1569 centralized SCM, this operation is a local operation. See
1571 :hg:`push` for a way to actively distribute your changes.
1570 :hg:`push` for a way to actively distribute your changes.
1572
1571
1573 If a list of files is omitted, all changes reported by :hg:`status`
1572 If a list of files is omitted, all changes reported by :hg:`status`
1574 will be committed.
1573 will be committed.
1575
1574
1576 If you are committing the result of a merge, do not provide any
1575 If you are committing the result of a merge, do not provide any
1577 filenames or -I/-X filters.
1576 filenames or -I/-X filters.
1578
1577
1579 If no commit message is specified, Mercurial starts your
1578 If no commit message is specified, Mercurial starts your
1580 configured editor where you can enter a message. In case your
1579 configured editor where you can enter a message. In case your
1581 commit fails, you will find a backup of your message in
1580 commit fails, you will find a backup of your message in
1582 ``.hg/last-message.txt``.
1581 ``.hg/last-message.txt``.
1583
1582
1584 The --close-branch flag can be used to mark the current branch
1583 The --close-branch flag can be used to mark the current branch
1585 head closed. When all heads of a branch are closed, the branch
1584 head closed. When all heads of a branch are closed, the branch
1586 will be considered closed and no longer listed.
1585 will be considered closed and no longer listed.
1587
1586
1588 The --amend flag can be used to amend the parent of the
1587 The --amend flag can be used to amend the parent of the
1589 working directory with a new commit that contains the changes
1588 working directory with a new commit that contains the changes
1590 in the parent in addition to those currently reported by :hg:`status`,
1589 in the parent in addition to those currently reported by :hg:`status`,
1591 if there are any. The old commit is stored in a backup bundle in
1590 if there are any. The old commit is stored in a backup bundle in
1592 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1591 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1593 on how to restore it).
1592 on how to restore it).
1594
1593
1595 Message, user and date are taken from the amended commit unless
1594 Message, user and date are taken from the amended commit unless
1596 specified. When a message isn't specified on the command line,
1595 specified. When a message isn't specified on the command line,
1597 the editor will open with the message of the amended commit.
1596 the editor will open with the message of the amended commit.
1598
1597
1599 It is not possible to amend public changesets (see :hg:`help phases`)
1598 It is not possible to amend public changesets (see :hg:`help phases`)
1600 or changesets that have children.
1599 or changesets that have children.
1601
1600
1602 See :hg:`help dates` for a list of formats valid for -d/--date.
1601 See :hg:`help dates` for a list of formats valid for -d/--date.
1603
1602
1604 Returns 0 on success, 1 if nothing changed.
1603 Returns 0 on success, 1 if nothing changed.
1605
1604
1606 .. container:: verbose
1605 .. container:: verbose
1607
1606
1608 Examples:
1607 Examples:
1609
1608
1610 - commit all files ending in .py::
1609 - commit all files ending in .py::
1611
1610
1612 hg commit --include "set:**.py"
1611 hg commit --include "set:**.py"
1613
1612
1614 - commit all non-binary files::
1613 - commit all non-binary files::
1615
1614
1616 hg commit --exclude "set:binary()"
1615 hg commit --exclude "set:binary()"
1617
1616
1618 - amend the current commit and set the date to now::
1617 - amend the current commit and set the date to now::
1619
1618
1620 hg commit --amend --date now
1619 hg commit --amend --date now
1621 """
1620 """
1622 wlock = lock = None
1621 wlock = lock = None
1623 try:
1622 try:
1624 wlock = repo.wlock()
1623 wlock = repo.wlock()
1625 lock = repo.lock()
1624 lock = repo.lock()
1626 return _docommit(ui, repo, *pats, **opts)
1625 return _docommit(ui, repo, *pats, **opts)
1627 finally:
1626 finally:
1628 release(lock, wlock)
1627 release(lock, wlock)
1629
1628
1630 def _docommit(ui, repo, *pats, **opts):
1629 def _docommit(ui, repo, *pats, **opts):
1631 if opts.get('interactive'):
1630 if opts.get('interactive'):
1632 opts.pop('interactive')
1631 opts.pop('interactive')
1633 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1632 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1634 cmdutil.recordfilter, *pats, **opts)
1633 cmdutil.recordfilter, *pats, **opts)
1635 # ret can be 0 (no changes to record) or the value returned by
1634 # ret can be 0 (no changes to record) or the value returned by
1636 # commit(), 1 if nothing changed or None on success.
1635 # commit(), 1 if nothing changed or None on success.
1637 return 1 if ret == 0 else ret
1636 return 1 if ret == 0 else ret
1638
1637
1639 if opts.get('subrepos'):
1638 if opts.get('subrepos'):
1640 if opts.get('amend'):
1639 if opts.get('amend'):
1641 raise error.Abort(_('cannot amend with --subrepos'))
1640 raise error.Abort(_('cannot amend with --subrepos'))
1642 # Let --subrepos on the command line override config setting.
1641 # Let --subrepos on the command line override config setting.
1643 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1642 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1644
1643
1645 cmdutil.checkunfinished(repo, commit=True)
1644 cmdutil.checkunfinished(repo, commit=True)
1646
1645
1647 branch = repo[None].branch()
1646 branch = repo[None].branch()
1648 bheads = repo.branchheads(branch)
1647 bheads = repo.branchheads(branch)
1649
1648
1650 extra = {}
1649 extra = {}
1651 if opts.get('close_branch'):
1650 if opts.get('close_branch'):
1652 extra['close'] = 1
1651 extra['close'] = 1
1653
1652
1654 if not bheads:
1653 if not bheads:
1655 raise error.Abort(_('can only close branch heads'))
1654 raise error.Abort(_('can only close branch heads'))
1656 elif opts.get('amend'):
1655 elif opts.get('amend'):
1657 if repo[None].parents()[0].p1().branch() != branch and \
1656 if repo[None].parents()[0].p1().branch() != branch and \
1658 repo[None].parents()[0].p2().branch() != branch:
1657 repo[None].parents()[0].p2().branch() != branch:
1659 raise error.Abort(_('can only close branch heads'))
1658 raise error.Abort(_('can only close branch heads'))
1660
1659
1661 if opts.get('amend'):
1660 if opts.get('amend'):
1662 if ui.configbool('ui', 'commitsubrepos'):
1661 if ui.configbool('ui', 'commitsubrepos'):
1663 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1662 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1664
1663
1665 old = repo['.']
1664 old = repo['.']
1666 if not old.mutable():
1665 if not old.mutable():
1667 raise error.Abort(_('cannot amend public changesets'))
1666 raise error.Abort(_('cannot amend public changesets'))
1668 if len(repo[None].parents()) > 1:
1667 if len(repo[None].parents()) > 1:
1669 raise error.Abort(_('cannot amend while merging'))
1668 raise error.Abort(_('cannot amend while merging'))
1670 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1669 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1671 if not allowunstable and old.children():
1670 if not allowunstable and old.children():
1672 raise error.Abort(_('cannot amend changeset with children'))
1671 raise error.Abort(_('cannot amend changeset with children'))
1673
1672
1674 # Currently histedit gets confused if an amend happens while histedit
1673 # Currently histedit gets confused if an amend happens while histedit
1675 # is in progress. Since we have a checkunfinished command, we are
1674 # is in progress. Since we have a checkunfinished command, we are
1676 # temporarily honoring it.
1675 # temporarily honoring it.
1677 #
1676 #
1678 # Note: eventually this guard will be removed. Please do not expect
1677 # Note: eventually this guard will be removed. Please do not expect
1679 # this behavior to remain.
1678 # this behavior to remain.
1680 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1681 cmdutil.checkunfinished(repo)
1680 cmdutil.checkunfinished(repo)
1682
1681
1683 # commitfunc is used only for temporary amend commit by cmdutil.amend
1682 # commitfunc is used only for temporary amend commit by cmdutil.amend
1684 def commitfunc(ui, repo, message, match, opts):
1683 def commitfunc(ui, repo, message, match, opts):
1685 return repo.commit(message,
1684 return repo.commit(message,
1686 opts.get('user') or old.user(),
1685 opts.get('user') or old.user(),
1687 opts.get('date') or old.date(),
1686 opts.get('date') or old.date(),
1688 match,
1687 match,
1689 extra=extra)
1688 extra=extra)
1690
1689
1691 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1690 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1692 if node == old.node():
1691 if node == old.node():
1693 ui.status(_("nothing changed\n"))
1692 ui.status(_("nothing changed\n"))
1694 return 1
1693 return 1
1695 else:
1694 else:
1696 def commitfunc(ui, repo, message, match, opts):
1695 def commitfunc(ui, repo, message, match, opts):
1697 backup = ui.backupconfig('phases', 'new-commit')
1696 backup = ui.backupconfig('phases', 'new-commit')
1698 baseui = repo.baseui
1697 baseui = repo.baseui
1699 basebackup = baseui.backupconfig('phases', 'new-commit')
1698 basebackup = baseui.backupconfig('phases', 'new-commit')
1700 try:
1699 try:
1701 if opts.get('secret'):
1700 if opts.get('secret'):
1702 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1701 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1703 # Propagate to subrepos
1702 # Propagate to subrepos
1704 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1703 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1705
1704
1706 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1705 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1707 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1706 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1708 return repo.commit(message, opts.get('user'), opts.get('date'),
1707 return repo.commit(message, opts.get('user'), opts.get('date'),
1709 match,
1708 match,
1710 editor=editor,
1709 editor=editor,
1711 extra=extra)
1710 extra=extra)
1712 finally:
1711 finally:
1713 ui.restoreconfig(backup)
1712 ui.restoreconfig(backup)
1714 repo.baseui.restoreconfig(basebackup)
1713 repo.baseui.restoreconfig(basebackup)
1715
1714
1716
1715
1717 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1716 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1718
1717
1719 if not node:
1718 if not node:
1720 stat = cmdutil.postcommitstatus(repo, pats, opts)
1719 stat = cmdutil.postcommitstatus(repo, pats, opts)
1721 if stat[3]:
1720 if stat[3]:
1722 ui.status(_("nothing changed (%d missing files, see "
1721 ui.status(_("nothing changed (%d missing files, see "
1723 "'hg status')\n") % len(stat[3]))
1722 "'hg status')\n") % len(stat[3]))
1724 else:
1723 else:
1725 ui.status(_("nothing changed\n"))
1724 ui.status(_("nothing changed\n"))
1726 return 1
1725 return 1
1727
1726
1728 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1727 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1729
1728
1730 @command('config|showconfig|debugconfig',
1729 @command('config|showconfig|debugconfig',
1731 [('u', 'untrusted', None, _('show untrusted configuration options')),
1730 [('u', 'untrusted', None, _('show untrusted configuration options')),
1732 ('e', 'edit', None, _('edit user config')),
1731 ('e', 'edit', None, _('edit user config')),
1733 ('l', 'local', None, _('edit repository config')),
1732 ('l', 'local', None, _('edit repository config')),
1734 ('g', 'global', None, _('edit global config'))] + formatteropts,
1733 ('g', 'global', None, _('edit global config'))] + formatteropts,
1735 _('[-u] [NAME]...'),
1734 _('[-u] [NAME]...'),
1736 optionalrepo=True)
1735 optionalrepo=True)
1737 def config(ui, repo, *values, **opts):
1736 def config(ui, repo, *values, **opts):
1738 """show combined config settings from all hgrc files
1737 """show combined config settings from all hgrc files
1739
1738
1740 With no arguments, print names and values of all config items.
1739 With no arguments, print names and values of all config items.
1741
1740
1742 With one argument of the form section.name, print just the value
1741 With one argument of the form section.name, print just the value
1743 of that config item.
1742 of that config item.
1744
1743
1745 With multiple arguments, print names and values of all config
1744 With multiple arguments, print names and values of all config
1746 items with matching section names.
1745 items with matching section names.
1747
1746
1748 With --edit, start an editor on the user-level config file. With
1747 With --edit, start an editor on the user-level config file. With
1749 --global, edit the system-wide config file. With --local, edit the
1748 --global, edit the system-wide config file. With --local, edit the
1750 repository-level config file.
1749 repository-level config file.
1751
1750
1752 With --debug, the source (filename and line number) is printed
1751 With --debug, the source (filename and line number) is printed
1753 for each config item.
1752 for each config item.
1754
1753
1755 See :hg:`help config` for more information about config files.
1754 See :hg:`help config` for more information about config files.
1756
1755
1757 Returns 0 on success, 1 if NAME does not exist.
1756 Returns 0 on success, 1 if NAME does not exist.
1758
1757
1759 """
1758 """
1760
1759
1761 if opts.get('edit') or opts.get('local') or opts.get('global'):
1760 if opts.get('edit') or opts.get('local') or opts.get('global'):
1762 if opts.get('local') and opts.get('global'):
1761 if opts.get('local') and opts.get('global'):
1763 raise error.Abort(_("can't use --local and --global together"))
1762 raise error.Abort(_("can't use --local and --global together"))
1764
1763
1765 if opts.get('local'):
1764 if opts.get('local'):
1766 if not repo:
1765 if not repo:
1767 raise error.Abort(_("can't use --local outside a repository"))
1766 raise error.Abort(_("can't use --local outside a repository"))
1768 paths = [repo.join('hgrc')]
1767 paths = [repo.join('hgrc')]
1769 elif opts.get('global'):
1768 elif opts.get('global'):
1770 paths = scmutil.systemrcpath()
1769 paths = scmutil.systemrcpath()
1771 else:
1770 else:
1772 paths = scmutil.userrcpath()
1771 paths = scmutil.userrcpath()
1773
1772
1774 for f in paths:
1773 for f in paths:
1775 if os.path.exists(f):
1774 if os.path.exists(f):
1776 break
1775 break
1777 else:
1776 else:
1778 if opts.get('global'):
1777 if opts.get('global'):
1779 samplehgrc = uimod.samplehgrcs['global']
1778 samplehgrc = uimod.samplehgrcs['global']
1780 elif opts.get('local'):
1779 elif opts.get('local'):
1781 samplehgrc = uimod.samplehgrcs['local']
1780 samplehgrc = uimod.samplehgrcs['local']
1782 else:
1781 else:
1783 samplehgrc = uimod.samplehgrcs['user']
1782 samplehgrc = uimod.samplehgrcs['user']
1784
1783
1785 f = paths[0]
1784 f = paths[0]
1786 fp = open(f, "w")
1785 fp = open(f, "w")
1787 fp.write(samplehgrc)
1786 fp.write(samplehgrc)
1788 fp.close()
1787 fp.close()
1789
1788
1790 editor = ui.geteditor()
1789 editor = ui.geteditor()
1791 ui.system("%s \"%s\"" % (editor, f),
1790 ui.system("%s \"%s\"" % (editor, f),
1792 onerr=error.Abort, errprefix=_("edit failed"))
1791 onerr=error.Abort, errprefix=_("edit failed"))
1793 return
1792 return
1794
1793
1795 fm = ui.formatter('config', opts)
1794 fm = ui.formatter('config', opts)
1796 for f in scmutil.rcpath():
1795 for f in scmutil.rcpath():
1797 ui.debug('read config from: %s\n' % f)
1796 ui.debug('read config from: %s\n' % f)
1798 untrusted = bool(opts.get('untrusted'))
1797 untrusted = bool(opts.get('untrusted'))
1799 if values:
1798 if values:
1800 sections = [v for v in values if '.' not in v]
1799 sections = [v for v in values if '.' not in v]
1801 items = [v for v in values if '.' in v]
1800 items = [v for v in values if '.' in v]
1802 if len(items) > 1 or items and sections:
1801 if len(items) > 1 or items and sections:
1803 raise error.Abort(_('only one config item permitted'))
1802 raise error.Abort(_('only one config item permitted'))
1804 matched = False
1803 matched = False
1805 for section, name, value in ui.walkconfig(untrusted=untrusted):
1804 for section, name, value in ui.walkconfig(untrusted=untrusted):
1806 source = ui.configsource(section, name, untrusted)
1805 source = ui.configsource(section, name, untrusted)
1807 value = str(value)
1806 value = str(value)
1808 if fm.isplain():
1807 if fm.isplain():
1809 source = source or 'none'
1808 source = source or 'none'
1810 value = value.replace('\n', '\\n')
1809 value = value.replace('\n', '\\n')
1811 entryname = section + '.' + name
1810 entryname = section + '.' + name
1812 if values:
1811 if values:
1813 for v in values:
1812 for v in values:
1814 if v == section:
1813 if v == section:
1815 fm.startitem()
1814 fm.startitem()
1816 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1815 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1817 fm.write('name value', '%s=%s\n', entryname, value)
1816 fm.write('name value', '%s=%s\n', entryname, value)
1818 matched = True
1817 matched = True
1819 elif v == entryname:
1818 elif v == entryname:
1820 fm.startitem()
1819 fm.startitem()
1821 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1820 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1822 fm.write('value', '%s\n', value)
1821 fm.write('value', '%s\n', value)
1823 fm.data(name=entryname)
1822 fm.data(name=entryname)
1824 matched = True
1823 matched = True
1825 else:
1824 else:
1826 fm.startitem()
1825 fm.startitem()
1827 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1826 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.write('name value', '%s=%s\n', entryname, value)
1827 fm.write('name value', '%s=%s\n', entryname, value)
1829 matched = True
1828 matched = True
1830 fm.end()
1829 fm.end()
1831 if matched:
1830 if matched:
1832 return 0
1831 return 0
1833 return 1
1832 return 1
1834
1833
1835 @command('copy|cp',
1834 @command('copy|cp',
1836 [('A', 'after', None, _('record a copy that has already occurred')),
1835 [('A', 'after', None, _('record a copy that has already occurred')),
1837 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1836 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1838 ] + walkopts + dryrunopts,
1837 ] + walkopts + dryrunopts,
1839 _('[OPTION]... [SOURCE]... DEST'))
1838 _('[OPTION]... [SOURCE]... DEST'))
1840 def copy(ui, repo, *pats, **opts):
1839 def copy(ui, repo, *pats, **opts):
1841 """mark files as copied for the next commit
1840 """mark files as copied for the next commit
1842
1841
1843 Mark dest as having copies of source files. If dest is a
1842 Mark dest as having copies of source files. If dest is a
1844 directory, copies are put in that directory. If dest is a file,
1843 directory, copies are put in that directory. If dest is a file,
1845 the source must be a single file.
1844 the source must be a single file.
1846
1845
1847 By default, this command copies the contents of files as they
1846 By default, this command copies the contents of files as they
1848 exist in the working directory. If invoked with -A/--after, the
1847 exist in the working directory. If invoked with -A/--after, the
1849 operation is recorded, but no copying is performed.
1848 operation is recorded, but no copying is performed.
1850
1849
1851 This command takes effect with the next commit. To undo a copy
1850 This command takes effect with the next commit. To undo a copy
1852 before that, see :hg:`revert`.
1851 before that, see :hg:`revert`.
1853
1852
1854 Returns 0 on success, 1 if errors are encountered.
1853 Returns 0 on success, 1 if errors are encountered.
1855 """
1854 """
1856 with repo.wlock(False):
1855 with repo.wlock(False):
1857 return cmdutil.copy(ui, repo, pats, opts)
1856 return cmdutil.copy(ui, repo, pats, opts)
1858
1857
1859 @command('debugrevspec',
1860 [('', 'optimize', None,
1861 _('print parsed tree after optimizing (DEPRECATED)')),
1862 ('p', 'show-stage', [],
1863 _('print parsed tree at the given stage'), _('NAME')),
1864 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1865 ('', 'verify-optimized', False, _('verify optimized result')),
1866 ],
1867 ('REVSPEC'))
1868 def debugrevspec(ui, repo, expr, **opts):
1869 """parse and apply a revision specification
1870
1871 Use -p/--show-stage option to print the parsed tree at the given stages.
1872 Use -p all to print tree at every stage.
1873
1874 Use --verify-optimized to compare the optimized result with the unoptimized
1875 one. Returns 1 if the optimized result differs.
1876 """
1877 stages = [
1878 ('parsed', lambda tree: tree),
1879 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1880 ('concatenated', revset.foldconcat),
1881 ('analyzed', revset.analyze),
1882 ('optimized', revset.optimize),
1883 ]
1884 if opts['no_optimized']:
1885 stages = stages[:-1]
1886 if opts['verify_optimized'] and opts['no_optimized']:
1887 raise error.Abort(_('cannot use --verify-optimized with '
1888 '--no-optimized'))
1889 stagenames = set(n for n, f in stages)
1890
1891 showalways = set()
1892 showchanged = set()
1893 if ui.verbose and not opts['show_stage']:
1894 # show parsed tree by --verbose (deprecated)
1895 showalways.add('parsed')
1896 showchanged.update(['expanded', 'concatenated'])
1897 if opts['optimize']:
1898 showalways.add('optimized')
1899 if opts['show_stage'] and opts['optimize']:
1900 raise error.Abort(_('cannot use --optimize with --show-stage'))
1901 if opts['show_stage'] == ['all']:
1902 showalways.update(stagenames)
1903 else:
1904 for n in opts['show_stage']:
1905 if n not in stagenames:
1906 raise error.Abort(_('invalid stage name: %s') % n)
1907 showalways.update(opts['show_stage'])
1908
1909 treebystage = {}
1910 printedtree = None
1911 tree = revset.parse(expr, lookup=repo.__contains__)
1912 for n, f in stages:
1913 treebystage[n] = tree = f(tree)
1914 if n in showalways or (n in showchanged and tree != printedtree):
1915 if opts['show_stage'] or n != 'parsed':
1916 ui.write(("* %s:\n") % n)
1917 ui.write(revset.prettyformat(tree), "\n")
1918 printedtree = tree
1919
1920 if opts['verify_optimized']:
1921 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1922 brevs = revset.makematcher(treebystage['optimized'])(repo)
1923 if ui.verbose:
1924 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1925 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1926 arevs = list(arevs)
1927 brevs = list(brevs)
1928 if arevs == brevs:
1929 return 0
1930 ui.write(('--- analyzed\n'), label='diff.file_a')
1931 ui.write(('+++ optimized\n'), label='diff.file_b')
1932 sm = difflib.SequenceMatcher(None, arevs, brevs)
1933 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1934 if tag in ('delete', 'replace'):
1935 for c in arevs[alo:ahi]:
1936 ui.write('-%s\n' % c, label='diff.deleted')
1937 if tag in ('insert', 'replace'):
1938 for c in brevs[blo:bhi]:
1939 ui.write('+%s\n' % c, label='diff.inserted')
1940 if tag == 'equal':
1941 for c in arevs[alo:ahi]:
1942 ui.write(' %s\n' % c)
1943 return 1
1944
1945 func = revset.makematcher(tree)
1946 revs = func(repo)
1947 if ui.verbose:
1948 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1949 for c in revs:
1950 ui.write("%s\n" % c)
1951
1952 @command('debugsetparents', [], _('REV1 [REV2]'))
1858 @command('debugsetparents', [], _('REV1 [REV2]'))
1953 def debugsetparents(ui, repo, rev1, rev2=None):
1859 def debugsetparents(ui, repo, rev1, rev2=None):
1954 """manually set the parents of the current working directory
1860 """manually set the parents of the current working directory
1955
1861
1956 This is useful for writing repository conversion tools, but should
1862 This is useful for writing repository conversion tools, but should
1957 be used with care. For example, neither the working directory nor the
1863 be used with care. For example, neither the working directory nor the
1958 dirstate is updated, so file status may be incorrect after running this
1864 dirstate is updated, so file status may be incorrect after running this
1959 command.
1865 command.
1960
1866
1961 Returns 0 on success.
1867 Returns 0 on success.
1962 """
1868 """
1963
1869
1964 r1 = scmutil.revsingle(repo, rev1).node()
1870 r1 = scmutil.revsingle(repo, rev1).node()
1965 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1871 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1966
1872
1967 with repo.wlock():
1873 with repo.wlock():
1968 repo.setparents(r1, r2)
1874 repo.setparents(r1, r2)
1969
1875
1970 @command('debugdirstate|debugstate',
1876 @command('debugdirstate|debugstate',
1971 [('', 'nodates', None, _('do not display the saved mtime')),
1877 [('', 'nodates', None, _('do not display the saved mtime')),
1972 ('', 'datesort', None, _('sort by saved mtime'))],
1878 ('', 'datesort', None, _('sort by saved mtime'))],
1973 _('[OPTION]...'))
1879 _('[OPTION]...'))
1974 def debugstate(ui, repo, **opts):
1880 def debugstate(ui, repo, **opts):
1975 """show the contents of the current dirstate"""
1881 """show the contents of the current dirstate"""
1976
1882
1977 nodates = opts.get('nodates')
1883 nodates = opts.get('nodates')
1978 datesort = opts.get('datesort')
1884 datesort = opts.get('datesort')
1979
1885
1980 timestr = ""
1886 timestr = ""
1981 if datesort:
1887 if datesort:
1982 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1888 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1983 else:
1889 else:
1984 keyfunc = None # sort by filename
1890 keyfunc = None # sort by filename
1985 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1891 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1986 if ent[3] == -1:
1892 if ent[3] == -1:
1987 timestr = 'unset '
1893 timestr = 'unset '
1988 elif nodates:
1894 elif nodates:
1989 timestr = 'set '
1895 timestr = 'set '
1990 else:
1896 else:
1991 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1897 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1992 time.localtime(ent[3]))
1898 time.localtime(ent[3]))
1993 if ent[1] & 0o20000:
1899 if ent[1] & 0o20000:
1994 mode = 'lnk'
1900 mode = 'lnk'
1995 else:
1901 else:
1996 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
1902 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
1997 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1903 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1998 for f in repo.dirstate.copies():
1904 for f in repo.dirstate.copies():
1999 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1905 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2000
1906
2001 @command('debugsub',
1907 @command('debugsub',
2002 [('r', 'rev', '',
1908 [('r', 'rev', '',
2003 _('revision to check'), _('REV'))],
1909 _('revision to check'), _('REV'))],
2004 _('[-r REV] [REV]'))
1910 _('[-r REV] [REV]'))
2005 def debugsub(ui, repo, rev=None):
1911 def debugsub(ui, repo, rev=None):
2006 ctx = scmutil.revsingle(repo, rev, None)
1912 ctx = scmutil.revsingle(repo, rev, None)
2007 for k, v in sorted(ctx.substate.items()):
1913 for k, v in sorted(ctx.substate.items()):
2008 ui.write(('path %s\n') % k)
1914 ui.write(('path %s\n') % k)
2009 ui.write((' source %s\n') % v[0])
1915 ui.write((' source %s\n') % v[0])
2010 ui.write((' revision %s\n') % v[1])
1916 ui.write((' revision %s\n') % v[1])
2011
1917
2012 @command('debugsuccessorssets',
1918 @command('debugsuccessorssets',
2013 [],
1919 [],
2014 _('[REV]'))
1920 _('[REV]'))
2015 def debugsuccessorssets(ui, repo, *revs):
1921 def debugsuccessorssets(ui, repo, *revs):
2016 """show set of successors for revision
1922 """show set of successors for revision
2017
1923
2018 A successors set of changeset A is a consistent group of revisions that
1924 A successors set of changeset A is a consistent group of revisions that
2019 succeed A. It contains non-obsolete changesets only.
1925 succeed A. It contains non-obsolete changesets only.
2020
1926
2021 In most cases a changeset A has a single successors set containing a single
1927 In most cases a changeset A has a single successors set containing a single
2022 successor (changeset A replaced by A').
1928 successor (changeset A replaced by A').
2023
1929
2024 A changeset that is made obsolete with no successors are called "pruned".
1930 A changeset that is made obsolete with no successors are called "pruned".
2025 Such changesets have no successors sets at all.
1931 Such changesets have no successors sets at all.
2026
1932
2027 A changeset that has been "split" will have a successors set containing
1933 A changeset that has been "split" will have a successors set containing
2028 more than one successor.
1934 more than one successor.
2029
1935
2030 A changeset that has been rewritten in multiple different ways is called
1936 A changeset that has been rewritten in multiple different ways is called
2031 "divergent". Such changesets have multiple successor sets (each of which
1937 "divergent". Such changesets have multiple successor sets (each of which
2032 may also be split, i.e. have multiple successors).
1938 may also be split, i.e. have multiple successors).
2033
1939
2034 Results are displayed as follows::
1940 Results are displayed as follows::
2035
1941
2036 <rev1>
1942 <rev1>
2037 <successors-1A>
1943 <successors-1A>
2038 <rev2>
1944 <rev2>
2039 <successors-2A>
1945 <successors-2A>
2040 <successors-2B1> <successors-2B2> <successors-2B3>
1946 <successors-2B1> <successors-2B2> <successors-2B3>
2041
1947
2042 Here rev2 has two possible (i.e. divergent) successors sets. The first
1948 Here rev2 has two possible (i.e. divergent) successors sets. The first
2043 holds one element, whereas the second holds three (i.e. the changeset has
1949 holds one element, whereas the second holds three (i.e. the changeset has
2044 been split).
1950 been split).
2045 """
1951 """
2046 # passed to successorssets caching computation from one call to another
1952 # passed to successorssets caching computation from one call to another
2047 cache = {}
1953 cache = {}
2048 ctx2str = str
1954 ctx2str = str
2049 node2str = short
1955 node2str = short
2050 if ui.debug():
1956 if ui.debug():
2051 def ctx2str(ctx):
1957 def ctx2str(ctx):
2052 return ctx.hex()
1958 return ctx.hex()
2053 node2str = hex
1959 node2str = hex
2054 for rev in scmutil.revrange(repo, revs):
1960 for rev in scmutil.revrange(repo, revs):
2055 ctx = repo[rev]
1961 ctx = repo[rev]
2056 ui.write('%s\n'% ctx2str(ctx))
1962 ui.write('%s\n'% ctx2str(ctx))
2057 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
1963 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2058 if succsset:
1964 if succsset:
2059 ui.write(' ')
1965 ui.write(' ')
2060 ui.write(node2str(succsset[0]))
1966 ui.write(node2str(succsset[0]))
2061 for node in succsset[1:]:
1967 for node in succsset[1:]:
2062 ui.write(' ')
1968 ui.write(' ')
2063 ui.write(node2str(node))
1969 ui.write(node2str(node))
2064 ui.write('\n')
1970 ui.write('\n')
2065
1971
2066 @command('debugtemplate',
1972 @command('debugtemplate',
2067 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
1973 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2068 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
1974 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2069 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
1975 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2070 optionalrepo=True)
1976 optionalrepo=True)
2071 def debugtemplate(ui, repo, tmpl, **opts):
1977 def debugtemplate(ui, repo, tmpl, **opts):
2072 """parse and apply a template
1978 """parse and apply a template
2073
1979
2074 If -r/--rev is given, the template is processed as a log template and
1980 If -r/--rev is given, the template is processed as a log template and
2075 applied to the given changesets. Otherwise, it is processed as a generic
1981 applied to the given changesets. Otherwise, it is processed as a generic
2076 template.
1982 template.
2077
1983
2078 Use --verbose to print the parsed tree.
1984 Use --verbose to print the parsed tree.
2079 """
1985 """
2080 revs = None
1986 revs = None
2081 if opts['rev']:
1987 if opts['rev']:
2082 if repo is None:
1988 if repo is None:
2083 raise error.RepoError(_('there is no Mercurial repository here '
1989 raise error.RepoError(_('there is no Mercurial repository here '
2084 '(.hg not found)'))
1990 '(.hg not found)'))
2085 revs = scmutil.revrange(repo, opts['rev'])
1991 revs = scmutil.revrange(repo, opts['rev'])
2086
1992
2087 props = {}
1993 props = {}
2088 for d in opts['define']:
1994 for d in opts['define']:
2089 try:
1995 try:
2090 k, v = (e.strip() for e in d.split('=', 1))
1996 k, v = (e.strip() for e in d.split('=', 1))
2091 if not k:
1997 if not k:
2092 raise ValueError
1998 raise ValueError
2093 props[k] = v
1999 props[k] = v
2094 except ValueError:
2000 except ValueError:
2095 raise error.Abort(_('malformed keyword definition: %s') % d)
2001 raise error.Abort(_('malformed keyword definition: %s') % d)
2096
2002
2097 if ui.verbose:
2003 if ui.verbose:
2098 aliases = ui.configitems('templatealias')
2004 aliases = ui.configitems('templatealias')
2099 tree = templater.parse(tmpl)
2005 tree = templater.parse(tmpl)
2100 ui.note(templater.prettyformat(tree), '\n')
2006 ui.note(templater.prettyformat(tree), '\n')
2101 newtree = templater.expandaliases(tree, aliases)
2007 newtree = templater.expandaliases(tree, aliases)
2102 if newtree != tree:
2008 if newtree != tree:
2103 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2009 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2104
2010
2105 mapfile = None
2011 mapfile = None
2106 if revs is None:
2012 if revs is None:
2107 k = 'debugtemplate'
2013 k = 'debugtemplate'
2108 t = formatter.maketemplater(ui, k, tmpl)
2014 t = formatter.maketemplater(ui, k, tmpl)
2109 ui.write(templater.stringify(t(k, **props)))
2015 ui.write(templater.stringify(t(k, **props)))
2110 else:
2016 else:
2111 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2017 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2112 mapfile, buffered=False)
2018 mapfile, buffered=False)
2113 for r in revs:
2019 for r in revs:
2114 displayer.show(repo[r], **props)
2020 displayer.show(repo[r], **props)
2115 displayer.close()
2021 displayer.close()
2116
2022
2117 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2023 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2118 def debugwalk(ui, repo, *pats, **opts):
2024 def debugwalk(ui, repo, *pats, **opts):
2119 """show how files match on given patterns"""
2025 """show how files match on given patterns"""
2120 m = scmutil.match(repo[None], pats, opts)
2026 m = scmutil.match(repo[None], pats, opts)
2121 items = list(repo.walk(m))
2027 items = list(repo.walk(m))
2122 if not items:
2028 if not items:
2123 return
2029 return
2124 f = lambda fn: fn
2030 f = lambda fn: fn
2125 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2031 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2126 f = lambda fn: util.normpath(fn)
2032 f = lambda fn: util.normpath(fn)
2127 fmt = 'f %%-%ds %%-%ds %%s' % (
2033 fmt = 'f %%-%ds %%-%ds %%s' % (
2128 max([len(abs) for abs in items]),
2034 max([len(abs) for abs in items]),
2129 max([len(m.rel(abs)) for abs in items]))
2035 max([len(m.rel(abs)) for abs in items]))
2130 for abs in items:
2036 for abs in items:
2131 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2037 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2132 ui.write("%s\n" % line.rstrip())
2038 ui.write("%s\n" % line.rstrip())
2133
2039
2134 @command('debugwireargs',
2040 @command('debugwireargs',
2135 [('', 'three', '', 'three'),
2041 [('', 'three', '', 'three'),
2136 ('', 'four', '', 'four'),
2042 ('', 'four', '', 'four'),
2137 ('', 'five', '', 'five'),
2043 ('', 'five', '', 'five'),
2138 ] + remoteopts,
2044 ] + remoteopts,
2139 _('REPO [OPTIONS]... [ONE [TWO]]'),
2045 _('REPO [OPTIONS]... [ONE [TWO]]'),
2140 norepo=True)
2046 norepo=True)
2141 def debugwireargs(ui, repopath, *vals, **opts):
2047 def debugwireargs(ui, repopath, *vals, **opts):
2142 repo = hg.peer(ui, opts, repopath)
2048 repo = hg.peer(ui, opts, repopath)
2143 for opt in remoteopts:
2049 for opt in remoteopts:
2144 del opts[opt[1]]
2050 del opts[opt[1]]
2145 args = {}
2051 args = {}
2146 for k, v in opts.iteritems():
2052 for k, v in opts.iteritems():
2147 if v:
2053 if v:
2148 args[k] = v
2054 args[k] = v
2149 # run twice to check that we don't mess up the stream for the next command
2055 # run twice to check that we don't mess up the stream for the next command
2150 res1 = repo.debugwireargs(*vals, **args)
2056 res1 = repo.debugwireargs(*vals, **args)
2151 res2 = repo.debugwireargs(*vals, **args)
2057 res2 = repo.debugwireargs(*vals, **args)
2152 ui.write("%s\n" % res1)
2058 ui.write("%s\n" % res1)
2153 if res1 != res2:
2059 if res1 != res2:
2154 ui.warn("%s\n" % res2)
2060 ui.warn("%s\n" % res2)
2155
2061
2156 @command('^diff',
2062 @command('^diff',
2157 [('r', 'rev', [], _('revision'), _('REV')),
2063 [('r', 'rev', [], _('revision'), _('REV')),
2158 ('c', 'change', '', _('change made by revision'), _('REV'))
2064 ('c', 'change', '', _('change made by revision'), _('REV'))
2159 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2065 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2066 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2161 inferrepo=True)
2067 inferrepo=True)
2162 def diff(ui, repo, *pats, **opts):
2068 def diff(ui, repo, *pats, **opts):
2163 """diff repository (or selected files)
2069 """diff repository (or selected files)
2164
2070
2165 Show differences between revisions for the specified files.
2071 Show differences between revisions for the specified files.
2166
2072
2167 Differences between files are shown using the unified diff format.
2073 Differences between files are shown using the unified diff format.
2168
2074
2169 .. note::
2075 .. note::
2170
2076
2171 :hg:`diff` may generate unexpected results for merges, as it will
2077 :hg:`diff` may generate unexpected results for merges, as it will
2172 default to comparing against the working directory's first
2078 default to comparing against the working directory's first
2173 parent changeset if no revisions are specified.
2079 parent changeset if no revisions are specified.
2174
2080
2175 When two revision arguments are given, then changes are shown
2081 When two revision arguments are given, then changes are shown
2176 between those revisions. If only one revision is specified then
2082 between those revisions. If only one revision is specified then
2177 that revision is compared to the working directory, and, when no
2083 that revision is compared to the working directory, and, when no
2178 revisions are specified, the working directory files are compared
2084 revisions are specified, the working directory files are compared
2179 to its first parent.
2085 to its first parent.
2180
2086
2181 Alternatively you can specify -c/--change with a revision to see
2087 Alternatively you can specify -c/--change with a revision to see
2182 the changes in that changeset relative to its first parent.
2088 the changes in that changeset relative to its first parent.
2183
2089
2184 Without the -a/--text option, diff will avoid generating diffs of
2090 Without the -a/--text option, diff will avoid generating diffs of
2185 files it detects as binary. With -a, diff will generate a diff
2091 files it detects as binary. With -a, diff will generate a diff
2186 anyway, probably with undesirable results.
2092 anyway, probably with undesirable results.
2187
2093
2188 Use the -g/--git option to generate diffs in the git extended diff
2094 Use the -g/--git option to generate diffs in the git extended diff
2189 format. For more information, read :hg:`help diffs`.
2095 format. For more information, read :hg:`help diffs`.
2190
2096
2191 .. container:: verbose
2097 .. container:: verbose
2192
2098
2193 Examples:
2099 Examples:
2194
2100
2195 - compare a file in the current working directory to its parent::
2101 - compare a file in the current working directory to its parent::
2196
2102
2197 hg diff foo.c
2103 hg diff foo.c
2198
2104
2199 - compare two historical versions of a directory, with rename info::
2105 - compare two historical versions of a directory, with rename info::
2200
2106
2201 hg diff --git -r 1.0:1.2 lib/
2107 hg diff --git -r 1.0:1.2 lib/
2202
2108
2203 - get change stats relative to the last change on some date::
2109 - get change stats relative to the last change on some date::
2204
2110
2205 hg diff --stat -r "date('may 2')"
2111 hg diff --stat -r "date('may 2')"
2206
2112
2207 - diff all newly-added files that contain a keyword::
2113 - diff all newly-added files that contain a keyword::
2208
2114
2209 hg diff "set:added() and grep(GNU)"
2115 hg diff "set:added() and grep(GNU)"
2210
2116
2211 - compare a revision and its parents::
2117 - compare a revision and its parents::
2212
2118
2213 hg diff -c 9353 # compare against first parent
2119 hg diff -c 9353 # compare against first parent
2214 hg diff -r 9353^:9353 # same using revset syntax
2120 hg diff -r 9353^:9353 # same using revset syntax
2215 hg diff -r 9353^2:9353 # compare against the second parent
2121 hg diff -r 9353^2:9353 # compare against the second parent
2216
2122
2217 Returns 0 on success.
2123 Returns 0 on success.
2218 """
2124 """
2219
2125
2220 revs = opts.get('rev')
2126 revs = opts.get('rev')
2221 change = opts.get('change')
2127 change = opts.get('change')
2222 stat = opts.get('stat')
2128 stat = opts.get('stat')
2223 reverse = opts.get('reverse')
2129 reverse = opts.get('reverse')
2224
2130
2225 if revs and change:
2131 if revs and change:
2226 msg = _('cannot specify --rev and --change at the same time')
2132 msg = _('cannot specify --rev and --change at the same time')
2227 raise error.Abort(msg)
2133 raise error.Abort(msg)
2228 elif change:
2134 elif change:
2229 node2 = scmutil.revsingle(repo, change, None).node()
2135 node2 = scmutil.revsingle(repo, change, None).node()
2230 node1 = repo[node2].p1().node()
2136 node1 = repo[node2].p1().node()
2231 else:
2137 else:
2232 node1, node2 = scmutil.revpair(repo, revs)
2138 node1, node2 = scmutil.revpair(repo, revs)
2233
2139
2234 if reverse:
2140 if reverse:
2235 node1, node2 = node2, node1
2141 node1, node2 = node2, node1
2236
2142
2237 diffopts = patch.diffallopts(ui, opts)
2143 diffopts = patch.diffallopts(ui, opts)
2238 m = scmutil.match(repo[node2], pats, opts)
2144 m = scmutil.match(repo[node2], pats, opts)
2239 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2145 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2240 listsubrepos=opts.get('subrepos'),
2146 listsubrepos=opts.get('subrepos'),
2241 root=opts.get('root'))
2147 root=opts.get('root'))
2242
2148
2243 @command('^export',
2149 @command('^export',
2244 [('o', 'output', '',
2150 [('o', 'output', '',
2245 _('print output to file with formatted name'), _('FORMAT')),
2151 _('print output to file with formatted name'), _('FORMAT')),
2246 ('', 'switch-parent', None, _('diff against the second parent')),
2152 ('', 'switch-parent', None, _('diff against the second parent')),
2247 ('r', 'rev', [], _('revisions to export'), _('REV')),
2153 ('r', 'rev', [], _('revisions to export'), _('REV')),
2248 ] + diffopts,
2154 ] + diffopts,
2249 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2155 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2250 def export(ui, repo, *changesets, **opts):
2156 def export(ui, repo, *changesets, **opts):
2251 """dump the header and diffs for one or more changesets
2157 """dump the header and diffs for one or more changesets
2252
2158
2253 Print the changeset header and diffs for one or more revisions.
2159 Print the changeset header and diffs for one or more revisions.
2254 If no revision is given, the parent of the working directory is used.
2160 If no revision is given, the parent of the working directory is used.
2255
2161
2256 The information shown in the changeset header is: author, date,
2162 The information shown in the changeset header is: author, date,
2257 branch name (if non-default), changeset hash, parent(s) and commit
2163 branch name (if non-default), changeset hash, parent(s) and commit
2258 comment.
2164 comment.
2259
2165
2260 .. note::
2166 .. note::
2261
2167
2262 :hg:`export` may generate unexpected diff output for merge
2168 :hg:`export` may generate unexpected diff output for merge
2263 changesets, as it will compare the merge changeset against its
2169 changesets, as it will compare the merge changeset against its
2264 first parent only.
2170 first parent only.
2265
2171
2266 Output may be to a file, in which case the name of the file is
2172 Output may be to a file, in which case the name of the file is
2267 given using a format string. The formatting rules are as follows:
2173 given using a format string. The formatting rules are as follows:
2268
2174
2269 :``%%``: literal "%" character
2175 :``%%``: literal "%" character
2270 :``%H``: changeset hash (40 hexadecimal digits)
2176 :``%H``: changeset hash (40 hexadecimal digits)
2271 :``%N``: number of patches being generated
2177 :``%N``: number of patches being generated
2272 :``%R``: changeset revision number
2178 :``%R``: changeset revision number
2273 :``%b``: basename of the exporting repository
2179 :``%b``: basename of the exporting repository
2274 :``%h``: short-form changeset hash (12 hexadecimal digits)
2180 :``%h``: short-form changeset hash (12 hexadecimal digits)
2275 :``%m``: first line of the commit message (only alphanumeric characters)
2181 :``%m``: first line of the commit message (only alphanumeric characters)
2276 :``%n``: zero-padded sequence number, starting at 1
2182 :``%n``: zero-padded sequence number, starting at 1
2277 :``%r``: zero-padded changeset revision number
2183 :``%r``: zero-padded changeset revision number
2278
2184
2279 Without the -a/--text option, export will avoid generating diffs
2185 Without the -a/--text option, export will avoid generating diffs
2280 of files it detects as binary. With -a, export will generate a
2186 of files it detects as binary. With -a, export will generate a
2281 diff anyway, probably with undesirable results.
2187 diff anyway, probably with undesirable results.
2282
2188
2283 Use the -g/--git option to generate diffs in the git extended diff
2189 Use the -g/--git option to generate diffs in the git extended diff
2284 format. See :hg:`help diffs` for more information.
2190 format. See :hg:`help diffs` for more information.
2285
2191
2286 With the --switch-parent option, the diff will be against the
2192 With the --switch-parent option, the diff will be against the
2287 second parent. It can be useful to review a merge.
2193 second parent. It can be useful to review a merge.
2288
2194
2289 .. container:: verbose
2195 .. container:: verbose
2290
2196
2291 Examples:
2197 Examples:
2292
2198
2293 - use export and import to transplant a bugfix to the current
2199 - use export and import to transplant a bugfix to the current
2294 branch::
2200 branch::
2295
2201
2296 hg export -r 9353 | hg import -
2202 hg export -r 9353 | hg import -
2297
2203
2298 - export all the changesets between two revisions to a file with
2204 - export all the changesets between two revisions to a file with
2299 rename information::
2205 rename information::
2300
2206
2301 hg export --git -r 123:150 > changes.txt
2207 hg export --git -r 123:150 > changes.txt
2302
2208
2303 - split outgoing changes into a series of patches with
2209 - split outgoing changes into a series of patches with
2304 descriptive names::
2210 descriptive names::
2305
2211
2306 hg export -r "outgoing()" -o "%n-%m.patch"
2212 hg export -r "outgoing()" -o "%n-%m.patch"
2307
2213
2308 Returns 0 on success.
2214 Returns 0 on success.
2309 """
2215 """
2310 changesets += tuple(opts.get('rev', []))
2216 changesets += tuple(opts.get('rev', []))
2311 if not changesets:
2217 if not changesets:
2312 changesets = ['.']
2218 changesets = ['.']
2313 revs = scmutil.revrange(repo, changesets)
2219 revs = scmutil.revrange(repo, changesets)
2314 if not revs:
2220 if not revs:
2315 raise error.Abort(_("export requires at least one changeset"))
2221 raise error.Abort(_("export requires at least one changeset"))
2316 if len(revs) > 1:
2222 if len(revs) > 1:
2317 ui.note(_('exporting patches:\n'))
2223 ui.note(_('exporting patches:\n'))
2318 else:
2224 else:
2319 ui.note(_('exporting patch:\n'))
2225 ui.note(_('exporting patch:\n'))
2320 cmdutil.export(repo, revs, template=opts.get('output'),
2226 cmdutil.export(repo, revs, template=opts.get('output'),
2321 switch_parent=opts.get('switch_parent'),
2227 switch_parent=opts.get('switch_parent'),
2322 opts=patch.diffallopts(ui, opts))
2228 opts=patch.diffallopts(ui, opts))
2323
2229
2324 @command('files',
2230 @command('files',
2325 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2231 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2326 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2232 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2327 ] + walkopts + formatteropts + subrepoopts,
2233 ] + walkopts + formatteropts + subrepoopts,
2328 _('[OPTION]... [FILE]...'))
2234 _('[OPTION]... [FILE]...'))
2329 def files(ui, repo, *pats, **opts):
2235 def files(ui, repo, *pats, **opts):
2330 """list tracked files
2236 """list tracked files
2331
2237
2332 Print files under Mercurial control in the working directory or
2238 Print files under Mercurial control in the working directory or
2333 specified revision for given files (excluding removed files).
2239 specified revision for given files (excluding removed files).
2334 Files can be specified as filenames or filesets.
2240 Files can be specified as filenames or filesets.
2335
2241
2336 If no files are given to match, this command prints the names
2242 If no files are given to match, this command prints the names
2337 of all files under Mercurial control.
2243 of all files under Mercurial control.
2338
2244
2339 .. container:: verbose
2245 .. container:: verbose
2340
2246
2341 Examples:
2247 Examples:
2342
2248
2343 - list all files under the current directory::
2249 - list all files under the current directory::
2344
2250
2345 hg files .
2251 hg files .
2346
2252
2347 - shows sizes and flags for current revision::
2253 - shows sizes and flags for current revision::
2348
2254
2349 hg files -vr .
2255 hg files -vr .
2350
2256
2351 - list all files named README::
2257 - list all files named README::
2352
2258
2353 hg files -I "**/README"
2259 hg files -I "**/README"
2354
2260
2355 - list all binary files::
2261 - list all binary files::
2356
2262
2357 hg files "set:binary()"
2263 hg files "set:binary()"
2358
2264
2359 - find files containing a regular expression::
2265 - find files containing a regular expression::
2360
2266
2361 hg files "set:grep('bob')"
2267 hg files "set:grep('bob')"
2362
2268
2363 - search tracked file contents with xargs and grep::
2269 - search tracked file contents with xargs and grep::
2364
2270
2365 hg files -0 | xargs -0 grep foo
2271 hg files -0 | xargs -0 grep foo
2366
2272
2367 See :hg:`help patterns` and :hg:`help filesets` for more information
2273 See :hg:`help patterns` and :hg:`help filesets` for more information
2368 on specifying file patterns.
2274 on specifying file patterns.
2369
2275
2370 Returns 0 if a match is found, 1 otherwise.
2276 Returns 0 if a match is found, 1 otherwise.
2371
2277
2372 """
2278 """
2373 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2279 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2374
2280
2375 end = '\n'
2281 end = '\n'
2376 if opts.get('print0'):
2282 if opts.get('print0'):
2377 end = '\0'
2283 end = '\0'
2378 fmt = '%s' + end
2284 fmt = '%s' + end
2379
2285
2380 m = scmutil.match(ctx, pats, opts)
2286 m = scmutil.match(ctx, pats, opts)
2381 with ui.formatter('files', opts) as fm:
2287 with ui.formatter('files', opts) as fm:
2382 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2288 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2383
2289
2384 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2290 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2385 def forget(ui, repo, *pats, **opts):
2291 def forget(ui, repo, *pats, **opts):
2386 """forget the specified files on the next commit
2292 """forget the specified files on the next commit
2387
2293
2388 Mark the specified files so they will no longer be tracked
2294 Mark the specified files so they will no longer be tracked
2389 after the next commit.
2295 after the next commit.
2390
2296
2391 This only removes files from the current branch, not from the
2297 This only removes files from the current branch, not from the
2392 entire project history, and it does not delete them from the
2298 entire project history, and it does not delete them from the
2393 working directory.
2299 working directory.
2394
2300
2395 To delete the file from the working directory, see :hg:`remove`.
2301 To delete the file from the working directory, see :hg:`remove`.
2396
2302
2397 To undo a forget before the next commit, see :hg:`add`.
2303 To undo a forget before the next commit, see :hg:`add`.
2398
2304
2399 .. container:: verbose
2305 .. container:: verbose
2400
2306
2401 Examples:
2307 Examples:
2402
2308
2403 - forget newly-added binary files::
2309 - forget newly-added binary files::
2404
2310
2405 hg forget "set:added() and binary()"
2311 hg forget "set:added() and binary()"
2406
2312
2407 - forget files that would be excluded by .hgignore::
2313 - forget files that would be excluded by .hgignore::
2408
2314
2409 hg forget "set:hgignore()"
2315 hg forget "set:hgignore()"
2410
2316
2411 Returns 0 on success.
2317 Returns 0 on success.
2412 """
2318 """
2413
2319
2414 if not pats:
2320 if not pats:
2415 raise error.Abort(_('no files specified'))
2321 raise error.Abort(_('no files specified'))
2416
2322
2417 m = scmutil.match(repo[None], pats, opts)
2323 m = scmutil.match(repo[None], pats, opts)
2418 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2324 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2419 return rejected and 1 or 0
2325 return rejected and 1 or 0
2420
2326
2421 @command(
2327 @command(
2422 'graft',
2328 'graft',
2423 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2329 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2424 ('c', 'continue', False, _('resume interrupted graft')),
2330 ('c', 'continue', False, _('resume interrupted graft')),
2425 ('e', 'edit', False, _('invoke editor on commit messages')),
2331 ('e', 'edit', False, _('invoke editor on commit messages')),
2426 ('', 'log', None, _('append graft info to log message')),
2332 ('', 'log', None, _('append graft info to log message')),
2427 ('f', 'force', False, _('force graft')),
2333 ('f', 'force', False, _('force graft')),
2428 ('D', 'currentdate', False,
2334 ('D', 'currentdate', False,
2429 _('record the current date as commit date')),
2335 _('record the current date as commit date')),
2430 ('U', 'currentuser', False,
2336 ('U', 'currentuser', False,
2431 _('record the current user as committer'), _('DATE'))]
2337 _('record the current user as committer'), _('DATE'))]
2432 + commitopts2 + mergetoolopts + dryrunopts,
2338 + commitopts2 + mergetoolopts + dryrunopts,
2433 _('[OPTION]... [-r REV]... REV...'))
2339 _('[OPTION]... [-r REV]... REV...'))
2434 def graft(ui, repo, *revs, **opts):
2340 def graft(ui, repo, *revs, **opts):
2435 '''copy changes from other branches onto the current branch
2341 '''copy changes from other branches onto the current branch
2436
2342
2437 This command uses Mercurial's merge logic to copy individual
2343 This command uses Mercurial's merge logic to copy individual
2438 changes from other branches without merging branches in the
2344 changes from other branches without merging branches in the
2439 history graph. This is sometimes known as 'backporting' or
2345 history graph. This is sometimes known as 'backporting' or
2440 'cherry-picking'. By default, graft will copy user, date, and
2346 'cherry-picking'. By default, graft will copy user, date, and
2441 description from the source changesets.
2347 description from the source changesets.
2442
2348
2443 Changesets that are ancestors of the current revision, that have
2349 Changesets that are ancestors of the current revision, that have
2444 already been grafted, or that are merges will be skipped.
2350 already been grafted, or that are merges will be skipped.
2445
2351
2446 If --log is specified, log messages will have a comment appended
2352 If --log is specified, log messages will have a comment appended
2447 of the form::
2353 of the form::
2448
2354
2449 (grafted from CHANGESETHASH)
2355 (grafted from CHANGESETHASH)
2450
2356
2451 If --force is specified, revisions will be grafted even if they
2357 If --force is specified, revisions will be grafted even if they
2452 are already ancestors of or have been grafted to the destination.
2358 are already ancestors of or have been grafted to the destination.
2453 This is useful when the revisions have since been backed out.
2359 This is useful when the revisions have since been backed out.
2454
2360
2455 If a graft merge results in conflicts, the graft process is
2361 If a graft merge results in conflicts, the graft process is
2456 interrupted so that the current merge can be manually resolved.
2362 interrupted so that the current merge can be manually resolved.
2457 Once all conflicts are addressed, the graft process can be
2363 Once all conflicts are addressed, the graft process can be
2458 continued with the -c/--continue option.
2364 continued with the -c/--continue option.
2459
2365
2460 .. note::
2366 .. note::
2461
2367
2462 The -c/--continue option does not reapply earlier options, except
2368 The -c/--continue option does not reapply earlier options, except
2463 for --force.
2369 for --force.
2464
2370
2465 .. container:: verbose
2371 .. container:: verbose
2466
2372
2467 Examples:
2373 Examples:
2468
2374
2469 - copy a single change to the stable branch and edit its description::
2375 - copy a single change to the stable branch and edit its description::
2470
2376
2471 hg update stable
2377 hg update stable
2472 hg graft --edit 9393
2378 hg graft --edit 9393
2473
2379
2474 - graft a range of changesets with one exception, updating dates::
2380 - graft a range of changesets with one exception, updating dates::
2475
2381
2476 hg graft -D "2085::2093 and not 2091"
2382 hg graft -D "2085::2093 and not 2091"
2477
2383
2478 - continue a graft after resolving conflicts::
2384 - continue a graft after resolving conflicts::
2479
2385
2480 hg graft -c
2386 hg graft -c
2481
2387
2482 - show the source of a grafted changeset::
2388 - show the source of a grafted changeset::
2483
2389
2484 hg log --debug -r .
2390 hg log --debug -r .
2485
2391
2486 - show revisions sorted by date::
2392 - show revisions sorted by date::
2487
2393
2488 hg log -r "sort(all(), date)"
2394 hg log -r "sort(all(), date)"
2489
2395
2490 See :hg:`help revisions` for more about specifying revisions.
2396 See :hg:`help revisions` for more about specifying revisions.
2491
2397
2492 Returns 0 on successful completion.
2398 Returns 0 on successful completion.
2493 '''
2399 '''
2494 with repo.wlock():
2400 with repo.wlock():
2495 return _dograft(ui, repo, *revs, **opts)
2401 return _dograft(ui, repo, *revs, **opts)
2496
2402
2497 def _dograft(ui, repo, *revs, **opts):
2403 def _dograft(ui, repo, *revs, **opts):
2498 if revs and opts.get('rev'):
2404 if revs and opts.get('rev'):
2499 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2405 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2500 'revision ordering!\n'))
2406 'revision ordering!\n'))
2501
2407
2502 revs = list(revs)
2408 revs = list(revs)
2503 revs.extend(opts.get('rev'))
2409 revs.extend(opts.get('rev'))
2504
2410
2505 if not opts.get('user') and opts.get('currentuser'):
2411 if not opts.get('user') and opts.get('currentuser'):
2506 opts['user'] = ui.username()
2412 opts['user'] = ui.username()
2507 if not opts.get('date') and opts.get('currentdate'):
2413 if not opts.get('date') and opts.get('currentdate'):
2508 opts['date'] = "%d %d" % util.makedate()
2414 opts['date'] = "%d %d" % util.makedate()
2509
2415
2510 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2416 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2511
2417
2512 cont = False
2418 cont = False
2513 if opts.get('continue'):
2419 if opts.get('continue'):
2514 cont = True
2420 cont = True
2515 if revs:
2421 if revs:
2516 raise error.Abort(_("can't specify --continue and revisions"))
2422 raise error.Abort(_("can't specify --continue and revisions"))
2517 # read in unfinished revisions
2423 # read in unfinished revisions
2518 try:
2424 try:
2519 nodes = repo.vfs.read('graftstate').splitlines()
2425 nodes = repo.vfs.read('graftstate').splitlines()
2520 revs = [repo[node].rev() for node in nodes]
2426 revs = [repo[node].rev() for node in nodes]
2521 except IOError as inst:
2427 except IOError as inst:
2522 if inst.errno != errno.ENOENT:
2428 if inst.errno != errno.ENOENT:
2523 raise
2429 raise
2524 cmdutil.wrongtooltocontinue(repo, _('graft'))
2430 cmdutil.wrongtooltocontinue(repo, _('graft'))
2525 else:
2431 else:
2526 cmdutil.checkunfinished(repo)
2432 cmdutil.checkunfinished(repo)
2527 cmdutil.bailifchanged(repo)
2433 cmdutil.bailifchanged(repo)
2528 if not revs:
2434 if not revs:
2529 raise error.Abort(_('no revisions specified'))
2435 raise error.Abort(_('no revisions specified'))
2530 revs = scmutil.revrange(repo, revs)
2436 revs = scmutil.revrange(repo, revs)
2531
2437
2532 skipped = set()
2438 skipped = set()
2533 # check for merges
2439 # check for merges
2534 for rev in repo.revs('%ld and merge()', revs):
2440 for rev in repo.revs('%ld and merge()', revs):
2535 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2441 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2536 skipped.add(rev)
2442 skipped.add(rev)
2537 revs = [r for r in revs if r not in skipped]
2443 revs = [r for r in revs if r not in skipped]
2538 if not revs:
2444 if not revs:
2539 return -1
2445 return -1
2540
2446
2541 # Don't check in the --continue case, in effect retaining --force across
2447 # Don't check in the --continue case, in effect retaining --force across
2542 # --continues. That's because without --force, any revisions we decided to
2448 # --continues. That's because without --force, any revisions we decided to
2543 # skip would have been filtered out here, so they wouldn't have made their
2449 # skip would have been filtered out here, so they wouldn't have made their
2544 # way to the graftstate. With --force, any revisions we would have otherwise
2450 # way to the graftstate. With --force, any revisions we would have otherwise
2545 # skipped would not have been filtered out, and if they hadn't been applied
2451 # skipped would not have been filtered out, and if they hadn't been applied
2546 # already, they'd have been in the graftstate.
2452 # already, they'd have been in the graftstate.
2547 if not (cont or opts.get('force')):
2453 if not (cont or opts.get('force')):
2548 # check for ancestors of dest branch
2454 # check for ancestors of dest branch
2549 crev = repo['.'].rev()
2455 crev = repo['.'].rev()
2550 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2456 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2551 # XXX make this lazy in the future
2457 # XXX make this lazy in the future
2552 # don't mutate while iterating, create a copy
2458 # don't mutate while iterating, create a copy
2553 for rev in list(revs):
2459 for rev in list(revs):
2554 if rev in ancestors:
2460 if rev in ancestors:
2555 ui.warn(_('skipping ancestor revision %d:%s\n') %
2461 ui.warn(_('skipping ancestor revision %d:%s\n') %
2556 (rev, repo[rev]))
2462 (rev, repo[rev]))
2557 # XXX remove on list is slow
2463 # XXX remove on list is slow
2558 revs.remove(rev)
2464 revs.remove(rev)
2559 if not revs:
2465 if not revs:
2560 return -1
2466 return -1
2561
2467
2562 # analyze revs for earlier grafts
2468 # analyze revs for earlier grafts
2563 ids = {}
2469 ids = {}
2564 for ctx in repo.set("%ld", revs):
2470 for ctx in repo.set("%ld", revs):
2565 ids[ctx.hex()] = ctx.rev()
2471 ids[ctx.hex()] = ctx.rev()
2566 n = ctx.extra().get('source')
2472 n = ctx.extra().get('source')
2567 if n:
2473 if n:
2568 ids[n] = ctx.rev()
2474 ids[n] = ctx.rev()
2569
2475
2570 # check ancestors for earlier grafts
2476 # check ancestors for earlier grafts
2571 ui.debug('scanning for duplicate grafts\n')
2477 ui.debug('scanning for duplicate grafts\n')
2572
2478
2573 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2479 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2574 ctx = repo[rev]
2480 ctx = repo[rev]
2575 n = ctx.extra().get('source')
2481 n = ctx.extra().get('source')
2576 if n in ids:
2482 if n in ids:
2577 try:
2483 try:
2578 r = repo[n].rev()
2484 r = repo[n].rev()
2579 except error.RepoLookupError:
2485 except error.RepoLookupError:
2580 r = None
2486 r = None
2581 if r in revs:
2487 if r in revs:
2582 ui.warn(_('skipping revision %d:%s '
2488 ui.warn(_('skipping revision %d:%s '
2583 '(already grafted to %d:%s)\n')
2489 '(already grafted to %d:%s)\n')
2584 % (r, repo[r], rev, ctx))
2490 % (r, repo[r], rev, ctx))
2585 revs.remove(r)
2491 revs.remove(r)
2586 elif ids[n] in revs:
2492 elif ids[n] in revs:
2587 if r is None:
2493 if r is None:
2588 ui.warn(_('skipping already grafted revision %d:%s '
2494 ui.warn(_('skipping already grafted revision %d:%s '
2589 '(%d:%s also has unknown origin %s)\n')
2495 '(%d:%s also has unknown origin %s)\n')
2590 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2496 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2591 else:
2497 else:
2592 ui.warn(_('skipping already grafted revision %d:%s '
2498 ui.warn(_('skipping already grafted revision %d:%s '
2593 '(%d:%s also has origin %d:%s)\n')
2499 '(%d:%s also has origin %d:%s)\n')
2594 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2500 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2595 revs.remove(ids[n])
2501 revs.remove(ids[n])
2596 elif ctx.hex() in ids:
2502 elif ctx.hex() in ids:
2597 r = ids[ctx.hex()]
2503 r = ids[ctx.hex()]
2598 ui.warn(_('skipping already grafted revision %d:%s '
2504 ui.warn(_('skipping already grafted revision %d:%s '
2599 '(was grafted from %d:%s)\n') %
2505 '(was grafted from %d:%s)\n') %
2600 (r, repo[r], rev, ctx))
2506 (r, repo[r], rev, ctx))
2601 revs.remove(r)
2507 revs.remove(r)
2602 if not revs:
2508 if not revs:
2603 return -1
2509 return -1
2604
2510
2605 for pos, ctx in enumerate(repo.set("%ld", revs)):
2511 for pos, ctx in enumerate(repo.set("%ld", revs)):
2606 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2512 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2607 ctx.description().split('\n', 1)[0])
2513 ctx.description().split('\n', 1)[0])
2608 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2514 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2609 if names:
2515 if names:
2610 desc += ' (%s)' % ' '.join(names)
2516 desc += ' (%s)' % ' '.join(names)
2611 ui.status(_('grafting %s\n') % desc)
2517 ui.status(_('grafting %s\n') % desc)
2612 if opts.get('dry_run'):
2518 if opts.get('dry_run'):
2613 continue
2519 continue
2614
2520
2615 source = ctx.extra().get('source')
2521 source = ctx.extra().get('source')
2616 extra = {}
2522 extra = {}
2617 if source:
2523 if source:
2618 extra['source'] = source
2524 extra['source'] = source
2619 extra['intermediate-source'] = ctx.hex()
2525 extra['intermediate-source'] = ctx.hex()
2620 else:
2526 else:
2621 extra['source'] = ctx.hex()
2527 extra['source'] = ctx.hex()
2622 user = ctx.user()
2528 user = ctx.user()
2623 if opts.get('user'):
2529 if opts.get('user'):
2624 user = opts['user']
2530 user = opts['user']
2625 date = ctx.date()
2531 date = ctx.date()
2626 if opts.get('date'):
2532 if opts.get('date'):
2627 date = opts['date']
2533 date = opts['date']
2628 message = ctx.description()
2534 message = ctx.description()
2629 if opts.get('log'):
2535 if opts.get('log'):
2630 message += '\n(grafted from %s)' % ctx.hex()
2536 message += '\n(grafted from %s)' % ctx.hex()
2631
2537
2632 # we don't merge the first commit when continuing
2538 # we don't merge the first commit when continuing
2633 if not cont:
2539 if not cont:
2634 # perform the graft merge with p1(rev) as 'ancestor'
2540 # perform the graft merge with p1(rev) as 'ancestor'
2635 try:
2541 try:
2636 # ui.forcemerge is an internal variable, do not document
2542 # ui.forcemerge is an internal variable, do not document
2637 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2543 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2638 'graft')
2544 'graft')
2639 stats = mergemod.graft(repo, ctx, ctx.p1(),
2545 stats = mergemod.graft(repo, ctx, ctx.p1(),
2640 ['local', 'graft'])
2546 ['local', 'graft'])
2641 finally:
2547 finally:
2642 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2548 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2643 # report any conflicts
2549 # report any conflicts
2644 if stats and stats[3] > 0:
2550 if stats and stats[3] > 0:
2645 # write out state for --continue
2551 # write out state for --continue
2646 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2552 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2647 repo.vfs.write('graftstate', ''.join(nodelines))
2553 repo.vfs.write('graftstate', ''.join(nodelines))
2648 extra = ''
2554 extra = ''
2649 if opts.get('user'):
2555 if opts.get('user'):
2650 extra += ' --user %s' % util.shellquote(opts['user'])
2556 extra += ' --user %s' % util.shellquote(opts['user'])
2651 if opts.get('date'):
2557 if opts.get('date'):
2652 extra += ' --date %s' % util.shellquote(opts['date'])
2558 extra += ' --date %s' % util.shellquote(opts['date'])
2653 if opts.get('log'):
2559 if opts.get('log'):
2654 extra += ' --log'
2560 extra += ' --log'
2655 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2561 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2656 raise error.Abort(
2562 raise error.Abort(
2657 _("unresolved conflicts, can't continue"),
2563 _("unresolved conflicts, can't continue"),
2658 hint=hint)
2564 hint=hint)
2659 else:
2565 else:
2660 cont = False
2566 cont = False
2661
2567
2662 # commit
2568 # commit
2663 node = repo.commit(text=message, user=user,
2569 node = repo.commit(text=message, user=user,
2664 date=date, extra=extra, editor=editor)
2570 date=date, extra=extra, editor=editor)
2665 if node is None:
2571 if node is None:
2666 ui.warn(
2572 ui.warn(
2667 _('note: graft of %d:%s created no changes to commit\n') %
2573 _('note: graft of %d:%s created no changes to commit\n') %
2668 (ctx.rev(), ctx))
2574 (ctx.rev(), ctx))
2669
2575
2670 # remove state when we complete successfully
2576 # remove state when we complete successfully
2671 if not opts.get('dry_run'):
2577 if not opts.get('dry_run'):
2672 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2578 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2673
2579
2674 return 0
2580 return 0
2675
2581
2676 @command('grep',
2582 @command('grep',
2677 [('0', 'print0', None, _('end fields with NUL')),
2583 [('0', 'print0', None, _('end fields with NUL')),
2678 ('', 'all', None, _('print all revisions that match')),
2584 ('', 'all', None, _('print all revisions that match')),
2679 ('a', 'text', None, _('treat all files as text')),
2585 ('a', 'text', None, _('treat all files as text')),
2680 ('f', 'follow', None,
2586 ('f', 'follow', None,
2681 _('follow changeset history,'
2587 _('follow changeset history,'
2682 ' or file history across copies and renames')),
2588 ' or file history across copies and renames')),
2683 ('i', 'ignore-case', None, _('ignore case when matching')),
2589 ('i', 'ignore-case', None, _('ignore case when matching')),
2684 ('l', 'files-with-matches', None,
2590 ('l', 'files-with-matches', None,
2685 _('print only filenames and revisions that match')),
2591 _('print only filenames and revisions that match')),
2686 ('n', 'line-number', None, _('print matching line numbers')),
2592 ('n', 'line-number', None, _('print matching line numbers')),
2687 ('r', 'rev', [],
2593 ('r', 'rev', [],
2688 _('only search files changed within revision range'), _('REV')),
2594 _('only search files changed within revision range'), _('REV')),
2689 ('u', 'user', None, _('list the author (long with -v)')),
2595 ('u', 'user', None, _('list the author (long with -v)')),
2690 ('d', 'date', None, _('list the date (short with -q)')),
2596 ('d', 'date', None, _('list the date (short with -q)')),
2691 ] + formatteropts + walkopts,
2597 ] + formatteropts + walkopts,
2692 _('[OPTION]... PATTERN [FILE]...'),
2598 _('[OPTION]... PATTERN [FILE]...'),
2693 inferrepo=True)
2599 inferrepo=True)
2694 def grep(ui, repo, pattern, *pats, **opts):
2600 def grep(ui, repo, pattern, *pats, **opts):
2695 """search revision history for a pattern in specified files
2601 """search revision history for a pattern in specified files
2696
2602
2697 Search revision history for a regular expression in the specified
2603 Search revision history for a regular expression in the specified
2698 files or the entire project.
2604 files or the entire project.
2699
2605
2700 By default, grep prints the most recent revision number for each
2606 By default, grep prints the most recent revision number for each
2701 file in which it finds a match. To get it to print every revision
2607 file in which it finds a match. To get it to print every revision
2702 that contains a change in match status ("-" for a match that becomes
2608 that contains a change in match status ("-" for a match that becomes
2703 a non-match, or "+" for a non-match that becomes a match), use the
2609 a non-match, or "+" for a non-match that becomes a match), use the
2704 --all flag.
2610 --all flag.
2705
2611
2706 PATTERN can be any Python (roughly Perl-compatible) regular
2612 PATTERN can be any Python (roughly Perl-compatible) regular
2707 expression.
2613 expression.
2708
2614
2709 If no FILEs are specified (and -f/--follow isn't set), all files in
2615 If no FILEs are specified (and -f/--follow isn't set), all files in
2710 the repository are searched, including those that don't exist in the
2616 the repository are searched, including those that don't exist in the
2711 current branch or have been deleted in a prior changeset.
2617 current branch or have been deleted in a prior changeset.
2712
2618
2713 Returns 0 if a match is found, 1 otherwise.
2619 Returns 0 if a match is found, 1 otherwise.
2714 """
2620 """
2715 reflags = re.M
2621 reflags = re.M
2716 if opts.get('ignore_case'):
2622 if opts.get('ignore_case'):
2717 reflags |= re.I
2623 reflags |= re.I
2718 try:
2624 try:
2719 regexp = util.re.compile(pattern, reflags)
2625 regexp = util.re.compile(pattern, reflags)
2720 except re.error as inst:
2626 except re.error as inst:
2721 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2627 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2722 return 1
2628 return 1
2723 sep, eol = ':', '\n'
2629 sep, eol = ':', '\n'
2724 if opts.get('print0'):
2630 if opts.get('print0'):
2725 sep = eol = '\0'
2631 sep = eol = '\0'
2726
2632
2727 getfile = util.lrucachefunc(repo.file)
2633 getfile = util.lrucachefunc(repo.file)
2728
2634
2729 def matchlines(body):
2635 def matchlines(body):
2730 begin = 0
2636 begin = 0
2731 linenum = 0
2637 linenum = 0
2732 while begin < len(body):
2638 while begin < len(body):
2733 match = regexp.search(body, begin)
2639 match = regexp.search(body, begin)
2734 if not match:
2640 if not match:
2735 break
2641 break
2736 mstart, mend = match.span()
2642 mstart, mend = match.span()
2737 linenum += body.count('\n', begin, mstart) + 1
2643 linenum += body.count('\n', begin, mstart) + 1
2738 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2644 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2739 begin = body.find('\n', mend) + 1 or len(body) + 1
2645 begin = body.find('\n', mend) + 1 or len(body) + 1
2740 lend = begin - 1
2646 lend = begin - 1
2741 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2647 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2742
2648
2743 class linestate(object):
2649 class linestate(object):
2744 def __init__(self, line, linenum, colstart, colend):
2650 def __init__(self, line, linenum, colstart, colend):
2745 self.line = line
2651 self.line = line
2746 self.linenum = linenum
2652 self.linenum = linenum
2747 self.colstart = colstart
2653 self.colstart = colstart
2748 self.colend = colend
2654 self.colend = colend
2749
2655
2750 def __hash__(self):
2656 def __hash__(self):
2751 return hash((self.linenum, self.line))
2657 return hash((self.linenum, self.line))
2752
2658
2753 def __eq__(self, other):
2659 def __eq__(self, other):
2754 return self.line == other.line
2660 return self.line == other.line
2755
2661
2756 def findpos(self):
2662 def findpos(self):
2757 """Iterate all (start, end) indices of matches"""
2663 """Iterate all (start, end) indices of matches"""
2758 yield self.colstart, self.colend
2664 yield self.colstart, self.colend
2759 p = self.colend
2665 p = self.colend
2760 while p < len(self.line):
2666 while p < len(self.line):
2761 m = regexp.search(self.line, p)
2667 m = regexp.search(self.line, p)
2762 if not m:
2668 if not m:
2763 break
2669 break
2764 yield m.span()
2670 yield m.span()
2765 p = m.end()
2671 p = m.end()
2766
2672
2767 matches = {}
2673 matches = {}
2768 copies = {}
2674 copies = {}
2769 def grepbody(fn, rev, body):
2675 def grepbody(fn, rev, body):
2770 matches[rev].setdefault(fn, [])
2676 matches[rev].setdefault(fn, [])
2771 m = matches[rev][fn]
2677 m = matches[rev][fn]
2772 for lnum, cstart, cend, line in matchlines(body):
2678 for lnum, cstart, cend, line in matchlines(body):
2773 s = linestate(line, lnum, cstart, cend)
2679 s = linestate(line, lnum, cstart, cend)
2774 m.append(s)
2680 m.append(s)
2775
2681
2776 def difflinestates(a, b):
2682 def difflinestates(a, b):
2777 sm = difflib.SequenceMatcher(None, a, b)
2683 sm = difflib.SequenceMatcher(None, a, b)
2778 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2684 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2779 if tag == 'insert':
2685 if tag == 'insert':
2780 for i in xrange(blo, bhi):
2686 for i in xrange(blo, bhi):
2781 yield ('+', b[i])
2687 yield ('+', b[i])
2782 elif tag == 'delete':
2688 elif tag == 'delete':
2783 for i in xrange(alo, ahi):
2689 for i in xrange(alo, ahi):
2784 yield ('-', a[i])
2690 yield ('-', a[i])
2785 elif tag == 'replace':
2691 elif tag == 'replace':
2786 for i in xrange(alo, ahi):
2692 for i in xrange(alo, ahi):
2787 yield ('-', a[i])
2693 yield ('-', a[i])
2788 for i in xrange(blo, bhi):
2694 for i in xrange(blo, bhi):
2789 yield ('+', b[i])
2695 yield ('+', b[i])
2790
2696
2791 def display(fm, fn, ctx, pstates, states):
2697 def display(fm, fn, ctx, pstates, states):
2792 rev = ctx.rev()
2698 rev = ctx.rev()
2793 if fm.isplain():
2699 if fm.isplain():
2794 formatuser = ui.shortuser
2700 formatuser = ui.shortuser
2795 else:
2701 else:
2796 formatuser = str
2702 formatuser = str
2797 if ui.quiet:
2703 if ui.quiet:
2798 datefmt = '%Y-%m-%d'
2704 datefmt = '%Y-%m-%d'
2799 else:
2705 else:
2800 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2706 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2801 found = False
2707 found = False
2802 @util.cachefunc
2708 @util.cachefunc
2803 def binary():
2709 def binary():
2804 flog = getfile(fn)
2710 flog = getfile(fn)
2805 return util.binary(flog.read(ctx.filenode(fn)))
2711 return util.binary(flog.read(ctx.filenode(fn)))
2806
2712
2807 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2713 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2808 if opts.get('all'):
2714 if opts.get('all'):
2809 iter = difflinestates(pstates, states)
2715 iter = difflinestates(pstates, states)
2810 else:
2716 else:
2811 iter = [('', l) for l in states]
2717 iter = [('', l) for l in states]
2812 for change, l in iter:
2718 for change, l in iter:
2813 fm.startitem()
2719 fm.startitem()
2814 fm.data(node=fm.hexfunc(ctx.node()))
2720 fm.data(node=fm.hexfunc(ctx.node()))
2815 cols = [
2721 cols = [
2816 ('filename', fn, True),
2722 ('filename', fn, True),
2817 ('rev', rev, True),
2723 ('rev', rev, True),
2818 ('linenumber', l.linenum, opts.get('line_number')),
2724 ('linenumber', l.linenum, opts.get('line_number')),
2819 ]
2725 ]
2820 if opts.get('all'):
2726 if opts.get('all'):
2821 cols.append(('change', change, True))
2727 cols.append(('change', change, True))
2822 cols.extend([
2728 cols.extend([
2823 ('user', formatuser(ctx.user()), opts.get('user')),
2729 ('user', formatuser(ctx.user()), opts.get('user')),
2824 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2730 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2825 ])
2731 ])
2826 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2732 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2827 for name, data, cond in cols:
2733 for name, data, cond in cols:
2828 field = fieldnamemap.get(name, name)
2734 field = fieldnamemap.get(name, name)
2829 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2735 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2830 if cond and name != lastcol:
2736 if cond and name != lastcol:
2831 fm.plain(sep, label='grep.sep')
2737 fm.plain(sep, label='grep.sep')
2832 if not opts.get('files_with_matches'):
2738 if not opts.get('files_with_matches'):
2833 fm.plain(sep, label='grep.sep')
2739 fm.plain(sep, label='grep.sep')
2834 if not opts.get('text') and binary():
2740 if not opts.get('text') and binary():
2835 fm.plain(_(" Binary file matches"))
2741 fm.plain(_(" Binary file matches"))
2836 else:
2742 else:
2837 displaymatches(fm.nested('texts'), l)
2743 displaymatches(fm.nested('texts'), l)
2838 fm.plain(eol)
2744 fm.plain(eol)
2839 found = True
2745 found = True
2840 if opts.get('files_with_matches'):
2746 if opts.get('files_with_matches'):
2841 break
2747 break
2842 return found
2748 return found
2843
2749
2844 def displaymatches(fm, l):
2750 def displaymatches(fm, l):
2845 p = 0
2751 p = 0
2846 for s, e in l.findpos():
2752 for s, e in l.findpos():
2847 if p < s:
2753 if p < s:
2848 fm.startitem()
2754 fm.startitem()
2849 fm.write('text', '%s', l.line[p:s])
2755 fm.write('text', '%s', l.line[p:s])
2850 fm.data(matched=False)
2756 fm.data(matched=False)
2851 fm.startitem()
2757 fm.startitem()
2852 fm.write('text', '%s', l.line[s:e], label='grep.match')
2758 fm.write('text', '%s', l.line[s:e], label='grep.match')
2853 fm.data(matched=True)
2759 fm.data(matched=True)
2854 p = e
2760 p = e
2855 if p < len(l.line):
2761 if p < len(l.line):
2856 fm.startitem()
2762 fm.startitem()
2857 fm.write('text', '%s', l.line[p:])
2763 fm.write('text', '%s', l.line[p:])
2858 fm.data(matched=False)
2764 fm.data(matched=False)
2859 fm.end()
2765 fm.end()
2860
2766
2861 skip = {}
2767 skip = {}
2862 revfiles = {}
2768 revfiles = {}
2863 matchfn = scmutil.match(repo[None], pats, opts)
2769 matchfn = scmutil.match(repo[None], pats, opts)
2864 found = False
2770 found = False
2865 follow = opts.get('follow')
2771 follow = opts.get('follow')
2866
2772
2867 def prep(ctx, fns):
2773 def prep(ctx, fns):
2868 rev = ctx.rev()
2774 rev = ctx.rev()
2869 pctx = ctx.p1()
2775 pctx = ctx.p1()
2870 parent = pctx.rev()
2776 parent = pctx.rev()
2871 matches.setdefault(rev, {})
2777 matches.setdefault(rev, {})
2872 matches.setdefault(parent, {})
2778 matches.setdefault(parent, {})
2873 files = revfiles.setdefault(rev, [])
2779 files = revfiles.setdefault(rev, [])
2874 for fn in fns:
2780 for fn in fns:
2875 flog = getfile(fn)
2781 flog = getfile(fn)
2876 try:
2782 try:
2877 fnode = ctx.filenode(fn)
2783 fnode = ctx.filenode(fn)
2878 except error.LookupError:
2784 except error.LookupError:
2879 continue
2785 continue
2880
2786
2881 copied = flog.renamed(fnode)
2787 copied = flog.renamed(fnode)
2882 copy = follow and copied and copied[0]
2788 copy = follow and copied and copied[0]
2883 if copy:
2789 if copy:
2884 copies.setdefault(rev, {})[fn] = copy
2790 copies.setdefault(rev, {})[fn] = copy
2885 if fn in skip:
2791 if fn in skip:
2886 if copy:
2792 if copy:
2887 skip[copy] = True
2793 skip[copy] = True
2888 continue
2794 continue
2889 files.append(fn)
2795 files.append(fn)
2890
2796
2891 if fn not in matches[rev]:
2797 if fn not in matches[rev]:
2892 grepbody(fn, rev, flog.read(fnode))
2798 grepbody(fn, rev, flog.read(fnode))
2893
2799
2894 pfn = copy or fn
2800 pfn = copy or fn
2895 if pfn not in matches[parent]:
2801 if pfn not in matches[parent]:
2896 try:
2802 try:
2897 fnode = pctx.filenode(pfn)
2803 fnode = pctx.filenode(pfn)
2898 grepbody(pfn, parent, flog.read(fnode))
2804 grepbody(pfn, parent, flog.read(fnode))
2899 except error.LookupError:
2805 except error.LookupError:
2900 pass
2806 pass
2901
2807
2902 fm = ui.formatter('grep', opts)
2808 fm = ui.formatter('grep', opts)
2903 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2809 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2904 rev = ctx.rev()
2810 rev = ctx.rev()
2905 parent = ctx.p1().rev()
2811 parent = ctx.p1().rev()
2906 for fn in sorted(revfiles.get(rev, [])):
2812 for fn in sorted(revfiles.get(rev, [])):
2907 states = matches[rev][fn]
2813 states = matches[rev][fn]
2908 copy = copies.get(rev, {}).get(fn)
2814 copy = copies.get(rev, {}).get(fn)
2909 if fn in skip:
2815 if fn in skip:
2910 if copy:
2816 if copy:
2911 skip[copy] = True
2817 skip[copy] = True
2912 continue
2818 continue
2913 pstates = matches.get(parent, {}).get(copy or fn, [])
2819 pstates = matches.get(parent, {}).get(copy or fn, [])
2914 if pstates or states:
2820 if pstates or states:
2915 r = display(fm, fn, ctx, pstates, states)
2821 r = display(fm, fn, ctx, pstates, states)
2916 found = found or r
2822 found = found or r
2917 if r and not opts.get('all'):
2823 if r and not opts.get('all'):
2918 skip[fn] = True
2824 skip[fn] = True
2919 if copy:
2825 if copy:
2920 skip[copy] = True
2826 skip[copy] = True
2921 del matches[rev]
2827 del matches[rev]
2922 del revfiles[rev]
2828 del revfiles[rev]
2923 fm.end()
2829 fm.end()
2924
2830
2925 return not found
2831 return not found
2926
2832
2927 @command('heads',
2833 @command('heads',
2928 [('r', 'rev', '',
2834 [('r', 'rev', '',
2929 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2835 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2930 ('t', 'topo', False, _('show topological heads only')),
2836 ('t', 'topo', False, _('show topological heads only')),
2931 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2837 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2932 ('c', 'closed', False, _('show normal and closed branch heads')),
2838 ('c', 'closed', False, _('show normal and closed branch heads')),
2933 ] + templateopts,
2839 ] + templateopts,
2934 _('[-ct] [-r STARTREV] [REV]...'))
2840 _('[-ct] [-r STARTREV] [REV]...'))
2935 def heads(ui, repo, *branchrevs, **opts):
2841 def heads(ui, repo, *branchrevs, **opts):
2936 """show branch heads
2842 """show branch heads
2937
2843
2938 With no arguments, show all open branch heads in the repository.
2844 With no arguments, show all open branch heads in the repository.
2939 Branch heads are changesets that have no descendants on the
2845 Branch heads are changesets that have no descendants on the
2940 same branch. They are where development generally takes place and
2846 same branch. They are where development generally takes place and
2941 are the usual targets for update and merge operations.
2847 are the usual targets for update and merge operations.
2942
2848
2943 If one or more REVs are given, only open branch heads on the
2849 If one or more REVs are given, only open branch heads on the
2944 branches associated with the specified changesets are shown. This
2850 branches associated with the specified changesets are shown. This
2945 means that you can use :hg:`heads .` to see the heads on the
2851 means that you can use :hg:`heads .` to see the heads on the
2946 currently checked-out branch.
2852 currently checked-out branch.
2947
2853
2948 If -c/--closed is specified, also show branch heads marked closed
2854 If -c/--closed is specified, also show branch heads marked closed
2949 (see :hg:`commit --close-branch`).
2855 (see :hg:`commit --close-branch`).
2950
2856
2951 If STARTREV is specified, only those heads that are descendants of
2857 If STARTREV is specified, only those heads that are descendants of
2952 STARTREV will be displayed.
2858 STARTREV will be displayed.
2953
2859
2954 If -t/--topo is specified, named branch mechanics will be ignored and only
2860 If -t/--topo is specified, named branch mechanics will be ignored and only
2955 topological heads (changesets with no children) will be shown.
2861 topological heads (changesets with no children) will be shown.
2956
2862
2957 Returns 0 if matching heads are found, 1 if not.
2863 Returns 0 if matching heads are found, 1 if not.
2958 """
2864 """
2959
2865
2960 start = None
2866 start = None
2961 if 'rev' in opts:
2867 if 'rev' in opts:
2962 start = scmutil.revsingle(repo, opts['rev'], None).node()
2868 start = scmutil.revsingle(repo, opts['rev'], None).node()
2963
2869
2964 if opts.get('topo'):
2870 if opts.get('topo'):
2965 heads = [repo[h] for h in repo.heads(start)]
2871 heads = [repo[h] for h in repo.heads(start)]
2966 else:
2872 else:
2967 heads = []
2873 heads = []
2968 for branch in repo.branchmap():
2874 for branch in repo.branchmap():
2969 heads += repo.branchheads(branch, start, opts.get('closed'))
2875 heads += repo.branchheads(branch, start, opts.get('closed'))
2970 heads = [repo[h] for h in heads]
2876 heads = [repo[h] for h in heads]
2971
2877
2972 if branchrevs:
2878 if branchrevs:
2973 branches = set(repo[br].branch() for br in branchrevs)
2879 branches = set(repo[br].branch() for br in branchrevs)
2974 heads = [h for h in heads if h.branch() in branches]
2880 heads = [h for h in heads if h.branch() in branches]
2975
2881
2976 if opts.get('active') and branchrevs:
2882 if opts.get('active') and branchrevs:
2977 dagheads = repo.heads(start)
2883 dagheads = repo.heads(start)
2978 heads = [h for h in heads if h.node() in dagheads]
2884 heads = [h for h in heads if h.node() in dagheads]
2979
2885
2980 if branchrevs:
2886 if branchrevs:
2981 haveheads = set(h.branch() for h in heads)
2887 haveheads = set(h.branch() for h in heads)
2982 if branches - haveheads:
2888 if branches - haveheads:
2983 headless = ', '.join(b for b in branches - haveheads)
2889 headless = ', '.join(b for b in branches - haveheads)
2984 msg = _('no open branch heads found on branches %s')
2890 msg = _('no open branch heads found on branches %s')
2985 if opts.get('rev'):
2891 if opts.get('rev'):
2986 msg += _(' (started at %s)') % opts['rev']
2892 msg += _(' (started at %s)') % opts['rev']
2987 ui.warn((msg + '\n') % headless)
2893 ui.warn((msg + '\n') % headless)
2988
2894
2989 if not heads:
2895 if not heads:
2990 return 1
2896 return 1
2991
2897
2992 heads = sorted(heads, key=lambda x: -x.rev())
2898 heads = sorted(heads, key=lambda x: -x.rev())
2993 displayer = cmdutil.show_changeset(ui, repo, opts)
2899 displayer = cmdutil.show_changeset(ui, repo, opts)
2994 for ctx in heads:
2900 for ctx in heads:
2995 displayer.show(ctx)
2901 displayer.show(ctx)
2996 displayer.close()
2902 displayer.close()
2997
2903
2998 @command('help',
2904 @command('help',
2999 [('e', 'extension', None, _('show only help for extensions')),
2905 [('e', 'extension', None, _('show only help for extensions')),
3000 ('c', 'command', None, _('show only help for commands')),
2906 ('c', 'command', None, _('show only help for commands')),
3001 ('k', 'keyword', None, _('show topics matching keyword')),
2907 ('k', 'keyword', None, _('show topics matching keyword')),
3002 ('s', 'system', [], _('show help for specific platform(s)')),
2908 ('s', 'system', [], _('show help for specific platform(s)')),
3003 ],
2909 ],
3004 _('[-ecks] [TOPIC]'),
2910 _('[-ecks] [TOPIC]'),
3005 norepo=True)
2911 norepo=True)
3006 def help_(ui, name=None, **opts):
2912 def help_(ui, name=None, **opts):
3007 """show help for a given topic or a help overview
2913 """show help for a given topic or a help overview
3008
2914
3009 With no arguments, print a list of commands with short help messages.
2915 With no arguments, print a list of commands with short help messages.
3010
2916
3011 Given a topic, extension, or command name, print help for that
2917 Given a topic, extension, or command name, print help for that
3012 topic.
2918 topic.
3013
2919
3014 Returns 0 if successful.
2920 Returns 0 if successful.
3015 """
2921 """
3016
2922
3017 textwidth = ui.configint('ui', 'textwidth', 78)
2923 textwidth = ui.configint('ui', 'textwidth', 78)
3018 termwidth = ui.termwidth() - 2
2924 termwidth = ui.termwidth() - 2
3019 if textwidth <= 0 or termwidth < textwidth:
2925 if textwidth <= 0 or termwidth < textwidth:
3020 textwidth = termwidth
2926 textwidth = termwidth
3021
2927
3022 keep = opts.get('system') or []
2928 keep = opts.get('system') or []
3023 if len(keep) == 0:
2929 if len(keep) == 0:
3024 if pycompat.sysplatform.startswith('win'):
2930 if pycompat.sysplatform.startswith('win'):
3025 keep.append('windows')
2931 keep.append('windows')
3026 elif pycompat.sysplatform == 'OpenVMS':
2932 elif pycompat.sysplatform == 'OpenVMS':
3027 keep.append('vms')
2933 keep.append('vms')
3028 elif pycompat.sysplatform == 'plan9':
2934 elif pycompat.sysplatform == 'plan9':
3029 keep.append('plan9')
2935 keep.append('plan9')
3030 else:
2936 else:
3031 keep.append('unix')
2937 keep.append('unix')
3032 keep.append(pycompat.sysplatform.lower())
2938 keep.append(pycompat.sysplatform.lower())
3033 if ui.verbose:
2939 if ui.verbose:
3034 keep.append('verbose')
2940 keep.append('verbose')
3035
2941
3036 fullname = name
2942 fullname = name
3037 section = None
2943 section = None
3038 subtopic = None
2944 subtopic = None
3039 if name and '.' in name:
2945 if name and '.' in name:
3040 name, remaining = name.split('.', 1)
2946 name, remaining = name.split('.', 1)
3041 remaining = encoding.lower(remaining)
2947 remaining = encoding.lower(remaining)
3042 if '.' in remaining:
2948 if '.' in remaining:
3043 subtopic, section = remaining.split('.', 1)
2949 subtopic, section = remaining.split('.', 1)
3044 else:
2950 else:
3045 if name in help.subtopics:
2951 if name in help.subtopics:
3046 subtopic = remaining
2952 subtopic = remaining
3047 else:
2953 else:
3048 section = remaining
2954 section = remaining
3049
2955
3050 text = help.help_(ui, name, subtopic=subtopic, **opts)
2956 text = help.help_(ui, name, subtopic=subtopic, **opts)
3051
2957
3052 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2958 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3053 section=section)
2959 section=section)
3054
2960
3055 # We could have been given a weird ".foo" section without a name
2961 # We could have been given a weird ".foo" section without a name
3056 # to look for, or we could have simply failed to found "foo.bar"
2962 # to look for, or we could have simply failed to found "foo.bar"
3057 # because bar isn't a section of foo
2963 # because bar isn't a section of foo
3058 if section and not (formatted and name):
2964 if section and not (formatted and name):
3059 raise error.Abort(_("help section not found: %s") % fullname)
2965 raise error.Abort(_("help section not found: %s") % fullname)
3060
2966
3061 if 'verbose' in pruned:
2967 if 'verbose' in pruned:
3062 keep.append('omitted')
2968 keep.append('omitted')
3063 else:
2969 else:
3064 keep.append('notomitted')
2970 keep.append('notomitted')
3065 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2971 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3066 section=section)
2972 section=section)
3067 ui.write(formatted)
2973 ui.write(formatted)
3068
2974
3069
2975
3070 @command('identify|id',
2976 @command('identify|id',
3071 [('r', 'rev', '',
2977 [('r', 'rev', '',
3072 _('identify the specified revision'), _('REV')),
2978 _('identify the specified revision'), _('REV')),
3073 ('n', 'num', None, _('show local revision number')),
2979 ('n', 'num', None, _('show local revision number')),
3074 ('i', 'id', None, _('show global revision id')),
2980 ('i', 'id', None, _('show global revision id')),
3075 ('b', 'branch', None, _('show branch')),
2981 ('b', 'branch', None, _('show branch')),
3076 ('t', 'tags', None, _('show tags')),
2982 ('t', 'tags', None, _('show tags')),
3077 ('B', 'bookmarks', None, _('show bookmarks')),
2983 ('B', 'bookmarks', None, _('show bookmarks')),
3078 ] + remoteopts,
2984 ] + remoteopts,
3079 _('[-nibtB] [-r REV] [SOURCE]'),
2985 _('[-nibtB] [-r REV] [SOURCE]'),
3080 optionalrepo=True)
2986 optionalrepo=True)
3081 def identify(ui, repo, source=None, rev=None,
2987 def identify(ui, repo, source=None, rev=None,
3082 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2988 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3083 """identify the working directory or specified revision
2989 """identify the working directory or specified revision
3084
2990
3085 Print a summary identifying the repository state at REV using one or
2991 Print a summary identifying the repository state at REV using one or
3086 two parent hash identifiers, followed by a "+" if the working
2992 two parent hash identifiers, followed by a "+" if the working
3087 directory has uncommitted changes, the branch name (if not default),
2993 directory has uncommitted changes, the branch name (if not default),
3088 a list of tags, and a list of bookmarks.
2994 a list of tags, and a list of bookmarks.
3089
2995
3090 When REV is not given, print a summary of the current state of the
2996 When REV is not given, print a summary of the current state of the
3091 repository.
2997 repository.
3092
2998
3093 Specifying a path to a repository root or Mercurial bundle will
2999 Specifying a path to a repository root or Mercurial bundle will
3094 cause lookup to operate on that repository/bundle.
3000 cause lookup to operate on that repository/bundle.
3095
3001
3096 .. container:: verbose
3002 .. container:: verbose
3097
3003
3098 Examples:
3004 Examples:
3099
3005
3100 - generate a build identifier for the working directory::
3006 - generate a build identifier for the working directory::
3101
3007
3102 hg id --id > build-id.dat
3008 hg id --id > build-id.dat
3103
3009
3104 - find the revision corresponding to a tag::
3010 - find the revision corresponding to a tag::
3105
3011
3106 hg id -n -r 1.3
3012 hg id -n -r 1.3
3107
3013
3108 - check the most recent revision of a remote repository::
3014 - check the most recent revision of a remote repository::
3109
3015
3110 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3016 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3111
3017
3112 See :hg:`log` for generating more information about specific revisions,
3018 See :hg:`log` for generating more information about specific revisions,
3113 including full hash identifiers.
3019 including full hash identifiers.
3114
3020
3115 Returns 0 if successful.
3021 Returns 0 if successful.
3116 """
3022 """
3117
3023
3118 if not repo and not source:
3024 if not repo and not source:
3119 raise error.Abort(_("there is no Mercurial repository here "
3025 raise error.Abort(_("there is no Mercurial repository here "
3120 "(.hg not found)"))
3026 "(.hg not found)"))
3121
3027
3122 if ui.debugflag:
3028 if ui.debugflag:
3123 hexfunc = hex
3029 hexfunc = hex
3124 else:
3030 else:
3125 hexfunc = short
3031 hexfunc = short
3126 default = not (num or id or branch or tags or bookmarks)
3032 default = not (num or id or branch or tags or bookmarks)
3127 output = []
3033 output = []
3128 revs = []
3034 revs = []
3129
3035
3130 if source:
3036 if source:
3131 source, branches = hg.parseurl(ui.expandpath(source))
3037 source, branches = hg.parseurl(ui.expandpath(source))
3132 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3038 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3133 repo = peer.local()
3039 repo = peer.local()
3134 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3040 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3135
3041
3136 if not repo:
3042 if not repo:
3137 if num or branch or tags:
3043 if num or branch or tags:
3138 raise error.Abort(
3044 raise error.Abort(
3139 _("can't query remote revision number, branch, or tags"))
3045 _("can't query remote revision number, branch, or tags"))
3140 if not rev and revs:
3046 if not rev and revs:
3141 rev = revs[0]
3047 rev = revs[0]
3142 if not rev:
3048 if not rev:
3143 rev = "tip"
3049 rev = "tip"
3144
3050
3145 remoterev = peer.lookup(rev)
3051 remoterev = peer.lookup(rev)
3146 if default or id:
3052 if default or id:
3147 output = [hexfunc(remoterev)]
3053 output = [hexfunc(remoterev)]
3148
3054
3149 def getbms():
3055 def getbms():
3150 bms = []
3056 bms = []
3151
3057
3152 if 'bookmarks' in peer.listkeys('namespaces'):
3058 if 'bookmarks' in peer.listkeys('namespaces'):
3153 hexremoterev = hex(remoterev)
3059 hexremoterev = hex(remoterev)
3154 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3060 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3155 if bmr == hexremoterev]
3061 if bmr == hexremoterev]
3156
3062
3157 return sorted(bms)
3063 return sorted(bms)
3158
3064
3159 if bookmarks:
3065 if bookmarks:
3160 output.extend(getbms())
3066 output.extend(getbms())
3161 elif default and not ui.quiet:
3067 elif default and not ui.quiet:
3162 # multiple bookmarks for a single parent separated by '/'
3068 # multiple bookmarks for a single parent separated by '/'
3163 bm = '/'.join(getbms())
3069 bm = '/'.join(getbms())
3164 if bm:
3070 if bm:
3165 output.append(bm)
3071 output.append(bm)
3166 else:
3072 else:
3167 ctx = scmutil.revsingle(repo, rev, None)
3073 ctx = scmutil.revsingle(repo, rev, None)
3168
3074
3169 if ctx.rev() is None:
3075 if ctx.rev() is None:
3170 ctx = repo[None]
3076 ctx = repo[None]
3171 parents = ctx.parents()
3077 parents = ctx.parents()
3172 taglist = []
3078 taglist = []
3173 for p in parents:
3079 for p in parents:
3174 taglist.extend(p.tags())
3080 taglist.extend(p.tags())
3175
3081
3176 changed = ""
3082 changed = ""
3177 if default or id or num:
3083 if default or id or num:
3178 if (any(repo.status())
3084 if (any(repo.status())
3179 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3085 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3180 changed = '+'
3086 changed = '+'
3181 if default or id:
3087 if default or id:
3182 output = ["%s%s" %
3088 output = ["%s%s" %
3183 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3089 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3184 if num:
3090 if num:
3185 output.append("%s%s" %
3091 output.append("%s%s" %
3186 ('+'.join([str(p.rev()) for p in parents]), changed))
3092 ('+'.join([str(p.rev()) for p in parents]), changed))
3187 else:
3093 else:
3188 if default or id:
3094 if default or id:
3189 output = [hexfunc(ctx.node())]
3095 output = [hexfunc(ctx.node())]
3190 if num:
3096 if num:
3191 output.append(str(ctx.rev()))
3097 output.append(str(ctx.rev()))
3192 taglist = ctx.tags()
3098 taglist = ctx.tags()
3193
3099
3194 if default and not ui.quiet:
3100 if default and not ui.quiet:
3195 b = ctx.branch()
3101 b = ctx.branch()
3196 if b != 'default':
3102 if b != 'default':
3197 output.append("(%s)" % b)
3103 output.append("(%s)" % b)
3198
3104
3199 # multiple tags for a single parent separated by '/'
3105 # multiple tags for a single parent separated by '/'
3200 t = '/'.join(taglist)
3106 t = '/'.join(taglist)
3201 if t:
3107 if t:
3202 output.append(t)
3108 output.append(t)
3203
3109
3204 # multiple bookmarks for a single parent separated by '/'
3110 # multiple bookmarks for a single parent separated by '/'
3205 bm = '/'.join(ctx.bookmarks())
3111 bm = '/'.join(ctx.bookmarks())
3206 if bm:
3112 if bm:
3207 output.append(bm)
3113 output.append(bm)
3208 else:
3114 else:
3209 if branch:
3115 if branch:
3210 output.append(ctx.branch())
3116 output.append(ctx.branch())
3211
3117
3212 if tags:
3118 if tags:
3213 output.extend(taglist)
3119 output.extend(taglist)
3214
3120
3215 if bookmarks:
3121 if bookmarks:
3216 output.extend(ctx.bookmarks())
3122 output.extend(ctx.bookmarks())
3217
3123
3218 ui.write("%s\n" % ' '.join(output))
3124 ui.write("%s\n" % ' '.join(output))
3219
3125
3220 @command('import|patch',
3126 @command('import|patch',
3221 [('p', 'strip', 1,
3127 [('p', 'strip', 1,
3222 _('directory strip option for patch. This has the same '
3128 _('directory strip option for patch. This has the same '
3223 'meaning as the corresponding patch option'), _('NUM')),
3129 'meaning as the corresponding patch option'), _('NUM')),
3224 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3130 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3225 ('e', 'edit', False, _('invoke editor on commit messages')),
3131 ('e', 'edit', False, _('invoke editor on commit messages')),
3226 ('f', 'force', None,
3132 ('f', 'force', None,
3227 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3133 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3228 ('', 'no-commit', None,
3134 ('', 'no-commit', None,
3229 _("don't commit, just update the working directory")),
3135 _("don't commit, just update the working directory")),
3230 ('', 'bypass', None,
3136 ('', 'bypass', None,
3231 _("apply patch without touching the working directory")),
3137 _("apply patch without touching the working directory")),
3232 ('', 'partial', None,
3138 ('', 'partial', None,
3233 _('commit even if some hunks fail')),
3139 _('commit even if some hunks fail')),
3234 ('', 'exact', None,
3140 ('', 'exact', None,
3235 _('abort if patch would apply lossily')),
3141 _('abort if patch would apply lossily')),
3236 ('', 'prefix', '',
3142 ('', 'prefix', '',
3237 _('apply patch to subdirectory'), _('DIR')),
3143 _('apply patch to subdirectory'), _('DIR')),
3238 ('', 'import-branch', None,
3144 ('', 'import-branch', None,
3239 _('use any branch information in patch (implied by --exact)'))] +
3145 _('use any branch information in patch (implied by --exact)'))] +
3240 commitopts + commitopts2 + similarityopts,
3146 commitopts + commitopts2 + similarityopts,
3241 _('[OPTION]... PATCH...'))
3147 _('[OPTION]... PATCH...'))
3242 def import_(ui, repo, patch1=None, *patches, **opts):
3148 def import_(ui, repo, patch1=None, *patches, **opts):
3243 """import an ordered set of patches
3149 """import an ordered set of patches
3244
3150
3245 Import a list of patches and commit them individually (unless
3151 Import a list of patches and commit them individually (unless
3246 --no-commit is specified).
3152 --no-commit is specified).
3247
3153
3248 To read a patch from standard input (stdin), use "-" as the patch
3154 To read a patch from standard input (stdin), use "-" as the patch
3249 name. If a URL is specified, the patch will be downloaded from
3155 name. If a URL is specified, the patch will be downloaded from
3250 there.
3156 there.
3251
3157
3252 Import first applies changes to the working directory (unless
3158 Import first applies changes to the working directory (unless
3253 --bypass is specified), import will abort if there are outstanding
3159 --bypass is specified), import will abort if there are outstanding
3254 changes.
3160 changes.
3255
3161
3256 Use --bypass to apply and commit patches directly to the
3162 Use --bypass to apply and commit patches directly to the
3257 repository, without affecting the working directory. Without
3163 repository, without affecting the working directory. Without
3258 --exact, patches will be applied on top of the working directory
3164 --exact, patches will be applied on top of the working directory
3259 parent revision.
3165 parent revision.
3260
3166
3261 You can import a patch straight from a mail message. Even patches
3167 You can import a patch straight from a mail message. Even patches
3262 as attachments work (to use the body part, it must have type
3168 as attachments work (to use the body part, it must have type
3263 text/plain or text/x-patch). From and Subject headers of email
3169 text/plain or text/x-patch). From and Subject headers of email
3264 message are used as default committer and commit message. All
3170 message are used as default committer and commit message. All
3265 text/plain body parts before first diff are added to the commit
3171 text/plain body parts before first diff are added to the commit
3266 message.
3172 message.
3267
3173
3268 If the imported patch was generated by :hg:`export`, user and
3174 If the imported patch was generated by :hg:`export`, user and
3269 description from patch override values from message headers and
3175 description from patch override values from message headers and
3270 body. Values given on command line with -m/--message and -u/--user
3176 body. Values given on command line with -m/--message and -u/--user
3271 override these.
3177 override these.
3272
3178
3273 If --exact is specified, import will set the working directory to
3179 If --exact is specified, import will set the working directory to
3274 the parent of each patch before applying it, and will abort if the
3180 the parent of each patch before applying it, and will abort if the
3275 resulting changeset has a different ID than the one recorded in
3181 resulting changeset has a different ID than the one recorded in
3276 the patch. This will guard against various ways that portable
3182 the patch. This will guard against various ways that portable
3277 patch formats and mail systems might fail to transfer Mercurial
3183 patch formats and mail systems might fail to transfer Mercurial
3278 data or metadata. See :hg:`bundle` for lossless transmission.
3184 data or metadata. See :hg:`bundle` for lossless transmission.
3279
3185
3280 Use --partial to ensure a changeset will be created from the patch
3186 Use --partial to ensure a changeset will be created from the patch
3281 even if some hunks fail to apply. Hunks that fail to apply will be
3187 even if some hunks fail to apply. Hunks that fail to apply will be
3282 written to a <target-file>.rej file. Conflicts can then be resolved
3188 written to a <target-file>.rej file. Conflicts can then be resolved
3283 by hand before :hg:`commit --amend` is run to update the created
3189 by hand before :hg:`commit --amend` is run to update the created
3284 changeset. This flag exists to let people import patches that
3190 changeset. This flag exists to let people import patches that
3285 partially apply without losing the associated metadata (author,
3191 partially apply without losing the associated metadata (author,
3286 date, description, ...).
3192 date, description, ...).
3287
3193
3288 .. note::
3194 .. note::
3289
3195
3290 When no hunks apply cleanly, :hg:`import --partial` will create
3196 When no hunks apply cleanly, :hg:`import --partial` will create
3291 an empty changeset, importing only the patch metadata.
3197 an empty changeset, importing only the patch metadata.
3292
3198
3293 With -s/--similarity, hg will attempt to discover renames and
3199 With -s/--similarity, hg will attempt to discover renames and
3294 copies in the patch in the same way as :hg:`addremove`.
3200 copies in the patch in the same way as :hg:`addremove`.
3295
3201
3296 It is possible to use external patch programs to perform the patch
3202 It is possible to use external patch programs to perform the patch
3297 by setting the ``ui.patch`` configuration option. For the default
3203 by setting the ``ui.patch`` configuration option. For the default
3298 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3204 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3299 See :hg:`help config` for more information about configuration
3205 See :hg:`help config` for more information about configuration
3300 files and how to use these options.
3206 files and how to use these options.
3301
3207
3302 See :hg:`help dates` for a list of formats valid for -d/--date.
3208 See :hg:`help dates` for a list of formats valid for -d/--date.
3303
3209
3304 .. container:: verbose
3210 .. container:: verbose
3305
3211
3306 Examples:
3212 Examples:
3307
3213
3308 - import a traditional patch from a website and detect renames::
3214 - import a traditional patch from a website and detect renames::
3309
3215
3310 hg import -s 80 http://example.com/bugfix.patch
3216 hg import -s 80 http://example.com/bugfix.patch
3311
3217
3312 - import a changeset from an hgweb server::
3218 - import a changeset from an hgweb server::
3313
3219
3314 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3220 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3315
3221
3316 - import all the patches in an Unix-style mbox::
3222 - import all the patches in an Unix-style mbox::
3317
3223
3318 hg import incoming-patches.mbox
3224 hg import incoming-patches.mbox
3319
3225
3320 - import patches from stdin::
3226 - import patches from stdin::
3321
3227
3322 hg import -
3228 hg import -
3323
3229
3324 - attempt to exactly restore an exported changeset (not always
3230 - attempt to exactly restore an exported changeset (not always
3325 possible)::
3231 possible)::
3326
3232
3327 hg import --exact proposed-fix.patch
3233 hg import --exact proposed-fix.patch
3328
3234
3329 - use an external tool to apply a patch which is too fuzzy for
3235 - use an external tool to apply a patch which is too fuzzy for
3330 the default internal tool.
3236 the default internal tool.
3331
3237
3332 hg import --config ui.patch="patch --merge" fuzzy.patch
3238 hg import --config ui.patch="patch --merge" fuzzy.patch
3333
3239
3334 - change the default fuzzing from 2 to a less strict 7
3240 - change the default fuzzing from 2 to a less strict 7
3335
3241
3336 hg import --config ui.fuzz=7 fuzz.patch
3242 hg import --config ui.fuzz=7 fuzz.patch
3337
3243
3338 Returns 0 on success, 1 on partial success (see --partial).
3244 Returns 0 on success, 1 on partial success (see --partial).
3339 """
3245 """
3340
3246
3341 if not patch1:
3247 if not patch1:
3342 raise error.Abort(_('need at least one patch to import'))
3248 raise error.Abort(_('need at least one patch to import'))
3343
3249
3344 patches = (patch1,) + patches
3250 patches = (patch1,) + patches
3345
3251
3346 date = opts.get('date')
3252 date = opts.get('date')
3347 if date:
3253 if date:
3348 opts['date'] = util.parsedate(date)
3254 opts['date'] = util.parsedate(date)
3349
3255
3350 exact = opts.get('exact')
3256 exact = opts.get('exact')
3351 update = not opts.get('bypass')
3257 update = not opts.get('bypass')
3352 if not update and opts.get('no_commit'):
3258 if not update and opts.get('no_commit'):
3353 raise error.Abort(_('cannot use --no-commit with --bypass'))
3259 raise error.Abort(_('cannot use --no-commit with --bypass'))
3354 try:
3260 try:
3355 sim = float(opts.get('similarity') or 0)
3261 sim = float(opts.get('similarity') or 0)
3356 except ValueError:
3262 except ValueError:
3357 raise error.Abort(_('similarity must be a number'))
3263 raise error.Abort(_('similarity must be a number'))
3358 if sim < 0 or sim > 100:
3264 if sim < 0 or sim > 100:
3359 raise error.Abort(_('similarity must be between 0 and 100'))
3265 raise error.Abort(_('similarity must be between 0 and 100'))
3360 if sim and not update:
3266 if sim and not update:
3361 raise error.Abort(_('cannot use --similarity with --bypass'))
3267 raise error.Abort(_('cannot use --similarity with --bypass'))
3362 if exact:
3268 if exact:
3363 if opts.get('edit'):
3269 if opts.get('edit'):
3364 raise error.Abort(_('cannot use --exact with --edit'))
3270 raise error.Abort(_('cannot use --exact with --edit'))
3365 if opts.get('prefix'):
3271 if opts.get('prefix'):
3366 raise error.Abort(_('cannot use --exact with --prefix'))
3272 raise error.Abort(_('cannot use --exact with --prefix'))
3367
3273
3368 base = opts["base"]
3274 base = opts["base"]
3369 wlock = dsguard = lock = tr = None
3275 wlock = dsguard = lock = tr = None
3370 msgs = []
3276 msgs = []
3371 ret = 0
3277 ret = 0
3372
3278
3373
3279
3374 try:
3280 try:
3375 wlock = repo.wlock()
3281 wlock = repo.wlock()
3376
3282
3377 if update:
3283 if update:
3378 cmdutil.checkunfinished(repo)
3284 cmdutil.checkunfinished(repo)
3379 if (exact or not opts.get('force')):
3285 if (exact or not opts.get('force')):
3380 cmdutil.bailifchanged(repo)
3286 cmdutil.bailifchanged(repo)
3381
3287
3382 if not opts.get('no_commit'):
3288 if not opts.get('no_commit'):
3383 lock = repo.lock()
3289 lock = repo.lock()
3384 tr = repo.transaction('import')
3290 tr = repo.transaction('import')
3385 else:
3291 else:
3386 dsguard = dirstateguard.dirstateguard(repo, 'import')
3292 dsguard = dirstateguard.dirstateguard(repo, 'import')
3387 parents = repo[None].parents()
3293 parents = repo[None].parents()
3388 for patchurl in patches:
3294 for patchurl in patches:
3389 if patchurl == '-':
3295 if patchurl == '-':
3390 ui.status(_('applying patch from stdin\n'))
3296 ui.status(_('applying patch from stdin\n'))
3391 patchfile = ui.fin
3297 patchfile = ui.fin
3392 patchurl = 'stdin' # for error message
3298 patchurl = 'stdin' # for error message
3393 else:
3299 else:
3394 patchurl = os.path.join(base, patchurl)
3300 patchurl = os.path.join(base, patchurl)
3395 ui.status(_('applying %s\n') % patchurl)
3301 ui.status(_('applying %s\n') % patchurl)
3396 patchfile = hg.openpath(ui, patchurl)
3302 patchfile = hg.openpath(ui, patchurl)
3397
3303
3398 haspatch = False
3304 haspatch = False
3399 for hunk in patch.split(patchfile):
3305 for hunk in patch.split(patchfile):
3400 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3306 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3401 parents, opts,
3307 parents, opts,
3402 msgs, hg.clean)
3308 msgs, hg.clean)
3403 if msg:
3309 if msg:
3404 haspatch = True
3310 haspatch = True
3405 ui.note(msg + '\n')
3311 ui.note(msg + '\n')
3406 if update or exact:
3312 if update or exact:
3407 parents = repo[None].parents()
3313 parents = repo[None].parents()
3408 else:
3314 else:
3409 parents = [repo[node]]
3315 parents = [repo[node]]
3410 if rej:
3316 if rej:
3411 ui.write_err(_("patch applied partially\n"))
3317 ui.write_err(_("patch applied partially\n"))
3412 ui.write_err(_("(fix the .rej files and run "
3318 ui.write_err(_("(fix the .rej files and run "
3413 "`hg commit --amend`)\n"))
3319 "`hg commit --amend`)\n"))
3414 ret = 1
3320 ret = 1
3415 break
3321 break
3416
3322
3417 if not haspatch:
3323 if not haspatch:
3418 raise error.Abort(_('%s: no diffs found') % patchurl)
3324 raise error.Abort(_('%s: no diffs found') % patchurl)
3419
3325
3420 if tr:
3326 if tr:
3421 tr.close()
3327 tr.close()
3422 if msgs:
3328 if msgs:
3423 repo.savecommitmessage('\n* * *\n'.join(msgs))
3329 repo.savecommitmessage('\n* * *\n'.join(msgs))
3424 if dsguard:
3330 if dsguard:
3425 dsguard.close()
3331 dsguard.close()
3426 return ret
3332 return ret
3427 finally:
3333 finally:
3428 if tr:
3334 if tr:
3429 tr.release()
3335 tr.release()
3430 release(lock, dsguard, wlock)
3336 release(lock, dsguard, wlock)
3431
3337
3432 @command('incoming|in',
3338 @command('incoming|in',
3433 [('f', 'force', None,
3339 [('f', 'force', None,
3434 _('run even if remote repository is unrelated')),
3340 _('run even if remote repository is unrelated')),
3435 ('n', 'newest-first', None, _('show newest record first')),
3341 ('n', 'newest-first', None, _('show newest record first')),
3436 ('', 'bundle', '',
3342 ('', 'bundle', '',
3437 _('file to store the bundles into'), _('FILE')),
3343 _('file to store the bundles into'), _('FILE')),
3438 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3344 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3439 ('B', 'bookmarks', False, _("compare bookmarks")),
3345 ('B', 'bookmarks', False, _("compare bookmarks")),
3440 ('b', 'branch', [],
3346 ('b', 'branch', [],
3441 _('a specific branch you would like to pull'), _('BRANCH')),
3347 _('a specific branch you would like to pull'), _('BRANCH')),
3442 ] + logopts + remoteopts + subrepoopts,
3348 ] + logopts + remoteopts + subrepoopts,
3443 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3349 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3444 def incoming(ui, repo, source="default", **opts):
3350 def incoming(ui, repo, source="default", **opts):
3445 """show new changesets found in source
3351 """show new changesets found in source
3446
3352
3447 Show new changesets found in the specified path/URL or the default
3353 Show new changesets found in the specified path/URL or the default
3448 pull location. These are the changesets that would have been pulled
3354 pull location. These are the changesets that would have been pulled
3449 if a pull at the time you issued this command.
3355 if a pull at the time you issued this command.
3450
3356
3451 See pull for valid source format details.
3357 See pull for valid source format details.
3452
3358
3453 .. container:: verbose
3359 .. container:: verbose
3454
3360
3455 With -B/--bookmarks, the result of bookmark comparison between
3361 With -B/--bookmarks, the result of bookmark comparison between
3456 local and remote repositories is displayed. With -v/--verbose,
3362 local and remote repositories is displayed. With -v/--verbose,
3457 status is also displayed for each bookmark like below::
3363 status is also displayed for each bookmark like below::
3458
3364
3459 BM1 01234567890a added
3365 BM1 01234567890a added
3460 BM2 1234567890ab advanced
3366 BM2 1234567890ab advanced
3461 BM3 234567890abc diverged
3367 BM3 234567890abc diverged
3462 BM4 34567890abcd changed
3368 BM4 34567890abcd changed
3463
3369
3464 The action taken locally when pulling depends on the
3370 The action taken locally when pulling depends on the
3465 status of each bookmark:
3371 status of each bookmark:
3466
3372
3467 :``added``: pull will create it
3373 :``added``: pull will create it
3468 :``advanced``: pull will update it
3374 :``advanced``: pull will update it
3469 :``diverged``: pull will create a divergent bookmark
3375 :``diverged``: pull will create a divergent bookmark
3470 :``changed``: result depends on remote changesets
3376 :``changed``: result depends on remote changesets
3471
3377
3472 From the point of view of pulling behavior, bookmark
3378 From the point of view of pulling behavior, bookmark
3473 existing only in the remote repository are treated as ``added``,
3379 existing only in the remote repository are treated as ``added``,
3474 even if it is in fact locally deleted.
3380 even if it is in fact locally deleted.
3475
3381
3476 .. container:: verbose
3382 .. container:: verbose
3477
3383
3478 For remote repository, using --bundle avoids downloading the
3384 For remote repository, using --bundle avoids downloading the
3479 changesets twice if the incoming is followed by a pull.
3385 changesets twice if the incoming is followed by a pull.
3480
3386
3481 Examples:
3387 Examples:
3482
3388
3483 - show incoming changes with patches and full description::
3389 - show incoming changes with patches and full description::
3484
3390
3485 hg incoming -vp
3391 hg incoming -vp
3486
3392
3487 - show incoming changes excluding merges, store a bundle::
3393 - show incoming changes excluding merges, store a bundle::
3488
3394
3489 hg in -vpM --bundle incoming.hg
3395 hg in -vpM --bundle incoming.hg
3490 hg pull incoming.hg
3396 hg pull incoming.hg
3491
3397
3492 - briefly list changes inside a bundle::
3398 - briefly list changes inside a bundle::
3493
3399
3494 hg in changes.hg -T "{desc|firstline}\\n"
3400 hg in changes.hg -T "{desc|firstline}\\n"
3495
3401
3496 Returns 0 if there are incoming changes, 1 otherwise.
3402 Returns 0 if there are incoming changes, 1 otherwise.
3497 """
3403 """
3498 if opts.get('graph'):
3404 if opts.get('graph'):
3499 cmdutil.checkunsupportedgraphflags([], opts)
3405 cmdutil.checkunsupportedgraphflags([], opts)
3500 def display(other, chlist, displayer):
3406 def display(other, chlist, displayer):
3501 revdag = cmdutil.graphrevs(other, chlist, opts)
3407 revdag = cmdutil.graphrevs(other, chlist, opts)
3502 cmdutil.displaygraph(ui, repo, revdag, displayer,
3408 cmdutil.displaygraph(ui, repo, revdag, displayer,
3503 graphmod.asciiedges)
3409 graphmod.asciiedges)
3504
3410
3505 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3411 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3506 return 0
3412 return 0
3507
3413
3508 if opts.get('bundle') and opts.get('subrepos'):
3414 if opts.get('bundle') and opts.get('subrepos'):
3509 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3415 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3510
3416
3511 if opts.get('bookmarks'):
3417 if opts.get('bookmarks'):
3512 source, branches = hg.parseurl(ui.expandpath(source),
3418 source, branches = hg.parseurl(ui.expandpath(source),
3513 opts.get('branch'))
3419 opts.get('branch'))
3514 other = hg.peer(repo, opts, source)
3420 other = hg.peer(repo, opts, source)
3515 if 'bookmarks' not in other.listkeys('namespaces'):
3421 if 'bookmarks' not in other.listkeys('namespaces'):
3516 ui.warn(_("remote doesn't support bookmarks\n"))
3422 ui.warn(_("remote doesn't support bookmarks\n"))
3517 return 0
3423 return 0
3518 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3424 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3519 return bookmarks.incoming(ui, repo, other)
3425 return bookmarks.incoming(ui, repo, other)
3520
3426
3521 repo._subtoppath = ui.expandpath(source)
3427 repo._subtoppath = ui.expandpath(source)
3522 try:
3428 try:
3523 return hg.incoming(ui, repo, source, opts)
3429 return hg.incoming(ui, repo, source, opts)
3524 finally:
3430 finally:
3525 del repo._subtoppath
3431 del repo._subtoppath
3526
3432
3527
3433
3528 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3434 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3529 norepo=True)
3435 norepo=True)
3530 def init(ui, dest=".", **opts):
3436 def init(ui, dest=".", **opts):
3531 """create a new repository in the given directory
3437 """create a new repository in the given directory
3532
3438
3533 Initialize a new repository in the given directory. If the given
3439 Initialize a new repository in the given directory. If the given
3534 directory does not exist, it will be created.
3440 directory does not exist, it will be created.
3535
3441
3536 If no directory is given, the current directory is used.
3442 If no directory is given, the current directory is used.
3537
3443
3538 It is possible to specify an ``ssh://`` URL as the destination.
3444 It is possible to specify an ``ssh://`` URL as the destination.
3539 See :hg:`help urls` for more information.
3445 See :hg:`help urls` for more information.
3540
3446
3541 Returns 0 on success.
3447 Returns 0 on success.
3542 """
3448 """
3543 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3449 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3544
3450
3545 @command('locate',
3451 @command('locate',
3546 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3452 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3547 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3453 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3548 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3454 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3549 ] + walkopts,
3455 ] + walkopts,
3550 _('[OPTION]... [PATTERN]...'))
3456 _('[OPTION]... [PATTERN]...'))
3551 def locate(ui, repo, *pats, **opts):
3457 def locate(ui, repo, *pats, **opts):
3552 """locate files matching specific patterns (DEPRECATED)
3458 """locate files matching specific patterns (DEPRECATED)
3553
3459
3554 Print files under Mercurial control in the working directory whose
3460 Print files under Mercurial control in the working directory whose
3555 names match the given patterns.
3461 names match the given patterns.
3556
3462
3557 By default, this command searches all directories in the working
3463 By default, this command searches all directories in the working
3558 directory. To search just the current directory and its
3464 directory. To search just the current directory and its
3559 subdirectories, use "--include .".
3465 subdirectories, use "--include .".
3560
3466
3561 If no patterns are given to match, this command prints the names
3467 If no patterns are given to match, this command prints the names
3562 of all files under Mercurial control in the working directory.
3468 of all files under Mercurial control in the working directory.
3563
3469
3564 If you want to feed the output of this command into the "xargs"
3470 If you want to feed the output of this command into the "xargs"
3565 command, use the -0 option to both this command and "xargs". This
3471 command, use the -0 option to both this command and "xargs". This
3566 will avoid the problem of "xargs" treating single filenames that
3472 will avoid the problem of "xargs" treating single filenames that
3567 contain whitespace as multiple filenames.
3473 contain whitespace as multiple filenames.
3568
3474
3569 See :hg:`help files` for a more versatile command.
3475 See :hg:`help files` for a more versatile command.
3570
3476
3571 Returns 0 if a match is found, 1 otherwise.
3477 Returns 0 if a match is found, 1 otherwise.
3572 """
3478 """
3573 if opts.get('print0'):
3479 if opts.get('print0'):
3574 end = '\0'
3480 end = '\0'
3575 else:
3481 else:
3576 end = '\n'
3482 end = '\n'
3577 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3483 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3578
3484
3579 ret = 1
3485 ret = 1
3580 ctx = repo[rev]
3486 ctx = repo[rev]
3581 m = scmutil.match(ctx, pats, opts, default='relglob',
3487 m = scmutil.match(ctx, pats, opts, default='relglob',
3582 badfn=lambda x, y: False)
3488 badfn=lambda x, y: False)
3583
3489
3584 for abs in ctx.matches(m):
3490 for abs in ctx.matches(m):
3585 if opts.get('fullpath'):
3491 if opts.get('fullpath'):
3586 ui.write(repo.wjoin(abs), end)
3492 ui.write(repo.wjoin(abs), end)
3587 else:
3493 else:
3588 ui.write(((pats and m.rel(abs)) or abs), end)
3494 ui.write(((pats and m.rel(abs)) or abs), end)
3589 ret = 0
3495 ret = 0
3590
3496
3591 return ret
3497 return ret
3592
3498
3593 @command('^log|history',
3499 @command('^log|history',
3594 [('f', 'follow', None,
3500 [('f', 'follow', None,
3595 _('follow changeset history, or file history across copies and renames')),
3501 _('follow changeset history, or file history across copies and renames')),
3596 ('', 'follow-first', None,
3502 ('', 'follow-first', None,
3597 _('only follow the first parent of merge changesets (DEPRECATED)')),
3503 _('only follow the first parent of merge changesets (DEPRECATED)')),
3598 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3504 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3599 ('C', 'copies', None, _('show copied files')),
3505 ('C', 'copies', None, _('show copied files')),
3600 ('k', 'keyword', [],
3506 ('k', 'keyword', [],
3601 _('do case-insensitive search for a given text'), _('TEXT')),
3507 _('do case-insensitive search for a given text'), _('TEXT')),
3602 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3508 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3603 ('', 'removed', None, _('include revisions where files were removed')),
3509 ('', 'removed', None, _('include revisions where files were removed')),
3604 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3510 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3605 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3511 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3606 ('', 'only-branch', [],
3512 ('', 'only-branch', [],
3607 _('show only changesets within the given named branch (DEPRECATED)'),
3513 _('show only changesets within the given named branch (DEPRECATED)'),
3608 _('BRANCH')),
3514 _('BRANCH')),
3609 ('b', 'branch', [],
3515 ('b', 'branch', [],
3610 _('show changesets within the given named branch'), _('BRANCH')),
3516 _('show changesets within the given named branch'), _('BRANCH')),
3611 ('P', 'prune', [],
3517 ('P', 'prune', [],
3612 _('do not display revision or any of its ancestors'), _('REV')),
3518 _('do not display revision or any of its ancestors'), _('REV')),
3613 ] + logopts + walkopts,
3519 ] + logopts + walkopts,
3614 _('[OPTION]... [FILE]'),
3520 _('[OPTION]... [FILE]'),
3615 inferrepo=True)
3521 inferrepo=True)
3616 def log(ui, repo, *pats, **opts):
3522 def log(ui, repo, *pats, **opts):
3617 """show revision history of entire repository or files
3523 """show revision history of entire repository or files
3618
3524
3619 Print the revision history of the specified files or the entire
3525 Print the revision history of the specified files or the entire
3620 project.
3526 project.
3621
3527
3622 If no revision range is specified, the default is ``tip:0`` unless
3528 If no revision range is specified, the default is ``tip:0`` unless
3623 --follow is set, in which case the working directory parent is
3529 --follow is set, in which case the working directory parent is
3624 used as the starting revision.
3530 used as the starting revision.
3625
3531
3626 File history is shown without following rename or copy history of
3532 File history is shown without following rename or copy history of
3627 files. Use -f/--follow with a filename to follow history across
3533 files. Use -f/--follow with a filename to follow history across
3628 renames and copies. --follow without a filename will only show
3534 renames and copies. --follow without a filename will only show
3629 ancestors or descendants of the starting revision.
3535 ancestors or descendants of the starting revision.
3630
3536
3631 By default this command prints revision number and changeset id,
3537 By default this command prints revision number and changeset id,
3632 tags, non-trivial parents, user, date and time, and a summary for
3538 tags, non-trivial parents, user, date and time, and a summary for
3633 each commit. When the -v/--verbose switch is used, the list of
3539 each commit. When the -v/--verbose switch is used, the list of
3634 changed files and full commit message are shown.
3540 changed files and full commit message are shown.
3635
3541
3636 With --graph the revisions are shown as an ASCII art DAG with the most
3542 With --graph the revisions are shown as an ASCII art DAG with the most
3637 recent changeset at the top.
3543 recent changeset at the top.
3638 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3544 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3639 and '+' represents a fork where the changeset from the lines below is a
3545 and '+' represents a fork where the changeset from the lines below is a
3640 parent of the 'o' merge on the same line.
3546 parent of the 'o' merge on the same line.
3641
3547
3642 .. note::
3548 .. note::
3643
3549
3644 :hg:`log --patch` may generate unexpected diff output for merge
3550 :hg:`log --patch` may generate unexpected diff output for merge
3645 changesets, as it will only compare the merge changeset against
3551 changesets, as it will only compare the merge changeset against
3646 its first parent. Also, only files different from BOTH parents
3552 its first parent. Also, only files different from BOTH parents
3647 will appear in files:.
3553 will appear in files:.
3648
3554
3649 .. note::
3555 .. note::
3650
3556
3651 For performance reasons, :hg:`log FILE` may omit duplicate changes
3557 For performance reasons, :hg:`log FILE` may omit duplicate changes
3652 made on branches and will not show removals or mode changes. To
3558 made on branches and will not show removals or mode changes. To
3653 see all such changes, use the --removed switch.
3559 see all such changes, use the --removed switch.
3654
3560
3655 .. container:: verbose
3561 .. container:: verbose
3656
3562
3657 Some examples:
3563 Some examples:
3658
3564
3659 - changesets with full descriptions and file lists::
3565 - changesets with full descriptions and file lists::
3660
3566
3661 hg log -v
3567 hg log -v
3662
3568
3663 - changesets ancestral to the working directory::
3569 - changesets ancestral to the working directory::
3664
3570
3665 hg log -f
3571 hg log -f
3666
3572
3667 - last 10 commits on the current branch::
3573 - last 10 commits on the current branch::
3668
3574
3669 hg log -l 10 -b .
3575 hg log -l 10 -b .
3670
3576
3671 - changesets showing all modifications of a file, including removals::
3577 - changesets showing all modifications of a file, including removals::
3672
3578
3673 hg log --removed file.c
3579 hg log --removed file.c
3674
3580
3675 - all changesets that touch a directory, with diffs, excluding merges::
3581 - all changesets that touch a directory, with diffs, excluding merges::
3676
3582
3677 hg log -Mp lib/
3583 hg log -Mp lib/
3678
3584
3679 - all revision numbers that match a keyword::
3585 - all revision numbers that match a keyword::
3680
3586
3681 hg log -k bug --template "{rev}\\n"
3587 hg log -k bug --template "{rev}\\n"
3682
3588
3683 - the full hash identifier of the working directory parent::
3589 - the full hash identifier of the working directory parent::
3684
3590
3685 hg log -r . --template "{node}\\n"
3591 hg log -r . --template "{node}\\n"
3686
3592
3687 - list available log templates::
3593 - list available log templates::
3688
3594
3689 hg log -T list
3595 hg log -T list
3690
3596
3691 - check if a given changeset is included in a tagged release::
3597 - check if a given changeset is included in a tagged release::
3692
3598
3693 hg log -r "a21ccf and ancestor(1.9)"
3599 hg log -r "a21ccf and ancestor(1.9)"
3694
3600
3695 - find all changesets by some user in a date range::
3601 - find all changesets by some user in a date range::
3696
3602
3697 hg log -k alice -d "may 2008 to jul 2008"
3603 hg log -k alice -d "may 2008 to jul 2008"
3698
3604
3699 - summary of all changesets after the last tag::
3605 - summary of all changesets after the last tag::
3700
3606
3701 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3607 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3702
3608
3703 See :hg:`help dates` for a list of formats valid for -d/--date.
3609 See :hg:`help dates` for a list of formats valid for -d/--date.
3704
3610
3705 See :hg:`help revisions` for more about specifying and ordering
3611 See :hg:`help revisions` for more about specifying and ordering
3706 revisions.
3612 revisions.
3707
3613
3708 See :hg:`help templates` for more about pre-packaged styles and
3614 See :hg:`help templates` for more about pre-packaged styles and
3709 specifying custom templates.
3615 specifying custom templates.
3710
3616
3711 Returns 0 on success.
3617 Returns 0 on success.
3712
3618
3713 """
3619 """
3714 if opts.get('follow') and opts.get('rev'):
3620 if opts.get('follow') and opts.get('rev'):
3715 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3621 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3716 del opts['follow']
3622 del opts['follow']
3717
3623
3718 if opts.get('graph'):
3624 if opts.get('graph'):
3719 return cmdutil.graphlog(ui, repo, *pats, **opts)
3625 return cmdutil.graphlog(ui, repo, *pats, **opts)
3720
3626
3721 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3627 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3722 limit = cmdutil.loglimit(opts)
3628 limit = cmdutil.loglimit(opts)
3723 count = 0
3629 count = 0
3724
3630
3725 getrenamed = None
3631 getrenamed = None
3726 if opts.get('copies'):
3632 if opts.get('copies'):
3727 endrev = None
3633 endrev = None
3728 if opts.get('rev'):
3634 if opts.get('rev'):
3729 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3635 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3730 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3636 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3731
3637
3732 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3638 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3733 for rev in revs:
3639 for rev in revs:
3734 if count == limit:
3640 if count == limit:
3735 break
3641 break
3736 ctx = repo[rev]
3642 ctx = repo[rev]
3737 copies = None
3643 copies = None
3738 if getrenamed is not None and rev:
3644 if getrenamed is not None and rev:
3739 copies = []
3645 copies = []
3740 for fn in ctx.files():
3646 for fn in ctx.files():
3741 rename = getrenamed(fn, rev)
3647 rename = getrenamed(fn, rev)
3742 if rename:
3648 if rename:
3743 copies.append((fn, rename[0]))
3649 copies.append((fn, rename[0]))
3744 if filematcher:
3650 if filematcher:
3745 revmatchfn = filematcher(ctx.rev())
3651 revmatchfn = filematcher(ctx.rev())
3746 else:
3652 else:
3747 revmatchfn = None
3653 revmatchfn = None
3748 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3654 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3749 if displayer.flush(ctx):
3655 if displayer.flush(ctx):
3750 count += 1
3656 count += 1
3751
3657
3752 displayer.close()
3658 displayer.close()
3753
3659
3754 @command('manifest',
3660 @command('manifest',
3755 [('r', 'rev', '', _('revision to display'), _('REV')),
3661 [('r', 'rev', '', _('revision to display'), _('REV')),
3756 ('', 'all', False, _("list files from all revisions"))]
3662 ('', 'all', False, _("list files from all revisions"))]
3757 + formatteropts,
3663 + formatteropts,
3758 _('[-r REV]'))
3664 _('[-r REV]'))
3759 def manifest(ui, repo, node=None, rev=None, **opts):
3665 def manifest(ui, repo, node=None, rev=None, **opts):
3760 """output the current or given revision of the project manifest
3666 """output the current or given revision of the project manifest
3761
3667
3762 Print a list of version controlled files for the given revision.
3668 Print a list of version controlled files for the given revision.
3763 If no revision is given, the first parent of the working directory
3669 If no revision is given, the first parent of the working directory
3764 is used, or the null revision if no revision is checked out.
3670 is used, or the null revision if no revision is checked out.
3765
3671
3766 With -v, print file permissions, symlink and executable bits.
3672 With -v, print file permissions, symlink and executable bits.
3767 With --debug, print file revision hashes.
3673 With --debug, print file revision hashes.
3768
3674
3769 If option --all is specified, the list of all files from all revisions
3675 If option --all is specified, the list of all files from all revisions
3770 is printed. This includes deleted and renamed files.
3676 is printed. This includes deleted and renamed files.
3771
3677
3772 Returns 0 on success.
3678 Returns 0 on success.
3773 """
3679 """
3774
3680
3775 fm = ui.formatter('manifest', opts)
3681 fm = ui.formatter('manifest', opts)
3776
3682
3777 if opts.get('all'):
3683 if opts.get('all'):
3778 if rev or node:
3684 if rev or node:
3779 raise error.Abort(_("can't specify a revision with --all"))
3685 raise error.Abort(_("can't specify a revision with --all"))
3780
3686
3781 res = []
3687 res = []
3782 prefix = "data/"
3688 prefix = "data/"
3783 suffix = ".i"
3689 suffix = ".i"
3784 plen = len(prefix)
3690 plen = len(prefix)
3785 slen = len(suffix)
3691 slen = len(suffix)
3786 with repo.lock():
3692 with repo.lock():
3787 for fn, b, size in repo.store.datafiles():
3693 for fn, b, size in repo.store.datafiles():
3788 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3694 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3789 res.append(fn[plen:-slen])
3695 res.append(fn[plen:-slen])
3790 for f in res:
3696 for f in res:
3791 fm.startitem()
3697 fm.startitem()
3792 fm.write("path", '%s\n', f)
3698 fm.write("path", '%s\n', f)
3793 fm.end()
3699 fm.end()
3794 return
3700 return
3795
3701
3796 if rev and node:
3702 if rev and node:
3797 raise error.Abort(_("please specify just one revision"))
3703 raise error.Abort(_("please specify just one revision"))
3798
3704
3799 if not node:
3705 if not node:
3800 node = rev
3706 node = rev
3801
3707
3802 char = {'l': '@', 'x': '*', '': ''}
3708 char = {'l': '@', 'x': '*', '': ''}
3803 mode = {'l': '644', 'x': '755', '': '644'}
3709 mode = {'l': '644', 'x': '755', '': '644'}
3804 ctx = scmutil.revsingle(repo, node)
3710 ctx = scmutil.revsingle(repo, node)
3805 mf = ctx.manifest()
3711 mf = ctx.manifest()
3806 for f in ctx:
3712 for f in ctx:
3807 fm.startitem()
3713 fm.startitem()
3808 fl = ctx[f].flags()
3714 fl = ctx[f].flags()
3809 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3715 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3810 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3716 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3811 fm.write('path', '%s\n', f)
3717 fm.write('path', '%s\n', f)
3812 fm.end()
3718 fm.end()
3813
3719
3814 @command('^merge',
3720 @command('^merge',
3815 [('f', 'force', None,
3721 [('f', 'force', None,
3816 _('force a merge including outstanding changes (DEPRECATED)')),
3722 _('force a merge including outstanding changes (DEPRECATED)')),
3817 ('r', 'rev', '', _('revision to merge'), _('REV')),
3723 ('r', 'rev', '', _('revision to merge'), _('REV')),
3818 ('P', 'preview', None,
3724 ('P', 'preview', None,
3819 _('review revisions to merge (no merge is performed)'))
3725 _('review revisions to merge (no merge is performed)'))
3820 ] + mergetoolopts,
3726 ] + mergetoolopts,
3821 _('[-P] [[-r] REV]'))
3727 _('[-P] [[-r] REV]'))
3822 def merge(ui, repo, node=None, **opts):
3728 def merge(ui, repo, node=None, **opts):
3823 """merge another revision into working directory
3729 """merge another revision into working directory
3824
3730
3825 The current working directory is updated with all changes made in
3731 The current working directory is updated with all changes made in
3826 the requested revision since the last common predecessor revision.
3732 the requested revision since the last common predecessor revision.
3827
3733
3828 Files that changed between either parent are marked as changed for
3734 Files that changed between either parent are marked as changed for
3829 the next commit and a commit must be performed before any further
3735 the next commit and a commit must be performed before any further
3830 updates to the repository are allowed. The next commit will have
3736 updates to the repository are allowed. The next commit will have
3831 two parents.
3737 two parents.
3832
3738
3833 ``--tool`` can be used to specify the merge tool used for file
3739 ``--tool`` can be used to specify the merge tool used for file
3834 merges. It overrides the HGMERGE environment variable and your
3740 merges. It overrides the HGMERGE environment variable and your
3835 configuration files. See :hg:`help merge-tools` for options.
3741 configuration files. See :hg:`help merge-tools` for options.
3836
3742
3837 If no revision is specified, the working directory's parent is a
3743 If no revision is specified, the working directory's parent is a
3838 head revision, and the current branch contains exactly one other
3744 head revision, and the current branch contains exactly one other
3839 head, the other head is merged with by default. Otherwise, an
3745 head, the other head is merged with by default. Otherwise, an
3840 explicit revision with which to merge with must be provided.
3746 explicit revision with which to merge with must be provided.
3841
3747
3842 See :hg:`help resolve` for information on handling file conflicts.
3748 See :hg:`help resolve` for information on handling file conflicts.
3843
3749
3844 To undo an uncommitted merge, use :hg:`update --clean .` which
3750 To undo an uncommitted merge, use :hg:`update --clean .` which
3845 will check out a clean copy of the original merge parent, losing
3751 will check out a clean copy of the original merge parent, losing
3846 all changes.
3752 all changes.
3847
3753
3848 Returns 0 on success, 1 if there are unresolved files.
3754 Returns 0 on success, 1 if there are unresolved files.
3849 """
3755 """
3850
3756
3851 if opts.get('rev') and node:
3757 if opts.get('rev') and node:
3852 raise error.Abort(_("please specify just one revision"))
3758 raise error.Abort(_("please specify just one revision"))
3853 if not node:
3759 if not node:
3854 node = opts.get('rev')
3760 node = opts.get('rev')
3855
3761
3856 if node:
3762 if node:
3857 node = scmutil.revsingle(repo, node).node()
3763 node = scmutil.revsingle(repo, node).node()
3858
3764
3859 if not node:
3765 if not node:
3860 node = repo[destutil.destmerge(repo)].node()
3766 node = repo[destutil.destmerge(repo)].node()
3861
3767
3862 if opts.get('preview'):
3768 if opts.get('preview'):
3863 # find nodes that are ancestors of p2 but not of p1
3769 # find nodes that are ancestors of p2 but not of p1
3864 p1 = repo.lookup('.')
3770 p1 = repo.lookup('.')
3865 p2 = repo.lookup(node)
3771 p2 = repo.lookup(node)
3866 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3772 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3867
3773
3868 displayer = cmdutil.show_changeset(ui, repo, opts)
3774 displayer = cmdutil.show_changeset(ui, repo, opts)
3869 for node in nodes:
3775 for node in nodes:
3870 displayer.show(repo[node])
3776 displayer.show(repo[node])
3871 displayer.close()
3777 displayer.close()
3872 return 0
3778 return 0
3873
3779
3874 try:
3780 try:
3875 # ui.forcemerge is an internal variable, do not document
3781 # ui.forcemerge is an internal variable, do not document
3876 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3782 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3877 force = opts.get('force')
3783 force = opts.get('force')
3878 labels = ['working copy', 'merge rev']
3784 labels = ['working copy', 'merge rev']
3879 return hg.merge(repo, node, force=force, mergeforce=force,
3785 return hg.merge(repo, node, force=force, mergeforce=force,
3880 labels=labels)
3786 labels=labels)
3881 finally:
3787 finally:
3882 ui.setconfig('ui', 'forcemerge', '', 'merge')
3788 ui.setconfig('ui', 'forcemerge', '', 'merge')
3883
3789
3884 @command('outgoing|out',
3790 @command('outgoing|out',
3885 [('f', 'force', None, _('run even when the destination is unrelated')),
3791 [('f', 'force', None, _('run even when the destination is unrelated')),
3886 ('r', 'rev', [],
3792 ('r', 'rev', [],
3887 _('a changeset intended to be included in the destination'), _('REV')),
3793 _('a changeset intended to be included in the destination'), _('REV')),
3888 ('n', 'newest-first', None, _('show newest record first')),
3794 ('n', 'newest-first', None, _('show newest record first')),
3889 ('B', 'bookmarks', False, _('compare bookmarks')),
3795 ('B', 'bookmarks', False, _('compare bookmarks')),
3890 ('b', 'branch', [], _('a specific branch you would like to push'),
3796 ('b', 'branch', [], _('a specific branch you would like to push'),
3891 _('BRANCH')),
3797 _('BRANCH')),
3892 ] + logopts + remoteopts + subrepoopts,
3798 ] + logopts + remoteopts + subrepoopts,
3893 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3799 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3894 def outgoing(ui, repo, dest=None, **opts):
3800 def outgoing(ui, repo, dest=None, **opts):
3895 """show changesets not found in the destination
3801 """show changesets not found in the destination
3896
3802
3897 Show changesets not found in the specified destination repository
3803 Show changesets not found in the specified destination repository
3898 or the default push location. These are the changesets that would
3804 or the default push location. These are the changesets that would
3899 be pushed if a push was requested.
3805 be pushed if a push was requested.
3900
3806
3901 See pull for details of valid destination formats.
3807 See pull for details of valid destination formats.
3902
3808
3903 .. container:: verbose
3809 .. container:: verbose
3904
3810
3905 With -B/--bookmarks, the result of bookmark comparison between
3811 With -B/--bookmarks, the result of bookmark comparison between
3906 local and remote repositories is displayed. With -v/--verbose,
3812 local and remote repositories is displayed. With -v/--verbose,
3907 status is also displayed for each bookmark like below::
3813 status is also displayed for each bookmark like below::
3908
3814
3909 BM1 01234567890a added
3815 BM1 01234567890a added
3910 BM2 deleted
3816 BM2 deleted
3911 BM3 234567890abc advanced
3817 BM3 234567890abc advanced
3912 BM4 34567890abcd diverged
3818 BM4 34567890abcd diverged
3913 BM5 4567890abcde changed
3819 BM5 4567890abcde changed
3914
3820
3915 The action taken when pushing depends on the
3821 The action taken when pushing depends on the
3916 status of each bookmark:
3822 status of each bookmark:
3917
3823
3918 :``added``: push with ``-B`` will create it
3824 :``added``: push with ``-B`` will create it
3919 :``deleted``: push with ``-B`` will delete it
3825 :``deleted``: push with ``-B`` will delete it
3920 :``advanced``: push will update it
3826 :``advanced``: push will update it
3921 :``diverged``: push with ``-B`` will update it
3827 :``diverged``: push with ``-B`` will update it
3922 :``changed``: push with ``-B`` will update it
3828 :``changed``: push with ``-B`` will update it
3923
3829
3924 From the point of view of pushing behavior, bookmarks
3830 From the point of view of pushing behavior, bookmarks
3925 existing only in the remote repository are treated as
3831 existing only in the remote repository are treated as
3926 ``deleted``, even if it is in fact added remotely.
3832 ``deleted``, even if it is in fact added remotely.
3927
3833
3928 Returns 0 if there are outgoing changes, 1 otherwise.
3834 Returns 0 if there are outgoing changes, 1 otherwise.
3929 """
3835 """
3930 if opts.get('graph'):
3836 if opts.get('graph'):
3931 cmdutil.checkunsupportedgraphflags([], opts)
3837 cmdutil.checkunsupportedgraphflags([], opts)
3932 o, other = hg._outgoing(ui, repo, dest, opts)
3838 o, other = hg._outgoing(ui, repo, dest, opts)
3933 if not o:
3839 if not o:
3934 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3840 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3935 return
3841 return
3936
3842
3937 revdag = cmdutil.graphrevs(repo, o, opts)
3843 revdag = cmdutil.graphrevs(repo, o, opts)
3938 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3844 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3939 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3845 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3940 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3846 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3941 return 0
3847 return 0
3942
3848
3943 if opts.get('bookmarks'):
3849 if opts.get('bookmarks'):
3944 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3850 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3945 dest, branches = hg.parseurl(dest, opts.get('branch'))
3851 dest, branches = hg.parseurl(dest, opts.get('branch'))
3946 other = hg.peer(repo, opts, dest)
3852 other = hg.peer(repo, opts, dest)
3947 if 'bookmarks' not in other.listkeys('namespaces'):
3853 if 'bookmarks' not in other.listkeys('namespaces'):
3948 ui.warn(_("remote doesn't support bookmarks\n"))
3854 ui.warn(_("remote doesn't support bookmarks\n"))
3949 return 0
3855 return 0
3950 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3856 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3951 return bookmarks.outgoing(ui, repo, other)
3857 return bookmarks.outgoing(ui, repo, other)
3952
3858
3953 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3859 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3954 try:
3860 try:
3955 return hg.outgoing(ui, repo, dest, opts)
3861 return hg.outgoing(ui, repo, dest, opts)
3956 finally:
3862 finally:
3957 del repo._subtoppath
3863 del repo._subtoppath
3958
3864
3959 @command('parents',
3865 @command('parents',
3960 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3866 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3961 ] + templateopts,
3867 ] + templateopts,
3962 _('[-r REV] [FILE]'),
3868 _('[-r REV] [FILE]'),
3963 inferrepo=True)
3869 inferrepo=True)
3964 def parents(ui, repo, file_=None, **opts):
3870 def parents(ui, repo, file_=None, **opts):
3965 """show the parents of the working directory or revision (DEPRECATED)
3871 """show the parents of the working directory or revision (DEPRECATED)
3966
3872
3967 Print the working directory's parent revisions. If a revision is
3873 Print the working directory's parent revisions. If a revision is
3968 given via -r/--rev, the parent of that revision will be printed.
3874 given via -r/--rev, the parent of that revision will be printed.
3969 If a file argument is given, the revision in which the file was
3875 If a file argument is given, the revision in which the file was
3970 last changed (before the working directory revision or the
3876 last changed (before the working directory revision or the
3971 argument to --rev if given) is printed.
3877 argument to --rev if given) is printed.
3972
3878
3973 This command is equivalent to::
3879 This command is equivalent to::
3974
3880
3975 hg log -r "p1()+p2()" or
3881 hg log -r "p1()+p2()" or
3976 hg log -r "p1(REV)+p2(REV)" or
3882 hg log -r "p1(REV)+p2(REV)" or
3977 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3883 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3978 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3884 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3979
3885
3980 See :hg:`summary` and :hg:`help revsets` for related information.
3886 See :hg:`summary` and :hg:`help revsets` for related information.
3981
3887
3982 Returns 0 on success.
3888 Returns 0 on success.
3983 """
3889 """
3984
3890
3985 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3891 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3986
3892
3987 if file_:
3893 if file_:
3988 m = scmutil.match(ctx, (file_,), opts)
3894 m = scmutil.match(ctx, (file_,), opts)
3989 if m.anypats() or len(m.files()) != 1:
3895 if m.anypats() or len(m.files()) != 1:
3990 raise error.Abort(_('can only specify an explicit filename'))
3896 raise error.Abort(_('can only specify an explicit filename'))
3991 file_ = m.files()[0]
3897 file_ = m.files()[0]
3992 filenodes = []
3898 filenodes = []
3993 for cp in ctx.parents():
3899 for cp in ctx.parents():
3994 if not cp:
3900 if not cp:
3995 continue
3901 continue
3996 try:
3902 try:
3997 filenodes.append(cp.filenode(file_))
3903 filenodes.append(cp.filenode(file_))
3998 except error.LookupError:
3904 except error.LookupError:
3999 pass
3905 pass
4000 if not filenodes:
3906 if not filenodes:
4001 raise error.Abort(_("'%s' not found in manifest!") % file_)
3907 raise error.Abort(_("'%s' not found in manifest!") % file_)
4002 p = []
3908 p = []
4003 for fn in filenodes:
3909 for fn in filenodes:
4004 fctx = repo.filectx(file_, fileid=fn)
3910 fctx = repo.filectx(file_, fileid=fn)
4005 p.append(fctx.node())
3911 p.append(fctx.node())
4006 else:
3912 else:
4007 p = [cp.node() for cp in ctx.parents()]
3913 p = [cp.node() for cp in ctx.parents()]
4008
3914
4009 displayer = cmdutil.show_changeset(ui, repo, opts)
3915 displayer = cmdutil.show_changeset(ui, repo, opts)
4010 for n in p:
3916 for n in p:
4011 if n != nullid:
3917 if n != nullid:
4012 displayer.show(repo[n])
3918 displayer.show(repo[n])
4013 displayer.close()
3919 displayer.close()
4014
3920
4015 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3921 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4016 def paths(ui, repo, search=None, **opts):
3922 def paths(ui, repo, search=None, **opts):
4017 """show aliases for remote repositories
3923 """show aliases for remote repositories
4018
3924
4019 Show definition of symbolic path name NAME. If no name is given,
3925 Show definition of symbolic path name NAME. If no name is given,
4020 show definition of all available names.
3926 show definition of all available names.
4021
3927
4022 Option -q/--quiet suppresses all output when searching for NAME
3928 Option -q/--quiet suppresses all output when searching for NAME
4023 and shows only the path names when listing all definitions.
3929 and shows only the path names when listing all definitions.
4024
3930
4025 Path names are defined in the [paths] section of your
3931 Path names are defined in the [paths] section of your
4026 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3932 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4027 repository, ``.hg/hgrc`` is used, too.
3933 repository, ``.hg/hgrc`` is used, too.
4028
3934
4029 The path names ``default`` and ``default-push`` have a special
3935 The path names ``default`` and ``default-push`` have a special
4030 meaning. When performing a push or pull operation, they are used
3936 meaning. When performing a push or pull operation, they are used
4031 as fallbacks if no location is specified on the command-line.
3937 as fallbacks if no location is specified on the command-line.
4032 When ``default-push`` is set, it will be used for push and
3938 When ``default-push`` is set, it will be used for push and
4033 ``default`` will be used for pull; otherwise ``default`` is used
3939 ``default`` will be used for pull; otherwise ``default`` is used
4034 as the fallback for both. When cloning a repository, the clone
3940 as the fallback for both. When cloning a repository, the clone
4035 source is written as ``default`` in ``.hg/hgrc``.
3941 source is written as ``default`` in ``.hg/hgrc``.
4036
3942
4037 .. note::
3943 .. note::
4038
3944
4039 ``default`` and ``default-push`` apply to all inbound (e.g.
3945 ``default`` and ``default-push`` apply to all inbound (e.g.
4040 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3946 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4041 and :hg:`bundle`) operations.
3947 and :hg:`bundle`) operations.
4042
3948
4043 See :hg:`help urls` for more information.
3949 See :hg:`help urls` for more information.
4044
3950
4045 Returns 0 on success.
3951 Returns 0 on success.
4046 """
3952 """
4047 if search:
3953 if search:
4048 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3954 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4049 if name == search]
3955 if name == search]
4050 else:
3956 else:
4051 pathitems = sorted(ui.paths.iteritems())
3957 pathitems = sorted(ui.paths.iteritems())
4052
3958
4053 fm = ui.formatter('paths', opts)
3959 fm = ui.formatter('paths', opts)
4054 if fm.isplain():
3960 if fm.isplain():
4055 hidepassword = util.hidepassword
3961 hidepassword = util.hidepassword
4056 else:
3962 else:
4057 hidepassword = str
3963 hidepassword = str
4058 if ui.quiet:
3964 if ui.quiet:
4059 namefmt = '%s\n'
3965 namefmt = '%s\n'
4060 else:
3966 else:
4061 namefmt = '%s = '
3967 namefmt = '%s = '
4062 showsubopts = not search and not ui.quiet
3968 showsubopts = not search and not ui.quiet
4063
3969
4064 for name, path in pathitems:
3970 for name, path in pathitems:
4065 fm.startitem()
3971 fm.startitem()
4066 fm.condwrite(not search, 'name', namefmt, name)
3972 fm.condwrite(not search, 'name', namefmt, name)
4067 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3973 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4068 for subopt, value in sorted(path.suboptions.items()):
3974 for subopt, value in sorted(path.suboptions.items()):
4069 assert subopt not in ('name', 'url')
3975 assert subopt not in ('name', 'url')
4070 if showsubopts:
3976 if showsubopts:
4071 fm.plain('%s:%s = ' % (name, subopt))
3977 fm.plain('%s:%s = ' % (name, subopt))
4072 fm.condwrite(showsubopts, subopt, '%s\n', value)
3978 fm.condwrite(showsubopts, subopt, '%s\n', value)
4073
3979
4074 fm.end()
3980 fm.end()
4075
3981
4076 if search and not pathitems:
3982 if search and not pathitems:
4077 if not ui.quiet:
3983 if not ui.quiet:
4078 ui.warn(_("not found!\n"))
3984 ui.warn(_("not found!\n"))
4079 return 1
3985 return 1
4080 else:
3986 else:
4081 return 0
3987 return 0
4082
3988
4083 @command('phase',
3989 @command('phase',
4084 [('p', 'public', False, _('set changeset phase to public')),
3990 [('p', 'public', False, _('set changeset phase to public')),
4085 ('d', 'draft', False, _('set changeset phase to draft')),
3991 ('d', 'draft', False, _('set changeset phase to draft')),
4086 ('s', 'secret', False, _('set changeset phase to secret')),
3992 ('s', 'secret', False, _('set changeset phase to secret')),
4087 ('f', 'force', False, _('allow to move boundary backward')),
3993 ('f', 'force', False, _('allow to move boundary backward')),
4088 ('r', 'rev', [], _('target revision'), _('REV')),
3994 ('r', 'rev', [], _('target revision'), _('REV')),
4089 ],
3995 ],
4090 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3996 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4091 def phase(ui, repo, *revs, **opts):
3997 def phase(ui, repo, *revs, **opts):
4092 """set or show the current phase name
3998 """set or show the current phase name
4093
3999
4094 With no argument, show the phase name of the current revision(s).
4000 With no argument, show the phase name of the current revision(s).
4095
4001
4096 With one of -p/--public, -d/--draft or -s/--secret, change the
4002 With one of -p/--public, -d/--draft or -s/--secret, change the
4097 phase value of the specified revisions.
4003 phase value of the specified revisions.
4098
4004
4099 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4005 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4100 lower phase to an higher phase. Phases are ordered as follows::
4006 lower phase to an higher phase. Phases are ordered as follows::
4101
4007
4102 public < draft < secret
4008 public < draft < secret
4103
4009
4104 Returns 0 on success, 1 if some phases could not be changed.
4010 Returns 0 on success, 1 if some phases could not be changed.
4105
4011
4106 (For more information about the phases concept, see :hg:`help phases`.)
4012 (For more information about the phases concept, see :hg:`help phases`.)
4107 """
4013 """
4108 # search for a unique phase argument
4014 # search for a unique phase argument
4109 targetphase = None
4015 targetphase = None
4110 for idx, name in enumerate(phases.phasenames):
4016 for idx, name in enumerate(phases.phasenames):
4111 if opts[name]:
4017 if opts[name]:
4112 if targetphase is not None:
4018 if targetphase is not None:
4113 raise error.Abort(_('only one phase can be specified'))
4019 raise error.Abort(_('only one phase can be specified'))
4114 targetphase = idx
4020 targetphase = idx
4115
4021
4116 # look for specified revision
4022 # look for specified revision
4117 revs = list(revs)
4023 revs = list(revs)
4118 revs.extend(opts['rev'])
4024 revs.extend(opts['rev'])
4119 if not revs:
4025 if not revs:
4120 # display both parents as the second parent phase can influence
4026 # display both parents as the second parent phase can influence
4121 # the phase of a merge commit
4027 # the phase of a merge commit
4122 revs = [c.rev() for c in repo[None].parents()]
4028 revs = [c.rev() for c in repo[None].parents()]
4123
4029
4124 revs = scmutil.revrange(repo, revs)
4030 revs = scmutil.revrange(repo, revs)
4125
4031
4126 lock = None
4032 lock = None
4127 ret = 0
4033 ret = 0
4128 if targetphase is None:
4034 if targetphase is None:
4129 # display
4035 # display
4130 for r in revs:
4036 for r in revs:
4131 ctx = repo[r]
4037 ctx = repo[r]
4132 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4038 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4133 else:
4039 else:
4134 tr = None
4040 tr = None
4135 lock = repo.lock()
4041 lock = repo.lock()
4136 try:
4042 try:
4137 tr = repo.transaction("phase")
4043 tr = repo.transaction("phase")
4138 # set phase
4044 # set phase
4139 if not revs:
4045 if not revs:
4140 raise error.Abort(_('empty revision set'))
4046 raise error.Abort(_('empty revision set'))
4141 nodes = [repo[r].node() for r in revs]
4047 nodes = [repo[r].node() for r in revs]
4142 # moving revision from public to draft may hide them
4048 # moving revision from public to draft may hide them
4143 # We have to check result on an unfiltered repository
4049 # We have to check result on an unfiltered repository
4144 unfi = repo.unfiltered()
4050 unfi = repo.unfiltered()
4145 getphase = unfi._phasecache.phase
4051 getphase = unfi._phasecache.phase
4146 olddata = [getphase(unfi, r) for r in unfi]
4052 olddata = [getphase(unfi, r) for r in unfi]
4147 phases.advanceboundary(repo, tr, targetphase, nodes)
4053 phases.advanceboundary(repo, tr, targetphase, nodes)
4148 if opts['force']:
4054 if opts['force']:
4149 phases.retractboundary(repo, tr, targetphase, nodes)
4055 phases.retractboundary(repo, tr, targetphase, nodes)
4150 tr.close()
4056 tr.close()
4151 finally:
4057 finally:
4152 if tr is not None:
4058 if tr is not None:
4153 tr.release()
4059 tr.release()
4154 lock.release()
4060 lock.release()
4155 getphase = unfi._phasecache.phase
4061 getphase = unfi._phasecache.phase
4156 newdata = [getphase(unfi, r) for r in unfi]
4062 newdata = [getphase(unfi, r) for r in unfi]
4157 changes = sum(newdata[r] != olddata[r] for r in unfi)
4063 changes = sum(newdata[r] != olddata[r] for r in unfi)
4158 cl = unfi.changelog
4064 cl = unfi.changelog
4159 rejected = [n for n in nodes
4065 rejected = [n for n in nodes
4160 if newdata[cl.rev(n)] < targetphase]
4066 if newdata[cl.rev(n)] < targetphase]
4161 if rejected:
4067 if rejected:
4162 ui.warn(_('cannot move %i changesets to a higher '
4068 ui.warn(_('cannot move %i changesets to a higher '
4163 'phase, use --force\n') % len(rejected))
4069 'phase, use --force\n') % len(rejected))
4164 ret = 1
4070 ret = 1
4165 if changes:
4071 if changes:
4166 msg = _('phase changed for %i changesets\n') % changes
4072 msg = _('phase changed for %i changesets\n') % changes
4167 if ret:
4073 if ret:
4168 ui.status(msg)
4074 ui.status(msg)
4169 else:
4075 else:
4170 ui.note(msg)
4076 ui.note(msg)
4171 else:
4077 else:
4172 ui.warn(_('no phases changed\n'))
4078 ui.warn(_('no phases changed\n'))
4173 return ret
4079 return ret
4174
4080
4175 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4081 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4176 """Run after a changegroup has been added via pull/unbundle
4082 """Run after a changegroup has been added via pull/unbundle
4177
4083
4178 This takes arguments below:
4084 This takes arguments below:
4179
4085
4180 :modheads: change of heads by pull/unbundle
4086 :modheads: change of heads by pull/unbundle
4181 :optupdate: updating working directory is needed or not
4087 :optupdate: updating working directory is needed or not
4182 :checkout: update destination revision (or None to default destination)
4088 :checkout: update destination revision (or None to default destination)
4183 :brev: a name, which might be a bookmark to be activated after updating
4089 :brev: a name, which might be a bookmark to be activated after updating
4184 """
4090 """
4185 if modheads == 0:
4091 if modheads == 0:
4186 return
4092 return
4187 if optupdate:
4093 if optupdate:
4188 try:
4094 try:
4189 return hg.updatetotally(ui, repo, checkout, brev)
4095 return hg.updatetotally(ui, repo, checkout, brev)
4190 except error.UpdateAbort as inst:
4096 except error.UpdateAbort as inst:
4191 msg = _("not updating: %s") % str(inst)
4097 msg = _("not updating: %s") % str(inst)
4192 hint = inst.hint
4098 hint = inst.hint
4193 raise error.UpdateAbort(msg, hint=hint)
4099 raise error.UpdateAbort(msg, hint=hint)
4194 if modheads > 1:
4100 if modheads > 1:
4195 currentbranchheads = len(repo.branchheads())
4101 currentbranchheads = len(repo.branchheads())
4196 if currentbranchheads == modheads:
4102 if currentbranchheads == modheads:
4197 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4103 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4198 elif currentbranchheads > 1:
4104 elif currentbranchheads > 1:
4199 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4105 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4200 "merge)\n"))
4106 "merge)\n"))
4201 else:
4107 else:
4202 ui.status(_("(run 'hg heads' to see heads)\n"))
4108 ui.status(_("(run 'hg heads' to see heads)\n"))
4203 else:
4109 else:
4204 ui.status(_("(run 'hg update' to get a working copy)\n"))
4110 ui.status(_("(run 'hg update' to get a working copy)\n"))
4205
4111
4206 @command('^pull',
4112 @command('^pull',
4207 [('u', 'update', None,
4113 [('u', 'update', None,
4208 _('update to new branch head if changesets were pulled')),
4114 _('update to new branch head if changesets were pulled')),
4209 ('f', 'force', None, _('run even when remote repository is unrelated')),
4115 ('f', 'force', None, _('run even when remote repository is unrelated')),
4210 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4116 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4211 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4117 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4212 ('b', 'branch', [], _('a specific branch you would like to pull'),
4118 ('b', 'branch', [], _('a specific branch you would like to pull'),
4213 _('BRANCH')),
4119 _('BRANCH')),
4214 ] + remoteopts,
4120 ] + remoteopts,
4215 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4121 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4216 def pull(ui, repo, source="default", **opts):
4122 def pull(ui, repo, source="default", **opts):
4217 """pull changes from the specified source
4123 """pull changes from the specified source
4218
4124
4219 Pull changes from a remote repository to a local one.
4125 Pull changes from a remote repository to a local one.
4220
4126
4221 This finds all changes from the repository at the specified path
4127 This finds all changes from the repository at the specified path
4222 or URL and adds them to a local repository (the current one unless
4128 or URL and adds them to a local repository (the current one unless
4223 -R is specified). By default, this does not update the copy of the
4129 -R is specified). By default, this does not update the copy of the
4224 project in the working directory.
4130 project in the working directory.
4225
4131
4226 Use :hg:`incoming` if you want to see what would have been added
4132 Use :hg:`incoming` if you want to see what would have been added
4227 by a pull at the time you issued this command. If you then decide
4133 by a pull at the time you issued this command. If you then decide
4228 to add those changes to the repository, you should use :hg:`pull
4134 to add those changes to the repository, you should use :hg:`pull
4229 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4135 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4230
4136
4231 If SOURCE is omitted, the 'default' path will be used.
4137 If SOURCE is omitted, the 'default' path will be used.
4232 See :hg:`help urls` for more information.
4138 See :hg:`help urls` for more information.
4233
4139
4234 Specifying bookmark as ``.`` is equivalent to specifying the active
4140 Specifying bookmark as ``.`` is equivalent to specifying the active
4235 bookmark's name.
4141 bookmark's name.
4236
4142
4237 Returns 0 on success, 1 if an update had unresolved files.
4143 Returns 0 on success, 1 if an update had unresolved files.
4238 """
4144 """
4239 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4145 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4240 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4146 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4241 other = hg.peer(repo, opts, source)
4147 other = hg.peer(repo, opts, source)
4242 try:
4148 try:
4243 revs, checkout = hg.addbranchrevs(repo, other, branches,
4149 revs, checkout = hg.addbranchrevs(repo, other, branches,
4244 opts.get('rev'))
4150 opts.get('rev'))
4245
4151
4246
4152
4247 pullopargs = {}
4153 pullopargs = {}
4248 if opts.get('bookmark'):
4154 if opts.get('bookmark'):
4249 if not revs:
4155 if not revs:
4250 revs = []
4156 revs = []
4251 # The list of bookmark used here is not the one used to actually
4157 # The list of bookmark used here is not the one used to actually
4252 # update the bookmark name. This can result in the revision pulled
4158 # update the bookmark name. This can result in the revision pulled
4253 # not ending up with the name of the bookmark because of a race
4159 # not ending up with the name of the bookmark because of a race
4254 # condition on the server. (See issue 4689 for details)
4160 # condition on the server. (See issue 4689 for details)
4255 remotebookmarks = other.listkeys('bookmarks')
4161 remotebookmarks = other.listkeys('bookmarks')
4256 pullopargs['remotebookmarks'] = remotebookmarks
4162 pullopargs['remotebookmarks'] = remotebookmarks
4257 for b in opts['bookmark']:
4163 for b in opts['bookmark']:
4258 b = repo._bookmarks.expandname(b)
4164 b = repo._bookmarks.expandname(b)
4259 if b not in remotebookmarks:
4165 if b not in remotebookmarks:
4260 raise error.Abort(_('remote bookmark %s not found!') % b)
4166 raise error.Abort(_('remote bookmark %s not found!') % b)
4261 revs.append(remotebookmarks[b])
4167 revs.append(remotebookmarks[b])
4262
4168
4263 if revs:
4169 if revs:
4264 try:
4170 try:
4265 # When 'rev' is a bookmark name, we cannot guarantee that it
4171 # When 'rev' is a bookmark name, we cannot guarantee that it
4266 # will be updated with that name because of a race condition
4172 # will be updated with that name because of a race condition
4267 # server side. (See issue 4689 for details)
4173 # server side. (See issue 4689 for details)
4268 oldrevs = revs
4174 oldrevs = revs
4269 revs = [] # actually, nodes
4175 revs = [] # actually, nodes
4270 for r in oldrevs:
4176 for r in oldrevs:
4271 node = other.lookup(r)
4177 node = other.lookup(r)
4272 revs.append(node)
4178 revs.append(node)
4273 if r == checkout:
4179 if r == checkout:
4274 checkout = node
4180 checkout = node
4275 except error.CapabilityError:
4181 except error.CapabilityError:
4276 err = _("other repository doesn't support revision lookup, "
4182 err = _("other repository doesn't support revision lookup, "
4277 "so a rev cannot be specified.")
4183 "so a rev cannot be specified.")
4278 raise error.Abort(err)
4184 raise error.Abort(err)
4279
4185
4280 pullopargs.update(opts.get('opargs', {}))
4186 pullopargs.update(opts.get('opargs', {}))
4281 modheads = exchange.pull(repo, other, heads=revs,
4187 modheads = exchange.pull(repo, other, heads=revs,
4282 force=opts.get('force'),
4188 force=opts.get('force'),
4283 bookmarks=opts.get('bookmark', ()),
4189 bookmarks=opts.get('bookmark', ()),
4284 opargs=pullopargs).cgresult
4190 opargs=pullopargs).cgresult
4285
4191
4286 # brev is a name, which might be a bookmark to be activated at
4192 # brev is a name, which might be a bookmark to be activated at
4287 # the end of the update. In other words, it is an explicit
4193 # the end of the update. In other words, it is an explicit
4288 # destination of the update
4194 # destination of the update
4289 brev = None
4195 brev = None
4290
4196
4291 if checkout:
4197 if checkout:
4292 checkout = str(repo.changelog.rev(checkout))
4198 checkout = str(repo.changelog.rev(checkout))
4293
4199
4294 # order below depends on implementation of
4200 # order below depends on implementation of
4295 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4201 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4296 # because 'checkout' is determined without it.
4202 # because 'checkout' is determined without it.
4297 if opts.get('rev'):
4203 if opts.get('rev'):
4298 brev = opts['rev'][0]
4204 brev = opts['rev'][0]
4299 elif opts.get('branch'):
4205 elif opts.get('branch'):
4300 brev = opts['branch'][0]
4206 brev = opts['branch'][0]
4301 else:
4207 else:
4302 brev = branches[0]
4208 brev = branches[0]
4303 repo._subtoppath = source
4209 repo._subtoppath = source
4304 try:
4210 try:
4305 ret = postincoming(ui, repo, modheads, opts.get('update'),
4211 ret = postincoming(ui, repo, modheads, opts.get('update'),
4306 checkout, brev)
4212 checkout, brev)
4307
4213
4308 finally:
4214 finally:
4309 del repo._subtoppath
4215 del repo._subtoppath
4310
4216
4311 finally:
4217 finally:
4312 other.close()
4218 other.close()
4313 return ret
4219 return ret
4314
4220
4315 @command('^push',
4221 @command('^push',
4316 [('f', 'force', None, _('force push')),
4222 [('f', 'force', None, _('force push')),
4317 ('r', 'rev', [],
4223 ('r', 'rev', [],
4318 _('a changeset intended to be included in the destination'),
4224 _('a changeset intended to be included in the destination'),
4319 _('REV')),
4225 _('REV')),
4320 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4226 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4321 ('b', 'branch', [],
4227 ('b', 'branch', [],
4322 _('a specific branch you would like to push'), _('BRANCH')),
4228 _('a specific branch you would like to push'), _('BRANCH')),
4323 ('', 'new-branch', False, _('allow pushing a new branch')),
4229 ('', 'new-branch', False, _('allow pushing a new branch')),
4324 ] + remoteopts,
4230 ] + remoteopts,
4325 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4231 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4326 def push(ui, repo, dest=None, **opts):
4232 def push(ui, repo, dest=None, **opts):
4327 """push changes to the specified destination
4233 """push changes to the specified destination
4328
4234
4329 Push changesets from the local repository to the specified
4235 Push changesets from the local repository to the specified
4330 destination.
4236 destination.
4331
4237
4332 This operation is symmetrical to pull: it is identical to a pull
4238 This operation is symmetrical to pull: it is identical to a pull
4333 in the destination repository from the current one.
4239 in the destination repository from the current one.
4334
4240
4335 By default, push will not allow creation of new heads at the
4241 By default, push will not allow creation of new heads at the
4336 destination, since multiple heads would make it unclear which head
4242 destination, since multiple heads would make it unclear which head
4337 to use. In this situation, it is recommended to pull and merge
4243 to use. In this situation, it is recommended to pull and merge
4338 before pushing.
4244 before pushing.
4339
4245
4340 Use --new-branch if you want to allow push to create a new named
4246 Use --new-branch if you want to allow push to create a new named
4341 branch that is not present at the destination. This allows you to
4247 branch that is not present at the destination. This allows you to
4342 only create a new branch without forcing other changes.
4248 only create a new branch without forcing other changes.
4343
4249
4344 .. note::
4250 .. note::
4345
4251
4346 Extra care should be taken with the -f/--force option,
4252 Extra care should be taken with the -f/--force option,
4347 which will push all new heads on all branches, an action which will
4253 which will push all new heads on all branches, an action which will
4348 almost always cause confusion for collaborators.
4254 almost always cause confusion for collaborators.
4349
4255
4350 If -r/--rev is used, the specified revision and all its ancestors
4256 If -r/--rev is used, the specified revision and all its ancestors
4351 will be pushed to the remote repository.
4257 will be pushed to the remote repository.
4352
4258
4353 If -B/--bookmark is used, the specified bookmarked revision, its
4259 If -B/--bookmark is used, the specified bookmarked revision, its
4354 ancestors, and the bookmark will be pushed to the remote
4260 ancestors, and the bookmark will be pushed to the remote
4355 repository. Specifying ``.`` is equivalent to specifying the active
4261 repository. Specifying ``.`` is equivalent to specifying the active
4356 bookmark's name.
4262 bookmark's name.
4357
4263
4358 Please see :hg:`help urls` for important details about ``ssh://``
4264 Please see :hg:`help urls` for important details about ``ssh://``
4359 URLs. If DESTINATION is omitted, a default path will be used.
4265 URLs. If DESTINATION is omitted, a default path will be used.
4360
4266
4361 Returns 0 if push was successful, 1 if nothing to push.
4267 Returns 0 if push was successful, 1 if nothing to push.
4362 """
4268 """
4363
4269
4364 if opts.get('bookmark'):
4270 if opts.get('bookmark'):
4365 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4271 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4366 for b in opts['bookmark']:
4272 for b in opts['bookmark']:
4367 # translate -B options to -r so changesets get pushed
4273 # translate -B options to -r so changesets get pushed
4368 b = repo._bookmarks.expandname(b)
4274 b = repo._bookmarks.expandname(b)
4369 if b in repo._bookmarks:
4275 if b in repo._bookmarks:
4370 opts.setdefault('rev', []).append(b)
4276 opts.setdefault('rev', []).append(b)
4371 else:
4277 else:
4372 # if we try to push a deleted bookmark, translate it to null
4278 # if we try to push a deleted bookmark, translate it to null
4373 # this lets simultaneous -r, -b options continue working
4279 # this lets simultaneous -r, -b options continue working
4374 opts.setdefault('rev', []).append("null")
4280 opts.setdefault('rev', []).append("null")
4375
4281
4376 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4282 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4377 if not path:
4283 if not path:
4378 raise error.Abort(_('default repository not configured!'),
4284 raise error.Abort(_('default repository not configured!'),
4379 hint=_("see 'hg help config.paths'"))
4285 hint=_("see 'hg help config.paths'"))
4380 dest = path.pushloc or path.loc
4286 dest = path.pushloc or path.loc
4381 branches = (path.branch, opts.get('branch') or [])
4287 branches = (path.branch, opts.get('branch') or [])
4382 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4288 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4383 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4289 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4384 other = hg.peer(repo, opts, dest)
4290 other = hg.peer(repo, opts, dest)
4385
4291
4386 if revs:
4292 if revs:
4387 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4293 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4388 if not revs:
4294 if not revs:
4389 raise error.Abort(_("specified revisions evaluate to an empty set"),
4295 raise error.Abort(_("specified revisions evaluate to an empty set"),
4390 hint=_("use different revision arguments"))
4296 hint=_("use different revision arguments"))
4391 elif path.pushrev:
4297 elif path.pushrev:
4392 # It doesn't make any sense to specify ancestor revisions. So limit
4298 # It doesn't make any sense to specify ancestor revisions. So limit
4393 # to DAG heads to make discovery simpler.
4299 # to DAG heads to make discovery simpler.
4394 expr = revset.formatspec('heads(%r)', path.pushrev)
4300 expr = revset.formatspec('heads(%r)', path.pushrev)
4395 revs = scmutil.revrange(repo, [expr])
4301 revs = scmutil.revrange(repo, [expr])
4396 revs = [repo[rev].node() for rev in revs]
4302 revs = [repo[rev].node() for rev in revs]
4397 if not revs:
4303 if not revs:
4398 raise error.Abort(_('default push revset for path evaluates to an '
4304 raise error.Abort(_('default push revset for path evaluates to an '
4399 'empty set'))
4305 'empty set'))
4400
4306
4401 repo._subtoppath = dest
4307 repo._subtoppath = dest
4402 try:
4308 try:
4403 # push subrepos depth-first for coherent ordering
4309 # push subrepos depth-first for coherent ordering
4404 c = repo['']
4310 c = repo['']
4405 subs = c.substate # only repos that are committed
4311 subs = c.substate # only repos that are committed
4406 for s in sorted(subs):
4312 for s in sorted(subs):
4407 result = c.sub(s).push(opts)
4313 result = c.sub(s).push(opts)
4408 if result == 0:
4314 if result == 0:
4409 return not result
4315 return not result
4410 finally:
4316 finally:
4411 del repo._subtoppath
4317 del repo._subtoppath
4412 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4318 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4413 newbranch=opts.get('new_branch'),
4319 newbranch=opts.get('new_branch'),
4414 bookmarks=opts.get('bookmark', ()),
4320 bookmarks=opts.get('bookmark', ()),
4415 opargs=opts.get('opargs'))
4321 opargs=opts.get('opargs'))
4416
4322
4417 result = not pushop.cgresult
4323 result = not pushop.cgresult
4418
4324
4419 if pushop.bkresult is not None:
4325 if pushop.bkresult is not None:
4420 if pushop.bkresult == 2:
4326 if pushop.bkresult == 2:
4421 result = 2
4327 result = 2
4422 elif not result and pushop.bkresult:
4328 elif not result and pushop.bkresult:
4423 result = 2
4329 result = 2
4424
4330
4425 return result
4331 return result
4426
4332
4427 @command('recover', [])
4333 @command('recover', [])
4428 def recover(ui, repo):
4334 def recover(ui, repo):
4429 """roll back an interrupted transaction
4335 """roll back an interrupted transaction
4430
4336
4431 Recover from an interrupted commit or pull.
4337 Recover from an interrupted commit or pull.
4432
4338
4433 This command tries to fix the repository status after an
4339 This command tries to fix the repository status after an
4434 interrupted operation. It should only be necessary when Mercurial
4340 interrupted operation. It should only be necessary when Mercurial
4435 suggests it.
4341 suggests it.
4436
4342
4437 Returns 0 if successful, 1 if nothing to recover or verify fails.
4343 Returns 0 if successful, 1 if nothing to recover or verify fails.
4438 """
4344 """
4439 if repo.recover():
4345 if repo.recover():
4440 return hg.verify(repo)
4346 return hg.verify(repo)
4441 return 1
4347 return 1
4442
4348
4443 @command('^remove|rm',
4349 @command('^remove|rm',
4444 [('A', 'after', None, _('record delete for missing files')),
4350 [('A', 'after', None, _('record delete for missing files')),
4445 ('f', 'force', None,
4351 ('f', 'force', None,
4446 _('forget added files, delete modified files')),
4352 _('forget added files, delete modified files')),
4447 ] + subrepoopts + walkopts,
4353 ] + subrepoopts + walkopts,
4448 _('[OPTION]... FILE...'),
4354 _('[OPTION]... FILE...'),
4449 inferrepo=True)
4355 inferrepo=True)
4450 def remove(ui, repo, *pats, **opts):
4356 def remove(ui, repo, *pats, **opts):
4451 """remove the specified files on the next commit
4357 """remove the specified files on the next commit
4452
4358
4453 Schedule the indicated files for removal from the current branch.
4359 Schedule the indicated files for removal from the current branch.
4454
4360
4455 This command schedules the files to be removed at the next commit.
4361 This command schedules the files to be removed at the next commit.
4456 To undo a remove before that, see :hg:`revert`. To undo added
4362 To undo a remove before that, see :hg:`revert`. To undo added
4457 files, see :hg:`forget`.
4363 files, see :hg:`forget`.
4458
4364
4459 .. container:: verbose
4365 .. container:: verbose
4460
4366
4461 -A/--after can be used to remove only files that have already
4367 -A/--after can be used to remove only files that have already
4462 been deleted, -f/--force can be used to force deletion, and -Af
4368 been deleted, -f/--force can be used to force deletion, and -Af
4463 can be used to remove files from the next revision without
4369 can be used to remove files from the next revision without
4464 deleting them from the working directory.
4370 deleting them from the working directory.
4465
4371
4466 The following table details the behavior of remove for different
4372 The following table details the behavior of remove for different
4467 file states (columns) and option combinations (rows). The file
4373 file states (columns) and option combinations (rows). The file
4468 states are Added [A], Clean [C], Modified [M] and Missing [!]
4374 states are Added [A], Clean [C], Modified [M] and Missing [!]
4469 (as reported by :hg:`status`). The actions are Warn, Remove
4375 (as reported by :hg:`status`). The actions are Warn, Remove
4470 (from branch) and Delete (from disk):
4376 (from branch) and Delete (from disk):
4471
4377
4472 ========= == == == ==
4378 ========= == == == ==
4473 opt/state A C M !
4379 opt/state A C M !
4474 ========= == == == ==
4380 ========= == == == ==
4475 none W RD W R
4381 none W RD W R
4476 -f R RD RD R
4382 -f R RD RD R
4477 -A W W W R
4383 -A W W W R
4478 -Af R R R R
4384 -Af R R R R
4479 ========= == == == ==
4385 ========= == == == ==
4480
4386
4481 .. note::
4387 .. note::
4482
4388
4483 :hg:`remove` never deletes files in Added [A] state from the
4389 :hg:`remove` never deletes files in Added [A] state from the
4484 working directory, not even if ``--force`` is specified.
4390 working directory, not even if ``--force`` is specified.
4485
4391
4486 Returns 0 on success, 1 if any warnings encountered.
4392 Returns 0 on success, 1 if any warnings encountered.
4487 """
4393 """
4488
4394
4489 after, force = opts.get('after'), opts.get('force')
4395 after, force = opts.get('after'), opts.get('force')
4490 if not pats and not after:
4396 if not pats and not after:
4491 raise error.Abort(_('no files specified'))
4397 raise error.Abort(_('no files specified'))
4492
4398
4493 m = scmutil.match(repo[None], pats, opts)
4399 m = scmutil.match(repo[None], pats, opts)
4494 subrepos = opts.get('subrepos')
4400 subrepos = opts.get('subrepos')
4495 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4401 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4496
4402
4497 @command('rename|move|mv',
4403 @command('rename|move|mv',
4498 [('A', 'after', None, _('record a rename that has already occurred')),
4404 [('A', 'after', None, _('record a rename that has already occurred')),
4499 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4405 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4500 ] + walkopts + dryrunopts,
4406 ] + walkopts + dryrunopts,
4501 _('[OPTION]... SOURCE... DEST'))
4407 _('[OPTION]... SOURCE... DEST'))
4502 def rename(ui, repo, *pats, **opts):
4408 def rename(ui, repo, *pats, **opts):
4503 """rename files; equivalent of copy + remove
4409 """rename files; equivalent of copy + remove
4504
4410
4505 Mark dest as copies of sources; mark sources for deletion. If dest
4411 Mark dest as copies of sources; mark sources for deletion. If dest
4506 is a directory, copies are put in that directory. If dest is a
4412 is a directory, copies are put in that directory. If dest is a
4507 file, there can only be one source.
4413 file, there can only be one source.
4508
4414
4509 By default, this command copies the contents of files as they
4415 By default, this command copies the contents of files as they
4510 exist in the working directory. If invoked with -A/--after, the
4416 exist in the working directory. If invoked with -A/--after, the
4511 operation is recorded, but no copying is performed.
4417 operation is recorded, but no copying is performed.
4512
4418
4513 This command takes effect at the next commit. To undo a rename
4419 This command takes effect at the next commit. To undo a rename
4514 before that, see :hg:`revert`.
4420 before that, see :hg:`revert`.
4515
4421
4516 Returns 0 on success, 1 if errors are encountered.
4422 Returns 0 on success, 1 if errors are encountered.
4517 """
4423 """
4518 with repo.wlock(False):
4424 with repo.wlock(False):
4519 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4425 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4520
4426
4521 @command('resolve',
4427 @command('resolve',
4522 [('a', 'all', None, _('select all unresolved files')),
4428 [('a', 'all', None, _('select all unresolved files')),
4523 ('l', 'list', None, _('list state of files needing merge')),
4429 ('l', 'list', None, _('list state of files needing merge')),
4524 ('m', 'mark', None, _('mark files as resolved')),
4430 ('m', 'mark', None, _('mark files as resolved')),
4525 ('u', 'unmark', None, _('mark files as unresolved')),
4431 ('u', 'unmark', None, _('mark files as unresolved')),
4526 ('n', 'no-status', None, _('hide status prefix'))]
4432 ('n', 'no-status', None, _('hide status prefix'))]
4527 + mergetoolopts + walkopts + formatteropts,
4433 + mergetoolopts + walkopts + formatteropts,
4528 _('[OPTION]... [FILE]...'),
4434 _('[OPTION]... [FILE]...'),
4529 inferrepo=True)
4435 inferrepo=True)
4530 def resolve(ui, repo, *pats, **opts):
4436 def resolve(ui, repo, *pats, **opts):
4531 """redo merges or set/view the merge status of files
4437 """redo merges or set/view the merge status of files
4532
4438
4533 Merges with unresolved conflicts are often the result of
4439 Merges with unresolved conflicts are often the result of
4534 non-interactive merging using the ``internal:merge`` configuration
4440 non-interactive merging using the ``internal:merge`` configuration
4535 setting, or a command-line merge tool like ``diff3``. The resolve
4441 setting, or a command-line merge tool like ``diff3``. The resolve
4536 command is used to manage the files involved in a merge, after
4442 command is used to manage the files involved in a merge, after
4537 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4443 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4538 working directory must have two parents). See :hg:`help
4444 working directory must have two parents). See :hg:`help
4539 merge-tools` for information on configuring merge tools.
4445 merge-tools` for information on configuring merge tools.
4540
4446
4541 The resolve command can be used in the following ways:
4447 The resolve command can be used in the following ways:
4542
4448
4543 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4449 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4544 files, discarding any previous merge attempts. Re-merging is not
4450 files, discarding any previous merge attempts. Re-merging is not
4545 performed for files already marked as resolved. Use ``--all/-a``
4451 performed for files already marked as resolved. Use ``--all/-a``
4546 to select all unresolved files. ``--tool`` can be used to specify
4452 to select all unresolved files. ``--tool`` can be used to specify
4547 the merge tool used for the given files. It overrides the HGMERGE
4453 the merge tool used for the given files. It overrides the HGMERGE
4548 environment variable and your configuration files. Previous file
4454 environment variable and your configuration files. Previous file
4549 contents are saved with a ``.orig`` suffix.
4455 contents are saved with a ``.orig`` suffix.
4550
4456
4551 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4457 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4552 (e.g. after having manually fixed-up the files). The default is
4458 (e.g. after having manually fixed-up the files). The default is
4553 to mark all unresolved files.
4459 to mark all unresolved files.
4554
4460
4555 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4461 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4556 default is to mark all resolved files.
4462 default is to mark all resolved files.
4557
4463
4558 - :hg:`resolve -l`: list files which had or still have conflicts.
4464 - :hg:`resolve -l`: list files which had or still have conflicts.
4559 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4465 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4560
4466
4561 .. note::
4467 .. note::
4562
4468
4563 Mercurial will not let you commit files with unresolved merge
4469 Mercurial will not let you commit files with unresolved merge
4564 conflicts. You must use :hg:`resolve -m ...` before you can
4470 conflicts. You must use :hg:`resolve -m ...` before you can
4565 commit after a conflicting merge.
4471 commit after a conflicting merge.
4566
4472
4567 Returns 0 on success, 1 if any files fail a resolve attempt.
4473 Returns 0 on success, 1 if any files fail a resolve attempt.
4568 """
4474 """
4569
4475
4570 flaglist = 'all mark unmark list no_status'.split()
4476 flaglist = 'all mark unmark list no_status'.split()
4571 all, mark, unmark, show, nostatus = \
4477 all, mark, unmark, show, nostatus = \
4572 [opts.get(o) for o in flaglist]
4478 [opts.get(o) for o in flaglist]
4573
4479
4574 if (show and (mark or unmark)) or (mark and unmark):
4480 if (show and (mark or unmark)) or (mark and unmark):
4575 raise error.Abort(_("too many options specified"))
4481 raise error.Abort(_("too many options specified"))
4576 if pats and all:
4482 if pats and all:
4577 raise error.Abort(_("can't specify --all and patterns"))
4483 raise error.Abort(_("can't specify --all and patterns"))
4578 if not (all or pats or show or mark or unmark):
4484 if not (all or pats or show or mark or unmark):
4579 raise error.Abort(_('no files or directories specified'),
4485 raise error.Abort(_('no files or directories specified'),
4580 hint=('use --all to re-merge all unresolved files'))
4486 hint=('use --all to re-merge all unresolved files'))
4581
4487
4582 if show:
4488 if show:
4583 fm = ui.formatter('resolve', opts)
4489 fm = ui.formatter('resolve', opts)
4584 ms = mergemod.mergestate.read(repo)
4490 ms = mergemod.mergestate.read(repo)
4585 m = scmutil.match(repo[None], pats, opts)
4491 m = scmutil.match(repo[None], pats, opts)
4586 for f in ms:
4492 for f in ms:
4587 if not m(f):
4493 if not m(f):
4588 continue
4494 continue
4589 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4495 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4590 'd': 'driverresolved'}[ms[f]]
4496 'd': 'driverresolved'}[ms[f]]
4591 fm.startitem()
4497 fm.startitem()
4592 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4498 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4593 fm.write('path', '%s\n', f, label=l)
4499 fm.write('path', '%s\n', f, label=l)
4594 fm.end()
4500 fm.end()
4595 return 0
4501 return 0
4596
4502
4597 with repo.wlock():
4503 with repo.wlock():
4598 ms = mergemod.mergestate.read(repo)
4504 ms = mergemod.mergestate.read(repo)
4599
4505
4600 if not (ms.active() or repo.dirstate.p2() != nullid):
4506 if not (ms.active() or repo.dirstate.p2() != nullid):
4601 raise error.Abort(
4507 raise error.Abort(
4602 _('resolve command not applicable when not merging'))
4508 _('resolve command not applicable when not merging'))
4603
4509
4604 wctx = repo[None]
4510 wctx = repo[None]
4605
4511
4606 if ms.mergedriver and ms.mdstate() == 'u':
4512 if ms.mergedriver and ms.mdstate() == 'u':
4607 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4513 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4608 ms.commit()
4514 ms.commit()
4609 # allow mark and unmark to go through
4515 # allow mark and unmark to go through
4610 if not mark and not unmark and not proceed:
4516 if not mark and not unmark and not proceed:
4611 return 1
4517 return 1
4612
4518
4613 m = scmutil.match(wctx, pats, opts)
4519 m = scmutil.match(wctx, pats, opts)
4614 ret = 0
4520 ret = 0
4615 didwork = False
4521 didwork = False
4616 runconclude = False
4522 runconclude = False
4617
4523
4618 tocomplete = []
4524 tocomplete = []
4619 for f in ms:
4525 for f in ms:
4620 if not m(f):
4526 if not m(f):
4621 continue
4527 continue
4622
4528
4623 didwork = True
4529 didwork = True
4624
4530
4625 # don't let driver-resolved files be marked, and run the conclude
4531 # don't let driver-resolved files be marked, and run the conclude
4626 # step if asked to resolve
4532 # step if asked to resolve
4627 if ms[f] == "d":
4533 if ms[f] == "d":
4628 exact = m.exact(f)
4534 exact = m.exact(f)
4629 if mark:
4535 if mark:
4630 if exact:
4536 if exact:
4631 ui.warn(_('not marking %s as it is driver-resolved\n')
4537 ui.warn(_('not marking %s as it is driver-resolved\n')
4632 % f)
4538 % f)
4633 elif unmark:
4539 elif unmark:
4634 if exact:
4540 if exact:
4635 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4541 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4636 % f)
4542 % f)
4637 else:
4543 else:
4638 runconclude = True
4544 runconclude = True
4639 continue
4545 continue
4640
4546
4641 if mark:
4547 if mark:
4642 ms.mark(f, "r")
4548 ms.mark(f, "r")
4643 elif unmark:
4549 elif unmark:
4644 ms.mark(f, "u")
4550 ms.mark(f, "u")
4645 else:
4551 else:
4646 # backup pre-resolve (merge uses .orig for its own purposes)
4552 # backup pre-resolve (merge uses .orig for its own purposes)
4647 a = repo.wjoin(f)
4553 a = repo.wjoin(f)
4648 try:
4554 try:
4649 util.copyfile(a, a + ".resolve")
4555 util.copyfile(a, a + ".resolve")
4650 except (IOError, OSError) as inst:
4556 except (IOError, OSError) as inst:
4651 if inst.errno != errno.ENOENT:
4557 if inst.errno != errno.ENOENT:
4652 raise
4558 raise
4653
4559
4654 try:
4560 try:
4655 # preresolve file
4561 # preresolve file
4656 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4562 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4657 'resolve')
4563 'resolve')
4658 complete, r = ms.preresolve(f, wctx)
4564 complete, r = ms.preresolve(f, wctx)
4659 if not complete:
4565 if not complete:
4660 tocomplete.append(f)
4566 tocomplete.append(f)
4661 elif r:
4567 elif r:
4662 ret = 1
4568 ret = 1
4663 finally:
4569 finally:
4664 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4570 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4665 ms.commit()
4571 ms.commit()
4666
4572
4667 # replace filemerge's .orig file with our resolve file, but only
4573 # replace filemerge's .orig file with our resolve file, but only
4668 # for merges that are complete
4574 # for merges that are complete
4669 if complete:
4575 if complete:
4670 try:
4576 try:
4671 util.rename(a + ".resolve",
4577 util.rename(a + ".resolve",
4672 scmutil.origpath(ui, repo, a))
4578 scmutil.origpath(ui, repo, a))
4673 except OSError as inst:
4579 except OSError as inst:
4674 if inst.errno != errno.ENOENT:
4580 if inst.errno != errno.ENOENT:
4675 raise
4581 raise
4676
4582
4677 for f in tocomplete:
4583 for f in tocomplete:
4678 try:
4584 try:
4679 # resolve file
4585 # resolve file
4680 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4586 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4681 'resolve')
4587 'resolve')
4682 r = ms.resolve(f, wctx)
4588 r = ms.resolve(f, wctx)
4683 if r:
4589 if r:
4684 ret = 1
4590 ret = 1
4685 finally:
4591 finally:
4686 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4592 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4687 ms.commit()
4593 ms.commit()
4688
4594
4689 # replace filemerge's .orig file with our resolve file
4595 # replace filemerge's .orig file with our resolve file
4690 a = repo.wjoin(f)
4596 a = repo.wjoin(f)
4691 try:
4597 try:
4692 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4598 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4693 except OSError as inst:
4599 except OSError as inst:
4694 if inst.errno != errno.ENOENT:
4600 if inst.errno != errno.ENOENT:
4695 raise
4601 raise
4696
4602
4697 ms.commit()
4603 ms.commit()
4698 ms.recordactions()
4604 ms.recordactions()
4699
4605
4700 if not didwork and pats:
4606 if not didwork and pats:
4701 hint = None
4607 hint = None
4702 if not any([p for p in pats if p.find(':') >= 0]):
4608 if not any([p for p in pats if p.find(':') >= 0]):
4703 pats = ['path:%s' % p for p in pats]
4609 pats = ['path:%s' % p for p in pats]
4704 m = scmutil.match(wctx, pats, opts)
4610 m = scmutil.match(wctx, pats, opts)
4705 for f in ms:
4611 for f in ms:
4706 if not m(f):
4612 if not m(f):
4707 continue
4613 continue
4708 flags = ''.join(['-%s ' % o[0] for o in flaglist
4614 flags = ''.join(['-%s ' % o[0] for o in flaglist
4709 if opts.get(o)])
4615 if opts.get(o)])
4710 hint = _("(try: hg resolve %s%s)\n") % (
4616 hint = _("(try: hg resolve %s%s)\n") % (
4711 flags,
4617 flags,
4712 ' '.join(pats))
4618 ' '.join(pats))
4713 break
4619 break
4714 ui.warn(_("arguments do not match paths that need resolving\n"))
4620 ui.warn(_("arguments do not match paths that need resolving\n"))
4715 if hint:
4621 if hint:
4716 ui.warn(hint)
4622 ui.warn(hint)
4717 elif ms.mergedriver and ms.mdstate() != 's':
4623 elif ms.mergedriver and ms.mdstate() != 's':
4718 # run conclude step when either a driver-resolved file is requested
4624 # run conclude step when either a driver-resolved file is requested
4719 # or there are no driver-resolved files
4625 # or there are no driver-resolved files
4720 # we can't use 'ret' to determine whether any files are unresolved
4626 # we can't use 'ret' to determine whether any files are unresolved
4721 # because we might not have tried to resolve some
4627 # because we might not have tried to resolve some
4722 if ((runconclude or not list(ms.driverresolved()))
4628 if ((runconclude or not list(ms.driverresolved()))
4723 and not list(ms.unresolved())):
4629 and not list(ms.unresolved())):
4724 proceed = mergemod.driverconclude(repo, ms, wctx)
4630 proceed = mergemod.driverconclude(repo, ms, wctx)
4725 ms.commit()
4631 ms.commit()
4726 if not proceed:
4632 if not proceed:
4727 return 1
4633 return 1
4728
4634
4729 # Nudge users into finishing an unfinished operation
4635 # Nudge users into finishing an unfinished operation
4730 unresolvedf = list(ms.unresolved())
4636 unresolvedf = list(ms.unresolved())
4731 driverresolvedf = list(ms.driverresolved())
4637 driverresolvedf = list(ms.driverresolved())
4732 if not unresolvedf and not driverresolvedf:
4638 if not unresolvedf and not driverresolvedf:
4733 ui.status(_('(no more unresolved files)\n'))
4639 ui.status(_('(no more unresolved files)\n'))
4734 cmdutil.checkafterresolved(repo)
4640 cmdutil.checkafterresolved(repo)
4735 elif not unresolvedf:
4641 elif not unresolvedf:
4736 ui.status(_('(no more unresolved files -- '
4642 ui.status(_('(no more unresolved files -- '
4737 'run "hg resolve --all" to conclude)\n'))
4643 'run "hg resolve --all" to conclude)\n'))
4738
4644
4739 return ret
4645 return ret
4740
4646
4741 @command('revert',
4647 @command('revert',
4742 [('a', 'all', None, _('revert all changes when no arguments given')),
4648 [('a', 'all', None, _('revert all changes when no arguments given')),
4743 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4649 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4744 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4650 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4745 ('C', 'no-backup', None, _('do not save backup copies of files')),
4651 ('C', 'no-backup', None, _('do not save backup copies of files')),
4746 ('i', 'interactive', None,
4652 ('i', 'interactive', None,
4747 _('interactively select the changes (EXPERIMENTAL)')),
4653 _('interactively select the changes (EXPERIMENTAL)')),
4748 ] + walkopts + dryrunopts,
4654 ] + walkopts + dryrunopts,
4749 _('[OPTION]... [-r REV] [NAME]...'))
4655 _('[OPTION]... [-r REV] [NAME]...'))
4750 def revert(ui, repo, *pats, **opts):
4656 def revert(ui, repo, *pats, **opts):
4751 """restore files to their checkout state
4657 """restore files to their checkout state
4752
4658
4753 .. note::
4659 .. note::
4754
4660
4755 To check out earlier revisions, you should use :hg:`update REV`.
4661 To check out earlier revisions, you should use :hg:`update REV`.
4756 To cancel an uncommitted merge (and lose your changes),
4662 To cancel an uncommitted merge (and lose your changes),
4757 use :hg:`update --clean .`.
4663 use :hg:`update --clean .`.
4758
4664
4759 With no revision specified, revert the specified files or directories
4665 With no revision specified, revert the specified files or directories
4760 to the contents they had in the parent of the working directory.
4666 to the contents they had in the parent of the working directory.
4761 This restores the contents of files to an unmodified
4667 This restores the contents of files to an unmodified
4762 state and unschedules adds, removes, copies, and renames. If the
4668 state and unschedules adds, removes, copies, and renames. If the
4763 working directory has two parents, you must explicitly specify a
4669 working directory has two parents, you must explicitly specify a
4764 revision.
4670 revision.
4765
4671
4766 Using the -r/--rev or -d/--date options, revert the given files or
4672 Using the -r/--rev or -d/--date options, revert the given files or
4767 directories to their states as of a specific revision. Because
4673 directories to their states as of a specific revision. Because
4768 revert does not change the working directory parents, this will
4674 revert does not change the working directory parents, this will
4769 cause these files to appear modified. This can be helpful to "back
4675 cause these files to appear modified. This can be helpful to "back
4770 out" some or all of an earlier change. See :hg:`backout` for a
4676 out" some or all of an earlier change. See :hg:`backout` for a
4771 related method.
4677 related method.
4772
4678
4773 Modified files are saved with a .orig suffix before reverting.
4679 Modified files are saved with a .orig suffix before reverting.
4774 To disable these backups, use --no-backup. It is possible to store
4680 To disable these backups, use --no-backup. It is possible to store
4775 the backup files in a custom directory relative to the root of the
4681 the backup files in a custom directory relative to the root of the
4776 repository by setting the ``ui.origbackuppath`` configuration
4682 repository by setting the ``ui.origbackuppath`` configuration
4777 option.
4683 option.
4778
4684
4779 See :hg:`help dates` for a list of formats valid for -d/--date.
4685 See :hg:`help dates` for a list of formats valid for -d/--date.
4780
4686
4781 See :hg:`help backout` for a way to reverse the effect of an
4687 See :hg:`help backout` for a way to reverse the effect of an
4782 earlier changeset.
4688 earlier changeset.
4783
4689
4784 Returns 0 on success.
4690 Returns 0 on success.
4785 """
4691 """
4786
4692
4787 if opts.get("date"):
4693 if opts.get("date"):
4788 if opts.get("rev"):
4694 if opts.get("rev"):
4789 raise error.Abort(_("you can't specify a revision and a date"))
4695 raise error.Abort(_("you can't specify a revision and a date"))
4790 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4696 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4791
4697
4792 parent, p2 = repo.dirstate.parents()
4698 parent, p2 = repo.dirstate.parents()
4793 if not opts.get('rev') and p2 != nullid:
4699 if not opts.get('rev') and p2 != nullid:
4794 # revert after merge is a trap for new users (issue2915)
4700 # revert after merge is a trap for new users (issue2915)
4795 raise error.Abort(_('uncommitted merge with no revision specified'),
4701 raise error.Abort(_('uncommitted merge with no revision specified'),
4796 hint=_("use 'hg update' or see 'hg help revert'"))
4702 hint=_("use 'hg update' or see 'hg help revert'"))
4797
4703
4798 ctx = scmutil.revsingle(repo, opts.get('rev'))
4704 ctx = scmutil.revsingle(repo, opts.get('rev'))
4799
4705
4800 if (not (pats or opts.get('include') or opts.get('exclude') or
4706 if (not (pats or opts.get('include') or opts.get('exclude') or
4801 opts.get('all') or opts.get('interactive'))):
4707 opts.get('all') or opts.get('interactive'))):
4802 msg = _("no files or directories specified")
4708 msg = _("no files or directories specified")
4803 if p2 != nullid:
4709 if p2 != nullid:
4804 hint = _("uncommitted merge, use --all to discard all changes,"
4710 hint = _("uncommitted merge, use --all to discard all changes,"
4805 " or 'hg update -C .' to abort the merge")
4711 " or 'hg update -C .' to abort the merge")
4806 raise error.Abort(msg, hint=hint)
4712 raise error.Abort(msg, hint=hint)
4807 dirty = any(repo.status())
4713 dirty = any(repo.status())
4808 node = ctx.node()
4714 node = ctx.node()
4809 if node != parent:
4715 if node != parent:
4810 if dirty:
4716 if dirty:
4811 hint = _("uncommitted changes, use --all to discard all"
4717 hint = _("uncommitted changes, use --all to discard all"
4812 " changes, or 'hg update %s' to update") % ctx.rev()
4718 " changes, or 'hg update %s' to update") % ctx.rev()
4813 else:
4719 else:
4814 hint = _("use --all to revert all files,"
4720 hint = _("use --all to revert all files,"
4815 " or 'hg update %s' to update") % ctx.rev()
4721 " or 'hg update %s' to update") % ctx.rev()
4816 elif dirty:
4722 elif dirty:
4817 hint = _("uncommitted changes, use --all to discard all changes")
4723 hint = _("uncommitted changes, use --all to discard all changes")
4818 else:
4724 else:
4819 hint = _("use --all to revert all files")
4725 hint = _("use --all to revert all files")
4820 raise error.Abort(msg, hint=hint)
4726 raise error.Abort(msg, hint=hint)
4821
4727
4822 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4728 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4823
4729
4824 @command('rollback', dryrunopts +
4730 @command('rollback', dryrunopts +
4825 [('f', 'force', False, _('ignore safety measures'))])
4731 [('f', 'force', False, _('ignore safety measures'))])
4826 def rollback(ui, repo, **opts):
4732 def rollback(ui, repo, **opts):
4827 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4733 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4828
4734
4829 Please use :hg:`commit --amend` instead of rollback to correct
4735 Please use :hg:`commit --amend` instead of rollback to correct
4830 mistakes in the last commit.
4736 mistakes in the last commit.
4831
4737
4832 This command should be used with care. There is only one level of
4738 This command should be used with care. There is only one level of
4833 rollback, and there is no way to undo a rollback. It will also
4739 rollback, and there is no way to undo a rollback. It will also
4834 restore the dirstate at the time of the last transaction, losing
4740 restore the dirstate at the time of the last transaction, losing
4835 any dirstate changes since that time. This command does not alter
4741 any dirstate changes since that time. This command does not alter
4836 the working directory.
4742 the working directory.
4837
4743
4838 Transactions are used to encapsulate the effects of all commands
4744 Transactions are used to encapsulate the effects of all commands
4839 that create new changesets or propagate existing changesets into a
4745 that create new changesets or propagate existing changesets into a
4840 repository.
4746 repository.
4841
4747
4842 .. container:: verbose
4748 .. container:: verbose
4843
4749
4844 For example, the following commands are transactional, and their
4750 For example, the following commands are transactional, and their
4845 effects can be rolled back:
4751 effects can be rolled back:
4846
4752
4847 - commit
4753 - commit
4848 - import
4754 - import
4849 - pull
4755 - pull
4850 - push (with this repository as the destination)
4756 - push (with this repository as the destination)
4851 - unbundle
4757 - unbundle
4852
4758
4853 To avoid permanent data loss, rollback will refuse to rollback a
4759 To avoid permanent data loss, rollback will refuse to rollback a
4854 commit transaction if it isn't checked out. Use --force to
4760 commit transaction if it isn't checked out. Use --force to
4855 override this protection.
4761 override this protection.
4856
4762
4857 The rollback command can be entirely disabled by setting the
4763 The rollback command can be entirely disabled by setting the
4858 ``ui.rollback`` configuration setting to false. If you're here
4764 ``ui.rollback`` configuration setting to false. If you're here
4859 because you want to use rollback and it's disabled, you can
4765 because you want to use rollback and it's disabled, you can
4860 re-enable the command by setting ``ui.rollback`` to true.
4766 re-enable the command by setting ``ui.rollback`` to true.
4861
4767
4862 This command is not intended for use on public repositories. Once
4768 This command is not intended for use on public repositories. Once
4863 changes are visible for pull by other users, rolling a transaction
4769 changes are visible for pull by other users, rolling a transaction
4864 back locally is ineffective (someone else may already have pulled
4770 back locally is ineffective (someone else may already have pulled
4865 the changes). Furthermore, a race is possible with readers of the
4771 the changes). Furthermore, a race is possible with readers of the
4866 repository; for example an in-progress pull from the repository
4772 repository; for example an in-progress pull from the repository
4867 may fail if a rollback is performed.
4773 may fail if a rollback is performed.
4868
4774
4869 Returns 0 on success, 1 if no rollback data is available.
4775 Returns 0 on success, 1 if no rollback data is available.
4870 """
4776 """
4871 if not ui.configbool('ui', 'rollback', True):
4777 if not ui.configbool('ui', 'rollback', True):
4872 raise error.Abort(_('rollback is disabled because it is unsafe'),
4778 raise error.Abort(_('rollback is disabled because it is unsafe'),
4873 hint=('see `hg help -v rollback` for information'))
4779 hint=('see `hg help -v rollback` for information'))
4874 return repo.rollback(dryrun=opts.get('dry_run'),
4780 return repo.rollback(dryrun=opts.get('dry_run'),
4875 force=opts.get('force'))
4781 force=opts.get('force'))
4876
4782
4877 @command('root', [])
4783 @command('root', [])
4878 def root(ui, repo):
4784 def root(ui, repo):
4879 """print the root (top) of the current working directory
4785 """print the root (top) of the current working directory
4880
4786
4881 Print the root directory of the current repository.
4787 Print the root directory of the current repository.
4882
4788
4883 Returns 0 on success.
4789 Returns 0 on success.
4884 """
4790 """
4885 ui.write(repo.root + "\n")
4791 ui.write(repo.root + "\n")
4886
4792
4887 @command('^serve',
4793 @command('^serve',
4888 [('A', 'accesslog', '', _('name of access log file to write to'),
4794 [('A', 'accesslog', '', _('name of access log file to write to'),
4889 _('FILE')),
4795 _('FILE')),
4890 ('d', 'daemon', None, _('run server in background')),
4796 ('d', 'daemon', None, _('run server in background')),
4891 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4797 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4892 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4798 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4893 # use string type, then we can check if something was passed
4799 # use string type, then we can check if something was passed
4894 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4800 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4895 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4801 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4896 _('ADDR')),
4802 _('ADDR')),
4897 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4803 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4898 _('PREFIX')),
4804 _('PREFIX')),
4899 ('n', 'name', '',
4805 ('n', 'name', '',
4900 _('name to show in web pages (default: working directory)'), _('NAME')),
4806 _('name to show in web pages (default: working directory)'), _('NAME')),
4901 ('', 'web-conf', '',
4807 ('', 'web-conf', '',
4902 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4808 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4903 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4809 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4904 _('FILE')),
4810 _('FILE')),
4905 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4811 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4906 ('', 'stdio', None, _('for remote clients')),
4812 ('', 'stdio', None, _('for remote clients')),
4907 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4813 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4908 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4814 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4909 ('', 'style', '', _('template style to use'), _('STYLE')),
4815 ('', 'style', '', _('template style to use'), _('STYLE')),
4910 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4816 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4911 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4817 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4912 _('[OPTION]...'),
4818 _('[OPTION]...'),
4913 optionalrepo=True)
4819 optionalrepo=True)
4914 def serve(ui, repo, **opts):
4820 def serve(ui, repo, **opts):
4915 """start stand-alone webserver
4821 """start stand-alone webserver
4916
4822
4917 Start a local HTTP repository browser and pull server. You can use
4823 Start a local HTTP repository browser and pull server. You can use
4918 this for ad-hoc sharing and browsing of repositories. It is
4824 this for ad-hoc sharing and browsing of repositories. It is
4919 recommended to use a real web server to serve a repository for
4825 recommended to use a real web server to serve a repository for
4920 longer periods of time.
4826 longer periods of time.
4921
4827
4922 Please note that the server does not implement access control.
4828 Please note that the server does not implement access control.
4923 This means that, by default, anybody can read from the server and
4829 This means that, by default, anybody can read from the server and
4924 nobody can write to it by default. Set the ``web.allow_push``
4830 nobody can write to it by default. Set the ``web.allow_push``
4925 option to ``*`` to allow everybody to push to the server. You
4831 option to ``*`` to allow everybody to push to the server. You
4926 should use a real web server if you need to authenticate users.
4832 should use a real web server if you need to authenticate users.
4927
4833
4928 By default, the server logs accesses to stdout and errors to
4834 By default, the server logs accesses to stdout and errors to
4929 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4835 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4930 files.
4836 files.
4931
4837
4932 To have the server choose a free port number to listen on, specify
4838 To have the server choose a free port number to listen on, specify
4933 a port number of 0; in this case, the server will print the port
4839 a port number of 0; in this case, the server will print the port
4934 number it uses.
4840 number it uses.
4935
4841
4936 Returns 0 on success.
4842 Returns 0 on success.
4937 """
4843 """
4938
4844
4939 if opts["stdio"] and opts["cmdserver"]:
4845 if opts["stdio"] and opts["cmdserver"]:
4940 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4846 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4941
4847
4942 if opts["stdio"]:
4848 if opts["stdio"]:
4943 if repo is None:
4849 if repo is None:
4944 raise error.RepoError(_("there is no Mercurial repository here"
4850 raise error.RepoError(_("there is no Mercurial repository here"
4945 " (.hg not found)"))
4851 " (.hg not found)"))
4946 s = sshserver.sshserver(ui, repo)
4852 s = sshserver.sshserver(ui, repo)
4947 s.serve_forever()
4853 s.serve_forever()
4948
4854
4949 service = server.createservice(ui, repo, opts)
4855 service = server.createservice(ui, repo, opts)
4950 return server.runservice(opts, initfn=service.init, runfn=service.run)
4856 return server.runservice(opts, initfn=service.init, runfn=service.run)
4951
4857
4952 @command('^status|st',
4858 @command('^status|st',
4953 [('A', 'all', None, _('show status of all files')),
4859 [('A', 'all', None, _('show status of all files')),
4954 ('m', 'modified', None, _('show only modified files')),
4860 ('m', 'modified', None, _('show only modified files')),
4955 ('a', 'added', None, _('show only added files')),
4861 ('a', 'added', None, _('show only added files')),
4956 ('r', 'removed', None, _('show only removed files')),
4862 ('r', 'removed', None, _('show only removed files')),
4957 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4863 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4958 ('c', 'clean', None, _('show only files without changes')),
4864 ('c', 'clean', None, _('show only files without changes')),
4959 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4865 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4960 ('i', 'ignored', None, _('show only ignored files')),
4866 ('i', 'ignored', None, _('show only ignored files')),
4961 ('n', 'no-status', None, _('hide status prefix')),
4867 ('n', 'no-status', None, _('hide status prefix')),
4962 ('C', 'copies', None, _('show source of copied files')),
4868 ('C', 'copies', None, _('show source of copied files')),
4963 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4869 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4964 ('', 'rev', [], _('show difference from revision'), _('REV')),
4870 ('', 'rev', [], _('show difference from revision'), _('REV')),
4965 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4871 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4966 ] + walkopts + subrepoopts + formatteropts,
4872 ] + walkopts + subrepoopts + formatteropts,
4967 _('[OPTION]... [FILE]...'),
4873 _('[OPTION]... [FILE]...'),
4968 inferrepo=True)
4874 inferrepo=True)
4969 def status(ui, repo, *pats, **opts):
4875 def status(ui, repo, *pats, **opts):
4970 """show changed files in the working directory
4876 """show changed files in the working directory
4971
4877
4972 Show status of files in the repository. If names are given, only
4878 Show status of files in the repository. If names are given, only
4973 files that match are shown. Files that are clean or ignored or
4879 files that match are shown. Files that are clean or ignored or
4974 the source of a copy/move operation, are not listed unless
4880 the source of a copy/move operation, are not listed unless
4975 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4881 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4976 Unless options described with "show only ..." are given, the
4882 Unless options described with "show only ..." are given, the
4977 options -mardu are used.
4883 options -mardu are used.
4978
4884
4979 Option -q/--quiet hides untracked (unknown and ignored) files
4885 Option -q/--quiet hides untracked (unknown and ignored) files
4980 unless explicitly requested with -u/--unknown or -i/--ignored.
4886 unless explicitly requested with -u/--unknown or -i/--ignored.
4981
4887
4982 .. note::
4888 .. note::
4983
4889
4984 :hg:`status` may appear to disagree with diff if permissions have
4890 :hg:`status` may appear to disagree with diff if permissions have
4985 changed or a merge has occurred. The standard diff format does
4891 changed or a merge has occurred. The standard diff format does
4986 not report permission changes and diff only reports changes
4892 not report permission changes and diff only reports changes
4987 relative to one merge parent.
4893 relative to one merge parent.
4988
4894
4989 If one revision is given, it is used as the base revision.
4895 If one revision is given, it is used as the base revision.
4990 If two revisions are given, the differences between them are
4896 If two revisions are given, the differences between them are
4991 shown. The --change option can also be used as a shortcut to list
4897 shown. The --change option can also be used as a shortcut to list
4992 the changed files of a revision from its first parent.
4898 the changed files of a revision from its first parent.
4993
4899
4994 The codes used to show the status of files are::
4900 The codes used to show the status of files are::
4995
4901
4996 M = modified
4902 M = modified
4997 A = added
4903 A = added
4998 R = removed
4904 R = removed
4999 C = clean
4905 C = clean
5000 ! = missing (deleted by non-hg command, but still tracked)
4906 ! = missing (deleted by non-hg command, but still tracked)
5001 ? = not tracked
4907 ? = not tracked
5002 I = ignored
4908 I = ignored
5003 = origin of the previous file (with --copies)
4909 = origin of the previous file (with --copies)
5004
4910
5005 .. container:: verbose
4911 .. container:: verbose
5006
4912
5007 Examples:
4913 Examples:
5008
4914
5009 - show changes in the working directory relative to a
4915 - show changes in the working directory relative to a
5010 changeset::
4916 changeset::
5011
4917
5012 hg status --rev 9353
4918 hg status --rev 9353
5013
4919
5014 - show changes in the working directory relative to the
4920 - show changes in the working directory relative to the
5015 current directory (see :hg:`help patterns` for more information)::
4921 current directory (see :hg:`help patterns` for more information)::
5016
4922
5017 hg status re:
4923 hg status re:
5018
4924
5019 - show all changes including copies in an existing changeset::
4925 - show all changes including copies in an existing changeset::
5020
4926
5021 hg status --copies --change 9353
4927 hg status --copies --change 9353
5022
4928
5023 - get a NUL separated list of added files, suitable for xargs::
4929 - get a NUL separated list of added files, suitable for xargs::
5024
4930
5025 hg status -an0
4931 hg status -an0
5026
4932
5027 Returns 0 on success.
4933 Returns 0 on success.
5028 """
4934 """
5029
4935
5030 revs = opts.get('rev')
4936 revs = opts.get('rev')
5031 change = opts.get('change')
4937 change = opts.get('change')
5032
4938
5033 if revs and change:
4939 if revs and change:
5034 msg = _('cannot specify --rev and --change at the same time')
4940 msg = _('cannot specify --rev and --change at the same time')
5035 raise error.Abort(msg)
4941 raise error.Abort(msg)
5036 elif change:
4942 elif change:
5037 node2 = scmutil.revsingle(repo, change, None).node()
4943 node2 = scmutil.revsingle(repo, change, None).node()
5038 node1 = repo[node2].p1().node()
4944 node1 = repo[node2].p1().node()
5039 else:
4945 else:
5040 node1, node2 = scmutil.revpair(repo, revs)
4946 node1, node2 = scmutil.revpair(repo, revs)
5041
4947
5042 if pats:
4948 if pats:
5043 cwd = repo.getcwd()
4949 cwd = repo.getcwd()
5044 else:
4950 else:
5045 cwd = ''
4951 cwd = ''
5046
4952
5047 if opts.get('print0'):
4953 if opts.get('print0'):
5048 end = '\0'
4954 end = '\0'
5049 else:
4955 else:
5050 end = '\n'
4956 end = '\n'
5051 copy = {}
4957 copy = {}
5052 states = 'modified added removed deleted unknown ignored clean'.split()
4958 states = 'modified added removed deleted unknown ignored clean'.split()
5053 show = [k for k in states if opts.get(k)]
4959 show = [k for k in states if opts.get(k)]
5054 if opts.get('all'):
4960 if opts.get('all'):
5055 show += ui.quiet and (states[:4] + ['clean']) or states
4961 show += ui.quiet and (states[:4] + ['clean']) or states
5056 if not show:
4962 if not show:
5057 if ui.quiet:
4963 if ui.quiet:
5058 show = states[:4]
4964 show = states[:4]
5059 else:
4965 else:
5060 show = states[:5]
4966 show = states[:5]
5061
4967
5062 m = scmutil.match(repo[node2], pats, opts)
4968 m = scmutil.match(repo[node2], pats, opts)
5063 stat = repo.status(node1, node2, m,
4969 stat = repo.status(node1, node2, m,
5064 'ignored' in show, 'clean' in show, 'unknown' in show,
4970 'ignored' in show, 'clean' in show, 'unknown' in show,
5065 opts.get('subrepos'))
4971 opts.get('subrepos'))
5066 changestates = zip(states, 'MAR!?IC', stat)
4972 changestates = zip(states, 'MAR!?IC', stat)
5067
4973
5068 if (opts.get('all') or opts.get('copies')
4974 if (opts.get('all') or opts.get('copies')
5069 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4975 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5070 copy = copies.pathcopies(repo[node1], repo[node2], m)
4976 copy = copies.pathcopies(repo[node1], repo[node2], m)
5071
4977
5072 fm = ui.formatter('status', opts)
4978 fm = ui.formatter('status', opts)
5073 fmt = '%s' + end
4979 fmt = '%s' + end
5074 showchar = not opts.get('no_status')
4980 showchar = not opts.get('no_status')
5075
4981
5076 for state, char, files in changestates:
4982 for state, char, files in changestates:
5077 if state in show:
4983 if state in show:
5078 label = 'status.' + state
4984 label = 'status.' + state
5079 for f in files:
4985 for f in files:
5080 fm.startitem()
4986 fm.startitem()
5081 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4987 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5082 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4988 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5083 if f in copy:
4989 if f in copy:
5084 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4990 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5085 label='status.copied')
4991 label='status.copied')
5086 fm.end()
4992 fm.end()
5087
4993
5088 @command('^summary|sum',
4994 @command('^summary|sum',
5089 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4995 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5090 def summary(ui, repo, **opts):
4996 def summary(ui, repo, **opts):
5091 """summarize working directory state
4997 """summarize working directory state
5092
4998
5093 This generates a brief summary of the working directory state,
4999 This generates a brief summary of the working directory state,
5094 including parents, branch, commit status, phase and available updates.
5000 including parents, branch, commit status, phase and available updates.
5095
5001
5096 With the --remote option, this will check the default paths for
5002 With the --remote option, this will check the default paths for
5097 incoming and outgoing changes. This can be time-consuming.
5003 incoming and outgoing changes. This can be time-consuming.
5098
5004
5099 Returns 0 on success.
5005 Returns 0 on success.
5100 """
5006 """
5101
5007
5102 ctx = repo[None]
5008 ctx = repo[None]
5103 parents = ctx.parents()
5009 parents = ctx.parents()
5104 pnode = parents[0].node()
5010 pnode = parents[0].node()
5105 marks = []
5011 marks = []
5106
5012
5107 ms = None
5013 ms = None
5108 try:
5014 try:
5109 ms = mergemod.mergestate.read(repo)
5015 ms = mergemod.mergestate.read(repo)
5110 except error.UnsupportedMergeRecords as e:
5016 except error.UnsupportedMergeRecords as e:
5111 s = ' '.join(e.recordtypes)
5017 s = ' '.join(e.recordtypes)
5112 ui.warn(
5018 ui.warn(
5113 _('warning: merge state has unsupported record types: %s\n') % s)
5019 _('warning: merge state has unsupported record types: %s\n') % s)
5114 unresolved = 0
5020 unresolved = 0
5115 else:
5021 else:
5116 unresolved = [f for f in ms if ms[f] == 'u']
5022 unresolved = [f for f in ms if ms[f] == 'u']
5117
5023
5118 for p in parents:
5024 for p in parents:
5119 # label with log.changeset (instead of log.parent) since this
5025 # label with log.changeset (instead of log.parent) since this
5120 # shows a working directory parent *changeset*:
5026 # shows a working directory parent *changeset*:
5121 # i18n: column positioning for "hg summary"
5027 # i18n: column positioning for "hg summary"
5122 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5028 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5123 label=cmdutil._changesetlabels(p))
5029 label=cmdutil._changesetlabels(p))
5124 ui.write(' '.join(p.tags()), label='log.tag')
5030 ui.write(' '.join(p.tags()), label='log.tag')
5125 if p.bookmarks():
5031 if p.bookmarks():
5126 marks.extend(p.bookmarks())
5032 marks.extend(p.bookmarks())
5127 if p.rev() == -1:
5033 if p.rev() == -1:
5128 if not len(repo):
5034 if not len(repo):
5129 ui.write(_(' (empty repository)'))
5035 ui.write(_(' (empty repository)'))
5130 else:
5036 else:
5131 ui.write(_(' (no revision checked out)'))
5037 ui.write(_(' (no revision checked out)'))
5132 if p.troubled():
5038 if p.troubled():
5133 ui.write(' ('
5039 ui.write(' ('
5134 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5040 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5135 for trouble in p.troubles())
5041 for trouble in p.troubles())
5136 + ')')
5042 + ')')
5137 ui.write('\n')
5043 ui.write('\n')
5138 if p.description():
5044 if p.description():
5139 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5045 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5140 label='log.summary')
5046 label='log.summary')
5141
5047
5142 branch = ctx.branch()
5048 branch = ctx.branch()
5143 bheads = repo.branchheads(branch)
5049 bheads = repo.branchheads(branch)
5144 # i18n: column positioning for "hg summary"
5050 # i18n: column positioning for "hg summary"
5145 m = _('branch: %s\n') % branch
5051 m = _('branch: %s\n') % branch
5146 if branch != 'default':
5052 if branch != 'default':
5147 ui.write(m, label='log.branch')
5053 ui.write(m, label='log.branch')
5148 else:
5054 else:
5149 ui.status(m, label='log.branch')
5055 ui.status(m, label='log.branch')
5150
5056
5151 if marks:
5057 if marks:
5152 active = repo._activebookmark
5058 active = repo._activebookmark
5153 # i18n: column positioning for "hg summary"
5059 # i18n: column positioning for "hg summary"
5154 ui.write(_('bookmarks:'), label='log.bookmark')
5060 ui.write(_('bookmarks:'), label='log.bookmark')
5155 if active is not None:
5061 if active is not None:
5156 if active in marks:
5062 if active in marks:
5157 ui.write(' *' + active, label=activebookmarklabel)
5063 ui.write(' *' + active, label=activebookmarklabel)
5158 marks.remove(active)
5064 marks.remove(active)
5159 else:
5065 else:
5160 ui.write(' [%s]' % active, label=activebookmarklabel)
5066 ui.write(' [%s]' % active, label=activebookmarklabel)
5161 for m in marks:
5067 for m in marks:
5162 ui.write(' ' + m, label='log.bookmark')
5068 ui.write(' ' + m, label='log.bookmark')
5163 ui.write('\n', label='log.bookmark')
5069 ui.write('\n', label='log.bookmark')
5164
5070
5165 status = repo.status(unknown=True)
5071 status = repo.status(unknown=True)
5166
5072
5167 c = repo.dirstate.copies()
5073 c = repo.dirstate.copies()
5168 copied, renamed = [], []
5074 copied, renamed = [], []
5169 for d, s in c.iteritems():
5075 for d, s in c.iteritems():
5170 if s in status.removed:
5076 if s in status.removed:
5171 status.removed.remove(s)
5077 status.removed.remove(s)
5172 renamed.append(d)
5078 renamed.append(d)
5173 else:
5079 else:
5174 copied.append(d)
5080 copied.append(d)
5175 if d in status.added:
5081 if d in status.added:
5176 status.added.remove(d)
5082 status.added.remove(d)
5177
5083
5178 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5084 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5179
5085
5180 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5086 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5181 (ui.label(_('%d added'), 'status.added'), status.added),
5087 (ui.label(_('%d added'), 'status.added'), status.added),
5182 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5088 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5183 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5089 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5184 (ui.label(_('%d copied'), 'status.copied'), copied),
5090 (ui.label(_('%d copied'), 'status.copied'), copied),
5185 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5091 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5186 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5092 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5187 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5093 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5188 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5094 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5189 t = []
5095 t = []
5190 for l, s in labels:
5096 for l, s in labels:
5191 if s:
5097 if s:
5192 t.append(l % len(s))
5098 t.append(l % len(s))
5193
5099
5194 t = ', '.join(t)
5100 t = ', '.join(t)
5195 cleanworkdir = False
5101 cleanworkdir = False
5196
5102
5197 if repo.vfs.exists('graftstate'):
5103 if repo.vfs.exists('graftstate'):
5198 t += _(' (graft in progress)')
5104 t += _(' (graft in progress)')
5199 if repo.vfs.exists('updatestate'):
5105 if repo.vfs.exists('updatestate'):
5200 t += _(' (interrupted update)')
5106 t += _(' (interrupted update)')
5201 elif len(parents) > 1:
5107 elif len(parents) > 1:
5202 t += _(' (merge)')
5108 t += _(' (merge)')
5203 elif branch != parents[0].branch():
5109 elif branch != parents[0].branch():
5204 t += _(' (new branch)')
5110 t += _(' (new branch)')
5205 elif (parents[0].closesbranch() and
5111 elif (parents[0].closesbranch() and
5206 pnode in repo.branchheads(branch, closed=True)):
5112 pnode in repo.branchheads(branch, closed=True)):
5207 t += _(' (head closed)')
5113 t += _(' (head closed)')
5208 elif not (status.modified or status.added or status.removed or renamed or
5114 elif not (status.modified or status.added or status.removed or renamed or
5209 copied or subs):
5115 copied or subs):
5210 t += _(' (clean)')
5116 t += _(' (clean)')
5211 cleanworkdir = True
5117 cleanworkdir = True
5212 elif pnode not in bheads:
5118 elif pnode not in bheads:
5213 t += _(' (new branch head)')
5119 t += _(' (new branch head)')
5214
5120
5215 if parents:
5121 if parents:
5216 pendingphase = max(p.phase() for p in parents)
5122 pendingphase = max(p.phase() for p in parents)
5217 else:
5123 else:
5218 pendingphase = phases.public
5124 pendingphase = phases.public
5219
5125
5220 if pendingphase > phases.newcommitphase(ui):
5126 if pendingphase > phases.newcommitphase(ui):
5221 t += ' (%s)' % phases.phasenames[pendingphase]
5127 t += ' (%s)' % phases.phasenames[pendingphase]
5222
5128
5223 if cleanworkdir:
5129 if cleanworkdir:
5224 # i18n: column positioning for "hg summary"
5130 # i18n: column positioning for "hg summary"
5225 ui.status(_('commit: %s\n') % t.strip())
5131 ui.status(_('commit: %s\n') % t.strip())
5226 else:
5132 else:
5227 # i18n: column positioning for "hg summary"
5133 # i18n: column positioning for "hg summary"
5228 ui.write(_('commit: %s\n') % t.strip())
5134 ui.write(_('commit: %s\n') % t.strip())
5229
5135
5230 # all ancestors of branch heads - all ancestors of parent = new csets
5136 # all ancestors of branch heads - all ancestors of parent = new csets
5231 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5137 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5232 bheads))
5138 bheads))
5233
5139
5234 if new == 0:
5140 if new == 0:
5235 # i18n: column positioning for "hg summary"
5141 # i18n: column positioning for "hg summary"
5236 ui.status(_('update: (current)\n'))
5142 ui.status(_('update: (current)\n'))
5237 elif pnode not in bheads:
5143 elif pnode not in bheads:
5238 # i18n: column positioning for "hg summary"
5144 # i18n: column positioning for "hg summary"
5239 ui.write(_('update: %d new changesets (update)\n') % new)
5145 ui.write(_('update: %d new changesets (update)\n') % new)
5240 else:
5146 else:
5241 # i18n: column positioning for "hg summary"
5147 # i18n: column positioning for "hg summary"
5242 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5148 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5243 (new, len(bheads)))
5149 (new, len(bheads)))
5244
5150
5245 t = []
5151 t = []
5246 draft = len(repo.revs('draft()'))
5152 draft = len(repo.revs('draft()'))
5247 if draft:
5153 if draft:
5248 t.append(_('%d draft') % draft)
5154 t.append(_('%d draft') % draft)
5249 secret = len(repo.revs('secret()'))
5155 secret = len(repo.revs('secret()'))
5250 if secret:
5156 if secret:
5251 t.append(_('%d secret') % secret)
5157 t.append(_('%d secret') % secret)
5252
5158
5253 if draft or secret:
5159 if draft or secret:
5254 ui.status(_('phases: %s\n') % ', '.join(t))
5160 ui.status(_('phases: %s\n') % ', '.join(t))
5255
5161
5256 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5162 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5257 for trouble in ("unstable", "divergent", "bumped"):
5163 for trouble in ("unstable", "divergent", "bumped"):
5258 numtrouble = len(repo.revs(trouble + "()"))
5164 numtrouble = len(repo.revs(trouble + "()"))
5259 # We write all the possibilities to ease translation
5165 # We write all the possibilities to ease translation
5260 troublemsg = {
5166 troublemsg = {
5261 "unstable": _("unstable: %d changesets"),
5167 "unstable": _("unstable: %d changesets"),
5262 "divergent": _("divergent: %d changesets"),
5168 "divergent": _("divergent: %d changesets"),
5263 "bumped": _("bumped: %d changesets"),
5169 "bumped": _("bumped: %d changesets"),
5264 }
5170 }
5265 if numtrouble > 0:
5171 if numtrouble > 0:
5266 ui.status(troublemsg[trouble] % numtrouble + "\n")
5172 ui.status(troublemsg[trouble] % numtrouble + "\n")
5267
5173
5268 cmdutil.summaryhooks(ui, repo)
5174 cmdutil.summaryhooks(ui, repo)
5269
5175
5270 if opts.get('remote'):
5176 if opts.get('remote'):
5271 needsincoming, needsoutgoing = True, True
5177 needsincoming, needsoutgoing = True, True
5272 else:
5178 else:
5273 needsincoming, needsoutgoing = False, False
5179 needsincoming, needsoutgoing = False, False
5274 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5180 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5275 if i:
5181 if i:
5276 needsincoming = True
5182 needsincoming = True
5277 if o:
5183 if o:
5278 needsoutgoing = True
5184 needsoutgoing = True
5279 if not needsincoming and not needsoutgoing:
5185 if not needsincoming and not needsoutgoing:
5280 return
5186 return
5281
5187
5282 def getincoming():
5188 def getincoming():
5283 source, branches = hg.parseurl(ui.expandpath('default'))
5189 source, branches = hg.parseurl(ui.expandpath('default'))
5284 sbranch = branches[0]
5190 sbranch = branches[0]
5285 try:
5191 try:
5286 other = hg.peer(repo, {}, source)
5192 other = hg.peer(repo, {}, source)
5287 except error.RepoError:
5193 except error.RepoError:
5288 if opts.get('remote'):
5194 if opts.get('remote'):
5289 raise
5195 raise
5290 return source, sbranch, None, None, None
5196 return source, sbranch, None, None, None
5291 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5197 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5292 if revs:
5198 if revs:
5293 revs = [other.lookup(rev) for rev in revs]
5199 revs = [other.lookup(rev) for rev in revs]
5294 ui.debug('comparing with %s\n' % util.hidepassword(source))
5200 ui.debug('comparing with %s\n' % util.hidepassword(source))
5295 repo.ui.pushbuffer()
5201 repo.ui.pushbuffer()
5296 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5202 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5297 repo.ui.popbuffer()
5203 repo.ui.popbuffer()
5298 return source, sbranch, other, commoninc, commoninc[1]
5204 return source, sbranch, other, commoninc, commoninc[1]
5299
5205
5300 if needsincoming:
5206 if needsincoming:
5301 source, sbranch, sother, commoninc, incoming = getincoming()
5207 source, sbranch, sother, commoninc, incoming = getincoming()
5302 else:
5208 else:
5303 source = sbranch = sother = commoninc = incoming = None
5209 source = sbranch = sother = commoninc = incoming = None
5304
5210
5305 def getoutgoing():
5211 def getoutgoing():
5306 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5212 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5307 dbranch = branches[0]
5213 dbranch = branches[0]
5308 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5214 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5309 if source != dest:
5215 if source != dest:
5310 try:
5216 try:
5311 dother = hg.peer(repo, {}, dest)
5217 dother = hg.peer(repo, {}, dest)
5312 except error.RepoError:
5218 except error.RepoError:
5313 if opts.get('remote'):
5219 if opts.get('remote'):
5314 raise
5220 raise
5315 return dest, dbranch, None, None
5221 return dest, dbranch, None, None
5316 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5222 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5317 elif sother is None:
5223 elif sother is None:
5318 # there is no explicit destination peer, but source one is invalid
5224 # there is no explicit destination peer, but source one is invalid
5319 return dest, dbranch, None, None
5225 return dest, dbranch, None, None
5320 else:
5226 else:
5321 dother = sother
5227 dother = sother
5322 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5228 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5323 common = None
5229 common = None
5324 else:
5230 else:
5325 common = commoninc
5231 common = commoninc
5326 if revs:
5232 if revs:
5327 revs = [repo.lookup(rev) for rev in revs]
5233 revs = [repo.lookup(rev) for rev in revs]
5328 repo.ui.pushbuffer()
5234 repo.ui.pushbuffer()
5329 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5235 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5330 commoninc=common)
5236 commoninc=common)
5331 repo.ui.popbuffer()
5237 repo.ui.popbuffer()
5332 return dest, dbranch, dother, outgoing
5238 return dest, dbranch, dother, outgoing
5333
5239
5334 if needsoutgoing:
5240 if needsoutgoing:
5335 dest, dbranch, dother, outgoing = getoutgoing()
5241 dest, dbranch, dother, outgoing = getoutgoing()
5336 else:
5242 else:
5337 dest = dbranch = dother = outgoing = None
5243 dest = dbranch = dother = outgoing = None
5338
5244
5339 if opts.get('remote'):
5245 if opts.get('remote'):
5340 t = []
5246 t = []
5341 if incoming:
5247 if incoming:
5342 t.append(_('1 or more incoming'))
5248 t.append(_('1 or more incoming'))
5343 o = outgoing.missing
5249 o = outgoing.missing
5344 if o:
5250 if o:
5345 t.append(_('%d outgoing') % len(o))
5251 t.append(_('%d outgoing') % len(o))
5346 other = dother or sother
5252 other = dother or sother
5347 if 'bookmarks' in other.listkeys('namespaces'):
5253 if 'bookmarks' in other.listkeys('namespaces'):
5348 counts = bookmarks.summary(repo, other)
5254 counts = bookmarks.summary(repo, other)
5349 if counts[0] > 0:
5255 if counts[0] > 0:
5350 t.append(_('%d incoming bookmarks') % counts[0])
5256 t.append(_('%d incoming bookmarks') % counts[0])
5351 if counts[1] > 0:
5257 if counts[1] > 0:
5352 t.append(_('%d outgoing bookmarks') % counts[1])
5258 t.append(_('%d outgoing bookmarks') % counts[1])
5353
5259
5354 if t:
5260 if t:
5355 # i18n: column positioning for "hg summary"
5261 # i18n: column positioning for "hg summary"
5356 ui.write(_('remote: %s\n') % (', '.join(t)))
5262 ui.write(_('remote: %s\n') % (', '.join(t)))
5357 else:
5263 else:
5358 # i18n: column positioning for "hg summary"
5264 # i18n: column positioning for "hg summary"
5359 ui.status(_('remote: (synced)\n'))
5265 ui.status(_('remote: (synced)\n'))
5360
5266
5361 cmdutil.summaryremotehooks(ui, repo, opts,
5267 cmdutil.summaryremotehooks(ui, repo, opts,
5362 ((source, sbranch, sother, commoninc),
5268 ((source, sbranch, sother, commoninc),
5363 (dest, dbranch, dother, outgoing)))
5269 (dest, dbranch, dother, outgoing)))
5364
5270
5365 @command('tag',
5271 @command('tag',
5366 [('f', 'force', None, _('force tag')),
5272 [('f', 'force', None, _('force tag')),
5367 ('l', 'local', None, _('make the tag local')),
5273 ('l', 'local', None, _('make the tag local')),
5368 ('r', 'rev', '', _('revision to tag'), _('REV')),
5274 ('r', 'rev', '', _('revision to tag'), _('REV')),
5369 ('', 'remove', None, _('remove a tag')),
5275 ('', 'remove', None, _('remove a tag')),
5370 # -l/--local is already there, commitopts cannot be used
5276 # -l/--local is already there, commitopts cannot be used
5371 ('e', 'edit', None, _('invoke editor on commit messages')),
5277 ('e', 'edit', None, _('invoke editor on commit messages')),
5372 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5278 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5373 ] + commitopts2,
5279 ] + commitopts2,
5374 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5280 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5375 def tag(ui, repo, name1, *names, **opts):
5281 def tag(ui, repo, name1, *names, **opts):
5376 """add one or more tags for the current or given revision
5282 """add one or more tags for the current or given revision
5377
5283
5378 Name a particular revision using <name>.
5284 Name a particular revision using <name>.
5379
5285
5380 Tags are used to name particular revisions of the repository and are
5286 Tags are used to name particular revisions of the repository and are
5381 very useful to compare different revisions, to go back to significant
5287 very useful to compare different revisions, to go back to significant
5382 earlier versions or to mark branch points as releases, etc. Changing
5288 earlier versions or to mark branch points as releases, etc. Changing
5383 an existing tag is normally disallowed; use -f/--force to override.
5289 an existing tag is normally disallowed; use -f/--force to override.
5384
5290
5385 If no revision is given, the parent of the working directory is
5291 If no revision is given, the parent of the working directory is
5386 used.
5292 used.
5387
5293
5388 To facilitate version control, distribution, and merging of tags,
5294 To facilitate version control, distribution, and merging of tags,
5389 they are stored as a file named ".hgtags" which is managed similarly
5295 they are stored as a file named ".hgtags" which is managed similarly
5390 to other project files and can be hand-edited if necessary. This
5296 to other project files and can be hand-edited if necessary. This
5391 also means that tagging creates a new commit. The file
5297 also means that tagging creates a new commit. The file
5392 ".hg/localtags" is used for local tags (not shared among
5298 ".hg/localtags" is used for local tags (not shared among
5393 repositories).
5299 repositories).
5394
5300
5395 Tag commits are usually made at the head of a branch. If the parent
5301 Tag commits are usually made at the head of a branch. If the parent
5396 of the working directory is not a branch head, :hg:`tag` aborts; use
5302 of the working directory is not a branch head, :hg:`tag` aborts; use
5397 -f/--force to force the tag commit to be based on a non-head
5303 -f/--force to force the tag commit to be based on a non-head
5398 changeset.
5304 changeset.
5399
5305
5400 See :hg:`help dates` for a list of formats valid for -d/--date.
5306 See :hg:`help dates` for a list of formats valid for -d/--date.
5401
5307
5402 Since tag names have priority over branch names during revision
5308 Since tag names have priority over branch names during revision
5403 lookup, using an existing branch name as a tag name is discouraged.
5309 lookup, using an existing branch name as a tag name is discouraged.
5404
5310
5405 Returns 0 on success.
5311 Returns 0 on success.
5406 """
5312 """
5407 wlock = lock = None
5313 wlock = lock = None
5408 try:
5314 try:
5409 wlock = repo.wlock()
5315 wlock = repo.wlock()
5410 lock = repo.lock()
5316 lock = repo.lock()
5411 rev_ = "."
5317 rev_ = "."
5412 names = [t.strip() for t in (name1,) + names]
5318 names = [t.strip() for t in (name1,) + names]
5413 if len(names) != len(set(names)):
5319 if len(names) != len(set(names)):
5414 raise error.Abort(_('tag names must be unique'))
5320 raise error.Abort(_('tag names must be unique'))
5415 for n in names:
5321 for n in names:
5416 scmutil.checknewlabel(repo, n, 'tag')
5322 scmutil.checknewlabel(repo, n, 'tag')
5417 if not n:
5323 if not n:
5418 raise error.Abort(_('tag names cannot consist entirely of '
5324 raise error.Abort(_('tag names cannot consist entirely of '
5419 'whitespace'))
5325 'whitespace'))
5420 if opts.get('rev') and opts.get('remove'):
5326 if opts.get('rev') and opts.get('remove'):
5421 raise error.Abort(_("--rev and --remove are incompatible"))
5327 raise error.Abort(_("--rev and --remove are incompatible"))
5422 if opts.get('rev'):
5328 if opts.get('rev'):
5423 rev_ = opts['rev']
5329 rev_ = opts['rev']
5424 message = opts.get('message')
5330 message = opts.get('message')
5425 if opts.get('remove'):
5331 if opts.get('remove'):
5426 if opts.get('local'):
5332 if opts.get('local'):
5427 expectedtype = 'local'
5333 expectedtype = 'local'
5428 else:
5334 else:
5429 expectedtype = 'global'
5335 expectedtype = 'global'
5430
5336
5431 for n in names:
5337 for n in names:
5432 if not repo.tagtype(n):
5338 if not repo.tagtype(n):
5433 raise error.Abort(_("tag '%s' does not exist") % n)
5339 raise error.Abort(_("tag '%s' does not exist") % n)
5434 if repo.tagtype(n) != expectedtype:
5340 if repo.tagtype(n) != expectedtype:
5435 if expectedtype == 'global':
5341 if expectedtype == 'global':
5436 raise error.Abort(_("tag '%s' is not a global tag") % n)
5342 raise error.Abort(_("tag '%s' is not a global tag") % n)
5437 else:
5343 else:
5438 raise error.Abort(_("tag '%s' is not a local tag") % n)
5344 raise error.Abort(_("tag '%s' is not a local tag") % n)
5439 rev_ = 'null'
5345 rev_ = 'null'
5440 if not message:
5346 if not message:
5441 # we don't translate commit messages
5347 # we don't translate commit messages
5442 message = 'Removed tag %s' % ', '.join(names)
5348 message = 'Removed tag %s' % ', '.join(names)
5443 elif not opts.get('force'):
5349 elif not opts.get('force'):
5444 for n in names:
5350 for n in names:
5445 if n in repo.tags():
5351 if n in repo.tags():
5446 raise error.Abort(_("tag '%s' already exists "
5352 raise error.Abort(_("tag '%s' already exists "
5447 "(use -f to force)") % n)
5353 "(use -f to force)") % n)
5448 if not opts.get('local'):
5354 if not opts.get('local'):
5449 p1, p2 = repo.dirstate.parents()
5355 p1, p2 = repo.dirstate.parents()
5450 if p2 != nullid:
5356 if p2 != nullid:
5451 raise error.Abort(_('uncommitted merge'))
5357 raise error.Abort(_('uncommitted merge'))
5452 bheads = repo.branchheads()
5358 bheads = repo.branchheads()
5453 if not opts.get('force') and bheads and p1 not in bheads:
5359 if not opts.get('force') and bheads and p1 not in bheads:
5454 raise error.Abort(_('working directory is not at a branch head '
5360 raise error.Abort(_('working directory is not at a branch head '
5455 '(use -f to force)'))
5361 '(use -f to force)'))
5456 r = scmutil.revsingle(repo, rev_).node()
5362 r = scmutil.revsingle(repo, rev_).node()
5457
5363
5458 if not message:
5364 if not message:
5459 # we don't translate commit messages
5365 # we don't translate commit messages
5460 message = ('Added tag %s for changeset %s' %
5366 message = ('Added tag %s for changeset %s' %
5461 (', '.join(names), short(r)))
5367 (', '.join(names), short(r)))
5462
5368
5463 date = opts.get('date')
5369 date = opts.get('date')
5464 if date:
5370 if date:
5465 date = util.parsedate(date)
5371 date = util.parsedate(date)
5466
5372
5467 if opts.get('remove'):
5373 if opts.get('remove'):
5468 editform = 'tag.remove'
5374 editform = 'tag.remove'
5469 else:
5375 else:
5470 editform = 'tag.add'
5376 editform = 'tag.add'
5471 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5377 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5472
5378
5473 # don't allow tagging the null rev
5379 # don't allow tagging the null rev
5474 if (not opts.get('remove') and
5380 if (not opts.get('remove') and
5475 scmutil.revsingle(repo, rev_).rev() == nullrev):
5381 scmutil.revsingle(repo, rev_).rev() == nullrev):
5476 raise error.Abort(_("cannot tag null revision"))
5382 raise error.Abort(_("cannot tag null revision"))
5477
5383
5478 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5384 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5479 editor=editor)
5385 editor=editor)
5480 finally:
5386 finally:
5481 release(lock, wlock)
5387 release(lock, wlock)
5482
5388
5483 @command('tags', formatteropts, '')
5389 @command('tags', formatteropts, '')
5484 def tags(ui, repo, **opts):
5390 def tags(ui, repo, **opts):
5485 """list repository tags
5391 """list repository tags
5486
5392
5487 This lists both regular and local tags. When the -v/--verbose
5393 This lists both regular and local tags. When the -v/--verbose
5488 switch is used, a third column "local" is printed for local tags.
5394 switch is used, a third column "local" is printed for local tags.
5489 When the -q/--quiet switch is used, only the tag name is printed.
5395 When the -q/--quiet switch is used, only the tag name is printed.
5490
5396
5491 Returns 0 on success.
5397 Returns 0 on success.
5492 """
5398 """
5493
5399
5494 fm = ui.formatter('tags', opts)
5400 fm = ui.formatter('tags', opts)
5495 hexfunc = fm.hexfunc
5401 hexfunc = fm.hexfunc
5496 tagtype = ""
5402 tagtype = ""
5497
5403
5498 for t, n in reversed(repo.tagslist()):
5404 for t, n in reversed(repo.tagslist()):
5499 hn = hexfunc(n)
5405 hn = hexfunc(n)
5500 label = 'tags.normal'
5406 label = 'tags.normal'
5501 tagtype = ''
5407 tagtype = ''
5502 if repo.tagtype(t) == 'local':
5408 if repo.tagtype(t) == 'local':
5503 label = 'tags.local'
5409 label = 'tags.local'
5504 tagtype = 'local'
5410 tagtype = 'local'
5505
5411
5506 fm.startitem()
5412 fm.startitem()
5507 fm.write('tag', '%s', t, label=label)
5413 fm.write('tag', '%s', t, label=label)
5508 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5414 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5509 fm.condwrite(not ui.quiet, 'rev node', fmt,
5415 fm.condwrite(not ui.quiet, 'rev node', fmt,
5510 repo.changelog.rev(n), hn, label=label)
5416 repo.changelog.rev(n), hn, label=label)
5511 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5417 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5512 tagtype, label=label)
5418 tagtype, label=label)
5513 fm.plain('\n')
5419 fm.plain('\n')
5514 fm.end()
5420 fm.end()
5515
5421
5516 @command('tip',
5422 @command('tip',
5517 [('p', 'patch', None, _('show patch')),
5423 [('p', 'patch', None, _('show patch')),
5518 ('g', 'git', None, _('use git extended diff format')),
5424 ('g', 'git', None, _('use git extended diff format')),
5519 ] + templateopts,
5425 ] + templateopts,
5520 _('[-p] [-g]'))
5426 _('[-p] [-g]'))
5521 def tip(ui, repo, **opts):
5427 def tip(ui, repo, **opts):
5522 """show the tip revision (DEPRECATED)
5428 """show the tip revision (DEPRECATED)
5523
5429
5524 The tip revision (usually just called the tip) is the changeset
5430 The tip revision (usually just called the tip) is the changeset
5525 most recently added to the repository (and therefore the most
5431 most recently added to the repository (and therefore the most
5526 recently changed head).
5432 recently changed head).
5527
5433
5528 If you have just made a commit, that commit will be the tip. If
5434 If you have just made a commit, that commit will be the tip. If
5529 you have just pulled changes from another repository, the tip of
5435 you have just pulled changes from another repository, the tip of
5530 that repository becomes the current tip. The "tip" tag is special
5436 that repository becomes the current tip. The "tip" tag is special
5531 and cannot be renamed or assigned to a different changeset.
5437 and cannot be renamed or assigned to a different changeset.
5532
5438
5533 This command is deprecated, please use :hg:`heads` instead.
5439 This command is deprecated, please use :hg:`heads` instead.
5534
5440
5535 Returns 0 on success.
5441 Returns 0 on success.
5536 """
5442 """
5537 displayer = cmdutil.show_changeset(ui, repo, opts)
5443 displayer = cmdutil.show_changeset(ui, repo, opts)
5538 displayer.show(repo['tip'])
5444 displayer.show(repo['tip'])
5539 displayer.close()
5445 displayer.close()
5540
5446
5541 @command('unbundle',
5447 @command('unbundle',
5542 [('u', 'update', None,
5448 [('u', 'update', None,
5543 _('update to new branch head if changesets were unbundled'))],
5449 _('update to new branch head if changesets were unbundled'))],
5544 _('[-u] FILE...'))
5450 _('[-u] FILE...'))
5545 def unbundle(ui, repo, fname1, *fnames, **opts):
5451 def unbundle(ui, repo, fname1, *fnames, **opts):
5546 """apply one or more changegroup files
5452 """apply one or more changegroup files
5547
5453
5548 Apply one or more compressed changegroup files generated by the
5454 Apply one or more compressed changegroup files generated by the
5549 bundle command.
5455 bundle command.
5550
5456
5551 Returns 0 on success, 1 if an update has unresolved files.
5457 Returns 0 on success, 1 if an update has unresolved files.
5552 """
5458 """
5553 fnames = (fname1,) + fnames
5459 fnames = (fname1,) + fnames
5554
5460
5555 with repo.lock():
5461 with repo.lock():
5556 for fname in fnames:
5462 for fname in fnames:
5557 f = hg.openpath(ui, fname)
5463 f = hg.openpath(ui, fname)
5558 gen = exchange.readbundle(ui, f, fname)
5464 gen = exchange.readbundle(ui, f, fname)
5559 if isinstance(gen, bundle2.unbundle20):
5465 if isinstance(gen, bundle2.unbundle20):
5560 tr = repo.transaction('unbundle')
5466 tr = repo.transaction('unbundle')
5561 try:
5467 try:
5562 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5468 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5563 url='bundle:' + fname)
5469 url='bundle:' + fname)
5564 tr.close()
5470 tr.close()
5565 except error.BundleUnknownFeatureError as exc:
5471 except error.BundleUnknownFeatureError as exc:
5566 raise error.Abort(_('%s: unknown bundle feature, %s')
5472 raise error.Abort(_('%s: unknown bundle feature, %s')
5567 % (fname, exc),
5473 % (fname, exc),
5568 hint=_("see https://mercurial-scm.org/"
5474 hint=_("see https://mercurial-scm.org/"
5569 "wiki/BundleFeature for more "
5475 "wiki/BundleFeature for more "
5570 "information"))
5476 "information"))
5571 finally:
5477 finally:
5572 if tr:
5478 if tr:
5573 tr.release()
5479 tr.release()
5574 changes = [r.get('return', 0)
5480 changes = [r.get('return', 0)
5575 for r in op.records['changegroup']]
5481 for r in op.records['changegroup']]
5576 modheads = changegroup.combineresults(changes)
5482 modheads = changegroup.combineresults(changes)
5577 elif isinstance(gen, streamclone.streamcloneapplier):
5483 elif isinstance(gen, streamclone.streamcloneapplier):
5578 raise error.Abort(
5484 raise error.Abort(
5579 _('packed bundles cannot be applied with '
5485 _('packed bundles cannot be applied with '
5580 '"hg unbundle"'),
5486 '"hg unbundle"'),
5581 hint=_('use "hg debugapplystreamclonebundle"'))
5487 hint=_('use "hg debugapplystreamclonebundle"'))
5582 else:
5488 else:
5583 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5489 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5584
5490
5585 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5491 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5586
5492
5587 @command('^update|up|checkout|co',
5493 @command('^update|up|checkout|co',
5588 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5494 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5589 ('c', 'check', None, _('require clean working directory')),
5495 ('c', 'check', None, _('require clean working directory')),
5590 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5496 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5591 ('r', 'rev', '', _('revision'), _('REV'))
5497 ('r', 'rev', '', _('revision'), _('REV'))
5592 ] + mergetoolopts,
5498 ] + mergetoolopts,
5593 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5499 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5594 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5500 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5595 tool=None):
5501 tool=None):
5596 """update working directory (or switch revisions)
5502 """update working directory (or switch revisions)
5597
5503
5598 Update the repository's working directory to the specified
5504 Update the repository's working directory to the specified
5599 changeset. If no changeset is specified, update to the tip of the
5505 changeset. If no changeset is specified, update to the tip of the
5600 current named branch and move the active bookmark (see :hg:`help
5506 current named branch and move the active bookmark (see :hg:`help
5601 bookmarks`).
5507 bookmarks`).
5602
5508
5603 Update sets the working directory's parent revision to the specified
5509 Update sets the working directory's parent revision to the specified
5604 changeset (see :hg:`help parents`).
5510 changeset (see :hg:`help parents`).
5605
5511
5606 If the changeset is not a descendant or ancestor of the working
5512 If the changeset is not a descendant or ancestor of the working
5607 directory's parent and there are uncommitted changes, the update is
5513 directory's parent and there are uncommitted changes, the update is
5608 aborted. With the -c/--check option, the working directory is checked
5514 aborted. With the -c/--check option, the working directory is checked
5609 for uncommitted changes; if none are found, the working directory is
5515 for uncommitted changes; if none are found, the working directory is
5610 updated to the specified changeset.
5516 updated to the specified changeset.
5611
5517
5612 .. container:: verbose
5518 .. container:: verbose
5613
5519
5614 The following rules apply when the working directory contains
5520 The following rules apply when the working directory contains
5615 uncommitted changes:
5521 uncommitted changes:
5616
5522
5617 1. If neither -c/--check nor -C/--clean is specified, and if
5523 1. If neither -c/--check nor -C/--clean is specified, and if
5618 the requested changeset is an ancestor or descendant of
5524 the requested changeset is an ancestor or descendant of
5619 the working directory's parent, the uncommitted changes
5525 the working directory's parent, the uncommitted changes
5620 are merged into the requested changeset and the merged
5526 are merged into the requested changeset and the merged
5621 result is left uncommitted. If the requested changeset is
5527 result is left uncommitted. If the requested changeset is
5622 not an ancestor or descendant (that is, it is on another
5528 not an ancestor or descendant (that is, it is on another
5623 branch), the update is aborted and the uncommitted changes
5529 branch), the update is aborted and the uncommitted changes
5624 are preserved.
5530 are preserved.
5625
5531
5626 2. With the -c/--check option, the update is aborted and the
5532 2. With the -c/--check option, the update is aborted and the
5627 uncommitted changes are preserved.
5533 uncommitted changes are preserved.
5628
5534
5629 3. With the -C/--clean option, uncommitted changes are discarded and
5535 3. With the -C/--clean option, uncommitted changes are discarded and
5630 the working directory is updated to the requested changeset.
5536 the working directory is updated to the requested changeset.
5631
5537
5632 To cancel an uncommitted merge (and lose your changes), use
5538 To cancel an uncommitted merge (and lose your changes), use
5633 :hg:`update --clean .`.
5539 :hg:`update --clean .`.
5634
5540
5635 Use null as the changeset to remove the working directory (like
5541 Use null as the changeset to remove the working directory (like
5636 :hg:`clone -U`).
5542 :hg:`clone -U`).
5637
5543
5638 If you want to revert just one file to an older revision, use
5544 If you want to revert just one file to an older revision, use
5639 :hg:`revert [-r REV] NAME`.
5545 :hg:`revert [-r REV] NAME`.
5640
5546
5641 See :hg:`help dates` for a list of formats valid for -d/--date.
5547 See :hg:`help dates` for a list of formats valid for -d/--date.
5642
5548
5643 Returns 0 on success, 1 if there are unresolved files.
5549 Returns 0 on success, 1 if there are unresolved files.
5644 """
5550 """
5645 if rev and node:
5551 if rev and node:
5646 raise error.Abort(_("please specify just one revision"))
5552 raise error.Abort(_("please specify just one revision"))
5647
5553
5648 if rev is None or rev == '':
5554 if rev is None or rev == '':
5649 rev = node
5555 rev = node
5650
5556
5651 if date and rev is not None:
5557 if date and rev is not None:
5652 raise error.Abort(_("you can't specify a revision and a date"))
5558 raise error.Abort(_("you can't specify a revision and a date"))
5653
5559
5654 if check and clean:
5560 if check and clean:
5655 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5561 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5656
5562
5657 with repo.wlock():
5563 with repo.wlock():
5658 cmdutil.clearunfinished(repo)
5564 cmdutil.clearunfinished(repo)
5659
5565
5660 if date:
5566 if date:
5661 rev = cmdutil.finddate(ui, repo, date)
5567 rev = cmdutil.finddate(ui, repo, date)
5662
5568
5663 # if we defined a bookmark, we have to remember the original name
5569 # if we defined a bookmark, we have to remember the original name
5664 brev = rev
5570 brev = rev
5665 rev = scmutil.revsingle(repo, rev, rev).rev()
5571 rev = scmutil.revsingle(repo, rev, rev).rev()
5666
5572
5667 if check:
5573 if check:
5668 cmdutil.bailifchanged(repo, merge=False)
5574 cmdutil.bailifchanged(repo, merge=False)
5669
5575
5670 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5576 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5671
5577
5672 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5578 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5673
5579
5674 @command('verify', [])
5580 @command('verify', [])
5675 def verify(ui, repo):
5581 def verify(ui, repo):
5676 """verify the integrity of the repository
5582 """verify the integrity of the repository
5677
5583
5678 Verify the integrity of the current repository.
5584 Verify the integrity of the current repository.
5679
5585
5680 This will perform an extensive check of the repository's
5586 This will perform an extensive check of the repository's
5681 integrity, validating the hashes and checksums of each entry in
5587 integrity, validating the hashes and checksums of each entry in
5682 the changelog, manifest, and tracked files, as well as the
5588 the changelog, manifest, and tracked files, as well as the
5683 integrity of their crosslinks and indices.
5589 integrity of their crosslinks and indices.
5684
5590
5685 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5591 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5686 for more information about recovery from corruption of the
5592 for more information about recovery from corruption of the
5687 repository.
5593 repository.
5688
5594
5689 Returns 0 on success, 1 if errors are encountered.
5595 Returns 0 on success, 1 if errors are encountered.
5690 """
5596 """
5691 return hg.verify(repo)
5597 return hg.verify(repo)
5692
5598
5693 @command('version', [] + formatteropts, norepo=True)
5599 @command('version', [] + formatteropts, norepo=True)
5694 def version_(ui, **opts):
5600 def version_(ui, **opts):
5695 """output version and copyright information"""
5601 """output version and copyright information"""
5696 fm = ui.formatter("version", opts)
5602 fm = ui.formatter("version", opts)
5697 fm.startitem()
5603 fm.startitem()
5698 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5604 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5699 util.version())
5605 util.version())
5700 license = _(
5606 license = _(
5701 "(see https://mercurial-scm.org for more information)\n"
5607 "(see https://mercurial-scm.org for more information)\n"
5702 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5608 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5703 "This is free software; see the source for copying conditions. "
5609 "This is free software; see the source for copying conditions. "
5704 "There is NO\nwarranty; "
5610 "There is NO\nwarranty; "
5705 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5611 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5706 )
5612 )
5707 if not ui.quiet:
5613 if not ui.quiet:
5708 fm.plain(license)
5614 fm.plain(license)
5709
5615
5710 if ui.verbose:
5616 if ui.verbose:
5711 fm.plain(_("\nEnabled extensions:\n\n"))
5617 fm.plain(_("\nEnabled extensions:\n\n"))
5712 # format names and versions into columns
5618 # format names and versions into columns
5713 names = []
5619 names = []
5714 vers = []
5620 vers = []
5715 isinternals = []
5621 isinternals = []
5716 for name, module in extensions.extensions():
5622 for name, module in extensions.extensions():
5717 names.append(name)
5623 names.append(name)
5718 vers.append(extensions.moduleversion(module) or None)
5624 vers.append(extensions.moduleversion(module) or None)
5719 isinternals.append(extensions.ismoduleinternal(module))
5625 isinternals.append(extensions.ismoduleinternal(module))
5720 fn = fm.nested("extensions")
5626 fn = fm.nested("extensions")
5721 if names:
5627 if names:
5722 namefmt = " %%-%ds " % max(len(n) for n in names)
5628 namefmt = " %%-%ds " % max(len(n) for n in names)
5723 places = [_("external"), _("internal")]
5629 places = [_("external"), _("internal")]
5724 for n, v, p in zip(names, vers, isinternals):
5630 for n, v, p in zip(names, vers, isinternals):
5725 fn.startitem()
5631 fn.startitem()
5726 fn.condwrite(ui.verbose, "name", namefmt, n)
5632 fn.condwrite(ui.verbose, "name", namefmt, n)
5727 if ui.verbose:
5633 if ui.verbose:
5728 fn.plain("%s " % places[p])
5634 fn.plain("%s " % places[p])
5729 fn.data(bundled=p)
5635 fn.data(bundled=p)
5730 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5636 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5731 if ui.verbose:
5637 if ui.verbose:
5732 fn.plain("\n")
5638 fn.plain("\n")
5733 fn.end()
5639 fn.end()
5734 fm.end()
5640 fm.end()
5735
5641
5736 def loadcmdtable(ui, name, cmdtable):
5642 def loadcmdtable(ui, name, cmdtable):
5737 """Load command functions from specified cmdtable
5643 """Load command functions from specified cmdtable
5738 """
5644 """
5739 overrides = [cmd for cmd in cmdtable if cmd in table]
5645 overrides = [cmd for cmd in cmdtable if cmd in table]
5740 if overrides:
5646 if overrides:
5741 ui.warn(_("extension '%s' overrides commands: %s\n")
5647 ui.warn(_("extension '%s' overrides commands: %s\n")
5742 % (name, " ".join(overrides)))
5648 % (name, " ".join(overrides)))
5743 table.update(cmdtable)
5649 table.update(cmdtable)
@@ -1,1765 +1,1861
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2016 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import errno
11 import errno
11 import operator
12 import operator
12 import os
13 import os
13 import random
14 import random
14 import socket
15 import socket
15 import string
16 import string
16 import sys
17 import sys
17 import tempfile
18 import tempfile
18 import time
19 import time
19
20
20 from .i18n import _
21 from .i18n import _
21 from .node import (
22 from .node import (
22 bin,
23 bin,
23 hex,
24 hex,
24 nullhex,
25 nullhex,
25 nullid,
26 nullid,
26 nullrev,
27 nullrev,
27 short,
28 short,
28 )
29 )
29 from . import (
30 from . import (
30 bundle2,
31 bundle2,
31 changegroup,
32 changegroup,
32 cmdutil,
33 cmdutil,
33 commands,
34 commands,
34 context,
35 context,
35 dagparser,
36 dagparser,
36 dagutil,
37 dagutil,
37 encoding,
38 encoding,
38 error,
39 error,
39 exchange,
40 exchange,
40 extensions,
41 extensions,
41 fileset,
42 fileset,
42 hg,
43 hg,
43 localrepo,
44 localrepo,
44 lock as lockmod,
45 lock as lockmod,
45 merge as mergemod,
46 merge as mergemod,
46 obsolete,
47 obsolete,
47 policy,
48 policy,
48 pvec,
49 pvec,
49 pycompat,
50 pycompat,
50 repair,
51 repair,
51 revlog,
52 revlog,
53 revset,
52 scmutil,
54 scmutil,
53 setdiscovery,
55 setdiscovery,
54 simplemerge,
56 simplemerge,
57 smartset,
55 sslutil,
58 sslutil,
56 streamclone,
59 streamclone,
57 templater,
60 templater,
58 treediscovery,
61 treediscovery,
59 util,
62 util,
60 )
63 )
61
64
62 release = lockmod.release
65 release = lockmod.release
63
66
64 # We reuse the command table from commands because it is easier than
67 # We reuse the command table from commands because it is easier than
65 # teaching dispatch about multiple tables.
68 # teaching dispatch about multiple tables.
66 command = cmdutil.command(commands.table)
69 command = cmdutil.command(commands.table)
67
70
68 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
71 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
69 def debugancestor(ui, repo, *args):
72 def debugancestor(ui, repo, *args):
70 """find the ancestor revision of two revisions in a given index"""
73 """find the ancestor revision of two revisions in a given index"""
71 if len(args) == 3:
74 if len(args) == 3:
72 index, rev1, rev2 = args
75 index, rev1, rev2 = args
73 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
76 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
74 lookup = r.lookup
77 lookup = r.lookup
75 elif len(args) == 2:
78 elif len(args) == 2:
76 if not repo:
79 if not repo:
77 raise error.Abort(_('there is no Mercurial repository here '
80 raise error.Abort(_('there is no Mercurial repository here '
78 '(.hg not found)'))
81 '(.hg not found)'))
79 rev1, rev2 = args
82 rev1, rev2 = args
80 r = repo.changelog
83 r = repo.changelog
81 lookup = repo.lookup
84 lookup = repo.lookup
82 else:
85 else:
83 raise error.Abort(_('either two or three arguments required'))
86 raise error.Abort(_('either two or three arguments required'))
84 a = r.ancestor(lookup(rev1), lookup(rev2))
87 a = r.ancestor(lookup(rev1), lookup(rev2))
85 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
88 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
86
89
87 @command('debugapplystreamclonebundle', [], 'FILE')
90 @command('debugapplystreamclonebundle', [], 'FILE')
88 def debugapplystreamclonebundle(ui, repo, fname):
91 def debugapplystreamclonebundle(ui, repo, fname):
89 """apply a stream clone bundle file"""
92 """apply a stream clone bundle file"""
90 f = hg.openpath(ui, fname)
93 f = hg.openpath(ui, fname)
91 gen = exchange.readbundle(ui, f, fname)
94 gen = exchange.readbundle(ui, f, fname)
92 gen.apply(repo)
95 gen.apply(repo)
93
96
94 @command('debugbuilddag',
97 @command('debugbuilddag',
95 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
98 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
96 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
99 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
97 ('n', 'new-file', None, _('add new file at each rev'))],
100 ('n', 'new-file', None, _('add new file at each rev'))],
98 _('[OPTION]... [TEXT]'))
101 _('[OPTION]... [TEXT]'))
99 def debugbuilddag(ui, repo, text=None,
102 def debugbuilddag(ui, repo, text=None,
100 mergeable_file=False,
103 mergeable_file=False,
101 overwritten_file=False,
104 overwritten_file=False,
102 new_file=False):
105 new_file=False):
103 """builds a repo with a given DAG from scratch in the current empty repo
106 """builds a repo with a given DAG from scratch in the current empty repo
104
107
105 The description of the DAG is read from stdin if not given on the
108 The description of the DAG is read from stdin if not given on the
106 command line.
109 command line.
107
110
108 Elements:
111 Elements:
109
112
110 - "+n" is a linear run of n nodes based on the current default parent
113 - "+n" is a linear run of n nodes based on the current default parent
111 - "." is a single node based on the current default parent
114 - "." is a single node based on the current default parent
112 - "$" resets the default parent to null (implied at the start);
115 - "$" resets the default parent to null (implied at the start);
113 otherwise the default parent is always the last node created
116 otherwise the default parent is always the last node created
114 - "<p" sets the default parent to the backref p
117 - "<p" sets the default parent to the backref p
115 - "*p" is a fork at parent p, which is a backref
118 - "*p" is a fork at parent p, which is a backref
116 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
119 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
117 - "/p2" is a merge of the preceding node and p2
120 - "/p2" is a merge of the preceding node and p2
118 - ":tag" defines a local tag for the preceding node
121 - ":tag" defines a local tag for the preceding node
119 - "@branch" sets the named branch for subsequent nodes
122 - "@branch" sets the named branch for subsequent nodes
120 - "#...\\n" is a comment up to the end of the line
123 - "#...\\n" is a comment up to the end of the line
121
124
122 Whitespace between the above elements is ignored.
125 Whitespace between the above elements is ignored.
123
126
124 A backref is either
127 A backref is either
125
128
126 - a number n, which references the node curr-n, where curr is the current
129 - a number n, which references the node curr-n, where curr is the current
127 node, or
130 node, or
128 - the name of a local tag you placed earlier using ":tag", or
131 - the name of a local tag you placed earlier using ":tag", or
129 - empty to denote the default parent.
132 - empty to denote the default parent.
130
133
131 All string valued-elements are either strictly alphanumeric, or must
134 All string valued-elements are either strictly alphanumeric, or must
132 be enclosed in double quotes ("..."), with "\\" as escape character.
135 be enclosed in double quotes ("..."), with "\\" as escape character.
133 """
136 """
134
137
135 if text is None:
138 if text is None:
136 ui.status(_("reading DAG from stdin\n"))
139 ui.status(_("reading DAG from stdin\n"))
137 text = ui.fin.read()
140 text = ui.fin.read()
138
141
139 cl = repo.changelog
142 cl = repo.changelog
140 if len(cl) > 0:
143 if len(cl) > 0:
141 raise error.Abort(_('repository is not empty'))
144 raise error.Abort(_('repository is not empty'))
142
145
143 # determine number of revs in DAG
146 # determine number of revs in DAG
144 total = 0
147 total = 0
145 for type, data in dagparser.parsedag(text):
148 for type, data in dagparser.parsedag(text):
146 if type == 'n':
149 if type == 'n':
147 total += 1
150 total += 1
148
151
149 if mergeable_file:
152 if mergeable_file:
150 linesperrev = 2
153 linesperrev = 2
151 # make a file with k lines per rev
154 # make a file with k lines per rev
152 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
155 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
153 initialmergedlines.append("")
156 initialmergedlines.append("")
154
157
155 tags = []
158 tags = []
156
159
157 wlock = lock = tr = None
160 wlock = lock = tr = None
158 try:
161 try:
159 wlock = repo.wlock()
162 wlock = repo.wlock()
160 lock = repo.lock()
163 lock = repo.lock()
161 tr = repo.transaction("builddag")
164 tr = repo.transaction("builddag")
162
165
163 at = -1
166 at = -1
164 atbranch = 'default'
167 atbranch = 'default'
165 nodeids = []
168 nodeids = []
166 id = 0
169 id = 0
167 ui.progress(_('building'), id, unit=_('revisions'), total=total)
170 ui.progress(_('building'), id, unit=_('revisions'), total=total)
168 for type, data in dagparser.parsedag(text):
171 for type, data in dagparser.parsedag(text):
169 if type == 'n':
172 if type == 'n':
170 ui.note(('node %s\n' % str(data)))
173 ui.note(('node %s\n' % str(data)))
171 id, ps = data
174 id, ps = data
172
175
173 files = []
176 files = []
174 fctxs = {}
177 fctxs = {}
175
178
176 p2 = None
179 p2 = None
177 if mergeable_file:
180 if mergeable_file:
178 fn = "mf"
181 fn = "mf"
179 p1 = repo[ps[0]]
182 p1 = repo[ps[0]]
180 if len(ps) > 1:
183 if len(ps) > 1:
181 p2 = repo[ps[1]]
184 p2 = repo[ps[1]]
182 pa = p1.ancestor(p2)
185 pa = p1.ancestor(p2)
183 base, local, other = [x[fn].data() for x in (pa, p1,
186 base, local, other = [x[fn].data() for x in (pa, p1,
184 p2)]
187 p2)]
185 m3 = simplemerge.Merge3Text(base, local, other)
188 m3 = simplemerge.Merge3Text(base, local, other)
186 ml = [l.strip() for l in m3.merge_lines()]
189 ml = [l.strip() for l in m3.merge_lines()]
187 ml.append("")
190 ml.append("")
188 elif at > 0:
191 elif at > 0:
189 ml = p1[fn].data().split("\n")
192 ml = p1[fn].data().split("\n")
190 else:
193 else:
191 ml = initialmergedlines
194 ml = initialmergedlines
192 ml[id * linesperrev] += " r%i" % id
195 ml[id * linesperrev] += " r%i" % id
193 mergedtext = "\n".join(ml)
196 mergedtext = "\n".join(ml)
194 files.append(fn)
197 files.append(fn)
195 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
198 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
196
199
197 if overwritten_file:
200 if overwritten_file:
198 fn = "of"
201 fn = "of"
199 files.append(fn)
202 files.append(fn)
200 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
203 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
201
204
202 if new_file:
205 if new_file:
203 fn = "nf%i" % id
206 fn = "nf%i" % id
204 files.append(fn)
207 files.append(fn)
205 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
208 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
206 if len(ps) > 1:
209 if len(ps) > 1:
207 if not p2:
210 if not p2:
208 p2 = repo[ps[1]]
211 p2 = repo[ps[1]]
209 for fn in p2:
212 for fn in p2:
210 if fn.startswith("nf"):
213 if fn.startswith("nf"):
211 files.append(fn)
214 files.append(fn)
212 fctxs[fn] = p2[fn]
215 fctxs[fn] = p2[fn]
213
216
214 def fctxfn(repo, cx, path):
217 def fctxfn(repo, cx, path):
215 return fctxs.get(path)
218 return fctxs.get(path)
216
219
217 if len(ps) == 0 or ps[0] < 0:
220 if len(ps) == 0 or ps[0] < 0:
218 pars = [None, None]
221 pars = [None, None]
219 elif len(ps) == 1:
222 elif len(ps) == 1:
220 pars = [nodeids[ps[0]], None]
223 pars = [nodeids[ps[0]], None]
221 else:
224 else:
222 pars = [nodeids[p] for p in ps]
225 pars = [nodeids[p] for p in ps]
223 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
226 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
224 date=(id, 0),
227 date=(id, 0),
225 user="debugbuilddag",
228 user="debugbuilddag",
226 extra={'branch': atbranch})
229 extra={'branch': atbranch})
227 nodeid = repo.commitctx(cx)
230 nodeid = repo.commitctx(cx)
228 nodeids.append(nodeid)
231 nodeids.append(nodeid)
229 at = id
232 at = id
230 elif type == 'l':
233 elif type == 'l':
231 id, name = data
234 id, name = data
232 ui.note(('tag %s\n' % name))
235 ui.note(('tag %s\n' % name))
233 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
236 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
234 elif type == 'a':
237 elif type == 'a':
235 ui.note(('branch %s\n' % data))
238 ui.note(('branch %s\n' % data))
236 atbranch = data
239 atbranch = data
237 ui.progress(_('building'), id, unit=_('revisions'), total=total)
240 ui.progress(_('building'), id, unit=_('revisions'), total=total)
238 tr.close()
241 tr.close()
239
242
240 if tags:
243 if tags:
241 repo.vfs.write("localtags", "".join(tags))
244 repo.vfs.write("localtags", "".join(tags))
242 finally:
245 finally:
243 ui.progress(_('building'), None)
246 ui.progress(_('building'), None)
244 release(tr, lock, wlock)
247 release(tr, lock, wlock)
245
248
246 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
249 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
247 indent_string = ' ' * indent
250 indent_string = ' ' * indent
248 if all:
251 if all:
249 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
252 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
250 % indent_string)
253 % indent_string)
251
254
252 def showchunks(named):
255 def showchunks(named):
253 ui.write("\n%s%s\n" % (indent_string, named))
256 ui.write("\n%s%s\n" % (indent_string, named))
254 chain = None
257 chain = None
255 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
258 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
256 node = chunkdata['node']
259 node = chunkdata['node']
257 p1 = chunkdata['p1']
260 p1 = chunkdata['p1']
258 p2 = chunkdata['p2']
261 p2 = chunkdata['p2']
259 cs = chunkdata['cs']
262 cs = chunkdata['cs']
260 deltabase = chunkdata['deltabase']
263 deltabase = chunkdata['deltabase']
261 delta = chunkdata['delta']
264 delta = chunkdata['delta']
262 ui.write("%s%s %s %s %s %s %s\n" %
265 ui.write("%s%s %s %s %s %s %s\n" %
263 (indent_string, hex(node), hex(p1), hex(p2),
266 (indent_string, hex(node), hex(p1), hex(p2),
264 hex(cs), hex(deltabase), len(delta)))
267 hex(cs), hex(deltabase), len(delta)))
265 chain = node
268 chain = node
266
269
267 chunkdata = gen.changelogheader()
270 chunkdata = gen.changelogheader()
268 showchunks("changelog")
271 showchunks("changelog")
269 chunkdata = gen.manifestheader()
272 chunkdata = gen.manifestheader()
270 showchunks("manifest")
273 showchunks("manifest")
271 for chunkdata in iter(gen.filelogheader, {}):
274 for chunkdata in iter(gen.filelogheader, {}):
272 fname = chunkdata['filename']
275 fname = chunkdata['filename']
273 showchunks(fname)
276 showchunks(fname)
274 else:
277 else:
275 if isinstance(gen, bundle2.unbundle20):
278 if isinstance(gen, bundle2.unbundle20):
276 raise error.Abort(_('use debugbundle2 for this file'))
279 raise error.Abort(_('use debugbundle2 for this file'))
277 chunkdata = gen.changelogheader()
280 chunkdata = gen.changelogheader()
278 chain = None
281 chain = None
279 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
282 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
280 node = chunkdata['node']
283 node = chunkdata['node']
281 ui.write("%s%s\n" % (indent_string, hex(node)))
284 ui.write("%s%s\n" % (indent_string, hex(node)))
282 chain = node
285 chain = node
283
286
284 def _debugbundle2(ui, gen, all=None, **opts):
287 def _debugbundle2(ui, gen, all=None, **opts):
285 """lists the contents of a bundle2"""
288 """lists the contents of a bundle2"""
286 if not isinstance(gen, bundle2.unbundle20):
289 if not isinstance(gen, bundle2.unbundle20):
287 raise error.Abort(_('not a bundle2 file'))
290 raise error.Abort(_('not a bundle2 file'))
288 ui.write(('Stream params: %s\n' % repr(gen.params)))
291 ui.write(('Stream params: %s\n' % repr(gen.params)))
289 for part in gen.iterparts():
292 for part in gen.iterparts():
290 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
293 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
291 if part.type == 'changegroup':
294 if part.type == 'changegroup':
292 version = part.params.get('version', '01')
295 version = part.params.get('version', '01')
293 cg = changegroup.getunbundler(version, part, 'UN')
296 cg = changegroup.getunbundler(version, part, 'UN')
294 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
297 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
295
298
296 @command('debugbundle',
299 @command('debugbundle',
297 [('a', 'all', None, _('show all details')),
300 [('a', 'all', None, _('show all details')),
298 ('', 'spec', None, _('print the bundlespec of the bundle'))],
301 ('', 'spec', None, _('print the bundlespec of the bundle'))],
299 _('FILE'),
302 _('FILE'),
300 norepo=True)
303 norepo=True)
301 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
304 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
302 """lists the contents of a bundle"""
305 """lists the contents of a bundle"""
303 with hg.openpath(ui, bundlepath) as f:
306 with hg.openpath(ui, bundlepath) as f:
304 if spec:
307 if spec:
305 spec = exchange.getbundlespec(ui, f)
308 spec = exchange.getbundlespec(ui, f)
306 ui.write('%s\n' % spec)
309 ui.write('%s\n' % spec)
307 return
310 return
308
311
309 gen = exchange.readbundle(ui, f, bundlepath)
312 gen = exchange.readbundle(ui, f, bundlepath)
310 if isinstance(gen, bundle2.unbundle20):
313 if isinstance(gen, bundle2.unbundle20):
311 return _debugbundle2(ui, gen, all=all, **opts)
314 return _debugbundle2(ui, gen, all=all, **opts)
312 _debugchangegroup(ui, gen, all=all, **opts)
315 _debugchangegroup(ui, gen, all=all, **opts)
313
316
314 @command('debugcheckstate', [], '')
317 @command('debugcheckstate', [], '')
315 def debugcheckstate(ui, repo):
318 def debugcheckstate(ui, repo):
316 """validate the correctness of the current dirstate"""
319 """validate the correctness of the current dirstate"""
317 parent1, parent2 = repo.dirstate.parents()
320 parent1, parent2 = repo.dirstate.parents()
318 m1 = repo[parent1].manifest()
321 m1 = repo[parent1].manifest()
319 m2 = repo[parent2].manifest()
322 m2 = repo[parent2].manifest()
320 errors = 0
323 errors = 0
321 for f in repo.dirstate:
324 for f in repo.dirstate:
322 state = repo.dirstate[f]
325 state = repo.dirstate[f]
323 if state in "nr" and f not in m1:
326 if state in "nr" and f not in m1:
324 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
327 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
325 errors += 1
328 errors += 1
326 if state in "a" and f in m1:
329 if state in "a" and f in m1:
327 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
330 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
328 errors += 1
331 errors += 1
329 if state in "m" and f not in m1 and f not in m2:
332 if state in "m" and f not in m1 and f not in m2:
330 ui.warn(_("%s in state %s, but not in either manifest\n") %
333 ui.warn(_("%s in state %s, but not in either manifest\n") %
331 (f, state))
334 (f, state))
332 errors += 1
335 errors += 1
333 for f in m1:
336 for f in m1:
334 state = repo.dirstate[f]
337 state = repo.dirstate[f]
335 if state not in "nrm":
338 if state not in "nrm":
336 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
339 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
337 errors += 1
340 errors += 1
338 if errors:
341 if errors:
339 error = _(".hg/dirstate inconsistent with current parent's manifest")
342 error = _(".hg/dirstate inconsistent with current parent's manifest")
340 raise error.Abort(error)
343 raise error.Abort(error)
341
344
342 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
345 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
343 def debugcommands(ui, cmd='', *args):
346 def debugcommands(ui, cmd='', *args):
344 """list all available commands and options"""
347 """list all available commands and options"""
345 for cmd, vals in sorted(commands.table.iteritems()):
348 for cmd, vals in sorted(commands.table.iteritems()):
346 cmd = cmd.split('|')[0].strip('^')
349 cmd = cmd.split('|')[0].strip('^')
347 opts = ', '.join([i[1] for i in vals[1]])
350 opts = ', '.join([i[1] for i in vals[1]])
348 ui.write('%s: %s\n' % (cmd, opts))
351 ui.write('%s: %s\n' % (cmd, opts))
349
352
350 @command('debugcomplete',
353 @command('debugcomplete',
351 [('o', 'options', None, _('show the command options'))],
354 [('o', 'options', None, _('show the command options'))],
352 _('[-o] CMD'),
355 _('[-o] CMD'),
353 norepo=True)
356 norepo=True)
354 def debugcomplete(ui, cmd='', **opts):
357 def debugcomplete(ui, cmd='', **opts):
355 """returns the completion list associated with the given command"""
358 """returns the completion list associated with the given command"""
356
359
357 if opts.get('options'):
360 if opts.get('options'):
358 options = []
361 options = []
359 otables = [commands.globalopts]
362 otables = [commands.globalopts]
360 if cmd:
363 if cmd:
361 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
364 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
362 otables.append(entry[1])
365 otables.append(entry[1])
363 for t in otables:
366 for t in otables:
364 for o in t:
367 for o in t:
365 if "(DEPRECATED)" in o[3]:
368 if "(DEPRECATED)" in o[3]:
366 continue
369 continue
367 if o[0]:
370 if o[0]:
368 options.append('-%s' % o[0])
371 options.append('-%s' % o[0])
369 options.append('--%s' % o[1])
372 options.append('--%s' % o[1])
370 ui.write("%s\n" % "\n".join(options))
373 ui.write("%s\n" % "\n".join(options))
371 return
374 return
372
375
373 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
376 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
374 if ui.verbose:
377 if ui.verbose:
375 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
378 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
376 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
379 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
377
380
378 @command('debugcreatestreamclonebundle', [], 'FILE')
381 @command('debugcreatestreamclonebundle', [], 'FILE')
379 def debugcreatestreamclonebundle(ui, repo, fname):
382 def debugcreatestreamclonebundle(ui, repo, fname):
380 """create a stream clone bundle file
383 """create a stream clone bundle file
381
384
382 Stream bundles are special bundles that are essentially archives of
385 Stream bundles are special bundles that are essentially archives of
383 revlog files. They are commonly used for cloning very quickly.
386 revlog files. They are commonly used for cloning very quickly.
384 """
387 """
385 requirements, gen = streamclone.generatebundlev1(repo)
388 requirements, gen = streamclone.generatebundlev1(repo)
386 changegroup.writechunks(ui, gen, fname)
389 changegroup.writechunks(ui, gen, fname)
387
390
388 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
391 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
389
392
390 @command('debugdag',
393 @command('debugdag',
391 [('t', 'tags', None, _('use tags as labels')),
394 [('t', 'tags', None, _('use tags as labels')),
392 ('b', 'branches', None, _('annotate with branch names')),
395 ('b', 'branches', None, _('annotate with branch names')),
393 ('', 'dots', None, _('use dots for runs')),
396 ('', 'dots', None, _('use dots for runs')),
394 ('s', 'spaces', None, _('separate elements by spaces'))],
397 ('s', 'spaces', None, _('separate elements by spaces'))],
395 _('[OPTION]... [FILE [REV]...]'),
398 _('[OPTION]... [FILE [REV]...]'),
396 optionalrepo=True)
399 optionalrepo=True)
397 def debugdag(ui, repo, file_=None, *revs, **opts):
400 def debugdag(ui, repo, file_=None, *revs, **opts):
398 """format the changelog or an index DAG as a concise textual description
401 """format the changelog or an index DAG as a concise textual description
399
402
400 If you pass a revlog index, the revlog's DAG is emitted. If you list
403 If you pass a revlog index, the revlog's DAG is emitted. If you list
401 revision numbers, they get labeled in the output as rN.
404 revision numbers, they get labeled in the output as rN.
402
405
403 Otherwise, the changelog DAG of the current repo is emitted.
406 Otherwise, the changelog DAG of the current repo is emitted.
404 """
407 """
405 spaces = opts.get('spaces')
408 spaces = opts.get('spaces')
406 dots = opts.get('dots')
409 dots = opts.get('dots')
407 if file_:
410 if file_:
408 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
411 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
409 file_)
412 file_)
410 revs = set((int(r) for r in revs))
413 revs = set((int(r) for r in revs))
411 def events():
414 def events():
412 for r in rlog:
415 for r in rlog:
413 yield 'n', (r, list(p for p in rlog.parentrevs(r)
416 yield 'n', (r, list(p for p in rlog.parentrevs(r)
414 if p != -1))
417 if p != -1))
415 if r in revs:
418 if r in revs:
416 yield 'l', (r, "r%i" % r)
419 yield 'l', (r, "r%i" % r)
417 elif repo:
420 elif repo:
418 cl = repo.changelog
421 cl = repo.changelog
419 tags = opts.get('tags')
422 tags = opts.get('tags')
420 branches = opts.get('branches')
423 branches = opts.get('branches')
421 if tags:
424 if tags:
422 labels = {}
425 labels = {}
423 for l, n in repo.tags().items():
426 for l, n in repo.tags().items():
424 labels.setdefault(cl.rev(n), []).append(l)
427 labels.setdefault(cl.rev(n), []).append(l)
425 def events():
428 def events():
426 b = "default"
429 b = "default"
427 for r in cl:
430 for r in cl:
428 if branches:
431 if branches:
429 newb = cl.read(cl.node(r))[5]['branch']
432 newb = cl.read(cl.node(r))[5]['branch']
430 if newb != b:
433 if newb != b:
431 yield 'a', newb
434 yield 'a', newb
432 b = newb
435 b = newb
433 yield 'n', (r, list(p for p in cl.parentrevs(r)
436 yield 'n', (r, list(p for p in cl.parentrevs(r)
434 if p != -1))
437 if p != -1))
435 if tags:
438 if tags:
436 ls = labels.get(r)
439 ls = labels.get(r)
437 if ls:
440 if ls:
438 for l in ls:
441 for l in ls:
439 yield 'l', (r, l)
442 yield 'l', (r, l)
440 else:
443 else:
441 raise error.Abort(_('need repo for changelog dag'))
444 raise error.Abort(_('need repo for changelog dag'))
442
445
443 for line in dagparser.dagtextlines(events(),
446 for line in dagparser.dagtextlines(events(),
444 addspaces=spaces,
447 addspaces=spaces,
445 wraplabels=True,
448 wraplabels=True,
446 wrapannotations=True,
449 wrapannotations=True,
447 wrapnonlinear=dots,
450 wrapnonlinear=dots,
448 usedots=dots,
451 usedots=dots,
449 maxlinewidth=70):
452 maxlinewidth=70):
450 ui.write(line)
453 ui.write(line)
451 ui.write("\n")
454 ui.write("\n")
452
455
453 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
456 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
454 def debugdata(ui, repo, file_, rev=None, **opts):
457 def debugdata(ui, repo, file_, rev=None, **opts):
455 """dump the contents of a data file revision"""
458 """dump the contents of a data file revision"""
456 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
459 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
457 if rev is not None:
460 if rev is not None:
458 raise error.CommandError('debugdata', _('invalid arguments'))
461 raise error.CommandError('debugdata', _('invalid arguments'))
459 file_, rev = None, file_
462 file_, rev = None, file_
460 elif rev is None:
463 elif rev is None:
461 raise error.CommandError('debugdata', _('invalid arguments'))
464 raise error.CommandError('debugdata', _('invalid arguments'))
462 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
465 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
463 try:
466 try:
464 ui.write(r.revision(r.lookup(rev), raw=True))
467 ui.write(r.revision(r.lookup(rev), raw=True))
465 except KeyError:
468 except KeyError:
466 raise error.Abort(_('invalid revision identifier %s') % rev)
469 raise error.Abort(_('invalid revision identifier %s') % rev)
467
470
468 @command('debugdate',
471 @command('debugdate',
469 [('e', 'extended', None, _('try extended date formats'))],
472 [('e', 'extended', None, _('try extended date formats'))],
470 _('[-e] DATE [RANGE]'),
473 _('[-e] DATE [RANGE]'),
471 norepo=True, optionalrepo=True)
474 norepo=True, optionalrepo=True)
472 def debugdate(ui, date, range=None, **opts):
475 def debugdate(ui, date, range=None, **opts):
473 """parse and display a date"""
476 """parse and display a date"""
474 if opts["extended"]:
477 if opts["extended"]:
475 d = util.parsedate(date, util.extendeddateformats)
478 d = util.parsedate(date, util.extendeddateformats)
476 else:
479 else:
477 d = util.parsedate(date)
480 d = util.parsedate(date)
478 ui.write(("internal: %s %s\n") % d)
481 ui.write(("internal: %s %s\n") % d)
479 ui.write(("standard: %s\n") % util.datestr(d))
482 ui.write(("standard: %s\n") % util.datestr(d))
480 if range:
483 if range:
481 m = util.matchdate(range)
484 m = util.matchdate(range)
482 ui.write(("match: %s\n") % m(d[0]))
485 ui.write(("match: %s\n") % m(d[0]))
483
486
484 @command('debugdeltachain',
487 @command('debugdeltachain',
485 commands.debugrevlogopts + commands.formatteropts,
488 commands.debugrevlogopts + commands.formatteropts,
486 _('-c|-m|FILE'),
489 _('-c|-m|FILE'),
487 optionalrepo=True)
490 optionalrepo=True)
488 def debugdeltachain(ui, repo, file_=None, **opts):
491 def debugdeltachain(ui, repo, file_=None, **opts):
489 """dump information about delta chains in a revlog
492 """dump information about delta chains in a revlog
490
493
491 Output can be templatized. Available template keywords are:
494 Output can be templatized. Available template keywords are:
492
495
493 :``rev``: revision number
496 :``rev``: revision number
494 :``chainid``: delta chain identifier (numbered by unique base)
497 :``chainid``: delta chain identifier (numbered by unique base)
495 :``chainlen``: delta chain length to this revision
498 :``chainlen``: delta chain length to this revision
496 :``prevrev``: previous revision in delta chain
499 :``prevrev``: previous revision in delta chain
497 :``deltatype``: role of delta / how it was computed
500 :``deltatype``: role of delta / how it was computed
498 :``compsize``: compressed size of revision
501 :``compsize``: compressed size of revision
499 :``uncompsize``: uncompressed size of revision
502 :``uncompsize``: uncompressed size of revision
500 :``chainsize``: total size of compressed revisions in chain
503 :``chainsize``: total size of compressed revisions in chain
501 :``chainratio``: total chain size divided by uncompressed revision size
504 :``chainratio``: total chain size divided by uncompressed revision size
502 (new delta chains typically start at ratio 2.00)
505 (new delta chains typically start at ratio 2.00)
503 :``lindist``: linear distance from base revision in delta chain to end
506 :``lindist``: linear distance from base revision in delta chain to end
504 of this revision
507 of this revision
505 :``extradist``: total size of revisions not part of this delta chain from
508 :``extradist``: total size of revisions not part of this delta chain from
506 base of delta chain to end of this revision; a measurement
509 base of delta chain to end of this revision; a measurement
507 of how much extra data we need to read/seek across to read
510 of how much extra data we need to read/seek across to read
508 the delta chain for this revision
511 the delta chain for this revision
509 :``extraratio``: extradist divided by chainsize; another representation of
512 :``extraratio``: extradist divided by chainsize; another representation of
510 how much unrelated data is needed to load this delta chain
513 how much unrelated data is needed to load this delta chain
511 """
514 """
512 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
515 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
513 index = r.index
516 index = r.index
514 generaldelta = r.version & revlog.REVLOGGENERALDELTA
517 generaldelta = r.version & revlog.REVLOGGENERALDELTA
515
518
516 def revinfo(rev):
519 def revinfo(rev):
517 e = index[rev]
520 e = index[rev]
518 compsize = e[1]
521 compsize = e[1]
519 uncompsize = e[2]
522 uncompsize = e[2]
520 chainsize = 0
523 chainsize = 0
521
524
522 if generaldelta:
525 if generaldelta:
523 if e[3] == e[5]:
526 if e[3] == e[5]:
524 deltatype = 'p1'
527 deltatype = 'p1'
525 elif e[3] == e[6]:
528 elif e[3] == e[6]:
526 deltatype = 'p2'
529 deltatype = 'p2'
527 elif e[3] == rev - 1:
530 elif e[3] == rev - 1:
528 deltatype = 'prev'
531 deltatype = 'prev'
529 elif e[3] == rev:
532 elif e[3] == rev:
530 deltatype = 'base'
533 deltatype = 'base'
531 else:
534 else:
532 deltatype = 'other'
535 deltatype = 'other'
533 else:
536 else:
534 if e[3] == rev:
537 if e[3] == rev:
535 deltatype = 'base'
538 deltatype = 'base'
536 else:
539 else:
537 deltatype = 'prev'
540 deltatype = 'prev'
538
541
539 chain = r._deltachain(rev)[0]
542 chain = r._deltachain(rev)[0]
540 for iterrev in chain:
543 for iterrev in chain:
541 e = index[iterrev]
544 e = index[iterrev]
542 chainsize += e[1]
545 chainsize += e[1]
543
546
544 return compsize, uncompsize, deltatype, chain, chainsize
547 return compsize, uncompsize, deltatype, chain, chainsize
545
548
546 fm = ui.formatter('debugdeltachain', opts)
549 fm = ui.formatter('debugdeltachain', opts)
547
550
548 fm.plain(' rev chain# chainlen prev delta '
551 fm.plain(' rev chain# chainlen prev delta '
549 'size rawsize chainsize ratio lindist extradist '
552 'size rawsize chainsize ratio lindist extradist '
550 'extraratio\n')
553 'extraratio\n')
551
554
552 chainbases = {}
555 chainbases = {}
553 for rev in r:
556 for rev in r:
554 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
557 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
555 chainbase = chain[0]
558 chainbase = chain[0]
556 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
559 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
557 basestart = r.start(chainbase)
560 basestart = r.start(chainbase)
558 revstart = r.start(rev)
561 revstart = r.start(rev)
559 lineardist = revstart + comp - basestart
562 lineardist = revstart + comp - basestart
560 extradist = lineardist - chainsize
563 extradist = lineardist - chainsize
561 try:
564 try:
562 prevrev = chain[-2]
565 prevrev = chain[-2]
563 except IndexError:
566 except IndexError:
564 prevrev = -1
567 prevrev = -1
565
568
566 chainratio = float(chainsize) / float(uncomp)
569 chainratio = float(chainsize) / float(uncomp)
567 extraratio = float(extradist) / float(chainsize)
570 extraratio = float(extradist) / float(chainsize)
568
571
569 fm.startitem()
572 fm.startitem()
570 fm.write('rev chainid chainlen prevrev deltatype compsize '
573 fm.write('rev chainid chainlen prevrev deltatype compsize '
571 'uncompsize chainsize chainratio lindist extradist '
574 'uncompsize chainsize chainratio lindist extradist '
572 'extraratio',
575 'extraratio',
573 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
576 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
574 rev, chainid, len(chain), prevrev, deltatype, comp,
577 rev, chainid, len(chain), prevrev, deltatype, comp,
575 uncomp, chainsize, chainratio, lineardist, extradist,
578 uncomp, chainsize, chainratio, lineardist, extradist,
576 extraratio,
579 extraratio,
577 rev=rev, chainid=chainid, chainlen=len(chain),
580 rev=rev, chainid=chainid, chainlen=len(chain),
578 prevrev=prevrev, deltatype=deltatype, compsize=comp,
581 prevrev=prevrev, deltatype=deltatype, compsize=comp,
579 uncompsize=uncomp, chainsize=chainsize,
582 uncompsize=uncomp, chainsize=chainsize,
580 chainratio=chainratio, lindist=lineardist,
583 chainratio=chainratio, lindist=lineardist,
581 extradist=extradist, extraratio=extraratio)
584 extradist=extradist, extraratio=extraratio)
582
585
583 fm.end()
586 fm.end()
584
587
585 @command('debugdiscovery',
588 @command('debugdiscovery',
586 [('', 'old', None, _('use old-style discovery')),
589 [('', 'old', None, _('use old-style discovery')),
587 ('', 'nonheads', None,
590 ('', 'nonheads', None,
588 _('use old-style discovery with non-heads included')),
591 _('use old-style discovery with non-heads included')),
589 ] + commands.remoteopts,
592 ] + commands.remoteopts,
590 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
593 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
591 def debugdiscovery(ui, repo, remoteurl="default", **opts):
594 def debugdiscovery(ui, repo, remoteurl="default", **opts):
592 """runs the changeset discovery protocol in isolation"""
595 """runs the changeset discovery protocol in isolation"""
593 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
596 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
594 opts.get('branch'))
597 opts.get('branch'))
595 remote = hg.peer(repo, opts, remoteurl)
598 remote = hg.peer(repo, opts, remoteurl)
596 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
599 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
597
600
598 # make sure tests are repeatable
601 # make sure tests are repeatable
599 random.seed(12323)
602 random.seed(12323)
600
603
601 def doit(localheads, remoteheads, remote=remote):
604 def doit(localheads, remoteheads, remote=remote):
602 if opts.get('old'):
605 if opts.get('old'):
603 if localheads:
606 if localheads:
604 raise error.Abort('cannot use localheads with old style '
607 raise error.Abort('cannot use localheads with old style '
605 'discovery')
608 'discovery')
606 if not util.safehasattr(remote, 'branches'):
609 if not util.safehasattr(remote, 'branches'):
607 # enable in-client legacy support
610 # enable in-client legacy support
608 remote = localrepo.locallegacypeer(remote.local())
611 remote = localrepo.locallegacypeer(remote.local())
609 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
612 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
610 force=True)
613 force=True)
611 common = set(common)
614 common = set(common)
612 if not opts.get('nonheads'):
615 if not opts.get('nonheads'):
613 ui.write(("unpruned common: %s\n") %
616 ui.write(("unpruned common: %s\n") %
614 " ".join(sorted(short(n) for n in common)))
617 " ".join(sorted(short(n) for n in common)))
615 dag = dagutil.revlogdag(repo.changelog)
618 dag = dagutil.revlogdag(repo.changelog)
616 all = dag.ancestorset(dag.internalizeall(common))
619 all = dag.ancestorset(dag.internalizeall(common))
617 common = dag.externalizeall(dag.headsetofconnecteds(all))
620 common = dag.externalizeall(dag.headsetofconnecteds(all))
618 else:
621 else:
619 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
622 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
620 common = set(common)
623 common = set(common)
621 rheads = set(hds)
624 rheads = set(hds)
622 lheads = set(repo.heads())
625 lheads = set(repo.heads())
623 ui.write(("common heads: %s\n") %
626 ui.write(("common heads: %s\n") %
624 " ".join(sorted(short(n) for n in common)))
627 " ".join(sorted(short(n) for n in common)))
625 if lheads <= common:
628 if lheads <= common:
626 ui.write(("local is subset\n"))
629 ui.write(("local is subset\n"))
627 elif rheads <= common:
630 elif rheads <= common:
628 ui.write(("remote is subset\n"))
631 ui.write(("remote is subset\n"))
629
632
630 serverlogs = opts.get('serverlog')
633 serverlogs = opts.get('serverlog')
631 if serverlogs:
634 if serverlogs:
632 for filename in serverlogs:
635 for filename in serverlogs:
633 with open(filename, 'r') as logfile:
636 with open(filename, 'r') as logfile:
634 line = logfile.readline()
637 line = logfile.readline()
635 while line:
638 while line:
636 parts = line.strip().split(';')
639 parts = line.strip().split(';')
637 op = parts[1]
640 op = parts[1]
638 if op == 'cg':
641 if op == 'cg':
639 pass
642 pass
640 elif op == 'cgss':
643 elif op == 'cgss':
641 doit(parts[2].split(' '), parts[3].split(' '))
644 doit(parts[2].split(' '), parts[3].split(' '))
642 elif op == 'unb':
645 elif op == 'unb':
643 doit(parts[3].split(' '), parts[2].split(' '))
646 doit(parts[3].split(' '), parts[2].split(' '))
644 line = logfile.readline()
647 line = logfile.readline()
645 else:
648 else:
646 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
649 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
647 opts.get('remote_head'))
650 opts.get('remote_head'))
648 localrevs = opts.get('local_head')
651 localrevs = opts.get('local_head')
649 doit(localrevs, remoterevs)
652 doit(localrevs, remoterevs)
650
653
651 @command('debugextensions', commands.formatteropts, [], norepo=True)
654 @command('debugextensions', commands.formatteropts, [], norepo=True)
652 def debugextensions(ui, **opts):
655 def debugextensions(ui, **opts):
653 '''show information about active extensions'''
656 '''show information about active extensions'''
654 exts = extensions.extensions(ui)
657 exts = extensions.extensions(ui)
655 hgver = util.version()
658 hgver = util.version()
656 fm = ui.formatter('debugextensions', opts)
659 fm = ui.formatter('debugextensions', opts)
657 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
660 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
658 isinternal = extensions.ismoduleinternal(extmod)
661 isinternal = extensions.ismoduleinternal(extmod)
659 extsource = extmod.__file__
662 extsource = extmod.__file__
660 if isinternal:
663 if isinternal:
661 exttestedwith = [] # never expose magic string to users
664 exttestedwith = [] # never expose magic string to users
662 else:
665 else:
663 exttestedwith = getattr(extmod, 'testedwith', '').split()
666 exttestedwith = getattr(extmod, 'testedwith', '').split()
664 extbuglink = getattr(extmod, 'buglink', None)
667 extbuglink = getattr(extmod, 'buglink', None)
665
668
666 fm.startitem()
669 fm.startitem()
667
670
668 if ui.quiet or ui.verbose:
671 if ui.quiet or ui.verbose:
669 fm.write('name', '%s\n', extname)
672 fm.write('name', '%s\n', extname)
670 else:
673 else:
671 fm.write('name', '%s', extname)
674 fm.write('name', '%s', extname)
672 if isinternal or hgver in exttestedwith:
675 if isinternal or hgver in exttestedwith:
673 fm.plain('\n')
676 fm.plain('\n')
674 elif not exttestedwith:
677 elif not exttestedwith:
675 fm.plain(_(' (untested!)\n'))
678 fm.plain(_(' (untested!)\n'))
676 else:
679 else:
677 lasttestedversion = exttestedwith[-1]
680 lasttestedversion = exttestedwith[-1]
678 fm.plain(' (%s!)\n' % lasttestedversion)
681 fm.plain(' (%s!)\n' % lasttestedversion)
679
682
680 fm.condwrite(ui.verbose and extsource, 'source',
683 fm.condwrite(ui.verbose and extsource, 'source',
681 _(' location: %s\n'), extsource or "")
684 _(' location: %s\n'), extsource or "")
682
685
683 if ui.verbose:
686 if ui.verbose:
684 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
687 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
685 fm.data(bundled=isinternal)
688 fm.data(bundled=isinternal)
686
689
687 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
690 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
688 _(' tested with: %s\n'),
691 _(' tested with: %s\n'),
689 fm.formatlist(exttestedwith, name='ver'))
692 fm.formatlist(exttestedwith, name='ver'))
690
693
691 fm.condwrite(ui.verbose and extbuglink, 'buglink',
694 fm.condwrite(ui.verbose and extbuglink, 'buglink',
692 _(' bug reporting: %s\n'), extbuglink or "")
695 _(' bug reporting: %s\n'), extbuglink or "")
693
696
694 fm.end()
697 fm.end()
695
698
696 @command('debugfileset',
699 @command('debugfileset',
697 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
700 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
698 _('[-r REV] FILESPEC'))
701 _('[-r REV] FILESPEC'))
699 def debugfileset(ui, repo, expr, **opts):
702 def debugfileset(ui, repo, expr, **opts):
700 '''parse and apply a fileset specification'''
703 '''parse and apply a fileset specification'''
701 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
704 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
702 if ui.verbose:
705 if ui.verbose:
703 tree = fileset.parse(expr)
706 tree = fileset.parse(expr)
704 ui.note(fileset.prettyformat(tree), "\n")
707 ui.note(fileset.prettyformat(tree), "\n")
705
708
706 for f in ctx.getfileset(expr):
709 for f in ctx.getfileset(expr):
707 ui.write("%s\n" % f)
710 ui.write("%s\n" % f)
708
711
709 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
712 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
710 def debugfsinfo(ui, path="."):
713 def debugfsinfo(ui, path="."):
711 """show information detected about current filesystem"""
714 """show information detected about current filesystem"""
712 util.writefile('.debugfsinfo', '')
715 util.writefile('.debugfsinfo', '')
713 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
716 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
714 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
717 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
715 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
718 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
716 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
719 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
717 and 'yes' or 'no'))
720 and 'yes' or 'no'))
718 os.unlink('.debugfsinfo')
721 os.unlink('.debugfsinfo')
719
722
720 @command('debuggetbundle',
723 @command('debuggetbundle',
721 [('H', 'head', [], _('id of head node'), _('ID')),
724 [('H', 'head', [], _('id of head node'), _('ID')),
722 ('C', 'common', [], _('id of common node'), _('ID')),
725 ('C', 'common', [], _('id of common node'), _('ID')),
723 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
726 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
724 _('REPO FILE [-H|-C ID]...'),
727 _('REPO FILE [-H|-C ID]...'),
725 norepo=True)
728 norepo=True)
726 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
729 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
727 """retrieves a bundle from a repo
730 """retrieves a bundle from a repo
728
731
729 Every ID must be a full-length hex node id string. Saves the bundle to the
732 Every ID must be a full-length hex node id string. Saves the bundle to the
730 given file.
733 given file.
731 """
734 """
732 repo = hg.peer(ui, opts, repopath)
735 repo = hg.peer(ui, opts, repopath)
733 if not repo.capable('getbundle'):
736 if not repo.capable('getbundle'):
734 raise error.Abort("getbundle() not supported by target repository")
737 raise error.Abort("getbundle() not supported by target repository")
735 args = {}
738 args = {}
736 if common:
739 if common:
737 args['common'] = [bin(s) for s in common]
740 args['common'] = [bin(s) for s in common]
738 if head:
741 if head:
739 args['heads'] = [bin(s) for s in head]
742 args['heads'] = [bin(s) for s in head]
740 # TODO: get desired bundlecaps from command line.
743 # TODO: get desired bundlecaps from command line.
741 args['bundlecaps'] = None
744 args['bundlecaps'] = None
742 bundle = repo.getbundle('debug', **args)
745 bundle = repo.getbundle('debug', **args)
743
746
744 bundletype = opts.get('type', 'bzip2').lower()
747 bundletype = opts.get('type', 'bzip2').lower()
745 btypes = {'none': 'HG10UN',
748 btypes = {'none': 'HG10UN',
746 'bzip2': 'HG10BZ',
749 'bzip2': 'HG10BZ',
747 'gzip': 'HG10GZ',
750 'gzip': 'HG10GZ',
748 'bundle2': 'HG20'}
751 'bundle2': 'HG20'}
749 bundletype = btypes.get(bundletype)
752 bundletype = btypes.get(bundletype)
750 if bundletype not in bundle2.bundletypes:
753 if bundletype not in bundle2.bundletypes:
751 raise error.Abort(_('unknown bundle type specified with --type'))
754 raise error.Abort(_('unknown bundle type specified with --type'))
752 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
755 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
753
756
754 @command('debugignore', [], '[FILE]')
757 @command('debugignore', [], '[FILE]')
755 def debugignore(ui, repo, *files, **opts):
758 def debugignore(ui, repo, *files, **opts):
756 """display the combined ignore pattern and information about ignored files
759 """display the combined ignore pattern and information about ignored files
757
760
758 With no argument display the combined ignore pattern.
761 With no argument display the combined ignore pattern.
759
762
760 Given space separated file names, shows if the given file is ignored and
763 Given space separated file names, shows if the given file is ignored and
761 if so, show the ignore rule (file and line number) that matched it.
764 if so, show the ignore rule (file and line number) that matched it.
762 """
765 """
763 ignore = repo.dirstate._ignore
766 ignore = repo.dirstate._ignore
764 if not files:
767 if not files:
765 # Show all the patterns
768 # Show all the patterns
766 includepat = getattr(ignore, 'includepat', None)
769 includepat = getattr(ignore, 'includepat', None)
767 if includepat is not None:
770 if includepat is not None:
768 ui.write("%s\n" % includepat)
771 ui.write("%s\n" % includepat)
769 else:
772 else:
770 raise error.Abort(_("no ignore patterns found"))
773 raise error.Abort(_("no ignore patterns found"))
771 else:
774 else:
772 for f in files:
775 for f in files:
773 nf = util.normpath(f)
776 nf = util.normpath(f)
774 ignored = None
777 ignored = None
775 ignoredata = None
778 ignoredata = None
776 if nf != '.':
779 if nf != '.':
777 if ignore(nf):
780 if ignore(nf):
778 ignored = nf
781 ignored = nf
779 ignoredata = repo.dirstate._ignorefileandline(nf)
782 ignoredata = repo.dirstate._ignorefileandline(nf)
780 else:
783 else:
781 for p in util.finddirs(nf):
784 for p in util.finddirs(nf):
782 if ignore(p):
785 if ignore(p):
783 ignored = p
786 ignored = p
784 ignoredata = repo.dirstate._ignorefileandline(p)
787 ignoredata = repo.dirstate._ignorefileandline(p)
785 break
788 break
786 if ignored:
789 if ignored:
787 if ignored == nf:
790 if ignored == nf:
788 ui.write(_("%s is ignored\n") % f)
791 ui.write(_("%s is ignored\n") % f)
789 else:
792 else:
790 ui.write(_("%s is ignored because of "
793 ui.write(_("%s is ignored because of "
791 "containing folder %s\n")
794 "containing folder %s\n")
792 % (f, ignored))
795 % (f, ignored))
793 ignorefile, lineno, line = ignoredata
796 ignorefile, lineno, line = ignoredata
794 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
797 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
795 % (ignorefile, lineno, line))
798 % (ignorefile, lineno, line))
796 else:
799 else:
797 ui.write(_("%s is not ignored\n") % f)
800 ui.write(_("%s is not ignored\n") % f)
798
801
799 @command('debugindex', commands.debugrevlogopts +
802 @command('debugindex', commands.debugrevlogopts +
800 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
803 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
801 _('[-f FORMAT] -c|-m|FILE'),
804 _('[-f FORMAT] -c|-m|FILE'),
802 optionalrepo=True)
805 optionalrepo=True)
803 def debugindex(ui, repo, file_=None, **opts):
806 def debugindex(ui, repo, file_=None, **opts):
804 """dump the contents of an index file"""
807 """dump the contents of an index file"""
805 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
808 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
806 format = opts.get('format', 0)
809 format = opts.get('format', 0)
807 if format not in (0, 1):
810 if format not in (0, 1):
808 raise error.Abort(_("unknown format %d") % format)
811 raise error.Abort(_("unknown format %d") % format)
809
812
810 generaldelta = r.version & revlog.REVLOGGENERALDELTA
813 generaldelta = r.version & revlog.REVLOGGENERALDELTA
811 if generaldelta:
814 if generaldelta:
812 basehdr = ' delta'
815 basehdr = ' delta'
813 else:
816 else:
814 basehdr = ' base'
817 basehdr = ' base'
815
818
816 if ui.debugflag:
819 if ui.debugflag:
817 shortfn = hex
820 shortfn = hex
818 else:
821 else:
819 shortfn = short
822 shortfn = short
820
823
821 # There might not be anything in r, so have a sane default
824 # There might not be anything in r, so have a sane default
822 idlen = 12
825 idlen = 12
823 for i in r:
826 for i in r:
824 idlen = len(shortfn(r.node(i)))
827 idlen = len(shortfn(r.node(i)))
825 break
828 break
826
829
827 if format == 0:
830 if format == 0:
828 ui.write((" rev offset length " + basehdr + " linkrev"
831 ui.write((" rev offset length " + basehdr + " linkrev"
829 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
832 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
830 elif format == 1:
833 elif format == 1:
831 ui.write((" rev flag offset length"
834 ui.write((" rev flag offset length"
832 " size " + basehdr + " link p1 p2"
835 " size " + basehdr + " link p1 p2"
833 " %s\n") % "nodeid".rjust(idlen))
836 " %s\n") % "nodeid".rjust(idlen))
834
837
835 for i in r:
838 for i in r:
836 node = r.node(i)
839 node = r.node(i)
837 if generaldelta:
840 if generaldelta:
838 base = r.deltaparent(i)
841 base = r.deltaparent(i)
839 else:
842 else:
840 base = r.chainbase(i)
843 base = r.chainbase(i)
841 if format == 0:
844 if format == 0:
842 try:
845 try:
843 pp = r.parents(node)
846 pp = r.parents(node)
844 except Exception:
847 except Exception:
845 pp = [nullid, nullid]
848 pp = [nullid, nullid]
846 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
849 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
847 i, r.start(i), r.length(i), base, r.linkrev(i),
850 i, r.start(i), r.length(i), base, r.linkrev(i),
848 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
851 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
849 elif format == 1:
852 elif format == 1:
850 pr = r.parentrevs(i)
853 pr = r.parentrevs(i)
851 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
854 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
852 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
855 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
853 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
856 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
854
857
855 @command('debugindexdot', commands.debugrevlogopts,
858 @command('debugindexdot', commands.debugrevlogopts,
856 _('-c|-m|FILE'), optionalrepo=True)
859 _('-c|-m|FILE'), optionalrepo=True)
857 def debugindexdot(ui, repo, file_=None, **opts):
860 def debugindexdot(ui, repo, file_=None, **opts):
858 """dump an index DAG as a graphviz dot file"""
861 """dump an index DAG as a graphviz dot file"""
859 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
862 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
860 ui.write(("digraph G {\n"))
863 ui.write(("digraph G {\n"))
861 for i in r:
864 for i in r:
862 node = r.node(i)
865 node = r.node(i)
863 pp = r.parents(node)
866 pp = r.parents(node)
864 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
867 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
865 if pp[1] != nullid:
868 if pp[1] != nullid:
866 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
869 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
867 ui.write("}\n")
870 ui.write("}\n")
868
871
869 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
872 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
870 def debuginstall(ui, **opts):
873 def debuginstall(ui, **opts):
871 '''test Mercurial installation
874 '''test Mercurial installation
872
875
873 Returns 0 on success.
876 Returns 0 on success.
874 '''
877 '''
875
878
876 def writetemp(contents):
879 def writetemp(contents):
877 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
880 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
878 f = os.fdopen(fd, "wb")
881 f = os.fdopen(fd, "wb")
879 f.write(contents)
882 f.write(contents)
880 f.close()
883 f.close()
881 return name
884 return name
882
885
883 problems = 0
886 problems = 0
884
887
885 fm = ui.formatter('debuginstall', opts)
888 fm = ui.formatter('debuginstall', opts)
886 fm.startitem()
889 fm.startitem()
887
890
888 # encoding
891 # encoding
889 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
892 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
890 err = None
893 err = None
891 try:
894 try:
892 encoding.fromlocal("test")
895 encoding.fromlocal("test")
893 except error.Abort as inst:
896 except error.Abort as inst:
894 err = inst
897 err = inst
895 problems += 1
898 problems += 1
896 fm.condwrite(err, 'encodingerror', _(" %s\n"
899 fm.condwrite(err, 'encodingerror', _(" %s\n"
897 " (check that your locale is properly set)\n"), err)
900 " (check that your locale is properly set)\n"), err)
898
901
899 # Python
902 # Python
900 fm.write('pythonexe', _("checking Python executable (%s)\n"),
903 fm.write('pythonexe', _("checking Python executable (%s)\n"),
901 pycompat.sysexecutable)
904 pycompat.sysexecutable)
902 fm.write('pythonver', _("checking Python version (%s)\n"),
905 fm.write('pythonver', _("checking Python version (%s)\n"),
903 ("%d.%d.%d" % sys.version_info[:3]))
906 ("%d.%d.%d" % sys.version_info[:3]))
904 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
907 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
905 os.path.dirname(pycompat.fsencode(os.__file__)))
908 os.path.dirname(pycompat.fsencode(os.__file__)))
906
909
907 security = set(sslutil.supportedprotocols)
910 security = set(sslutil.supportedprotocols)
908 if sslutil.hassni:
911 if sslutil.hassni:
909 security.add('sni')
912 security.add('sni')
910
913
911 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
914 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
912 fm.formatlist(sorted(security), name='protocol',
915 fm.formatlist(sorted(security), name='protocol',
913 fmt='%s', sep=','))
916 fmt='%s', sep=','))
914
917
915 # These are warnings, not errors. So don't increment problem count. This
918 # These are warnings, not errors. So don't increment problem count. This
916 # may change in the future.
919 # may change in the future.
917 if 'tls1.2' not in security:
920 if 'tls1.2' not in security:
918 fm.plain(_(' TLS 1.2 not supported by Python install; '
921 fm.plain(_(' TLS 1.2 not supported by Python install; '
919 'network connections lack modern security\n'))
922 'network connections lack modern security\n'))
920 if 'sni' not in security:
923 if 'sni' not in security:
921 fm.plain(_(' SNI not supported by Python install; may have '
924 fm.plain(_(' SNI not supported by Python install; may have '
922 'connectivity issues with some servers\n'))
925 'connectivity issues with some servers\n'))
923
926
924 # TODO print CA cert info
927 # TODO print CA cert info
925
928
926 # hg version
929 # hg version
927 hgver = util.version()
930 hgver = util.version()
928 fm.write('hgver', _("checking Mercurial version (%s)\n"),
931 fm.write('hgver', _("checking Mercurial version (%s)\n"),
929 hgver.split('+')[0])
932 hgver.split('+')[0])
930 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
933 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
931 '+'.join(hgver.split('+')[1:]))
934 '+'.join(hgver.split('+')[1:]))
932
935
933 # compiled modules
936 # compiled modules
934 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
937 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
935 policy.policy)
938 policy.policy)
936 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
939 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
937 os.path.dirname(__file__))
940 os.path.dirname(__file__))
938
941
939 err = None
942 err = None
940 try:
943 try:
941 from . import (
944 from . import (
942 base85,
945 base85,
943 bdiff,
946 bdiff,
944 mpatch,
947 mpatch,
945 osutil,
948 osutil,
946 )
949 )
947 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
950 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
948 except Exception as inst:
951 except Exception as inst:
949 err = inst
952 err = inst
950 problems += 1
953 problems += 1
951 fm.condwrite(err, 'extensionserror', " %s\n", err)
954 fm.condwrite(err, 'extensionserror', " %s\n", err)
952
955
953 compengines = util.compengines._engines.values()
956 compengines = util.compengines._engines.values()
954 fm.write('compengines', _('checking registered compression engines (%s)\n'),
957 fm.write('compengines', _('checking registered compression engines (%s)\n'),
955 fm.formatlist(sorted(e.name() for e in compengines),
958 fm.formatlist(sorted(e.name() for e in compengines),
956 name='compengine', fmt='%s', sep=', '))
959 name='compengine', fmt='%s', sep=', '))
957 fm.write('compenginesavail', _('checking available compression engines '
960 fm.write('compenginesavail', _('checking available compression engines '
958 '(%s)\n'),
961 '(%s)\n'),
959 fm.formatlist(sorted(e.name() for e in compengines
962 fm.formatlist(sorted(e.name() for e in compengines
960 if e.available()),
963 if e.available()),
961 name='compengine', fmt='%s', sep=', '))
964 name='compengine', fmt='%s', sep=', '))
962 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
965 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
963 fm.write('compenginesserver', _('checking available compression engines '
966 fm.write('compenginesserver', _('checking available compression engines '
964 'for wire protocol (%s)\n'),
967 'for wire protocol (%s)\n'),
965 fm.formatlist([e.name() for e in wirecompengines
968 fm.formatlist([e.name() for e in wirecompengines
966 if e.wireprotosupport()],
969 if e.wireprotosupport()],
967 name='compengine', fmt='%s', sep=', '))
970 name='compengine', fmt='%s', sep=', '))
968
971
969 # templates
972 # templates
970 p = templater.templatepaths()
973 p = templater.templatepaths()
971 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
974 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
972 fm.condwrite(not p, '', _(" no template directories found\n"))
975 fm.condwrite(not p, '', _(" no template directories found\n"))
973 if p:
976 if p:
974 m = templater.templatepath("map-cmdline.default")
977 m = templater.templatepath("map-cmdline.default")
975 if m:
978 if m:
976 # template found, check if it is working
979 # template found, check if it is working
977 err = None
980 err = None
978 try:
981 try:
979 templater.templater.frommapfile(m)
982 templater.templater.frommapfile(m)
980 except Exception as inst:
983 except Exception as inst:
981 err = inst
984 err = inst
982 p = None
985 p = None
983 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
986 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
984 else:
987 else:
985 p = None
988 p = None
986 fm.condwrite(p, 'defaulttemplate',
989 fm.condwrite(p, 'defaulttemplate',
987 _("checking default template (%s)\n"), m)
990 _("checking default template (%s)\n"), m)
988 fm.condwrite(not m, 'defaulttemplatenotfound',
991 fm.condwrite(not m, 'defaulttemplatenotfound',
989 _(" template '%s' not found\n"), "default")
992 _(" template '%s' not found\n"), "default")
990 if not p:
993 if not p:
991 problems += 1
994 problems += 1
992 fm.condwrite(not p, '',
995 fm.condwrite(not p, '',
993 _(" (templates seem to have been installed incorrectly)\n"))
996 _(" (templates seem to have been installed incorrectly)\n"))
994
997
995 # editor
998 # editor
996 editor = ui.geteditor()
999 editor = ui.geteditor()
997 editor = util.expandpath(editor)
1000 editor = util.expandpath(editor)
998 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1001 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
999 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1002 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1000 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1003 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1001 _(" No commit editor set and can't find %s in PATH\n"
1004 _(" No commit editor set and can't find %s in PATH\n"
1002 " (specify a commit editor in your configuration"
1005 " (specify a commit editor in your configuration"
1003 " file)\n"), not cmdpath and editor == 'vi' and editor)
1006 " file)\n"), not cmdpath and editor == 'vi' and editor)
1004 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1007 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1005 _(" Can't find editor '%s' in PATH\n"
1008 _(" Can't find editor '%s' in PATH\n"
1006 " (specify a commit editor in your configuration"
1009 " (specify a commit editor in your configuration"
1007 " file)\n"), not cmdpath and editor)
1010 " file)\n"), not cmdpath and editor)
1008 if not cmdpath and editor != 'vi':
1011 if not cmdpath and editor != 'vi':
1009 problems += 1
1012 problems += 1
1010
1013
1011 # check username
1014 # check username
1012 username = None
1015 username = None
1013 err = None
1016 err = None
1014 try:
1017 try:
1015 username = ui.username()
1018 username = ui.username()
1016 except error.Abort as e:
1019 except error.Abort as e:
1017 err = e
1020 err = e
1018 problems += 1
1021 problems += 1
1019
1022
1020 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1023 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1021 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1024 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1022 " (specify a username in your configuration file)\n"), err)
1025 " (specify a username in your configuration file)\n"), err)
1023
1026
1024 fm.condwrite(not problems, '',
1027 fm.condwrite(not problems, '',
1025 _("no problems detected\n"))
1028 _("no problems detected\n"))
1026 if not problems:
1029 if not problems:
1027 fm.data(problems=problems)
1030 fm.data(problems=problems)
1028 fm.condwrite(problems, 'problems',
1031 fm.condwrite(problems, 'problems',
1029 _("%d problems detected,"
1032 _("%d problems detected,"
1030 " please check your install!\n"), problems)
1033 " please check your install!\n"), problems)
1031 fm.end()
1034 fm.end()
1032
1035
1033 return problems
1036 return problems
1034
1037
1035 @command('debugknown', [], _('REPO ID...'), norepo=True)
1038 @command('debugknown', [], _('REPO ID...'), norepo=True)
1036 def debugknown(ui, repopath, *ids, **opts):
1039 def debugknown(ui, repopath, *ids, **opts):
1037 """test whether node ids are known to a repo
1040 """test whether node ids are known to a repo
1038
1041
1039 Every ID must be a full-length hex node id string. Returns a list of 0s
1042 Every ID must be a full-length hex node id string. Returns a list of 0s
1040 and 1s indicating unknown/known.
1043 and 1s indicating unknown/known.
1041 """
1044 """
1042 repo = hg.peer(ui, opts, repopath)
1045 repo = hg.peer(ui, opts, repopath)
1043 if not repo.capable('known'):
1046 if not repo.capable('known'):
1044 raise error.Abort("known() not supported by target repository")
1047 raise error.Abort("known() not supported by target repository")
1045 flags = repo.known([bin(s) for s in ids])
1048 flags = repo.known([bin(s) for s in ids])
1046 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1049 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1047
1050
1048 @command('debuglabelcomplete', [], _('LABEL...'))
1051 @command('debuglabelcomplete', [], _('LABEL...'))
1049 def debuglabelcomplete(ui, repo, *args):
1052 def debuglabelcomplete(ui, repo, *args):
1050 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1053 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1051 commands.debugnamecomplete(ui, repo, *args)
1054 commands.debugnamecomplete(ui, repo, *args)
1052
1055
1053 @command('debuglocks',
1056 @command('debuglocks',
1054 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1057 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1055 ('W', 'force-wlock', None,
1058 ('W', 'force-wlock', None,
1056 _('free the working state lock (DANGEROUS)'))],
1059 _('free the working state lock (DANGEROUS)'))],
1057 _('[OPTION]...'))
1060 _('[OPTION]...'))
1058 def debuglocks(ui, repo, **opts):
1061 def debuglocks(ui, repo, **opts):
1059 """show or modify state of locks
1062 """show or modify state of locks
1060
1063
1061 By default, this command will show which locks are held. This
1064 By default, this command will show which locks are held. This
1062 includes the user and process holding the lock, the amount of time
1065 includes the user and process holding the lock, the amount of time
1063 the lock has been held, and the machine name where the process is
1066 the lock has been held, and the machine name where the process is
1064 running if it's not local.
1067 running if it's not local.
1065
1068
1066 Locks protect the integrity of Mercurial's data, so should be
1069 Locks protect the integrity of Mercurial's data, so should be
1067 treated with care. System crashes or other interruptions may cause
1070 treated with care. System crashes or other interruptions may cause
1068 locks to not be properly released, though Mercurial will usually
1071 locks to not be properly released, though Mercurial will usually
1069 detect and remove such stale locks automatically.
1072 detect and remove such stale locks automatically.
1070
1073
1071 However, detecting stale locks may not always be possible (for
1074 However, detecting stale locks may not always be possible (for
1072 instance, on a shared filesystem). Removing locks may also be
1075 instance, on a shared filesystem). Removing locks may also be
1073 blocked by filesystem permissions.
1076 blocked by filesystem permissions.
1074
1077
1075 Returns 0 if no locks are held.
1078 Returns 0 if no locks are held.
1076
1079
1077 """
1080 """
1078
1081
1079 if opts.get('force_lock'):
1082 if opts.get('force_lock'):
1080 repo.svfs.unlink('lock')
1083 repo.svfs.unlink('lock')
1081 if opts.get('force_wlock'):
1084 if opts.get('force_wlock'):
1082 repo.vfs.unlink('wlock')
1085 repo.vfs.unlink('wlock')
1083 if opts.get('force_lock') or opts.get('force_lock'):
1086 if opts.get('force_lock') or opts.get('force_lock'):
1084 return 0
1087 return 0
1085
1088
1086 now = time.time()
1089 now = time.time()
1087 held = 0
1090 held = 0
1088
1091
1089 def report(vfs, name, method):
1092 def report(vfs, name, method):
1090 # this causes stale locks to get reaped for more accurate reporting
1093 # this causes stale locks to get reaped for more accurate reporting
1091 try:
1094 try:
1092 l = method(False)
1095 l = method(False)
1093 except error.LockHeld:
1096 except error.LockHeld:
1094 l = None
1097 l = None
1095
1098
1096 if l:
1099 if l:
1097 l.release()
1100 l.release()
1098 else:
1101 else:
1099 try:
1102 try:
1100 stat = vfs.lstat(name)
1103 stat = vfs.lstat(name)
1101 age = now - stat.st_mtime
1104 age = now - stat.st_mtime
1102 user = util.username(stat.st_uid)
1105 user = util.username(stat.st_uid)
1103 locker = vfs.readlock(name)
1106 locker = vfs.readlock(name)
1104 if ":" in locker:
1107 if ":" in locker:
1105 host, pid = locker.split(':')
1108 host, pid = locker.split(':')
1106 if host == socket.gethostname():
1109 if host == socket.gethostname():
1107 locker = 'user %s, process %s' % (user, pid)
1110 locker = 'user %s, process %s' % (user, pid)
1108 else:
1111 else:
1109 locker = 'user %s, process %s, host %s' \
1112 locker = 'user %s, process %s, host %s' \
1110 % (user, pid, host)
1113 % (user, pid, host)
1111 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1114 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1112 return 1
1115 return 1
1113 except OSError as e:
1116 except OSError as e:
1114 if e.errno != errno.ENOENT:
1117 if e.errno != errno.ENOENT:
1115 raise
1118 raise
1116
1119
1117 ui.write(("%-6s free\n") % (name + ":"))
1120 ui.write(("%-6s free\n") % (name + ":"))
1118 return 0
1121 return 0
1119
1122
1120 held += report(repo.svfs, "lock", repo.lock)
1123 held += report(repo.svfs, "lock", repo.lock)
1121 held += report(repo.vfs, "wlock", repo.wlock)
1124 held += report(repo.vfs, "wlock", repo.wlock)
1122
1125
1123 return held
1126 return held
1124
1127
1125 @command('debugmergestate', [], '')
1128 @command('debugmergestate', [], '')
1126 def debugmergestate(ui, repo, *args):
1129 def debugmergestate(ui, repo, *args):
1127 """print merge state
1130 """print merge state
1128
1131
1129 Use --verbose to print out information about whether v1 or v2 merge state
1132 Use --verbose to print out information about whether v1 or v2 merge state
1130 was chosen."""
1133 was chosen."""
1131 def _hashornull(h):
1134 def _hashornull(h):
1132 if h == nullhex:
1135 if h == nullhex:
1133 return 'null'
1136 return 'null'
1134 else:
1137 else:
1135 return h
1138 return h
1136
1139
1137 def printrecords(version):
1140 def printrecords(version):
1138 ui.write(('* version %s records\n') % version)
1141 ui.write(('* version %s records\n') % version)
1139 if version == 1:
1142 if version == 1:
1140 records = v1records
1143 records = v1records
1141 else:
1144 else:
1142 records = v2records
1145 records = v2records
1143
1146
1144 for rtype, record in records:
1147 for rtype, record in records:
1145 # pretty print some record types
1148 # pretty print some record types
1146 if rtype == 'L':
1149 if rtype == 'L':
1147 ui.write(('local: %s\n') % record)
1150 ui.write(('local: %s\n') % record)
1148 elif rtype == 'O':
1151 elif rtype == 'O':
1149 ui.write(('other: %s\n') % record)
1152 ui.write(('other: %s\n') % record)
1150 elif rtype == 'm':
1153 elif rtype == 'm':
1151 driver, mdstate = record.split('\0', 1)
1154 driver, mdstate = record.split('\0', 1)
1152 ui.write(('merge driver: %s (state "%s")\n')
1155 ui.write(('merge driver: %s (state "%s")\n')
1153 % (driver, mdstate))
1156 % (driver, mdstate))
1154 elif rtype in 'FDC':
1157 elif rtype in 'FDC':
1155 r = record.split('\0')
1158 r = record.split('\0')
1156 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1159 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1157 if version == 1:
1160 if version == 1:
1158 onode = 'not stored in v1 format'
1161 onode = 'not stored in v1 format'
1159 flags = r[7]
1162 flags = r[7]
1160 else:
1163 else:
1161 onode, flags = r[7:9]
1164 onode, flags = r[7:9]
1162 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1165 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1163 % (f, rtype, state, _hashornull(hash)))
1166 % (f, rtype, state, _hashornull(hash)))
1164 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1167 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1165 ui.write((' ancestor path: %s (node %s)\n')
1168 ui.write((' ancestor path: %s (node %s)\n')
1166 % (afile, _hashornull(anode)))
1169 % (afile, _hashornull(anode)))
1167 ui.write((' other path: %s (node %s)\n')
1170 ui.write((' other path: %s (node %s)\n')
1168 % (ofile, _hashornull(onode)))
1171 % (ofile, _hashornull(onode)))
1169 elif rtype == 'f':
1172 elif rtype == 'f':
1170 filename, rawextras = record.split('\0', 1)
1173 filename, rawextras = record.split('\0', 1)
1171 extras = rawextras.split('\0')
1174 extras = rawextras.split('\0')
1172 i = 0
1175 i = 0
1173 extrastrings = []
1176 extrastrings = []
1174 while i < len(extras):
1177 while i < len(extras):
1175 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1178 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1176 i += 2
1179 i += 2
1177
1180
1178 ui.write(('file extras: %s (%s)\n')
1181 ui.write(('file extras: %s (%s)\n')
1179 % (filename, ', '.join(extrastrings)))
1182 % (filename, ', '.join(extrastrings)))
1180 elif rtype == 'l':
1183 elif rtype == 'l':
1181 labels = record.split('\0', 2)
1184 labels = record.split('\0', 2)
1182 labels = [l for l in labels if len(l) > 0]
1185 labels = [l for l in labels if len(l) > 0]
1183 ui.write(('labels:\n'))
1186 ui.write(('labels:\n'))
1184 ui.write((' local: %s\n' % labels[0]))
1187 ui.write((' local: %s\n' % labels[0]))
1185 ui.write((' other: %s\n' % labels[1]))
1188 ui.write((' other: %s\n' % labels[1]))
1186 if len(labels) > 2:
1189 if len(labels) > 2:
1187 ui.write((' base: %s\n' % labels[2]))
1190 ui.write((' base: %s\n' % labels[2]))
1188 else:
1191 else:
1189 ui.write(('unrecognized entry: %s\t%s\n')
1192 ui.write(('unrecognized entry: %s\t%s\n')
1190 % (rtype, record.replace('\0', '\t')))
1193 % (rtype, record.replace('\0', '\t')))
1191
1194
1192 # Avoid mergestate.read() since it may raise an exception for unsupported
1195 # Avoid mergestate.read() since it may raise an exception for unsupported
1193 # merge state records. We shouldn't be doing this, but this is OK since this
1196 # merge state records. We shouldn't be doing this, but this is OK since this
1194 # command is pretty low-level.
1197 # command is pretty low-level.
1195 ms = mergemod.mergestate(repo)
1198 ms = mergemod.mergestate(repo)
1196
1199
1197 # sort so that reasonable information is on top
1200 # sort so that reasonable information is on top
1198 v1records = ms._readrecordsv1()
1201 v1records = ms._readrecordsv1()
1199 v2records = ms._readrecordsv2()
1202 v2records = ms._readrecordsv2()
1200 order = 'LOml'
1203 order = 'LOml'
1201 def key(r):
1204 def key(r):
1202 idx = order.find(r[0])
1205 idx = order.find(r[0])
1203 if idx == -1:
1206 if idx == -1:
1204 return (1, r[1])
1207 return (1, r[1])
1205 else:
1208 else:
1206 return (0, idx)
1209 return (0, idx)
1207 v1records.sort(key=key)
1210 v1records.sort(key=key)
1208 v2records.sort(key=key)
1211 v2records.sort(key=key)
1209
1212
1210 if not v1records and not v2records:
1213 if not v1records and not v2records:
1211 ui.write(('no merge state found\n'))
1214 ui.write(('no merge state found\n'))
1212 elif not v2records:
1215 elif not v2records:
1213 ui.note(('no version 2 merge state\n'))
1216 ui.note(('no version 2 merge state\n'))
1214 printrecords(1)
1217 printrecords(1)
1215 elif ms._v1v2match(v1records, v2records):
1218 elif ms._v1v2match(v1records, v2records):
1216 ui.note(('v1 and v2 states match: using v2\n'))
1219 ui.note(('v1 and v2 states match: using v2\n'))
1217 printrecords(2)
1220 printrecords(2)
1218 else:
1221 else:
1219 ui.note(('v1 and v2 states mismatch: using v1\n'))
1222 ui.note(('v1 and v2 states mismatch: using v1\n'))
1220 printrecords(1)
1223 printrecords(1)
1221 if ui.verbose:
1224 if ui.verbose:
1222 printrecords(2)
1225 printrecords(2)
1223
1226
1224 @command('debugnamecomplete', [], _('NAME...'))
1227 @command('debugnamecomplete', [], _('NAME...'))
1225 def debugnamecomplete(ui, repo, *args):
1228 def debugnamecomplete(ui, repo, *args):
1226 '''complete "names" - tags, open branch names, bookmark names'''
1229 '''complete "names" - tags, open branch names, bookmark names'''
1227
1230
1228 names = set()
1231 names = set()
1229 # since we previously only listed open branches, we will handle that
1232 # since we previously only listed open branches, we will handle that
1230 # specially (after this for loop)
1233 # specially (after this for loop)
1231 for name, ns in repo.names.iteritems():
1234 for name, ns in repo.names.iteritems():
1232 if name != 'branches':
1235 if name != 'branches':
1233 names.update(ns.listnames(repo))
1236 names.update(ns.listnames(repo))
1234 names.update(tag for (tag, heads, tip, closed)
1237 names.update(tag for (tag, heads, tip, closed)
1235 in repo.branchmap().iterbranches() if not closed)
1238 in repo.branchmap().iterbranches() if not closed)
1236 completions = set()
1239 completions = set()
1237 if not args:
1240 if not args:
1238 args = ['']
1241 args = ['']
1239 for a in args:
1242 for a in args:
1240 completions.update(n for n in names if n.startswith(a))
1243 completions.update(n for n in names if n.startswith(a))
1241 ui.write('\n'.join(sorted(completions)))
1244 ui.write('\n'.join(sorted(completions)))
1242 ui.write('\n')
1245 ui.write('\n')
1243
1246
1244 @command('debugobsolete',
1247 @command('debugobsolete',
1245 [('', 'flags', 0, _('markers flag')),
1248 [('', 'flags', 0, _('markers flag')),
1246 ('', 'record-parents', False,
1249 ('', 'record-parents', False,
1247 _('record parent information for the precursor')),
1250 _('record parent information for the precursor')),
1248 ('r', 'rev', [], _('display markers relevant to REV')),
1251 ('r', 'rev', [], _('display markers relevant to REV')),
1249 ('', 'index', False, _('display index of the marker')),
1252 ('', 'index', False, _('display index of the marker')),
1250 ('', 'delete', [], _('delete markers specified by indices')),
1253 ('', 'delete', [], _('delete markers specified by indices')),
1251 ] + commands.commitopts2 + commands.formatteropts,
1254 ] + commands.commitopts2 + commands.formatteropts,
1252 _('[OBSOLETED [REPLACEMENT ...]]'))
1255 _('[OBSOLETED [REPLACEMENT ...]]'))
1253 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1256 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1254 """create arbitrary obsolete marker
1257 """create arbitrary obsolete marker
1255
1258
1256 With no arguments, displays the list of obsolescence markers."""
1259 With no arguments, displays the list of obsolescence markers."""
1257
1260
1258 def parsenodeid(s):
1261 def parsenodeid(s):
1259 try:
1262 try:
1260 # We do not use revsingle/revrange functions here to accept
1263 # We do not use revsingle/revrange functions here to accept
1261 # arbitrary node identifiers, possibly not present in the
1264 # arbitrary node identifiers, possibly not present in the
1262 # local repository.
1265 # local repository.
1263 n = bin(s)
1266 n = bin(s)
1264 if len(n) != len(nullid):
1267 if len(n) != len(nullid):
1265 raise TypeError()
1268 raise TypeError()
1266 return n
1269 return n
1267 except TypeError:
1270 except TypeError:
1268 raise error.Abort('changeset references must be full hexadecimal '
1271 raise error.Abort('changeset references must be full hexadecimal '
1269 'node identifiers')
1272 'node identifiers')
1270
1273
1271 if opts.get('delete'):
1274 if opts.get('delete'):
1272 indices = []
1275 indices = []
1273 for v in opts.get('delete'):
1276 for v in opts.get('delete'):
1274 try:
1277 try:
1275 indices.append(int(v))
1278 indices.append(int(v))
1276 except ValueError:
1279 except ValueError:
1277 raise error.Abort(_('invalid index value: %r') % v,
1280 raise error.Abort(_('invalid index value: %r') % v,
1278 hint=_('use integers for indices'))
1281 hint=_('use integers for indices'))
1279
1282
1280 if repo.currenttransaction():
1283 if repo.currenttransaction():
1281 raise error.Abort(_('cannot delete obsmarkers in the middle '
1284 raise error.Abort(_('cannot delete obsmarkers in the middle '
1282 'of transaction.'))
1285 'of transaction.'))
1283
1286
1284 with repo.lock():
1287 with repo.lock():
1285 n = repair.deleteobsmarkers(repo.obsstore, indices)
1288 n = repair.deleteobsmarkers(repo.obsstore, indices)
1286 ui.write(_('deleted %i obsolescence markers\n') % n)
1289 ui.write(_('deleted %i obsolescence markers\n') % n)
1287
1290
1288 return
1291 return
1289
1292
1290 if precursor is not None:
1293 if precursor is not None:
1291 if opts['rev']:
1294 if opts['rev']:
1292 raise error.Abort('cannot select revision when creating marker')
1295 raise error.Abort('cannot select revision when creating marker')
1293 metadata = {}
1296 metadata = {}
1294 metadata['user'] = opts['user'] or ui.username()
1297 metadata['user'] = opts['user'] or ui.username()
1295 succs = tuple(parsenodeid(succ) for succ in successors)
1298 succs = tuple(parsenodeid(succ) for succ in successors)
1296 l = repo.lock()
1299 l = repo.lock()
1297 try:
1300 try:
1298 tr = repo.transaction('debugobsolete')
1301 tr = repo.transaction('debugobsolete')
1299 try:
1302 try:
1300 date = opts.get('date')
1303 date = opts.get('date')
1301 if date:
1304 if date:
1302 date = util.parsedate(date)
1305 date = util.parsedate(date)
1303 else:
1306 else:
1304 date = None
1307 date = None
1305 prec = parsenodeid(precursor)
1308 prec = parsenodeid(precursor)
1306 parents = None
1309 parents = None
1307 if opts['record_parents']:
1310 if opts['record_parents']:
1308 if prec not in repo.unfiltered():
1311 if prec not in repo.unfiltered():
1309 raise error.Abort('cannot used --record-parents on '
1312 raise error.Abort('cannot used --record-parents on '
1310 'unknown changesets')
1313 'unknown changesets')
1311 parents = repo.unfiltered()[prec].parents()
1314 parents = repo.unfiltered()[prec].parents()
1312 parents = tuple(p.node() for p in parents)
1315 parents = tuple(p.node() for p in parents)
1313 repo.obsstore.create(tr, prec, succs, opts['flags'],
1316 repo.obsstore.create(tr, prec, succs, opts['flags'],
1314 parents=parents, date=date,
1317 parents=parents, date=date,
1315 metadata=metadata)
1318 metadata=metadata)
1316 tr.close()
1319 tr.close()
1317 except ValueError as exc:
1320 except ValueError as exc:
1318 raise error.Abort(_('bad obsmarker input: %s') % exc)
1321 raise error.Abort(_('bad obsmarker input: %s') % exc)
1319 finally:
1322 finally:
1320 tr.release()
1323 tr.release()
1321 finally:
1324 finally:
1322 l.release()
1325 l.release()
1323 else:
1326 else:
1324 if opts['rev']:
1327 if opts['rev']:
1325 revs = scmutil.revrange(repo, opts['rev'])
1328 revs = scmutil.revrange(repo, opts['rev'])
1326 nodes = [repo[r].node() for r in revs]
1329 nodes = [repo[r].node() for r in revs]
1327 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1330 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1328 markers.sort(key=lambda x: x._data)
1331 markers.sort(key=lambda x: x._data)
1329 else:
1332 else:
1330 markers = obsolete.getmarkers(repo)
1333 markers = obsolete.getmarkers(repo)
1331
1334
1332 markerstoiter = markers
1335 markerstoiter = markers
1333 isrelevant = lambda m: True
1336 isrelevant = lambda m: True
1334 if opts.get('rev') and opts.get('index'):
1337 if opts.get('rev') and opts.get('index'):
1335 markerstoiter = obsolete.getmarkers(repo)
1338 markerstoiter = obsolete.getmarkers(repo)
1336 markerset = set(markers)
1339 markerset = set(markers)
1337 isrelevant = lambda m: m in markerset
1340 isrelevant = lambda m: m in markerset
1338
1341
1339 fm = ui.formatter('debugobsolete', opts)
1342 fm = ui.formatter('debugobsolete', opts)
1340 for i, m in enumerate(markerstoiter):
1343 for i, m in enumerate(markerstoiter):
1341 if not isrelevant(m):
1344 if not isrelevant(m):
1342 # marker can be irrelevant when we're iterating over a set
1345 # marker can be irrelevant when we're iterating over a set
1343 # of markers (markerstoiter) which is bigger than the set
1346 # of markers (markerstoiter) which is bigger than the set
1344 # of markers we want to display (markers)
1347 # of markers we want to display (markers)
1345 # this can happen if both --index and --rev options are
1348 # this can happen if both --index and --rev options are
1346 # provided and thus we need to iterate over all of the markers
1349 # provided and thus we need to iterate over all of the markers
1347 # to get the correct indices, but only display the ones that
1350 # to get the correct indices, but only display the ones that
1348 # are relevant to --rev value
1351 # are relevant to --rev value
1349 continue
1352 continue
1350 fm.startitem()
1353 fm.startitem()
1351 ind = i if opts.get('index') else None
1354 ind = i if opts.get('index') else None
1352 cmdutil.showmarker(fm, m, index=ind)
1355 cmdutil.showmarker(fm, m, index=ind)
1353 fm.end()
1356 fm.end()
1354
1357
1355 @command('debugpathcomplete',
1358 @command('debugpathcomplete',
1356 [('f', 'full', None, _('complete an entire path')),
1359 [('f', 'full', None, _('complete an entire path')),
1357 ('n', 'normal', None, _('show only normal files')),
1360 ('n', 'normal', None, _('show only normal files')),
1358 ('a', 'added', None, _('show only added files')),
1361 ('a', 'added', None, _('show only added files')),
1359 ('r', 'removed', None, _('show only removed files'))],
1362 ('r', 'removed', None, _('show only removed files'))],
1360 _('FILESPEC...'))
1363 _('FILESPEC...'))
1361 def debugpathcomplete(ui, repo, *specs, **opts):
1364 def debugpathcomplete(ui, repo, *specs, **opts):
1362 '''complete part or all of a tracked path
1365 '''complete part or all of a tracked path
1363
1366
1364 This command supports shells that offer path name completion. It
1367 This command supports shells that offer path name completion. It
1365 currently completes only files already known to the dirstate.
1368 currently completes only files already known to the dirstate.
1366
1369
1367 Completion extends only to the next path segment unless
1370 Completion extends only to the next path segment unless
1368 --full is specified, in which case entire paths are used.'''
1371 --full is specified, in which case entire paths are used.'''
1369
1372
1370 def complete(path, acceptable):
1373 def complete(path, acceptable):
1371 dirstate = repo.dirstate
1374 dirstate = repo.dirstate
1372 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1375 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1373 rootdir = repo.root + pycompat.ossep
1376 rootdir = repo.root + pycompat.ossep
1374 if spec != repo.root and not spec.startswith(rootdir):
1377 if spec != repo.root and not spec.startswith(rootdir):
1375 return [], []
1378 return [], []
1376 if os.path.isdir(spec):
1379 if os.path.isdir(spec):
1377 spec += '/'
1380 spec += '/'
1378 spec = spec[len(rootdir):]
1381 spec = spec[len(rootdir):]
1379 fixpaths = pycompat.ossep != '/'
1382 fixpaths = pycompat.ossep != '/'
1380 if fixpaths:
1383 if fixpaths:
1381 spec = spec.replace(pycompat.ossep, '/')
1384 spec = spec.replace(pycompat.ossep, '/')
1382 speclen = len(spec)
1385 speclen = len(spec)
1383 fullpaths = opts['full']
1386 fullpaths = opts['full']
1384 files, dirs = set(), set()
1387 files, dirs = set(), set()
1385 adddir, addfile = dirs.add, files.add
1388 adddir, addfile = dirs.add, files.add
1386 for f, st in dirstate.iteritems():
1389 for f, st in dirstate.iteritems():
1387 if f.startswith(spec) and st[0] in acceptable:
1390 if f.startswith(spec) and st[0] in acceptable:
1388 if fixpaths:
1391 if fixpaths:
1389 f = f.replace('/', pycompat.ossep)
1392 f = f.replace('/', pycompat.ossep)
1390 if fullpaths:
1393 if fullpaths:
1391 addfile(f)
1394 addfile(f)
1392 continue
1395 continue
1393 s = f.find(pycompat.ossep, speclen)
1396 s = f.find(pycompat.ossep, speclen)
1394 if s >= 0:
1397 if s >= 0:
1395 adddir(f[:s])
1398 adddir(f[:s])
1396 else:
1399 else:
1397 addfile(f)
1400 addfile(f)
1398 return files, dirs
1401 return files, dirs
1399
1402
1400 acceptable = ''
1403 acceptable = ''
1401 if opts['normal']:
1404 if opts['normal']:
1402 acceptable += 'nm'
1405 acceptable += 'nm'
1403 if opts['added']:
1406 if opts['added']:
1404 acceptable += 'a'
1407 acceptable += 'a'
1405 if opts['removed']:
1408 if opts['removed']:
1406 acceptable += 'r'
1409 acceptable += 'r'
1407 cwd = repo.getcwd()
1410 cwd = repo.getcwd()
1408 if not specs:
1411 if not specs:
1409 specs = ['.']
1412 specs = ['.']
1410
1413
1411 files, dirs = set(), set()
1414 files, dirs = set(), set()
1412 for spec in specs:
1415 for spec in specs:
1413 f, d = complete(spec, acceptable or 'nmar')
1416 f, d = complete(spec, acceptable or 'nmar')
1414 files.update(f)
1417 files.update(f)
1415 dirs.update(d)
1418 dirs.update(d)
1416 files.update(dirs)
1419 files.update(dirs)
1417 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1420 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1418 ui.write('\n')
1421 ui.write('\n')
1419
1422
1420 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1423 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1421 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1424 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1422 '''access the pushkey key/value protocol
1425 '''access the pushkey key/value protocol
1423
1426
1424 With two args, list the keys in the given namespace.
1427 With two args, list the keys in the given namespace.
1425
1428
1426 With five args, set a key to new if it currently is set to old.
1429 With five args, set a key to new if it currently is set to old.
1427 Reports success or failure.
1430 Reports success or failure.
1428 '''
1431 '''
1429
1432
1430 target = hg.peer(ui, {}, repopath)
1433 target = hg.peer(ui, {}, repopath)
1431 if keyinfo:
1434 if keyinfo:
1432 key, old, new = keyinfo
1435 key, old, new = keyinfo
1433 r = target.pushkey(namespace, key, old, new)
1436 r = target.pushkey(namespace, key, old, new)
1434 ui.status(str(r) + '\n')
1437 ui.status(str(r) + '\n')
1435 return not r
1438 return not r
1436 else:
1439 else:
1437 for k, v in sorted(target.listkeys(namespace).iteritems()):
1440 for k, v in sorted(target.listkeys(namespace).iteritems()):
1438 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1441 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1439 v.encode('string-escape')))
1442 v.encode('string-escape')))
1440
1443
1441 @command('debugpvec', [], _('A B'))
1444 @command('debugpvec', [], _('A B'))
1442 def debugpvec(ui, repo, a, b=None):
1445 def debugpvec(ui, repo, a, b=None):
1443 ca = scmutil.revsingle(repo, a)
1446 ca = scmutil.revsingle(repo, a)
1444 cb = scmutil.revsingle(repo, b)
1447 cb = scmutil.revsingle(repo, b)
1445 pa = pvec.ctxpvec(ca)
1448 pa = pvec.ctxpvec(ca)
1446 pb = pvec.ctxpvec(cb)
1449 pb = pvec.ctxpvec(cb)
1447 if pa == pb:
1450 if pa == pb:
1448 rel = "="
1451 rel = "="
1449 elif pa > pb:
1452 elif pa > pb:
1450 rel = ">"
1453 rel = ">"
1451 elif pa < pb:
1454 elif pa < pb:
1452 rel = "<"
1455 rel = "<"
1453 elif pa | pb:
1456 elif pa | pb:
1454 rel = "|"
1457 rel = "|"
1455 ui.write(_("a: %s\n") % pa)
1458 ui.write(_("a: %s\n") % pa)
1456 ui.write(_("b: %s\n") % pb)
1459 ui.write(_("b: %s\n") % pb)
1457 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1460 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1458 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1461 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1459 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1462 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1460 pa.distance(pb), rel))
1463 pa.distance(pb), rel))
1461
1464
1462 @command('debugrebuilddirstate|debugrebuildstate',
1465 @command('debugrebuilddirstate|debugrebuildstate',
1463 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1466 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1464 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1467 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1465 'the working copy parent')),
1468 'the working copy parent')),
1466 ],
1469 ],
1467 _('[-r REV]'))
1470 _('[-r REV]'))
1468 def debugrebuilddirstate(ui, repo, rev, **opts):
1471 def debugrebuilddirstate(ui, repo, rev, **opts):
1469 """rebuild the dirstate as it would look like for the given revision
1472 """rebuild the dirstate as it would look like for the given revision
1470
1473
1471 If no revision is specified the first current parent will be used.
1474 If no revision is specified the first current parent will be used.
1472
1475
1473 The dirstate will be set to the files of the given revision.
1476 The dirstate will be set to the files of the given revision.
1474 The actual working directory content or existing dirstate
1477 The actual working directory content or existing dirstate
1475 information such as adds or removes is not considered.
1478 information such as adds or removes is not considered.
1476
1479
1477 ``minimal`` will only rebuild the dirstate status for files that claim to be
1480 ``minimal`` will only rebuild the dirstate status for files that claim to be
1478 tracked but are not in the parent manifest, or that exist in the parent
1481 tracked but are not in the parent manifest, or that exist in the parent
1479 manifest but are not in the dirstate. It will not change adds, removes, or
1482 manifest but are not in the dirstate. It will not change adds, removes, or
1480 modified files that are in the working copy parent.
1483 modified files that are in the working copy parent.
1481
1484
1482 One use of this command is to make the next :hg:`status` invocation
1485 One use of this command is to make the next :hg:`status` invocation
1483 check the actual file content.
1486 check the actual file content.
1484 """
1487 """
1485 ctx = scmutil.revsingle(repo, rev)
1488 ctx = scmutil.revsingle(repo, rev)
1486 with repo.wlock():
1489 with repo.wlock():
1487 dirstate = repo.dirstate
1490 dirstate = repo.dirstate
1488 changedfiles = None
1491 changedfiles = None
1489 # See command doc for what minimal does.
1492 # See command doc for what minimal does.
1490 if opts.get('minimal'):
1493 if opts.get('minimal'):
1491 manifestfiles = set(ctx.manifest().keys())
1494 manifestfiles = set(ctx.manifest().keys())
1492 dirstatefiles = set(dirstate)
1495 dirstatefiles = set(dirstate)
1493 manifestonly = manifestfiles - dirstatefiles
1496 manifestonly = manifestfiles - dirstatefiles
1494 dsonly = dirstatefiles - manifestfiles
1497 dsonly = dirstatefiles - manifestfiles
1495 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1498 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1496 changedfiles = manifestonly | dsnotadded
1499 changedfiles = manifestonly | dsnotadded
1497
1500
1498 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1501 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1499
1502
1500 @command('debugrebuildfncache', [], '')
1503 @command('debugrebuildfncache', [], '')
1501 def debugrebuildfncache(ui, repo):
1504 def debugrebuildfncache(ui, repo):
1502 """rebuild the fncache file"""
1505 """rebuild the fncache file"""
1503 repair.rebuildfncache(ui, repo)
1506 repair.rebuildfncache(ui, repo)
1504
1507
1505 @command('debugrename',
1508 @command('debugrename',
1506 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1509 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1507 _('[-r REV] FILE'))
1510 _('[-r REV] FILE'))
1508 def debugrename(ui, repo, file1, *pats, **opts):
1511 def debugrename(ui, repo, file1, *pats, **opts):
1509 """dump rename information"""
1512 """dump rename information"""
1510
1513
1511 ctx = scmutil.revsingle(repo, opts.get('rev'))
1514 ctx = scmutil.revsingle(repo, opts.get('rev'))
1512 m = scmutil.match(ctx, (file1,) + pats, opts)
1515 m = scmutil.match(ctx, (file1,) + pats, opts)
1513 for abs in ctx.walk(m):
1516 for abs in ctx.walk(m):
1514 fctx = ctx[abs]
1517 fctx = ctx[abs]
1515 o = fctx.filelog().renamed(fctx.filenode())
1518 o = fctx.filelog().renamed(fctx.filenode())
1516 rel = m.rel(abs)
1519 rel = m.rel(abs)
1517 if o:
1520 if o:
1518 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1521 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1519 else:
1522 else:
1520 ui.write(_("%s not renamed\n") % rel)
1523 ui.write(_("%s not renamed\n") % rel)
1521
1524
1522 @command('debugrevlog', commands.debugrevlogopts +
1525 @command('debugrevlog', commands.debugrevlogopts +
1523 [('d', 'dump', False, _('dump index data'))],
1526 [('d', 'dump', False, _('dump index data'))],
1524 _('-c|-m|FILE'),
1527 _('-c|-m|FILE'),
1525 optionalrepo=True)
1528 optionalrepo=True)
1526 def debugrevlog(ui, repo, file_=None, **opts):
1529 def debugrevlog(ui, repo, file_=None, **opts):
1527 """show data and statistics about a revlog"""
1530 """show data and statistics about a revlog"""
1528 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1531 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1529
1532
1530 if opts.get("dump"):
1533 if opts.get("dump"):
1531 numrevs = len(r)
1534 numrevs = len(r)
1532 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1535 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1533 " rawsize totalsize compression heads chainlen\n"))
1536 " rawsize totalsize compression heads chainlen\n"))
1534 ts = 0
1537 ts = 0
1535 heads = set()
1538 heads = set()
1536
1539
1537 for rev in xrange(numrevs):
1540 for rev in xrange(numrevs):
1538 dbase = r.deltaparent(rev)
1541 dbase = r.deltaparent(rev)
1539 if dbase == -1:
1542 if dbase == -1:
1540 dbase = rev
1543 dbase = rev
1541 cbase = r.chainbase(rev)
1544 cbase = r.chainbase(rev)
1542 clen = r.chainlen(rev)
1545 clen = r.chainlen(rev)
1543 p1, p2 = r.parentrevs(rev)
1546 p1, p2 = r.parentrevs(rev)
1544 rs = r.rawsize(rev)
1547 rs = r.rawsize(rev)
1545 ts = ts + rs
1548 ts = ts + rs
1546 heads -= set(r.parentrevs(rev))
1549 heads -= set(r.parentrevs(rev))
1547 heads.add(rev)
1550 heads.add(rev)
1548 try:
1551 try:
1549 compression = ts / r.end(rev)
1552 compression = ts / r.end(rev)
1550 except ZeroDivisionError:
1553 except ZeroDivisionError:
1551 compression = 0
1554 compression = 0
1552 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1555 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1553 "%11d %5d %8d\n" %
1556 "%11d %5d %8d\n" %
1554 (rev, p1, p2, r.start(rev), r.end(rev),
1557 (rev, p1, p2, r.start(rev), r.end(rev),
1555 r.start(dbase), r.start(cbase),
1558 r.start(dbase), r.start(cbase),
1556 r.start(p1), r.start(p2),
1559 r.start(p1), r.start(p2),
1557 rs, ts, compression, len(heads), clen))
1560 rs, ts, compression, len(heads), clen))
1558 return 0
1561 return 0
1559
1562
1560 v = r.version
1563 v = r.version
1561 format = v & 0xFFFF
1564 format = v & 0xFFFF
1562 flags = []
1565 flags = []
1563 gdelta = False
1566 gdelta = False
1564 if v & revlog.REVLOGNGINLINEDATA:
1567 if v & revlog.REVLOGNGINLINEDATA:
1565 flags.append('inline')
1568 flags.append('inline')
1566 if v & revlog.REVLOGGENERALDELTA:
1569 if v & revlog.REVLOGGENERALDELTA:
1567 gdelta = True
1570 gdelta = True
1568 flags.append('generaldelta')
1571 flags.append('generaldelta')
1569 if not flags:
1572 if not flags:
1570 flags = ['(none)']
1573 flags = ['(none)']
1571
1574
1572 nummerges = 0
1575 nummerges = 0
1573 numfull = 0
1576 numfull = 0
1574 numprev = 0
1577 numprev = 0
1575 nump1 = 0
1578 nump1 = 0
1576 nump2 = 0
1579 nump2 = 0
1577 numother = 0
1580 numother = 0
1578 nump1prev = 0
1581 nump1prev = 0
1579 nump2prev = 0
1582 nump2prev = 0
1580 chainlengths = []
1583 chainlengths = []
1581
1584
1582 datasize = [None, 0, 0]
1585 datasize = [None, 0, 0]
1583 fullsize = [None, 0, 0]
1586 fullsize = [None, 0, 0]
1584 deltasize = [None, 0, 0]
1587 deltasize = [None, 0, 0]
1585 chunktypecounts = {}
1588 chunktypecounts = {}
1586 chunktypesizes = {}
1589 chunktypesizes = {}
1587
1590
1588 def addsize(size, l):
1591 def addsize(size, l):
1589 if l[0] is None or size < l[0]:
1592 if l[0] is None or size < l[0]:
1590 l[0] = size
1593 l[0] = size
1591 if size > l[1]:
1594 if size > l[1]:
1592 l[1] = size
1595 l[1] = size
1593 l[2] += size
1596 l[2] += size
1594
1597
1595 numrevs = len(r)
1598 numrevs = len(r)
1596 for rev in xrange(numrevs):
1599 for rev in xrange(numrevs):
1597 p1, p2 = r.parentrevs(rev)
1600 p1, p2 = r.parentrevs(rev)
1598 delta = r.deltaparent(rev)
1601 delta = r.deltaparent(rev)
1599 if format > 0:
1602 if format > 0:
1600 addsize(r.rawsize(rev), datasize)
1603 addsize(r.rawsize(rev), datasize)
1601 if p2 != nullrev:
1604 if p2 != nullrev:
1602 nummerges += 1
1605 nummerges += 1
1603 size = r.length(rev)
1606 size = r.length(rev)
1604 if delta == nullrev:
1607 if delta == nullrev:
1605 chainlengths.append(0)
1608 chainlengths.append(0)
1606 numfull += 1
1609 numfull += 1
1607 addsize(size, fullsize)
1610 addsize(size, fullsize)
1608 else:
1611 else:
1609 chainlengths.append(chainlengths[delta] + 1)
1612 chainlengths.append(chainlengths[delta] + 1)
1610 addsize(size, deltasize)
1613 addsize(size, deltasize)
1611 if delta == rev - 1:
1614 if delta == rev - 1:
1612 numprev += 1
1615 numprev += 1
1613 if delta == p1:
1616 if delta == p1:
1614 nump1prev += 1
1617 nump1prev += 1
1615 elif delta == p2:
1618 elif delta == p2:
1616 nump2prev += 1
1619 nump2prev += 1
1617 elif delta == p1:
1620 elif delta == p1:
1618 nump1 += 1
1621 nump1 += 1
1619 elif delta == p2:
1622 elif delta == p2:
1620 nump2 += 1
1623 nump2 += 1
1621 elif delta != nullrev:
1624 elif delta != nullrev:
1622 numother += 1
1625 numother += 1
1623
1626
1624 # Obtain data on the raw chunks in the revlog.
1627 # Obtain data on the raw chunks in the revlog.
1625 chunk = r._chunkraw(rev, rev)[1]
1628 chunk = r._chunkraw(rev, rev)[1]
1626 if chunk:
1629 if chunk:
1627 chunktype = chunk[0]
1630 chunktype = chunk[0]
1628 else:
1631 else:
1629 chunktype = 'empty'
1632 chunktype = 'empty'
1630
1633
1631 if chunktype not in chunktypecounts:
1634 if chunktype not in chunktypecounts:
1632 chunktypecounts[chunktype] = 0
1635 chunktypecounts[chunktype] = 0
1633 chunktypesizes[chunktype] = 0
1636 chunktypesizes[chunktype] = 0
1634
1637
1635 chunktypecounts[chunktype] += 1
1638 chunktypecounts[chunktype] += 1
1636 chunktypesizes[chunktype] += size
1639 chunktypesizes[chunktype] += size
1637
1640
1638 # Adjust size min value for empty cases
1641 # Adjust size min value for empty cases
1639 for size in (datasize, fullsize, deltasize):
1642 for size in (datasize, fullsize, deltasize):
1640 if size[0] is None:
1643 if size[0] is None:
1641 size[0] = 0
1644 size[0] = 0
1642
1645
1643 numdeltas = numrevs - numfull
1646 numdeltas = numrevs - numfull
1644 numoprev = numprev - nump1prev - nump2prev
1647 numoprev = numprev - nump1prev - nump2prev
1645 totalrawsize = datasize[2]
1648 totalrawsize = datasize[2]
1646 datasize[2] /= numrevs
1649 datasize[2] /= numrevs
1647 fulltotal = fullsize[2]
1650 fulltotal = fullsize[2]
1648 fullsize[2] /= numfull
1651 fullsize[2] /= numfull
1649 deltatotal = deltasize[2]
1652 deltatotal = deltasize[2]
1650 if numrevs - numfull > 0:
1653 if numrevs - numfull > 0:
1651 deltasize[2] /= numrevs - numfull
1654 deltasize[2] /= numrevs - numfull
1652 totalsize = fulltotal + deltatotal
1655 totalsize = fulltotal + deltatotal
1653 avgchainlen = sum(chainlengths) / numrevs
1656 avgchainlen = sum(chainlengths) / numrevs
1654 maxchainlen = max(chainlengths)
1657 maxchainlen = max(chainlengths)
1655 compratio = 1
1658 compratio = 1
1656 if totalsize:
1659 if totalsize:
1657 compratio = totalrawsize / totalsize
1660 compratio = totalrawsize / totalsize
1658
1661
1659 basedfmtstr = '%%%dd\n'
1662 basedfmtstr = '%%%dd\n'
1660 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1663 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1661
1664
1662 def dfmtstr(max):
1665 def dfmtstr(max):
1663 return basedfmtstr % len(str(max))
1666 return basedfmtstr % len(str(max))
1664 def pcfmtstr(max, padding=0):
1667 def pcfmtstr(max, padding=0):
1665 return basepcfmtstr % (len(str(max)), ' ' * padding)
1668 return basepcfmtstr % (len(str(max)), ' ' * padding)
1666
1669
1667 def pcfmt(value, total):
1670 def pcfmt(value, total):
1668 if total:
1671 if total:
1669 return (value, 100 * float(value) / total)
1672 return (value, 100 * float(value) / total)
1670 else:
1673 else:
1671 return value, 100.0
1674 return value, 100.0
1672
1675
1673 ui.write(('format : %d\n') % format)
1676 ui.write(('format : %d\n') % format)
1674 ui.write(('flags : %s\n') % ', '.join(flags))
1677 ui.write(('flags : %s\n') % ', '.join(flags))
1675
1678
1676 ui.write('\n')
1679 ui.write('\n')
1677 fmt = pcfmtstr(totalsize)
1680 fmt = pcfmtstr(totalsize)
1678 fmt2 = dfmtstr(totalsize)
1681 fmt2 = dfmtstr(totalsize)
1679 ui.write(('revisions : ') + fmt2 % numrevs)
1682 ui.write(('revisions : ') + fmt2 % numrevs)
1680 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1683 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1681 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1684 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1682 ui.write(('revisions : ') + fmt2 % numrevs)
1685 ui.write(('revisions : ') + fmt2 % numrevs)
1683 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1686 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1684 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1687 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1685 ui.write(('revision size : ') + fmt2 % totalsize)
1688 ui.write(('revision size : ') + fmt2 % totalsize)
1686 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1689 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1687 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1690 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1688
1691
1689 def fmtchunktype(chunktype):
1692 def fmtchunktype(chunktype):
1690 if chunktype == 'empty':
1693 if chunktype == 'empty':
1691 return ' %s : ' % chunktype
1694 return ' %s : ' % chunktype
1692 elif chunktype in string.ascii_letters:
1695 elif chunktype in string.ascii_letters:
1693 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1696 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1694 else:
1697 else:
1695 return ' 0x%s : ' % hex(chunktype)
1698 return ' 0x%s : ' % hex(chunktype)
1696
1699
1697 ui.write('\n')
1700 ui.write('\n')
1698 ui.write(('chunks : ') + fmt2 % numrevs)
1701 ui.write(('chunks : ') + fmt2 % numrevs)
1699 for chunktype in sorted(chunktypecounts):
1702 for chunktype in sorted(chunktypecounts):
1700 ui.write(fmtchunktype(chunktype))
1703 ui.write(fmtchunktype(chunktype))
1701 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1704 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1702 ui.write(('chunks size : ') + fmt2 % totalsize)
1705 ui.write(('chunks size : ') + fmt2 % totalsize)
1703 for chunktype in sorted(chunktypecounts):
1706 for chunktype in sorted(chunktypecounts):
1704 ui.write(fmtchunktype(chunktype))
1707 ui.write(fmtchunktype(chunktype))
1705 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1708 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1706
1709
1707 ui.write('\n')
1710 ui.write('\n')
1708 fmt = dfmtstr(max(avgchainlen, compratio))
1711 fmt = dfmtstr(max(avgchainlen, compratio))
1709 ui.write(('avg chain length : ') + fmt % avgchainlen)
1712 ui.write(('avg chain length : ') + fmt % avgchainlen)
1710 ui.write(('max chain length : ') + fmt % maxchainlen)
1713 ui.write(('max chain length : ') + fmt % maxchainlen)
1711 ui.write(('compression ratio : ') + fmt % compratio)
1714 ui.write(('compression ratio : ') + fmt % compratio)
1712
1715
1713 if format > 0:
1716 if format > 0:
1714 ui.write('\n')
1717 ui.write('\n')
1715 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1718 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1716 % tuple(datasize))
1719 % tuple(datasize))
1717 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1720 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1718 % tuple(fullsize))
1721 % tuple(fullsize))
1719 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1722 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1720 % tuple(deltasize))
1723 % tuple(deltasize))
1721
1724
1722 if numdeltas > 0:
1725 if numdeltas > 0:
1723 ui.write('\n')
1726 ui.write('\n')
1724 fmt = pcfmtstr(numdeltas)
1727 fmt = pcfmtstr(numdeltas)
1725 fmt2 = pcfmtstr(numdeltas, 4)
1728 fmt2 = pcfmtstr(numdeltas, 4)
1726 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1729 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1727 if numprev > 0:
1730 if numprev > 0:
1728 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1731 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1729 numprev))
1732 numprev))
1730 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1733 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1731 numprev))
1734 numprev))
1732 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1735 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1733 numprev))
1736 numprev))
1734 if gdelta:
1737 if gdelta:
1735 ui.write(('deltas against p1 : ')
1738 ui.write(('deltas against p1 : ')
1736 + fmt % pcfmt(nump1, numdeltas))
1739 + fmt % pcfmt(nump1, numdeltas))
1737 ui.write(('deltas against p2 : ')
1740 ui.write(('deltas against p2 : ')
1738 + fmt % pcfmt(nump2, numdeltas))
1741 + fmt % pcfmt(nump2, numdeltas))
1739 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1742 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1740 numdeltas))
1743 numdeltas))
1741
1744
1745 @command('debugrevspec',
1746 [('', 'optimize', None,
1747 _('print parsed tree after optimizing (DEPRECATED)')),
1748 ('p', 'show-stage', [],
1749 _('print parsed tree at the given stage'), _('NAME')),
1750 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1751 ('', 'verify-optimized', False, _('verify optimized result')),
1752 ],
1753 ('REVSPEC'))
1754 def debugrevspec(ui, repo, expr, **opts):
1755 """parse and apply a revision specification
1756
1757 Use -p/--show-stage option to print the parsed tree at the given stages.
1758 Use -p all to print tree at every stage.
1759
1760 Use --verify-optimized to compare the optimized result with the unoptimized
1761 one. Returns 1 if the optimized result differs.
1762 """
1763 stages = [
1764 ('parsed', lambda tree: tree),
1765 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1766 ('concatenated', revset.foldconcat),
1767 ('analyzed', revset.analyze),
1768 ('optimized', revset.optimize),
1769 ]
1770 if opts['no_optimized']:
1771 stages = stages[:-1]
1772 if opts['verify_optimized'] and opts['no_optimized']:
1773 raise error.Abort(_('cannot use --verify-optimized with '
1774 '--no-optimized'))
1775 stagenames = set(n for n, f in stages)
1776
1777 showalways = set()
1778 showchanged = set()
1779 if ui.verbose and not opts['show_stage']:
1780 # show parsed tree by --verbose (deprecated)
1781 showalways.add('parsed')
1782 showchanged.update(['expanded', 'concatenated'])
1783 if opts['optimize']:
1784 showalways.add('optimized')
1785 if opts['show_stage'] and opts['optimize']:
1786 raise error.Abort(_('cannot use --optimize with --show-stage'))
1787 if opts['show_stage'] == ['all']:
1788 showalways.update(stagenames)
1789 else:
1790 for n in opts['show_stage']:
1791 if n not in stagenames:
1792 raise error.Abort(_('invalid stage name: %s') % n)
1793 showalways.update(opts['show_stage'])
1794
1795 treebystage = {}
1796 printedtree = None
1797 tree = revset.parse(expr, lookup=repo.__contains__)
1798 for n, f in stages:
1799 treebystage[n] = tree = f(tree)
1800 if n in showalways or (n in showchanged and tree != printedtree):
1801 if opts['show_stage'] or n != 'parsed':
1802 ui.write(("* %s:\n") % n)
1803 ui.write(revset.prettyformat(tree), "\n")
1804 printedtree = tree
1805
1806 if opts['verify_optimized']:
1807 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1808 brevs = revset.makematcher(treebystage['optimized'])(repo)
1809 if ui.verbose:
1810 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1811 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1812 arevs = list(arevs)
1813 brevs = list(brevs)
1814 if arevs == brevs:
1815 return 0
1816 ui.write(('--- analyzed\n'), label='diff.file_a')
1817 ui.write(('+++ optimized\n'), label='diff.file_b')
1818 sm = difflib.SequenceMatcher(None, arevs, brevs)
1819 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1820 if tag in ('delete', 'replace'):
1821 for c in arevs[alo:ahi]:
1822 ui.write('-%s\n' % c, label='diff.deleted')
1823 if tag in ('insert', 'replace'):
1824 for c in brevs[blo:bhi]:
1825 ui.write('+%s\n' % c, label='diff.inserted')
1826 if tag == 'equal':
1827 for c in arevs[alo:ahi]:
1828 ui.write(' %s\n' % c)
1829 return 1
1830
1831 func = revset.makematcher(tree)
1832 revs = func(repo)
1833 if ui.verbose:
1834 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1835 for c in revs:
1836 ui.write("%s\n" % c)
1837
1742 @command('debugupgraderepo', [
1838 @command('debugupgraderepo', [
1743 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1839 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1744 ('', 'run', False, _('performs an upgrade')),
1840 ('', 'run', False, _('performs an upgrade')),
1745 ])
1841 ])
1746 def debugupgraderepo(ui, repo, run=False, optimize=None):
1842 def debugupgraderepo(ui, repo, run=False, optimize=None):
1747 """upgrade a repository to use different features
1843 """upgrade a repository to use different features
1748
1844
1749 If no arguments are specified, the repository is evaluated for upgrade
1845 If no arguments are specified, the repository is evaluated for upgrade
1750 and a list of problems and potential optimizations is printed.
1846 and a list of problems and potential optimizations is printed.
1751
1847
1752 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1848 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1753 can be influenced via additional arguments. More details will be provided
1849 can be influenced via additional arguments. More details will be provided
1754 by the command output when run without ``--run``.
1850 by the command output when run without ``--run``.
1755
1851
1756 During the upgrade, the repository will be locked and no writes will be
1852 During the upgrade, the repository will be locked and no writes will be
1757 allowed.
1853 allowed.
1758
1854
1759 At the end of the upgrade, the repository may not be readable while new
1855 At the end of the upgrade, the repository may not be readable while new
1760 repository data is swapped in. This window will be as long as it takes to
1856 repository data is swapped in. This window will be as long as it takes to
1761 rename some directories inside the ``.hg`` directory. On most machines, this
1857 rename some directories inside the ``.hg`` directory. On most machines, this
1762 should complete almost instantaneously and the chances of a consumer being
1858 should complete almost instantaneously and the chances of a consumer being
1763 unable to access the repository should be low.
1859 unable to access the repository should be low.
1764 """
1860 """
1765 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1861 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now