##// END OF EJS Templates
debugcommands: move 'debugpushkey' in the new module
Pierre-Yves David -
r30946:71031224 default
parent child Browse files
Show More
@@ -1,6069 +1,6048
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 string
14 import string
15 import time
15 import time
16
16
17 from .i18n import _
17 from .i18n import _
18 from .node import (
18 from .node import (
19 hex,
19 hex,
20 nullid,
20 nullid,
21 nullrev,
21 nullrev,
22 short,
22 short,
23 )
23 )
24 from . import (
24 from . import (
25 archival,
25 archival,
26 bookmarks,
26 bookmarks,
27 bundle2,
27 bundle2,
28 changegroup,
28 changegroup,
29 cmdutil,
29 cmdutil,
30 copies,
30 copies,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 minirst,
45 minirst,
46 obsolete,
46 obsolete,
47 patch,
47 patch,
48 phases,
48 phases,
49 pvec,
49 pvec,
50 pycompat,
50 pycompat,
51 repair,
51 repair,
52 revlog,
52 revlog,
53 revset,
53 revset,
54 scmutil,
54 scmutil,
55 server,
55 server,
56 smartset,
56 smartset,
57 sshserver,
57 sshserver,
58 streamclone,
58 streamclone,
59 templatekw,
59 templatekw,
60 templater,
60 templater,
61 ui as uimod,
61 ui as uimod,
62 util,
62 util,
63 )
63 )
64
64
65 release = lockmod.release
65 release = lockmod.release
66
66
67 table = {}
67 table = {}
68
68
69 command = cmdutil.command(table)
69 command = cmdutil.command(table)
70
70
71 # label constants
71 # label constants
72 # until 3.5, bookmarks.current was the advertised name, not
72 # until 3.5, bookmarks.current was the advertised name, not
73 # bookmarks.active, so we must use both to avoid breaking old
73 # bookmarks.active, so we must use both to avoid breaking old
74 # custom styles
74 # custom styles
75 activebookmarklabel = 'bookmarks.active bookmarks.current'
75 activebookmarklabel = 'bookmarks.active bookmarks.current'
76
76
77 # common command options
77 # common command options
78
78
79 globalopts = [
79 globalopts = [
80 ('R', 'repository', '',
80 ('R', 'repository', '',
81 _('repository root directory or name of overlay bundle file'),
81 _('repository root directory or name of overlay bundle file'),
82 _('REPO')),
82 _('REPO')),
83 ('', 'cwd', '',
83 ('', 'cwd', '',
84 _('change working directory'), _('DIR')),
84 _('change working directory'), _('DIR')),
85 ('y', 'noninteractive', None,
85 ('y', 'noninteractive', None,
86 _('do not prompt, automatically pick the first choice for all prompts')),
86 _('do not prompt, automatically pick the first choice for all prompts')),
87 ('q', 'quiet', None, _('suppress output')),
87 ('q', 'quiet', None, _('suppress output')),
88 ('v', 'verbose', None, _('enable additional output')),
88 ('v', 'verbose', None, _('enable additional output')),
89 ('', 'config', [],
89 ('', 'config', [],
90 _('set/override config option (use \'section.name=value\')'),
90 _('set/override config option (use \'section.name=value\')'),
91 _('CONFIG')),
91 _('CONFIG')),
92 ('', 'debug', None, _('enable debugging output')),
92 ('', 'debug', None, _('enable debugging output')),
93 ('', 'debugger', None, _('start debugger')),
93 ('', 'debugger', None, _('start debugger')),
94 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
94 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
95 _('ENCODE')),
95 _('ENCODE')),
96 ('', 'encodingmode', encoding.encodingmode,
96 ('', 'encodingmode', encoding.encodingmode,
97 _('set the charset encoding mode'), _('MODE')),
97 _('set the charset encoding mode'), _('MODE')),
98 ('', 'traceback', None, _('always print a traceback on exception')),
98 ('', 'traceback', None, _('always print a traceback on exception')),
99 ('', 'time', None, _('time how long the command takes')),
99 ('', 'time', None, _('time how long the command takes')),
100 ('', 'profile', None, _('print command execution profile')),
100 ('', 'profile', None, _('print command execution profile')),
101 ('', 'version', None, _('output version information and exit')),
101 ('', 'version', None, _('output version information and exit')),
102 ('h', 'help', None, _('display help and exit')),
102 ('h', 'help', None, _('display help and exit')),
103 ('', 'hidden', False, _('consider hidden changesets')),
103 ('', 'hidden', False, _('consider hidden changesets')),
104 ]
104 ]
105
105
106 dryrunopts = [('n', 'dry-run', None,
106 dryrunopts = [('n', 'dry-run', None,
107 _('do not perform actions, just print output'))]
107 _('do not perform actions, just print output'))]
108
108
109 remoteopts = [
109 remoteopts = [
110 ('e', 'ssh', '',
110 ('e', 'ssh', '',
111 _('specify ssh command to use'), _('CMD')),
111 _('specify ssh command to use'), _('CMD')),
112 ('', 'remotecmd', '',
112 ('', 'remotecmd', '',
113 _('specify hg command to run on the remote side'), _('CMD')),
113 _('specify hg command to run on the remote side'), _('CMD')),
114 ('', 'insecure', None,
114 ('', 'insecure', None,
115 _('do not verify server certificate (ignoring web.cacerts config)')),
115 _('do not verify server certificate (ignoring web.cacerts config)')),
116 ]
116 ]
117
117
118 walkopts = [
118 walkopts = [
119 ('I', 'include', [],
119 ('I', 'include', [],
120 _('include names matching the given patterns'), _('PATTERN')),
120 _('include names matching the given patterns'), _('PATTERN')),
121 ('X', 'exclude', [],
121 ('X', 'exclude', [],
122 _('exclude names matching the given patterns'), _('PATTERN')),
122 _('exclude names matching the given patterns'), _('PATTERN')),
123 ]
123 ]
124
124
125 commitopts = [
125 commitopts = [
126 ('m', 'message', '',
126 ('m', 'message', '',
127 _('use text as commit message'), _('TEXT')),
127 _('use text as commit message'), _('TEXT')),
128 ('l', 'logfile', '',
128 ('l', 'logfile', '',
129 _('read commit message from file'), _('FILE')),
129 _('read commit message from file'), _('FILE')),
130 ]
130 ]
131
131
132 commitopts2 = [
132 commitopts2 = [
133 ('d', 'date', '',
133 ('d', 'date', '',
134 _('record the specified date as commit date'), _('DATE')),
134 _('record the specified date as commit date'), _('DATE')),
135 ('u', 'user', '',
135 ('u', 'user', '',
136 _('record the specified user as committer'), _('USER')),
136 _('record the specified user as committer'), _('USER')),
137 ]
137 ]
138
138
139 # hidden for now
139 # hidden for now
140 formatteropts = [
140 formatteropts = [
141 ('T', 'template', '',
141 ('T', 'template', '',
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
143 ]
143 ]
144
144
145 templateopts = [
145 templateopts = [
146 ('', 'style', '',
146 ('', 'style', '',
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
148 ('T', 'template', '',
148 ('T', 'template', '',
149 _('display with template'), _('TEMPLATE')),
149 _('display with template'), _('TEMPLATE')),
150 ]
150 ]
151
151
152 logopts = [
152 logopts = [
153 ('p', 'patch', None, _('show patch')),
153 ('p', 'patch', None, _('show patch')),
154 ('g', 'git', None, _('use git extended diff format')),
154 ('g', 'git', None, _('use git extended diff format')),
155 ('l', 'limit', '',
155 ('l', 'limit', '',
156 _('limit number of changes displayed'), _('NUM')),
156 _('limit number of changes displayed'), _('NUM')),
157 ('M', 'no-merges', None, _('do not show merges')),
157 ('M', 'no-merges', None, _('do not show merges')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
159 ('G', 'graph', None, _("show the revision DAG")),
159 ('G', 'graph', None, _("show the revision DAG")),
160 ] + templateopts
160 ] + templateopts
161
161
162 diffopts = [
162 diffopts = [
163 ('a', 'text', None, _('treat all files as text')),
163 ('a', 'text', None, _('treat all files as text')),
164 ('g', 'git', None, _('use git extended diff format')),
164 ('g', 'git', None, _('use git extended diff format')),
165 ('', 'nodates', None, _('omit dates from diff headers'))
165 ('', 'nodates', None, _('omit dates from diff headers'))
166 ]
166 ]
167
167
168 diffwsopts = [
168 diffwsopts = [
169 ('w', 'ignore-all-space', None,
169 ('w', 'ignore-all-space', None,
170 _('ignore white space when comparing lines')),
170 _('ignore white space when comparing lines')),
171 ('b', 'ignore-space-change', None,
171 ('b', 'ignore-space-change', None,
172 _('ignore changes in the amount of white space')),
172 _('ignore changes in the amount of white space')),
173 ('B', 'ignore-blank-lines', None,
173 ('B', 'ignore-blank-lines', None,
174 _('ignore changes whose lines are all blank')),
174 _('ignore changes whose lines are all blank')),
175 ]
175 ]
176
176
177 diffopts2 = [
177 diffopts2 = [
178 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
178 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
179 ('p', 'show-function', None, _('show which function each change is in')),
179 ('p', 'show-function', None, _('show which function each change is in')),
180 ('', 'reverse', None, _('produce a diff that undoes the changes')),
180 ('', 'reverse', None, _('produce a diff that undoes the changes')),
181 ] + diffwsopts + [
181 ] + diffwsopts + [
182 ('U', 'unified', '',
182 ('U', 'unified', '',
183 _('number of lines of context to show'), _('NUM')),
183 _('number of lines of context to show'), _('NUM')),
184 ('', 'stat', None, _('output diffstat-style summary of changes')),
184 ('', 'stat', None, _('output diffstat-style summary of changes')),
185 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
185 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
186 ]
186 ]
187
187
188 mergetoolopts = [
188 mergetoolopts = [
189 ('t', 'tool', '', _('specify merge tool')),
189 ('t', 'tool', '', _('specify merge tool')),
190 ]
190 ]
191
191
192 similarityopts = [
192 similarityopts = [
193 ('s', 'similarity', '',
193 ('s', 'similarity', '',
194 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
194 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
195 ]
195 ]
196
196
197 subrepoopts = [
197 subrepoopts = [
198 ('S', 'subrepos', None,
198 ('S', 'subrepos', None,
199 _('recurse into subrepositories'))
199 _('recurse into subrepositories'))
200 ]
200 ]
201
201
202 debugrevlogopts = [
202 debugrevlogopts = [
203 ('c', 'changelog', False, _('open changelog')),
203 ('c', 'changelog', False, _('open changelog')),
204 ('m', 'manifest', False, _('open manifest')),
204 ('m', 'manifest', False, _('open manifest')),
205 ('', 'dir', '', _('open directory manifest')),
205 ('', 'dir', '', _('open directory manifest')),
206 ]
206 ]
207
207
208 # Commands start here, listed alphabetically
208 # Commands start here, listed alphabetically
209
209
210 @command('^add',
210 @command('^add',
211 walkopts + subrepoopts + dryrunopts,
211 walkopts + subrepoopts + dryrunopts,
212 _('[OPTION]... [FILE]...'),
212 _('[OPTION]... [FILE]...'),
213 inferrepo=True)
213 inferrepo=True)
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 m = scmutil.match(repo[None], pats, opts)
257 m = scmutil.match(repo[None], pats, opts)
258 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
258 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
259 return rejected and 1 or 0
259 return rejected and 1 or 0
260
260
261 @command('addremove',
261 @command('addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _('[OPTION]... [FILE]...'),
263 _('[OPTION]... [FILE]...'),
264 inferrepo=True)
264 inferrepo=True)
265 def addremove(ui, repo, *pats, **opts):
265 def addremove(ui, repo, *pats, **opts):
266 """add all new files, delete all missing files
266 """add all new files, delete all missing files
267
267
268 Add all new files and remove all missing files from the
268 Add all new files and remove all missing files from the
269 repository.
269 repository.
270
270
271 Unless names are given, new files are ignored if they match any of
271 Unless names are given, new files are ignored if they match any of
272 the patterns in ``.hgignore``. As with add, these changes take
272 the patterns in ``.hgignore``. As with add, these changes take
273 effect at the next commit.
273 effect at the next commit.
274
274
275 Use the -s/--similarity option to detect renamed files. This
275 Use the -s/--similarity option to detect renamed files. This
276 option takes a percentage between 0 (disabled) and 100 (files must
276 option takes a percentage between 0 (disabled) and 100 (files must
277 be identical) as its parameter. With a parameter greater than 0,
277 be identical) as its parameter. With a parameter greater than 0,
278 this compares every removed file with every added file and records
278 this compares every removed file with every added file and records
279 those similar enough as renames. Detecting renamed files this way
279 those similar enough as renames. Detecting renamed files this way
280 can be expensive. After using this option, :hg:`status -C` can be
280 can be expensive. After using this option, :hg:`status -C` can be
281 used to check which files were identified as moved or renamed. If
281 used to check which files were identified as moved or renamed. If
282 not specified, -s/--similarity defaults to 100 and only renames of
282 not specified, -s/--similarity defaults to 100 and only renames of
283 identical files are detected.
283 identical files are detected.
284
284
285 .. container:: verbose
285 .. container:: verbose
286
286
287 Examples:
287 Examples:
288
288
289 - A number of files (bar.c and foo.c) are new,
289 - A number of files (bar.c and foo.c) are new,
290 while foobar.c has been removed (without using :hg:`remove`)
290 while foobar.c has been removed (without using :hg:`remove`)
291 from the repository::
291 from the repository::
292
292
293 $ ls
293 $ ls
294 bar.c foo.c
294 bar.c foo.c
295 $ hg status
295 $ hg status
296 ! foobar.c
296 ! foobar.c
297 ? bar.c
297 ? bar.c
298 ? foo.c
298 ? foo.c
299 $ hg addremove
299 $ hg addremove
300 adding bar.c
300 adding bar.c
301 adding foo.c
301 adding foo.c
302 removing foobar.c
302 removing foobar.c
303 $ hg status
303 $ hg status
304 A bar.c
304 A bar.c
305 A foo.c
305 A foo.c
306 R foobar.c
306 R foobar.c
307
307
308 - A file foobar.c was moved to foo.c without using :hg:`rename`.
308 - A file foobar.c was moved to foo.c without using :hg:`rename`.
309 Afterwards, it was edited slightly::
309 Afterwards, it was edited slightly::
310
310
311 $ ls
311 $ ls
312 foo.c
312 foo.c
313 $ hg status
313 $ hg status
314 ! foobar.c
314 ! foobar.c
315 ? foo.c
315 ? foo.c
316 $ hg addremove --similarity 90
316 $ hg addremove --similarity 90
317 removing foobar.c
317 removing foobar.c
318 adding foo.c
318 adding foo.c
319 recording removal of foobar.c as rename to foo.c (94% similar)
319 recording removal of foobar.c as rename to foo.c (94% similar)
320 $ hg status -C
320 $ hg status -C
321 A foo.c
321 A foo.c
322 foobar.c
322 foobar.c
323 R foobar.c
323 R foobar.c
324
324
325 Returns 0 if all files are successfully added.
325 Returns 0 if all files are successfully added.
326 """
326 """
327 try:
327 try:
328 sim = float(opts.get('similarity') or 100)
328 sim = float(opts.get('similarity') or 100)
329 except ValueError:
329 except ValueError:
330 raise error.Abort(_('similarity must be a number'))
330 raise error.Abort(_('similarity must be a number'))
331 if sim < 0 or sim > 100:
331 if sim < 0 or sim > 100:
332 raise error.Abort(_('similarity must be between 0 and 100'))
332 raise error.Abort(_('similarity must be between 0 and 100'))
333 matcher = scmutil.match(repo[None], pats, opts)
333 matcher = scmutil.match(repo[None], pats, opts)
334 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
334 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
335
335
336 @command('^annotate|blame',
336 @command('^annotate|blame',
337 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
337 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
338 ('', 'follow', None,
338 ('', 'follow', None,
339 _('follow copies/renames and list the filename (DEPRECATED)')),
339 _('follow copies/renames and list the filename (DEPRECATED)')),
340 ('', 'no-follow', None, _("don't follow copies and renames")),
340 ('', 'no-follow', None, _("don't follow copies and renames")),
341 ('a', 'text', None, _('treat all files as text')),
341 ('a', 'text', None, _('treat all files as text')),
342 ('u', 'user', None, _('list the author (long with -v)')),
342 ('u', 'user', None, _('list the author (long with -v)')),
343 ('f', 'file', None, _('list the filename')),
343 ('f', 'file', None, _('list the filename')),
344 ('d', 'date', None, _('list the date (short with -q)')),
344 ('d', 'date', None, _('list the date (short with -q)')),
345 ('n', 'number', None, _('list the revision number (default)')),
345 ('n', 'number', None, _('list the revision number (default)')),
346 ('c', 'changeset', None, _('list the changeset')),
346 ('c', 'changeset', None, _('list the changeset')),
347 ('l', 'line-number', None, _('show line number at the first appearance'))
347 ('l', 'line-number', None, _('show line number at the first appearance'))
348 ] + diffwsopts + walkopts + formatteropts,
348 ] + diffwsopts + walkopts + formatteropts,
349 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
349 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
350 inferrepo=True)
350 inferrepo=True)
351 def annotate(ui, repo, *pats, **opts):
351 def annotate(ui, repo, *pats, **opts):
352 """show changeset information by line for each file
352 """show changeset information by line for each file
353
353
354 List changes in files, showing the revision id responsible for
354 List changes in files, showing the revision id responsible for
355 each line.
355 each line.
356
356
357 This command is useful for discovering when a change was made and
357 This command is useful for discovering when a change was made and
358 by whom.
358 by whom.
359
359
360 If you include --file, --user, or --date, the revision number is
360 If you include --file, --user, or --date, the revision number is
361 suppressed unless you also include --number.
361 suppressed unless you also include --number.
362
362
363 Without the -a/--text option, annotate will avoid processing files
363 Without the -a/--text option, annotate will avoid processing files
364 it detects as binary. With -a, annotate will annotate the file
364 it detects as binary. With -a, annotate will annotate the file
365 anyway, although the results will probably be neither useful
365 anyway, although the results will probably be neither useful
366 nor desirable.
366 nor desirable.
367
367
368 Returns 0 on success.
368 Returns 0 on success.
369 """
369 """
370 if not pats:
370 if not pats:
371 raise error.Abort(_('at least one filename or pattern is required'))
371 raise error.Abort(_('at least one filename or pattern is required'))
372
372
373 if opts.get('follow'):
373 if opts.get('follow'):
374 # --follow is deprecated and now just an alias for -f/--file
374 # --follow is deprecated and now just an alias for -f/--file
375 # to mimic the behavior of Mercurial before version 1.5
375 # to mimic the behavior of Mercurial before version 1.5
376 opts['file'] = True
376 opts['file'] = True
377
377
378 ctx = scmutil.revsingle(repo, opts.get('rev'))
378 ctx = scmutil.revsingle(repo, opts.get('rev'))
379
379
380 fm = ui.formatter('annotate', opts)
380 fm = ui.formatter('annotate', opts)
381 if ui.quiet:
381 if ui.quiet:
382 datefunc = util.shortdate
382 datefunc = util.shortdate
383 else:
383 else:
384 datefunc = util.datestr
384 datefunc = util.datestr
385 if ctx.rev() is None:
385 if ctx.rev() is None:
386 def hexfn(node):
386 def hexfn(node):
387 if node is None:
387 if node is None:
388 return None
388 return None
389 else:
389 else:
390 return fm.hexfunc(node)
390 return fm.hexfunc(node)
391 if opts.get('changeset'):
391 if opts.get('changeset'):
392 # omit "+" suffix which is appended to node hex
392 # omit "+" suffix which is appended to node hex
393 def formatrev(rev):
393 def formatrev(rev):
394 if rev is None:
394 if rev is None:
395 return '%d' % ctx.p1().rev()
395 return '%d' % ctx.p1().rev()
396 else:
396 else:
397 return '%d' % rev
397 return '%d' % rev
398 else:
398 else:
399 def formatrev(rev):
399 def formatrev(rev):
400 if rev is None:
400 if rev is None:
401 return '%d+' % ctx.p1().rev()
401 return '%d+' % ctx.p1().rev()
402 else:
402 else:
403 return '%d ' % rev
403 return '%d ' % rev
404 def formathex(hex):
404 def formathex(hex):
405 if hex is None:
405 if hex is None:
406 return '%s+' % fm.hexfunc(ctx.p1().node())
406 return '%s+' % fm.hexfunc(ctx.p1().node())
407 else:
407 else:
408 return '%s ' % hex
408 return '%s ' % hex
409 else:
409 else:
410 hexfn = fm.hexfunc
410 hexfn = fm.hexfunc
411 formatrev = formathex = str
411 formatrev = formathex = str
412
412
413 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
413 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
414 ('number', ' ', lambda x: x[0].rev(), formatrev),
414 ('number', ' ', lambda x: x[0].rev(), formatrev),
415 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
415 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
416 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
416 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
417 ('file', ' ', lambda x: x[0].path(), str),
417 ('file', ' ', lambda x: x[0].path(), str),
418 ('line_number', ':', lambda x: x[1], str),
418 ('line_number', ':', lambda x: x[1], str),
419 ]
419 ]
420 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
420 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
421
421
422 if (not opts.get('user') and not opts.get('changeset')
422 if (not opts.get('user') and not opts.get('changeset')
423 and not opts.get('date') and not opts.get('file')):
423 and not opts.get('date') and not opts.get('file')):
424 opts['number'] = True
424 opts['number'] = True
425
425
426 linenumber = opts.get('line_number') is not None
426 linenumber = opts.get('line_number') is not None
427 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
427 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
428 raise error.Abort(_('at least one of -n/-c is required for -l'))
428 raise error.Abort(_('at least one of -n/-c is required for -l'))
429
429
430 if fm.isplain():
430 if fm.isplain():
431 def makefunc(get, fmt):
431 def makefunc(get, fmt):
432 return lambda x: fmt(get(x))
432 return lambda x: fmt(get(x))
433 else:
433 else:
434 def makefunc(get, fmt):
434 def makefunc(get, fmt):
435 return get
435 return get
436 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
436 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
437 if opts.get(op)]
437 if opts.get(op)]
438 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
438 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
439 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
439 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
440 if opts.get(op))
440 if opts.get(op))
441
441
442 def bad(x, y):
442 def bad(x, y):
443 raise error.Abort("%s: %s" % (x, y))
443 raise error.Abort("%s: %s" % (x, y))
444
444
445 m = scmutil.match(ctx, pats, opts, badfn=bad)
445 m = scmutil.match(ctx, pats, opts, badfn=bad)
446
446
447 follow = not opts.get('no_follow')
447 follow = not opts.get('no_follow')
448 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
448 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
449 whitespace=True)
449 whitespace=True)
450 for abs in ctx.walk(m):
450 for abs in ctx.walk(m):
451 fctx = ctx[abs]
451 fctx = ctx[abs]
452 if not opts.get('text') and util.binary(fctx.data()):
452 if not opts.get('text') and util.binary(fctx.data()):
453 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
453 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
454 continue
454 continue
455
455
456 lines = fctx.annotate(follow=follow, linenumber=linenumber,
456 lines = fctx.annotate(follow=follow, linenumber=linenumber,
457 diffopts=diffopts)
457 diffopts=diffopts)
458 if not lines:
458 if not lines:
459 continue
459 continue
460 formats = []
460 formats = []
461 pieces = []
461 pieces = []
462
462
463 for f, sep in funcmap:
463 for f, sep in funcmap:
464 l = [f(n) for n, dummy in lines]
464 l = [f(n) for n, dummy in lines]
465 if fm.isplain():
465 if fm.isplain():
466 sizes = [encoding.colwidth(x) for x in l]
466 sizes = [encoding.colwidth(x) for x in l]
467 ml = max(sizes)
467 ml = max(sizes)
468 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
468 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
469 else:
469 else:
470 formats.append(['%s' for x in l])
470 formats.append(['%s' for x in l])
471 pieces.append(l)
471 pieces.append(l)
472
472
473 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
473 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
474 fm.startitem()
474 fm.startitem()
475 fm.write(fields, "".join(f), *p)
475 fm.write(fields, "".join(f), *p)
476 fm.write('line', ": %s", l[1])
476 fm.write('line', ": %s", l[1])
477
477
478 if not lines[-1][1].endswith('\n'):
478 if not lines[-1][1].endswith('\n'):
479 fm.plain('\n')
479 fm.plain('\n')
480
480
481 fm.end()
481 fm.end()
482
482
483 @command('archive',
483 @command('archive',
484 [('', 'no-decode', None, _('do not pass files through decoders')),
484 [('', 'no-decode', None, _('do not pass files through decoders')),
485 ('p', 'prefix', '', _('directory prefix for files in archive'),
485 ('p', 'prefix', '', _('directory prefix for files in archive'),
486 _('PREFIX')),
486 _('PREFIX')),
487 ('r', 'rev', '', _('revision to distribute'), _('REV')),
487 ('r', 'rev', '', _('revision to distribute'), _('REV')),
488 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
488 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
489 ] + subrepoopts + walkopts,
489 ] + subrepoopts + walkopts,
490 _('[OPTION]... DEST'))
490 _('[OPTION]... DEST'))
491 def archive(ui, repo, dest, **opts):
491 def archive(ui, repo, dest, **opts):
492 '''create an unversioned archive of a repository revision
492 '''create an unversioned archive of a repository revision
493
493
494 By default, the revision used is the parent of the working
494 By default, the revision used is the parent of the working
495 directory; use -r/--rev to specify a different revision.
495 directory; use -r/--rev to specify a different revision.
496
496
497 The archive type is automatically detected based on file
497 The archive type is automatically detected based on file
498 extension (to override, use -t/--type).
498 extension (to override, use -t/--type).
499
499
500 .. container:: verbose
500 .. container:: verbose
501
501
502 Examples:
502 Examples:
503
503
504 - create a zip file containing the 1.0 release::
504 - create a zip file containing the 1.0 release::
505
505
506 hg archive -r 1.0 project-1.0.zip
506 hg archive -r 1.0 project-1.0.zip
507
507
508 - create a tarball excluding .hg files::
508 - create a tarball excluding .hg files::
509
509
510 hg archive project.tar.gz -X ".hg*"
510 hg archive project.tar.gz -X ".hg*"
511
511
512 Valid types are:
512 Valid types are:
513
513
514 :``files``: a directory full of files (default)
514 :``files``: a directory full of files (default)
515 :``tar``: tar archive, uncompressed
515 :``tar``: tar archive, uncompressed
516 :``tbz2``: tar archive, compressed using bzip2
516 :``tbz2``: tar archive, compressed using bzip2
517 :``tgz``: tar archive, compressed using gzip
517 :``tgz``: tar archive, compressed using gzip
518 :``uzip``: zip archive, uncompressed
518 :``uzip``: zip archive, uncompressed
519 :``zip``: zip archive, compressed using deflate
519 :``zip``: zip archive, compressed using deflate
520
520
521 The exact name of the destination archive or directory is given
521 The exact name of the destination archive or directory is given
522 using a format string; see :hg:`help export` for details.
522 using a format string; see :hg:`help export` for details.
523
523
524 Each member added to an archive file has a directory prefix
524 Each member added to an archive file has a directory prefix
525 prepended. Use -p/--prefix to specify a format string for the
525 prepended. Use -p/--prefix to specify a format string for the
526 prefix. The default is the basename of the archive, with suffixes
526 prefix. The default is the basename of the archive, with suffixes
527 removed.
527 removed.
528
528
529 Returns 0 on success.
529 Returns 0 on success.
530 '''
530 '''
531
531
532 ctx = scmutil.revsingle(repo, opts.get('rev'))
532 ctx = scmutil.revsingle(repo, opts.get('rev'))
533 if not ctx:
533 if not ctx:
534 raise error.Abort(_('no working directory: please specify a revision'))
534 raise error.Abort(_('no working directory: please specify a revision'))
535 node = ctx.node()
535 node = ctx.node()
536 dest = cmdutil.makefilename(repo, dest, node)
536 dest = cmdutil.makefilename(repo, dest, node)
537 if os.path.realpath(dest) == repo.root:
537 if os.path.realpath(dest) == repo.root:
538 raise error.Abort(_('repository root cannot be destination'))
538 raise error.Abort(_('repository root cannot be destination'))
539
539
540 kind = opts.get('type') or archival.guesskind(dest) or 'files'
540 kind = opts.get('type') or archival.guesskind(dest) or 'files'
541 prefix = opts.get('prefix')
541 prefix = opts.get('prefix')
542
542
543 if dest == '-':
543 if dest == '-':
544 if kind == 'files':
544 if kind == 'files':
545 raise error.Abort(_('cannot archive plain files to stdout'))
545 raise error.Abort(_('cannot archive plain files to stdout'))
546 dest = cmdutil.makefileobj(repo, dest)
546 dest = cmdutil.makefileobj(repo, dest)
547 if not prefix:
547 if not prefix:
548 prefix = os.path.basename(repo.root) + '-%h'
548 prefix = os.path.basename(repo.root) + '-%h'
549
549
550 prefix = cmdutil.makefilename(repo, prefix, node)
550 prefix = cmdutil.makefilename(repo, prefix, node)
551 matchfn = scmutil.match(ctx, [], opts)
551 matchfn = scmutil.match(ctx, [], opts)
552 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
552 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
553 matchfn, prefix, subrepos=opts.get('subrepos'))
553 matchfn, prefix, subrepos=opts.get('subrepos'))
554
554
555 @command('backout',
555 @command('backout',
556 [('', 'merge', None, _('merge with old dirstate parent after backout')),
556 [('', 'merge', None, _('merge with old dirstate parent after backout')),
557 ('', 'commit', None,
557 ('', 'commit', None,
558 _('commit if no conflicts were encountered (DEPRECATED)')),
558 _('commit if no conflicts were encountered (DEPRECATED)')),
559 ('', 'no-commit', None, _('do not commit')),
559 ('', 'no-commit', None, _('do not commit')),
560 ('', 'parent', '',
560 ('', 'parent', '',
561 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
561 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
562 ('r', 'rev', '', _('revision to backout'), _('REV')),
562 ('r', 'rev', '', _('revision to backout'), _('REV')),
563 ('e', 'edit', False, _('invoke editor on commit messages')),
563 ('e', 'edit', False, _('invoke editor on commit messages')),
564 ] + mergetoolopts + walkopts + commitopts + commitopts2,
564 ] + mergetoolopts + walkopts + commitopts + commitopts2,
565 _('[OPTION]... [-r] REV'))
565 _('[OPTION]... [-r] REV'))
566 def backout(ui, repo, node=None, rev=None, **opts):
566 def backout(ui, repo, node=None, rev=None, **opts):
567 '''reverse effect of earlier changeset
567 '''reverse effect of earlier changeset
568
568
569 Prepare a new changeset with the effect of REV undone in the
569 Prepare a new changeset with the effect of REV undone in the
570 current working directory. If no conflicts were encountered,
570 current working directory. If no conflicts were encountered,
571 it will be committed immediately.
571 it will be committed immediately.
572
572
573 If REV is the parent of the working directory, then this new changeset
573 If REV is the parent of the working directory, then this new changeset
574 is committed automatically (unless --no-commit is specified).
574 is committed automatically (unless --no-commit is specified).
575
575
576 .. note::
576 .. note::
577
577
578 :hg:`backout` cannot be used to fix either an unwanted or
578 :hg:`backout` cannot be used to fix either an unwanted or
579 incorrect merge.
579 incorrect merge.
580
580
581 .. container:: verbose
581 .. container:: verbose
582
582
583 Examples:
583 Examples:
584
584
585 - Reverse the effect of the parent of the working directory.
585 - Reverse the effect of the parent of the working directory.
586 This backout will be committed immediately::
586 This backout will be committed immediately::
587
587
588 hg backout -r .
588 hg backout -r .
589
589
590 - Reverse the effect of previous bad revision 23::
590 - Reverse the effect of previous bad revision 23::
591
591
592 hg backout -r 23
592 hg backout -r 23
593
593
594 - Reverse the effect of previous bad revision 23 and
594 - Reverse the effect of previous bad revision 23 and
595 leave changes uncommitted::
595 leave changes uncommitted::
596
596
597 hg backout -r 23 --no-commit
597 hg backout -r 23 --no-commit
598 hg commit -m "Backout revision 23"
598 hg commit -m "Backout revision 23"
599
599
600 By default, the pending changeset will have one parent,
600 By default, the pending changeset will have one parent,
601 maintaining a linear history. With --merge, the pending
601 maintaining a linear history. With --merge, the pending
602 changeset will instead have two parents: the old parent of the
602 changeset will instead have two parents: the old parent of the
603 working directory and a new child of REV that simply undoes REV.
603 working directory and a new child of REV that simply undoes REV.
604
604
605 Before version 1.7, the behavior without --merge was equivalent
605 Before version 1.7, the behavior without --merge was equivalent
606 to specifying --merge followed by :hg:`update --clean .` to
606 to specifying --merge followed by :hg:`update --clean .` to
607 cancel the merge and leave the child of REV as a head to be
607 cancel the merge and leave the child of REV as a head to be
608 merged separately.
608 merged separately.
609
609
610 See :hg:`help dates` for a list of formats valid for -d/--date.
610 See :hg:`help dates` for a list of formats valid for -d/--date.
611
611
612 See :hg:`help revert` for a way to restore files to the state
612 See :hg:`help revert` for a way to restore files to the state
613 of another revision.
613 of another revision.
614
614
615 Returns 0 on success, 1 if nothing to backout or there are unresolved
615 Returns 0 on success, 1 if nothing to backout or there are unresolved
616 files.
616 files.
617 '''
617 '''
618 wlock = lock = None
618 wlock = lock = None
619 try:
619 try:
620 wlock = repo.wlock()
620 wlock = repo.wlock()
621 lock = repo.lock()
621 lock = repo.lock()
622 return _dobackout(ui, repo, node, rev, **opts)
622 return _dobackout(ui, repo, node, rev, **opts)
623 finally:
623 finally:
624 release(lock, wlock)
624 release(lock, wlock)
625
625
626 def _dobackout(ui, repo, node=None, rev=None, **opts):
626 def _dobackout(ui, repo, node=None, rev=None, **opts):
627 if opts.get('commit') and opts.get('no_commit'):
627 if opts.get('commit') and opts.get('no_commit'):
628 raise error.Abort(_("cannot use --commit with --no-commit"))
628 raise error.Abort(_("cannot use --commit with --no-commit"))
629 if opts.get('merge') and opts.get('no_commit'):
629 if opts.get('merge') and opts.get('no_commit'):
630 raise error.Abort(_("cannot use --merge with --no-commit"))
630 raise error.Abort(_("cannot use --merge with --no-commit"))
631
631
632 if rev and node:
632 if rev and node:
633 raise error.Abort(_("please specify just one revision"))
633 raise error.Abort(_("please specify just one revision"))
634
634
635 if not rev:
635 if not rev:
636 rev = node
636 rev = node
637
637
638 if not rev:
638 if not rev:
639 raise error.Abort(_("please specify a revision to backout"))
639 raise error.Abort(_("please specify a revision to backout"))
640
640
641 date = opts.get('date')
641 date = opts.get('date')
642 if date:
642 if date:
643 opts['date'] = util.parsedate(date)
643 opts['date'] = util.parsedate(date)
644
644
645 cmdutil.checkunfinished(repo)
645 cmdutil.checkunfinished(repo)
646 cmdutil.bailifchanged(repo)
646 cmdutil.bailifchanged(repo)
647 node = scmutil.revsingle(repo, rev).node()
647 node = scmutil.revsingle(repo, rev).node()
648
648
649 op1, op2 = repo.dirstate.parents()
649 op1, op2 = repo.dirstate.parents()
650 if not repo.changelog.isancestor(node, op1):
650 if not repo.changelog.isancestor(node, op1):
651 raise error.Abort(_('cannot backout change that is not an ancestor'))
651 raise error.Abort(_('cannot backout change that is not an ancestor'))
652
652
653 p1, p2 = repo.changelog.parents(node)
653 p1, p2 = repo.changelog.parents(node)
654 if p1 == nullid:
654 if p1 == nullid:
655 raise error.Abort(_('cannot backout a change with no parents'))
655 raise error.Abort(_('cannot backout a change with no parents'))
656 if p2 != nullid:
656 if p2 != nullid:
657 if not opts.get('parent'):
657 if not opts.get('parent'):
658 raise error.Abort(_('cannot backout a merge changeset'))
658 raise error.Abort(_('cannot backout a merge changeset'))
659 p = repo.lookup(opts['parent'])
659 p = repo.lookup(opts['parent'])
660 if p not in (p1, p2):
660 if p not in (p1, p2):
661 raise error.Abort(_('%s is not a parent of %s') %
661 raise error.Abort(_('%s is not a parent of %s') %
662 (short(p), short(node)))
662 (short(p), short(node)))
663 parent = p
663 parent = p
664 else:
664 else:
665 if opts.get('parent'):
665 if opts.get('parent'):
666 raise error.Abort(_('cannot use --parent on non-merge changeset'))
666 raise error.Abort(_('cannot use --parent on non-merge changeset'))
667 parent = p1
667 parent = p1
668
668
669 # the backout should appear on the same branch
669 # the backout should appear on the same branch
670 branch = repo.dirstate.branch()
670 branch = repo.dirstate.branch()
671 bheads = repo.branchheads(branch)
671 bheads = repo.branchheads(branch)
672 rctx = scmutil.revsingle(repo, hex(parent))
672 rctx = scmutil.revsingle(repo, hex(parent))
673 if not opts.get('merge') and op1 != node:
673 if not opts.get('merge') and op1 != node:
674 dsguard = dirstateguard.dirstateguard(repo, 'backout')
674 dsguard = dirstateguard.dirstateguard(repo, 'backout')
675 try:
675 try:
676 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
676 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
677 'backout')
677 'backout')
678 stats = mergemod.update(repo, parent, True, True, node, False)
678 stats = mergemod.update(repo, parent, True, True, node, False)
679 repo.setparents(op1, op2)
679 repo.setparents(op1, op2)
680 dsguard.close()
680 dsguard.close()
681 hg._showstats(repo, stats)
681 hg._showstats(repo, stats)
682 if stats[3]:
682 if stats[3]:
683 repo.ui.status(_("use 'hg resolve' to retry unresolved "
683 repo.ui.status(_("use 'hg resolve' to retry unresolved "
684 "file merges\n"))
684 "file merges\n"))
685 return 1
685 return 1
686 finally:
686 finally:
687 ui.setconfig('ui', 'forcemerge', '', '')
687 ui.setconfig('ui', 'forcemerge', '', '')
688 lockmod.release(dsguard)
688 lockmod.release(dsguard)
689 else:
689 else:
690 hg.clean(repo, node, show_stats=False)
690 hg.clean(repo, node, show_stats=False)
691 repo.dirstate.setbranch(branch)
691 repo.dirstate.setbranch(branch)
692 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
692 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
693
693
694 if opts.get('no_commit'):
694 if opts.get('no_commit'):
695 msg = _("changeset %s backed out, "
695 msg = _("changeset %s backed out, "
696 "don't forget to commit.\n")
696 "don't forget to commit.\n")
697 ui.status(msg % short(node))
697 ui.status(msg % short(node))
698 return 0
698 return 0
699
699
700 def commitfunc(ui, repo, message, match, opts):
700 def commitfunc(ui, repo, message, match, opts):
701 editform = 'backout'
701 editform = 'backout'
702 e = cmdutil.getcommiteditor(editform=editform, **opts)
702 e = cmdutil.getcommiteditor(editform=editform, **opts)
703 if not message:
703 if not message:
704 # we don't translate commit messages
704 # we don't translate commit messages
705 message = "Backed out changeset %s" % short(node)
705 message = "Backed out changeset %s" % short(node)
706 e = cmdutil.getcommiteditor(edit=True, editform=editform)
706 e = cmdutil.getcommiteditor(edit=True, editform=editform)
707 return repo.commit(message, opts.get('user'), opts.get('date'),
707 return repo.commit(message, opts.get('user'), opts.get('date'),
708 match, editor=e)
708 match, editor=e)
709 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
709 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
710 if not newnode:
710 if not newnode:
711 ui.status(_("nothing changed\n"))
711 ui.status(_("nothing changed\n"))
712 return 1
712 return 1
713 cmdutil.commitstatus(repo, newnode, branch, bheads)
713 cmdutil.commitstatus(repo, newnode, branch, bheads)
714
714
715 def nice(node):
715 def nice(node):
716 return '%d:%s' % (repo.changelog.rev(node), short(node))
716 return '%d:%s' % (repo.changelog.rev(node), short(node))
717 ui.status(_('changeset %s backs out changeset %s\n') %
717 ui.status(_('changeset %s backs out changeset %s\n') %
718 (nice(repo.changelog.tip()), nice(node)))
718 (nice(repo.changelog.tip()), nice(node)))
719 if opts.get('merge') and op1 != node:
719 if opts.get('merge') and op1 != node:
720 hg.clean(repo, op1, show_stats=False)
720 hg.clean(repo, op1, show_stats=False)
721 ui.status(_('merging with changeset %s\n')
721 ui.status(_('merging with changeset %s\n')
722 % nice(repo.changelog.tip()))
722 % nice(repo.changelog.tip()))
723 try:
723 try:
724 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
724 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
725 'backout')
725 'backout')
726 return hg.merge(repo, hex(repo.changelog.tip()))
726 return hg.merge(repo, hex(repo.changelog.tip()))
727 finally:
727 finally:
728 ui.setconfig('ui', 'forcemerge', '', '')
728 ui.setconfig('ui', 'forcemerge', '', '')
729 return 0
729 return 0
730
730
731 @command('bisect',
731 @command('bisect',
732 [('r', 'reset', False, _('reset bisect state')),
732 [('r', 'reset', False, _('reset bisect state')),
733 ('g', 'good', False, _('mark changeset good')),
733 ('g', 'good', False, _('mark changeset good')),
734 ('b', 'bad', False, _('mark changeset bad')),
734 ('b', 'bad', False, _('mark changeset bad')),
735 ('s', 'skip', False, _('skip testing changeset')),
735 ('s', 'skip', False, _('skip testing changeset')),
736 ('e', 'extend', False, _('extend the bisect range')),
736 ('e', 'extend', False, _('extend the bisect range')),
737 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
737 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
738 ('U', 'noupdate', False, _('do not update to target'))],
738 ('U', 'noupdate', False, _('do not update to target'))],
739 _("[-gbsr] [-U] [-c CMD] [REV]"))
739 _("[-gbsr] [-U] [-c CMD] [REV]"))
740 def bisect(ui, repo, rev=None, extra=None, command=None,
740 def bisect(ui, repo, rev=None, extra=None, command=None,
741 reset=None, good=None, bad=None, skip=None, extend=None,
741 reset=None, good=None, bad=None, skip=None, extend=None,
742 noupdate=None):
742 noupdate=None):
743 """subdivision search of changesets
743 """subdivision search of changesets
744
744
745 This command helps to find changesets which introduce problems. To
745 This command helps to find changesets which introduce problems. To
746 use, mark the earliest changeset you know exhibits the problem as
746 use, mark the earliest changeset you know exhibits the problem as
747 bad, then mark the latest changeset which is free from the problem
747 bad, then mark the latest changeset which is free from the problem
748 as good. Bisect will update your working directory to a revision
748 as good. Bisect will update your working directory to a revision
749 for testing (unless the -U/--noupdate option is specified). Once
749 for testing (unless the -U/--noupdate option is specified). Once
750 you have performed tests, mark the working directory as good or
750 you have performed tests, mark the working directory as good or
751 bad, and bisect will either update to another candidate changeset
751 bad, and bisect will either update to another candidate changeset
752 or announce that it has found the bad revision.
752 or announce that it has found the bad revision.
753
753
754 As a shortcut, you can also use the revision argument to mark a
754 As a shortcut, you can also use the revision argument to mark a
755 revision as good or bad without checking it out first.
755 revision as good or bad without checking it out first.
756
756
757 If you supply a command, it will be used for automatic bisection.
757 If you supply a command, it will be used for automatic bisection.
758 The environment variable HG_NODE will contain the ID of the
758 The environment variable HG_NODE will contain the ID of the
759 changeset being tested. The exit status of the command will be
759 changeset being tested. The exit status of the command will be
760 used to mark revisions as good or bad: status 0 means good, 125
760 used to mark revisions as good or bad: status 0 means good, 125
761 means to skip the revision, 127 (command not found) will abort the
761 means to skip the revision, 127 (command not found) will abort the
762 bisection, and any other non-zero exit status means the revision
762 bisection, and any other non-zero exit status means the revision
763 is bad.
763 is bad.
764
764
765 .. container:: verbose
765 .. container:: verbose
766
766
767 Some examples:
767 Some examples:
768
768
769 - start a bisection with known bad revision 34, and good revision 12::
769 - start a bisection with known bad revision 34, and good revision 12::
770
770
771 hg bisect --bad 34
771 hg bisect --bad 34
772 hg bisect --good 12
772 hg bisect --good 12
773
773
774 - advance the current bisection by marking current revision as good or
774 - advance the current bisection by marking current revision as good or
775 bad::
775 bad::
776
776
777 hg bisect --good
777 hg bisect --good
778 hg bisect --bad
778 hg bisect --bad
779
779
780 - mark the current revision, or a known revision, to be skipped (e.g. if
780 - mark the current revision, or a known revision, to be skipped (e.g. if
781 that revision is not usable because of another issue)::
781 that revision is not usable because of another issue)::
782
782
783 hg bisect --skip
783 hg bisect --skip
784 hg bisect --skip 23
784 hg bisect --skip 23
785
785
786 - skip all revisions that do not touch directories ``foo`` or ``bar``::
786 - skip all revisions that do not touch directories ``foo`` or ``bar``::
787
787
788 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
788 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
789
789
790 - forget the current bisection::
790 - forget the current bisection::
791
791
792 hg bisect --reset
792 hg bisect --reset
793
793
794 - use 'make && make tests' to automatically find the first broken
794 - use 'make && make tests' to automatically find the first broken
795 revision::
795 revision::
796
796
797 hg bisect --reset
797 hg bisect --reset
798 hg bisect --bad 34
798 hg bisect --bad 34
799 hg bisect --good 12
799 hg bisect --good 12
800 hg bisect --command "make && make tests"
800 hg bisect --command "make && make tests"
801
801
802 - see all changesets whose states are already known in the current
802 - see all changesets whose states are already known in the current
803 bisection::
803 bisection::
804
804
805 hg log -r "bisect(pruned)"
805 hg log -r "bisect(pruned)"
806
806
807 - see the changeset currently being bisected (especially useful
807 - see the changeset currently being bisected (especially useful
808 if running with -U/--noupdate)::
808 if running with -U/--noupdate)::
809
809
810 hg log -r "bisect(current)"
810 hg log -r "bisect(current)"
811
811
812 - see all changesets that took part in the current bisection::
812 - see all changesets that took part in the current bisection::
813
813
814 hg log -r "bisect(range)"
814 hg log -r "bisect(range)"
815
815
816 - you can even get a nice graph::
816 - you can even get a nice graph::
817
817
818 hg log --graph -r "bisect(range)"
818 hg log --graph -r "bisect(range)"
819
819
820 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
820 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
821
821
822 Returns 0 on success.
822 Returns 0 on success.
823 """
823 """
824 # backward compatibility
824 # backward compatibility
825 if rev in "good bad reset init".split():
825 if rev in "good bad reset init".split():
826 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
826 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
827 cmd, rev, extra = rev, extra, None
827 cmd, rev, extra = rev, extra, None
828 if cmd == "good":
828 if cmd == "good":
829 good = True
829 good = True
830 elif cmd == "bad":
830 elif cmd == "bad":
831 bad = True
831 bad = True
832 else:
832 else:
833 reset = True
833 reset = True
834 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
834 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
835 raise error.Abort(_('incompatible arguments'))
835 raise error.Abort(_('incompatible arguments'))
836
836
837 cmdutil.checkunfinished(repo)
837 cmdutil.checkunfinished(repo)
838
838
839 if reset:
839 if reset:
840 hbisect.resetstate(repo)
840 hbisect.resetstate(repo)
841 return
841 return
842
842
843 state = hbisect.load_state(repo)
843 state = hbisect.load_state(repo)
844
844
845 # update state
845 # update state
846 if good or bad or skip:
846 if good or bad or skip:
847 if rev:
847 if rev:
848 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
848 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
849 else:
849 else:
850 nodes = [repo.lookup('.')]
850 nodes = [repo.lookup('.')]
851 if good:
851 if good:
852 state['good'] += nodes
852 state['good'] += nodes
853 elif bad:
853 elif bad:
854 state['bad'] += nodes
854 state['bad'] += nodes
855 elif skip:
855 elif skip:
856 state['skip'] += nodes
856 state['skip'] += nodes
857 hbisect.save_state(repo, state)
857 hbisect.save_state(repo, state)
858 if not (state['good'] and state['bad']):
858 if not (state['good'] and state['bad']):
859 return
859 return
860
860
861 def mayupdate(repo, node, show_stats=True):
861 def mayupdate(repo, node, show_stats=True):
862 """common used update sequence"""
862 """common used update sequence"""
863 if noupdate:
863 if noupdate:
864 return
864 return
865 cmdutil.bailifchanged(repo)
865 cmdutil.bailifchanged(repo)
866 return hg.clean(repo, node, show_stats=show_stats)
866 return hg.clean(repo, node, show_stats=show_stats)
867
867
868 displayer = cmdutil.show_changeset(ui, repo, {})
868 displayer = cmdutil.show_changeset(ui, repo, {})
869
869
870 if command:
870 if command:
871 changesets = 1
871 changesets = 1
872 if noupdate:
872 if noupdate:
873 try:
873 try:
874 node = state['current'][0]
874 node = state['current'][0]
875 except LookupError:
875 except LookupError:
876 raise error.Abort(_('current bisect revision is unknown - '
876 raise error.Abort(_('current bisect revision is unknown - '
877 'start a new bisect to fix'))
877 'start a new bisect to fix'))
878 else:
878 else:
879 node, p2 = repo.dirstate.parents()
879 node, p2 = repo.dirstate.parents()
880 if p2 != nullid:
880 if p2 != nullid:
881 raise error.Abort(_('current bisect revision is a merge'))
881 raise error.Abort(_('current bisect revision is a merge'))
882 if rev:
882 if rev:
883 node = repo[scmutil.revsingle(repo, rev, node)].node()
883 node = repo[scmutil.revsingle(repo, rev, node)].node()
884 try:
884 try:
885 while changesets:
885 while changesets:
886 # update state
886 # update state
887 state['current'] = [node]
887 state['current'] = [node]
888 hbisect.save_state(repo, state)
888 hbisect.save_state(repo, state)
889 status = ui.system(command, environ={'HG_NODE': hex(node)})
889 status = ui.system(command, environ={'HG_NODE': hex(node)})
890 if status == 125:
890 if status == 125:
891 transition = "skip"
891 transition = "skip"
892 elif status == 0:
892 elif status == 0:
893 transition = "good"
893 transition = "good"
894 # status < 0 means process was killed
894 # status < 0 means process was killed
895 elif status == 127:
895 elif status == 127:
896 raise error.Abort(_("failed to execute %s") % command)
896 raise error.Abort(_("failed to execute %s") % command)
897 elif status < 0:
897 elif status < 0:
898 raise error.Abort(_("%s killed") % command)
898 raise error.Abort(_("%s killed") % command)
899 else:
899 else:
900 transition = "bad"
900 transition = "bad"
901 state[transition].append(node)
901 state[transition].append(node)
902 ctx = repo[node]
902 ctx = repo[node]
903 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
903 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
904 hbisect.checkstate(state)
904 hbisect.checkstate(state)
905 # bisect
905 # bisect
906 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
906 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
907 # update to next check
907 # update to next check
908 node = nodes[0]
908 node = nodes[0]
909 mayupdate(repo, node, show_stats=False)
909 mayupdate(repo, node, show_stats=False)
910 finally:
910 finally:
911 state['current'] = [node]
911 state['current'] = [node]
912 hbisect.save_state(repo, state)
912 hbisect.save_state(repo, state)
913 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
913 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
914 return
914 return
915
915
916 hbisect.checkstate(state)
916 hbisect.checkstate(state)
917
917
918 # actually bisect
918 # actually bisect
919 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
919 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
920 if extend:
920 if extend:
921 if not changesets:
921 if not changesets:
922 extendnode = hbisect.extendrange(repo, state, nodes, good)
922 extendnode = hbisect.extendrange(repo, state, nodes, good)
923 if extendnode is not None:
923 if extendnode is not None:
924 ui.write(_("Extending search to changeset %d:%s\n")
924 ui.write(_("Extending search to changeset %d:%s\n")
925 % (extendnode.rev(), extendnode))
925 % (extendnode.rev(), extendnode))
926 state['current'] = [extendnode.node()]
926 state['current'] = [extendnode.node()]
927 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
928 return mayupdate(repo, extendnode.node())
928 return mayupdate(repo, extendnode.node())
929 raise error.Abort(_("nothing to extend"))
929 raise error.Abort(_("nothing to extend"))
930
930
931 if changesets == 0:
931 if changesets == 0:
932 hbisect.printresult(ui, repo, state, displayer, nodes, good)
932 hbisect.printresult(ui, repo, state, displayer, nodes, good)
933 else:
933 else:
934 assert len(nodes) == 1 # only a single node can be tested next
934 assert len(nodes) == 1 # only a single node can be tested next
935 node = nodes[0]
935 node = nodes[0]
936 # compute the approximate number of remaining tests
936 # compute the approximate number of remaining tests
937 tests, size = 0, 2
937 tests, size = 0, 2
938 while size <= changesets:
938 while size <= changesets:
939 tests, size = tests + 1, size * 2
939 tests, size = tests + 1, size * 2
940 rev = repo.changelog.rev(node)
940 rev = repo.changelog.rev(node)
941 ui.write(_("Testing changeset %d:%s "
941 ui.write(_("Testing changeset %d:%s "
942 "(%d changesets remaining, ~%d tests)\n")
942 "(%d changesets remaining, ~%d tests)\n")
943 % (rev, short(node), changesets, tests))
943 % (rev, short(node), changesets, tests))
944 state['current'] = [node]
944 state['current'] = [node]
945 hbisect.save_state(repo, state)
945 hbisect.save_state(repo, state)
946 return mayupdate(repo, node)
946 return mayupdate(repo, node)
947
947
948 @command('bookmarks|bookmark',
948 @command('bookmarks|bookmark',
949 [('f', 'force', False, _('force')),
949 [('f', 'force', False, _('force')),
950 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
950 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
951 ('d', 'delete', False, _('delete a given bookmark')),
951 ('d', 'delete', False, _('delete a given bookmark')),
952 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
952 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
953 ('i', 'inactive', False, _('mark a bookmark inactive')),
953 ('i', 'inactive', False, _('mark a bookmark inactive')),
954 ] + formatteropts,
954 ] + formatteropts,
955 _('hg bookmarks [OPTIONS]... [NAME]...'))
955 _('hg bookmarks [OPTIONS]... [NAME]...'))
956 def bookmark(ui, repo, *names, **opts):
956 def bookmark(ui, repo, *names, **opts):
957 '''create a new bookmark or list existing bookmarks
957 '''create a new bookmark or list existing bookmarks
958
958
959 Bookmarks are labels on changesets to help track lines of development.
959 Bookmarks are labels on changesets to help track lines of development.
960 Bookmarks are unversioned and can be moved, renamed and deleted.
960 Bookmarks are unversioned and can be moved, renamed and deleted.
961 Deleting or moving a bookmark has no effect on the associated changesets.
961 Deleting or moving a bookmark has no effect on the associated changesets.
962
962
963 Creating or updating to a bookmark causes it to be marked as 'active'.
963 Creating or updating to a bookmark causes it to be marked as 'active'.
964 The active bookmark is indicated with a '*'.
964 The active bookmark is indicated with a '*'.
965 When a commit is made, the active bookmark will advance to the new commit.
965 When a commit is made, the active bookmark will advance to the new commit.
966 A plain :hg:`update` will also advance an active bookmark, if possible.
966 A plain :hg:`update` will also advance an active bookmark, if possible.
967 Updating away from a bookmark will cause it to be deactivated.
967 Updating away from a bookmark will cause it to be deactivated.
968
968
969 Bookmarks can be pushed and pulled between repositories (see
969 Bookmarks can be pushed and pulled between repositories (see
970 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
970 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
971 diverged, a new 'divergent bookmark' of the form 'name@path' will
971 diverged, a new 'divergent bookmark' of the form 'name@path' will
972 be created. Using :hg:`merge` will resolve the divergence.
972 be created. Using :hg:`merge` will resolve the divergence.
973
973
974 A bookmark named '@' has the special property that :hg:`clone` will
974 A bookmark named '@' has the special property that :hg:`clone` will
975 check it out by default if it exists.
975 check it out by default if it exists.
976
976
977 .. container:: verbose
977 .. container:: verbose
978
978
979 Examples:
979 Examples:
980
980
981 - create an active bookmark for a new line of development::
981 - create an active bookmark for a new line of development::
982
982
983 hg book new-feature
983 hg book new-feature
984
984
985 - create an inactive bookmark as a place marker::
985 - create an inactive bookmark as a place marker::
986
986
987 hg book -i reviewed
987 hg book -i reviewed
988
988
989 - create an inactive bookmark on another changeset::
989 - create an inactive bookmark on another changeset::
990
990
991 hg book -r .^ tested
991 hg book -r .^ tested
992
992
993 - rename bookmark turkey to dinner::
993 - rename bookmark turkey to dinner::
994
994
995 hg book -m turkey dinner
995 hg book -m turkey dinner
996
996
997 - move the '@' bookmark from another branch::
997 - move the '@' bookmark from another branch::
998
998
999 hg book -f @
999 hg book -f @
1000 '''
1000 '''
1001 force = opts.get('force')
1001 force = opts.get('force')
1002 rev = opts.get('rev')
1002 rev = opts.get('rev')
1003 delete = opts.get('delete')
1003 delete = opts.get('delete')
1004 rename = opts.get('rename')
1004 rename = opts.get('rename')
1005 inactive = opts.get('inactive')
1005 inactive = opts.get('inactive')
1006
1006
1007 def checkformat(mark):
1007 def checkformat(mark):
1008 mark = mark.strip()
1008 mark = mark.strip()
1009 if not mark:
1009 if not mark:
1010 raise error.Abort(_("bookmark names cannot consist entirely of "
1010 raise error.Abort(_("bookmark names cannot consist entirely of "
1011 "whitespace"))
1011 "whitespace"))
1012 scmutil.checknewlabel(repo, mark, 'bookmark')
1012 scmutil.checknewlabel(repo, mark, 'bookmark')
1013 return mark
1013 return mark
1014
1014
1015 def checkconflict(repo, mark, cur, force=False, target=None):
1015 def checkconflict(repo, mark, cur, force=False, target=None):
1016 if mark in marks and not force:
1016 if mark in marks and not force:
1017 if target:
1017 if target:
1018 if marks[mark] == target and target == cur:
1018 if marks[mark] == target and target == cur:
1019 # re-activating a bookmark
1019 # re-activating a bookmark
1020 return
1020 return
1021 anc = repo.changelog.ancestors([repo[target].rev()])
1021 anc = repo.changelog.ancestors([repo[target].rev()])
1022 bmctx = repo[marks[mark]]
1022 bmctx = repo[marks[mark]]
1023 divs = [repo[b].node() for b in marks
1023 divs = [repo[b].node() for b in marks
1024 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1024 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1025
1025
1026 # allow resolving a single divergent bookmark even if moving
1026 # allow resolving a single divergent bookmark even if moving
1027 # the bookmark across branches when a revision is specified
1027 # the bookmark across branches when a revision is specified
1028 # that contains a divergent bookmark
1028 # that contains a divergent bookmark
1029 if bmctx.rev() not in anc and target in divs:
1029 if bmctx.rev() not in anc and target in divs:
1030 bookmarks.deletedivergent(repo, [target], mark)
1030 bookmarks.deletedivergent(repo, [target], mark)
1031 return
1031 return
1032
1032
1033 deletefrom = [b for b in divs
1033 deletefrom = [b for b in divs
1034 if repo[b].rev() in anc or b == target]
1034 if repo[b].rev() in anc or b == target]
1035 bookmarks.deletedivergent(repo, deletefrom, mark)
1035 bookmarks.deletedivergent(repo, deletefrom, mark)
1036 if bookmarks.validdest(repo, bmctx, repo[target]):
1036 if bookmarks.validdest(repo, bmctx, repo[target]):
1037 ui.status(_("moving bookmark '%s' forward from %s\n") %
1037 ui.status(_("moving bookmark '%s' forward from %s\n") %
1038 (mark, short(bmctx.node())))
1038 (mark, short(bmctx.node())))
1039 return
1039 return
1040 raise error.Abort(_("bookmark '%s' already exists "
1040 raise error.Abort(_("bookmark '%s' already exists "
1041 "(use -f to force)") % mark)
1041 "(use -f to force)") % mark)
1042 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1042 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1043 and not force):
1043 and not force):
1044 raise error.Abort(
1044 raise error.Abort(
1045 _("a bookmark cannot have the name of an existing branch"))
1045 _("a bookmark cannot have the name of an existing branch"))
1046
1046
1047 if delete and rename:
1047 if delete and rename:
1048 raise error.Abort(_("--delete and --rename are incompatible"))
1048 raise error.Abort(_("--delete and --rename are incompatible"))
1049 if delete and rev:
1049 if delete and rev:
1050 raise error.Abort(_("--rev is incompatible with --delete"))
1050 raise error.Abort(_("--rev is incompatible with --delete"))
1051 if rename and rev:
1051 if rename and rev:
1052 raise error.Abort(_("--rev is incompatible with --rename"))
1052 raise error.Abort(_("--rev is incompatible with --rename"))
1053 if not names and (delete or rev):
1053 if not names and (delete or rev):
1054 raise error.Abort(_("bookmark name required"))
1054 raise error.Abort(_("bookmark name required"))
1055
1055
1056 if delete or rename or names or inactive:
1056 if delete or rename or names or inactive:
1057 wlock = lock = tr = None
1057 wlock = lock = tr = None
1058 try:
1058 try:
1059 wlock = repo.wlock()
1059 wlock = repo.wlock()
1060 lock = repo.lock()
1060 lock = repo.lock()
1061 cur = repo.changectx('.').node()
1061 cur = repo.changectx('.').node()
1062 marks = repo._bookmarks
1062 marks = repo._bookmarks
1063 if delete:
1063 if delete:
1064 tr = repo.transaction('bookmark')
1064 tr = repo.transaction('bookmark')
1065 for mark in names:
1065 for mark in names:
1066 if mark not in marks:
1066 if mark not in marks:
1067 raise error.Abort(_("bookmark '%s' does not exist") %
1067 raise error.Abort(_("bookmark '%s' does not exist") %
1068 mark)
1068 mark)
1069 if mark == repo._activebookmark:
1069 if mark == repo._activebookmark:
1070 bookmarks.deactivate(repo)
1070 bookmarks.deactivate(repo)
1071 del marks[mark]
1071 del marks[mark]
1072
1072
1073 elif rename:
1073 elif rename:
1074 tr = repo.transaction('bookmark')
1074 tr = repo.transaction('bookmark')
1075 if not names:
1075 if not names:
1076 raise error.Abort(_("new bookmark name required"))
1076 raise error.Abort(_("new bookmark name required"))
1077 elif len(names) > 1:
1077 elif len(names) > 1:
1078 raise error.Abort(_("only one new bookmark name allowed"))
1078 raise error.Abort(_("only one new bookmark name allowed"))
1079 mark = checkformat(names[0])
1079 mark = checkformat(names[0])
1080 if rename not in marks:
1080 if rename not in marks:
1081 raise error.Abort(_("bookmark '%s' does not exist")
1081 raise error.Abort(_("bookmark '%s' does not exist")
1082 % rename)
1082 % rename)
1083 checkconflict(repo, mark, cur, force)
1083 checkconflict(repo, mark, cur, force)
1084 marks[mark] = marks[rename]
1084 marks[mark] = marks[rename]
1085 if repo._activebookmark == rename and not inactive:
1085 if repo._activebookmark == rename and not inactive:
1086 bookmarks.activate(repo, mark)
1086 bookmarks.activate(repo, mark)
1087 del marks[rename]
1087 del marks[rename]
1088 elif names:
1088 elif names:
1089 tr = repo.transaction('bookmark')
1089 tr = repo.transaction('bookmark')
1090 newact = None
1090 newact = None
1091 for mark in names:
1091 for mark in names:
1092 mark = checkformat(mark)
1092 mark = checkformat(mark)
1093 if newact is None:
1093 if newact is None:
1094 newact = mark
1094 newact = mark
1095 if inactive and mark == repo._activebookmark:
1095 if inactive and mark == repo._activebookmark:
1096 bookmarks.deactivate(repo)
1096 bookmarks.deactivate(repo)
1097 return
1097 return
1098 tgt = cur
1098 tgt = cur
1099 if rev:
1099 if rev:
1100 tgt = scmutil.revsingle(repo, rev).node()
1100 tgt = scmutil.revsingle(repo, rev).node()
1101 checkconflict(repo, mark, cur, force, tgt)
1101 checkconflict(repo, mark, cur, force, tgt)
1102 marks[mark] = tgt
1102 marks[mark] = tgt
1103 if not inactive and cur == marks[newact] and not rev:
1103 if not inactive and cur == marks[newact] and not rev:
1104 bookmarks.activate(repo, newact)
1104 bookmarks.activate(repo, newact)
1105 elif cur != tgt and newact == repo._activebookmark:
1105 elif cur != tgt and newact == repo._activebookmark:
1106 bookmarks.deactivate(repo)
1106 bookmarks.deactivate(repo)
1107 elif inactive:
1107 elif inactive:
1108 if len(marks) == 0:
1108 if len(marks) == 0:
1109 ui.status(_("no bookmarks set\n"))
1109 ui.status(_("no bookmarks set\n"))
1110 elif not repo._activebookmark:
1110 elif not repo._activebookmark:
1111 ui.status(_("no active bookmark\n"))
1111 ui.status(_("no active bookmark\n"))
1112 else:
1112 else:
1113 bookmarks.deactivate(repo)
1113 bookmarks.deactivate(repo)
1114 if tr is not None:
1114 if tr is not None:
1115 marks.recordchange(tr)
1115 marks.recordchange(tr)
1116 tr.close()
1116 tr.close()
1117 finally:
1117 finally:
1118 lockmod.release(tr, lock, wlock)
1118 lockmod.release(tr, lock, wlock)
1119 else: # show bookmarks
1119 else: # show bookmarks
1120 fm = ui.formatter('bookmarks', opts)
1120 fm = ui.formatter('bookmarks', opts)
1121 hexfn = fm.hexfunc
1121 hexfn = fm.hexfunc
1122 marks = repo._bookmarks
1122 marks = repo._bookmarks
1123 if len(marks) == 0 and fm.isplain():
1123 if len(marks) == 0 and fm.isplain():
1124 ui.status(_("no bookmarks set\n"))
1124 ui.status(_("no bookmarks set\n"))
1125 for bmark, n in sorted(marks.iteritems()):
1125 for bmark, n in sorted(marks.iteritems()):
1126 active = repo._activebookmark
1126 active = repo._activebookmark
1127 if bmark == active:
1127 if bmark == active:
1128 prefix, label = '*', activebookmarklabel
1128 prefix, label = '*', activebookmarklabel
1129 else:
1129 else:
1130 prefix, label = ' ', ''
1130 prefix, label = ' ', ''
1131
1131
1132 fm.startitem()
1132 fm.startitem()
1133 if not ui.quiet:
1133 if not ui.quiet:
1134 fm.plain(' %s ' % prefix, label=label)
1134 fm.plain(' %s ' % prefix, label=label)
1135 fm.write('bookmark', '%s', bmark, label=label)
1135 fm.write('bookmark', '%s', bmark, label=label)
1136 pad = " " * (25 - encoding.colwidth(bmark))
1136 pad = " " * (25 - encoding.colwidth(bmark))
1137 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1137 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1138 repo.changelog.rev(n), hexfn(n), label=label)
1138 repo.changelog.rev(n), hexfn(n), label=label)
1139 fm.data(active=(bmark == active))
1139 fm.data(active=(bmark == active))
1140 fm.plain('\n')
1140 fm.plain('\n')
1141 fm.end()
1141 fm.end()
1142
1142
1143 @command('branch',
1143 @command('branch',
1144 [('f', 'force', None,
1144 [('f', 'force', None,
1145 _('set branch name even if it shadows an existing branch')),
1145 _('set branch name even if it shadows an existing branch')),
1146 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1146 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1147 _('[-fC] [NAME]'))
1147 _('[-fC] [NAME]'))
1148 def branch(ui, repo, label=None, **opts):
1148 def branch(ui, repo, label=None, **opts):
1149 """set or show the current branch name
1149 """set or show the current branch name
1150
1150
1151 .. note::
1151 .. note::
1152
1152
1153 Branch names are permanent and global. Use :hg:`bookmark` to create a
1153 Branch names are permanent and global. Use :hg:`bookmark` to create a
1154 light-weight bookmark instead. See :hg:`help glossary` for more
1154 light-weight bookmark instead. See :hg:`help glossary` for more
1155 information about named branches and bookmarks.
1155 information about named branches and bookmarks.
1156
1156
1157 With no argument, show the current branch name. With one argument,
1157 With no argument, show the current branch name. With one argument,
1158 set the working directory branch name (the branch will not exist
1158 set the working directory branch name (the branch will not exist
1159 in the repository until the next commit). Standard practice
1159 in the repository until the next commit). Standard practice
1160 recommends that primary development take place on the 'default'
1160 recommends that primary development take place on the 'default'
1161 branch.
1161 branch.
1162
1162
1163 Unless -f/--force is specified, branch will not let you set a
1163 Unless -f/--force is specified, branch will not let you set a
1164 branch name that already exists.
1164 branch name that already exists.
1165
1165
1166 Use -C/--clean to reset the working directory branch to that of
1166 Use -C/--clean to reset the working directory branch to that of
1167 the parent of the working directory, negating a previous branch
1167 the parent of the working directory, negating a previous branch
1168 change.
1168 change.
1169
1169
1170 Use the command :hg:`update` to switch to an existing branch. Use
1170 Use the command :hg:`update` to switch to an existing branch. Use
1171 :hg:`commit --close-branch` to mark this branch head as closed.
1171 :hg:`commit --close-branch` to mark this branch head as closed.
1172 When all heads of a branch are closed, the branch will be
1172 When all heads of a branch are closed, the branch will be
1173 considered closed.
1173 considered closed.
1174
1174
1175 Returns 0 on success.
1175 Returns 0 on success.
1176 """
1176 """
1177 if label:
1177 if label:
1178 label = label.strip()
1178 label = label.strip()
1179
1179
1180 if not opts.get('clean') and not label:
1180 if not opts.get('clean') and not label:
1181 ui.write("%s\n" % repo.dirstate.branch())
1181 ui.write("%s\n" % repo.dirstate.branch())
1182 return
1182 return
1183
1183
1184 with repo.wlock():
1184 with repo.wlock():
1185 if opts.get('clean'):
1185 if opts.get('clean'):
1186 label = repo[None].p1().branch()
1186 label = repo[None].p1().branch()
1187 repo.dirstate.setbranch(label)
1187 repo.dirstate.setbranch(label)
1188 ui.status(_('reset working directory to branch %s\n') % label)
1188 ui.status(_('reset working directory to branch %s\n') % label)
1189 elif label:
1189 elif label:
1190 if not opts.get('force') and label in repo.branchmap():
1190 if not opts.get('force') and label in repo.branchmap():
1191 if label not in [p.branch() for p in repo[None].parents()]:
1191 if label not in [p.branch() for p in repo[None].parents()]:
1192 raise error.Abort(_('a branch of the same name already'
1192 raise error.Abort(_('a branch of the same name already'
1193 ' exists'),
1193 ' exists'),
1194 # i18n: "it" refers to an existing branch
1194 # i18n: "it" refers to an existing branch
1195 hint=_("use 'hg update' to switch to it"))
1195 hint=_("use 'hg update' to switch to it"))
1196 scmutil.checknewlabel(repo, label, 'branch')
1196 scmutil.checknewlabel(repo, label, 'branch')
1197 repo.dirstate.setbranch(label)
1197 repo.dirstate.setbranch(label)
1198 ui.status(_('marked working directory as branch %s\n') % label)
1198 ui.status(_('marked working directory as branch %s\n') % label)
1199
1199
1200 # find any open named branches aside from default
1200 # find any open named branches aside from default
1201 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1201 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1202 if n != "default" and not c]
1202 if n != "default" and not c]
1203 if not others:
1203 if not others:
1204 ui.status(_('(branches are permanent and global, '
1204 ui.status(_('(branches are permanent and global, '
1205 'did you want a bookmark?)\n'))
1205 'did you want a bookmark?)\n'))
1206
1206
1207 @command('branches',
1207 @command('branches',
1208 [('a', 'active', False,
1208 [('a', 'active', False,
1209 _('show only branches that have unmerged heads (DEPRECATED)')),
1209 _('show only branches that have unmerged heads (DEPRECATED)')),
1210 ('c', 'closed', False, _('show normal and closed branches')),
1210 ('c', 'closed', False, _('show normal and closed branches')),
1211 ] + formatteropts,
1211 ] + formatteropts,
1212 _('[-c]'))
1212 _('[-c]'))
1213 def branches(ui, repo, active=False, closed=False, **opts):
1213 def branches(ui, repo, active=False, closed=False, **opts):
1214 """list repository named branches
1214 """list repository named branches
1215
1215
1216 List the repository's named branches, indicating which ones are
1216 List the repository's named branches, indicating which ones are
1217 inactive. If -c/--closed is specified, also list branches which have
1217 inactive. If -c/--closed is specified, also list branches which have
1218 been marked closed (see :hg:`commit --close-branch`).
1218 been marked closed (see :hg:`commit --close-branch`).
1219
1219
1220 Use the command :hg:`update` to switch to an existing branch.
1220 Use the command :hg:`update` to switch to an existing branch.
1221
1221
1222 Returns 0.
1222 Returns 0.
1223 """
1223 """
1224
1224
1225 fm = ui.formatter('branches', opts)
1225 fm = ui.formatter('branches', opts)
1226 hexfunc = fm.hexfunc
1226 hexfunc = fm.hexfunc
1227
1227
1228 allheads = set(repo.heads())
1228 allheads = set(repo.heads())
1229 branches = []
1229 branches = []
1230 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1230 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1231 isactive = not isclosed and bool(set(heads) & allheads)
1231 isactive = not isclosed and bool(set(heads) & allheads)
1232 branches.append((tag, repo[tip], isactive, not isclosed))
1232 branches.append((tag, repo[tip], isactive, not isclosed))
1233 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1233 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1234 reverse=True)
1234 reverse=True)
1235
1235
1236 for tag, ctx, isactive, isopen in branches:
1236 for tag, ctx, isactive, isopen in branches:
1237 if active and not isactive:
1237 if active and not isactive:
1238 continue
1238 continue
1239 if isactive:
1239 if isactive:
1240 label = 'branches.active'
1240 label = 'branches.active'
1241 notice = ''
1241 notice = ''
1242 elif not isopen:
1242 elif not isopen:
1243 if not closed:
1243 if not closed:
1244 continue
1244 continue
1245 label = 'branches.closed'
1245 label = 'branches.closed'
1246 notice = _(' (closed)')
1246 notice = _(' (closed)')
1247 else:
1247 else:
1248 label = 'branches.inactive'
1248 label = 'branches.inactive'
1249 notice = _(' (inactive)')
1249 notice = _(' (inactive)')
1250 current = (tag == repo.dirstate.branch())
1250 current = (tag == repo.dirstate.branch())
1251 if current:
1251 if current:
1252 label = 'branches.current'
1252 label = 'branches.current'
1253
1253
1254 fm.startitem()
1254 fm.startitem()
1255 fm.write('branch', '%s', tag, label=label)
1255 fm.write('branch', '%s', tag, label=label)
1256 rev = ctx.rev()
1256 rev = ctx.rev()
1257 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1257 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1258 fmt = ' ' * padsize + ' %d:%s'
1258 fmt = ' ' * padsize + ' %d:%s'
1259 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1259 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1260 label='log.changeset changeset.%s' % ctx.phasestr())
1260 label='log.changeset changeset.%s' % ctx.phasestr())
1261 fm.data(active=isactive, closed=not isopen, current=current)
1261 fm.data(active=isactive, closed=not isopen, current=current)
1262 if not ui.quiet:
1262 if not ui.quiet:
1263 fm.plain(notice)
1263 fm.plain(notice)
1264 fm.plain('\n')
1264 fm.plain('\n')
1265 fm.end()
1265 fm.end()
1266
1266
1267 @command('bundle',
1267 @command('bundle',
1268 [('f', 'force', None, _('run even when the destination is unrelated')),
1268 [('f', 'force', None, _('run even when the destination is unrelated')),
1269 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1269 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1270 _('REV')),
1270 _('REV')),
1271 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1271 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1272 _('BRANCH')),
1272 _('BRANCH')),
1273 ('', 'base', [],
1273 ('', 'base', [],
1274 _('a base changeset assumed to be available at the destination'),
1274 _('a base changeset assumed to be available at the destination'),
1275 _('REV')),
1275 _('REV')),
1276 ('a', 'all', None, _('bundle all changesets in the repository')),
1276 ('a', 'all', None, _('bundle all changesets in the repository')),
1277 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1277 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1278 ] + remoteopts,
1278 ] + remoteopts,
1279 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1279 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1280 def bundle(ui, repo, fname, dest=None, **opts):
1280 def bundle(ui, repo, fname, dest=None, **opts):
1281 """create a changegroup file
1281 """create a changegroup file
1282
1282
1283 Generate a changegroup file collecting changesets to be added
1283 Generate a changegroup file collecting changesets to be added
1284 to a repository.
1284 to a repository.
1285
1285
1286 To create a bundle containing all changesets, use -a/--all
1286 To create a bundle containing all changesets, use -a/--all
1287 (or --base null). Otherwise, hg assumes the destination will have
1287 (or --base null). Otherwise, hg assumes the destination will have
1288 all the nodes you specify with --base parameters. Otherwise, hg
1288 all the nodes you specify with --base parameters. Otherwise, hg
1289 will assume the repository has all the nodes in destination, or
1289 will assume the repository has all the nodes in destination, or
1290 default-push/default if no destination is specified.
1290 default-push/default if no destination is specified.
1291
1291
1292 You can change bundle format with the -t/--type option. You can
1292 You can change bundle format with the -t/--type option. You can
1293 specify a compression, a bundle version or both using a dash
1293 specify a compression, a bundle version or both using a dash
1294 (comp-version). The available compression methods are: none, bzip2,
1294 (comp-version). The available compression methods are: none, bzip2,
1295 and gzip (by default, bundles are compressed using bzip2). The
1295 and gzip (by default, bundles are compressed using bzip2). The
1296 available formats are: v1, v2 (default to most suitable).
1296 available formats are: v1, v2 (default to most suitable).
1297
1297
1298 The bundle file can then be transferred using conventional means
1298 The bundle file can then be transferred using conventional means
1299 and applied to another repository with the unbundle or pull
1299 and applied to another repository with the unbundle or pull
1300 command. This is useful when direct push and pull are not
1300 command. This is useful when direct push and pull are not
1301 available or when exporting an entire repository is undesirable.
1301 available or when exporting an entire repository is undesirable.
1302
1302
1303 Applying bundles preserves all changeset contents including
1303 Applying bundles preserves all changeset contents including
1304 permissions, copy/rename information, and revision history.
1304 permissions, copy/rename information, and revision history.
1305
1305
1306 Returns 0 on success, 1 if no changes found.
1306 Returns 0 on success, 1 if no changes found.
1307 """
1307 """
1308 revs = None
1308 revs = None
1309 if 'rev' in opts:
1309 if 'rev' in opts:
1310 revstrings = opts['rev']
1310 revstrings = opts['rev']
1311 revs = scmutil.revrange(repo, revstrings)
1311 revs = scmutil.revrange(repo, revstrings)
1312 if revstrings and not revs:
1312 if revstrings and not revs:
1313 raise error.Abort(_('no commits to bundle'))
1313 raise error.Abort(_('no commits to bundle'))
1314
1314
1315 bundletype = opts.get('type', 'bzip2').lower()
1315 bundletype = opts.get('type', 'bzip2').lower()
1316 try:
1316 try:
1317 bcompression, cgversion, params = exchange.parsebundlespec(
1317 bcompression, cgversion, params = exchange.parsebundlespec(
1318 repo, bundletype, strict=False)
1318 repo, bundletype, strict=False)
1319 except error.UnsupportedBundleSpecification as e:
1319 except error.UnsupportedBundleSpecification as e:
1320 raise error.Abort(str(e),
1320 raise error.Abort(str(e),
1321 hint=_("see 'hg help bundle' for supported "
1321 hint=_("see 'hg help bundle' for supported "
1322 "values for --type"))
1322 "values for --type"))
1323
1323
1324 # Packed bundles are a pseudo bundle format for now.
1324 # Packed bundles are a pseudo bundle format for now.
1325 if cgversion == 's1':
1325 if cgversion == 's1':
1326 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1326 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1327 hint=_("use 'hg debugcreatestreamclonebundle'"))
1327 hint=_("use 'hg debugcreatestreamclonebundle'"))
1328
1328
1329 if opts.get('all'):
1329 if opts.get('all'):
1330 if dest:
1330 if dest:
1331 raise error.Abort(_("--all is incompatible with specifying "
1331 raise error.Abort(_("--all is incompatible with specifying "
1332 "a destination"))
1332 "a destination"))
1333 if opts.get('base'):
1333 if opts.get('base'):
1334 ui.warn(_("ignoring --base because --all was specified\n"))
1334 ui.warn(_("ignoring --base because --all was specified\n"))
1335 base = ['null']
1335 base = ['null']
1336 else:
1336 else:
1337 base = scmutil.revrange(repo, opts.get('base'))
1337 base = scmutil.revrange(repo, opts.get('base'))
1338 # TODO: get desired bundlecaps from command line.
1338 # TODO: get desired bundlecaps from command line.
1339 bundlecaps = None
1339 bundlecaps = None
1340 if cgversion not in changegroup.supportedoutgoingversions(repo):
1340 if cgversion not in changegroup.supportedoutgoingversions(repo):
1341 raise error.Abort(_("repository does not support bundle version %s") %
1341 raise error.Abort(_("repository does not support bundle version %s") %
1342 cgversion)
1342 cgversion)
1343
1343
1344 if base:
1344 if base:
1345 if dest:
1345 if dest:
1346 raise error.Abort(_("--base is incompatible with specifying "
1346 raise error.Abort(_("--base is incompatible with specifying "
1347 "a destination"))
1347 "a destination"))
1348 common = [repo.lookup(rev) for rev in base]
1348 common = [repo.lookup(rev) for rev in base]
1349 heads = revs and map(repo.lookup, revs) or None
1349 heads = revs and map(repo.lookup, revs) or None
1350 outgoing = discovery.outgoing(repo, common, heads)
1350 outgoing = discovery.outgoing(repo, common, heads)
1351 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1351 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1352 bundlecaps=bundlecaps,
1352 bundlecaps=bundlecaps,
1353 version=cgversion)
1353 version=cgversion)
1354 outgoing = None
1354 outgoing = None
1355 else:
1355 else:
1356 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1356 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1357 dest, branches = hg.parseurl(dest, opts.get('branch'))
1357 dest, branches = hg.parseurl(dest, opts.get('branch'))
1358 other = hg.peer(repo, opts, dest)
1358 other = hg.peer(repo, opts, dest)
1359 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1359 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1360 heads = revs and map(repo.lookup, revs) or revs
1360 heads = revs and map(repo.lookup, revs) or revs
1361 outgoing = discovery.findcommonoutgoing(repo, other,
1361 outgoing = discovery.findcommonoutgoing(repo, other,
1362 onlyheads=heads,
1362 onlyheads=heads,
1363 force=opts.get('force'),
1363 force=opts.get('force'),
1364 portable=True)
1364 portable=True)
1365 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1365 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1366 bundlecaps, version=cgversion)
1366 bundlecaps, version=cgversion)
1367 if not cg:
1367 if not cg:
1368 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1368 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1369 return 1
1369 return 1
1370
1370
1371 if cgversion == '01': #bundle1
1371 if cgversion == '01': #bundle1
1372 if bcompression is None:
1372 if bcompression is None:
1373 bcompression = 'UN'
1373 bcompression = 'UN'
1374 bversion = 'HG10' + bcompression
1374 bversion = 'HG10' + bcompression
1375 bcompression = None
1375 bcompression = None
1376 else:
1376 else:
1377 assert cgversion == '02'
1377 assert cgversion == '02'
1378 bversion = 'HG20'
1378 bversion = 'HG20'
1379
1379
1380 # TODO compression options should be derived from bundlespec parsing.
1380 # TODO compression options should be derived from bundlespec parsing.
1381 # This is a temporary hack to allow adjusting bundle compression
1381 # This is a temporary hack to allow adjusting bundle compression
1382 # level without a) formalizing the bundlespec changes to declare it
1382 # level without a) formalizing the bundlespec changes to declare it
1383 # b) introducing a command flag.
1383 # b) introducing a command flag.
1384 compopts = {}
1384 compopts = {}
1385 complevel = ui.configint('experimental', 'bundlecomplevel')
1385 complevel = ui.configint('experimental', 'bundlecomplevel')
1386 if complevel is not None:
1386 if complevel is not None:
1387 compopts['level'] = complevel
1387 compopts['level'] = complevel
1388
1388
1389 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1389 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1390 compopts=compopts)
1390 compopts=compopts)
1391
1391
1392 @command('cat',
1392 @command('cat',
1393 [('o', 'output', '',
1393 [('o', 'output', '',
1394 _('print output to file with formatted name'), _('FORMAT')),
1394 _('print output to file with formatted name'), _('FORMAT')),
1395 ('r', 'rev', '', _('print the given revision'), _('REV')),
1395 ('r', 'rev', '', _('print the given revision'), _('REV')),
1396 ('', 'decode', None, _('apply any matching decode filter')),
1396 ('', 'decode', None, _('apply any matching decode filter')),
1397 ] + walkopts,
1397 ] + walkopts,
1398 _('[OPTION]... FILE...'),
1398 _('[OPTION]... FILE...'),
1399 inferrepo=True)
1399 inferrepo=True)
1400 def cat(ui, repo, file1, *pats, **opts):
1400 def cat(ui, repo, file1, *pats, **opts):
1401 """output the current or given revision of files
1401 """output the current or given revision of files
1402
1402
1403 Print the specified files as they were at the given revision. If
1403 Print the specified files as they were at the given revision. If
1404 no revision is given, the parent of the working directory is used.
1404 no revision is given, the parent of the working directory is used.
1405
1405
1406 Output may be to a file, in which case the name of the file is
1406 Output may be to a file, in which case the name of the file is
1407 given using a format string. The formatting rules as follows:
1407 given using a format string. The formatting rules as follows:
1408
1408
1409 :``%%``: literal "%" character
1409 :``%%``: literal "%" character
1410 :``%s``: basename of file being printed
1410 :``%s``: basename of file being printed
1411 :``%d``: dirname of file being printed, or '.' if in repository root
1411 :``%d``: dirname of file being printed, or '.' if in repository root
1412 :``%p``: root-relative path name of file being printed
1412 :``%p``: root-relative path name of file being printed
1413 :``%H``: changeset hash (40 hexadecimal digits)
1413 :``%H``: changeset hash (40 hexadecimal digits)
1414 :``%R``: changeset revision number
1414 :``%R``: changeset revision number
1415 :``%h``: short-form changeset hash (12 hexadecimal digits)
1415 :``%h``: short-form changeset hash (12 hexadecimal digits)
1416 :``%r``: zero-padded changeset revision number
1416 :``%r``: zero-padded changeset revision number
1417 :``%b``: basename of the exporting repository
1417 :``%b``: basename of the exporting repository
1418
1418
1419 Returns 0 on success.
1419 Returns 0 on success.
1420 """
1420 """
1421 ctx = scmutil.revsingle(repo, opts.get('rev'))
1421 ctx = scmutil.revsingle(repo, opts.get('rev'))
1422 m = scmutil.match(ctx, (file1,) + pats, opts)
1422 m = scmutil.match(ctx, (file1,) + pats, opts)
1423
1423
1424 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1424 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1425
1425
1426 @command('^clone',
1426 @command('^clone',
1427 [('U', 'noupdate', None, _('the clone will include an empty working '
1427 [('U', 'noupdate', None, _('the clone will include an empty working '
1428 'directory (only a repository)')),
1428 'directory (only a repository)')),
1429 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1429 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1430 _('REV')),
1430 _('REV')),
1431 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1431 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1432 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1432 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1433 ('', 'pull', None, _('use pull protocol to copy metadata')),
1433 ('', 'pull', None, _('use pull protocol to copy metadata')),
1434 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1434 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1435 ] + remoteopts,
1435 ] + remoteopts,
1436 _('[OPTION]... SOURCE [DEST]'),
1436 _('[OPTION]... SOURCE [DEST]'),
1437 norepo=True)
1437 norepo=True)
1438 def clone(ui, source, dest=None, **opts):
1438 def clone(ui, source, dest=None, **opts):
1439 """make a copy of an existing repository
1439 """make a copy of an existing repository
1440
1440
1441 Create a copy of an existing repository in a new directory.
1441 Create a copy of an existing repository in a new directory.
1442
1442
1443 If no destination directory name is specified, it defaults to the
1443 If no destination directory name is specified, it defaults to the
1444 basename of the source.
1444 basename of the source.
1445
1445
1446 The location of the source is added to the new repository's
1446 The location of the source is added to the new repository's
1447 ``.hg/hgrc`` file, as the default to be used for future pulls.
1447 ``.hg/hgrc`` file, as the default to be used for future pulls.
1448
1448
1449 Only local paths and ``ssh://`` URLs are supported as
1449 Only local paths and ``ssh://`` URLs are supported as
1450 destinations. For ``ssh://`` destinations, no working directory or
1450 destinations. For ``ssh://`` destinations, no working directory or
1451 ``.hg/hgrc`` will be created on the remote side.
1451 ``.hg/hgrc`` will be created on the remote side.
1452
1452
1453 If the source repository has a bookmark called '@' set, that
1453 If the source repository has a bookmark called '@' set, that
1454 revision will be checked out in the new repository by default.
1454 revision will be checked out in the new repository by default.
1455
1455
1456 To check out a particular version, use -u/--update, or
1456 To check out a particular version, use -u/--update, or
1457 -U/--noupdate to create a clone with no working directory.
1457 -U/--noupdate to create a clone with no working directory.
1458
1458
1459 To pull only a subset of changesets, specify one or more revisions
1459 To pull only a subset of changesets, specify one or more revisions
1460 identifiers with -r/--rev or branches with -b/--branch. The
1460 identifiers with -r/--rev or branches with -b/--branch. The
1461 resulting clone will contain only the specified changesets and
1461 resulting clone will contain only the specified changesets and
1462 their ancestors. These options (or 'clone src#rev dest') imply
1462 their ancestors. These options (or 'clone src#rev dest') imply
1463 --pull, even for local source repositories.
1463 --pull, even for local source repositories.
1464
1464
1465 .. note::
1465 .. note::
1466
1466
1467 Specifying a tag will include the tagged changeset but not the
1467 Specifying a tag will include the tagged changeset but not the
1468 changeset containing the tag.
1468 changeset containing the tag.
1469
1469
1470 .. container:: verbose
1470 .. container:: verbose
1471
1471
1472 For efficiency, hardlinks are used for cloning whenever the
1472 For efficiency, hardlinks are used for cloning whenever the
1473 source and destination are on the same filesystem (note this
1473 source and destination are on the same filesystem (note this
1474 applies only to the repository data, not to the working
1474 applies only to the repository data, not to the working
1475 directory). Some filesystems, such as AFS, implement hardlinking
1475 directory). Some filesystems, such as AFS, implement hardlinking
1476 incorrectly, but do not report errors. In these cases, use the
1476 incorrectly, but do not report errors. In these cases, use the
1477 --pull option to avoid hardlinking.
1477 --pull option to avoid hardlinking.
1478
1478
1479 In some cases, you can clone repositories and the working
1479 In some cases, you can clone repositories and the working
1480 directory using full hardlinks with ::
1480 directory using full hardlinks with ::
1481
1481
1482 $ cp -al REPO REPOCLONE
1482 $ cp -al REPO REPOCLONE
1483
1483
1484 This is the fastest way to clone, but it is not always safe. The
1484 This is the fastest way to clone, but it is not always safe. The
1485 operation is not atomic (making sure REPO is not modified during
1485 operation is not atomic (making sure REPO is not modified during
1486 the operation is up to you) and you have to make sure your
1486 the operation is up to you) and you have to make sure your
1487 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1487 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1488 so). Also, this is not compatible with certain extensions that
1488 so). Also, this is not compatible with certain extensions that
1489 place their metadata under the .hg directory, such as mq.
1489 place their metadata under the .hg directory, such as mq.
1490
1490
1491 Mercurial will update the working directory to the first applicable
1491 Mercurial will update the working directory to the first applicable
1492 revision from this list:
1492 revision from this list:
1493
1493
1494 a) null if -U or the source repository has no changesets
1494 a) null if -U or the source repository has no changesets
1495 b) if -u . and the source repository is local, the first parent of
1495 b) if -u . and the source repository is local, the first parent of
1496 the source repository's working directory
1496 the source repository's working directory
1497 c) the changeset specified with -u (if a branch name, this means the
1497 c) the changeset specified with -u (if a branch name, this means the
1498 latest head of that branch)
1498 latest head of that branch)
1499 d) the changeset specified with -r
1499 d) the changeset specified with -r
1500 e) the tipmost head specified with -b
1500 e) the tipmost head specified with -b
1501 f) the tipmost head specified with the url#branch source syntax
1501 f) the tipmost head specified with the url#branch source syntax
1502 g) the revision marked with the '@' bookmark, if present
1502 g) the revision marked with the '@' bookmark, if present
1503 h) the tipmost head of the default branch
1503 h) the tipmost head of the default branch
1504 i) tip
1504 i) tip
1505
1505
1506 When cloning from servers that support it, Mercurial may fetch
1506 When cloning from servers that support it, Mercurial may fetch
1507 pre-generated data from a server-advertised URL. When this is done,
1507 pre-generated data from a server-advertised URL. When this is done,
1508 hooks operating on incoming changesets and changegroups may fire twice,
1508 hooks operating on incoming changesets and changegroups may fire twice,
1509 once for the bundle fetched from the URL and another for any additional
1509 once for the bundle fetched from the URL and another for any additional
1510 data not fetched from this URL. In addition, if an error occurs, the
1510 data not fetched from this URL. In addition, if an error occurs, the
1511 repository may be rolled back to a partial clone. This behavior may
1511 repository may be rolled back to a partial clone. This behavior may
1512 change in future releases. See :hg:`help -e clonebundles` for more.
1512 change in future releases. See :hg:`help -e clonebundles` for more.
1513
1513
1514 Examples:
1514 Examples:
1515
1515
1516 - clone a remote repository to a new directory named hg/::
1516 - clone a remote repository to a new directory named hg/::
1517
1517
1518 hg clone https://www.mercurial-scm.org/repo/hg/
1518 hg clone https://www.mercurial-scm.org/repo/hg/
1519
1519
1520 - create a lightweight local clone::
1520 - create a lightweight local clone::
1521
1521
1522 hg clone project/ project-feature/
1522 hg clone project/ project-feature/
1523
1523
1524 - clone from an absolute path on an ssh server (note double-slash)::
1524 - clone from an absolute path on an ssh server (note double-slash)::
1525
1525
1526 hg clone ssh://user@server//home/projects/alpha/
1526 hg clone ssh://user@server//home/projects/alpha/
1527
1527
1528 - do a high-speed clone over a LAN while checking out a
1528 - do a high-speed clone over a LAN while checking out a
1529 specified version::
1529 specified version::
1530
1530
1531 hg clone --uncompressed http://server/repo -u 1.5
1531 hg clone --uncompressed http://server/repo -u 1.5
1532
1532
1533 - create a repository without changesets after a particular revision::
1533 - create a repository without changesets after a particular revision::
1534
1534
1535 hg clone -r 04e544 experimental/ good/
1535 hg clone -r 04e544 experimental/ good/
1536
1536
1537 - clone (and track) a particular named branch::
1537 - clone (and track) a particular named branch::
1538
1538
1539 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1539 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1540
1540
1541 See :hg:`help urls` for details on specifying URLs.
1541 See :hg:`help urls` for details on specifying URLs.
1542
1542
1543 Returns 0 on success.
1543 Returns 0 on success.
1544 """
1544 """
1545 if opts.get('noupdate') and opts.get('updaterev'):
1545 if opts.get('noupdate') and opts.get('updaterev'):
1546 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1546 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1547
1547
1548 r = hg.clone(ui, opts, source, dest,
1548 r = hg.clone(ui, opts, source, dest,
1549 pull=opts.get('pull'),
1549 pull=opts.get('pull'),
1550 stream=opts.get('uncompressed'),
1550 stream=opts.get('uncompressed'),
1551 rev=opts.get('rev'),
1551 rev=opts.get('rev'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1553 branch=opts.get('branch'),
1553 branch=opts.get('branch'),
1554 shareopts=opts.get('shareopts'))
1554 shareopts=opts.get('shareopts'))
1555
1555
1556 return r is None
1556 return r is None
1557
1557
1558 @command('^commit|ci',
1558 @command('^commit|ci',
1559 [('A', 'addremove', None,
1559 [('A', 'addremove', None,
1560 _('mark new/missing files as added/removed before committing')),
1560 _('mark new/missing files as added/removed before committing')),
1561 ('', 'close-branch', None,
1561 ('', 'close-branch', None,
1562 _('mark a branch head as closed')),
1562 _('mark a branch head as closed')),
1563 ('', 'amend', None, _('amend the parent of the working directory')),
1563 ('', 'amend', None, _('amend the parent of the working directory')),
1564 ('s', 'secret', None, _('use the secret phase for committing')),
1564 ('s', 'secret', None, _('use the secret phase for committing')),
1565 ('e', 'edit', None, _('invoke editor on commit messages')),
1565 ('e', 'edit', None, _('invoke editor on commit messages')),
1566 ('i', 'interactive', None, _('use interactive mode')),
1566 ('i', 'interactive', None, _('use interactive mode')),
1567 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1567 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1568 _('[OPTION]... [FILE]...'),
1568 _('[OPTION]... [FILE]...'),
1569 inferrepo=True)
1569 inferrepo=True)
1570 def commit(ui, repo, *pats, **opts):
1570 def commit(ui, repo, *pats, **opts):
1571 """commit the specified files or all outstanding changes
1571 """commit the specified files or all outstanding changes
1572
1572
1573 Commit changes to the given files into the repository. Unlike a
1573 Commit changes to the given files into the repository. Unlike a
1574 centralized SCM, this operation is a local operation. See
1574 centralized SCM, this operation is a local operation. See
1575 :hg:`push` for a way to actively distribute your changes.
1575 :hg:`push` for a way to actively distribute your changes.
1576
1576
1577 If a list of files is omitted, all changes reported by :hg:`status`
1577 If a list of files is omitted, all changes reported by :hg:`status`
1578 will be committed.
1578 will be committed.
1579
1579
1580 If you are committing the result of a merge, do not provide any
1580 If you are committing the result of a merge, do not provide any
1581 filenames or -I/-X filters.
1581 filenames or -I/-X filters.
1582
1582
1583 If no commit message is specified, Mercurial starts your
1583 If no commit message is specified, Mercurial starts your
1584 configured editor where you can enter a message. In case your
1584 configured editor where you can enter a message. In case your
1585 commit fails, you will find a backup of your message in
1585 commit fails, you will find a backup of your message in
1586 ``.hg/last-message.txt``.
1586 ``.hg/last-message.txt``.
1587
1587
1588 The --close-branch flag can be used to mark the current branch
1588 The --close-branch flag can be used to mark the current branch
1589 head closed. When all heads of a branch are closed, the branch
1589 head closed. When all heads of a branch are closed, the branch
1590 will be considered closed and no longer listed.
1590 will be considered closed and no longer listed.
1591
1591
1592 The --amend flag can be used to amend the parent of the
1592 The --amend flag can be used to amend the parent of the
1593 working directory with a new commit that contains the changes
1593 working directory with a new commit that contains the changes
1594 in the parent in addition to those currently reported by :hg:`status`,
1594 in the parent in addition to those currently reported by :hg:`status`,
1595 if there are any. The old commit is stored in a backup bundle in
1595 if there are any. The old commit is stored in a backup bundle in
1596 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1596 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1597 on how to restore it).
1597 on how to restore it).
1598
1598
1599 Message, user and date are taken from the amended commit unless
1599 Message, user and date are taken from the amended commit unless
1600 specified. When a message isn't specified on the command line,
1600 specified. When a message isn't specified on the command line,
1601 the editor will open with the message of the amended commit.
1601 the editor will open with the message of the amended commit.
1602
1602
1603 It is not possible to amend public changesets (see :hg:`help phases`)
1603 It is not possible to amend public changesets (see :hg:`help phases`)
1604 or changesets that have children.
1604 or changesets that have children.
1605
1605
1606 See :hg:`help dates` for a list of formats valid for -d/--date.
1606 See :hg:`help dates` for a list of formats valid for -d/--date.
1607
1607
1608 Returns 0 on success, 1 if nothing changed.
1608 Returns 0 on success, 1 if nothing changed.
1609
1609
1610 .. container:: verbose
1610 .. container:: verbose
1611
1611
1612 Examples:
1612 Examples:
1613
1613
1614 - commit all files ending in .py::
1614 - commit all files ending in .py::
1615
1615
1616 hg commit --include "set:**.py"
1616 hg commit --include "set:**.py"
1617
1617
1618 - commit all non-binary files::
1618 - commit all non-binary files::
1619
1619
1620 hg commit --exclude "set:binary()"
1620 hg commit --exclude "set:binary()"
1621
1621
1622 - amend the current commit and set the date to now::
1622 - amend the current commit and set the date to now::
1623
1623
1624 hg commit --amend --date now
1624 hg commit --amend --date now
1625 """
1625 """
1626 wlock = lock = None
1626 wlock = lock = None
1627 try:
1627 try:
1628 wlock = repo.wlock()
1628 wlock = repo.wlock()
1629 lock = repo.lock()
1629 lock = repo.lock()
1630 return _docommit(ui, repo, *pats, **opts)
1630 return _docommit(ui, repo, *pats, **opts)
1631 finally:
1631 finally:
1632 release(lock, wlock)
1632 release(lock, wlock)
1633
1633
1634 def _docommit(ui, repo, *pats, **opts):
1634 def _docommit(ui, repo, *pats, **opts):
1635 if opts.get('interactive'):
1635 if opts.get('interactive'):
1636 opts.pop('interactive')
1636 opts.pop('interactive')
1637 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1637 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1638 cmdutil.recordfilter, *pats, **opts)
1638 cmdutil.recordfilter, *pats, **opts)
1639 # ret can be 0 (no changes to record) or the value returned by
1639 # ret can be 0 (no changes to record) or the value returned by
1640 # commit(), 1 if nothing changed or None on success.
1640 # commit(), 1 if nothing changed or None on success.
1641 return 1 if ret == 0 else ret
1641 return 1 if ret == 0 else ret
1642
1642
1643 if opts.get('subrepos'):
1643 if opts.get('subrepos'):
1644 if opts.get('amend'):
1644 if opts.get('amend'):
1645 raise error.Abort(_('cannot amend with --subrepos'))
1645 raise error.Abort(_('cannot amend with --subrepos'))
1646 # Let --subrepos on the command line override config setting.
1646 # Let --subrepos on the command line override config setting.
1647 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1647 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1648
1648
1649 cmdutil.checkunfinished(repo, commit=True)
1649 cmdutil.checkunfinished(repo, commit=True)
1650
1650
1651 branch = repo[None].branch()
1651 branch = repo[None].branch()
1652 bheads = repo.branchheads(branch)
1652 bheads = repo.branchheads(branch)
1653
1653
1654 extra = {}
1654 extra = {}
1655 if opts.get('close_branch'):
1655 if opts.get('close_branch'):
1656 extra['close'] = 1
1656 extra['close'] = 1
1657
1657
1658 if not bheads:
1658 if not bheads:
1659 raise error.Abort(_('can only close branch heads'))
1659 raise error.Abort(_('can only close branch heads'))
1660 elif opts.get('amend'):
1660 elif opts.get('amend'):
1661 if repo[None].parents()[0].p1().branch() != branch and \
1661 if repo[None].parents()[0].p1().branch() != branch and \
1662 repo[None].parents()[0].p2().branch() != branch:
1662 repo[None].parents()[0].p2().branch() != branch:
1663 raise error.Abort(_('can only close branch heads'))
1663 raise error.Abort(_('can only close branch heads'))
1664
1664
1665 if opts.get('amend'):
1665 if opts.get('amend'):
1666 if ui.configbool('ui', 'commitsubrepos'):
1666 if ui.configbool('ui', 'commitsubrepos'):
1667 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1667 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1668
1668
1669 old = repo['.']
1669 old = repo['.']
1670 if not old.mutable():
1670 if not old.mutable():
1671 raise error.Abort(_('cannot amend public changesets'))
1671 raise error.Abort(_('cannot amend public changesets'))
1672 if len(repo[None].parents()) > 1:
1672 if len(repo[None].parents()) > 1:
1673 raise error.Abort(_('cannot amend while merging'))
1673 raise error.Abort(_('cannot amend while merging'))
1674 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1674 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1675 if not allowunstable and old.children():
1675 if not allowunstable and old.children():
1676 raise error.Abort(_('cannot amend changeset with children'))
1676 raise error.Abort(_('cannot amend changeset with children'))
1677
1677
1678 # Currently histedit gets confused if an amend happens while histedit
1678 # Currently histedit gets confused if an amend happens while histedit
1679 # is in progress. Since we have a checkunfinished command, we are
1679 # is in progress. Since we have a checkunfinished command, we are
1680 # temporarily honoring it.
1680 # temporarily honoring it.
1681 #
1681 #
1682 # Note: eventually this guard will be removed. Please do not expect
1682 # Note: eventually this guard will be removed. Please do not expect
1683 # this behavior to remain.
1683 # this behavior to remain.
1684 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1684 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1685 cmdutil.checkunfinished(repo)
1685 cmdutil.checkunfinished(repo)
1686
1686
1687 # commitfunc is used only for temporary amend commit by cmdutil.amend
1687 # commitfunc is used only for temporary amend commit by cmdutil.amend
1688 def commitfunc(ui, repo, message, match, opts):
1688 def commitfunc(ui, repo, message, match, opts):
1689 return repo.commit(message,
1689 return repo.commit(message,
1690 opts.get('user') or old.user(),
1690 opts.get('user') or old.user(),
1691 opts.get('date') or old.date(),
1691 opts.get('date') or old.date(),
1692 match,
1692 match,
1693 extra=extra)
1693 extra=extra)
1694
1694
1695 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1695 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1696 if node == old.node():
1696 if node == old.node():
1697 ui.status(_("nothing changed\n"))
1697 ui.status(_("nothing changed\n"))
1698 return 1
1698 return 1
1699 else:
1699 else:
1700 def commitfunc(ui, repo, message, match, opts):
1700 def commitfunc(ui, repo, message, match, opts):
1701 backup = ui.backupconfig('phases', 'new-commit')
1701 backup = ui.backupconfig('phases', 'new-commit')
1702 baseui = repo.baseui
1702 baseui = repo.baseui
1703 basebackup = baseui.backupconfig('phases', 'new-commit')
1703 basebackup = baseui.backupconfig('phases', 'new-commit')
1704 try:
1704 try:
1705 if opts.get('secret'):
1705 if opts.get('secret'):
1706 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1706 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1707 # Propagate to subrepos
1707 # Propagate to subrepos
1708 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1708 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1709
1709
1710 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1710 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1711 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1711 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1712 return repo.commit(message, opts.get('user'), opts.get('date'),
1712 return repo.commit(message, opts.get('user'), opts.get('date'),
1713 match,
1713 match,
1714 editor=editor,
1714 editor=editor,
1715 extra=extra)
1715 extra=extra)
1716 finally:
1716 finally:
1717 ui.restoreconfig(backup)
1717 ui.restoreconfig(backup)
1718 repo.baseui.restoreconfig(basebackup)
1718 repo.baseui.restoreconfig(basebackup)
1719
1719
1720
1720
1721 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1721 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1722
1722
1723 if not node:
1723 if not node:
1724 stat = cmdutil.postcommitstatus(repo, pats, opts)
1724 stat = cmdutil.postcommitstatus(repo, pats, opts)
1725 if stat[3]:
1725 if stat[3]:
1726 ui.status(_("nothing changed (%d missing files, see "
1726 ui.status(_("nothing changed (%d missing files, see "
1727 "'hg status')\n") % len(stat[3]))
1727 "'hg status')\n") % len(stat[3]))
1728 else:
1728 else:
1729 ui.status(_("nothing changed\n"))
1729 ui.status(_("nothing changed\n"))
1730 return 1
1730 return 1
1731
1731
1732 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1732 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1733
1733
1734 @command('config|showconfig|debugconfig',
1734 @command('config|showconfig|debugconfig',
1735 [('u', 'untrusted', None, _('show untrusted configuration options')),
1735 [('u', 'untrusted', None, _('show untrusted configuration options')),
1736 ('e', 'edit', None, _('edit user config')),
1736 ('e', 'edit', None, _('edit user config')),
1737 ('l', 'local', None, _('edit repository config')),
1737 ('l', 'local', None, _('edit repository config')),
1738 ('g', 'global', None, _('edit global config'))] + formatteropts,
1738 ('g', 'global', None, _('edit global config'))] + formatteropts,
1739 _('[-u] [NAME]...'),
1739 _('[-u] [NAME]...'),
1740 optionalrepo=True)
1740 optionalrepo=True)
1741 def config(ui, repo, *values, **opts):
1741 def config(ui, repo, *values, **opts):
1742 """show combined config settings from all hgrc files
1742 """show combined config settings from all hgrc files
1743
1743
1744 With no arguments, print names and values of all config items.
1744 With no arguments, print names and values of all config items.
1745
1745
1746 With one argument of the form section.name, print just the value
1746 With one argument of the form section.name, print just the value
1747 of that config item.
1747 of that config item.
1748
1748
1749 With multiple arguments, print names and values of all config
1749 With multiple arguments, print names and values of all config
1750 items with matching section names.
1750 items with matching section names.
1751
1751
1752 With --edit, start an editor on the user-level config file. With
1752 With --edit, start an editor on the user-level config file. With
1753 --global, edit the system-wide config file. With --local, edit the
1753 --global, edit the system-wide config file. With --local, edit the
1754 repository-level config file.
1754 repository-level config file.
1755
1755
1756 With --debug, the source (filename and line number) is printed
1756 With --debug, the source (filename and line number) is printed
1757 for each config item.
1757 for each config item.
1758
1758
1759 See :hg:`help config` for more information about config files.
1759 See :hg:`help config` for more information about config files.
1760
1760
1761 Returns 0 on success, 1 if NAME does not exist.
1761 Returns 0 on success, 1 if NAME does not exist.
1762
1762
1763 """
1763 """
1764
1764
1765 if opts.get('edit') or opts.get('local') or opts.get('global'):
1765 if opts.get('edit') or opts.get('local') or opts.get('global'):
1766 if opts.get('local') and opts.get('global'):
1766 if opts.get('local') and opts.get('global'):
1767 raise error.Abort(_("can't use --local and --global together"))
1767 raise error.Abort(_("can't use --local and --global together"))
1768
1768
1769 if opts.get('local'):
1769 if opts.get('local'):
1770 if not repo:
1770 if not repo:
1771 raise error.Abort(_("can't use --local outside a repository"))
1771 raise error.Abort(_("can't use --local outside a repository"))
1772 paths = [repo.join('hgrc')]
1772 paths = [repo.join('hgrc')]
1773 elif opts.get('global'):
1773 elif opts.get('global'):
1774 paths = scmutil.systemrcpath()
1774 paths = scmutil.systemrcpath()
1775 else:
1775 else:
1776 paths = scmutil.userrcpath()
1776 paths = scmutil.userrcpath()
1777
1777
1778 for f in paths:
1778 for f in paths:
1779 if os.path.exists(f):
1779 if os.path.exists(f):
1780 break
1780 break
1781 else:
1781 else:
1782 if opts.get('global'):
1782 if opts.get('global'):
1783 samplehgrc = uimod.samplehgrcs['global']
1783 samplehgrc = uimod.samplehgrcs['global']
1784 elif opts.get('local'):
1784 elif opts.get('local'):
1785 samplehgrc = uimod.samplehgrcs['local']
1785 samplehgrc = uimod.samplehgrcs['local']
1786 else:
1786 else:
1787 samplehgrc = uimod.samplehgrcs['user']
1787 samplehgrc = uimod.samplehgrcs['user']
1788
1788
1789 f = paths[0]
1789 f = paths[0]
1790 fp = open(f, "w")
1790 fp = open(f, "w")
1791 fp.write(samplehgrc)
1791 fp.write(samplehgrc)
1792 fp.close()
1792 fp.close()
1793
1793
1794 editor = ui.geteditor()
1794 editor = ui.geteditor()
1795 ui.system("%s \"%s\"" % (editor, f),
1795 ui.system("%s \"%s\"" % (editor, f),
1796 onerr=error.Abort, errprefix=_("edit failed"))
1796 onerr=error.Abort, errprefix=_("edit failed"))
1797 return
1797 return
1798
1798
1799 fm = ui.formatter('config', opts)
1799 fm = ui.formatter('config', opts)
1800 for f in scmutil.rcpath():
1800 for f in scmutil.rcpath():
1801 ui.debug('read config from: %s\n' % f)
1801 ui.debug('read config from: %s\n' % f)
1802 untrusted = bool(opts.get('untrusted'))
1802 untrusted = bool(opts.get('untrusted'))
1803 if values:
1803 if values:
1804 sections = [v for v in values if '.' not in v]
1804 sections = [v for v in values if '.' not in v]
1805 items = [v for v in values if '.' in v]
1805 items = [v for v in values if '.' in v]
1806 if len(items) > 1 or items and sections:
1806 if len(items) > 1 or items and sections:
1807 raise error.Abort(_('only one config item permitted'))
1807 raise error.Abort(_('only one config item permitted'))
1808 matched = False
1808 matched = False
1809 for section, name, value in ui.walkconfig(untrusted=untrusted):
1809 for section, name, value in ui.walkconfig(untrusted=untrusted):
1810 source = ui.configsource(section, name, untrusted)
1810 source = ui.configsource(section, name, untrusted)
1811 value = str(value)
1811 value = str(value)
1812 if fm.isplain():
1812 if fm.isplain():
1813 source = source or 'none'
1813 source = source or 'none'
1814 value = value.replace('\n', '\\n')
1814 value = value.replace('\n', '\\n')
1815 entryname = section + '.' + name
1815 entryname = section + '.' + name
1816 if values:
1816 if values:
1817 for v in values:
1817 for v in values:
1818 if v == section:
1818 if v == section:
1819 fm.startitem()
1819 fm.startitem()
1820 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1820 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1821 fm.write('name value', '%s=%s\n', entryname, value)
1821 fm.write('name value', '%s=%s\n', entryname, value)
1822 matched = True
1822 matched = True
1823 elif v == entryname:
1823 elif v == entryname:
1824 fm.startitem()
1824 fm.startitem()
1825 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1825 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1826 fm.write('value', '%s\n', value)
1826 fm.write('value', '%s\n', value)
1827 fm.data(name=entryname)
1827 fm.data(name=entryname)
1828 matched = True
1828 matched = True
1829 else:
1829 else:
1830 fm.startitem()
1830 fm.startitem()
1831 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1831 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1832 fm.write('name value', '%s=%s\n', entryname, value)
1832 fm.write('name value', '%s=%s\n', entryname, value)
1833 matched = True
1833 matched = True
1834 fm.end()
1834 fm.end()
1835 if matched:
1835 if matched:
1836 return 0
1836 return 0
1837 return 1
1837 return 1
1838
1838
1839 @command('copy|cp',
1839 @command('copy|cp',
1840 [('A', 'after', None, _('record a copy that has already occurred')),
1840 [('A', 'after', None, _('record a copy that has already occurred')),
1841 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1841 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1842 ] + walkopts + dryrunopts,
1842 ] + walkopts + dryrunopts,
1843 _('[OPTION]... [SOURCE]... DEST'))
1843 _('[OPTION]... [SOURCE]... DEST'))
1844 def copy(ui, repo, *pats, **opts):
1844 def copy(ui, repo, *pats, **opts):
1845 """mark files as copied for the next commit
1845 """mark files as copied for the next commit
1846
1846
1847 Mark dest as having copies of source files. If dest is a
1847 Mark dest as having copies of source files. If dest is a
1848 directory, copies are put in that directory. If dest is a file,
1848 directory, copies are put in that directory. If dest is a file,
1849 the source must be a single file.
1849 the source must be a single file.
1850
1850
1851 By default, this command copies the contents of files as they
1851 By default, this command copies the contents of files as they
1852 exist in the working directory. If invoked with -A/--after, the
1852 exist in the working directory. If invoked with -A/--after, the
1853 operation is recorded, but no copying is performed.
1853 operation is recorded, but no copying is performed.
1854
1854
1855 This command takes effect with the next commit. To undo a copy
1855 This command takes effect with the next commit. To undo a copy
1856 before that, see :hg:`revert`.
1856 before that, see :hg:`revert`.
1857
1857
1858 Returns 0 on success, 1 if errors are encountered.
1858 Returns 0 on success, 1 if errors are encountered.
1859 """
1859 """
1860 with repo.wlock(False):
1860 with repo.wlock(False):
1861 return cmdutil.copy(ui, repo, pats, opts)
1861 return cmdutil.copy(ui, repo, pats, opts)
1862
1862
1863 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1864 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1865 '''access the pushkey key/value protocol
1866
1867 With two args, list the keys in the given namespace.
1868
1869 With five args, set a key to new if it currently is set to old.
1870 Reports success or failure.
1871 '''
1872
1873 target = hg.peer(ui, {}, repopath)
1874 if keyinfo:
1875 key, old, new = keyinfo
1876 r = target.pushkey(namespace, key, old, new)
1877 ui.status(str(r) + '\n')
1878 return not r
1879 else:
1880 for k, v in sorted(target.listkeys(namespace).iteritems()):
1881 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1882 v.encode('string-escape')))
1883
1884 @command('debugpvec', [], _('A B'))
1863 @command('debugpvec', [], _('A B'))
1885 def debugpvec(ui, repo, a, b=None):
1864 def debugpvec(ui, repo, a, b=None):
1886 ca = scmutil.revsingle(repo, a)
1865 ca = scmutil.revsingle(repo, a)
1887 cb = scmutil.revsingle(repo, b)
1866 cb = scmutil.revsingle(repo, b)
1888 pa = pvec.ctxpvec(ca)
1867 pa = pvec.ctxpvec(ca)
1889 pb = pvec.ctxpvec(cb)
1868 pb = pvec.ctxpvec(cb)
1890 if pa == pb:
1869 if pa == pb:
1891 rel = "="
1870 rel = "="
1892 elif pa > pb:
1871 elif pa > pb:
1893 rel = ">"
1872 rel = ">"
1894 elif pa < pb:
1873 elif pa < pb:
1895 rel = "<"
1874 rel = "<"
1896 elif pa | pb:
1875 elif pa | pb:
1897 rel = "|"
1876 rel = "|"
1898 ui.write(_("a: %s\n") % pa)
1877 ui.write(_("a: %s\n") % pa)
1899 ui.write(_("b: %s\n") % pb)
1878 ui.write(_("b: %s\n") % pb)
1900 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1879 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1901 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1880 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1902 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1881 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1903 pa.distance(pb), rel))
1882 pa.distance(pb), rel))
1904
1883
1905 @command('debugrebuilddirstate|debugrebuildstate',
1884 @command('debugrebuilddirstate|debugrebuildstate',
1906 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1885 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1907 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1886 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1908 'the working copy parent')),
1887 'the working copy parent')),
1909 ],
1888 ],
1910 _('[-r REV]'))
1889 _('[-r REV]'))
1911 def debugrebuilddirstate(ui, repo, rev, **opts):
1890 def debugrebuilddirstate(ui, repo, rev, **opts):
1912 """rebuild the dirstate as it would look like for the given revision
1891 """rebuild the dirstate as it would look like for the given revision
1913
1892
1914 If no revision is specified the first current parent will be used.
1893 If no revision is specified the first current parent will be used.
1915
1894
1916 The dirstate will be set to the files of the given revision.
1895 The dirstate will be set to the files of the given revision.
1917 The actual working directory content or existing dirstate
1896 The actual working directory content or existing dirstate
1918 information such as adds or removes is not considered.
1897 information such as adds or removes is not considered.
1919
1898
1920 ``minimal`` will only rebuild the dirstate status for files that claim to be
1899 ``minimal`` will only rebuild the dirstate status for files that claim to be
1921 tracked but are not in the parent manifest, or that exist in the parent
1900 tracked but are not in the parent manifest, or that exist in the parent
1922 manifest but are not in the dirstate. It will not change adds, removes, or
1901 manifest but are not in the dirstate. It will not change adds, removes, or
1923 modified files that are in the working copy parent.
1902 modified files that are in the working copy parent.
1924
1903
1925 One use of this command is to make the next :hg:`status` invocation
1904 One use of this command is to make the next :hg:`status` invocation
1926 check the actual file content.
1905 check the actual file content.
1927 """
1906 """
1928 ctx = scmutil.revsingle(repo, rev)
1907 ctx = scmutil.revsingle(repo, rev)
1929 with repo.wlock():
1908 with repo.wlock():
1930 dirstate = repo.dirstate
1909 dirstate = repo.dirstate
1931 changedfiles = None
1910 changedfiles = None
1932 # See command doc for what minimal does.
1911 # See command doc for what minimal does.
1933 if opts.get('minimal'):
1912 if opts.get('minimal'):
1934 manifestfiles = set(ctx.manifest().keys())
1913 manifestfiles = set(ctx.manifest().keys())
1935 dirstatefiles = set(dirstate)
1914 dirstatefiles = set(dirstate)
1936 manifestonly = manifestfiles - dirstatefiles
1915 manifestonly = manifestfiles - dirstatefiles
1937 dsonly = dirstatefiles - manifestfiles
1916 dsonly = dirstatefiles - manifestfiles
1938 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1917 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1939 changedfiles = manifestonly | dsnotadded
1918 changedfiles = manifestonly | dsnotadded
1940
1919
1941 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1920 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1942
1921
1943 @command('debugrebuildfncache', [], '')
1922 @command('debugrebuildfncache', [], '')
1944 def debugrebuildfncache(ui, repo):
1923 def debugrebuildfncache(ui, repo):
1945 """rebuild the fncache file"""
1924 """rebuild the fncache file"""
1946 repair.rebuildfncache(ui, repo)
1925 repair.rebuildfncache(ui, repo)
1947
1926
1948 @command('debugrename',
1927 @command('debugrename',
1949 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1928 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1950 _('[-r REV] FILE'))
1929 _('[-r REV] FILE'))
1951 def debugrename(ui, repo, file1, *pats, **opts):
1930 def debugrename(ui, repo, file1, *pats, **opts):
1952 """dump rename information"""
1931 """dump rename information"""
1953
1932
1954 ctx = scmutil.revsingle(repo, opts.get('rev'))
1933 ctx = scmutil.revsingle(repo, opts.get('rev'))
1955 m = scmutil.match(ctx, (file1,) + pats, opts)
1934 m = scmutil.match(ctx, (file1,) + pats, opts)
1956 for abs in ctx.walk(m):
1935 for abs in ctx.walk(m):
1957 fctx = ctx[abs]
1936 fctx = ctx[abs]
1958 o = fctx.filelog().renamed(fctx.filenode())
1937 o = fctx.filelog().renamed(fctx.filenode())
1959 rel = m.rel(abs)
1938 rel = m.rel(abs)
1960 if o:
1939 if o:
1961 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1940 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1962 else:
1941 else:
1963 ui.write(_("%s not renamed\n") % rel)
1942 ui.write(_("%s not renamed\n") % rel)
1964
1943
1965 @command('debugrevlog', debugrevlogopts +
1944 @command('debugrevlog', debugrevlogopts +
1966 [('d', 'dump', False, _('dump index data'))],
1945 [('d', 'dump', False, _('dump index data'))],
1967 _('-c|-m|FILE'),
1946 _('-c|-m|FILE'),
1968 optionalrepo=True)
1947 optionalrepo=True)
1969 def debugrevlog(ui, repo, file_=None, **opts):
1948 def debugrevlog(ui, repo, file_=None, **opts):
1970 """show data and statistics about a revlog"""
1949 """show data and statistics about a revlog"""
1971 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1950 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1972
1951
1973 if opts.get("dump"):
1952 if opts.get("dump"):
1974 numrevs = len(r)
1953 numrevs = len(r)
1975 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1954 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1976 " rawsize totalsize compression heads chainlen\n"))
1955 " rawsize totalsize compression heads chainlen\n"))
1977 ts = 0
1956 ts = 0
1978 heads = set()
1957 heads = set()
1979
1958
1980 for rev in xrange(numrevs):
1959 for rev in xrange(numrevs):
1981 dbase = r.deltaparent(rev)
1960 dbase = r.deltaparent(rev)
1982 if dbase == -1:
1961 if dbase == -1:
1983 dbase = rev
1962 dbase = rev
1984 cbase = r.chainbase(rev)
1963 cbase = r.chainbase(rev)
1985 clen = r.chainlen(rev)
1964 clen = r.chainlen(rev)
1986 p1, p2 = r.parentrevs(rev)
1965 p1, p2 = r.parentrevs(rev)
1987 rs = r.rawsize(rev)
1966 rs = r.rawsize(rev)
1988 ts = ts + rs
1967 ts = ts + rs
1989 heads -= set(r.parentrevs(rev))
1968 heads -= set(r.parentrevs(rev))
1990 heads.add(rev)
1969 heads.add(rev)
1991 try:
1970 try:
1992 compression = ts / r.end(rev)
1971 compression = ts / r.end(rev)
1993 except ZeroDivisionError:
1972 except ZeroDivisionError:
1994 compression = 0
1973 compression = 0
1995 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1974 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1996 "%11d %5d %8d\n" %
1975 "%11d %5d %8d\n" %
1997 (rev, p1, p2, r.start(rev), r.end(rev),
1976 (rev, p1, p2, r.start(rev), r.end(rev),
1998 r.start(dbase), r.start(cbase),
1977 r.start(dbase), r.start(cbase),
1999 r.start(p1), r.start(p2),
1978 r.start(p1), r.start(p2),
2000 rs, ts, compression, len(heads), clen))
1979 rs, ts, compression, len(heads), clen))
2001 return 0
1980 return 0
2002
1981
2003 v = r.version
1982 v = r.version
2004 format = v & 0xFFFF
1983 format = v & 0xFFFF
2005 flags = []
1984 flags = []
2006 gdelta = False
1985 gdelta = False
2007 if v & revlog.REVLOGNGINLINEDATA:
1986 if v & revlog.REVLOGNGINLINEDATA:
2008 flags.append('inline')
1987 flags.append('inline')
2009 if v & revlog.REVLOGGENERALDELTA:
1988 if v & revlog.REVLOGGENERALDELTA:
2010 gdelta = True
1989 gdelta = True
2011 flags.append('generaldelta')
1990 flags.append('generaldelta')
2012 if not flags:
1991 if not flags:
2013 flags = ['(none)']
1992 flags = ['(none)']
2014
1993
2015 nummerges = 0
1994 nummerges = 0
2016 numfull = 0
1995 numfull = 0
2017 numprev = 0
1996 numprev = 0
2018 nump1 = 0
1997 nump1 = 0
2019 nump2 = 0
1998 nump2 = 0
2020 numother = 0
1999 numother = 0
2021 nump1prev = 0
2000 nump1prev = 0
2022 nump2prev = 0
2001 nump2prev = 0
2023 chainlengths = []
2002 chainlengths = []
2024
2003
2025 datasize = [None, 0, 0]
2004 datasize = [None, 0, 0]
2026 fullsize = [None, 0, 0]
2005 fullsize = [None, 0, 0]
2027 deltasize = [None, 0, 0]
2006 deltasize = [None, 0, 0]
2028 chunktypecounts = {}
2007 chunktypecounts = {}
2029 chunktypesizes = {}
2008 chunktypesizes = {}
2030
2009
2031 def addsize(size, l):
2010 def addsize(size, l):
2032 if l[0] is None or size < l[0]:
2011 if l[0] is None or size < l[0]:
2033 l[0] = size
2012 l[0] = size
2034 if size > l[1]:
2013 if size > l[1]:
2035 l[1] = size
2014 l[1] = size
2036 l[2] += size
2015 l[2] += size
2037
2016
2038 numrevs = len(r)
2017 numrevs = len(r)
2039 for rev in xrange(numrevs):
2018 for rev in xrange(numrevs):
2040 p1, p2 = r.parentrevs(rev)
2019 p1, p2 = r.parentrevs(rev)
2041 delta = r.deltaparent(rev)
2020 delta = r.deltaparent(rev)
2042 if format > 0:
2021 if format > 0:
2043 addsize(r.rawsize(rev), datasize)
2022 addsize(r.rawsize(rev), datasize)
2044 if p2 != nullrev:
2023 if p2 != nullrev:
2045 nummerges += 1
2024 nummerges += 1
2046 size = r.length(rev)
2025 size = r.length(rev)
2047 if delta == nullrev:
2026 if delta == nullrev:
2048 chainlengths.append(0)
2027 chainlengths.append(0)
2049 numfull += 1
2028 numfull += 1
2050 addsize(size, fullsize)
2029 addsize(size, fullsize)
2051 else:
2030 else:
2052 chainlengths.append(chainlengths[delta] + 1)
2031 chainlengths.append(chainlengths[delta] + 1)
2053 addsize(size, deltasize)
2032 addsize(size, deltasize)
2054 if delta == rev - 1:
2033 if delta == rev - 1:
2055 numprev += 1
2034 numprev += 1
2056 if delta == p1:
2035 if delta == p1:
2057 nump1prev += 1
2036 nump1prev += 1
2058 elif delta == p2:
2037 elif delta == p2:
2059 nump2prev += 1
2038 nump2prev += 1
2060 elif delta == p1:
2039 elif delta == p1:
2061 nump1 += 1
2040 nump1 += 1
2062 elif delta == p2:
2041 elif delta == p2:
2063 nump2 += 1
2042 nump2 += 1
2064 elif delta != nullrev:
2043 elif delta != nullrev:
2065 numother += 1
2044 numother += 1
2066
2045
2067 # Obtain data on the raw chunks in the revlog.
2046 # Obtain data on the raw chunks in the revlog.
2068 chunk = r._chunkraw(rev, rev)[1]
2047 chunk = r._chunkraw(rev, rev)[1]
2069 if chunk:
2048 if chunk:
2070 chunktype = chunk[0]
2049 chunktype = chunk[0]
2071 else:
2050 else:
2072 chunktype = 'empty'
2051 chunktype = 'empty'
2073
2052
2074 if chunktype not in chunktypecounts:
2053 if chunktype not in chunktypecounts:
2075 chunktypecounts[chunktype] = 0
2054 chunktypecounts[chunktype] = 0
2076 chunktypesizes[chunktype] = 0
2055 chunktypesizes[chunktype] = 0
2077
2056
2078 chunktypecounts[chunktype] += 1
2057 chunktypecounts[chunktype] += 1
2079 chunktypesizes[chunktype] += size
2058 chunktypesizes[chunktype] += size
2080
2059
2081 # Adjust size min value for empty cases
2060 # Adjust size min value for empty cases
2082 for size in (datasize, fullsize, deltasize):
2061 for size in (datasize, fullsize, deltasize):
2083 if size[0] is None:
2062 if size[0] is None:
2084 size[0] = 0
2063 size[0] = 0
2085
2064
2086 numdeltas = numrevs - numfull
2065 numdeltas = numrevs - numfull
2087 numoprev = numprev - nump1prev - nump2prev
2066 numoprev = numprev - nump1prev - nump2prev
2088 totalrawsize = datasize[2]
2067 totalrawsize = datasize[2]
2089 datasize[2] /= numrevs
2068 datasize[2] /= numrevs
2090 fulltotal = fullsize[2]
2069 fulltotal = fullsize[2]
2091 fullsize[2] /= numfull
2070 fullsize[2] /= numfull
2092 deltatotal = deltasize[2]
2071 deltatotal = deltasize[2]
2093 if numrevs - numfull > 0:
2072 if numrevs - numfull > 0:
2094 deltasize[2] /= numrevs - numfull
2073 deltasize[2] /= numrevs - numfull
2095 totalsize = fulltotal + deltatotal
2074 totalsize = fulltotal + deltatotal
2096 avgchainlen = sum(chainlengths) / numrevs
2075 avgchainlen = sum(chainlengths) / numrevs
2097 maxchainlen = max(chainlengths)
2076 maxchainlen = max(chainlengths)
2098 compratio = 1
2077 compratio = 1
2099 if totalsize:
2078 if totalsize:
2100 compratio = totalrawsize / totalsize
2079 compratio = totalrawsize / totalsize
2101
2080
2102 basedfmtstr = '%%%dd\n'
2081 basedfmtstr = '%%%dd\n'
2103 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2082 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2104
2083
2105 def dfmtstr(max):
2084 def dfmtstr(max):
2106 return basedfmtstr % len(str(max))
2085 return basedfmtstr % len(str(max))
2107 def pcfmtstr(max, padding=0):
2086 def pcfmtstr(max, padding=0):
2108 return basepcfmtstr % (len(str(max)), ' ' * padding)
2087 return basepcfmtstr % (len(str(max)), ' ' * padding)
2109
2088
2110 def pcfmt(value, total):
2089 def pcfmt(value, total):
2111 if total:
2090 if total:
2112 return (value, 100 * float(value) / total)
2091 return (value, 100 * float(value) / total)
2113 else:
2092 else:
2114 return value, 100.0
2093 return value, 100.0
2115
2094
2116 ui.write(('format : %d\n') % format)
2095 ui.write(('format : %d\n') % format)
2117 ui.write(('flags : %s\n') % ', '.join(flags))
2096 ui.write(('flags : %s\n') % ', '.join(flags))
2118
2097
2119 ui.write('\n')
2098 ui.write('\n')
2120 fmt = pcfmtstr(totalsize)
2099 fmt = pcfmtstr(totalsize)
2121 fmt2 = dfmtstr(totalsize)
2100 fmt2 = dfmtstr(totalsize)
2122 ui.write(('revisions : ') + fmt2 % numrevs)
2101 ui.write(('revisions : ') + fmt2 % numrevs)
2123 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2102 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2124 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2103 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2125 ui.write(('revisions : ') + fmt2 % numrevs)
2104 ui.write(('revisions : ') + fmt2 % numrevs)
2126 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2105 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2127 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2106 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2128 ui.write(('revision size : ') + fmt2 % totalsize)
2107 ui.write(('revision size : ') + fmt2 % totalsize)
2129 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2108 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2130 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2109 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2131
2110
2132 def fmtchunktype(chunktype):
2111 def fmtchunktype(chunktype):
2133 if chunktype == 'empty':
2112 if chunktype == 'empty':
2134 return ' %s : ' % chunktype
2113 return ' %s : ' % chunktype
2135 elif chunktype in string.ascii_letters:
2114 elif chunktype in string.ascii_letters:
2136 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2115 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2137 else:
2116 else:
2138 return ' 0x%s : ' % hex(chunktype)
2117 return ' 0x%s : ' % hex(chunktype)
2139
2118
2140 ui.write('\n')
2119 ui.write('\n')
2141 ui.write(('chunks : ') + fmt2 % numrevs)
2120 ui.write(('chunks : ') + fmt2 % numrevs)
2142 for chunktype in sorted(chunktypecounts):
2121 for chunktype in sorted(chunktypecounts):
2143 ui.write(fmtchunktype(chunktype))
2122 ui.write(fmtchunktype(chunktype))
2144 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2123 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2145 ui.write(('chunks size : ') + fmt2 % totalsize)
2124 ui.write(('chunks size : ') + fmt2 % totalsize)
2146 for chunktype in sorted(chunktypecounts):
2125 for chunktype in sorted(chunktypecounts):
2147 ui.write(fmtchunktype(chunktype))
2126 ui.write(fmtchunktype(chunktype))
2148 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2127 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2149
2128
2150 ui.write('\n')
2129 ui.write('\n')
2151 fmt = dfmtstr(max(avgchainlen, compratio))
2130 fmt = dfmtstr(max(avgchainlen, compratio))
2152 ui.write(('avg chain length : ') + fmt % avgchainlen)
2131 ui.write(('avg chain length : ') + fmt % avgchainlen)
2153 ui.write(('max chain length : ') + fmt % maxchainlen)
2132 ui.write(('max chain length : ') + fmt % maxchainlen)
2154 ui.write(('compression ratio : ') + fmt % compratio)
2133 ui.write(('compression ratio : ') + fmt % compratio)
2155
2134
2156 if format > 0:
2135 if format > 0:
2157 ui.write('\n')
2136 ui.write('\n')
2158 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2137 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2159 % tuple(datasize))
2138 % tuple(datasize))
2160 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2139 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2161 % tuple(fullsize))
2140 % tuple(fullsize))
2162 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2141 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2163 % tuple(deltasize))
2142 % tuple(deltasize))
2164
2143
2165 if numdeltas > 0:
2144 if numdeltas > 0:
2166 ui.write('\n')
2145 ui.write('\n')
2167 fmt = pcfmtstr(numdeltas)
2146 fmt = pcfmtstr(numdeltas)
2168 fmt2 = pcfmtstr(numdeltas, 4)
2147 fmt2 = pcfmtstr(numdeltas, 4)
2169 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2148 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2170 if numprev > 0:
2149 if numprev > 0:
2171 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2150 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2172 numprev))
2151 numprev))
2173 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2152 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2174 numprev))
2153 numprev))
2175 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2154 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2176 numprev))
2155 numprev))
2177 if gdelta:
2156 if gdelta:
2178 ui.write(('deltas against p1 : ')
2157 ui.write(('deltas against p1 : ')
2179 + fmt % pcfmt(nump1, numdeltas))
2158 + fmt % pcfmt(nump1, numdeltas))
2180 ui.write(('deltas against p2 : ')
2159 ui.write(('deltas against p2 : ')
2181 + fmt % pcfmt(nump2, numdeltas))
2160 + fmt % pcfmt(nump2, numdeltas))
2182 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2161 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2183 numdeltas))
2162 numdeltas))
2184
2163
2185 @command('debugrevspec',
2164 @command('debugrevspec',
2186 [('', 'optimize', None,
2165 [('', 'optimize', None,
2187 _('print parsed tree after optimizing (DEPRECATED)')),
2166 _('print parsed tree after optimizing (DEPRECATED)')),
2188 ('p', 'show-stage', [],
2167 ('p', 'show-stage', [],
2189 _('print parsed tree at the given stage'), _('NAME')),
2168 _('print parsed tree at the given stage'), _('NAME')),
2190 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2169 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2191 ('', 'verify-optimized', False, _('verify optimized result')),
2170 ('', 'verify-optimized', False, _('verify optimized result')),
2192 ],
2171 ],
2193 ('REVSPEC'))
2172 ('REVSPEC'))
2194 def debugrevspec(ui, repo, expr, **opts):
2173 def debugrevspec(ui, repo, expr, **opts):
2195 """parse and apply a revision specification
2174 """parse and apply a revision specification
2196
2175
2197 Use -p/--show-stage option to print the parsed tree at the given stages.
2176 Use -p/--show-stage option to print the parsed tree at the given stages.
2198 Use -p all to print tree at every stage.
2177 Use -p all to print tree at every stage.
2199
2178
2200 Use --verify-optimized to compare the optimized result with the unoptimized
2179 Use --verify-optimized to compare the optimized result with the unoptimized
2201 one. Returns 1 if the optimized result differs.
2180 one. Returns 1 if the optimized result differs.
2202 """
2181 """
2203 stages = [
2182 stages = [
2204 ('parsed', lambda tree: tree),
2183 ('parsed', lambda tree: tree),
2205 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2184 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2206 ('concatenated', revset.foldconcat),
2185 ('concatenated', revset.foldconcat),
2207 ('analyzed', revset.analyze),
2186 ('analyzed', revset.analyze),
2208 ('optimized', revset.optimize),
2187 ('optimized', revset.optimize),
2209 ]
2188 ]
2210 if opts['no_optimized']:
2189 if opts['no_optimized']:
2211 stages = stages[:-1]
2190 stages = stages[:-1]
2212 if opts['verify_optimized'] and opts['no_optimized']:
2191 if opts['verify_optimized'] and opts['no_optimized']:
2213 raise error.Abort(_('cannot use --verify-optimized with '
2192 raise error.Abort(_('cannot use --verify-optimized with '
2214 '--no-optimized'))
2193 '--no-optimized'))
2215 stagenames = set(n for n, f in stages)
2194 stagenames = set(n for n, f in stages)
2216
2195
2217 showalways = set()
2196 showalways = set()
2218 showchanged = set()
2197 showchanged = set()
2219 if ui.verbose and not opts['show_stage']:
2198 if ui.verbose and not opts['show_stage']:
2220 # show parsed tree by --verbose (deprecated)
2199 # show parsed tree by --verbose (deprecated)
2221 showalways.add('parsed')
2200 showalways.add('parsed')
2222 showchanged.update(['expanded', 'concatenated'])
2201 showchanged.update(['expanded', 'concatenated'])
2223 if opts['optimize']:
2202 if opts['optimize']:
2224 showalways.add('optimized')
2203 showalways.add('optimized')
2225 if opts['show_stage'] and opts['optimize']:
2204 if opts['show_stage'] and opts['optimize']:
2226 raise error.Abort(_('cannot use --optimize with --show-stage'))
2205 raise error.Abort(_('cannot use --optimize with --show-stage'))
2227 if opts['show_stage'] == ['all']:
2206 if opts['show_stage'] == ['all']:
2228 showalways.update(stagenames)
2207 showalways.update(stagenames)
2229 else:
2208 else:
2230 for n in opts['show_stage']:
2209 for n in opts['show_stage']:
2231 if n not in stagenames:
2210 if n not in stagenames:
2232 raise error.Abort(_('invalid stage name: %s') % n)
2211 raise error.Abort(_('invalid stage name: %s') % n)
2233 showalways.update(opts['show_stage'])
2212 showalways.update(opts['show_stage'])
2234
2213
2235 treebystage = {}
2214 treebystage = {}
2236 printedtree = None
2215 printedtree = None
2237 tree = revset.parse(expr, lookup=repo.__contains__)
2216 tree = revset.parse(expr, lookup=repo.__contains__)
2238 for n, f in stages:
2217 for n, f in stages:
2239 treebystage[n] = tree = f(tree)
2218 treebystage[n] = tree = f(tree)
2240 if n in showalways or (n in showchanged and tree != printedtree):
2219 if n in showalways or (n in showchanged and tree != printedtree):
2241 if opts['show_stage'] or n != 'parsed':
2220 if opts['show_stage'] or n != 'parsed':
2242 ui.write(("* %s:\n") % n)
2221 ui.write(("* %s:\n") % n)
2243 ui.write(revset.prettyformat(tree), "\n")
2222 ui.write(revset.prettyformat(tree), "\n")
2244 printedtree = tree
2223 printedtree = tree
2245
2224
2246 if opts['verify_optimized']:
2225 if opts['verify_optimized']:
2247 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2226 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2248 brevs = revset.makematcher(treebystage['optimized'])(repo)
2227 brevs = revset.makematcher(treebystage['optimized'])(repo)
2249 if ui.verbose:
2228 if ui.verbose:
2250 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2229 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2251 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2230 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2252 arevs = list(arevs)
2231 arevs = list(arevs)
2253 brevs = list(brevs)
2232 brevs = list(brevs)
2254 if arevs == brevs:
2233 if arevs == brevs:
2255 return 0
2234 return 0
2256 ui.write(('--- analyzed\n'), label='diff.file_a')
2235 ui.write(('--- analyzed\n'), label='diff.file_a')
2257 ui.write(('+++ optimized\n'), label='diff.file_b')
2236 ui.write(('+++ optimized\n'), label='diff.file_b')
2258 sm = difflib.SequenceMatcher(None, arevs, brevs)
2237 sm = difflib.SequenceMatcher(None, arevs, brevs)
2259 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2238 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2260 if tag in ('delete', 'replace'):
2239 if tag in ('delete', 'replace'):
2261 for c in arevs[alo:ahi]:
2240 for c in arevs[alo:ahi]:
2262 ui.write('-%s\n' % c, label='diff.deleted')
2241 ui.write('-%s\n' % c, label='diff.deleted')
2263 if tag in ('insert', 'replace'):
2242 if tag in ('insert', 'replace'):
2264 for c in brevs[blo:bhi]:
2243 for c in brevs[blo:bhi]:
2265 ui.write('+%s\n' % c, label='diff.inserted')
2244 ui.write('+%s\n' % c, label='diff.inserted')
2266 if tag == 'equal':
2245 if tag == 'equal':
2267 for c in arevs[alo:ahi]:
2246 for c in arevs[alo:ahi]:
2268 ui.write(' %s\n' % c)
2247 ui.write(' %s\n' % c)
2269 return 1
2248 return 1
2270
2249
2271 func = revset.makematcher(tree)
2250 func = revset.makematcher(tree)
2272 revs = func(repo)
2251 revs = func(repo)
2273 if ui.verbose:
2252 if ui.verbose:
2274 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2253 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2275 for c in revs:
2254 for c in revs:
2276 ui.write("%s\n" % c)
2255 ui.write("%s\n" % c)
2277
2256
2278 @command('debugsetparents', [], _('REV1 [REV2]'))
2257 @command('debugsetparents', [], _('REV1 [REV2]'))
2279 def debugsetparents(ui, repo, rev1, rev2=None):
2258 def debugsetparents(ui, repo, rev1, rev2=None):
2280 """manually set the parents of the current working directory
2259 """manually set the parents of the current working directory
2281
2260
2282 This is useful for writing repository conversion tools, but should
2261 This is useful for writing repository conversion tools, but should
2283 be used with care. For example, neither the working directory nor the
2262 be used with care. For example, neither the working directory nor the
2284 dirstate is updated, so file status may be incorrect after running this
2263 dirstate is updated, so file status may be incorrect after running this
2285 command.
2264 command.
2286
2265
2287 Returns 0 on success.
2266 Returns 0 on success.
2288 """
2267 """
2289
2268
2290 r1 = scmutil.revsingle(repo, rev1).node()
2269 r1 = scmutil.revsingle(repo, rev1).node()
2291 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2270 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2292
2271
2293 with repo.wlock():
2272 with repo.wlock():
2294 repo.setparents(r1, r2)
2273 repo.setparents(r1, r2)
2295
2274
2296 @command('debugdirstate|debugstate',
2275 @command('debugdirstate|debugstate',
2297 [('', 'nodates', None, _('do not display the saved mtime')),
2276 [('', 'nodates', None, _('do not display the saved mtime')),
2298 ('', 'datesort', None, _('sort by saved mtime'))],
2277 ('', 'datesort', None, _('sort by saved mtime'))],
2299 _('[OPTION]...'))
2278 _('[OPTION]...'))
2300 def debugstate(ui, repo, **opts):
2279 def debugstate(ui, repo, **opts):
2301 """show the contents of the current dirstate"""
2280 """show the contents of the current dirstate"""
2302
2281
2303 nodates = opts.get('nodates')
2282 nodates = opts.get('nodates')
2304 datesort = opts.get('datesort')
2283 datesort = opts.get('datesort')
2305
2284
2306 timestr = ""
2285 timestr = ""
2307 if datesort:
2286 if datesort:
2308 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2287 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2309 else:
2288 else:
2310 keyfunc = None # sort by filename
2289 keyfunc = None # sort by filename
2311 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2290 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2312 if ent[3] == -1:
2291 if ent[3] == -1:
2313 timestr = 'unset '
2292 timestr = 'unset '
2314 elif nodates:
2293 elif nodates:
2315 timestr = 'set '
2294 timestr = 'set '
2316 else:
2295 else:
2317 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2296 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2318 time.localtime(ent[3]))
2297 time.localtime(ent[3]))
2319 if ent[1] & 0o20000:
2298 if ent[1] & 0o20000:
2320 mode = 'lnk'
2299 mode = 'lnk'
2321 else:
2300 else:
2322 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2301 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2323 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2302 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2324 for f in repo.dirstate.copies():
2303 for f in repo.dirstate.copies():
2325 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2304 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2326
2305
2327 @command('debugsub',
2306 @command('debugsub',
2328 [('r', 'rev', '',
2307 [('r', 'rev', '',
2329 _('revision to check'), _('REV'))],
2308 _('revision to check'), _('REV'))],
2330 _('[-r REV] [REV]'))
2309 _('[-r REV] [REV]'))
2331 def debugsub(ui, repo, rev=None):
2310 def debugsub(ui, repo, rev=None):
2332 ctx = scmutil.revsingle(repo, rev, None)
2311 ctx = scmutil.revsingle(repo, rev, None)
2333 for k, v in sorted(ctx.substate.items()):
2312 for k, v in sorted(ctx.substate.items()):
2334 ui.write(('path %s\n') % k)
2313 ui.write(('path %s\n') % k)
2335 ui.write((' source %s\n') % v[0])
2314 ui.write((' source %s\n') % v[0])
2336 ui.write((' revision %s\n') % v[1])
2315 ui.write((' revision %s\n') % v[1])
2337
2316
2338 @command('debugsuccessorssets',
2317 @command('debugsuccessorssets',
2339 [],
2318 [],
2340 _('[REV]'))
2319 _('[REV]'))
2341 def debugsuccessorssets(ui, repo, *revs):
2320 def debugsuccessorssets(ui, repo, *revs):
2342 """show set of successors for revision
2321 """show set of successors for revision
2343
2322
2344 A successors set of changeset A is a consistent group of revisions that
2323 A successors set of changeset A is a consistent group of revisions that
2345 succeed A. It contains non-obsolete changesets only.
2324 succeed A. It contains non-obsolete changesets only.
2346
2325
2347 In most cases a changeset A has a single successors set containing a single
2326 In most cases a changeset A has a single successors set containing a single
2348 successor (changeset A replaced by A').
2327 successor (changeset A replaced by A').
2349
2328
2350 A changeset that is made obsolete with no successors are called "pruned".
2329 A changeset that is made obsolete with no successors are called "pruned".
2351 Such changesets have no successors sets at all.
2330 Such changesets have no successors sets at all.
2352
2331
2353 A changeset that has been "split" will have a successors set containing
2332 A changeset that has been "split" will have a successors set containing
2354 more than one successor.
2333 more than one successor.
2355
2334
2356 A changeset that has been rewritten in multiple different ways is called
2335 A changeset that has been rewritten in multiple different ways is called
2357 "divergent". Such changesets have multiple successor sets (each of which
2336 "divergent". Such changesets have multiple successor sets (each of which
2358 may also be split, i.e. have multiple successors).
2337 may also be split, i.e. have multiple successors).
2359
2338
2360 Results are displayed as follows::
2339 Results are displayed as follows::
2361
2340
2362 <rev1>
2341 <rev1>
2363 <successors-1A>
2342 <successors-1A>
2364 <rev2>
2343 <rev2>
2365 <successors-2A>
2344 <successors-2A>
2366 <successors-2B1> <successors-2B2> <successors-2B3>
2345 <successors-2B1> <successors-2B2> <successors-2B3>
2367
2346
2368 Here rev2 has two possible (i.e. divergent) successors sets. The first
2347 Here rev2 has two possible (i.e. divergent) successors sets. The first
2369 holds one element, whereas the second holds three (i.e. the changeset has
2348 holds one element, whereas the second holds three (i.e. the changeset has
2370 been split).
2349 been split).
2371 """
2350 """
2372 # passed to successorssets caching computation from one call to another
2351 # passed to successorssets caching computation from one call to another
2373 cache = {}
2352 cache = {}
2374 ctx2str = str
2353 ctx2str = str
2375 node2str = short
2354 node2str = short
2376 if ui.debug():
2355 if ui.debug():
2377 def ctx2str(ctx):
2356 def ctx2str(ctx):
2378 return ctx.hex()
2357 return ctx.hex()
2379 node2str = hex
2358 node2str = hex
2380 for rev in scmutil.revrange(repo, revs):
2359 for rev in scmutil.revrange(repo, revs):
2381 ctx = repo[rev]
2360 ctx = repo[rev]
2382 ui.write('%s\n'% ctx2str(ctx))
2361 ui.write('%s\n'% ctx2str(ctx))
2383 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2362 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2384 if succsset:
2363 if succsset:
2385 ui.write(' ')
2364 ui.write(' ')
2386 ui.write(node2str(succsset[0]))
2365 ui.write(node2str(succsset[0]))
2387 for node in succsset[1:]:
2366 for node in succsset[1:]:
2388 ui.write(' ')
2367 ui.write(' ')
2389 ui.write(node2str(node))
2368 ui.write(node2str(node))
2390 ui.write('\n')
2369 ui.write('\n')
2391
2370
2392 @command('debugtemplate',
2371 @command('debugtemplate',
2393 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2372 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2394 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2373 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2395 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2374 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2396 optionalrepo=True)
2375 optionalrepo=True)
2397 def debugtemplate(ui, repo, tmpl, **opts):
2376 def debugtemplate(ui, repo, tmpl, **opts):
2398 """parse and apply a template
2377 """parse and apply a template
2399
2378
2400 If -r/--rev is given, the template is processed as a log template and
2379 If -r/--rev is given, the template is processed as a log template and
2401 applied to the given changesets. Otherwise, it is processed as a generic
2380 applied to the given changesets. Otherwise, it is processed as a generic
2402 template.
2381 template.
2403
2382
2404 Use --verbose to print the parsed tree.
2383 Use --verbose to print the parsed tree.
2405 """
2384 """
2406 revs = None
2385 revs = None
2407 if opts['rev']:
2386 if opts['rev']:
2408 if repo is None:
2387 if repo is None:
2409 raise error.RepoError(_('there is no Mercurial repository here '
2388 raise error.RepoError(_('there is no Mercurial repository here '
2410 '(.hg not found)'))
2389 '(.hg not found)'))
2411 revs = scmutil.revrange(repo, opts['rev'])
2390 revs = scmutil.revrange(repo, opts['rev'])
2412
2391
2413 props = {}
2392 props = {}
2414 for d in opts['define']:
2393 for d in opts['define']:
2415 try:
2394 try:
2416 k, v = (e.strip() for e in d.split('=', 1))
2395 k, v = (e.strip() for e in d.split('=', 1))
2417 if not k:
2396 if not k:
2418 raise ValueError
2397 raise ValueError
2419 props[k] = v
2398 props[k] = v
2420 except ValueError:
2399 except ValueError:
2421 raise error.Abort(_('malformed keyword definition: %s') % d)
2400 raise error.Abort(_('malformed keyword definition: %s') % d)
2422
2401
2423 if ui.verbose:
2402 if ui.verbose:
2424 aliases = ui.configitems('templatealias')
2403 aliases = ui.configitems('templatealias')
2425 tree = templater.parse(tmpl)
2404 tree = templater.parse(tmpl)
2426 ui.note(templater.prettyformat(tree), '\n')
2405 ui.note(templater.prettyformat(tree), '\n')
2427 newtree = templater.expandaliases(tree, aliases)
2406 newtree = templater.expandaliases(tree, aliases)
2428 if newtree != tree:
2407 if newtree != tree:
2429 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2408 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2430
2409
2431 mapfile = None
2410 mapfile = None
2432 if revs is None:
2411 if revs is None:
2433 k = 'debugtemplate'
2412 k = 'debugtemplate'
2434 t = formatter.maketemplater(ui, k, tmpl)
2413 t = formatter.maketemplater(ui, k, tmpl)
2435 ui.write(templater.stringify(t(k, **props)))
2414 ui.write(templater.stringify(t(k, **props)))
2436 else:
2415 else:
2437 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2416 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2438 mapfile, buffered=False)
2417 mapfile, buffered=False)
2439 for r in revs:
2418 for r in revs:
2440 displayer.show(repo[r], **props)
2419 displayer.show(repo[r], **props)
2441 displayer.close()
2420 displayer.close()
2442
2421
2443 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2422 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2444 def debugwalk(ui, repo, *pats, **opts):
2423 def debugwalk(ui, repo, *pats, **opts):
2445 """show how files match on given patterns"""
2424 """show how files match on given patterns"""
2446 m = scmutil.match(repo[None], pats, opts)
2425 m = scmutil.match(repo[None], pats, opts)
2447 items = list(repo.walk(m))
2426 items = list(repo.walk(m))
2448 if not items:
2427 if not items:
2449 return
2428 return
2450 f = lambda fn: fn
2429 f = lambda fn: fn
2451 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2430 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2452 f = lambda fn: util.normpath(fn)
2431 f = lambda fn: util.normpath(fn)
2453 fmt = 'f %%-%ds %%-%ds %%s' % (
2432 fmt = 'f %%-%ds %%-%ds %%s' % (
2454 max([len(abs) for abs in items]),
2433 max([len(abs) for abs in items]),
2455 max([len(m.rel(abs)) for abs in items]))
2434 max([len(m.rel(abs)) for abs in items]))
2456 for abs in items:
2435 for abs in items:
2457 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2436 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2458 ui.write("%s\n" % line.rstrip())
2437 ui.write("%s\n" % line.rstrip())
2459
2438
2460 @command('debugwireargs',
2439 @command('debugwireargs',
2461 [('', 'three', '', 'three'),
2440 [('', 'three', '', 'three'),
2462 ('', 'four', '', 'four'),
2441 ('', 'four', '', 'four'),
2463 ('', 'five', '', 'five'),
2442 ('', 'five', '', 'five'),
2464 ] + remoteopts,
2443 ] + remoteopts,
2465 _('REPO [OPTIONS]... [ONE [TWO]]'),
2444 _('REPO [OPTIONS]... [ONE [TWO]]'),
2466 norepo=True)
2445 norepo=True)
2467 def debugwireargs(ui, repopath, *vals, **opts):
2446 def debugwireargs(ui, repopath, *vals, **opts):
2468 repo = hg.peer(ui, opts, repopath)
2447 repo = hg.peer(ui, opts, repopath)
2469 for opt in remoteopts:
2448 for opt in remoteopts:
2470 del opts[opt[1]]
2449 del opts[opt[1]]
2471 args = {}
2450 args = {}
2472 for k, v in opts.iteritems():
2451 for k, v in opts.iteritems():
2473 if v:
2452 if v:
2474 args[k] = v
2453 args[k] = v
2475 # run twice to check that we don't mess up the stream for the next command
2454 # run twice to check that we don't mess up the stream for the next command
2476 res1 = repo.debugwireargs(*vals, **args)
2455 res1 = repo.debugwireargs(*vals, **args)
2477 res2 = repo.debugwireargs(*vals, **args)
2456 res2 = repo.debugwireargs(*vals, **args)
2478 ui.write("%s\n" % res1)
2457 ui.write("%s\n" % res1)
2479 if res1 != res2:
2458 if res1 != res2:
2480 ui.warn("%s\n" % res2)
2459 ui.warn("%s\n" % res2)
2481
2460
2482 @command('^diff',
2461 @command('^diff',
2483 [('r', 'rev', [], _('revision'), _('REV')),
2462 [('r', 'rev', [], _('revision'), _('REV')),
2484 ('c', 'change', '', _('change made by revision'), _('REV'))
2463 ('c', 'change', '', _('change made by revision'), _('REV'))
2485 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2464 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2486 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2465 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2487 inferrepo=True)
2466 inferrepo=True)
2488 def diff(ui, repo, *pats, **opts):
2467 def diff(ui, repo, *pats, **opts):
2489 """diff repository (or selected files)
2468 """diff repository (or selected files)
2490
2469
2491 Show differences between revisions for the specified files.
2470 Show differences between revisions for the specified files.
2492
2471
2493 Differences between files are shown using the unified diff format.
2472 Differences between files are shown using the unified diff format.
2494
2473
2495 .. note::
2474 .. note::
2496
2475
2497 :hg:`diff` may generate unexpected results for merges, as it will
2476 :hg:`diff` may generate unexpected results for merges, as it will
2498 default to comparing against the working directory's first
2477 default to comparing against the working directory's first
2499 parent changeset if no revisions are specified.
2478 parent changeset if no revisions are specified.
2500
2479
2501 When two revision arguments are given, then changes are shown
2480 When two revision arguments are given, then changes are shown
2502 between those revisions. If only one revision is specified then
2481 between those revisions. If only one revision is specified then
2503 that revision is compared to the working directory, and, when no
2482 that revision is compared to the working directory, and, when no
2504 revisions are specified, the working directory files are compared
2483 revisions are specified, the working directory files are compared
2505 to its first parent.
2484 to its first parent.
2506
2485
2507 Alternatively you can specify -c/--change with a revision to see
2486 Alternatively you can specify -c/--change with a revision to see
2508 the changes in that changeset relative to its first parent.
2487 the changes in that changeset relative to its first parent.
2509
2488
2510 Without the -a/--text option, diff will avoid generating diffs of
2489 Without the -a/--text option, diff will avoid generating diffs of
2511 files it detects as binary. With -a, diff will generate a diff
2490 files it detects as binary. With -a, diff will generate a diff
2512 anyway, probably with undesirable results.
2491 anyway, probably with undesirable results.
2513
2492
2514 Use the -g/--git option to generate diffs in the git extended diff
2493 Use the -g/--git option to generate diffs in the git extended diff
2515 format. For more information, read :hg:`help diffs`.
2494 format. For more information, read :hg:`help diffs`.
2516
2495
2517 .. container:: verbose
2496 .. container:: verbose
2518
2497
2519 Examples:
2498 Examples:
2520
2499
2521 - compare a file in the current working directory to its parent::
2500 - compare a file in the current working directory to its parent::
2522
2501
2523 hg diff foo.c
2502 hg diff foo.c
2524
2503
2525 - compare two historical versions of a directory, with rename info::
2504 - compare two historical versions of a directory, with rename info::
2526
2505
2527 hg diff --git -r 1.0:1.2 lib/
2506 hg diff --git -r 1.0:1.2 lib/
2528
2507
2529 - get change stats relative to the last change on some date::
2508 - get change stats relative to the last change on some date::
2530
2509
2531 hg diff --stat -r "date('may 2')"
2510 hg diff --stat -r "date('may 2')"
2532
2511
2533 - diff all newly-added files that contain a keyword::
2512 - diff all newly-added files that contain a keyword::
2534
2513
2535 hg diff "set:added() and grep(GNU)"
2514 hg diff "set:added() and grep(GNU)"
2536
2515
2537 - compare a revision and its parents::
2516 - compare a revision and its parents::
2538
2517
2539 hg diff -c 9353 # compare against first parent
2518 hg diff -c 9353 # compare against first parent
2540 hg diff -r 9353^:9353 # same using revset syntax
2519 hg diff -r 9353^:9353 # same using revset syntax
2541 hg diff -r 9353^2:9353 # compare against the second parent
2520 hg diff -r 9353^2:9353 # compare against the second parent
2542
2521
2543 Returns 0 on success.
2522 Returns 0 on success.
2544 """
2523 """
2545
2524
2546 revs = opts.get('rev')
2525 revs = opts.get('rev')
2547 change = opts.get('change')
2526 change = opts.get('change')
2548 stat = opts.get('stat')
2527 stat = opts.get('stat')
2549 reverse = opts.get('reverse')
2528 reverse = opts.get('reverse')
2550
2529
2551 if revs and change:
2530 if revs and change:
2552 msg = _('cannot specify --rev and --change at the same time')
2531 msg = _('cannot specify --rev and --change at the same time')
2553 raise error.Abort(msg)
2532 raise error.Abort(msg)
2554 elif change:
2533 elif change:
2555 node2 = scmutil.revsingle(repo, change, None).node()
2534 node2 = scmutil.revsingle(repo, change, None).node()
2556 node1 = repo[node2].p1().node()
2535 node1 = repo[node2].p1().node()
2557 else:
2536 else:
2558 node1, node2 = scmutil.revpair(repo, revs)
2537 node1, node2 = scmutil.revpair(repo, revs)
2559
2538
2560 if reverse:
2539 if reverse:
2561 node1, node2 = node2, node1
2540 node1, node2 = node2, node1
2562
2541
2563 diffopts = patch.diffallopts(ui, opts)
2542 diffopts = patch.diffallopts(ui, opts)
2564 m = scmutil.match(repo[node2], pats, opts)
2543 m = scmutil.match(repo[node2], pats, opts)
2565 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2544 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2566 listsubrepos=opts.get('subrepos'),
2545 listsubrepos=opts.get('subrepos'),
2567 root=opts.get('root'))
2546 root=opts.get('root'))
2568
2547
2569 @command('^export',
2548 @command('^export',
2570 [('o', 'output', '',
2549 [('o', 'output', '',
2571 _('print output to file with formatted name'), _('FORMAT')),
2550 _('print output to file with formatted name'), _('FORMAT')),
2572 ('', 'switch-parent', None, _('diff against the second parent')),
2551 ('', 'switch-parent', None, _('diff against the second parent')),
2573 ('r', 'rev', [], _('revisions to export'), _('REV')),
2552 ('r', 'rev', [], _('revisions to export'), _('REV')),
2574 ] + diffopts,
2553 ] + diffopts,
2575 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2554 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2576 def export(ui, repo, *changesets, **opts):
2555 def export(ui, repo, *changesets, **opts):
2577 """dump the header and diffs for one or more changesets
2556 """dump the header and diffs for one or more changesets
2578
2557
2579 Print the changeset header and diffs for one or more revisions.
2558 Print the changeset header and diffs for one or more revisions.
2580 If no revision is given, the parent of the working directory is used.
2559 If no revision is given, the parent of the working directory is used.
2581
2560
2582 The information shown in the changeset header is: author, date,
2561 The information shown in the changeset header is: author, date,
2583 branch name (if non-default), changeset hash, parent(s) and commit
2562 branch name (if non-default), changeset hash, parent(s) and commit
2584 comment.
2563 comment.
2585
2564
2586 .. note::
2565 .. note::
2587
2566
2588 :hg:`export` may generate unexpected diff output for merge
2567 :hg:`export` may generate unexpected diff output for merge
2589 changesets, as it will compare the merge changeset against its
2568 changesets, as it will compare the merge changeset against its
2590 first parent only.
2569 first parent only.
2591
2570
2592 Output may be to a file, in which case the name of the file is
2571 Output may be to a file, in which case the name of the file is
2593 given using a format string. The formatting rules are as follows:
2572 given using a format string. The formatting rules are as follows:
2594
2573
2595 :``%%``: literal "%" character
2574 :``%%``: literal "%" character
2596 :``%H``: changeset hash (40 hexadecimal digits)
2575 :``%H``: changeset hash (40 hexadecimal digits)
2597 :``%N``: number of patches being generated
2576 :``%N``: number of patches being generated
2598 :``%R``: changeset revision number
2577 :``%R``: changeset revision number
2599 :``%b``: basename of the exporting repository
2578 :``%b``: basename of the exporting repository
2600 :``%h``: short-form changeset hash (12 hexadecimal digits)
2579 :``%h``: short-form changeset hash (12 hexadecimal digits)
2601 :``%m``: first line of the commit message (only alphanumeric characters)
2580 :``%m``: first line of the commit message (only alphanumeric characters)
2602 :``%n``: zero-padded sequence number, starting at 1
2581 :``%n``: zero-padded sequence number, starting at 1
2603 :``%r``: zero-padded changeset revision number
2582 :``%r``: zero-padded changeset revision number
2604
2583
2605 Without the -a/--text option, export will avoid generating diffs
2584 Without the -a/--text option, export will avoid generating diffs
2606 of files it detects as binary. With -a, export will generate a
2585 of files it detects as binary. With -a, export will generate a
2607 diff anyway, probably with undesirable results.
2586 diff anyway, probably with undesirable results.
2608
2587
2609 Use the -g/--git option to generate diffs in the git extended diff
2588 Use the -g/--git option to generate diffs in the git extended diff
2610 format. See :hg:`help diffs` for more information.
2589 format. See :hg:`help diffs` for more information.
2611
2590
2612 With the --switch-parent option, the diff will be against the
2591 With the --switch-parent option, the diff will be against the
2613 second parent. It can be useful to review a merge.
2592 second parent. It can be useful to review a merge.
2614
2593
2615 .. container:: verbose
2594 .. container:: verbose
2616
2595
2617 Examples:
2596 Examples:
2618
2597
2619 - use export and import to transplant a bugfix to the current
2598 - use export and import to transplant a bugfix to the current
2620 branch::
2599 branch::
2621
2600
2622 hg export -r 9353 | hg import -
2601 hg export -r 9353 | hg import -
2623
2602
2624 - export all the changesets between two revisions to a file with
2603 - export all the changesets between two revisions to a file with
2625 rename information::
2604 rename information::
2626
2605
2627 hg export --git -r 123:150 > changes.txt
2606 hg export --git -r 123:150 > changes.txt
2628
2607
2629 - split outgoing changes into a series of patches with
2608 - split outgoing changes into a series of patches with
2630 descriptive names::
2609 descriptive names::
2631
2610
2632 hg export -r "outgoing()" -o "%n-%m.patch"
2611 hg export -r "outgoing()" -o "%n-%m.patch"
2633
2612
2634 Returns 0 on success.
2613 Returns 0 on success.
2635 """
2614 """
2636 changesets += tuple(opts.get('rev', []))
2615 changesets += tuple(opts.get('rev', []))
2637 if not changesets:
2616 if not changesets:
2638 changesets = ['.']
2617 changesets = ['.']
2639 revs = scmutil.revrange(repo, changesets)
2618 revs = scmutil.revrange(repo, changesets)
2640 if not revs:
2619 if not revs:
2641 raise error.Abort(_("export requires at least one changeset"))
2620 raise error.Abort(_("export requires at least one changeset"))
2642 if len(revs) > 1:
2621 if len(revs) > 1:
2643 ui.note(_('exporting patches:\n'))
2622 ui.note(_('exporting patches:\n'))
2644 else:
2623 else:
2645 ui.note(_('exporting patch:\n'))
2624 ui.note(_('exporting patch:\n'))
2646 cmdutil.export(repo, revs, template=opts.get('output'),
2625 cmdutil.export(repo, revs, template=opts.get('output'),
2647 switch_parent=opts.get('switch_parent'),
2626 switch_parent=opts.get('switch_parent'),
2648 opts=patch.diffallopts(ui, opts))
2627 opts=patch.diffallopts(ui, opts))
2649
2628
2650 @command('files',
2629 @command('files',
2651 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2630 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2652 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2631 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2653 ] + walkopts + formatteropts + subrepoopts,
2632 ] + walkopts + formatteropts + subrepoopts,
2654 _('[OPTION]... [FILE]...'))
2633 _('[OPTION]... [FILE]...'))
2655 def files(ui, repo, *pats, **opts):
2634 def files(ui, repo, *pats, **opts):
2656 """list tracked files
2635 """list tracked files
2657
2636
2658 Print files under Mercurial control in the working directory or
2637 Print files under Mercurial control in the working directory or
2659 specified revision for given files (excluding removed files).
2638 specified revision for given files (excluding removed files).
2660 Files can be specified as filenames or filesets.
2639 Files can be specified as filenames or filesets.
2661
2640
2662 If no files are given to match, this command prints the names
2641 If no files are given to match, this command prints the names
2663 of all files under Mercurial control.
2642 of all files under Mercurial control.
2664
2643
2665 .. container:: verbose
2644 .. container:: verbose
2666
2645
2667 Examples:
2646 Examples:
2668
2647
2669 - list all files under the current directory::
2648 - list all files under the current directory::
2670
2649
2671 hg files .
2650 hg files .
2672
2651
2673 - shows sizes and flags for current revision::
2652 - shows sizes and flags for current revision::
2674
2653
2675 hg files -vr .
2654 hg files -vr .
2676
2655
2677 - list all files named README::
2656 - list all files named README::
2678
2657
2679 hg files -I "**/README"
2658 hg files -I "**/README"
2680
2659
2681 - list all binary files::
2660 - list all binary files::
2682
2661
2683 hg files "set:binary()"
2662 hg files "set:binary()"
2684
2663
2685 - find files containing a regular expression::
2664 - find files containing a regular expression::
2686
2665
2687 hg files "set:grep('bob')"
2666 hg files "set:grep('bob')"
2688
2667
2689 - search tracked file contents with xargs and grep::
2668 - search tracked file contents with xargs and grep::
2690
2669
2691 hg files -0 | xargs -0 grep foo
2670 hg files -0 | xargs -0 grep foo
2692
2671
2693 See :hg:`help patterns` and :hg:`help filesets` for more information
2672 See :hg:`help patterns` and :hg:`help filesets` for more information
2694 on specifying file patterns.
2673 on specifying file patterns.
2695
2674
2696 Returns 0 if a match is found, 1 otherwise.
2675 Returns 0 if a match is found, 1 otherwise.
2697
2676
2698 """
2677 """
2699 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2678 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2700
2679
2701 end = '\n'
2680 end = '\n'
2702 if opts.get('print0'):
2681 if opts.get('print0'):
2703 end = '\0'
2682 end = '\0'
2704 fmt = '%s' + end
2683 fmt = '%s' + end
2705
2684
2706 m = scmutil.match(ctx, pats, opts)
2685 m = scmutil.match(ctx, pats, opts)
2707 with ui.formatter('files', opts) as fm:
2686 with ui.formatter('files', opts) as fm:
2708 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2687 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2709
2688
2710 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2689 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2711 def forget(ui, repo, *pats, **opts):
2690 def forget(ui, repo, *pats, **opts):
2712 """forget the specified files on the next commit
2691 """forget the specified files on the next commit
2713
2692
2714 Mark the specified files so they will no longer be tracked
2693 Mark the specified files so they will no longer be tracked
2715 after the next commit.
2694 after the next commit.
2716
2695
2717 This only removes files from the current branch, not from the
2696 This only removes files from the current branch, not from the
2718 entire project history, and it does not delete them from the
2697 entire project history, and it does not delete them from the
2719 working directory.
2698 working directory.
2720
2699
2721 To delete the file from the working directory, see :hg:`remove`.
2700 To delete the file from the working directory, see :hg:`remove`.
2722
2701
2723 To undo a forget before the next commit, see :hg:`add`.
2702 To undo a forget before the next commit, see :hg:`add`.
2724
2703
2725 .. container:: verbose
2704 .. container:: verbose
2726
2705
2727 Examples:
2706 Examples:
2728
2707
2729 - forget newly-added binary files::
2708 - forget newly-added binary files::
2730
2709
2731 hg forget "set:added() and binary()"
2710 hg forget "set:added() and binary()"
2732
2711
2733 - forget files that would be excluded by .hgignore::
2712 - forget files that would be excluded by .hgignore::
2734
2713
2735 hg forget "set:hgignore()"
2714 hg forget "set:hgignore()"
2736
2715
2737 Returns 0 on success.
2716 Returns 0 on success.
2738 """
2717 """
2739
2718
2740 if not pats:
2719 if not pats:
2741 raise error.Abort(_('no files specified'))
2720 raise error.Abort(_('no files specified'))
2742
2721
2743 m = scmutil.match(repo[None], pats, opts)
2722 m = scmutil.match(repo[None], pats, opts)
2744 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2723 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2745 return rejected and 1 or 0
2724 return rejected and 1 or 0
2746
2725
2747 @command(
2726 @command(
2748 'graft',
2727 'graft',
2749 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2728 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2750 ('c', 'continue', False, _('resume interrupted graft')),
2729 ('c', 'continue', False, _('resume interrupted graft')),
2751 ('e', 'edit', False, _('invoke editor on commit messages')),
2730 ('e', 'edit', False, _('invoke editor on commit messages')),
2752 ('', 'log', None, _('append graft info to log message')),
2731 ('', 'log', None, _('append graft info to log message')),
2753 ('f', 'force', False, _('force graft')),
2732 ('f', 'force', False, _('force graft')),
2754 ('D', 'currentdate', False,
2733 ('D', 'currentdate', False,
2755 _('record the current date as commit date')),
2734 _('record the current date as commit date')),
2756 ('U', 'currentuser', False,
2735 ('U', 'currentuser', False,
2757 _('record the current user as committer'), _('DATE'))]
2736 _('record the current user as committer'), _('DATE'))]
2758 + commitopts2 + mergetoolopts + dryrunopts,
2737 + commitopts2 + mergetoolopts + dryrunopts,
2759 _('[OPTION]... [-r REV]... REV...'))
2738 _('[OPTION]... [-r REV]... REV...'))
2760 def graft(ui, repo, *revs, **opts):
2739 def graft(ui, repo, *revs, **opts):
2761 '''copy changes from other branches onto the current branch
2740 '''copy changes from other branches onto the current branch
2762
2741
2763 This command uses Mercurial's merge logic to copy individual
2742 This command uses Mercurial's merge logic to copy individual
2764 changes from other branches without merging branches in the
2743 changes from other branches without merging branches in the
2765 history graph. This is sometimes known as 'backporting' or
2744 history graph. This is sometimes known as 'backporting' or
2766 'cherry-picking'. By default, graft will copy user, date, and
2745 'cherry-picking'. By default, graft will copy user, date, and
2767 description from the source changesets.
2746 description from the source changesets.
2768
2747
2769 Changesets that are ancestors of the current revision, that have
2748 Changesets that are ancestors of the current revision, that have
2770 already been grafted, or that are merges will be skipped.
2749 already been grafted, or that are merges will be skipped.
2771
2750
2772 If --log is specified, log messages will have a comment appended
2751 If --log is specified, log messages will have a comment appended
2773 of the form::
2752 of the form::
2774
2753
2775 (grafted from CHANGESETHASH)
2754 (grafted from CHANGESETHASH)
2776
2755
2777 If --force is specified, revisions will be grafted even if they
2756 If --force is specified, revisions will be grafted even if they
2778 are already ancestors of or have been grafted to the destination.
2757 are already ancestors of or have been grafted to the destination.
2779 This is useful when the revisions have since been backed out.
2758 This is useful when the revisions have since been backed out.
2780
2759
2781 If a graft merge results in conflicts, the graft process is
2760 If a graft merge results in conflicts, the graft process is
2782 interrupted so that the current merge can be manually resolved.
2761 interrupted so that the current merge can be manually resolved.
2783 Once all conflicts are addressed, the graft process can be
2762 Once all conflicts are addressed, the graft process can be
2784 continued with the -c/--continue option.
2763 continued with the -c/--continue option.
2785
2764
2786 .. note::
2765 .. note::
2787
2766
2788 The -c/--continue option does not reapply earlier options, except
2767 The -c/--continue option does not reapply earlier options, except
2789 for --force.
2768 for --force.
2790
2769
2791 .. container:: verbose
2770 .. container:: verbose
2792
2771
2793 Examples:
2772 Examples:
2794
2773
2795 - copy a single change to the stable branch and edit its description::
2774 - copy a single change to the stable branch and edit its description::
2796
2775
2797 hg update stable
2776 hg update stable
2798 hg graft --edit 9393
2777 hg graft --edit 9393
2799
2778
2800 - graft a range of changesets with one exception, updating dates::
2779 - graft a range of changesets with one exception, updating dates::
2801
2780
2802 hg graft -D "2085::2093 and not 2091"
2781 hg graft -D "2085::2093 and not 2091"
2803
2782
2804 - continue a graft after resolving conflicts::
2783 - continue a graft after resolving conflicts::
2805
2784
2806 hg graft -c
2785 hg graft -c
2807
2786
2808 - show the source of a grafted changeset::
2787 - show the source of a grafted changeset::
2809
2788
2810 hg log --debug -r .
2789 hg log --debug -r .
2811
2790
2812 - show revisions sorted by date::
2791 - show revisions sorted by date::
2813
2792
2814 hg log -r "sort(all(), date)"
2793 hg log -r "sort(all(), date)"
2815
2794
2816 See :hg:`help revisions` for more about specifying revisions.
2795 See :hg:`help revisions` for more about specifying revisions.
2817
2796
2818 Returns 0 on successful completion.
2797 Returns 0 on successful completion.
2819 '''
2798 '''
2820 with repo.wlock():
2799 with repo.wlock():
2821 return _dograft(ui, repo, *revs, **opts)
2800 return _dograft(ui, repo, *revs, **opts)
2822
2801
2823 def _dograft(ui, repo, *revs, **opts):
2802 def _dograft(ui, repo, *revs, **opts):
2824 if revs and opts.get('rev'):
2803 if revs and opts.get('rev'):
2825 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2804 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2826 'revision ordering!\n'))
2805 'revision ordering!\n'))
2827
2806
2828 revs = list(revs)
2807 revs = list(revs)
2829 revs.extend(opts.get('rev'))
2808 revs.extend(opts.get('rev'))
2830
2809
2831 if not opts.get('user') and opts.get('currentuser'):
2810 if not opts.get('user') and opts.get('currentuser'):
2832 opts['user'] = ui.username()
2811 opts['user'] = ui.username()
2833 if not opts.get('date') and opts.get('currentdate'):
2812 if not opts.get('date') and opts.get('currentdate'):
2834 opts['date'] = "%d %d" % util.makedate()
2813 opts['date'] = "%d %d" % util.makedate()
2835
2814
2836 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2815 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2837
2816
2838 cont = False
2817 cont = False
2839 if opts.get('continue'):
2818 if opts.get('continue'):
2840 cont = True
2819 cont = True
2841 if revs:
2820 if revs:
2842 raise error.Abort(_("can't specify --continue and revisions"))
2821 raise error.Abort(_("can't specify --continue and revisions"))
2843 # read in unfinished revisions
2822 # read in unfinished revisions
2844 try:
2823 try:
2845 nodes = repo.vfs.read('graftstate').splitlines()
2824 nodes = repo.vfs.read('graftstate').splitlines()
2846 revs = [repo[node].rev() for node in nodes]
2825 revs = [repo[node].rev() for node in nodes]
2847 except IOError as inst:
2826 except IOError as inst:
2848 if inst.errno != errno.ENOENT:
2827 if inst.errno != errno.ENOENT:
2849 raise
2828 raise
2850 cmdutil.wrongtooltocontinue(repo, _('graft'))
2829 cmdutil.wrongtooltocontinue(repo, _('graft'))
2851 else:
2830 else:
2852 cmdutil.checkunfinished(repo)
2831 cmdutil.checkunfinished(repo)
2853 cmdutil.bailifchanged(repo)
2832 cmdutil.bailifchanged(repo)
2854 if not revs:
2833 if not revs:
2855 raise error.Abort(_('no revisions specified'))
2834 raise error.Abort(_('no revisions specified'))
2856 revs = scmutil.revrange(repo, revs)
2835 revs = scmutil.revrange(repo, revs)
2857
2836
2858 skipped = set()
2837 skipped = set()
2859 # check for merges
2838 # check for merges
2860 for rev in repo.revs('%ld and merge()', revs):
2839 for rev in repo.revs('%ld and merge()', revs):
2861 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2840 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2862 skipped.add(rev)
2841 skipped.add(rev)
2863 revs = [r for r in revs if r not in skipped]
2842 revs = [r for r in revs if r not in skipped]
2864 if not revs:
2843 if not revs:
2865 return -1
2844 return -1
2866
2845
2867 # Don't check in the --continue case, in effect retaining --force across
2846 # Don't check in the --continue case, in effect retaining --force across
2868 # --continues. That's because without --force, any revisions we decided to
2847 # --continues. That's because without --force, any revisions we decided to
2869 # skip would have been filtered out here, so they wouldn't have made their
2848 # skip would have been filtered out here, so they wouldn't have made their
2870 # way to the graftstate. With --force, any revisions we would have otherwise
2849 # way to the graftstate. With --force, any revisions we would have otherwise
2871 # skipped would not have been filtered out, and if they hadn't been applied
2850 # skipped would not have been filtered out, and if they hadn't been applied
2872 # already, they'd have been in the graftstate.
2851 # already, they'd have been in the graftstate.
2873 if not (cont or opts.get('force')):
2852 if not (cont or opts.get('force')):
2874 # check for ancestors of dest branch
2853 # check for ancestors of dest branch
2875 crev = repo['.'].rev()
2854 crev = repo['.'].rev()
2876 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2855 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2877 # XXX make this lazy in the future
2856 # XXX make this lazy in the future
2878 # don't mutate while iterating, create a copy
2857 # don't mutate while iterating, create a copy
2879 for rev in list(revs):
2858 for rev in list(revs):
2880 if rev in ancestors:
2859 if rev in ancestors:
2881 ui.warn(_('skipping ancestor revision %d:%s\n') %
2860 ui.warn(_('skipping ancestor revision %d:%s\n') %
2882 (rev, repo[rev]))
2861 (rev, repo[rev]))
2883 # XXX remove on list is slow
2862 # XXX remove on list is slow
2884 revs.remove(rev)
2863 revs.remove(rev)
2885 if not revs:
2864 if not revs:
2886 return -1
2865 return -1
2887
2866
2888 # analyze revs for earlier grafts
2867 # analyze revs for earlier grafts
2889 ids = {}
2868 ids = {}
2890 for ctx in repo.set("%ld", revs):
2869 for ctx in repo.set("%ld", revs):
2891 ids[ctx.hex()] = ctx.rev()
2870 ids[ctx.hex()] = ctx.rev()
2892 n = ctx.extra().get('source')
2871 n = ctx.extra().get('source')
2893 if n:
2872 if n:
2894 ids[n] = ctx.rev()
2873 ids[n] = ctx.rev()
2895
2874
2896 # check ancestors for earlier grafts
2875 # check ancestors for earlier grafts
2897 ui.debug('scanning for duplicate grafts\n')
2876 ui.debug('scanning for duplicate grafts\n')
2898
2877
2899 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2878 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2900 ctx = repo[rev]
2879 ctx = repo[rev]
2901 n = ctx.extra().get('source')
2880 n = ctx.extra().get('source')
2902 if n in ids:
2881 if n in ids:
2903 try:
2882 try:
2904 r = repo[n].rev()
2883 r = repo[n].rev()
2905 except error.RepoLookupError:
2884 except error.RepoLookupError:
2906 r = None
2885 r = None
2907 if r in revs:
2886 if r in revs:
2908 ui.warn(_('skipping revision %d:%s '
2887 ui.warn(_('skipping revision %d:%s '
2909 '(already grafted to %d:%s)\n')
2888 '(already grafted to %d:%s)\n')
2910 % (r, repo[r], rev, ctx))
2889 % (r, repo[r], rev, ctx))
2911 revs.remove(r)
2890 revs.remove(r)
2912 elif ids[n] in revs:
2891 elif ids[n] in revs:
2913 if r is None:
2892 if r is None:
2914 ui.warn(_('skipping already grafted revision %d:%s '
2893 ui.warn(_('skipping already grafted revision %d:%s '
2915 '(%d:%s also has unknown origin %s)\n')
2894 '(%d:%s also has unknown origin %s)\n')
2916 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2895 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2917 else:
2896 else:
2918 ui.warn(_('skipping already grafted revision %d:%s '
2897 ui.warn(_('skipping already grafted revision %d:%s '
2919 '(%d:%s also has origin %d:%s)\n')
2898 '(%d:%s also has origin %d:%s)\n')
2920 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2899 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2921 revs.remove(ids[n])
2900 revs.remove(ids[n])
2922 elif ctx.hex() in ids:
2901 elif ctx.hex() in ids:
2923 r = ids[ctx.hex()]
2902 r = ids[ctx.hex()]
2924 ui.warn(_('skipping already grafted revision %d:%s '
2903 ui.warn(_('skipping already grafted revision %d:%s '
2925 '(was grafted from %d:%s)\n') %
2904 '(was grafted from %d:%s)\n') %
2926 (r, repo[r], rev, ctx))
2905 (r, repo[r], rev, ctx))
2927 revs.remove(r)
2906 revs.remove(r)
2928 if not revs:
2907 if not revs:
2929 return -1
2908 return -1
2930
2909
2931 for pos, ctx in enumerate(repo.set("%ld", revs)):
2910 for pos, ctx in enumerate(repo.set("%ld", revs)):
2932 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2911 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2933 ctx.description().split('\n', 1)[0])
2912 ctx.description().split('\n', 1)[0])
2934 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2913 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2935 if names:
2914 if names:
2936 desc += ' (%s)' % ' '.join(names)
2915 desc += ' (%s)' % ' '.join(names)
2937 ui.status(_('grafting %s\n') % desc)
2916 ui.status(_('grafting %s\n') % desc)
2938 if opts.get('dry_run'):
2917 if opts.get('dry_run'):
2939 continue
2918 continue
2940
2919
2941 source = ctx.extra().get('source')
2920 source = ctx.extra().get('source')
2942 extra = {}
2921 extra = {}
2943 if source:
2922 if source:
2944 extra['source'] = source
2923 extra['source'] = source
2945 extra['intermediate-source'] = ctx.hex()
2924 extra['intermediate-source'] = ctx.hex()
2946 else:
2925 else:
2947 extra['source'] = ctx.hex()
2926 extra['source'] = ctx.hex()
2948 user = ctx.user()
2927 user = ctx.user()
2949 if opts.get('user'):
2928 if opts.get('user'):
2950 user = opts['user']
2929 user = opts['user']
2951 date = ctx.date()
2930 date = ctx.date()
2952 if opts.get('date'):
2931 if opts.get('date'):
2953 date = opts['date']
2932 date = opts['date']
2954 message = ctx.description()
2933 message = ctx.description()
2955 if opts.get('log'):
2934 if opts.get('log'):
2956 message += '\n(grafted from %s)' % ctx.hex()
2935 message += '\n(grafted from %s)' % ctx.hex()
2957
2936
2958 # we don't merge the first commit when continuing
2937 # we don't merge the first commit when continuing
2959 if not cont:
2938 if not cont:
2960 # perform the graft merge with p1(rev) as 'ancestor'
2939 # perform the graft merge with p1(rev) as 'ancestor'
2961 try:
2940 try:
2962 # ui.forcemerge is an internal variable, do not document
2941 # ui.forcemerge is an internal variable, do not document
2963 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2942 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2964 'graft')
2943 'graft')
2965 stats = mergemod.graft(repo, ctx, ctx.p1(),
2944 stats = mergemod.graft(repo, ctx, ctx.p1(),
2966 ['local', 'graft'])
2945 ['local', 'graft'])
2967 finally:
2946 finally:
2968 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2947 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2969 # report any conflicts
2948 # report any conflicts
2970 if stats and stats[3] > 0:
2949 if stats and stats[3] > 0:
2971 # write out state for --continue
2950 # write out state for --continue
2972 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2951 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2973 repo.vfs.write('graftstate', ''.join(nodelines))
2952 repo.vfs.write('graftstate', ''.join(nodelines))
2974 extra = ''
2953 extra = ''
2975 if opts.get('user'):
2954 if opts.get('user'):
2976 extra += ' --user %s' % util.shellquote(opts['user'])
2955 extra += ' --user %s' % util.shellquote(opts['user'])
2977 if opts.get('date'):
2956 if opts.get('date'):
2978 extra += ' --date %s' % util.shellquote(opts['date'])
2957 extra += ' --date %s' % util.shellquote(opts['date'])
2979 if opts.get('log'):
2958 if opts.get('log'):
2980 extra += ' --log'
2959 extra += ' --log'
2981 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2960 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2982 raise error.Abort(
2961 raise error.Abort(
2983 _("unresolved conflicts, can't continue"),
2962 _("unresolved conflicts, can't continue"),
2984 hint=hint)
2963 hint=hint)
2985 else:
2964 else:
2986 cont = False
2965 cont = False
2987
2966
2988 # commit
2967 # commit
2989 node = repo.commit(text=message, user=user,
2968 node = repo.commit(text=message, user=user,
2990 date=date, extra=extra, editor=editor)
2969 date=date, extra=extra, editor=editor)
2991 if node is None:
2970 if node is None:
2992 ui.warn(
2971 ui.warn(
2993 _('note: graft of %d:%s created no changes to commit\n') %
2972 _('note: graft of %d:%s created no changes to commit\n') %
2994 (ctx.rev(), ctx))
2973 (ctx.rev(), ctx))
2995
2974
2996 # remove state when we complete successfully
2975 # remove state when we complete successfully
2997 if not opts.get('dry_run'):
2976 if not opts.get('dry_run'):
2998 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2977 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2999
2978
3000 return 0
2979 return 0
3001
2980
3002 @command('grep',
2981 @command('grep',
3003 [('0', 'print0', None, _('end fields with NUL')),
2982 [('0', 'print0', None, _('end fields with NUL')),
3004 ('', 'all', None, _('print all revisions that match')),
2983 ('', 'all', None, _('print all revisions that match')),
3005 ('a', 'text', None, _('treat all files as text')),
2984 ('a', 'text', None, _('treat all files as text')),
3006 ('f', 'follow', None,
2985 ('f', 'follow', None,
3007 _('follow changeset history,'
2986 _('follow changeset history,'
3008 ' or file history across copies and renames')),
2987 ' or file history across copies and renames')),
3009 ('i', 'ignore-case', None, _('ignore case when matching')),
2988 ('i', 'ignore-case', None, _('ignore case when matching')),
3010 ('l', 'files-with-matches', None,
2989 ('l', 'files-with-matches', None,
3011 _('print only filenames and revisions that match')),
2990 _('print only filenames and revisions that match')),
3012 ('n', 'line-number', None, _('print matching line numbers')),
2991 ('n', 'line-number', None, _('print matching line numbers')),
3013 ('r', 'rev', [],
2992 ('r', 'rev', [],
3014 _('only search files changed within revision range'), _('REV')),
2993 _('only search files changed within revision range'), _('REV')),
3015 ('u', 'user', None, _('list the author (long with -v)')),
2994 ('u', 'user', None, _('list the author (long with -v)')),
3016 ('d', 'date', None, _('list the date (short with -q)')),
2995 ('d', 'date', None, _('list the date (short with -q)')),
3017 ] + formatteropts + walkopts,
2996 ] + formatteropts + walkopts,
3018 _('[OPTION]... PATTERN [FILE]...'),
2997 _('[OPTION]... PATTERN [FILE]...'),
3019 inferrepo=True)
2998 inferrepo=True)
3020 def grep(ui, repo, pattern, *pats, **opts):
2999 def grep(ui, repo, pattern, *pats, **opts):
3021 """search revision history for a pattern in specified files
3000 """search revision history for a pattern in specified files
3022
3001
3023 Search revision history for a regular expression in the specified
3002 Search revision history for a regular expression in the specified
3024 files or the entire project.
3003 files or the entire project.
3025
3004
3026 By default, grep prints the most recent revision number for each
3005 By default, grep prints the most recent revision number for each
3027 file in which it finds a match. To get it to print every revision
3006 file in which it finds a match. To get it to print every revision
3028 that contains a change in match status ("-" for a match that becomes
3007 that contains a change in match status ("-" for a match that becomes
3029 a non-match, or "+" for a non-match that becomes a match), use the
3008 a non-match, or "+" for a non-match that becomes a match), use the
3030 --all flag.
3009 --all flag.
3031
3010
3032 PATTERN can be any Python (roughly Perl-compatible) regular
3011 PATTERN can be any Python (roughly Perl-compatible) regular
3033 expression.
3012 expression.
3034
3013
3035 If no FILEs are specified (and -f/--follow isn't set), all files in
3014 If no FILEs are specified (and -f/--follow isn't set), all files in
3036 the repository are searched, including those that don't exist in the
3015 the repository are searched, including those that don't exist in the
3037 current branch or have been deleted in a prior changeset.
3016 current branch or have been deleted in a prior changeset.
3038
3017
3039 Returns 0 if a match is found, 1 otherwise.
3018 Returns 0 if a match is found, 1 otherwise.
3040 """
3019 """
3041 reflags = re.M
3020 reflags = re.M
3042 if opts.get('ignore_case'):
3021 if opts.get('ignore_case'):
3043 reflags |= re.I
3022 reflags |= re.I
3044 try:
3023 try:
3045 regexp = util.re.compile(pattern, reflags)
3024 regexp = util.re.compile(pattern, reflags)
3046 except re.error as inst:
3025 except re.error as inst:
3047 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3026 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3048 return 1
3027 return 1
3049 sep, eol = ':', '\n'
3028 sep, eol = ':', '\n'
3050 if opts.get('print0'):
3029 if opts.get('print0'):
3051 sep = eol = '\0'
3030 sep = eol = '\0'
3052
3031
3053 getfile = util.lrucachefunc(repo.file)
3032 getfile = util.lrucachefunc(repo.file)
3054
3033
3055 def matchlines(body):
3034 def matchlines(body):
3056 begin = 0
3035 begin = 0
3057 linenum = 0
3036 linenum = 0
3058 while begin < len(body):
3037 while begin < len(body):
3059 match = regexp.search(body, begin)
3038 match = regexp.search(body, begin)
3060 if not match:
3039 if not match:
3061 break
3040 break
3062 mstart, mend = match.span()
3041 mstart, mend = match.span()
3063 linenum += body.count('\n', begin, mstart) + 1
3042 linenum += body.count('\n', begin, mstart) + 1
3064 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3043 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3065 begin = body.find('\n', mend) + 1 or len(body) + 1
3044 begin = body.find('\n', mend) + 1 or len(body) + 1
3066 lend = begin - 1
3045 lend = begin - 1
3067 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3046 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3068
3047
3069 class linestate(object):
3048 class linestate(object):
3070 def __init__(self, line, linenum, colstart, colend):
3049 def __init__(self, line, linenum, colstart, colend):
3071 self.line = line
3050 self.line = line
3072 self.linenum = linenum
3051 self.linenum = linenum
3073 self.colstart = colstart
3052 self.colstart = colstart
3074 self.colend = colend
3053 self.colend = colend
3075
3054
3076 def __hash__(self):
3055 def __hash__(self):
3077 return hash((self.linenum, self.line))
3056 return hash((self.linenum, self.line))
3078
3057
3079 def __eq__(self, other):
3058 def __eq__(self, other):
3080 return self.line == other.line
3059 return self.line == other.line
3081
3060
3082 def findpos(self):
3061 def findpos(self):
3083 """Iterate all (start, end) indices of matches"""
3062 """Iterate all (start, end) indices of matches"""
3084 yield self.colstart, self.colend
3063 yield self.colstart, self.colend
3085 p = self.colend
3064 p = self.colend
3086 while p < len(self.line):
3065 while p < len(self.line):
3087 m = regexp.search(self.line, p)
3066 m = regexp.search(self.line, p)
3088 if not m:
3067 if not m:
3089 break
3068 break
3090 yield m.span()
3069 yield m.span()
3091 p = m.end()
3070 p = m.end()
3092
3071
3093 matches = {}
3072 matches = {}
3094 copies = {}
3073 copies = {}
3095 def grepbody(fn, rev, body):
3074 def grepbody(fn, rev, body):
3096 matches[rev].setdefault(fn, [])
3075 matches[rev].setdefault(fn, [])
3097 m = matches[rev][fn]
3076 m = matches[rev][fn]
3098 for lnum, cstart, cend, line in matchlines(body):
3077 for lnum, cstart, cend, line in matchlines(body):
3099 s = linestate(line, lnum, cstart, cend)
3078 s = linestate(line, lnum, cstart, cend)
3100 m.append(s)
3079 m.append(s)
3101
3080
3102 def difflinestates(a, b):
3081 def difflinestates(a, b):
3103 sm = difflib.SequenceMatcher(None, a, b)
3082 sm = difflib.SequenceMatcher(None, a, b)
3104 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3083 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3105 if tag == 'insert':
3084 if tag == 'insert':
3106 for i in xrange(blo, bhi):
3085 for i in xrange(blo, bhi):
3107 yield ('+', b[i])
3086 yield ('+', b[i])
3108 elif tag == 'delete':
3087 elif tag == 'delete':
3109 for i in xrange(alo, ahi):
3088 for i in xrange(alo, ahi):
3110 yield ('-', a[i])
3089 yield ('-', a[i])
3111 elif tag == 'replace':
3090 elif tag == 'replace':
3112 for i in xrange(alo, ahi):
3091 for i in xrange(alo, ahi):
3113 yield ('-', a[i])
3092 yield ('-', a[i])
3114 for i in xrange(blo, bhi):
3093 for i in xrange(blo, bhi):
3115 yield ('+', b[i])
3094 yield ('+', b[i])
3116
3095
3117 def display(fm, fn, ctx, pstates, states):
3096 def display(fm, fn, ctx, pstates, states):
3118 rev = ctx.rev()
3097 rev = ctx.rev()
3119 if fm.isplain():
3098 if fm.isplain():
3120 formatuser = ui.shortuser
3099 formatuser = ui.shortuser
3121 else:
3100 else:
3122 formatuser = str
3101 formatuser = str
3123 if ui.quiet:
3102 if ui.quiet:
3124 datefmt = '%Y-%m-%d'
3103 datefmt = '%Y-%m-%d'
3125 else:
3104 else:
3126 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3105 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3127 found = False
3106 found = False
3128 @util.cachefunc
3107 @util.cachefunc
3129 def binary():
3108 def binary():
3130 flog = getfile(fn)
3109 flog = getfile(fn)
3131 return util.binary(flog.read(ctx.filenode(fn)))
3110 return util.binary(flog.read(ctx.filenode(fn)))
3132
3111
3133 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3112 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3134 if opts.get('all'):
3113 if opts.get('all'):
3135 iter = difflinestates(pstates, states)
3114 iter = difflinestates(pstates, states)
3136 else:
3115 else:
3137 iter = [('', l) for l in states]
3116 iter = [('', l) for l in states]
3138 for change, l in iter:
3117 for change, l in iter:
3139 fm.startitem()
3118 fm.startitem()
3140 fm.data(node=fm.hexfunc(ctx.node()))
3119 fm.data(node=fm.hexfunc(ctx.node()))
3141 cols = [
3120 cols = [
3142 ('filename', fn, True),
3121 ('filename', fn, True),
3143 ('rev', rev, True),
3122 ('rev', rev, True),
3144 ('linenumber', l.linenum, opts.get('line_number')),
3123 ('linenumber', l.linenum, opts.get('line_number')),
3145 ]
3124 ]
3146 if opts.get('all'):
3125 if opts.get('all'):
3147 cols.append(('change', change, True))
3126 cols.append(('change', change, True))
3148 cols.extend([
3127 cols.extend([
3149 ('user', formatuser(ctx.user()), opts.get('user')),
3128 ('user', formatuser(ctx.user()), opts.get('user')),
3150 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3129 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3151 ])
3130 ])
3152 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3131 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3153 for name, data, cond in cols:
3132 for name, data, cond in cols:
3154 field = fieldnamemap.get(name, name)
3133 field = fieldnamemap.get(name, name)
3155 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3134 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3156 if cond and name != lastcol:
3135 if cond and name != lastcol:
3157 fm.plain(sep, label='grep.sep')
3136 fm.plain(sep, label='grep.sep')
3158 if not opts.get('files_with_matches'):
3137 if not opts.get('files_with_matches'):
3159 fm.plain(sep, label='grep.sep')
3138 fm.plain(sep, label='grep.sep')
3160 if not opts.get('text') and binary():
3139 if not opts.get('text') and binary():
3161 fm.plain(_(" Binary file matches"))
3140 fm.plain(_(" Binary file matches"))
3162 else:
3141 else:
3163 displaymatches(fm.nested('texts'), l)
3142 displaymatches(fm.nested('texts'), l)
3164 fm.plain(eol)
3143 fm.plain(eol)
3165 found = True
3144 found = True
3166 if opts.get('files_with_matches'):
3145 if opts.get('files_with_matches'):
3167 break
3146 break
3168 return found
3147 return found
3169
3148
3170 def displaymatches(fm, l):
3149 def displaymatches(fm, l):
3171 p = 0
3150 p = 0
3172 for s, e in l.findpos():
3151 for s, e in l.findpos():
3173 if p < s:
3152 if p < s:
3174 fm.startitem()
3153 fm.startitem()
3175 fm.write('text', '%s', l.line[p:s])
3154 fm.write('text', '%s', l.line[p:s])
3176 fm.data(matched=False)
3155 fm.data(matched=False)
3177 fm.startitem()
3156 fm.startitem()
3178 fm.write('text', '%s', l.line[s:e], label='grep.match')
3157 fm.write('text', '%s', l.line[s:e], label='grep.match')
3179 fm.data(matched=True)
3158 fm.data(matched=True)
3180 p = e
3159 p = e
3181 if p < len(l.line):
3160 if p < len(l.line):
3182 fm.startitem()
3161 fm.startitem()
3183 fm.write('text', '%s', l.line[p:])
3162 fm.write('text', '%s', l.line[p:])
3184 fm.data(matched=False)
3163 fm.data(matched=False)
3185 fm.end()
3164 fm.end()
3186
3165
3187 skip = {}
3166 skip = {}
3188 revfiles = {}
3167 revfiles = {}
3189 matchfn = scmutil.match(repo[None], pats, opts)
3168 matchfn = scmutil.match(repo[None], pats, opts)
3190 found = False
3169 found = False
3191 follow = opts.get('follow')
3170 follow = opts.get('follow')
3192
3171
3193 def prep(ctx, fns):
3172 def prep(ctx, fns):
3194 rev = ctx.rev()
3173 rev = ctx.rev()
3195 pctx = ctx.p1()
3174 pctx = ctx.p1()
3196 parent = pctx.rev()
3175 parent = pctx.rev()
3197 matches.setdefault(rev, {})
3176 matches.setdefault(rev, {})
3198 matches.setdefault(parent, {})
3177 matches.setdefault(parent, {})
3199 files = revfiles.setdefault(rev, [])
3178 files = revfiles.setdefault(rev, [])
3200 for fn in fns:
3179 for fn in fns:
3201 flog = getfile(fn)
3180 flog = getfile(fn)
3202 try:
3181 try:
3203 fnode = ctx.filenode(fn)
3182 fnode = ctx.filenode(fn)
3204 except error.LookupError:
3183 except error.LookupError:
3205 continue
3184 continue
3206
3185
3207 copied = flog.renamed(fnode)
3186 copied = flog.renamed(fnode)
3208 copy = follow and copied and copied[0]
3187 copy = follow and copied and copied[0]
3209 if copy:
3188 if copy:
3210 copies.setdefault(rev, {})[fn] = copy
3189 copies.setdefault(rev, {})[fn] = copy
3211 if fn in skip:
3190 if fn in skip:
3212 if copy:
3191 if copy:
3213 skip[copy] = True
3192 skip[copy] = True
3214 continue
3193 continue
3215 files.append(fn)
3194 files.append(fn)
3216
3195
3217 if fn not in matches[rev]:
3196 if fn not in matches[rev]:
3218 grepbody(fn, rev, flog.read(fnode))
3197 grepbody(fn, rev, flog.read(fnode))
3219
3198
3220 pfn = copy or fn
3199 pfn = copy or fn
3221 if pfn not in matches[parent]:
3200 if pfn not in matches[parent]:
3222 try:
3201 try:
3223 fnode = pctx.filenode(pfn)
3202 fnode = pctx.filenode(pfn)
3224 grepbody(pfn, parent, flog.read(fnode))
3203 grepbody(pfn, parent, flog.read(fnode))
3225 except error.LookupError:
3204 except error.LookupError:
3226 pass
3205 pass
3227
3206
3228 fm = ui.formatter('grep', opts)
3207 fm = ui.formatter('grep', opts)
3229 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3208 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3230 rev = ctx.rev()
3209 rev = ctx.rev()
3231 parent = ctx.p1().rev()
3210 parent = ctx.p1().rev()
3232 for fn in sorted(revfiles.get(rev, [])):
3211 for fn in sorted(revfiles.get(rev, [])):
3233 states = matches[rev][fn]
3212 states = matches[rev][fn]
3234 copy = copies.get(rev, {}).get(fn)
3213 copy = copies.get(rev, {}).get(fn)
3235 if fn in skip:
3214 if fn in skip:
3236 if copy:
3215 if copy:
3237 skip[copy] = True
3216 skip[copy] = True
3238 continue
3217 continue
3239 pstates = matches.get(parent, {}).get(copy or fn, [])
3218 pstates = matches.get(parent, {}).get(copy or fn, [])
3240 if pstates or states:
3219 if pstates or states:
3241 r = display(fm, fn, ctx, pstates, states)
3220 r = display(fm, fn, ctx, pstates, states)
3242 found = found or r
3221 found = found or r
3243 if r and not opts.get('all'):
3222 if r and not opts.get('all'):
3244 skip[fn] = True
3223 skip[fn] = True
3245 if copy:
3224 if copy:
3246 skip[copy] = True
3225 skip[copy] = True
3247 del matches[rev]
3226 del matches[rev]
3248 del revfiles[rev]
3227 del revfiles[rev]
3249 fm.end()
3228 fm.end()
3250
3229
3251 return not found
3230 return not found
3252
3231
3253 @command('heads',
3232 @command('heads',
3254 [('r', 'rev', '',
3233 [('r', 'rev', '',
3255 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3234 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3256 ('t', 'topo', False, _('show topological heads only')),
3235 ('t', 'topo', False, _('show topological heads only')),
3257 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3236 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3258 ('c', 'closed', False, _('show normal and closed branch heads')),
3237 ('c', 'closed', False, _('show normal and closed branch heads')),
3259 ] + templateopts,
3238 ] + templateopts,
3260 _('[-ct] [-r STARTREV] [REV]...'))
3239 _('[-ct] [-r STARTREV] [REV]...'))
3261 def heads(ui, repo, *branchrevs, **opts):
3240 def heads(ui, repo, *branchrevs, **opts):
3262 """show branch heads
3241 """show branch heads
3263
3242
3264 With no arguments, show all open branch heads in the repository.
3243 With no arguments, show all open branch heads in the repository.
3265 Branch heads are changesets that have no descendants on the
3244 Branch heads are changesets that have no descendants on the
3266 same branch. They are where development generally takes place and
3245 same branch. They are where development generally takes place and
3267 are the usual targets for update and merge operations.
3246 are the usual targets for update and merge operations.
3268
3247
3269 If one or more REVs are given, only open branch heads on the
3248 If one or more REVs are given, only open branch heads on the
3270 branches associated with the specified changesets are shown. This
3249 branches associated with the specified changesets are shown. This
3271 means that you can use :hg:`heads .` to see the heads on the
3250 means that you can use :hg:`heads .` to see the heads on the
3272 currently checked-out branch.
3251 currently checked-out branch.
3273
3252
3274 If -c/--closed is specified, also show branch heads marked closed
3253 If -c/--closed is specified, also show branch heads marked closed
3275 (see :hg:`commit --close-branch`).
3254 (see :hg:`commit --close-branch`).
3276
3255
3277 If STARTREV is specified, only those heads that are descendants of
3256 If STARTREV is specified, only those heads that are descendants of
3278 STARTREV will be displayed.
3257 STARTREV will be displayed.
3279
3258
3280 If -t/--topo is specified, named branch mechanics will be ignored and only
3259 If -t/--topo is specified, named branch mechanics will be ignored and only
3281 topological heads (changesets with no children) will be shown.
3260 topological heads (changesets with no children) will be shown.
3282
3261
3283 Returns 0 if matching heads are found, 1 if not.
3262 Returns 0 if matching heads are found, 1 if not.
3284 """
3263 """
3285
3264
3286 start = None
3265 start = None
3287 if 'rev' in opts:
3266 if 'rev' in opts:
3288 start = scmutil.revsingle(repo, opts['rev'], None).node()
3267 start = scmutil.revsingle(repo, opts['rev'], None).node()
3289
3268
3290 if opts.get('topo'):
3269 if opts.get('topo'):
3291 heads = [repo[h] for h in repo.heads(start)]
3270 heads = [repo[h] for h in repo.heads(start)]
3292 else:
3271 else:
3293 heads = []
3272 heads = []
3294 for branch in repo.branchmap():
3273 for branch in repo.branchmap():
3295 heads += repo.branchheads(branch, start, opts.get('closed'))
3274 heads += repo.branchheads(branch, start, opts.get('closed'))
3296 heads = [repo[h] for h in heads]
3275 heads = [repo[h] for h in heads]
3297
3276
3298 if branchrevs:
3277 if branchrevs:
3299 branches = set(repo[br].branch() for br in branchrevs)
3278 branches = set(repo[br].branch() for br in branchrevs)
3300 heads = [h for h in heads if h.branch() in branches]
3279 heads = [h for h in heads if h.branch() in branches]
3301
3280
3302 if opts.get('active') and branchrevs:
3281 if opts.get('active') and branchrevs:
3303 dagheads = repo.heads(start)
3282 dagheads = repo.heads(start)
3304 heads = [h for h in heads if h.node() in dagheads]
3283 heads = [h for h in heads if h.node() in dagheads]
3305
3284
3306 if branchrevs:
3285 if branchrevs:
3307 haveheads = set(h.branch() for h in heads)
3286 haveheads = set(h.branch() for h in heads)
3308 if branches - haveheads:
3287 if branches - haveheads:
3309 headless = ', '.join(b for b in branches - haveheads)
3288 headless = ', '.join(b for b in branches - haveheads)
3310 msg = _('no open branch heads found on branches %s')
3289 msg = _('no open branch heads found on branches %s')
3311 if opts.get('rev'):
3290 if opts.get('rev'):
3312 msg += _(' (started at %s)') % opts['rev']
3291 msg += _(' (started at %s)') % opts['rev']
3313 ui.warn((msg + '\n') % headless)
3292 ui.warn((msg + '\n') % headless)
3314
3293
3315 if not heads:
3294 if not heads:
3316 return 1
3295 return 1
3317
3296
3318 heads = sorted(heads, key=lambda x: -x.rev())
3297 heads = sorted(heads, key=lambda x: -x.rev())
3319 displayer = cmdutil.show_changeset(ui, repo, opts)
3298 displayer = cmdutil.show_changeset(ui, repo, opts)
3320 for ctx in heads:
3299 for ctx in heads:
3321 displayer.show(ctx)
3300 displayer.show(ctx)
3322 displayer.close()
3301 displayer.close()
3323
3302
3324 @command('help',
3303 @command('help',
3325 [('e', 'extension', None, _('show only help for extensions')),
3304 [('e', 'extension', None, _('show only help for extensions')),
3326 ('c', 'command', None, _('show only help for commands')),
3305 ('c', 'command', None, _('show only help for commands')),
3327 ('k', 'keyword', None, _('show topics matching keyword')),
3306 ('k', 'keyword', None, _('show topics matching keyword')),
3328 ('s', 'system', [], _('show help for specific platform(s)')),
3307 ('s', 'system', [], _('show help for specific platform(s)')),
3329 ],
3308 ],
3330 _('[-ecks] [TOPIC]'),
3309 _('[-ecks] [TOPIC]'),
3331 norepo=True)
3310 norepo=True)
3332 def help_(ui, name=None, **opts):
3311 def help_(ui, name=None, **opts):
3333 """show help for a given topic or a help overview
3312 """show help for a given topic or a help overview
3334
3313
3335 With no arguments, print a list of commands with short help messages.
3314 With no arguments, print a list of commands with short help messages.
3336
3315
3337 Given a topic, extension, or command name, print help for that
3316 Given a topic, extension, or command name, print help for that
3338 topic.
3317 topic.
3339
3318
3340 Returns 0 if successful.
3319 Returns 0 if successful.
3341 """
3320 """
3342
3321
3343 textwidth = ui.configint('ui', 'textwidth', 78)
3322 textwidth = ui.configint('ui', 'textwidth', 78)
3344 termwidth = ui.termwidth() - 2
3323 termwidth = ui.termwidth() - 2
3345 if textwidth <= 0 or termwidth < textwidth:
3324 if textwidth <= 0 or termwidth < textwidth:
3346 textwidth = termwidth
3325 textwidth = termwidth
3347
3326
3348 keep = opts.get('system') or []
3327 keep = opts.get('system') or []
3349 if len(keep) == 0:
3328 if len(keep) == 0:
3350 if pycompat.sysplatform.startswith('win'):
3329 if pycompat.sysplatform.startswith('win'):
3351 keep.append('windows')
3330 keep.append('windows')
3352 elif pycompat.sysplatform == 'OpenVMS':
3331 elif pycompat.sysplatform == 'OpenVMS':
3353 keep.append('vms')
3332 keep.append('vms')
3354 elif pycompat.sysplatform == 'plan9':
3333 elif pycompat.sysplatform == 'plan9':
3355 keep.append('plan9')
3334 keep.append('plan9')
3356 else:
3335 else:
3357 keep.append('unix')
3336 keep.append('unix')
3358 keep.append(pycompat.sysplatform.lower())
3337 keep.append(pycompat.sysplatform.lower())
3359 if ui.verbose:
3338 if ui.verbose:
3360 keep.append('verbose')
3339 keep.append('verbose')
3361
3340
3362 fullname = name
3341 fullname = name
3363 section = None
3342 section = None
3364 subtopic = None
3343 subtopic = None
3365 if name and '.' in name:
3344 if name and '.' in name:
3366 name, remaining = name.split('.', 1)
3345 name, remaining = name.split('.', 1)
3367 remaining = encoding.lower(remaining)
3346 remaining = encoding.lower(remaining)
3368 if '.' in remaining:
3347 if '.' in remaining:
3369 subtopic, section = remaining.split('.', 1)
3348 subtopic, section = remaining.split('.', 1)
3370 else:
3349 else:
3371 if name in help.subtopics:
3350 if name in help.subtopics:
3372 subtopic = remaining
3351 subtopic = remaining
3373 else:
3352 else:
3374 section = remaining
3353 section = remaining
3375
3354
3376 text = help.help_(ui, name, subtopic=subtopic, **opts)
3355 text = help.help_(ui, name, subtopic=subtopic, **opts)
3377
3356
3378 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3357 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3379 section=section)
3358 section=section)
3380
3359
3381 # We could have been given a weird ".foo" section without a name
3360 # We could have been given a weird ".foo" section without a name
3382 # to look for, or we could have simply failed to found "foo.bar"
3361 # to look for, or we could have simply failed to found "foo.bar"
3383 # because bar isn't a section of foo
3362 # because bar isn't a section of foo
3384 if section and not (formatted and name):
3363 if section and not (formatted and name):
3385 raise error.Abort(_("help section not found: %s") % fullname)
3364 raise error.Abort(_("help section not found: %s") % fullname)
3386
3365
3387 if 'verbose' in pruned:
3366 if 'verbose' in pruned:
3388 keep.append('omitted')
3367 keep.append('omitted')
3389 else:
3368 else:
3390 keep.append('notomitted')
3369 keep.append('notomitted')
3391 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3370 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3392 section=section)
3371 section=section)
3393 ui.write(formatted)
3372 ui.write(formatted)
3394
3373
3395
3374
3396 @command('identify|id',
3375 @command('identify|id',
3397 [('r', 'rev', '',
3376 [('r', 'rev', '',
3398 _('identify the specified revision'), _('REV')),
3377 _('identify the specified revision'), _('REV')),
3399 ('n', 'num', None, _('show local revision number')),
3378 ('n', 'num', None, _('show local revision number')),
3400 ('i', 'id', None, _('show global revision id')),
3379 ('i', 'id', None, _('show global revision id')),
3401 ('b', 'branch', None, _('show branch')),
3380 ('b', 'branch', None, _('show branch')),
3402 ('t', 'tags', None, _('show tags')),
3381 ('t', 'tags', None, _('show tags')),
3403 ('B', 'bookmarks', None, _('show bookmarks')),
3382 ('B', 'bookmarks', None, _('show bookmarks')),
3404 ] + remoteopts,
3383 ] + remoteopts,
3405 _('[-nibtB] [-r REV] [SOURCE]'),
3384 _('[-nibtB] [-r REV] [SOURCE]'),
3406 optionalrepo=True)
3385 optionalrepo=True)
3407 def identify(ui, repo, source=None, rev=None,
3386 def identify(ui, repo, source=None, rev=None,
3408 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3387 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3409 """identify the working directory or specified revision
3388 """identify the working directory or specified revision
3410
3389
3411 Print a summary identifying the repository state at REV using one or
3390 Print a summary identifying the repository state at REV using one or
3412 two parent hash identifiers, followed by a "+" if the working
3391 two parent hash identifiers, followed by a "+" if the working
3413 directory has uncommitted changes, the branch name (if not default),
3392 directory has uncommitted changes, the branch name (if not default),
3414 a list of tags, and a list of bookmarks.
3393 a list of tags, and a list of bookmarks.
3415
3394
3416 When REV is not given, print a summary of the current state of the
3395 When REV is not given, print a summary of the current state of the
3417 repository.
3396 repository.
3418
3397
3419 Specifying a path to a repository root or Mercurial bundle will
3398 Specifying a path to a repository root or Mercurial bundle will
3420 cause lookup to operate on that repository/bundle.
3399 cause lookup to operate on that repository/bundle.
3421
3400
3422 .. container:: verbose
3401 .. container:: verbose
3423
3402
3424 Examples:
3403 Examples:
3425
3404
3426 - generate a build identifier for the working directory::
3405 - generate a build identifier for the working directory::
3427
3406
3428 hg id --id > build-id.dat
3407 hg id --id > build-id.dat
3429
3408
3430 - find the revision corresponding to a tag::
3409 - find the revision corresponding to a tag::
3431
3410
3432 hg id -n -r 1.3
3411 hg id -n -r 1.3
3433
3412
3434 - check the most recent revision of a remote repository::
3413 - check the most recent revision of a remote repository::
3435
3414
3436 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3415 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3437
3416
3438 See :hg:`log` for generating more information about specific revisions,
3417 See :hg:`log` for generating more information about specific revisions,
3439 including full hash identifiers.
3418 including full hash identifiers.
3440
3419
3441 Returns 0 if successful.
3420 Returns 0 if successful.
3442 """
3421 """
3443
3422
3444 if not repo and not source:
3423 if not repo and not source:
3445 raise error.Abort(_("there is no Mercurial repository here "
3424 raise error.Abort(_("there is no Mercurial repository here "
3446 "(.hg not found)"))
3425 "(.hg not found)"))
3447
3426
3448 if ui.debugflag:
3427 if ui.debugflag:
3449 hexfunc = hex
3428 hexfunc = hex
3450 else:
3429 else:
3451 hexfunc = short
3430 hexfunc = short
3452 default = not (num or id or branch or tags or bookmarks)
3431 default = not (num or id or branch or tags or bookmarks)
3453 output = []
3432 output = []
3454 revs = []
3433 revs = []
3455
3434
3456 if source:
3435 if source:
3457 source, branches = hg.parseurl(ui.expandpath(source))
3436 source, branches = hg.parseurl(ui.expandpath(source))
3458 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3437 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3459 repo = peer.local()
3438 repo = peer.local()
3460 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3439 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3461
3440
3462 if not repo:
3441 if not repo:
3463 if num or branch or tags:
3442 if num or branch or tags:
3464 raise error.Abort(
3443 raise error.Abort(
3465 _("can't query remote revision number, branch, or tags"))
3444 _("can't query remote revision number, branch, or tags"))
3466 if not rev and revs:
3445 if not rev and revs:
3467 rev = revs[0]
3446 rev = revs[0]
3468 if not rev:
3447 if not rev:
3469 rev = "tip"
3448 rev = "tip"
3470
3449
3471 remoterev = peer.lookup(rev)
3450 remoterev = peer.lookup(rev)
3472 if default or id:
3451 if default or id:
3473 output = [hexfunc(remoterev)]
3452 output = [hexfunc(remoterev)]
3474
3453
3475 def getbms():
3454 def getbms():
3476 bms = []
3455 bms = []
3477
3456
3478 if 'bookmarks' in peer.listkeys('namespaces'):
3457 if 'bookmarks' in peer.listkeys('namespaces'):
3479 hexremoterev = hex(remoterev)
3458 hexremoterev = hex(remoterev)
3480 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3459 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3481 if bmr == hexremoterev]
3460 if bmr == hexremoterev]
3482
3461
3483 return sorted(bms)
3462 return sorted(bms)
3484
3463
3485 if bookmarks:
3464 if bookmarks:
3486 output.extend(getbms())
3465 output.extend(getbms())
3487 elif default and not ui.quiet:
3466 elif default and not ui.quiet:
3488 # multiple bookmarks for a single parent separated by '/'
3467 # multiple bookmarks for a single parent separated by '/'
3489 bm = '/'.join(getbms())
3468 bm = '/'.join(getbms())
3490 if bm:
3469 if bm:
3491 output.append(bm)
3470 output.append(bm)
3492 else:
3471 else:
3493 ctx = scmutil.revsingle(repo, rev, None)
3472 ctx = scmutil.revsingle(repo, rev, None)
3494
3473
3495 if ctx.rev() is None:
3474 if ctx.rev() is None:
3496 ctx = repo[None]
3475 ctx = repo[None]
3497 parents = ctx.parents()
3476 parents = ctx.parents()
3498 taglist = []
3477 taglist = []
3499 for p in parents:
3478 for p in parents:
3500 taglist.extend(p.tags())
3479 taglist.extend(p.tags())
3501
3480
3502 changed = ""
3481 changed = ""
3503 if default or id or num:
3482 if default or id or num:
3504 if (any(repo.status())
3483 if (any(repo.status())
3505 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3484 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3506 changed = '+'
3485 changed = '+'
3507 if default or id:
3486 if default or id:
3508 output = ["%s%s" %
3487 output = ["%s%s" %
3509 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3488 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3510 if num:
3489 if num:
3511 output.append("%s%s" %
3490 output.append("%s%s" %
3512 ('+'.join([str(p.rev()) for p in parents]), changed))
3491 ('+'.join([str(p.rev()) for p in parents]), changed))
3513 else:
3492 else:
3514 if default or id:
3493 if default or id:
3515 output = [hexfunc(ctx.node())]
3494 output = [hexfunc(ctx.node())]
3516 if num:
3495 if num:
3517 output.append(str(ctx.rev()))
3496 output.append(str(ctx.rev()))
3518 taglist = ctx.tags()
3497 taglist = ctx.tags()
3519
3498
3520 if default and not ui.quiet:
3499 if default and not ui.quiet:
3521 b = ctx.branch()
3500 b = ctx.branch()
3522 if b != 'default':
3501 if b != 'default':
3523 output.append("(%s)" % b)
3502 output.append("(%s)" % b)
3524
3503
3525 # multiple tags for a single parent separated by '/'
3504 # multiple tags for a single parent separated by '/'
3526 t = '/'.join(taglist)
3505 t = '/'.join(taglist)
3527 if t:
3506 if t:
3528 output.append(t)
3507 output.append(t)
3529
3508
3530 # multiple bookmarks for a single parent separated by '/'
3509 # multiple bookmarks for a single parent separated by '/'
3531 bm = '/'.join(ctx.bookmarks())
3510 bm = '/'.join(ctx.bookmarks())
3532 if bm:
3511 if bm:
3533 output.append(bm)
3512 output.append(bm)
3534 else:
3513 else:
3535 if branch:
3514 if branch:
3536 output.append(ctx.branch())
3515 output.append(ctx.branch())
3537
3516
3538 if tags:
3517 if tags:
3539 output.extend(taglist)
3518 output.extend(taglist)
3540
3519
3541 if bookmarks:
3520 if bookmarks:
3542 output.extend(ctx.bookmarks())
3521 output.extend(ctx.bookmarks())
3543
3522
3544 ui.write("%s\n" % ' '.join(output))
3523 ui.write("%s\n" % ' '.join(output))
3545
3524
3546 @command('import|patch',
3525 @command('import|patch',
3547 [('p', 'strip', 1,
3526 [('p', 'strip', 1,
3548 _('directory strip option for patch. This has the same '
3527 _('directory strip option for patch. This has the same '
3549 'meaning as the corresponding patch option'), _('NUM')),
3528 'meaning as the corresponding patch option'), _('NUM')),
3550 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3529 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3551 ('e', 'edit', False, _('invoke editor on commit messages')),
3530 ('e', 'edit', False, _('invoke editor on commit messages')),
3552 ('f', 'force', None,
3531 ('f', 'force', None,
3553 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3532 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3554 ('', 'no-commit', None,
3533 ('', 'no-commit', None,
3555 _("don't commit, just update the working directory")),
3534 _("don't commit, just update the working directory")),
3556 ('', 'bypass', None,
3535 ('', 'bypass', None,
3557 _("apply patch without touching the working directory")),
3536 _("apply patch without touching the working directory")),
3558 ('', 'partial', None,
3537 ('', 'partial', None,
3559 _('commit even if some hunks fail')),
3538 _('commit even if some hunks fail')),
3560 ('', 'exact', None,
3539 ('', 'exact', None,
3561 _('abort if patch would apply lossily')),
3540 _('abort if patch would apply lossily')),
3562 ('', 'prefix', '',
3541 ('', 'prefix', '',
3563 _('apply patch to subdirectory'), _('DIR')),
3542 _('apply patch to subdirectory'), _('DIR')),
3564 ('', 'import-branch', None,
3543 ('', 'import-branch', None,
3565 _('use any branch information in patch (implied by --exact)'))] +
3544 _('use any branch information in patch (implied by --exact)'))] +
3566 commitopts + commitopts2 + similarityopts,
3545 commitopts + commitopts2 + similarityopts,
3567 _('[OPTION]... PATCH...'))
3546 _('[OPTION]... PATCH...'))
3568 def import_(ui, repo, patch1=None, *patches, **opts):
3547 def import_(ui, repo, patch1=None, *patches, **opts):
3569 """import an ordered set of patches
3548 """import an ordered set of patches
3570
3549
3571 Import a list of patches and commit them individually (unless
3550 Import a list of patches and commit them individually (unless
3572 --no-commit is specified).
3551 --no-commit is specified).
3573
3552
3574 To read a patch from standard input (stdin), use "-" as the patch
3553 To read a patch from standard input (stdin), use "-" as the patch
3575 name. If a URL is specified, the patch will be downloaded from
3554 name. If a URL is specified, the patch will be downloaded from
3576 there.
3555 there.
3577
3556
3578 Import first applies changes to the working directory (unless
3557 Import first applies changes to the working directory (unless
3579 --bypass is specified), import will abort if there are outstanding
3558 --bypass is specified), import will abort if there are outstanding
3580 changes.
3559 changes.
3581
3560
3582 Use --bypass to apply and commit patches directly to the
3561 Use --bypass to apply and commit patches directly to the
3583 repository, without affecting the working directory. Without
3562 repository, without affecting the working directory. Without
3584 --exact, patches will be applied on top of the working directory
3563 --exact, patches will be applied on top of the working directory
3585 parent revision.
3564 parent revision.
3586
3565
3587 You can import a patch straight from a mail message. Even patches
3566 You can import a patch straight from a mail message. Even patches
3588 as attachments work (to use the body part, it must have type
3567 as attachments work (to use the body part, it must have type
3589 text/plain or text/x-patch). From and Subject headers of email
3568 text/plain or text/x-patch). From and Subject headers of email
3590 message are used as default committer and commit message. All
3569 message are used as default committer and commit message. All
3591 text/plain body parts before first diff are added to the commit
3570 text/plain body parts before first diff are added to the commit
3592 message.
3571 message.
3593
3572
3594 If the imported patch was generated by :hg:`export`, user and
3573 If the imported patch was generated by :hg:`export`, user and
3595 description from patch override values from message headers and
3574 description from patch override values from message headers and
3596 body. Values given on command line with -m/--message and -u/--user
3575 body. Values given on command line with -m/--message and -u/--user
3597 override these.
3576 override these.
3598
3577
3599 If --exact is specified, import will set the working directory to
3578 If --exact is specified, import will set the working directory to
3600 the parent of each patch before applying it, and will abort if the
3579 the parent of each patch before applying it, and will abort if the
3601 resulting changeset has a different ID than the one recorded in
3580 resulting changeset has a different ID than the one recorded in
3602 the patch. This will guard against various ways that portable
3581 the patch. This will guard against various ways that portable
3603 patch formats and mail systems might fail to transfer Mercurial
3582 patch formats and mail systems might fail to transfer Mercurial
3604 data or metadata. See :hg:`bundle` for lossless transmission.
3583 data or metadata. See :hg:`bundle` for lossless transmission.
3605
3584
3606 Use --partial to ensure a changeset will be created from the patch
3585 Use --partial to ensure a changeset will be created from the patch
3607 even if some hunks fail to apply. Hunks that fail to apply will be
3586 even if some hunks fail to apply. Hunks that fail to apply will be
3608 written to a <target-file>.rej file. Conflicts can then be resolved
3587 written to a <target-file>.rej file. Conflicts can then be resolved
3609 by hand before :hg:`commit --amend` is run to update the created
3588 by hand before :hg:`commit --amend` is run to update the created
3610 changeset. This flag exists to let people import patches that
3589 changeset. This flag exists to let people import patches that
3611 partially apply without losing the associated metadata (author,
3590 partially apply without losing the associated metadata (author,
3612 date, description, ...).
3591 date, description, ...).
3613
3592
3614 .. note::
3593 .. note::
3615
3594
3616 When no hunks apply cleanly, :hg:`import --partial` will create
3595 When no hunks apply cleanly, :hg:`import --partial` will create
3617 an empty changeset, importing only the patch metadata.
3596 an empty changeset, importing only the patch metadata.
3618
3597
3619 With -s/--similarity, hg will attempt to discover renames and
3598 With -s/--similarity, hg will attempt to discover renames and
3620 copies in the patch in the same way as :hg:`addremove`.
3599 copies in the patch in the same way as :hg:`addremove`.
3621
3600
3622 It is possible to use external patch programs to perform the patch
3601 It is possible to use external patch programs to perform the patch
3623 by setting the ``ui.patch`` configuration option. For the default
3602 by setting the ``ui.patch`` configuration option. For the default
3624 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3603 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3625 See :hg:`help config` for more information about configuration
3604 See :hg:`help config` for more information about configuration
3626 files and how to use these options.
3605 files and how to use these options.
3627
3606
3628 See :hg:`help dates` for a list of formats valid for -d/--date.
3607 See :hg:`help dates` for a list of formats valid for -d/--date.
3629
3608
3630 .. container:: verbose
3609 .. container:: verbose
3631
3610
3632 Examples:
3611 Examples:
3633
3612
3634 - import a traditional patch from a website and detect renames::
3613 - import a traditional patch from a website and detect renames::
3635
3614
3636 hg import -s 80 http://example.com/bugfix.patch
3615 hg import -s 80 http://example.com/bugfix.patch
3637
3616
3638 - import a changeset from an hgweb server::
3617 - import a changeset from an hgweb server::
3639
3618
3640 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3619 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3641
3620
3642 - import all the patches in an Unix-style mbox::
3621 - import all the patches in an Unix-style mbox::
3643
3622
3644 hg import incoming-patches.mbox
3623 hg import incoming-patches.mbox
3645
3624
3646 - import patches from stdin::
3625 - import patches from stdin::
3647
3626
3648 hg import -
3627 hg import -
3649
3628
3650 - attempt to exactly restore an exported changeset (not always
3629 - attempt to exactly restore an exported changeset (not always
3651 possible)::
3630 possible)::
3652
3631
3653 hg import --exact proposed-fix.patch
3632 hg import --exact proposed-fix.patch
3654
3633
3655 - use an external tool to apply a patch which is too fuzzy for
3634 - use an external tool to apply a patch which is too fuzzy for
3656 the default internal tool.
3635 the default internal tool.
3657
3636
3658 hg import --config ui.patch="patch --merge" fuzzy.patch
3637 hg import --config ui.patch="patch --merge" fuzzy.patch
3659
3638
3660 - change the default fuzzing from 2 to a less strict 7
3639 - change the default fuzzing from 2 to a less strict 7
3661
3640
3662 hg import --config ui.fuzz=7 fuzz.patch
3641 hg import --config ui.fuzz=7 fuzz.patch
3663
3642
3664 Returns 0 on success, 1 on partial success (see --partial).
3643 Returns 0 on success, 1 on partial success (see --partial).
3665 """
3644 """
3666
3645
3667 if not patch1:
3646 if not patch1:
3668 raise error.Abort(_('need at least one patch to import'))
3647 raise error.Abort(_('need at least one patch to import'))
3669
3648
3670 patches = (patch1,) + patches
3649 patches = (patch1,) + patches
3671
3650
3672 date = opts.get('date')
3651 date = opts.get('date')
3673 if date:
3652 if date:
3674 opts['date'] = util.parsedate(date)
3653 opts['date'] = util.parsedate(date)
3675
3654
3676 exact = opts.get('exact')
3655 exact = opts.get('exact')
3677 update = not opts.get('bypass')
3656 update = not opts.get('bypass')
3678 if not update and opts.get('no_commit'):
3657 if not update and opts.get('no_commit'):
3679 raise error.Abort(_('cannot use --no-commit with --bypass'))
3658 raise error.Abort(_('cannot use --no-commit with --bypass'))
3680 try:
3659 try:
3681 sim = float(opts.get('similarity') or 0)
3660 sim = float(opts.get('similarity') or 0)
3682 except ValueError:
3661 except ValueError:
3683 raise error.Abort(_('similarity must be a number'))
3662 raise error.Abort(_('similarity must be a number'))
3684 if sim < 0 or sim > 100:
3663 if sim < 0 or sim > 100:
3685 raise error.Abort(_('similarity must be between 0 and 100'))
3664 raise error.Abort(_('similarity must be between 0 and 100'))
3686 if sim and not update:
3665 if sim and not update:
3687 raise error.Abort(_('cannot use --similarity with --bypass'))
3666 raise error.Abort(_('cannot use --similarity with --bypass'))
3688 if exact:
3667 if exact:
3689 if opts.get('edit'):
3668 if opts.get('edit'):
3690 raise error.Abort(_('cannot use --exact with --edit'))
3669 raise error.Abort(_('cannot use --exact with --edit'))
3691 if opts.get('prefix'):
3670 if opts.get('prefix'):
3692 raise error.Abort(_('cannot use --exact with --prefix'))
3671 raise error.Abort(_('cannot use --exact with --prefix'))
3693
3672
3694 base = opts["base"]
3673 base = opts["base"]
3695 wlock = dsguard = lock = tr = None
3674 wlock = dsguard = lock = tr = None
3696 msgs = []
3675 msgs = []
3697 ret = 0
3676 ret = 0
3698
3677
3699
3678
3700 try:
3679 try:
3701 wlock = repo.wlock()
3680 wlock = repo.wlock()
3702
3681
3703 if update:
3682 if update:
3704 cmdutil.checkunfinished(repo)
3683 cmdutil.checkunfinished(repo)
3705 if (exact or not opts.get('force')):
3684 if (exact or not opts.get('force')):
3706 cmdutil.bailifchanged(repo)
3685 cmdutil.bailifchanged(repo)
3707
3686
3708 if not opts.get('no_commit'):
3687 if not opts.get('no_commit'):
3709 lock = repo.lock()
3688 lock = repo.lock()
3710 tr = repo.transaction('import')
3689 tr = repo.transaction('import')
3711 else:
3690 else:
3712 dsguard = dirstateguard.dirstateguard(repo, 'import')
3691 dsguard = dirstateguard.dirstateguard(repo, 'import')
3713 parents = repo[None].parents()
3692 parents = repo[None].parents()
3714 for patchurl in patches:
3693 for patchurl in patches:
3715 if patchurl == '-':
3694 if patchurl == '-':
3716 ui.status(_('applying patch from stdin\n'))
3695 ui.status(_('applying patch from stdin\n'))
3717 patchfile = ui.fin
3696 patchfile = ui.fin
3718 patchurl = 'stdin' # for error message
3697 patchurl = 'stdin' # for error message
3719 else:
3698 else:
3720 patchurl = os.path.join(base, patchurl)
3699 patchurl = os.path.join(base, patchurl)
3721 ui.status(_('applying %s\n') % patchurl)
3700 ui.status(_('applying %s\n') % patchurl)
3722 patchfile = hg.openpath(ui, patchurl)
3701 patchfile = hg.openpath(ui, patchurl)
3723
3702
3724 haspatch = False
3703 haspatch = False
3725 for hunk in patch.split(patchfile):
3704 for hunk in patch.split(patchfile):
3726 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3705 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3727 parents, opts,
3706 parents, opts,
3728 msgs, hg.clean)
3707 msgs, hg.clean)
3729 if msg:
3708 if msg:
3730 haspatch = True
3709 haspatch = True
3731 ui.note(msg + '\n')
3710 ui.note(msg + '\n')
3732 if update or exact:
3711 if update or exact:
3733 parents = repo[None].parents()
3712 parents = repo[None].parents()
3734 else:
3713 else:
3735 parents = [repo[node]]
3714 parents = [repo[node]]
3736 if rej:
3715 if rej:
3737 ui.write_err(_("patch applied partially\n"))
3716 ui.write_err(_("patch applied partially\n"))
3738 ui.write_err(_("(fix the .rej files and run "
3717 ui.write_err(_("(fix the .rej files and run "
3739 "`hg commit --amend`)\n"))
3718 "`hg commit --amend`)\n"))
3740 ret = 1
3719 ret = 1
3741 break
3720 break
3742
3721
3743 if not haspatch:
3722 if not haspatch:
3744 raise error.Abort(_('%s: no diffs found') % patchurl)
3723 raise error.Abort(_('%s: no diffs found') % patchurl)
3745
3724
3746 if tr:
3725 if tr:
3747 tr.close()
3726 tr.close()
3748 if msgs:
3727 if msgs:
3749 repo.savecommitmessage('\n* * *\n'.join(msgs))
3728 repo.savecommitmessage('\n* * *\n'.join(msgs))
3750 if dsguard:
3729 if dsguard:
3751 dsguard.close()
3730 dsguard.close()
3752 return ret
3731 return ret
3753 finally:
3732 finally:
3754 if tr:
3733 if tr:
3755 tr.release()
3734 tr.release()
3756 release(lock, dsguard, wlock)
3735 release(lock, dsguard, wlock)
3757
3736
3758 @command('incoming|in',
3737 @command('incoming|in',
3759 [('f', 'force', None,
3738 [('f', 'force', None,
3760 _('run even if remote repository is unrelated')),
3739 _('run even if remote repository is unrelated')),
3761 ('n', 'newest-first', None, _('show newest record first')),
3740 ('n', 'newest-first', None, _('show newest record first')),
3762 ('', 'bundle', '',
3741 ('', 'bundle', '',
3763 _('file to store the bundles into'), _('FILE')),
3742 _('file to store the bundles into'), _('FILE')),
3764 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3743 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3765 ('B', 'bookmarks', False, _("compare bookmarks")),
3744 ('B', 'bookmarks', False, _("compare bookmarks")),
3766 ('b', 'branch', [],
3745 ('b', 'branch', [],
3767 _('a specific branch you would like to pull'), _('BRANCH')),
3746 _('a specific branch you would like to pull'), _('BRANCH')),
3768 ] + logopts + remoteopts + subrepoopts,
3747 ] + logopts + remoteopts + subrepoopts,
3769 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3748 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3770 def incoming(ui, repo, source="default", **opts):
3749 def incoming(ui, repo, source="default", **opts):
3771 """show new changesets found in source
3750 """show new changesets found in source
3772
3751
3773 Show new changesets found in the specified path/URL or the default
3752 Show new changesets found in the specified path/URL or the default
3774 pull location. These are the changesets that would have been pulled
3753 pull location. These are the changesets that would have been pulled
3775 if a pull at the time you issued this command.
3754 if a pull at the time you issued this command.
3776
3755
3777 See pull for valid source format details.
3756 See pull for valid source format details.
3778
3757
3779 .. container:: verbose
3758 .. container:: verbose
3780
3759
3781 With -B/--bookmarks, the result of bookmark comparison between
3760 With -B/--bookmarks, the result of bookmark comparison between
3782 local and remote repositories is displayed. With -v/--verbose,
3761 local and remote repositories is displayed. With -v/--verbose,
3783 status is also displayed for each bookmark like below::
3762 status is also displayed for each bookmark like below::
3784
3763
3785 BM1 01234567890a added
3764 BM1 01234567890a added
3786 BM2 1234567890ab advanced
3765 BM2 1234567890ab advanced
3787 BM3 234567890abc diverged
3766 BM3 234567890abc diverged
3788 BM4 34567890abcd changed
3767 BM4 34567890abcd changed
3789
3768
3790 The action taken locally when pulling depends on the
3769 The action taken locally when pulling depends on the
3791 status of each bookmark:
3770 status of each bookmark:
3792
3771
3793 :``added``: pull will create it
3772 :``added``: pull will create it
3794 :``advanced``: pull will update it
3773 :``advanced``: pull will update it
3795 :``diverged``: pull will create a divergent bookmark
3774 :``diverged``: pull will create a divergent bookmark
3796 :``changed``: result depends on remote changesets
3775 :``changed``: result depends on remote changesets
3797
3776
3798 From the point of view of pulling behavior, bookmark
3777 From the point of view of pulling behavior, bookmark
3799 existing only in the remote repository are treated as ``added``,
3778 existing only in the remote repository are treated as ``added``,
3800 even if it is in fact locally deleted.
3779 even if it is in fact locally deleted.
3801
3780
3802 .. container:: verbose
3781 .. container:: verbose
3803
3782
3804 For remote repository, using --bundle avoids downloading the
3783 For remote repository, using --bundle avoids downloading the
3805 changesets twice if the incoming is followed by a pull.
3784 changesets twice if the incoming is followed by a pull.
3806
3785
3807 Examples:
3786 Examples:
3808
3787
3809 - show incoming changes with patches and full description::
3788 - show incoming changes with patches and full description::
3810
3789
3811 hg incoming -vp
3790 hg incoming -vp
3812
3791
3813 - show incoming changes excluding merges, store a bundle::
3792 - show incoming changes excluding merges, store a bundle::
3814
3793
3815 hg in -vpM --bundle incoming.hg
3794 hg in -vpM --bundle incoming.hg
3816 hg pull incoming.hg
3795 hg pull incoming.hg
3817
3796
3818 - briefly list changes inside a bundle::
3797 - briefly list changes inside a bundle::
3819
3798
3820 hg in changes.hg -T "{desc|firstline}\\n"
3799 hg in changes.hg -T "{desc|firstline}\\n"
3821
3800
3822 Returns 0 if there are incoming changes, 1 otherwise.
3801 Returns 0 if there are incoming changes, 1 otherwise.
3823 """
3802 """
3824 if opts.get('graph'):
3803 if opts.get('graph'):
3825 cmdutil.checkunsupportedgraphflags([], opts)
3804 cmdutil.checkunsupportedgraphflags([], opts)
3826 def display(other, chlist, displayer):
3805 def display(other, chlist, displayer):
3827 revdag = cmdutil.graphrevs(other, chlist, opts)
3806 revdag = cmdutil.graphrevs(other, chlist, opts)
3828 cmdutil.displaygraph(ui, repo, revdag, displayer,
3807 cmdutil.displaygraph(ui, repo, revdag, displayer,
3829 graphmod.asciiedges)
3808 graphmod.asciiedges)
3830
3809
3831 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3810 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3832 return 0
3811 return 0
3833
3812
3834 if opts.get('bundle') and opts.get('subrepos'):
3813 if opts.get('bundle') and opts.get('subrepos'):
3835 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3814 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3836
3815
3837 if opts.get('bookmarks'):
3816 if opts.get('bookmarks'):
3838 source, branches = hg.parseurl(ui.expandpath(source),
3817 source, branches = hg.parseurl(ui.expandpath(source),
3839 opts.get('branch'))
3818 opts.get('branch'))
3840 other = hg.peer(repo, opts, source)
3819 other = hg.peer(repo, opts, source)
3841 if 'bookmarks' not in other.listkeys('namespaces'):
3820 if 'bookmarks' not in other.listkeys('namespaces'):
3842 ui.warn(_("remote doesn't support bookmarks\n"))
3821 ui.warn(_("remote doesn't support bookmarks\n"))
3843 return 0
3822 return 0
3844 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3823 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3845 return bookmarks.incoming(ui, repo, other)
3824 return bookmarks.incoming(ui, repo, other)
3846
3825
3847 repo._subtoppath = ui.expandpath(source)
3826 repo._subtoppath = ui.expandpath(source)
3848 try:
3827 try:
3849 return hg.incoming(ui, repo, source, opts)
3828 return hg.incoming(ui, repo, source, opts)
3850 finally:
3829 finally:
3851 del repo._subtoppath
3830 del repo._subtoppath
3852
3831
3853
3832
3854 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3833 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3855 norepo=True)
3834 norepo=True)
3856 def init(ui, dest=".", **opts):
3835 def init(ui, dest=".", **opts):
3857 """create a new repository in the given directory
3836 """create a new repository in the given directory
3858
3837
3859 Initialize a new repository in the given directory. If the given
3838 Initialize a new repository in the given directory. If the given
3860 directory does not exist, it will be created.
3839 directory does not exist, it will be created.
3861
3840
3862 If no directory is given, the current directory is used.
3841 If no directory is given, the current directory is used.
3863
3842
3864 It is possible to specify an ``ssh://`` URL as the destination.
3843 It is possible to specify an ``ssh://`` URL as the destination.
3865 See :hg:`help urls` for more information.
3844 See :hg:`help urls` for more information.
3866
3845
3867 Returns 0 on success.
3846 Returns 0 on success.
3868 """
3847 """
3869 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3848 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3870
3849
3871 @command('locate',
3850 @command('locate',
3872 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3851 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3873 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3852 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3874 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3853 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3875 ] + walkopts,
3854 ] + walkopts,
3876 _('[OPTION]... [PATTERN]...'))
3855 _('[OPTION]... [PATTERN]...'))
3877 def locate(ui, repo, *pats, **opts):
3856 def locate(ui, repo, *pats, **opts):
3878 """locate files matching specific patterns (DEPRECATED)
3857 """locate files matching specific patterns (DEPRECATED)
3879
3858
3880 Print files under Mercurial control in the working directory whose
3859 Print files under Mercurial control in the working directory whose
3881 names match the given patterns.
3860 names match the given patterns.
3882
3861
3883 By default, this command searches all directories in the working
3862 By default, this command searches all directories in the working
3884 directory. To search just the current directory and its
3863 directory. To search just the current directory and its
3885 subdirectories, use "--include .".
3864 subdirectories, use "--include .".
3886
3865
3887 If no patterns are given to match, this command prints the names
3866 If no patterns are given to match, this command prints the names
3888 of all files under Mercurial control in the working directory.
3867 of all files under Mercurial control in the working directory.
3889
3868
3890 If you want to feed the output of this command into the "xargs"
3869 If you want to feed the output of this command into the "xargs"
3891 command, use the -0 option to both this command and "xargs". This
3870 command, use the -0 option to both this command and "xargs". This
3892 will avoid the problem of "xargs" treating single filenames that
3871 will avoid the problem of "xargs" treating single filenames that
3893 contain whitespace as multiple filenames.
3872 contain whitespace as multiple filenames.
3894
3873
3895 See :hg:`help files` for a more versatile command.
3874 See :hg:`help files` for a more versatile command.
3896
3875
3897 Returns 0 if a match is found, 1 otherwise.
3876 Returns 0 if a match is found, 1 otherwise.
3898 """
3877 """
3899 if opts.get('print0'):
3878 if opts.get('print0'):
3900 end = '\0'
3879 end = '\0'
3901 else:
3880 else:
3902 end = '\n'
3881 end = '\n'
3903 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3882 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3904
3883
3905 ret = 1
3884 ret = 1
3906 ctx = repo[rev]
3885 ctx = repo[rev]
3907 m = scmutil.match(ctx, pats, opts, default='relglob',
3886 m = scmutil.match(ctx, pats, opts, default='relglob',
3908 badfn=lambda x, y: False)
3887 badfn=lambda x, y: False)
3909
3888
3910 for abs in ctx.matches(m):
3889 for abs in ctx.matches(m):
3911 if opts.get('fullpath'):
3890 if opts.get('fullpath'):
3912 ui.write(repo.wjoin(abs), end)
3891 ui.write(repo.wjoin(abs), end)
3913 else:
3892 else:
3914 ui.write(((pats and m.rel(abs)) or abs), end)
3893 ui.write(((pats and m.rel(abs)) or abs), end)
3915 ret = 0
3894 ret = 0
3916
3895
3917 return ret
3896 return ret
3918
3897
3919 @command('^log|history',
3898 @command('^log|history',
3920 [('f', 'follow', None,
3899 [('f', 'follow', None,
3921 _('follow changeset history, or file history across copies and renames')),
3900 _('follow changeset history, or file history across copies and renames')),
3922 ('', 'follow-first', None,
3901 ('', 'follow-first', None,
3923 _('only follow the first parent of merge changesets (DEPRECATED)')),
3902 _('only follow the first parent of merge changesets (DEPRECATED)')),
3924 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3903 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3925 ('C', 'copies', None, _('show copied files')),
3904 ('C', 'copies', None, _('show copied files')),
3926 ('k', 'keyword', [],
3905 ('k', 'keyword', [],
3927 _('do case-insensitive search for a given text'), _('TEXT')),
3906 _('do case-insensitive search for a given text'), _('TEXT')),
3928 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3907 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3929 ('', 'removed', None, _('include revisions where files were removed')),
3908 ('', 'removed', None, _('include revisions where files were removed')),
3930 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3909 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3931 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3910 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3932 ('', 'only-branch', [],
3911 ('', 'only-branch', [],
3933 _('show only changesets within the given named branch (DEPRECATED)'),
3912 _('show only changesets within the given named branch (DEPRECATED)'),
3934 _('BRANCH')),
3913 _('BRANCH')),
3935 ('b', 'branch', [],
3914 ('b', 'branch', [],
3936 _('show changesets within the given named branch'), _('BRANCH')),
3915 _('show changesets within the given named branch'), _('BRANCH')),
3937 ('P', 'prune', [],
3916 ('P', 'prune', [],
3938 _('do not display revision or any of its ancestors'), _('REV')),
3917 _('do not display revision or any of its ancestors'), _('REV')),
3939 ] + logopts + walkopts,
3918 ] + logopts + walkopts,
3940 _('[OPTION]... [FILE]'),
3919 _('[OPTION]... [FILE]'),
3941 inferrepo=True)
3920 inferrepo=True)
3942 def log(ui, repo, *pats, **opts):
3921 def log(ui, repo, *pats, **opts):
3943 """show revision history of entire repository or files
3922 """show revision history of entire repository or files
3944
3923
3945 Print the revision history of the specified files or the entire
3924 Print the revision history of the specified files or the entire
3946 project.
3925 project.
3947
3926
3948 If no revision range is specified, the default is ``tip:0`` unless
3927 If no revision range is specified, the default is ``tip:0`` unless
3949 --follow is set, in which case the working directory parent is
3928 --follow is set, in which case the working directory parent is
3950 used as the starting revision.
3929 used as the starting revision.
3951
3930
3952 File history is shown without following rename or copy history of
3931 File history is shown without following rename or copy history of
3953 files. Use -f/--follow with a filename to follow history across
3932 files. Use -f/--follow with a filename to follow history across
3954 renames and copies. --follow without a filename will only show
3933 renames and copies. --follow without a filename will only show
3955 ancestors or descendants of the starting revision.
3934 ancestors or descendants of the starting revision.
3956
3935
3957 By default this command prints revision number and changeset id,
3936 By default this command prints revision number and changeset id,
3958 tags, non-trivial parents, user, date and time, and a summary for
3937 tags, non-trivial parents, user, date and time, and a summary for
3959 each commit. When the -v/--verbose switch is used, the list of
3938 each commit. When the -v/--verbose switch is used, the list of
3960 changed files and full commit message are shown.
3939 changed files and full commit message are shown.
3961
3940
3962 With --graph the revisions are shown as an ASCII art DAG with the most
3941 With --graph the revisions are shown as an ASCII art DAG with the most
3963 recent changeset at the top.
3942 recent changeset at the top.
3964 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3943 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3965 and '+' represents a fork where the changeset from the lines below is a
3944 and '+' represents a fork where the changeset from the lines below is a
3966 parent of the 'o' merge on the same line.
3945 parent of the 'o' merge on the same line.
3967
3946
3968 .. note::
3947 .. note::
3969
3948
3970 :hg:`log --patch` may generate unexpected diff output for merge
3949 :hg:`log --patch` may generate unexpected diff output for merge
3971 changesets, as it will only compare the merge changeset against
3950 changesets, as it will only compare the merge changeset against
3972 its first parent. Also, only files different from BOTH parents
3951 its first parent. Also, only files different from BOTH parents
3973 will appear in files:.
3952 will appear in files:.
3974
3953
3975 .. note::
3954 .. note::
3976
3955
3977 For performance reasons, :hg:`log FILE` may omit duplicate changes
3956 For performance reasons, :hg:`log FILE` may omit duplicate changes
3978 made on branches and will not show removals or mode changes. To
3957 made on branches and will not show removals or mode changes. To
3979 see all such changes, use the --removed switch.
3958 see all such changes, use the --removed switch.
3980
3959
3981 .. container:: verbose
3960 .. container:: verbose
3982
3961
3983 Some examples:
3962 Some examples:
3984
3963
3985 - changesets with full descriptions and file lists::
3964 - changesets with full descriptions and file lists::
3986
3965
3987 hg log -v
3966 hg log -v
3988
3967
3989 - changesets ancestral to the working directory::
3968 - changesets ancestral to the working directory::
3990
3969
3991 hg log -f
3970 hg log -f
3992
3971
3993 - last 10 commits on the current branch::
3972 - last 10 commits on the current branch::
3994
3973
3995 hg log -l 10 -b .
3974 hg log -l 10 -b .
3996
3975
3997 - changesets showing all modifications of a file, including removals::
3976 - changesets showing all modifications of a file, including removals::
3998
3977
3999 hg log --removed file.c
3978 hg log --removed file.c
4000
3979
4001 - all changesets that touch a directory, with diffs, excluding merges::
3980 - all changesets that touch a directory, with diffs, excluding merges::
4002
3981
4003 hg log -Mp lib/
3982 hg log -Mp lib/
4004
3983
4005 - all revision numbers that match a keyword::
3984 - all revision numbers that match a keyword::
4006
3985
4007 hg log -k bug --template "{rev}\\n"
3986 hg log -k bug --template "{rev}\\n"
4008
3987
4009 - the full hash identifier of the working directory parent::
3988 - the full hash identifier of the working directory parent::
4010
3989
4011 hg log -r . --template "{node}\\n"
3990 hg log -r . --template "{node}\\n"
4012
3991
4013 - list available log templates::
3992 - list available log templates::
4014
3993
4015 hg log -T list
3994 hg log -T list
4016
3995
4017 - check if a given changeset is included in a tagged release::
3996 - check if a given changeset is included in a tagged release::
4018
3997
4019 hg log -r "a21ccf and ancestor(1.9)"
3998 hg log -r "a21ccf and ancestor(1.9)"
4020
3999
4021 - find all changesets by some user in a date range::
4000 - find all changesets by some user in a date range::
4022
4001
4023 hg log -k alice -d "may 2008 to jul 2008"
4002 hg log -k alice -d "may 2008 to jul 2008"
4024
4003
4025 - summary of all changesets after the last tag::
4004 - summary of all changesets after the last tag::
4026
4005
4027 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4006 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4028
4007
4029 See :hg:`help dates` for a list of formats valid for -d/--date.
4008 See :hg:`help dates` for a list of formats valid for -d/--date.
4030
4009
4031 See :hg:`help revisions` for more about specifying and ordering
4010 See :hg:`help revisions` for more about specifying and ordering
4032 revisions.
4011 revisions.
4033
4012
4034 See :hg:`help templates` for more about pre-packaged styles and
4013 See :hg:`help templates` for more about pre-packaged styles and
4035 specifying custom templates.
4014 specifying custom templates.
4036
4015
4037 Returns 0 on success.
4016 Returns 0 on success.
4038
4017
4039 """
4018 """
4040 if opts.get('follow') and opts.get('rev'):
4019 if opts.get('follow') and opts.get('rev'):
4041 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4020 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4042 del opts['follow']
4021 del opts['follow']
4043
4022
4044 if opts.get('graph'):
4023 if opts.get('graph'):
4045 return cmdutil.graphlog(ui, repo, *pats, **opts)
4024 return cmdutil.graphlog(ui, repo, *pats, **opts)
4046
4025
4047 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4026 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4048 limit = cmdutil.loglimit(opts)
4027 limit = cmdutil.loglimit(opts)
4049 count = 0
4028 count = 0
4050
4029
4051 getrenamed = None
4030 getrenamed = None
4052 if opts.get('copies'):
4031 if opts.get('copies'):
4053 endrev = None
4032 endrev = None
4054 if opts.get('rev'):
4033 if opts.get('rev'):
4055 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4034 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4056 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4035 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4057
4036
4058 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4037 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4059 for rev in revs:
4038 for rev in revs:
4060 if count == limit:
4039 if count == limit:
4061 break
4040 break
4062 ctx = repo[rev]
4041 ctx = repo[rev]
4063 copies = None
4042 copies = None
4064 if getrenamed is not None and rev:
4043 if getrenamed is not None and rev:
4065 copies = []
4044 copies = []
4066 for fn in ctx.files():
4045 for fn in ctx.files():
4067 rename = getrenamed(fn, rev)
4046 rename = getrenamed(fn, rev)
4068 if rename:
4047 if rename:
4069 copies.append((fn, rename[0]))
4048 copies.append((fn, rename[0]))
4070 if filematcher:
4049 if filematcher:
4071 revmatchfn = filematcher(ctx.rev())
4050 revmatchfn = filematcher(ctx.rev())
4072 else:
4051 else:
4073 revmatchfn = None
4052 revmatchfn = None
4074 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4053 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4075 if displayer.flush(ctx):
4054 if displayer.flush(ctx):
4076 count += 1
4055 count += 1
4077
4056
4078 displayer.close()
4057 displayer.close()
4079
4058
4080 @command('manifest',
4059 @command('manifest',
4081 [('r', 'rev', '', _('revision to display'), _('REV')),
4060 [('r', 'rev', '', _('revision to display'), _('REV')),
4082 ('', 'all', False, _("list files from all revisions"))]
4061 ('', 'all', False, _("list files from all revisions"))]
4083 + formatteropts,
4062 + formatteropts,
4084 _('[-r REV]'))
4063 _('[-r REV]'))
4085 def manifest(ui, repo, node=None, rev=None, **opts):
4064 def manifest(ui, repo, node=None, rev=None, **opts):
4086 """output the current or given revision of the project manifest
4065 """output the current or given revision of the project manifest
4087
4066
4088 Print a list of version controlled files for the given revision.
4067 Print a list of version controlled files for the given revision.
4089 If no revision is given, the first parent of the working directory
4068 If no revision is given, the first parent of the working directory
4090 is used, or the null revision if no revision is checked out.
4069 is used, or the null revision if no revision is checked out.
4091
4070
4092 With -v, print file permissions, symlink and executable bits.
4071 With -v, print file permissions, symlink and executable bits.
4093 With --debug, print file revision hashes.
4072 With --debug, print file revision hashes.
4094
4073
4095 If option --all is specified, the list of all files from all revisions
4074 If option --all is specified, the list of all files from all revisions
4096 is printed. This includes deleted and renamed files.
4075 is printed. This includes deleted and renamed files.
4097
4076
4098 Returns 0 on success.
4077 Returns 0 on success.
4099 """
4078 """
4100
4079
4101 fm = ui.formatter('manifest', opts)
4080 fm = ui.formatter('manifest', opts)
4102
4081
4103 if opts.get('all'):
4082 if opts.get('all'):
4104 if rev or node:
4083 if rev or node:
4105 raise error.Abort(_("can't specify a revision with --all"))
4084 raise error.Abort(_("can't specify a revision with --all"))
4106
4085
4107 res = []
4086 res = []
4108 prefix = "data/"
4087 prefix = "data/"
4109 suffix = ".i"
4088 suffix = ".i"
4110 plen = len(prefix)
4089 plen = len(prefix)
4111 slen = len(suffix)
4090 slen = len(suffix)
4112 with repo.lock():
4091 with repo.lock():
4113 for fn, b, size in repo.store.datafiles():
4092 for fn, b, size in repo.store.datafiles():
4114 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4093 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4115 res.append(fn[plen:-slen])
4094 res.append(fn[plen:-slen])
4116 for f in res:
4095 for f in res:
4117 fm.startitem()
4096 fm.startitem()
4118 fm.write("path", '%s\n', f)
4097 fm.write("path", '%s\n', f)
4119 fm.end()
4098 fm.end()
4120 return
4099 return
4121
4100
4122 if rev and node:
4101 if rev and node:
4123 raise error.Abort(_("please specify just one revision"))
4102 raise error.Abort(_("please specify just one revision"))
4124
4103
4125 if not node:
4104 if not node:
4126 node = rev
4105 node = rev
4127
4106
4128 char = {'l': '@', 'x': '*', '': ''}
4107 char = {'l': '@', 'x': '*', '': ''}
4129 mode = {'l': '644', 'x': '755', '': '644'}
4108 mode = {'l': '644', 'x': '755', '': '644'}
4130 ctx = scmutil.revsingle(repo, node)
4109 ctx = scmutil.revsingle(repo, node)
4131 mf = ctx.manifest()
4110 mf = ctx.manifest()
4132 for f in ctx:
4111 for f in ctx:
4133 fm.startitem()
4112 fm.startitem()
4134 fl = ctx[f].flags()
4113 fl = ctx[f].flags()
4135 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4114 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4136 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4115 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4137 fm.write('path', '%s\n', f)
4116 fm.write('path', '%s\n', f)
4138 fm.end()
4117 fm.end()
4139
4118
4140 @command('^merge',
4119 @command('^merge',
4141 [('f', 'force', None,
4120 [('f', 'force', None,
4142 _('force a merge including outstanding changes (DEPRECATED)')),
4121 _('force a merge including outstanding changes (DEPRECATED)')),
4143 ('r', 'rev', '', _('revision to merge'), _('REV')),
4122 ('r', 'rev', '', _('revision to merge'), _('REV')),
4144 ('P', 'preview', None,
4123 ('P', 'preview', None,
4145 _('review revisions to merge (no merge is performed)'))
4124 _('review revisions to merge (no merge is performed)'))
4146 ] + mergetoolopts,
4125 ] + mergetoolopts,
4147 _('[-P] [[-r] REV]'))
4126 _('[-P] [[-r] REV]'))
4148 def merge(ui, repo, node=None, **opts):
4127 def merge(ui, repo, node=None, **opts):
4149 """merge another revision into working directory
4128 """merge another revision into working directory
4150
4129
4151 The current working directory is updated with all changes made in
4130 The current working directory is updated with all changes made in
4152 the requested revision since the last common predecessor revision.
4131 the requested revision since the last common predecessor revision.
4153
4132
4154 Files that changed between either parent are marked as changed for
4133 Files that changed between either parent are marked as changed for
4155 the next commit and a commit must be performed before any further
4134 the next commit and a commit must be performed before any further
4156 updates to the repository are allowed. The next commit will have
4135 updates to the repository are allowed. The next commit will have
4157 two parents.
4136 two parents.
4158
4137
4159 ``--tool`` can be used to specify the merge tool used for file
4138 ``--tool`` can be used to specify the merge tool used for file
4160 merges. It overrides the HGMERGE environment variable and your
4139 merges. It overrides the HGMERGE environment variable and your
4161 configuration files. See :hg:`help merge-tools` for options.
4140 configuration files. See :hg:`help merge-tools` for options.
4162
4141
4163 If no revision is specified, the working directory's parent is a
4142 If no revision is specified, the working directory's parent is a
4164 head revision, and the current branch contains exactly one other
4143 head revision, and the current branch contains exactly one other
4165 head, the other head is merged with by default. Otherwise, an
4144 head, the other head is merged with by default. Otherwise, an
4166 explicit revision with which to merge with must be provided.
4145 explicit revision with which to merge with must be provided.
4167
4146
4168 See :hg:`help resolve` for information on handling file conflicts.
4147 See :hg:`help resolve` for information on handling file conflicts.
4169
4148
4170 To undo an uncommitted merge, use :hg:`update --clean .` which
4149 To undo an uncommitted merge, use :hg:`update --clean .` which
4171 will check out a clean copy of the original merge parent, losing
4150 will check out a clean copy of the original merge parent, losing
4172 all changes.
4151 all changes.
4173
4152
4174 Returns 0 on success, 1 if there are unresolved files.
4153 Returns 0 on success, 1 if there are unresolved files.
4175 """
4154 """
4176
4155
4177 if opts.get('rev') and node:
4156 if opts.get('rev') and node:
4178 raise error.Abort(_("please specify just one revision"))
4157 raise error.Abort(_("please specify just one revision"))
4179 if not node:
4158 if not node:
4180 node = opts.get('rev')
4159 node = opts.get('rev')
4181
4160
4182 if node:
4161 if node:
4183 node = scmutil.revsingle(repo, node).node()
4162 node = scmutil.revsingle(repo, node).node()
4184
4163
4185 if not node:
4164 if not node:
4186 node = repo[destutil.destmerge(repo)].node()
4165 node = repo[destutil.destmerge(repo)].node()
4187
4166
4188 if opts.get('preview'):
4167 if opts.get('preview'):
4189 # find nodes that are ancestors of p2 but not of p1
4168 # find nodes that are ancestors of p2 but not of p1
4190 p1 = repo.lookup('.')
4169 p1 = repo.lookup('.')
4191 p2 = repo.lookup(node)
4170 p2 = repo.lookup(node)
4192 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4171 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4193
4172
4194 displayer = cmdutil.show_changeset(ui, repo, opts)
4173 displayer = cmdutil.show_changeset(ui, repo, opts)
4195 for node in nodes:
4174 for node in nodes:
4196 displayer.show(repo[node])
4175 displayer.show(repo[node])
4197 displayer.close()
4176 displayer.close()
4198 return 0
4177 return 0
4199
4178
4200 try:
4179 try:
4201 # ui.forcemerge is an internal variable, do not document
4180 # ui.forcemerge is an internal variable, do not document
4202 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4181 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4203 force = opts.get('force')
4182 force = opts.get('force')
4204 labels = ['working copy', 'merge rev']
4183 labels = ['working copy', 'merge rev']
4205 return hg.merge(repo, node, force=force, mergeforce=force,
4184 return hg.merge(repo, node, force=force, mergeforce=force,
4206 labels=labels)
4185 labels=labels)
4207 finally:
4186 finally:
4208 ui.setconfig('ui', 'forcemerge', '', 'merge')
4187 ui.setconfig('ui', 'forcemerge', '', 'merge')
4209
4188
4210 @command('outgoing|out',
4189 @command('outgoing|out',
4211 [('f', 'force', None, _('run even when the destination is unrelated')),
4190 [('f', 'force', None, _('run even when the destination is unrelated')),
4212 ('r', 'rev', [],
4191 ('r', 'rev', [],
4213 _('a changeset intended to be included in the destination'), _('REV')),
4192 _('a changeset intended to be included in the destination'), _('REV')),
4214 ('n', 'newest-first', None, _('show newest record first')),
4193 ('n', 'newest-first', None, _('show newest record first')),
4215 ('B', 'bookmarks', False, _('compare bookmarks')),
4194 ('B', 'bookmarks', False, _('compare bookmarks')),
4216 ('b', 'branch', [], _('a specific branch you would like to push'),
4195 ('b', 'branch', [], _('a specific branch you would like to push'),
4217 _('BRANCH')),
4196 _('BRANCH')),
4218 ] + logopts + remoteopts + subrepoopts,
4197 ] + logopts + remoteopts + subrepoopts,
4219 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4198 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4220 def outgoing(ui, repo, dest=None, **opts):
4199 def outgoing(ui, repo, dest=None, **opts):
4221 """show changesets not found in the destination
4200 """show changesets not found in the destination
4222
4201
4223 Show changesets not found in the specified destination repository
4202 Show changesets not found in the specified destination repository
4224 or the default push location. These are the changesets that would
4203 or the default push location. These are the changesets that would
4225 be pushed if a push was requested.
4204 be pushed if a push was requested.
4226
4205
4227 See pull for details of valid destination formats.
4206 See pull for details of valid destination formats.
4228
4207
4229 .. container:: verbose
4208 .. container:: verbose
4230
4209
4231 With -B/--bookmarks, the result of bookmark comparison between
4210 With -B/--bookmarks, the result of bookmark comparison between
4232 local and remote repositories is displayed. With -v/--verbose,
4211 local and remote repositories is displayed. With -v/--verbose,
4233 status is also displayed for each bookmark like below::
4212 status is also displayed for each bookmark like below::
4234
4213
4235 BM1 01234567890a added
4214 BM1 01234567890a added
4236 BM2 deleted
4215 BM2 deleted
4237 BM3 234567890abc advanced
4216 BM3 234567890abc advanced
4238 BM4 34567890abcd diverged
4217 BM4 34567890abcd diverged
4239 BM5 4567890abcde changed
4218 BM5 4567890abcde changed
4240
4219
4241 The action taken when pushing depends on the
4220 The action taken when pushing depends on the
4242 status of each bookmark:
4221 status of each bookmark:
4243
4222
4244 :``added``: push with ``-B`` will create it
4223 :``added``: push with ``-B`` will create it
4245 :``deleted``: push with ``-B`` will delete it
4224 :``deleted``: push with ``-B`` will delete it
4246 :``advanced``: push will update it
4225 :``advanced``: push will update it
4247 :``diverged``: push with ``-B`` will update it
4226 :``diverged``: push with ``-B`` will update it
4248 :``changed``: push with ``-B`` will update it
4227 :``changed``: push with ``-B`` will update it
4249
4228
4250 From the point of view of pushing behavior, bookmarks
4229 From the point of view of pushing behavior, bookmarks
4251 existing only in the remote repository are treated as
4230 existing only in the remote repository are treated as
4252 ``deleted``, even if it is in fact added remotely.
4231 ``deleted``, even if it is in fact added remotely.
4253
4232
4254 Returns 0 if there are outgoing changes, 1 otherwise.
4233 Returns 0 if there are outgoing changes, 1 otherwise.
4255 """
4234 """
4256 if opts.get('graph'):
4235 if opts.get('graph'):
4257 cmdutil.checkunsupportedgraphflags([], opts)
4236 cmdutil.checkunsupportedgraphflags([], opts)
4258 o, other = hg._outgoing(ui, repo, dest, opts)
4237 o, other = hg._outgoing(ui, repo, dest, opts)
4259 if not o:
4238 if not o:
4260 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4239 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4261 return
4240 return
4262
4241
4263 revdag = cmdutil.graphrevs(repo, o, opts)
4242 revdag = cmdutil.graphrevs(repo, o, opts)
4264 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4243 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4265 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4244 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4266 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4245 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4267 return 0
4246 return 0
4268
4247
4269 if opts.get('bookmarks'):
4248 if opts.get('bookmarks'):
4270 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4249 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4271 dest, branches = hg.parseurl(dest, opts.get('branch'))
4250 dest, branches = hg.parseurl(dest, opts.get('branch'))
4272 other = hg.peer(repo, opts, dest)
4251 other = hg.peer(repo, opts, dest)
4273 if 'bookmarks' not in other.listkeys('namespaces'):
4252 if 'bookmarks' not in other.listkeys('namespaces'):
4274 ui.warn(_("remote doesn't support bookmarks\n"))
4253 ui.warn(_("remote doesn't support bookmarks\n"))
4275 return 0
4254 return 0
4276 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4255 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4277 return bookmarks.outgoing(ui, repo, other)
4256 return bookmarks.outgoing(ui, repo, other)
4278
4257
4279 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4258 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4280 try:
4259 try:
4281 return hg.outgoing(ui, repo, dest, opts)
4260 return hg.outgoing(ui, repo, dest, opts)
4282 finally:
4261 finally:
4283 del repo._subtoppath
4262 del repo._subtoppath
4284
4263
4285 @command('parents',
4264 @command('parents',
4286 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4265 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4287 ] + templateopts,
4266 ] + templateopts,
4288 _('[-r REV] [FILE]'),
4267 _('[-r REV] [FILE]'),
4289 inferrepo=True)
4268 inferrepo=True)
4290 def parents(ui, repo, file_=None, **opts):
4269 def parents(ui, repo, file_=None, **opts):
4291 """show the parents of the working directory or revision (DEPRECATED)
4270 """show the parents of the working directory or revision (DEPRECATED)
4292
4271
4293 Print the working directory's parent revisions. If a revision is
4272 Print the working directory's parent revisions. If a revision is
4294 given via -r/--rev, the parent of that revision will be printed.
4273 given via -r/--rev, the parent of that revision will be printed.
4295 If a file argument is given, the revision in which the file was
4274 If a file argument is given, the revision in which the file was
4296 last changed (before the working directory revision or the
4275 last changed (before the working directory revision or the
4297 argument to --rev if given) is printed.
4276 argument to --rev if given) is printed.
4298
4277
4299 This command is equivalent to::
4278 This command is equivalent to::
4300
4279
4301 hg log -r "p1()+p2()" or
4280 hg log -r "p1()+p2()" or
4302 hg log -r "p1(REV)+p2(REV)" or
4281 hg log -r "p1(REV)+p2(REV)" or
4303 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4282 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4304 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4283 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4305
4284
4306 See :hg:`summary` and :hg:`help revsets` for related information.
4285 See :hg:`summary` and :hg:`help revsets` for related information.
4307
4286
4308 Returns 0 on success.
4287 Returns 0 on success.
4309 """
4288 """
4310
4289
4311 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4290 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4312
4291
4313 if file_:
4292 if file_:
4314 m = scmutil.match(ctx, (file_,), opts)
4293 m = scmutil.match(ctx, (file_,), opts)
4315 if m.anypats() or len(m.files()) != 1:
4294 if m.anypats() or len(m.files()) != 1:
4316 raise error.Abort(_('can only specify an explicit filename'))
4295 raise error.Abort(_('can only specify an explicit filename'))
4317 file_ = m.files()[0]
4296 file_ = m.files()[0]
4318 filenodes = []
4297 filenodes = []
4319 for cp in ctx.parents():
4298 for cp in ctx.parents():
4320 if not cp:
4299 if not cp:
4321 continue
4300 continue
4322 try:
4301 try:
4323 filenodes.append(cp.filenode(file_))
4302 filenodes.append(cp.filenode(file_))
4324 except error.LookupError:
4303 except error.LookupError:
4325 pass
4304 pass
4326 if not filenodes:
4305 if not filenodes:
4327 raise error.Abort(_("'%s' not found in manifest!") % file_)
4306 raise error.Abort(_("'%s' not found in manifest!") % file_)
4328 p = []
4307 p = []
4329 for fn in filenodes:
4308 for fn in filenodes:
4330 fctx = repo.filectx(file_, fileid=fn)
4309 fctx = repo.filectx(file_, fileid=fn)
4331 p.append(fctx.node())
4310 p.append(fctx.node())
4332 else:
4311 else:
4333 p = [cp.node() for cp in ctx.parents()]
4312 p = [cp.node() for cp in ctx.parents()]
4334
4313
4335 displayer = cmdutil.show_changeset(ui, repo, opts)
4314 displayer = cmdutil.show_changeset(ui, repo, opts)
4336 for n in p:
4315 for n in p:
4337 if n != nullid:
4316 if n != nullid:
4338 displayer.show(repo[n])
4317 displayer.show(repo[n])
4339 displayer.close()
4318 displayer.close()
4340
4319
4341 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4320 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4342 def paths(ui, repo, search=None, **opts):
4321 def paths(ui, repo, search=None, **opts):
4343 """show aliases for remote repositories
4322 """show aliases for remote repositories
4344
4323
4345 Show definition of symbolic path name NAME. If no name is given,
4324 Show definition of symbolic path name NAME. If no name is given,
4346 show definition of all available names.
4325 show definition of all available names.
4347
4326
4348 Option -q/--quiet suppresses all output when searching for NAME
4327 Option -q/--quiet suppresses all output when searching for NAME
4349 and shows only the path names when listing all definitions.
4328 and shows only the path names when listing all definitions.
4350
4329
4351 Path names are defined in the [paths] section of your
4330 Path names are defined in the [paths] section of your
4352 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4331 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4353 repository, ``.hg/hgrc`` is used, too.
4332 repository, ``.hg/hgrc`` is used, too.
4354
4333
4355 The path names ``default`` and ``default-push`` have a special
4334 The path names ``default`` and ``default-push`` have a special
4356 meaning. When performing a push or pull operation, they are used
4335 meaning. When performing a push or pull operation, they are used
4357 as fallbacks if no location is specified on the command-line.
4336 as fallbacks if no location is specified on the command-line.
4358 When ``default-push`` is set, it will be used for push and
4337 When ``default-push`` is set, it will be used for push and
4359 ``default`` will be used for pull; otherwise ``default`` is used
4338 ``default`` will be used for pull; otherwise ``default`` is used
4360 as the fallback for both. When cloning a repository, the clone
4339 as the fallback for both. When cloning a repository, the clone
4361 source is written as ``default`` in ``.hg/hgrc``.
4340 source is written as ``default`` in ``.hg/hgrc``.
4362
4341
4363 .. note::
4342 .. note::
4364
4343
4365 ``default`` and ``default-push`` apply to all inbound (e.g.
4344 ``default`` and ``default-push`` apply to all inbound (e.g.
4366 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4345 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4367 and :hg:`bundle`) operations.
4346 and :hg:`bundle`) operations.
4368
4347
4369 See :hg:`help urls` for more information.
4348 See :hg:`help urls` for more information.
4370
4349
4371 Returns 0 on success.
4350 Returns 0 on success.
4372 """
4351 """
4373 if search:
4352 if search:
4374 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4353 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4375 if name == search]
4354 if name == search]
4376 else:
4355 else:
4377 pathitems = sorted(ui.paths.iteritems())
4356 pathitems = sorted(ui.paths.iteritems())
4378
4357
4379 fm = ui.formatter('paths', opts)
4358 fm = ui.formatter('paths', opts)
4380 if fm.isplain():
4359 if fm.isplain():
4381 hidepassword = util.hidepassword
4360 hidepassword = util.hidepassword
4382 else:
4361 else:
4383 hidepassword = str
4362 hidepassword = str
4384 if ui.quiet:
4363 if ui.quiet:
4385 namefmt = '%s\n'
4364 namefmt = '%s\n'
4386 else:
4365 else:
4387 namefmt = '%s = '
4366 namefmt = '%s = '
4388 showsubopts = not search and not ui.quiet
4367 showsubopts = not search and not ui.quiet
4389
4368
4390 for name, path in pathitems:
4369 for name, path in pathitems:
4391 fm.startitem()
4370 fm.startitem()
4392 fm.condwrite(not search, 'name', namefmt, name)
4371 fm.condwrite(not search, 'name', namefmt, name)
4393 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4372 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4394 for subopt, value in sorted(path.suboptions.items()):
4373 for subopt, value in sorted(path.suboptions.items()):
4395 assert subopt not in ('name', 'url')
4374 assert subopt not in ('name', 'url')
4396 if showsubopts:
4375 if showsubopts:
4397 fm.plain('%s:%s = ' % (name, subopt))
4376 fm.plain('%s:%s = ' % (name, subopt))
4398 fm.condwrite(showsubopts, subopt, '%s\n', value)
4377 fm.condwrite(showsubopts, subopt, '%s\n', value)
4399
4378
4400 fm.end()
4379 fm.end()
4401
4380
4402 if search and not pathitems:
4381 if search and not pathitems:
4403 if not ui.quiet:
4382 if not ui.quiet:
4404 ui.warn(_("not found!\n"))
4383 ui.warn(_("not found!\n"))
4405 return 1
4384 return 1
4406 else:
4385 else:
4407 return 0
4386 return 0
4408
4387
4409 @command('phase',
4388 @command('phase',
4410 [('p', 'public', False, _('set changeset phase to public')),
4389 [('p', 'public', False, _('set changeset phase to public')),
4411 ('d', 'draft', False, _('set changeset phase to draft')),
4390 ('d', 'draft', False, _('set changeset phase to draft')),
4412 ('s', 'secret', False, _('set changeset phase to secret')),
4391 ('s', 'secret', False, _('set changeset phase to secret')),
4413 ('f', 'force', False, _('allow to move boundary backward')),
4392 ('f', 'force', False, _('allow to move boundary backward')),
4414 ('r', 'rev', [], _('target revision'), _('REV')),
4393 ('r', 'rev', [], _('target revision'), _('REV')),
4415 ],
4394 ],
4416 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4395 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4417 def phase(ui, repo, *revs, **opts):
4396 def phase(ui, repo, *revs, **opts):
4418 """set or show the current phase name
4397 """set or show the current phase name
4419
4398
4420 With no argument, show the phase name of the current revision(s).
4399 With no argument, show the phase name of the current revision(s).
4421
4400
4422 With one of -p/--public, -d/--draft or -s/--secret, change the
4401 With one of -p/--public, -d/--draft or -s/--secret, change the
4423 phase value of the specified revisions.
4402 phase value of the specified revisions.
4424
4403
4425 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4404 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4426 lower phase to an higher phase. Phases are ordered as follows::
4405 lower phase to an higher phase. Phases are ordered as follows::
4427
4406
4428 public < draft < secret
4407 public < draft < secret
4429
4408
4430 Returns 0 on success, 1 if some phases could not be changed.
4409 Returns 0 on success, 1 if some phases could not be changed.
4431
4410
4432 (For more information about the phases concept, see :hg:`help phases`.)
4411 (For more information about the phases concept, see :hg:`help phases`.)
4433 """
4412 """
4434 # search for a unique phase argument
4413 # search for a unique phase argument
4435 targetphase = None
4414 targetphase = None
4436 for idx, name in enumerate(phases.phasenames):
4415 for idx, name in enumerate(phases.phasenames):
4437 if opts[name]:
4416 if opts[name]:
4438 if targetphase is not None:
4417 if targetphase is not None:
4439 raise error.Abort(_('only one phase can be specified'))
4418 raise error.Abort(_('only one phase can be specified'))
4440 targetphase = idx
4419 targetphase = idx
4441
4420
4442 # look for specified revision
4421 # look for specified revision
4443 revs = list(revs)
4422 revs = list(revs)
4444 revs.extend(opts['rev'])
4423 revs.extend(opts['rev'])
4445 if not revs:
4424 if not revs:
4446 # display both parents as the second parent phase can influence
4425 # display both parents as the second parent phase can influence
4447 # the phase of a merge commit
4426 # the phase of a merge commit
4448 revs = [c.rev() for c in repo[None].parents()]
4427 revs = [c.rev() for c in repo[None].parents()]
4449
4428
4450 revs = scmutil.revrange(repo, revs)
4429 revs = scmutil.revrange(repo, revs)
4451
4430
4452 lock = None
4431 lock = None
4453 ret = 0
4432 ret = 0
4454 if targetphase is None:
4433 if targetphase is None:
4455 # display
4434 # display
4456 for r in revs:
4435 for r in revs:
4457 ctx = repo[r]
4436 ctx = repo[r]
4458 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4437 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4459 else:
4438 else:
4460 tr = None
4439 tr = None
4461 lock = repo.lock()
4440 lock = repo.lock()
4462 try:
4441 try:
4463 tr = repo.transaction("phase")
4442 tr = repo.transaction("phase")
4464 # set phase
4443 # set phase
4465 if not revs:
4444 if not revs:
4466 raise error.Abort(_('empty revision set'))
4445 raise error.Abort(_('empty revision set'))
4467 nodes = [repo[r].node() for r in revs]
4446 nodes = [repo[r].node() for r in revs]
4468 # moving revision from public to draft may hide them
4447 # moving revision from public to draft may hide them
4469 # We have to check result on an unfiltered repository
4448 # We have to check result on an unfiltered repository
4470 unfi = repo.unfiltered()
4449 unfi = repo.unfiltered()
4471 getphase = unfi._phasecache.phase
4450 getphase = unfi._phasecache.phase
4472 olddata = [getphase(unfi, r) for r in unfi]
4451 olddata = [getphase(unfi, r) for r in unfi]
4473 phases.advanceboundary(repo, tr, targetphase, nodes)
4452 phases.advanceboundary(repo, tr, targetphase, nodes)
4474 if opts['force']:
4453 if opts['force']:
4475 phases.retractboundary(repo, tr, targetphase, nodes)
4454 phases.retractboundary(repo, tr, targetphase, nodes)
4476 tr.close()
4455 tr.close()
4477 finally:
4456 finally:
4478 if tr is not None:
4457 if tr is not None:
4479 tr.release()
4458 tr.release()
4480 lock.release()
4459 lock.release()
4481 getphase = unfi._phasecache.phase
4460 getphase = unfi._phasecache.phase
4482 newdata = [getphase(unfi, r) for r in unfi]
4461 newdata = [getphase(unfi, r) for r in unfi]
4483 changes = sum(newdata[r] != olddata[r] for r in unfi)
4462 changes = sum(newdata[r] != olddata[r] for r in unfi)
4484 cl = unfi.changelog
4463 cl = unfi.changelog
4485 rejected = [n for n in nodes
4464 rejected = [n for n in nodes
4486 if newdata[cl.rev(n)] < targetphase]
4465 if newdata[cl.rev(n)] < targetphase]
4487 if rejected:
4466 if rejected:
4488 ui.warn(_('cannot move %i changesets to a higher '
4467 ui.warn(_('cannot move %i changesets to a higher '
4489 'phase, use --force\n') % len(rejected))
4468 'phase, use --force\n') % len(rejected))
4490 ret = 1
4469 ret = 1
4491 if changes:
4470 if changes:
4492 msg = _('phase changed for %i changesets\n') % changes
4471 msg = _('phase changed for %i changesets\n') % changes
4493 if ret:
4472 if ret:
4494 ui.status(msg)
4473 ui.status(msg)
4495 else:
4474 else:
4496 ui.note(msg)
4475 ui.note(msg)
4497 else:
4476 else:
4498 ui.warn(_('no phases changed\n'))
4477 ui.warn(_('no phases changed\n'))
4499 return ret
4478 return ret
4500
4479
4501 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4480 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4502 """Run after a changegroup has been added via pull/unbundle
4481 """Run after a changegroup has been added via pull/unbundle
4503
4482
4504 This takes arguments below:
4483 This takes arguments below:
4505
4484
4506 :modheads: change of heads by pull/unbundle
4485 :modheads: change of heads by pull/unbundle
4507 :optupdate: updating working directory is needed or not
4486 :optupdate: updating working directory is needed or not
4508 :checkout: update destination revision (or None to default destination)
4487 :checkout: update destination revision (or None to default destination)
4509 :brev: a name, which might be a bookmark to be activated after updating
4488 :brev: a name, which might be a bookmark to be activated after updating
4510 """
4489 """
4511 if modheads == 0:
4490 if modheads == 0:
4512 return
4491 return
4513 if optupdate:
4492 if optupdate:
4514 try:
4493 try:
4515 return hg.updatetotally(ui, repo, checkout, brev)
4494 return hg.updatetotally(ui, repo, checkout, brev)
4516 except error.UpdateAbort as inst:
4495 except error.UpdateAbort as inst:
4517 msg = _("not updating: %s") % str(inst)
4496 msg = _("not updating: %s") % str(inst)
4518 hint = inst.hint
4497 hint = inst.hint
4519 raise error.UpdateAbort(msg, hint=hint)
4498 raise error.UpdateAbort(msg, hint=hint)
4520 if modheads > 1:
4499 if modheads > 1:
4521 currentbranchheads = len(repo.branchheads())
4500 currentbranchheads = len(repo.branchheads())
4522 if currentbranchheads == modheads:
4501 if currentbranchheads == modheads:
4523 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4502 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4524 elif currentbranchheads > 1:
4503 elif currentbranchheads > 1:
4525 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4504 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4526 "merge)\n"))
4505 "merge)\n"))
4527 else:
4506 else:
4528 ui.status(_("(run 'hg heads' to see heads)\n"))
4507 ui.status(_("(run 'hg heads' to see heads)\n"))
4529 else:
4508 else:
4530 ui.status(_("(run 'hg update' to get a working copy)\n"))
4509 ui.status(_("(run 'hg update' to get a working copy)\n"))
4531
4510
4532 @command('^pull',
4511 @command('^pull',
4533 [('u', 'update', None,
4512 [('u', 'update', None,
4534 _('update to new branch head if changesets were pulled')),
4513 _('update to new branch head if changesets were pulled')),
4535 ('f', 'force', None, _('run even when remote repository is unrelated')),
4514 ('f', 'force', None, _('run even when remote repository is unrelated')),
4536 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4515 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4537 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4516 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4538 ('b', 'branch', [], _('a specific branch you would like to pull'),
4517 ('b', 'branch', [], _('a specific branch you would like to pull'),
4539 _('BRANCH')),
4518 _('BRANCH')),
4540 ] + remoteopts,
4519 ] + remoteopts,
4541 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4520 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4542 def pull(ui, repo, source="default", **opts):
4521 def pull(ui, repo, source="default", **opts):
4543 """pull changes from the specified source
4522 """pull changes from the specified source
4544
4523
4545 Pull changes from a remote repository to a local one.
4524 Pull changes from a remote repository to a local one.
4546
4525
4547 This finds all changes from the repository at the specified path
4526 This finds all changes from the repository at the specified path
4548 or URL and adds them to a local repository (the current one unless
4527 or URL and adds them to a local repository (the current one unless
4549 -R is specified). By default, this does not update the copy of the
4528 -R is specified). By default, this does not update the copy of the
4550 project in the working directory.
4529 project in the working directory.
4551
4530
4552 Use :hg:`incoming` if you want to see what would have been added
4531 Use :hg:`incoming` if you want to see what would have been added
4553 by a pull at the time you issued this command. If you then decide
4532 by a pull at the time you issued this command. If you then decide
4554 to add those changes to the repository, you should use :hg:`pull
4533 to add those changes to the repository, you should use :hg:`pull
4555 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4534 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4556
4535
4557 If SOURCE is omitted, the 'default' path will be used.
4536 If SOURCE is omitted, the 'default' path will be used.
4558 See :hg:`help urls` for more information.
4537 See :hg:`help urls` for more information.
4559
4538
4560 Specifying bookmark as ``.`` is equivalent to specifying the active
4539 Specifying bookmark as ``.`` is equivalent to specifying the active
4561 bookmark's name.
4540 bookmark's name.
4562
4541
4563 Returns 0 on success, 1 if an update had unresolved files.
4542 Returns 0 on success, 1 if an update had unresolved files.
4564 """
4543 """
4565 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4544 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4566 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4545 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4567 other = hg.peer(repo, opts, source)
4546 other = hg.peer(repo, opts, source)
4568 try:
4547 try:
4569 revs, checkout = hg.addbranchrevs(repo, other, branches,
4548 revs, checkout = hg.addbranchrevs(repo, other, branches,
4570 opts.get('rev'))
4549 opts.get('rev'))
4571
4550
4572
4551
4573 pullopargs = {}
4552 pullopargs = {}
4574 if opts.get('bookmark'):
4553 if opts.get('bookmark'):
4575 if not revs:
4554 if not revs:
4576 revs = []
4555 revs = []
4577 # The list of bookmark used here is not the one used to actually
4556 # The list of bookmark used here is not the one used to actually
4578 # update the bookmark name. This can result in the revision pulled
4557 # update the bookmark name. This can result in the revision pulled
4579 # not ending up with the name of the bookmark because of a race
4558 # not ending up with the name of the bookmark because of a race
4580 # condition on the server. (See issue 4689 for details)
4559 # condition on the server. (See issue 4689 for details)
4581 remotebookmarks = other.listkeys('bookmarks')
4560 remotebookmarks = other.listkeys('bookmarks')
4582 pullopargs['remotebookmarks'] = remotebookmarks
4561 pullopargs['remotebookmarks'] = remotebookmarks
4583 for b in opts['bookmark']:
4562 for b in opts['bookmark']:
4584 b = repo._bookmarks.expandname(b)
4563 b = repo._bookmarks.expandname(b)
4585 if b not in remotebookmarks:
4564 if b not in remotebookmarks:
4586 raise error.Abort(_('remote bookmark %s not found!') % b)
4565 raise error.Abort(_('remote bookmark %s not found!') % b)
4587 revs.append(remotebookmarks[b])
4566 revs.append(remotebookmarks[b])
4588
4567
4589 if revs:
4568 if revs:
4590 try:
4569 try:
4591 # When 'rev' is a bookmark name, we cannot guarantee that it
4570 # When 'rev' is a bookmark name, we cannot guarantee that it
4592 # will be updated with that name because of a race condition
4571 # will be updated with that name because of a race condition
4593 # server side. (See issue 4689 for details)
4572 # server side. (See issue 4689 for details)
4594 oldrevs = revs
4573 oldrevs = revs
4595 revs = [] # actually, nodes
4574 revs = [] # actually, nodes
4596 for r in oldrevs:
4575 for r in oldrevs:
4597 node = other.lookup(r)
4576 node = other.lookup(r)
4598 revs.append(node)
4577 revs.append(node)
4599 if r == checkout:
4578 if r == checkout:
4600 checkout = node
4579 checkout = node
4601 except error.CapabilityError:
4580 except error.CapabilityError:
4602 err = _("other repository doesn't support revision lookup, "
4581 err = _("other repository doesn't support revision lookup, "
4603 "so a rev cannot be specified.")
4582 "so a rev cannot be specified.")
4604 raise error.Abort(err)
4583 raise error.Abort(err)
4605
4584
4606 pullopargs.update(opts.get('opargs', {}))
4585 pullopargs.update(opts.get('opargs', {}))
4607 modheads = exchange.pull(repo, other, heads=revs,
4586 modheads = exchange.pull(repo, other, heads=revs,
4608 force=opts.get('force'),
4587 force=opts.get('force'),
4609 bookmarks=opts.get('bookmark', ()),
4588 bookmarks=opts.get('bookmark', ()),
4610 opargs=pullopargs).cgresult
4589 opargs=pullopargs).cgresult
4611
4590
4612 # brev is a name, which might be a bookmark to be activated at
4591 # brev is a name, which might be a bookmark to be activated at
4613 # the end of the update. In other words, it is an explicit
4592 # the end of the update. In other words, it is an explicit
4614 # destination of the update
4593 # destination of the update
4615 brev = None
4594 brev = None
4616
4595
4617 if checkout:
4596 if checkout:
4618 checkout = str(repo.changelog.rev(checkout))
4597 checkout = str(repo.changelog.rev(checkout))
4619
4598
4620 # order below depends on implementation of
4599 # order below depends on implementation of
4621 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4600 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4622 # because 'checkout' is determined without it.
4601 # because 'checkout' is determined without it.
4623 if opts.get('rev'):
4602 if opts.get('rev'):
4624 brev = opts['rev'][0]
4603 brev = opts['rev'][0]
4625 elif opts.get('branch'):
4604 elif opts.get('branch'):
4626 brev = opts['branch'][0]
4605 brev = opts['branch'][0]
4627 else:
4606 else:
4628 brev = branches[0]
4607 brev = branches[0]
4629 repo._subtoppath = source
4608 repo._subtoppath = source
4630 try:
4609 try:
4631 ret = postincoming(ui, repo, modheads, opts.get('update'),
4610 ret = postincoming(ui, repo, modheads, opts.get('update'),
4632 checkout, brev)
4611 checkout, brev)
4633
4612
4634 finally:
4613 finally:
4635 del repo._subtoppath
4614 del repo._subtoppath
4636
4615
4637 finally:
4616 finally:
4638 other.close()
4617 other.close()
4639 return ret
4618 return ret
4640
4619
4641 @command('^push',
4620 @command('^push',
4642 [('f', 'force', None, _('force push')),
4621 [('f', 'force', None, _('force push')),
4643 ('r', 'rev', [],
4622 ('r', 'rev', [],
4644 _('a changeset intended to be included in the destination'),
4623 _('a changeset intended to be included in the destination'),
4645 _('REV')),
4624 _('REV')),
4646 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4625 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4647 ('b', 'branch', [],
4626 ('b', 'branch', [],
4648 _('a specific branch you would like to push'), _('BRANCH')),
4627 _('a specific branch you would like to push'), _('BRANCH')),
4649 ('', 'new-branch', False, _('allow pushing a new branch')),
4628 ('', 'new-branch', False, _('allow pushing a new branch')),
4650 ] + remoteopts,
4629 ] + remoteopts,
4651 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4630 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4652 def push(ui, repo, dest=None, **opts):
4631 def push(ui, repo, dest=None, **opts):
4653 """push changes to the specified destination
4632 """push changes to the specified destination
4654
4633
4655 Push changesets from the local repository to the specified
4634 Push changesets from the local repository to the specified
4656 destination.
4635 destination.
4657
4636
4658 This operation is symmetrical to pull: it is identical to a pull
4637 This operation is symmetrical to pull: it is identical to a pull
4659 in the destination repository from the current one.
4638 in the destination repository from the current one.
4660
4639
4661 By default, push will not allow creation of new heads at the
4640 By default, push will not allow creation of new heads at the
4662 destination, since multiple heads would make it unclear which head
4641 destination, since multiple heads would make it unclear which head
4663 to use. In this situation, it is recommended to pull and merge
4642 to use. In this situation, it is recommended to pull and merge
4664 before pushing.
4643 before pushing.
4665
4644
4666 Use --new-branch if you want to allow push to create a new named
4645 Use --new-branch if you want to allow push to create a new named
4667 branch that is not present at the destination. This allows you to
4646 branch that is not present at the destination. This allows you to
4668 only create a new branch without forcing other changes.
4647 only create a new branch without forcing other changes.
4669
4648
4670 .. note::
4649 .. note::
4671
4650
4672 Extra care should be taken with the -f/--force option,
4651 Extra care should be taken with the -f/--force option,
4673 which will push all new heads on all branches, an action which will
4652 which will push all new heads on all branches, an action which will
4674 almost always cause confusion for collaborators.
4653 almost always cause confusion for collaborators.
4675
4654
4676 If -r/--rev is used, the specified revision and all its ancestors
4655 If -r/--rev is used, the specified revision and all its ancestors
4677 will be pushed to the remote repository.
4656 will be pushed to the remote repository.
4678
4657
4679 If -B/--bookmark is used, the specified bookmarked revision, its
4658 If -B/--bookmark is used, the specified bookmarked revision, its
4680 ancestors, and the bookmark will be pushed to the remote
4659 ancestors, and the bookmark will be pushed to the remote
4681 repository. Specifying ``.`` is equivalent to specifying the active
4660 repository. Specifying ``.`` is equivalent to specifying the active
4682 bookmark's name.
4661 bookmark's name.
4683
4662
4684 Please see :hg:`help urls` for important details about ``ssh://``
4663 Please see :hg:`help urls` for important details about ``ssh://``
4685 URLs. If DESTINATION is omitted, a default path will be used.
4664 URLs. If DESTINATION is omitted, a default path will be used.
4686
4665
4687 Returns 0 if push was successful, 1 if nothing to push.
4666 Returns 0 if push was successful, 1 if nothing to push.
4688 """
4667 """
4689
4668
4690 if opts.get('bookmark'):
4669 if opts.get('bookmark'):
4691 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4670 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4692 for b in opts['bookmark']:
4671 for b in opts['bookmark']:
4693 # translate -B options to -r so changesets get pushed
4672 # translate -B options to -r so changesets get pushed
4694 b = repo._bookmarks.expandname(b)
4673 b = repo._bookmarks.expandname(b)
4695 if b in repo._bookmarks:
4674 if b in repo._bookmarks:
4696 opts.setdefault('rev', []).append(b)
4675 opts.setdefault('rev', []).append(b)
4697 else:
4676 else:
4698 # if we try to push a deleted bookmark, translate it to null
4677 # if we try to push a deleted bookmark, translate it to null
4699 # this lets simultaneous -r, -b options continue working
4678 # this lets simultaneous -r, -b options continue working
4700 opts.setdefault('rev', []).append("null")
4679 opts.setdefault('rev', []).append("null")
4701
4680
4702 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4681 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4703 if not path:
4682 if not path:
4704 raise error.Abort(_('default repository not configured!'),
4683 raise error.Abort(_('default repository not configured!'),
4705 hint=_("see 'hg help config.paths'"))
4684 hint=_("see 'hg help config.paths'"))
4706 dest = path.pushloc or path.loc
4685 dest = path.pushloc or path.loc
4707 branches = (path.branch, opts.get('branch') or [])
4686 branches = (path.branch, opts.get('branch') or [])
4708 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4687 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4709 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4688 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4710 other = hg.peer(repo, opts, dest)
4689 other = hg.peer(repo, opts, dest)
4711
4690
4712 if revs:
4691 if revs:
4713 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4692 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4714 if not revs:
4693 if not revs:
4715 raise error.Abort(_("specified revisions evaluate to an empty set"),
4694 raise error.Abort(_("specified revisions evaluate to an empty set"),
4716 hint=_("use different revision arguments"))
4695 hint=_("use different revision arguments"))
4717 elif path.pushrev:
4696 elif path.pushrev:
4718 # It doesn't make any sense to specify ancestor revisions. So limit
4697 # It doesn't make any sense to specify ancestor revisions. So limit
4719 # to DAG heads to make discovery simpler.
4698 # to DAG heads to make discovery simpler.
4720 expr = revset.formatspec('heads(%r)', path.pushrev)
4699 expr = revset.formatspec('heads(%r)', path.pushrev)
4721 revs = scmutil.revrange(repo, [expr])
4700 revs = scmutil.revrange(repo, [expr])
4722 revs = [repo[rev].node() for rev in revs]
4701 revs = [repo[rev].node() for rev in revs]
4723 if not revs:
4702 if not revs:
4724 raise error.Abort(_('default push revset for path evaluates to an '
4703 raise error.Abort(_('default push revset for path evaluates to an '
4725 'empty set'))
4704 'empty set'))
4726
4705
4727 repo._subtoppath = dest
4706 repo._subtoppath = dest
4728 try:
4707 try:
4729 # push subrepos depth-first for coherent ordering
4708 # push subrepos depth-first for coherent ordering
4730 c = repo['']
4709 c = repo['']
4731 subs = c.substate # only repos that are committed
4710 subs = c.substate # only repos that are committed
4732 for s in sorted(subs):
4711 for s in sorted(subs):
4733 result = c.sub(s).push(opts)
4712 result = c.sub(s).push(opts)
4734 if result == 0:
4713 if result == 0:
4735 return not result
4714 return not result
4736 finally:
4715 finally:
4737 del repo._subtoppath
4716 del repo._subtoppath
4738 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4717 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4739 newbranch=opts.get('new_branch'),
4718 newbranch=opts.get('new_branch'),
4740 bookmarks=opts.get('bookmark', ()),
4719 bookmarks=opts.get('bookmark', ()),
4741 opargs=opts.get('opargs'))
4720 opargs=opts.get('opargs'))
4742
4721
4743 result = not pushop.cgresult
4722 result = not pushop.cgresult
4744
4723
4745 if pushop.bkresult is not None:
4724 if pushop.bkresult is not None:
4746 if pushop.bkresult == 2:
4725 if pushop.bkresult == 2:
4747 result = 2
4726 result = 2
4748 elif not result and pushop.bkresult:
4727 elif not result and pushop.bkresult:
4749 result = 2
4728 result = 2
4750
4729
4751 return result
4730 return result
4752
4731
4753 @command('recover', [])
4732 @command('recover', [])
4754 def recover(ui, repo):
4733 def recover(ui, repo):
4755 """roll back an interrupted transaction
4734 """roll back an interrupted transaction
4756
4735
4757 Recover from an interrupted commit or pull.
4736 Recover from an interrupted commit or pull.
4758
4737
4759 This command tries to fix the repository status after an
4738 This command tries to fix the repository status after an
4760 interrupted operation. It should only be necessary when Mercurial
4739 interrupted operation. It should only be necessary when Mercurial
4761 suggests it.
4740 suggests it.
4762
4741
4763 Returns 0 if successful, 1 if nothing to recover or verify fails.
4742 Returns 0 if successful, 1 if nothing to recover or verify fails.
4764 """
4743 """
4765 if repo.recover():
4744 if repo.recover():
4766 return hg.verify(repo)
4745 return hg.verify(repo)
4767 return 1
4746 return 1
4768
4747
4769 @command('^remove|rm',
4748 @command('^remove|rm',
4770 [('A', 'after', None, _('record delete for missing files')),
4749 [('A', 'after', None, _('record delete for missing files')),
4771 ('f', 'force', None,
4750 ('f', 'force', None,
4772 _('forget added files, delete modified files')),
4751 _('forget added files, delete modified files')),
4773 ] + subrepoopts + walkopts,
4752 ] + subrepoopts + walkopts,
4774 _('[OPTION]... FILE...'),
4753 _('[OPTION]... FILE...'),
4775 inferrepo=True)
4754 inferrepo=True)
4776 def remove(ui, repo, *pats, **opts):
4755 def remove(ui, repo, *pats, **opts):
4777 """remove the specified files on the next commit
4756 """remove the specified files on the next commit
4778
4757
4779 Schedule the indicated files for removal from the current branch.
4758 Schedule the indicated files for removal from the current branch.
4780
4759
4781 This command schedules the files to be removed at the next commit.
4760 This command schedules the files to be removed at the next commit.
4782 To undo a remove before that, see :hg:`revert`. To undo added
4761 To undo a remove before that, see :hg:`revert`. To undo added
4783 files, see :hg:`forget`.
4762 files, see :hg:`forget`.
4784
4763
4785 .. container:: verbose
4764 .. container:: verbose
4786
4765
4787 -A/--after can be used to remove only files that have already
4766 -A/--after can be used to remove only files that have already
4788 been deleted, -f/--force can be used to force deletion, and -Af
4767 been deleted, -f/--force can be used to force deletion, and -Af
4789 can be used to remove files from the next revision without
4768 can be used to remove files from the next revision without
4790 deleting them from the working directory.
4769 deleting them from the working directory.
4791
4770
4792 The following table details the behavior of remove for different
4771 The following table details the behavior of remove for different
4793 file states (columns) and option combinations (rows). The file
4772 file states (columns) and option combinations (rows). The file
4794 states are Added [A], Clean [C], Modified [M] and Missing [!]
4773 states are Added [A], Clean [C], Modified [M] and Missing [!]
4795 (as reported by :hg:`status`). The actions are Warn, Remove
4774 (as reported by :hg:`status`). The actions are Warn, Remove
4796 (from branch) and Delete (from disk):
4775 (from branch) and Delete (from disk):
4797
4776
4798 ========= == == == ==
4777 ========= == == == ==
4799 opt/state A C M !
4778 opt/state A C M !
4800 ========= == == == ==
4779 ========= == == == ==
4801 none W RD W R
4780 none W RD W R
4802 -f R RD RD R
4781 -f R RD RD R
4803 -A W W W R
4782 -A W W W R
4804 -Af R R R R
4783 -Af R R R R
4805 ========= == == == ==
4784 ========= == == == ==
4806
4785
4807 .. note::
4786 .. note::
4808
4787
4809 :hg:`remove` never deletes files in Added [A] state from the
4788 :hg:`remove` never deletes files in Added [A] state from the
4810 working directory, not even if ``--force`` is specified.
4789 working directory, not even if ``--force`` is specified.
4811
4790
4812 Returns 0 on success, 1 if any warnings encountered.
4791 Returns 0 on success, 1 if any warnings encountered.
4813 """
4792 """
4814
4793
4815 after, force = opts.get('after'), opts.get('force')
4794 after, force = opts.get('after'), opts.get('force')
4816 if not pats and not after:
4795 if not pats and not after:
4817 raise error.Abort(_('no files specified'))
4796 raise error.Abort(_('no files specified'))
4818
4797
4819 m = scmutil.match(repo[None], pats, opts)
4798 m = scmutil.match(repo[None], pats, opts)
4820 subrepos = opts.get('subrepos')
4799 subrepos = opts.get('subrepos')
4821 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4800 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4822
4801
4823 @command('rename|move|mv',
4802 @command('rename|move|mv',
4824 [('A', 'after', None, _('record a rename that has already occurred')),
4803 [('A', 'after', None, _('record a rename that has already occurred')),
4825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4804 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4826 ] + walkopts + dryrunopts,
4805 ] + walkopts + dryrunopts,
4827 _('[OPTION]... SOURCE... DEST'))
4806 _('[OPTION]... SOURCE... DEST'))
4828 def rename(ui, repo, *pats, **opts):
4807 def rename(ui, repo, *pats, **opts):
4829 """rename files; equivalent of copy + remove
4808 """rename files; equivalent of copy + remove
4830
4809
4831 Mark dest as copies of sources; mark sources for deletion. If dest
4810 Mark dest as copies of sources; mark sources for deletion. If dest
4832 is a directory, copies are put in that directory. If dest is a
4811 is a directory, copies are put in that directory. If dest is a
4833 file, there can only be one source.
4812 file, there can only be one source.
4834
4813
4835 By default, this command copies the contents of files as they
4814 By default, this command copies the contents of files as they
4836 exist in the working directory. If invoked with -A/--after, the
4815 exist in the working directory. If invoked with -A/--after, the
4837 operation is recorded, but no copying is performed.
4816 operation is recorded, but no copying is performed.
4838
4817
4839 This command takes effect at the next commit. To undo a rename
4818 This command takes effect at the next commit. To undo a rename
4840 before that, see :hg:`revert`.
4819 before that, see :hg:`revert`.
4841
4820
4842 Returns 0 on success, 1 if errors are encountered.
4821 Returns 0 on success, 1 if errors are encountered.
4843 """
4822 """
4844 with repo.wlock(False):
4823 with repo.wlock(False):
4845 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4824 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4846
4825
4847 @command('resolve',
4826 @command('resolve',
4848 [('a', 'all', None, _('select all unresolved files')),
4827 [('a', 'all', None, _('select all unresolved files')),
4849 ('l', 'list', None, _('list state of files needing merge')),
4828 ('l', 'list', None, _('list state of files needing merge')),
4850 ('m', 'mark', None, _('mark files as resolved')),
4829 ('m', 'mark', None, _('mark files as resolved')),
4851 ('u', 'unmark', None, _('mark files as unresolved')),
4830 ('u', 'unmark', None, _('mark files as unresolved')),
4852 ('n', 'no-status', None, _('hide status prefix'))]
4831 ('n', 'no-status', None, _('hide status prefix'))]
4853 + mergetoolopts + walkopts + formatteropts,
4832 + mergetoolopts + walkopts + formatteropts,
4854 _('[OPTION]... [FILE]...'),
4833 _('[OPTION]... [FILE]...'),
4855 inferrepo=True)
4834 inferrepo=True)
4856 def resolve(ui, repo, *pats, **opts):
4835 def resolve(ui, repo, *pats, **opts):
4857 """redo merges or set/view the merge status of files
4836 """redo merges or set/view the merge status of files
4858
4837
4859 Merges with unresolved conflicts are often the result of
4838 Merges with unresolved conflicts are often the result of
4860 non-interactive merging using the ``internal:merge`` configuration
4839 non-interactive merging using the ``internal:merge`` configuration
4861 setting, or a command-line merge tool like ``diff3``. The resolve
4840 setting, or a command-line merge tool like ``diff3``. The resolve
4862 command is used to manage the files involved in a merge, after
4841 command is used to manage the files involved in a merge, after
4863 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4842 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4864 working directory must have two parents). See :hg:`help
4843 working directory must have two parents). See :hg:`help
4865 merge-tools` for information on configuring merge tools.
4844 merge-tools` for information on configuring merge tools.
4866
4845
4867 The resolve command can be used in the following ways:
4846 The resolve command can be used in the following ways:
4868
4847
4869 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4848 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4870 files, discarding any previous merge attempts. Re-merging is not
4849 files, discarding any previous merge attempts. Re-merging is not
4871 performed for files already marked as resolved. Use ``--all/-a``
4850 performed for files already marked as resolved. Use ``--all/-a``
4872 to select all unresolved files. ``--tool`` can be used to specify
4851 to select all unresolved files. ``--tool`` can be used to specify
4873 the merge tool used for the given files. It overrides the HGMERGE
4852 the merge tool used for the given files. It overrides the HGMERGE
4874 environment variable and your configuration files. Previous file
4853 environment variable and your configuration files. Previous file
4875 contents are saved with a ``.orig`` suffix.
4854 contents are saved with a ``.orig`` suffix.
4876
4855
4877 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4856 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4878 (e.g. after having manually fixed-up the files). The default is
4857 (e.g. after having manually fixed-up the files). The default is
4879 to mark all unresolved files.
4858 to mark all unresolved files.
4880
4859
4881 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4860 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4882 default is to mark all resolved files.
4861 default is to mark all resolved files.
4883
4862
4884 - :hg:`resolve -l`: list files which had or still have conflicts.
4863 - :hg:`resolve -l`: list files which had or still have conflicts.
4885 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4864 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4886
4865
4887 .. note::
4866 .. note::
4888
4867
4889 Mercurial will not let you commit files with unresolved merge
4868 Mercurial will not let you commit files with unresolved merge
4890 conflicts. You must use :hg:`resolve -m ...` before you can
4869 conflicts. You must use :hg:`resolve -m ...` before you can
4891 commit after a conflicting merge.
4870 commit after a conflicting merge.
4892
4871
4893 Returns 0 on success, 1 if any files fail a resolve attempt.
4872 Returns 0 on success, 1 if any files fail a resolve attempt.
4894 """
4873 """
4895
4874
4896 flaglist = 'all mark unmark list no_status'.split()
4875 flaglist = 'all mark unmark list no_status'.split()
4897 all, mark, unmark, show, nostatus = \
4876 all, mark, unmark, show, nostatus = \
4898 [opts.get(o) for o in flaglist]
4877 [opts.get(o) for o in flaglist]
4899
4878
4900 if (show and (mark or unmark)) or (mark and unmark):
4879 if (show and (mark or unmark)) or (mark and unmark):
4901 raise error.Abort(_("too many options specified"))
4880 raise error.Abort(_("too many options specified"))
4902 if pats and all:
4881 if pats and all:
4903 raise error.Abort(_("can't specify --all and patterns"))
4882 raise error.Abort(_("can't specify --all and patterns"))
4904 if not (all or pats or show or mark or unmark):
4883 if not (all or pats or show or mark or unmark):
4905 raise error.Abort(_('no files or directories specified'),
4884 raise error.Abort(_('no files or directories specified'),
4906 hint=('use --all to re-merge all unresolved files'))
4885 hint=('use --all to re-merge all unresolved files'))
4907
4886
4908 if show:
4887 if show:
4909 fm = ui.formatter('resolve', opts)
4888 fm = ui.formatter('resolve', opts)
4910 ms = mergemod.mergestate.read(repo)
4889 ms = mergemod.mergestate.read(repo)
4911 m = scmutil.match(repo[None], pats, opts)
4890 m = scmutil.match(repo[None], pats, opts)
4912 for f in ms:
4891 for f in ms:
4913 if not m(f):
4892 if not m(f):
4914 continue
4893 continue
4915 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4894 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4916 'd': 'driverresolved'}[ms[f]]
4895 'd': 'driverresolved'}[ms[f]]
4917 fm.startitem()
4896 fm.startitem()
4918 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4897 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4919 fm.write('path', '%s\n', f, label=l)
4898 fm.write('path', '%s\n', f, label=l)
4920 fm.end()
4899 fm.end()
4921 return 0
4900 return 0
4922
4901
4923 with repo.wlock():
4902 with repo.wlock():
4924 ms = mergemod.mergestate.read(repo)
4903 ms = mergemod.mergestate.read(repo)
4925
4904
4926 if not (ms.active() or repo.dirstate.p2() != nullid):
4905 if not (ms.active() or repo.dirstate.p2() != nullid):
4927 raise error.Abort(
4906 raise error.Abort(
4928 _('resolve command not applicable when not merging'))
4907 _('resolve command not applicable when not merging'))
4929
4908
4930 wctx = repo[None]
4909 wctx = repo[None]
4931
4910
4932 if ms.mergedriver and ms.mdstate() == 'u':
4911 if ms.mergedriver and ms.mdstate() == 'u':
4933 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4912 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4934 ms.commit()
4913 ms.commit()
4935 # allow mark and unmark to go through
4914 # allow mark and unmark to go through
4936 if not mark and not unmark and not proceed:
4915 if not mark and not unmark and not proceed:
4937 return 1
4916 return 1
4938
4917
4939 m = scmutil.match(wctx, pats, opts)
4918 m = scmutil.match(wctx, pats, opts)
4940 ret = 0
4919 ret = 0
4941 didwork = False
4920 didwork = False
4942 runconclude = False
4921 runconclude = False
4943
4922
4944 tocomplete = []
4923 tocomplete = []
4945 for f in ms:
4924 for f in ms:
4946 if not m(f):
4925 if not m(f):
4947 continue
4926 continue
4948
4927
4949 didwork = True
4928 didwork = True
4950
4929
4951 # don't let driver-resolved files be marked, and run the conclude
4930 # don't let driver-resolved files be marked, and run the conclude
4952 # step if asked to resolve
4931 # step if asked to resolve
4953 if ms[f] == "d":
4932 if ms[f] == "d":
4954 exact = m.exact(f)
4933 exact = m.exact(f)
4955 if mark:
4934 if mark:
4956 if exact:
4935 if exact:
4957 ui.warn(_('not marking %s as it is driver-resolved\n')
4936 ui.warn(_('not marking %s as it is driver-resolved\n')
4958 % f)
4937 % f)
4959 elif unmark:
4938 elif unmark:
4960 if exact:
4939 if exact:
4961 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4940 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4962 % f)
4941 % f)
4963 else:
4942 else:
4964 runconclude = True
4943 runconclude = True
4965 continue
4944 continue
4966
4945
4967 if mark:
4946 if mark:
4968 ms.mark(f, "r")
4947 ms.mark(f, "r")
4969 elif unmark:
4948 elif unmark:
4970 ms.mark(f, "u")
4949 ms.mark(f, "u")
4971 else:
4950 else:
4972 # backup pre-resolve (merge uses .orig for its own purposes)
4951 # backup pre-resolve (merge uses .orig for its own purposes)
4973 a = repo.wjoin(f)
4952 a = repo.wjoin(f)
4974 try:
4953 try:
4975 util.copyfile(a, a + ".resolve")
4954 util.copyfile(a, a + ".resolve")
4976 except (IOError, OSError) as inst:
4955 except (IOError, OSError) as inst:
4977 if inst.errno != errno.ENOENT:
4956 if inst.errno != errno.ENOENT:
4978 raise
4957 raise
4979
4958
4980 try:
4959 try:
4981 # preresolve file
4960 # preresolve file
4982 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4961 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4983 'resolve')
4962 'resolve')
4984 complete, r = ms.preresolve(f, wctx)
4963 complete, r = ms.preresolve(f, wctx)
4985 if not complete:
4964 if not complete:
4986 tocomplete.append(f)
4965 tocomplete.append(f)
4987 elif r:
4966 elif r:
4988 ret = 1
4967 ret = 1
4989 finally:
4968 finally:
4990 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4969 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4991 ms.commit()
4970 ms.commit()
4992
4971
4993 # replace filemerge's .orig file with our resolve file, but only
4972 # replace filemerge's .orig file with our resolve file, but only
4994 # for merges that are complete
4973 # for merges that are complete
4995 if complete:
4974 if complete:
4996 try:
4975 try:
4997 util.rename(a + ".resolve",
4976 util.rename(a + ".resolve",
4998 scmutil.origpath(ui, repo, a))
4977 scmutil.origpath(ui, repo, a))
4999 except OSError as inst:
4978 except OSError as inst:
5000 if inst.errno != errno.ENOENT:
4979 if inst.errno != errno.ENOENT:
5001 raise
4980 raise
5002
4981
5003 for f in tocomplete:
4982 for f in tocomplete:
5004 try:
4983 try:
5005 # resolve file
4984 # resolve file
5006 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4985 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5007 'resolve')
4986 'resolve')
5008 r = ms.resolve(f, wctx)
4987 r = ms.resolve(f, wctx)
5009 if r:
4988 if r:
5010 ret = 1
4989 ret = 1
5011 finally:
4990 finally:
5012 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4991 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5013 ms.commit()
4992 ms.commit()
5014
4993
5015 # replace filemerge's .orig file with our resolve file
4994 # replace filemerge's .orig file with our resolve file
5016 a = repo.wjoin(f)
4995 a = repo.wjoin(f)
5017 try:
4996 try:
5018 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4997 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5019 except OSError as inst:
4998 except OSError as inst:
5020 if inst.errno != errno.ENOENT:
4999 if inst.errno != errno.ENOENT:
5021 raise
5000 raise
5022
5001
5023 ms.commit()
5002 ms.commit()
5024 ms.recordactions()
5003 ms.recordactions()
5025
5004
5026 if not didwork and pats:
5005 if not didwork and pats:
5027 hint = None
5006 hint = None
5028 if not any([p for p in pats if p.find(':') >= 0]):
5007 if not any([p for p in pats if p.find(':') >= 0]):
5029 pats = ['path:%s' % p for p in pats]
5008 pats = ['path:%s' % p for p in pats]
5030 m = scmutil.match(wctx, pats, opts)
5009 m = scmutil.match(wctx, pats, opts)
5031 for f in ms:
5010 for f in ms:
5032 if not m(f):
5011 if not m(f):
5033 continue
5012 continue
5034 flags = ''.join(['-%s ' % o[0] for o in flaglist
5013 flags = ''.join(['-%s ' % o[0] for o in flaglist
5035 if opts.get(o)])
5014 if opts.get(o)])
5036 hint = _("(try: hg resolve %s%s)\n") % (
5015 hint = _("(try: hg resolve %s%s)\n") % (
5037 flags,
5016 flags,
5038 ' '.join(pats))
5017 ' '.join(pats))
5039 break
5018 break
5040 ui.warn(_("arguments do not match paths that need resolving\n"))
5019 ui.warn(_("arguments do not match paths that need resolving\n"))
5041 if hint:
5020 if hint:
5042 ui.warn(hint)
5021 ui.warn(hint)
5043 elif ms.mergedriver and ms.mdstate() != 's':
5022 elif ms.mergedriver and ms.mdstate() != 's':
5044 # run conclude step when either a driver-resolved file is requested
5023 # run conclude step when either a driver-resolved file is requested
5045 # or there are no driver-resolved files
5024 # or there are no driver-resolved files
5046 # we can't use 'ret' to determine whether any files are unresolved
5025 # we can't use 'ret' to determine whether any files are unresolved
5047 # because we might not have tried to resolve some
5026 # because we might not have tried to resolve some
5048 if ((runconclude or not list(ms.driverresolved()))
5027 if ((runconclude or not list(ms.driverresolved()))
5049 and not list(ms.unresolved())):
5028 and not list(ms.unresolved())):
5050 proceed = mergemod.driverconclude(repo, ms, wctx)
5029 proceed = mergemod.driverconclude(repo, ms, wctx)
5051 ms.commit()
5030 ms.commit()
5052 if not proceed:
5031 if not proceed:
5053 return 1
5032 return 1
5054
5033
5055 # Nudge users into finishing an unfinished operation
5034 # Nudge users into finishing an unfinished operation
5056 unresolvedf = list(ms.unresolved())
5035 unresolvedf = list(ms.unresolved())
5057 driverresolvedf = list(ms.driverresolved())
5036 driverresolvedf = list(ms.driverresolved())
5058 if not unresolvedf and not driverresolvedf:
5037 if not unresolvedf and not driverresolvedf:
5059 ui.status(_('(no more unresolved files)\n'))
5038 ui.status(_('(no more unresolved files)\n'))
5060 cmdutil.checkafterresolved(repo)
5039 cmdutil.checkafterresolved(repo)
5061 elif not unresolvedf:
5040 elif not unresolvedf:
5062 ui.status(_('(no more unresolved files -- '
5041 ui.status(_('(no more unresolved files -- '
5063 'run "hg resolve --all" to conclude)\n'))
5042 'run "hg resolve --all" to conclude)\n'))
5064
5043
5065 return ret
5044 return ret
5066
5045
5067 @command('revert',
5046 @command('revert',
5068 [('a', 'all', None, _('revert all changes when no arguments given')),
5047 [('a', 'all', None, _('revert all changes when no arguments given')),
5069 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5048 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5070 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5049 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5071 ('C', 'no-backup', None, _('do not save backup copies of files')),
5050 ('C', 'no-backup', None, _('do not save backup copies of files')),
5072 ('i', 'interactive', None,
5051 ('i', 'interactive', None,
5073 _('interactively select the changes (EXPERIMENTAL)')),
5052 _('interactively select the changes (EXPERIMENTAL)')),
5074 ] + walkopts + dryrunopts,
5053 ] + walkopts + dryrunopts,
5075 _('[OPTION]... [-r REV] [NAME]...'))
5054 _('[OPTION]... [-r REV] [NAME]...'))
5076 def revert(ui, repo, *pats, **opts):
5055 def revert(ui, repo, *pats, **opts):
5077 """restore files to their checkout state
5056 """restore files to their checkout state
5078
5057
5079 .. note::
5058 .. note::
5080
5059
5081 To check out earlier revisions, you should use :hg:`update REV`.
5060 To check out earlier revisions, you should use :hg:`update REV`.
5082 To cancel an uncommitted merge (and lose your changes),
5061 To cancel an uncommitted merge (and lose your changes),
5083 use :hg:`update --clean .`.
5062 use :hg:`update --clean .`.
5084
5063
5085 With no revision specified, revert the specified files or directories
5064 With no revision specified, revert the specified files or directories
5086 to the contents they had in the parent of the working directory.
5065 to the contents they had in the parent of the working directory.
5087 This restores the contents of files to an unmodified
5066 This restores the contents of files to an unmodified
5088 state and unschedules adds, removes, copies, and renames. If the
5067 state and unschedules adds, removes, copies, and renames. If the
5089 working directory has two parents, you must explicitly specify a
5068 working directory has two parents, you must explicitly specify a
5090 revision.
5069 revision.
5091
5070
5092 Using the -r/--rev or -d/--date options, revert the given files or
5071 Using the -r/--rev or -d/--date options, revert the given files or
5093 directories to their states as of a specific revision. Because
5072 directories to their states as of a specific revision. Because
5094 revert does not change the working directory parents, this will
5073 revert does not change the working directory parents, this will
5095 cause these files to appear modified. This can be helpful to "back
5074 cause these files to appear modified. This can be helpful to "back
5096 out" some or all of an earlier change. See :hg:`backout` for a
5075 out" some or all of an earlier change. See :hg:`backout` for a
5097 related method.
5076 related method.
5098
5077
5099 Modified files are saved with a .orig suffix before reverting.
5078 Modified files are saved with a .orig suffix before reverting.
5100 To disable these backups, use --no-backup. It is possible to store
5079 To disable these backups, use --no-backup. It is possible to store
5101 the backup files in a custom directory relative to the root of the
5080 the backup files in a custom directory relative to the root of the
5102 repository by setting the ``ui.origbackuppath`` configuration
5081 repository by setting the ``ui.origbackuppath`` configuration
5103 option.
5082 option.
5104
5083
5105 See :hg:`help dates` for a list of formats valid for -d/--date.
5084 See :hg:`help dates` for a list of formats valid for -d/--date.
5106
5085
5107 See :hg:`help backout` for a way to reverse the effect of an
5086 See :hg:`help backout` for a way to reverse the effect of an
5108 earlier changeset.
5087 earlier changeset.
5109
5088
5110 Returns 0 on success.
5089 Returns 0 on success.
5111 """
5090 """
5112
5091
5113 if opts.get("date"):
5092 if opts.get("date"):
5114 if opts.get("rev"):
5093 if opts.get("rev"):
5115 raise error.Abort(_("you can't specify a revision and a date"))
5094 raise error.Abort(_("you can't specify a revision and a date"))
5116 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5095 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5117
5096
5118 parent, p2 = repo.dirstate.parents()
5097 parent, p2 = repo.dirstate.parents()
5119 if not opts.get('rev') and p2 != nullid:
5098 if not opts.get('rev') and p2 != nullid:
5120 # revert after merge is a trap for new users (issue2915)
5099 # revert after merge is a trap for new users (issue2915)
5121 raise error.Abort(_('uncommitted merge with no revision specified'),
5100 raise error.Abort(_('uncommitted merge with no revision specified'),
5122 hint=_("use 'hg update' or see 'hg help revert'"))
5101 hint=_("use 'hg update' or see 'hg help revert'"))
5123
5102
5124 ctx = scmutil.revsingle(repo, opts.get('rev'))
5103 ctx = scmutil.revsingle(repo, opts.get('rev'))
5125
5104
5126 if (not (pats or opts.get('include') or opts.get('exclude') or
5105 if (not (pats or opts.get('include') or opts.get('exclude') or
5127 opts.get('all') or opts.get('interactive'))):
5106 opts.get('all') or opts.get('interactive'))):
5128 msg = _("no files or directories specified")
5107 msg = _("no files or directories specified")
5129 if p2 != nullid:
5108 if p2 != nullid:
5130 hint = _("uncommitted merge, use --all to discard all changes,"
5109 hint = _("uncommitted merge, use --all to discard all changes,"
5131 " or 'hg update -C .' to abort the merge")
5110 " or 'hg update -C .' to abort the merge")
5132 raise error.Abort(msg, hint=hint)
5111 raise error.Abort(msg, hint=hint)
5133 dirty = any(repo.status())
5112 dirty = any(repo.status())
5134 node = ctx.node()
5113 node = ctx.node()
5135 if node != parent:
5114 if node != parent:
5136 if dirty:
5115 if dirty:
5137 hint = _("uncommitted changes, use --all to discard all"
5116 hint = _("uncommitted changes, use --all to discard all"
5138 " changes, or 'hg update %s' to update") % ctx.rev()
5117 " changes, or 'hg update %s' to update") % ctx.rev()
5139 else:
5118 else:
5140 hint = _("use --all to revert all files,"
5119 hint = _("use --all to revert all files,"
5141 " or 'hg update %s' to update") % ctx.rev()
5120 " or 'hg update %s' to update") % ctx.rev()
5142 elif dirty:
5121 elif dirty:
5143 hint = _("uncommitted changes, use --all to discard all changes")
5122 hint = _("uncommitted changes, use --all to discard all changes")
5144 else:
5123 else:
5145 hint = _("use --all to revert all files")
5124 hint = _("use --all to revert all files")
5146 raise error.Abort(msg, hint=hint)
5125 raise error.Abort(msg, hint=hint)
5147
5126
5148 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5127 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5149
5128
5150 @command('rollback', dryrunopts +
5129 @command('rollback', dryrunopts +
5151 [('f', 'force', False, _('ignore safety measures'))])
5130 [('f', 'force', False, _('ignore safety measures'))])
5152 def rollback(ui, repo, **opts):
5131 def rollback(ui, repo, **opts):
5153 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5154
5133
5155 Please use :hg:`commit --amend` instead of rollback to correct
5134 Please use :hg:`commit --amend` instead of rollback to correct
5156 mistakes in the last commit.
5135 mistakes in the last commit.
5157
5136
5158 This command should be used with care. There is only one level of
5137 This command should be used with care. There is only one level of
5159 rollback, and there is no way to undo a rollback. It will also
5138 rollback, and there is no way to undo a rollback. It will also
5160 restore the dirstate at the time of the last transaction, losing
5139 restore the dirstate at the time of the last transaction, losing
5161 any dirstate changes since that time. This command does not alter
5140 any dirstate changes since that time. This command does not alter
5162 the working directory.
5141 the working directory.
5163
5142
5164 Transactions are used to encapsulate the effects of all commands
5143 Transactions are used to encapsulate the effects of all commands
5165 that create new changesets or propagate existing changesets into a
5144 that create new changesets or propagate existing changesets into a
5166 repository.
5145 repository.
5167
5146
5168 .. container:: verbose
5147 .. container:: verbose
5169
5148
5170 For example, the following commands are transactional, and their
5149 For example, the following commands are transactional, and their
5171 effects can be rolled back:
5150 effects can be rolled back:
5172
5151
5173 - commit
5152 - commit
5174 - import
5153 - import
5175 - pull
5154 - pull
5176 - push (with this repository as the destination)
5155 - push (with this repository as the destination)
5177 - unbundle
5156 - unbundle
5178
5157
5179 To avoid permanent data loss, rollback will refuse to rollback a
5158 To avoid permanent data loss, rollback will refuse to rollback a
5180 commit transaction if it isn't checked out. Use --force to
5159 commit transaction if it isn't checked out. Use --force to
5181 override this protection.
5160 override this protection.
5182
5161
5183 The rollback command can be entirely disabled by setting the
5162 The rollback command can be entirely disabled by setting the
5184 ``ui.rollback`` configuration setting to false. If you're here
5163 ``ui.rollback`` configuration setting to false. If you're here
5185 because you want to use rollback and it's disabled, you can
5164 because you want to use rollback and it's disabled, you can
5186 re-enable the command by setting ``ui.rollback`` to true.
5165 re-enable the command by setting ``ui.rollback`` to true.
5187
5166
5188 This command is not intended for use on public repositories. Once
5167 This command is not intended for use on public repositories. Once
5189 changes are visible for pull by other users, rolling a transaction
5168 changes are visible for pull by other users, rolling a transaction
5190 back locally is ineffective (someone else may already have pulled
5169 back locally is ineffective (someone else may already have pulled
5191 the changes). Furthermore, a race is possible with readers of the
5170 the changes). Furthermore, a race is possible with readers of the
5192 repository; for example an in-progress pull from the repository
5171 repository; for example an in-progress pull from the repository
5193 may fail if a rollback is performed.
5172 may fail if a rollback is performed.
5194
5173
5195 Returns 0 on success, 1 if no rollback data is available.
5174 Returns 0 on success, 1 if no rollback data is available.
5196 """
5175 """
5197 if not ui.configbool('ui', 'rollback', True):
5176 if not ui.configbool('ui', 'rollback', True):
5198 raise error.Abort(_('rollback is disabled because it is unsafe'),
5177 raise error.Abort(_('rollback is disabled because it is unsafe'),
5199 hint=('see `hg help -v rollback` for information'))
5178 hint=('see `hg help -v rollback` for information'))
5200 return repo.rollback(dryrun=opts.get('dry_run'),
5179 return repo.rollback(dryrun=opts.get('dry_run'),
5201 force=opts.get('force'))
5180 force=opts.get('force'))
5202
5181
5203 @command('root', [])
5182 @command('root', [])
5204 def root(ui, repo):
5183 def root(ui, repo):
5205 """print the root (top) of the current working directory
5184 """print the root (top) of the current working directory
5206
5185
5207 Print the root directory of the current repository.
5186 Print the root directory of the current repository.
5208
5187
5209 Returns 0 on success.
5188 Returns 0 on success.
5210 """
5189 """
5211 ui.write(repo.root + "\n")
5190 ui.write(repo.root + "\n")
5212
5191
5213 @command('^serve',
5192 @command('^serve',
5214 [('A', 'accesslog', '', _('name of access log file to write to'),
5193 [('A', 'accesslog', '', _('name of access log file to write to'),
5215 _('FILE')),
5194 _('FILE')),
5216 ('d', 'daemon', None, _('run server in background')),
5195 ('d', 'daemon', None, _('run server in background')),
5217 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5196 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5218 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5197 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5219 # use string type, then we can check if something was passed
5198 # use string type, then we can check if something was passed
5220 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5199 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5221 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5200 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5222 _('ADDR')),
5201 _('ADDR')),
5223 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5202 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5224 _('PREFIX')),
5203 _('PREFIX')),
5225 ('n', 'name', '',
5204 ('n', 'name', '',
5226 _('name to show in web pages (default: working directory)'), _('NAME')),
5205 _('name to show in web pages (default: working directory)'), _('NAME')),
5227 ('', 'web-conf', '',
5206 ('', 'web-conf', '',
5228 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5207 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5229 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5208 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5230 _('FILE')),
5209 _('FILE')),
5231 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5210 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5232 ('', 'stdio', None, _('for remote clients')),
5211 ('', 'stdio', None, _('for remote clients')),
5233 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5212 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5234 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5213 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5235 ('', 'style', '', _('template style to use'), _('STYLE')),
5214 ('', 'style', '', _('template style to use'), _('STYLE')),
5236 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5215 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5237 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5216 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5238 _('[OPTION]...'),
5217 _('[OPTION]...'),
5239 optionalrepo=True)
5218 optionalrepo=True)
5240 def serve(ui, repo, **opts):
5219 def serve(ui, repo, **opts):
5241 """start stand-alone webserver
5220 """start stand-alone webserver
5242
5221
5243 Start a local HTTP repository browser and pull server. You can use
5222 Start a local HTTP repository browser and pull server. You can use
5244 this for ad-hoc sharing and browsing of repositories. It is
5223 this for ad-hoc sharing and browsing of repositories. It is
5245 recommended to use a real web server to serve a repository for
5224 recommended to use a real web server to serve a repository for
5246 longer periods of time.
5225 longer periods of time.
5247
5226
5248 Please note that the server does not implement access control.
5227 Please note that the server does not implement access control.
5249 This means that, by default, anybody can read from the server and
5228 This means that, by default, anybody can read from the server and
5250 nobody can write to it by default. Set the ``web.allow_push``
5229 nobody can write to it by default. Set the ``web.allow_push``
5251 option to ``*`` to allow everybody to push to the server. You
5230 option to ``*`` to allow everybody to push to the server. You
5252 should use a real web server if you need to authenticate users.
5231 should use a real web server if you need to authenticate users.
5253
5232
5254 By default, the server logs accesses to stdout and errors to
5233 By default, the server logs accesses to stdout and errors to
5255 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5234 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5256 files.
5235 files.
5257
5236
5258 To have the server choose a free port number to listen on, specify
5237 To have the server choose a free port number to listen on, specify
5259 a port number of 0; in this case, the server will print the port
5238 a port number of 0; in this case, the server will print the port
5260 number it uses.
5239 number it uses.
5261
5240
5262 Returns 0 on success.
5241 Returns 0 on success.
5263 """
5242 """
5264
5243
5265 if opts["stdio"] and opts["cmdserver"]:
5244 if opts["stdio"] and opts["cmdserver"]:
5266 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5245 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5267
5246
5268 if opts["stdio"]:
5247 if opts["stdio"]:
5269 if repo is None:
5248 if repo is None:
5270 raise error.RepoError(_("there is no Mercurial repository here"
5249 raise error.RepoError(_("there is no Mercurial repository here"
5271 " (.hg not found)"))
5250 " (.hg not found)"))
5272 s = sshserver.sshserver(ui, repo)
5251 s = sshserver.sshserver(ui, repo)
5273 s.serve_forever()
5252 s.serve_forever()
5274
5253
5275 service = server.createservice(ui, repo, opts)
5254 service = server.createservice(ui, repo, opts)
5276 return server.runservice(opts, initfn=service.init, runfn=service.run)
5255 return server.runservice(opts, initfn=service.init, runfn=service.run)
5277
5256
5278 @command('^status|st',
5257 @command('^status|st',
5279 [('A', 'all', None, _('show status of all files')),
5258 [('A', 'all', None, _('show status of all files')),
5280 ('m', 'modified', None, _('show only modified files')),
5259 ('m', 'modified', None, _('show only modified files')),
5281 ('a', 'added', None, _('show only added files')),
5260 ('a', 'added', None, _('show only added files')),
5282 ('r', 'removed', None, _('show only removed files')),
5261 ('r', 'removed', None, _('show only removed files')),
5283 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5262 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5284 ('c', 'clean', None, _('show only files without changes')),
5263 ('c', 'clean', None, _('show only files without changes')),
5285 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5264 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5286 ('i', 'ignored', None, _('show only ignored files')),
5265 ('i', 'ignored', None, _('show only ignored files')),
5287 ('n', 'no-status', None, _('hide status prefix')),
5266 ('n', 'no-status', None, _('hide status prefix')),
5288 ('C', 'copies', None, _('show source of copied files')),
5267 ('C', 'copies', None, _('show source of copied files')),
5289 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5268 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5290 ('', 'rev', [], _('show difference from revision'), _('REV')),
5269 ('', 'rev', [], _('show difference from revision'), _('REV')),
5291 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5270 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5292 ] + walkopts + subrepoopts + formatteropts,
5271 ] + walkopts + subrepoopts + formatteropts,
5293 _('[OPTION]... [FILE]...'),
5272 _('[OPTION]... [FILE]...'),
5294 inferrepo=True)
5273 inferrepo=True)
5295 def status(ui, repo, *pats, **opts):
5274 def status(ui, repo, *pats, **opts):
5296 """show changed files in the working directory
5275 """show changed files in the working directory
5297
5276
5298 Show status of files in the repository. If names are given, only
5277 Show status of files in the repository. If names are given, only
5299 files that match are shown. Files that are clean or ignored or
5278 files that match are shown. Files that are clean or ignored or
5300 the source of a copy/move operation, are not listed unless
5279 the source of a copy/move operation, are not listed unless
5301 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5280 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5302 Unless options described with "show only ..." are given, the
5281 Unless options described with "show only ..." are given, the
5303 options -mardu are used.
5282 options -mardu are used.
5304
5283
5305 Option -q/--quiet hides untracked (unknown and ignored) files
5284 Option -q/--quiet hides untracked (unknown and ignored) files
5306 unless explicitly requested with -u/--unknown or -i/--ignored.
5285 unless explicitly requested with -u/--unknown or -i/--ignored.
5307
5286
5308 .. note::
5287 .. note::
5309
5288
5310 :hg:`status` may appear to disagree with diff if permissions have
5289 :hg:`status` may appear to disagree with diff if permissions have
5311 changed or a merge has occurred. The standard diff format does
5290 changed or a merge has occurred. The standard diff format does
5312 not report permission changes and diff only reports changes
5291 not report permission changes and diff only reports changes
5313 relative to one merge parent.
5292 relative to one merge parent.
5314
5293
5315 If one revision is given, it is used as the base revision.
5294 If one revision is given, it is used as the base revision.
5316 If two revisions are given, the differences between them are
5295 If two revisions are given, the differences between them are
5317 shown. The --change option can also be used as a shortcut to list
5296 shown. The --change option can also be used as a shortcut to list
5318 the changed files of a revision from its first parent.
5297 the changed files of a revision from its first parent.
5319
5298
5320 The codes used to show the status of files are::
5299 The codes used to show the status of files are::
5321
5300
5322 M = modified
5301 M = modified
5323 A = added
5302 A = added
5324 R = removed
5303 R = removed
5325 C = clean
5304 C = clean
5326 ! = missing (deleted by non-hg command, but still tracked)
5305 ! = missing (deleted by non-hg command, but still tracked)
5327 ? = not tracked
5306 ? = not tracked
5328 I = ignored
5307 I = ignored
5329 = origin of the previous file (with --copies)
5308 = origin of the previous file (with --copies)
5330
5309
5331 .. container:: verbose
5310 .. container:: verbose
5332
5311
5333 Examples:
5312 Examples:
5334
5313
5335 - show changes in the working directory relative to a
5314 - show changes in the working directory relative to a
5336 changeset::
5315 changeset::
5337
5316
5338 hg status --rev 9353
5317 hg status --rev 9353
5339
5318
5340 - show changes in the working directory relative to the
5319 - show changes in the working directory relative to the
5341 current directory (see :hg:`help patterns` for more information)::
5320 current directory (see :hg:`help patterns` for more information)::
5342
5321
5343 hg status re:
5322 hg status re:
5344
5323
5345 - show all changes including copies in an existing changeset::
5324 - show all changes including copies in an existing changeset::
5346
5325
5347 hg status --copies --change 9353
5326 hg status --copies --change 9353
5348
5327
5349 - get a NUL separated list of added files, suitable for xargs::
5328 - get a NUL separated list of added files, suitable for xargs::
5350
5329
5351 hg status -an0
5330 hg status -an0
5352
5331
5353 Returns 0 on success.
5332 Returns 0 on success.
5354 """
5333 """
5355
5334
5356 revs = opts.get('rev')
5335 revs = opts.get('rev')
5357 change = opts.get('change')
5336 change = opts.get('change')
5358
5337
5359 if revs and change:
5338 if revs and change:
5360 msg = _('cannot specify --rev and --change at the same time')
5339 msg = _('cannot specify --rev and --change at the same time')
5361 raise error.Abort(msg)
5340 raise error.Abort(msg)
5362 elif change:
5341 elif change:
5363 node2 = scmutil.revsingle(repo, change, None).node()
5342 node2 = scmutil.revsingle(repo, change, None).node()
5364 node1 = repo[node2].p1().node()
5343 node1 = repo[node2].p1().node()
5365 else:
5344 else:
5366 node1, node2 = scmutil.revpair(repo, revs)
5345 node1, node2 = scmutil.revpair(repo, revs)
5367
5346
5368 if pats:
5347 if pats:
5369 cwd = repo.getcwd()
5348 cwd = repo.getcwd()
5370 else:
5349 else:
5371 cwd = ''
5350 cwd = ''
5372
5351
5373 if opts.get('print0'):
5352 if opts.get('print0'):
5374 end = '\0'
5353 end = '\0'
5375 else:
5354 else:
5376 end = '\n'
5355 end = '\n'
5377 copy = {}
5356 copy = {}
5378 states = 'modified added removed deleted unknown ignored clean'.split()
5357 states = 'modified added removed deleted unknown ignored clean'.split()
5379 show = [k for k in states if opts.get(k)]
5358 show = [k for k in states if opts.get(k)]
5380 if opts.get('all'):
5359 if opts.get('all'):
5381 show += ui.quiet and (states[:4] + ['clean']) or states
5360 show += ui.quiet and (states[:4] + ['clean']) or states
5382 if not show:
5361 if not show:
5383 if ui.quiet:
5362 if ui.quiet:
5384 show = states[:4]
5363 show = states[:4]
5385 else:
5364 else:
5386 show = states[:5]
5365 show = states[:5]
5387
5366
5388 m = scmutil.match(repo[node2], pats, opts)
5367 m = scmutil.match(repo[node2], pats, opts)
5389 stat = repo.status(node1, node2, m,
5368 stat = repo.status(node1, node2, m,
5390 'ignored' in show, 'clean' in show, 'unknown' in show,
5369 'ignored' in show, 'clean' in show, 'unknown' in show,
5391 opts.get('subrepos'))
5370 opts.get('subrepos'))
5392 changestates = zip(states, 'MAR!?IC', stat)
5371 changestates = zip(states, 'MAR!?IC', stat)
5393
5372
5394 if (opts.get('all') or opts.get('copies')
5373 if (opts.get('all') or opts.get('copies')
5395 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5374 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5396 copy = copies.pathcopies(repo[node1], repo[node2], m)
5375 copy = copies.pathcopies(repo[node1], repo[node2], m)
5397
5376
5398 fm = ui.formatter('status', opts)
5377 fm = ui.formatter('status', opts)
5399 fmt = '%s' + end
5378 fmt = '%s' + end
5400 showchar = not opts.get('no_status')
5379 showchar = not opts.get('no_status')
5401
5380
5402 for state, char, files in changestates:
5381 for state, char, files in changestates:
5403 if state in show:
5382 if state in show:
5404 label = 'status.' + state
5383 label = 'status.' + state
5405 for f in files:
5384 for f in files:
5406 fm.startitem()
5385 fm.startitem()
5407 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5386 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5408 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5387 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5409 if f in copy:
5388 if f in copy:
5410 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5389 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5411 label='status.copied')
5390 label='status.copied')
5412 fm.end()
5391 fm.end()
5413
5392
5414 @command('^summary|sum',
5393 @command('^summary|sum',
5415 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5394 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5416 def summary(ui, repo, **opts):
5395 def summary(ui, repo, **opts):
5417 """summarize working directory state
5396 """summarize working directory state
5418
5397
5419 This generates a brief summary of the working directory state,
5398 This generates a brief summary of the working directory state,
5420 including parents, branch, commit status, phase and available updates.
5399 including parents, branch, commit status, phase and available updates.
5421
5400
5422 With the --remote option, this will check the default paths for
5401 With the --remote option, this will check the default paths for
5423 incoming and outgoing changes. This can be time-consuming.
5402 incoming and outgoing changes. This can be time-consuming.
5424
5403
5425 Returns 0 on success.
5404 Returns 0 on success.
5426 """
5405 """
5427
5406
5428 ctx = repo[None]
5407 ctx = repo[None]
5429 parents = ctx.parents()
5408 parents = ctx.parents()
5430 pnode = parents[0].node()
5409 pnode = parents[0].node()
5431 marks = []
5410 marks = []
5432
5411
5433 ms = None
5412 ms = None
5434 try:
5413 try:
5435 ms = mergemod.mergestate.read(repo)
5414 ms = mergemod.mergestate.read(repo)
5436 except error.UnsupportedMergeRecords as e:
5415 except error.UnsupportedMergeRecords as e:
5437 s = ' '.join(e.recordtypes)
5416 s = ' '.join(e.recordtypes)
5438 ui.warn(
5417 ui.warn(
5439 _('warning: merge state has unsupported record types: %s\n') % s)
5418 _('warning: merge state has unsupported record types: %s\n') % s)
5440 unresolved = 0
5419 unresolved = 0
5441 else:
5420 else:
5442 unresolved = [f for f in ms if ms[f] == 'u']
5421 unresolved = [f for f in ms if ms[f] == 'u']
5443
5422
5444 for p in parents:
5423 for p in parents:
5445 # label with log.changeset (instead of log.parent) since this
5424 # label with log.changeset (instead of log.parent) since this
5446 # shows a working directory parent *changeset*:
5425 # shows a working directory parent *changeset*:
5447 # i18n: column positioning for "hg summary"
5426 # i18n: column positioning for "hg summary"
5448 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5427 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5449 label=cmdutil._changesetlabels(p))
5428 label=cmdutil._changesetlabels(p))
5450 ui.write(' '.join(p.tags()), label='log.tag')
5429 ui.write(' '.join(p.tags()), label='log.tag')
5451 if p.bookmarks():
5430 if p.bookmarks():
5452 marks.extend(p.bookmarks())
5431 marks.extend(p.bookmarks())
5453 if p.rev() == -1:
5432 if p.rev() == -1:
5454 if not len(repo):
5433 if not len(repo):
5455 ui.write(_(' (empty repository)'))
5434 ui.write(_(' (empty repository)'))
5456 else:
5435 else:
5457 ui.write(_(' (no revision checked out)'))
5436 ui.write(_(' (no revision checked out)'))
5458 if p.troubled():
5437 if p.troubled():
5459 ui.write(' ('
5438 ui.write(' ('
5460 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5439 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5461 for trouble in p.troubles())
5440 for trouble in p.troubles())
5462 + ')')
5441 + ')')
5463 ui.write('\n')
5442 ui.write('\n')
5464 if p.description():
5443 if p.description():
5465 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5444 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5466 label='log.summary')
5445 label='log.summary')
5467
5446
5468 branch = ctx.branch()
5447 branch = ctx.branch()
5469 bheads = repo.branchheads(branch)
5448 bheads = repo.branchheads(branch)
5470 # i18n: column positioning for "hg summary"
5449 # i18n: column positioning for "hg summary"
5471 m = _('branch: %s\n') % branch
5450 m = _('branch: %s\n') % branch
5472 if branch != 'default':
5451 if branch != 'default':
5473 ui.write(m, label='log.branch')
5452 ui.write(m, label='log.branch')
5474 else:
5453 else:
5475 ui.status(m, label='log.branch')
5454 ui.status(m, label='log.branch')
5476
5455
5477 if marks:
5456 if marks:
5478 active = repo._activebookmark
5457 active = repo._activebookmark
5479 # i18n: column positioning for "hg summary"
5458 # i18n: column positioning for "hg summary"
5480 ui.write(_('bookmarks:'), label='log.bookmark')
5459 ui.write(_('bookmarks:'), label='log.bookmark')
5481 if active is not None:
5460 if active is not None:
5482 if active in marks:
5461 if active in marks:
5483 ui.write(' *' + active, label=activebookmarklabel)
5462 ui.write(' *' + active, label=activebookmarklabel)
5484 marks.remove(active)
5463 marks.remove(active)
5485 else:
5464 else:
5486 ui.write(' [%s]' % active, label=activebookmarklabel)
5465 ui.write(' [%s]' % active, label=activebookmarklabel)
5487 for m in marks:
5466 for m in marks:
5488 ui.write(' ' + m, label='log.bookmark')
5467 ui.write(' ' + m, label='log.bookmark')
5489 ui.write('\n', label='log.bookmark')
5468 ui.write('\n', label='log.bookmark')
5490
5469
5491 status = repo.status(unknown=True)
5470 status = repo.status(unknown=True)
5492
5471
5493 c = repo.dirstate.copies()
5472 c = repo.dirstate.copies()
5494 copied, renamed = [], []
5473 copied, renamed = [], []
5495 for d, s in c.iteritems():
5474 for d, s in c.iteritems():
5496 if s in status.removed:
5475 if s in status.removed:
5497 status.removed.remove(s)
5476 status.removed.remove(s)
5498 renamed.append(d)
5477 renamed.append(d)
5499 else:
5478 else:
5500 copied.append(d)
5479 copied.append(d)
5501 if d in status.added:
5480 if d in status.added:
5502 status.added.remove(d)
5481 status.added.remove(d)
5503
5482
5504 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5483 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5505
5484
5506 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5485 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5507 (ui.label(_('%d added'), 'status.added'), status.added),
5486 (ui.label(_('%d added'), 'status.added'), status.added),
5508 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5487 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5509 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5488 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5510 (ui.label(_('%d copied'), 'status.copied'), copied),
5489 (ui.label(_('%d copied'), 'status.copied'), copied),
5511 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5490 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5512 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5491 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5513 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5492 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5514 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5493 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5515 t = []
5494 t = []
5516 for l, s in labels:
5495 for l, s in labels:
5517 if s:
5496 if s:
5518 t.append(l % len(s))
5497 t.append(l % len(s))
5519
5498
5520 t = ', '.join(t)
5499 t = ', '.join(t)
5521 cleanworkdir = False
5500 cleanworkdir = False
5522
5501
5523 if repo.vfs.exists('graftstate'):
5502 if repo.vfs.exists('graftstate'):
5524 t += _(' (graft in progress)')
5503 t += _(' (graft in progress)')
5525 if repo.vfs.exists('updatestate'):
5504 if repo.vfs.exists('updatestate'):
5526 t += _(' (interrupted update)')
5505 t += _(' (interrupted update)')
5527 elif len(parents) > 1:
5506 elif len(parents) > 1:
5528 t += _(' (merge)')
5507 t += _(' (merge)')
5529 elif branch != parents[0].branch():
5508 elif branch != parents[0].branch():
5530 t += _(' (new branch)')
5509 t += _(' (new branch)')
5531 elif (parents[0].closesbranch() and
5510 elif (parents[0].closesbranch() and
5532 pnode in repo.branchheads(branch, closed=True)):
5511 pnode in repo.branchheads(branch, closed=True)):
5533 t += _(' (head closed)')
5512 t += _(' (head closed)')
5534 elif not (status.modified or status.added or status.removed or renamed or
5513 elif not (status.modified or status.added or status.removed or renamed or
5535 copied or subs):
5514 copied or subs):
5536 t += _(' (clean)')
5515 t += _(' (clean)')
5537 cleanworkdir = True
5516 cleanworkdir = True
5538 elif pnode not in bheads:
5517 elif pnode not in bheads:
5539 t += _(' (new branch head)')
5518 t += _(' (new branch head)')
5540
5519
5541 if parents:
5520 if parents:
5542 pendingphase = max(p.phase() for p in parents)
5521 pendingphase = max(p.phase() for p in parents)
5543 else:
5522 else:
5544 pendingphase = phases.public
5523 pendingphase = phases.public
5545
5524
5546 if pendingphase > phases.newcommitphase(ui):
5525 if pendingphase > phases.newcommitphase(ui):
5547 t += ' (%s)' % phases.phasenames[pendingphase]
5526 t += ' (%s)' % phases.phasenames[pendingphase]
5548
5527
5549 if cleanworkdir:
5528 if cleanworkdir:
5550 # i18n: column positioning for "hg summary"
5529 # i18n: column positioning for "hg summary"
5551 ui.status(_('commit: %s\n') % t.strip())
5530 ui.status(_('commit: %s\n') % t.strip())
5552 else:
5531 else:
5553 # i18n: column positioning for "hg summary"
5532 # i18n: column positioning for "hg summary"
5554 ui.write(_('commit: %s\n') % t.strip())
5533 ui.write(_('commit: %s\n') % t.strip())
5555
5534
5556 # all ancestors of branch heads - all ancestors of parent = new csets
5535 # all ancestors of branch heads - all ancestors of parent = new csets
5557 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5536 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5558 bheads))
5537 bheads))
5559
5538
5560 if new == 0:
5539 if new == 0:
5561 # i18n: column positioning for "hg summary"
5540 # i18n: column positioning for "hg summary"
5562 ui.status(_('update: (current)\n'))
5541 ui.status(_('update: (current)\n'))
5563 elif pnode not in bheads:
5542 elif pnode not in bheads:
5564 # i18n: column positioning for "hg summary"
5543 # i18n: column positioning for "hg summary"
5565 ui.write(_('update: %d new changesets (update)\n') % new)
5544 ui.write(_('update: %d new changesets (update)\n') % new)
5566 else:
5545 else:
5567 # i18n: column positioning for "hg summary"
5546 # i18n: column positioning for "hg summary"
5568 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5547 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5569 (new, len(bheads)))
5548 (new, len(bheads)))
5570
5549
5571 t = []
5550 t = []
5572 draft = len(repo.revs('draft()'))
5551 draft = len(repo.revs('draft()'))
5573 if draft:
5552 if draft:
5574 t.append(_('%d draft') % draft)
5553 t.append(_('%d draft') % draft)
5575 secret = len(repo.revs('secret()'))
5554 secret = len(repo.revs('secret()'))
5576 if secret:
5555 if secret:
5577 t.append(_('%d secret') % secret)
5556 t.append(_('%d secret') % secret)
5578
5557
5579 if draft or secret:
5558 if draft or secret:
5580 ui.status(_('phases: %s\n') % ', '.join(t))
5559 ui.status(_('phases: %s\n') % ', '.join(t))
5581
5560
5582 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5561 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5583 for trouble in ("unstable", "divergent", "bumped"):
5562 for trouble in ("unstable", "divergent", "bumped"):
5584 numtrouble = len(repo.revs(trouble + "()"))
5563 numtrouble = len(repo.revs(trouble + "()"))
5585 # We write all the possibilities to ease translation
5564 # We write all the possibilities to ease translation
5586 troublemsg = {
5565 troublemsg = {
5587 "unstable": _("unstable: %d changesets"),
5566 "unstable": _("unstable: %d changesets"),
5588 "divergent": _("divergent: %d changesets"),
5567 "divergent": _("divergent: %d changesets"),
5589 "bumped": _("bumped: %d changesets"),
5568 "bumped": _("bumped: %d changesets"),
5590 }
5569 }
5591 if numtrouble > 0:
5570 if numtrouble > 0:
5592 ui.status(troublemsg[trouble] % numtrouble + "\n")
5571 ui.status(troublemsg[trouble] % numtrouble + "\n")
5593
5572
5594 cmdutil.summaryhooks(ui, repo)
5573 cmdutil.summaryhooks(ui, repo)
5595
5574
5596 if opts.get('remote'):
5575 if opts.get('remote'):
5597 needsincoming, needsoutgoing = True, True
5576 needsincoming, needsoutgoing = True, True
5598 else:
5577 else:
5599 needsincoming, needsoutgoing = False, False
5578 needsincoming, needsoutgoing = False, False
5600 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5579 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5601 if i:
5580 if i:
5602 needsincoming = True
5581 needsincoming = True
5603 if o:
5582 if o:
5604 needsoutgoing = True
5583 needsoutgoing = True
5605 if not needsincoming and not needsoutgoing:
5584 if not needsincoming and not needsoutgoing:
5606 return
5585 return
5607
5586
5608 def getincoming():
5587 def getincoming():
5609 source, branches = hg.parseurl(ui.expandpath('default'))
5588 source, branches = hg.parseurl(ui.expandpath('default'))
5610 sbranch = branches[0]
5589 sbranch = branches[0]
5611 try:
5590 try:
5612 other = hg.peer(repo, {}, source)
5591 other = hg.peer(repo, {}, source)
5613 except error.RepoError:
5592 except error.RepoError:
5614 if opts.get('remote'):
5593 if opts.get('remote'):
5615 raise
5594 raise
5616 return source, sbranch, None, None, None
5595 return source, sbranch, None, None, None
5617 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5596 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5618 if revs:
5597 if revs:
5619 revs = [other.lookup(rev) for rev in revs]
5598 revs = [other.lookup(rev) for rev in revs]
5620 ui.debug('comparing with %s\n' % util.hidepassword(source))
5599 ui.debug('comparing with %s\n' % util.hidepassword(source))
5621 repo.ui.pushbuffer()
5600 repo.ui.pushbuffer()
5622 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5601 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5623 repo.ui.popbuffer()
5602 repo.ui.popbuffer()
5624 return source, sbranch, other, commoninc, commoninc[1]
5603 return source, sbranch, other, commoninc, commoninc[1]
5625
5604
5626 if needsincoming:
5605 if needsincoming:
5627 source, sbranch, sother, commoninc, incoming = getincoming()
5606 source, sbranch, sother, commoninc, incoming = getincoming()
5628 else:
5607 else:
5629 source = sbranch = sother = commoninc = incoming = None
5608 source = sbranch = sother = commoninc = incoming = None
5630
5609
5631 def getoutgoing():
5610 def getoutgoing():
5632 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5611 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5633 dbranch = branches[0]
5612 dbranch = branches[0]
5634 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5613 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5635 if source != dest:
5614 if source != dest:
5636 try:
5615 try:
5637 dother = hg.peer(repo, {}, dest)
5616 dother = hg.peer(repo, {}, dest)
5638 except error.RepoError:
5617 except error.RepoError:
5639 if opts.get('remote'):
5618 if opts.get('remote'):
5640 raise
5619 raise
5641 return dest, dbranch, None, None
5620 return dest, dbranch, None, None
5642 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5621 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5643 elif sother is None:
5622 elif sother is None:
5644 # there is no explicit destination peer, but source one is invalid
5623 # there is no explicit destination peer, but source one is invalid
5645 return dest, dbranch, None, None
5624 return dest, dbranch, None, None
5646 else:
5625 else:
5647 dother = sother
5626 dother = sother
5648 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5627 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5649 common = None
5628 common = None
5650 else:
5629 else:
5651 common = commoninc
5630 common = commoninc
5652 if revs:
5631 if revs:
5653 revs = [repo.lookup(rev) for rev in revs]
5632 revs = [repo.lookup(rev) for rev in revs]
5654 repo.ui.pushbuffer()
5633 repo.ui.pushbuffer()
5655 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5634 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5656 commoninc=common)
5635 commoninc=common)
5657 repo.ui.popbuffer()
5636 repo.ui.popbuffer()
5658 return dest, dbranch, dother, outgoing
5637 return dest, dbranch, dother, outgoing
5659
5638
5660 if needsoutgoing:
5639 if needsoutgoing:
5661 dest, dbranch, dother, outgoing = getoutgoing()
5640 dest, dbranch, dother, outgoing = getoutgoing()
5662 else:
5641 else:
5663 dest = dbranch = dother = outgoing = None
5642 dest = dbranch = dother = outgoing = None
5664
5643
5665 if opts.get('remote'):
5644 if opts.get('remote'):
5666 t = []
5645 t = []
5667 if incoming:
5646 if incoming:
5668 t.append(_('1 or more incoming'))
5647 t.append(_('1 or more incoming'))
5669 o = outgoing.missing
5648 o = outgoing.missing
5670 if o:
5649 if o:
5671 t.append(_('%d outgoing') % len(o))
5650 t.append(_('%d outgoing') % len(o))
5672 other = dother or sother
5651 other = dother or sother
5673 if 'bookmarks' in other.listkeys('namespaces'):
5652 if 'bookmarks' in other.listkeys('namespaces'):
5674 counts = bookmarks.summary(repo, other)
5653 counts = bookmarks.summary(repo, other)
5675 if counts[0] > 0:
5654 if counts[0] > 0:
5676 t.append(_('%d incoming bookmarks') % counts[0])
5655 t.append(_('%d incoming bookmarks') % counts[0])
5677 if counts[1] > 0:
5656 if counts[1] > 0:
5678 t.append(_('%d outgoing bookmarks') % counts[1])
5657 t.append(_('%d outgoing bookmarks') % counts[1])
5679
5658
5680 if t:
5659 if t:
5681 # i18n: column positioning for "hg summary"
5660 # i18n: column positioning for "hg summary"
5682 ui.write(_('remote: %s\n') % (', '.join(t)))
5661 ui.write(_('remote: %s\n') % (', '.join(t)))
5683 else:
5662 else:
5684 # i18n: column positioning for "hg summary"
5663 # i18n: column positioning for "hg summary"
5685 ui.status(_('remote: (synced)\n'))
5664 ui.status(_('remote: (synced)\n'))
5686
5665
5687 cmdutil.summaryremotehooks(ui, repo, opts,
5666 cmdutil.summaryremotehooks(ui, repo, opts,
5688 ((source, sbranch, sother, commoninc),
5667 ((source, sbranch, sother, commoninc),
5689 (dest, dbranch, dother, outgoing)))
5668 (dest, dbranch, dother, outgoing)))
5690
5669
5691 @command('tag',
5670 @command('tag',
5692 [('f', 'force', None, _('force tag')),
5671 [('f', 'force', None, _('force tag')),
5693 ('l', 'local', None, _('make the tag local')),
5672 ('l', 'local', None, _('make the tag local')),
5694 ('r', 'rev', '', _('revision to tag'), _('REV')),
5673 ('r', 'rev', '', _('revision to tag'), _('REV')),
5695 ('', 'remove', None, _('remove a tag')),
5674 ('', 'remove', None, _('remove a tag')),
5696 # -l/--local is already there, commitopts cannot be used
5675 # -l/--local is already there, commitopts cannot be used
5697 ('e', 'edit', None, _('invoke editor on commit messages')),
5676 ('e', 'edit', None, _('invoke editor on commit messages')),
5698 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5677 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5699 ] + commitopts2,
5678 ] + commitopts2,
5700 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5679 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5701 def tag(ui, repo, name1, *names, **opts):
5680 def tag(ui, repo, name1, *names, **opts):
5702 """add one or more tags for the current or given revision
5681 """add one or more tags for the current or given revision
5703
5682
5704 Name a particular revision using <name>.
5683 Name a particular revision using <name>.
5705
5684
5706 Tags are used to name particular revisions of the repository and are
5685 Tags are used to name particular revisions of the repository and are
5707 very useful to compare different revisions, to go back to significant
5686 very useful to compare different revisions, to go back to significant
5708 earlier versions or to mark branch points as releases, etc. Changing
5687 earlier versions or to mark branch points as releases, etc. Changing
5709 an existing tag is normally disallowed; use -f/--force to override.
5688 an existing tag is normally disallowed; use -f/--force to override.
5710
5689
5711 If no revision is given, the parent of the working directory is
5690 If no revision is given, the parent of the working directory is
5712 used.
5691 used.
5713
5692
5714 To facilitate version control, distribution, and merging of tags,
5693 To facilitate version control, distribution, and merging of tags,
5715 they are stored as a file named ".hgtags" which is managed similarly
5694 they are stored as a file named ".hgtags" which is managed similarly
5716 to other project files and can be hand-edited if necessary. This
5695 to other project files and can be hand-edited if necessary. This
5717 also means that tagging creates a new commit. The file
5696 also means that tagging creates a new commit. The file
5718 ".hg/localtags" is used for local tags (not shared among
5697 ".hg/localtags" is used for local tags (not shared among
5719 repositories).
5698 repositories).
5720
5699
5721 Tag commits are usually made at the head of a branch. If the parent
5700 Tag commits are usually made at the head of a branch. If the parent
5722 of the working directory is not a branch head, :hg:`tag` aborts; use
5701 of the working directory is not a branch head, :hg:`tag` aborts; use
5723 -f/--force to force the tag commit to be based on a non-head
5702 -f/--force to force the tag commit to be based on a non-head
5724 changeset.
5703 changeset.
5725
5704
5726 See :hg:`help dates` for a list of formats valid for -d/--date.
5705 See :hg:`help dates` for a list of formats valid for -d/--date.
5727
5706
5728 Since tag names have priority over branch names during revision
5707 Since tag names have priority over branch names during revision
5729 lookup, using an existing branch name as a tag name is discouraged.
5708 lookup, using an existing branch name as a tag name is discouraged.
5730
5709
5731 Returns 0 on success.
5710 Returns 0 on success.
5732 """
5711 """
5733 wlock = lock = None
5712 wlock = lock = None
5734 try:
5713 try:
5735 wlock = repo.wlock()
5714 wlock = repo.wlock()
5736 lock = repo.lock()
5715 lock = repo.lock()
5737 rev_ = "."
5716 rev_ = "."
5738 names = [t.strip() for t in (name1,) + names]
5717 names = [t.strip() for t in (name1,) + names]
5739 if len(names) != len(set(names)):
5718 if len(names) != len(set(names)):
5740 raise error.Abort(_('tag names must be unique'))
5719 raise error.Abort(_('tag names must be unique'))
5741 for n in names:
5720 for n in names:
5742 scmutil.checknewlabel(repo, n, 'tag')
5721 scmutil.checknewlabel(repo, n, 'tag')
5743 if not n:
5722 if not n:
5744 raise error.Abort(_('tag names cannot consist entirely of '
5723 raise error.Abort(_('tag names cannot consist entirely of '
5745 'whitespace'))
5724 'whitespace'))
5746 if opts.get('rev') and opts.get('remove'):
5725 if opts.get('rev') and opts.get('remove'):
5747 raise error.Abort(_("--rev and --remove are incompatible"))
5726 raise error.Abort(_("--rev and --remove are incompatible"))
5748 if opts.get('rev'):
5727 if opts.get('rev'):
5749 rev_ = opts['rev']
5728 rev_ = opts['rev']
5750 message = opts.get('message')
5729 message = opts.get('message')
5751 if opts.get('remove'):
5730 if opts.get('remove'):
5752 if opts.get('local'):
5731 if opts.get('local'):
5753 expectedtype = 'local'
5732 expectedtype = 'local'
5754 else:
5733 else:
5755 expectedtype = 'global'
5734 expectedtype = 'global'
5756
5735
5757 for n in names:
5736 for n in names:
5758 if not repo.tagtype(n):
5737 if not repo.tagtype(n):
5759 raise error.Abort(_("tag '%s' does not exist") % n)
5738 raise error.Abort(_("tag '%s' does not exist") % n)
5760 if repo.tagtype(n) != expectedtype:
5739 if repo.tagtype(n) != expectedtype:
5761 if expectedtype == 'global':
5740 if expectedtype == 'global':
5762 raise error.Abort(_("tag '%s' is not a global tag") % n)
5741 raise error.Abort(_("tag '%s' is not a global tag") % n)
5763 else:
5742 else:
5764 raise error.Abort(_("tag '%s' is not a local tag") % n)
5743 raise error.Abort(_("tag '%s' is not a local tag") % n)
5765 rev_ = 'null'
5744 rev_ = 'null'
5766 if not message:
5745 if not message:
5767 # we don't translate commit messages
5746 # we don't translate commit messages
5768 message = 'Removed tag %s' % ', '.join(names)
5747 message = 'Removed tag %s' % ', '.join(names)
5769 elif not opts.get('force'):
5748 elif not opts.get('force'):
5770 for n in names:
5749 for n in names:
5771 if n in repo.tags():
5750 if n in repo.tags():
5772 raise error.Abort(_("tag '%s' already exists "
5751 raise error.Abort(_("tag '%s' already exists "
5773 "(use -f to force)") % n)
5752 "(use -f to force)") % n)
5774 if not opts.get('local'):
5753 if not opts.get('local'):
5775 p1, p2 = repo.dirstate.parents()
5754 p1, p2 = repo.dirstate.parents()
5776 if p2 != nullid:
5755 if p2 != nullid:
5777 raise error.Abort(_('uncommitted merge'))
5756 raise error.Abort(_('uncommitted merge'))
5778 bheads = repo.branchheads()
5757 bheads = repo.branchheads()
5779 if not opts.get('force') and bheads and p1 not in bheads:
5758 if not opts.get('force') and bheads and p1 not in bheads:
5780 raise error.Abort(_('working directory is not at a branch head '
5759 raise error.Abort(_('working directory is not at a branch head '
5781 '(use -f to force)'))
5760 '(use -f to force)'))
5782 r = scmutil.revsingle(repo, rev_).node()
5761 r = scmutil.revsingle(repo, rev_).node()
5783
5762
5784 if not message:
5763 if not message:
5785 # we don't translate commit messages
5764 # we don't translate commit messages
5786 message = ('Added tag %s for changeset %s' %
5765 message = ('Added tag %s for changeset %s' %
5787 (', '.join(names), short(r)))
5766 (', '.join(names), short(r)))
5788
5767
5789 date = opts.get('date')
5768 date = opts.get('date')
5790 if date:
5769 if date:
5791 date = util.parsedate(date)
5770 date = util.parsedate(date)
5792
5771
5793 if opts.get('remove'):
5772 if opts.get('remove'):
5794 editform = 'tag.remove'
5773 editform = 'tag.remove'
5795 else:
5774 else:
5796 editform = 'tag.add'
5775 editform = 'tag.add'
5797 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5776 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5798
5777
5799 # don't allow tagging the null rev
5778 # don't allow tagging the null rev
5800 if (not opts.get('remove') and
5779 if (not opts.get('remove') and
5801 scmutil.revsingle(repo, rev_).rev() == nullrev):
5780 scmutil.revsingle(repo, rev_).rev() == nullrev):
5802 raise error.Abort(_("cannot tag null revision"))
5781 raise error.Abort(_("cannot tag null revision"))
5803
5782
5804 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5783 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5805 editor=editor)
5784 editor=editor)
5806 finally:
5785 finally:
5807 release(lock, wlock)
5786 release(lock, wlock)
5808
5787
5809 @command('tags', formatteropts, '')
5788 @command('tags', formatteropts, '')
5810 def tags(ui, repo, **opts):
5789 def tags(ui, repo, **opts):
5811 """list repository tags
5790 """list repository tags
5812
5791
5813 This lists both regular and local tags. When the -v/--verbose
5792 This lists both regular and local tags. When the -v/--verbose
5814 switch is used, a third column "local" is printed for local tags.
5793 switch is used, a third column "local" is printed for local tags.
5815 When the -q/--quiet switch is used, only the tag name is printed.
5794 When the -q/--quiet switch is used, only the tag name is printed.
5816
5795
5817 Returns 0 on success.
5796 Returns 0 on success.
5818 """
5797 """
5819
5798
5820 fm = ui.formatter('tags', opts)
5799 fm = ui.formatter('tags', opts)
5821 hexfunc = fm.hexfunc
5800 hexfunc = fm.hexfunc
5822 tagtype = ""
5801 tagtype = ""
5823
5802
5824 for t, n in reversed(repo.tagslist()):
5803 for t, n in reversed(repo.tagslist()):
5825 hn = hexfunc(n)
5804 hn = hexfunc(n)
5826 label = 'tags.normal'
5805 label = 'tags.normal'
5827 tagtype = ''
5806 tagtype = ''
5828 if repo.tagtype(t) == 'local':
5807 if repo.tagtype(t) == 'local':
5829 label = 'tags.local'
5808 label = 'tags.local'
5830 tagtype = 'local'
5809 tagtype = 'local'
5831
5810
5832 fm.startitem()
5811 fm.startitem()
5833 fm.write('tag', '%s', t, label=label)
5812 fm.write('tag', '%s', t, label=label)
5834 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5813 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5835 fm.condwrite(not ui.quiet, 'rev node', fmt,
5814 fm.condwrite(not ui.quiet, 'rev node', fmt,
5836 repo.changelog.rev(n), hn, label=label)
5815 repo.changelog.rev(n), hn, label=label)
5837 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5816 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5838 tagtype, label=label)
5817 tagtype, label=label)
5839 fm.plain('\n')
5818 fm.plain('\n')
5840 fm.end()
5819 fm.end()
5841
5820
5842 @command('tip',
5821 @command('tip',
5843 [('p', 'patch', None, _('show patch')),
5822 [('p', 'patch', None, _('show patch')),
5844 ('g', 'git', None, _('use git extended diff format')),
5823 ('g', 'git', None, _('use git extended diff format')),
5845 ] + templateopts,
5824 ] + templateopts,
5846 _('[-p] [-g]'))
5825 _('[-p] [-g]'))
5847 def tip(ui, repo, **opts):
5826 def tip(ui, repo, **opts):
5848 """show the tip revision (DEPRECATED)
5827 """show the tip revision (DEPRECATED)
5849
5828
5850 The tip revision (usually just called the tip) is the changeset
5829 The tip revision (usually just called the tip) is the changeset
5851 most recently added to the repository (and therefore the most
5830 most recently added to the repository (and therefore the most
5852 recently changed head).
5831 recently changed head).
5853
5832
5854 If you have just made a commit, that commit will be the tip. If
5833 If you have just made a commit, that commit will be the tip. If
5855 you have just pulled changes from another repository, the tip of
5834 you have just pulled changes from another repository, the tip of
5856 that repository becomes the current tip. The "tip" tag is special
5835 that repository becomes the current tip. The "tip" tag is special
5857 and cannot be renamed or assigned to a different changeset.
5836 and cannot be renamed or assigned to a different changeset.
5858
5837
5859 This command is deprecated, please use :hg:`heads` instead.
5838 This command is deprecated, please use :hg:`heads` instead.
5860
5839
5861 Returns 0 on success.
5840 Returns 0 on success.
5862 """
5841 """
5863 displayer = cmdutil.show_changeset(ui, repo, opts)
5842 displayer = cmdutil.show_changeset(ui, repo, opts)
5864 displayer.show(repo['tip'])
5843 displayer.show(repo['tip'])
5865 displayer.close()
5844 displayer.close()
5866
5845
5867 @command('unbundle',
5846 @command('unbundle',
5868 [('u', 'update', None,
5847 [('u', 'update', None,
5869 _('update to new branch head if changesets were unbundled'))],
5848 _('update to new branch head if changesets were unbundled'))],
5870 _('[-u] FILE...'))
5849 _('[-u] FILE...'))
5871 def unbundle(ui, repo, fname1, *fnames, **opts):
5850 def unbundle(ui, repo, fname1, *fnames, **opts):
5872 """apply one or more changegroup files
5851 """apply one or more changegroup files
5873
5852
5874 Apply one or more compressed changegroup files generated by the
5853 Apply one or more compressed changegroup files generated by the
5875 bundle command.
5854 bundle command.
5876
5855
5877 Returns 0 on success, 1 if an update has unresolved files.
5856 Returns 0 on success, 1 if an update has unresolved files.
5878 """
5857 """
5879 fnames = (fname1,) + fnames
5858 fnames = (fname1,) + fnames
5880
5859
5881 with repo.lock():
5860 with repo.lock():
5882 for fname in fnames:
5861 for fname in fnames:
5883 f = hg.openpath(ui, fname)
5862 f = hg.openpath(ui, fname)
5884 gen = exchange.readbundle(ui, f, fname)
5863 gen = exchange.readbundle(ui, f, fname)
5885 if isinstance(gen, bundle2.unbundle20):
5864 if isinstance(gen, bundle2.unbundle20):
5886 tr = repo.transaction('unbundle')
5865 tr = repo.transaction('unbundle')
5887 try:
5866 try:
5888 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5867 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5889 url='bundle:' + fname)
5868 url='bundle:' + fname)
5890 tr.close()
5869 tr.close()
5891 except error.BundleUnknownFeatureError as exc:
5870 except error.BundleUnknownFeatureError as exc:
5892 raise error.Abort(_('%s: unknown bundle feature, %s')
5871 raise error.Abort(_('%s: unknown bundle feature, %s')
5893 % (fname, exc),
5872 % (fname, exc),
5894 hint=_("see https://mercurial-scm.org/"
5873 hint=_("see https://mercurial-scm.org/"
5895 "wiki/BundleFeature for more "
5874 "wiki/BundleFeature for more "
5896 "information"))
5875 "information"))
5897 finally:
5876 finally:
5898 if tr:
5877 if tr:
5899 tr.release()
5878 tr.release()
5900 changes = [r.get('return', 0)
5879 changes = [r.get('return', 0)
5901 for r in op.records['changegroup']]
5880 for r in op.records['changegroup']]
5902 modheads = changegroup.combineresults(changes)
5881 modheads = changegroup.combineresults(changes)
5903 elif isinstance(gen, streamclone.streamcloneapplier):
5882 elif isinstance(gen, streamclone.streamcloneapplier):
5904 raise error.Abort(
5883 raise error.Abort(
5905 _('packed bundles cannot be applied with '
5884 _('packed bundles cannot be applied with '
5906 '"hg unbundle"'),
5885 '"hg unbundle"'),
5907 hint=_('use "hg debugapplystreamclonebundle"'))
5886 hint=_('use "hg debugapplystreamclonebundle"'))
5908 else:
5887 else:
5909 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5888 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5910
5889
5911 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5890 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5912
5891
5913 @command('^update|up|checkout|co',
5892 @command('^update|up|checkout|co',
5914 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5893 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5915 ('c', 'check', None, _('require clean working directory')),
5894 ('c', 'check', None, _('require clean working directory')),
5916 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5895 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5917 ('r', 'rev', '', _('revision'), _('REV'))
5896 ('r', 'rev', '', _('revision'), _('REV'))
5918 ] + mergetoolopts,
5897 ] + mergetoolopts,
5919 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5898 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5920 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5899 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5921 tool=None):
5900 tool=None):
5922 """update working directory (or switch revisions)
5901 """update working directory (or switch revisions)
5923
5902
5924 Update the repository's working directory to the specified
5903 Update the repository's working directory to the specified
5925 changeset. If no changeset is specified, update to the tip of the
5904 changeset. If no changeset is specified, update to the tip of the
5926 current named branch and move the active bookmark (see :hg:`help
5905 current named branch and move the active bookmark (see :hg:`help
5927 bookmarks`).
5906 bookmarks`).
5928
5907
5929 Update sets the working directory's parent revision to the specified
5908 Update sets the working directory's parent revision to the specified
5930 changeset (see :hg:`help parents`).
5909 changeset (see :hg:`help parents`).
5931
5910
5932 If the changeset is not a descendant or ancestor of the working
5911 If the changeset is not a descendant or ancestor of the working
5933 directory's parent and there are uncommitted changes, the update is
5912 directory's parent and there are uncommitted changes, the update is
5934 aborted. With the -c/--check option, the working directory is checked
5913 aborted. With the -c/--check option, the working directory is checked
5935 for uncommitted changes; if none are found, the working directory is
5914 for uncommitted changes; if none are found, the working directory is
5936 updated to the specified changeset.
5915 updated to the specified changeset.
5937
5916
5938 .. container:: verbose
5917 .. container:: verbose
5939
5918
5940 The following rules apply when the working directory contains
5919 The following rules apply when the working directory contains
5941 uncommitted changes:
5920 uncommitted changes:
5942
5921
5943 1. If neither -c/--check nor -C/--clean is specified, and if
5922 1. If neither -c/--check nor -C/--clean is specified, and if
5944 the requested changeset is an ancestor or descendant of
5923 the requested changeset is an ancestor or descendant of
5945 the working directory's parent, the uncommitted changes
5924 the working directory's parent, the uncommitted changes
5946 are merged into the requested changeset and the merged
5925 are merged into the requested changeset and the merged
5947 result is left uncommitted. If the requested changeset is
5926 result is left uncommitted. If the requested changeset is
5948 not an ancestor or descendant (that is, it is on another
5927 not an ancestor or descendant (that is, it is on another
5949 branch), the update is aborted and the uncommitted changes
5928 branch), the update is aborted and the uncommitted changes
5950 are preserved.
5929 are preserved.
5951
5930
5952 2. With the -c/--check option, the update is aborted and the
5931 2. With the -c/--check option, the update is aborted and the
5953 uncommitted changes are preserved.
5932 uncommitted changes are preserved.
5954
5933
5955 3. With the -C/--clean option, uncommitted changes are discarded and
5934 3. With the -C/--clean option, uncommitted changes are discarded and
5956 the working directory is updated to the requested changeset.
5935 the working directory is updated to the requested changeset.
5957
5936
5958 To cancel an uncommitted merge (and lose your changes), use
5937 To cancel an uncommitted merge (and lose your changes), use
5959 :hg:`update --clean .`.
5938 :hg:`update --clean .`.
5960
5939
5961 Use null as the changeset to remove the working directory (like
5940 Use null as the changeset to remove the working directory (like
5962 :hg:`clone -U`).
5941 :hg:`clone -U`).
5963
5942
5964 If you want to revert just one file to an older revision, use
5943 If you want to revert just one file to an older revision, use
5965 :hg:`revert [-r REV] NAME`.
5944 :hg:`revert [-r REV] NAME`.
5966
5945
5967 See :hg:`help dates` for a list of formats valid for -d/--date.
5946 See :hg:`help dates` for a list of formats valid for -d/--date.
5968
5947
5969 Returns 0 on success, 1 if there are unresolved files.
5948 Returns 0 on success, 1 if there are unresolved files.
5970 """
5949 """
5971 if rev and node:
5950 if rev and node:
5972 raise error.Abort(_("please specify just one revision"))
5951 raise error.Abort(_("please specify just one revision"))
5973
5952
5974 if rev is None or rev == '':
5953 if rev is None or rev == '':
5975 rev = node
5954 rev = node
5976
5955
5977 if date and rev is not None:
5956 if date and rev is not None:
5978 raise error.Abort(_("you can't specify a revision and a date"))
5957 raise error.Abort(_("you can't specify a revision and a date"))
5979
5958
5980 if check and clean:
5959 if check and clean:
5981 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5960 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5982
5961
5983 with repo.wlock():
5962 with repo.wlock():
5984 cmdutil.clearunfinished(repo)
5963 cmdutil.clearunfinished(repo)
5985
5964
5986 if date:
5965 if date:
5987 rev = cmdutil.finddate(ui, repo, date)
5966 rev = cmdutil.finddate(ui, repo, date)
5988
5967
5989 # if we defined a bookmark, we have to remember the original name
5968 # if we defined a bookmark, we have to remember the original name
5990 brev = rev
5969 brev = rev
5991 rev = scmutil.revsingle(repo, rev, rev).rev()
5970 rev = scmutil.revsingle(repo, rev, rev).rev()
5992
5971
5993 if check:
5972 if check:
5994 cmdutil.bailifchanged(repo, merge=False)
5973 cmdutil.bailifchanged(repo, merge=False)
5995
5974
5996 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5975 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5997
5976
5998 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5977 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5999
5978
6000 @command('verify', [])
5979 @command('verify', [])
6001 def verify(ui, repo):
5980 def verify(ui, repo):
6002 """verify the integrity of the repository
5981 """verify the integrity of the repository
6003
5982
6004 Verify the integrity of the current repository.
5983 Verify the integrity of the current repository.
6005
5984
6006 This will perform an extensive check of the repository's
5985 This will perform an extensive check of the repository's
6007 integrity, validating the hashes and checksums of each entry in
5986 integrity, validating the hashes and checksums of each entry in
6008 the changelog, manifest, and tracked files, as well as the
5987 the changelog, manifest, and tracked files, as well as the
6009 integrity of their crosslinks and indices.
5988 integrity of their crosslinks and indices.
6010
5989
6011 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5990 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6012 for more information about recovery from corruption of the
5991 for more information about recovery from corruption of the
6013 repository.
5992 repository.
6014
5993
6015 Returns 0 on success, 1 if errors are encountered.
5994 Returns 0 on success, 1 if errors are encountered.
6016 """
5995 """
6017 return hg.verify(repo)
5996 return hg.verify(repo)
6018
5997
6019 @command('version', [] + formatteropts, norepo=True)
5998 @command('version', [] + formatteropts, norepo=True)
6020 def version_(ui, **opts):
5999 def version_(ui, **opts):
6021 """output version and copyright information"""
6000 """output version and copyright information"""
6022 fm = ui.formatter("version", opts)
6001 fm = ui.formatter("version", opts)
6023 fm.startitem()
6002 fm.startitem()
6024 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6003 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6025 util.version())
6004 util.version())
6026 license = _(
6005 license = _(
6027 "(see https://mercurial-scm.org for more information)\n"
6006 "(see https://mercurial-scm.org for more information)\n"
6028 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6007 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6029 "This is free software; see the source for copying conditions. "
6008 "This is free software; see the source for copying conditions. "
6030 "There is NO\nwarranty; "
6009 "There is NO\nwarranty; "
6031 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6010 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6032 )
6011 )
6033 if not ui.quiet:
6012 if not ui.quiet:
6034 fm.plain(license)
6013 fm.plain(license)
6035
6014
6036 if ui.verbose:
6015 if ui.verbose:
6037 fm.plain(_("\nEnabled extensions:\n\n"))
6016 fm.plain(_("\nEnabled extensions:\n\n"))
6038 # format names and versions into columns
6017 # format names and versions into columns
6039 names = []
6018 names = []
6040 vers = []
6019 vers = []
6041 isinternals = []
6020 isinternals = []
6042 for name, module in extensions.extensions():
6021 for name, module in extensions.extensions():
6043 names.append(name)
6022 names.append(name)
6044 vers.append(extensions.moduleversion(module) or None)
6023 vers.append(extensions.moduleversion(module) or None)
6045 isinternals.append(extensions.ismoduleinternal(module))
6024 isinternals.append(extensions.ismoduleinternal(module))
6046 fn = fm.nested("extensions")
6025 fn = fm.nested("extensions")
6047 if names:
6026 if names:
6048 namefmt = " %%-%ds " % max(len(n) for n in names)
6027 namefmt = " %%-%ds " % max(len(n) for n in names)
6049 places = [_("external"), _("internal")]
6028 places = [_("external"), _("internal")]
6050 for n, v, p in zip(names, vers, isinternals):
6029 for n, v, p in zip(names, vers, isinternals):
6051 fn.startitem()
6030 fn.startitem()
6052 fn.condwrite(ui.verbose, "name", namefmt, n)
6031 fn.condwrite(ui.verbose, "name", namefmt, n)
6053 if ui.verbose:
6032 if ui.verbose:
6054 fn.plain("%s " % places[p])
6033 fn.plain("%s " % places[p])
6055 fn.data(bundled=p)
6034 fn.data(bundled=p)
6056 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6035 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6057 if ui.verbose:
6036 if ui.verbose:
6058 fn.plain("\n")
6037 fn.plain("\n")
6059 fn.end()
6038 fn.end()
6060 fm.end()
6039 fm.end()
6061
6040
6062 def loadcmdtable(ui, name, cmdtable):
6041 def loadcmdtable(ui, name, cmdtable):
6063 """Load command functions from specified cmdtable
6042 """Load command functions from specified cmdtable
6064 """
6043 """
6065 overrides = [cmd for cmd in cmdtable if cmd in table]
6044 overrides = [cmd for cmd in cmdtable if cmd in table]
6066 if overrides:
6045 if overrides:
6067 ui.warn(_("extension '%s' overrides commands: %s\n")
6046 ui.warn(_("extension '%s' overrides commands: %s\n")
6068 % (name, " ".join(overrides)))
6047 % (name, " ".join(overrides)))
6069 table.update(cmdtable)
6048 table.update(cmdtable)
@@ -1,1440 +1,1461
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 errno
10 import errno
11 import operator
11 import operator
12 import os
12 import os
13 import random
13 import random
14 import socket
14 import socket
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17 import time
17 import time
18
18
19 from .i18n import _
19 from .i18n import _
20 from .node import (
20 from .node import (
21 bin,
21 bin,
22 hex,
22 hex,
23 nullhex,
23 nullhex,
24 nullid,
24 nullid,
25 short,
25 short,
26 )
26 )
27 from . import (
27 from . import (
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 commands,
31 commands,
32 context,
32 context,
33 dagparser,
33 dagparser,
34 dagutil,
34 dagutil,
35 encoding,
35 encoding,
36 error,
36 error,
37 exchange,
37 exchange,
38 extensions,
38 extensions,
39 fileset,
39 fileset,
40 hg,
40 hg,
41 localrepo,
41 localrepo,
42 lock as lockmod,
42 lock as lockmod,
43 merge as mergemod,
43 merge as mergemod,
44 obsolete,
44 obsolete,
45 policy,
45 policy,
46 pycompat,
46 pycompat,
47 repair,
47 repair,
48 revlog,
48 revlog,
49 scmutil,
49 scmutil,
50 setdiscovery,
50 setdiscovery,
51 simplemerge,
51 simplemerge,
52 sslutil,
52 sslutil,
53 streamclone,
53 streamclone,
54 templater,
54 templater,
55 treediscovery,
55 treediscovery,
56 util,
56 util,
57 )
57 )
58
58
59 release = lockmod.release
59 release = lockmod.release
60
60
61 # We reuse the command table from commands because it is easier than
61 # We reuse the command table from commands because it is easier than
62 # teaching dispatch about multiple tables.
62 # teaching dispatch about multiple tables.
63 command = cmdutil.command(commands.table)
63 command = cmdutil.command(commands.table)
64
64
65 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
65 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
66 def debugancestor(ui, repo, *args):
66 def debugancestor(ui, repo, *args):
67 """find the ancestor revision of two revisions in a given index"""
67 """find the ancestor revision of two revisions in a given index"""
68 if len(args) == 3:
68 if len(args) == 3:
69 index, rev1, rev2 = args
69 index, rev1, rev2 = args
70 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
70 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
71 lookup = r.lookup
71 lookup = r.lookup
72 elif len(args) == 2:
72 elif len(args) == 2:
73 if not repo:
73 if not repo:
74 raise error.Abort(_('there is no Mercurial repository here '
74 raise error.Abort(_('there is no Mercurial repository here '
75 '(.hg not found)'))
75 '(.hg not found)'))
76 rev1, rev2 = args
76 rev1, rev2 = args
77 r = repo.changelog
77 r = repo.changelog
78 lookup = repo.lookup
78 lookup = repo.lookup
79 else:
79 else:
80 raise error.Abort(_('either two or three arguments required'))
80 raise error.Abort(_('either two or three arguments required'))
81 a = r.ancestor(lookup(rev1), lookup(rev2))
81 a = r.ancestor(lookup(rev1), lookup(rev2))
82 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
82 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
83
83
84 @command('debugapplystreamclonebundle', [], 'FILE')
84 @command('debugapplystreamclonebundle', [], 'FILE')
85 def debugapplystreamclonebundle(ui, repo, fname):
85 def debugapplystreamclonebundle(ui, repo, fname):
86 """apply a stream clone bundle file"""
86 """apply a stream clone bundle file"""
87 f = hg.openpath(ui, fname)
87 f = hg.openpath(ui, fname)
88 gen = exchange.readbundle(ui, f, fname)
88 gen = exchange.readbundle(ui, f, fname)
89 gen.apply(repo)
89 gen.apply(repo)
90
90
91 @command('debugbuilddag',
91 @command('debugbuilddag',
92 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
92 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
93 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
93 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
94 ('n', 'new-file', None, _('add new file at each rev'))],
94 ('n', 'new-file', None, _('add new file at each rev'))],
95 _('[OPTION]... [TEXT]'))
95 _('[OPTION]... [TEXT]'))
96 def debugbuilddag(ui, repo, text=None,
96 def debugbuilddag(ui, repo, text=None,
97 mergeable_file=False,
97 mergeable_file=False,
98 overwritten_file=False,
98 overwritten_file=False,
99 new_file=False):
99 new_file=False):
100 """builds a repo with a given DAG from scratch in the current empty repo
100 """builds a repo with a given DAG from scratch in the current empty repo
101
101
102 The description of the DAG is read from stdin if not given on the
102 The description of the DAG is read from stdin if not given on the
103 command line.
103 command line.
104
104
105 Elements:
105 Elements:
106
106
107 - "+n" is a linear run of n nodes based on the current default parent
107 - "+n" is a linear run of n nodes based on the current default parent
108 - "." is a single node based on the current default parent
108 - "." is a single node based on the current default parent
109 - "$" resets the default parent to null (implied at the start);
109 - "$" resets the default parent to null (implied at the start);
110 otherwise the default parent is always the last node created
110 otherwise the default parent is always the last node created
111 - "<p" sets the default parent to the backref p
111 - "<p" sets the default parent to the backref p
112 - "*p" is a fork at parent p, which is a backref
112 - "*p" is a fork at parent p, which is a backref
113 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
113 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
114 - "/p2" is a merge of the preceding node and p2
114 - "/p2" is a merge of the preceding node and p2
115 - ":tag" defines a local tag for the preceding node
115 - ":tag" defines a local tag for the preceding node
116 - "@branch" sets the named branch for subsequent nodes
116 - "@branch" sets the named branch for subsequent nodes
117 - "#...\\n" is a comment up to the end of the line
117 - "#...\\n" is a comment up to the end of the line
118
118
119 Whitespace between the above elements is ignored.
119 Whitespace between the above elements is ignored.
120
120
121 A backref is either
121 A backref is either
122
122
123 - a number n, which references the node curr-n, where curr is the current
123 - a number n, which references the node curr-n, where curr is the current
124 node, or
124 node, or
125 - the name of a local tag you placed earlier using ":tag", or
125 - the name of a local tag you placed earlier using ":tag", or
126 - empty to denote the default parent.
126 - empty to denote the default parent.
127
127
128 All string valued-elements are either strictly alphanumeric, or must
128 All string valued-elements are either strictly alphanumeric, or must
129 be enclosed in double quotes ("..."), with "\\" as escape character.
129 be enclosed in double quotes ("..."), with "\\" as escape character.
130 """
130 """
131
131
132 if text is None:
132 if text is None:
133 ui.status(_("reading DAG from stdin\n"))
133 ui.status(_("reading DAG from stdin\n"))
134 text = ui.fin.read()
134 text = ui.fin.read()
135
135
136 cl = repo.changelog
136 cl = repo.changelog
137 if len(cl) > 0:
137 if len(cl) > 0:
138 raise error.Abort(_('repository is not empty'))
138 raise error.Abort(_('repository is not empty'))
139
139
140 # determine number of revs in DAG
140 # determine number of revs in DAG
141 total = 0
141 total = 0
142 for type, data in dagparser.parsedag(text):
142 for type, data in dagparser.parsedag(text):
143 if type == 'n':
143 if type == 'n':
144 total += 1
144 total += 1
145
145
146 if mergeable_file:
146 if mergeable_file:
147 linesperrev = 2
147 linesperrev = 2
148 # make a file with k lines per rev
148 # make a file with k lines per rev
149 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
149 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
150 initialmergedlines.append("")
150 initialmergedlines.append("")
151
151
152 tags = []
152 tags = []
153
153
154 wlock = lock = tr = None
154 wlock = lock = tr = None
155 try:
155 try:
156 wlock = repo.wlock()
156 wlock = repo.wlock()
157 lock = repo.lock()
157 lock = repo.lock()
158 tr = repo.transaction("builddag")
158 tr = repo.transaction("builddag")
159
159
160 at = -1
160 at = -1
161 atbranch = 'default'
161 atbranch = 'default'
162 nodeids = []
162 nodeids = []
163 id = 0
163 id = 0
164 ui.progress(_('building'), id, unit=_('revisions'), total=total)
164 ui.progress(_('building'), id, unit=_('revisions'), total=total)
165 for type, data in dagparser.parsedag(text):
165 for type, data in dagparser.parsedag(text):
166 if type == 'n':
166 if type == 'n':
167 ui.note(('node %s\n' % str(data)))
167 ui.note(('node %s\n' % str(data)))
168 id, ps = data
168 id, ps = data
169
169
170 files = []
170 files = []
171 fctxs = {}
171 fctxs = {}
172
172
173 p2 = None
173 p2 = None
174 if mergeable_file:
174 if mergeable_file:
175 fn = "mf"
175 fn = "mf"
176 p1 = repo[ps[0]]
176 p1 = repo[ps[0]]
177 if len(ps) > 1:
177 if len(ps) > 1:
178 p2 = repo[ps[1]]
178 p2 = repo[ps[1]]
179 pa = p1.ancestor(p2)
179 pa = p1.ancestor(p2)
180 base, local, other = [x[fn].data() for x in (pa, p1,
180 base, local, other = [x[fn].data() for x in (pa, p1,
181 p2)]
181 p2)]
182 m3 = simplemerge.Merge3Text(base, local, other)
182 m3 = simplemerge.Merge3Text(base, local, other)
183 ml = [l.strip() for l in m3.merge_lines()]
183 ml = [l.strip() for l in m3.merge_lines()]
184 ml.append("")
184 ml.append("")
185 elif at > 0:
185 elif at > 0:
186 ml = p1[fn].data().split("\n")
186 ml = p1[fn].data().split("\n")
187 else:
187 else:
188 ml = initialmergedlines
188 ml = initialmergedlines
189 ml[id * linesperrev] += " r%i" % id
189 ml[id * linesperrev] += " r%i" % id
190 mergedtext = "\n".join(ml)
190 mergedtext = "\n".join(ml)
191 files.append(fn)
191 files.append(fn)
192 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
192 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
193
193
194 if overwritten_file:
194 if overwritten_file:
195 fn = "of"
195 fn = "of"
196 files.append(fn)
196 files.append(fn)
197 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
197 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
198
198
199 if new_file:
199 if new_file:
200 fn = "nf%i" % id
200 fn = "nf%i" % id
201 files.append(fn)
201 files.append(fn)
202 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
202 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
203 if len(ps) > 1:
203 if len(ps) > 1:
204 if not p2:
204 if not p2:
205 p2 = repo[ps[1]]
205 p2 = repo[ps[1]]
206 for fn in p2:
206 for fn in p2:
207 if fn.startswith("nf"):
207 if fn.startswith("nf"):
208 files.append(fn)
208 files.append(fn)
209 fctxs[fn] = p2[fn]
209 fctxs[fn] = p2[fn]
210
210
211 def fctxfn(repo, cx, path):
211 def fctxfn(repo, cx, path):
212 return fctxs.get(path)
212 return fctxs.get(path)
213
213
214 if len(ps) == 0 or ps[0] < 0:
214 if len(ps) == 0 or ps[0] < 0:
215 pars = [None, None]
215 pars = [None, None]
216 elif len(ps) == 1:
216 elif len(ps) == 1:
217 pars = [nodeids[ps[0]], None]
217 pars = [nodeids[ps[0]], None]
218 else:
218 else:
219 pars = [nodeids[p] for p in ps]
219 pars = [nodeids[p] for p in ps]
220 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
220 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
221 date=(id, 0),
221 date=(id, 0),
222 user="debugbuilddag",
222 user="debugbuilddag",
223 extra={'branch': atbranch})
223 extra={'branch': atbranch})
224 nodeid = repo.commitctx(cx)
224 nodeid = repo.commitctx(cx)
225 nodeids.append(nodeid)
225 nodeids.append(nodeid)
226 at = id
226 at = id
227 elif type == 'l':
227 elif type == 'l':
228 id, name = data
228 id, name = data
229 ui.note(('tag %s\n' % name))
229 ui.note(('tag %s\n' % name))
230 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
230 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
231 elif type == 'a':
231 elif type == 'a':
232 ui.note(('branch %s\n' % data))
232 ui.note(('branch %s\n' % data))
233 atbranch = data
233 atbranch = data
234 ui.progress(_('building'), id, unit=_('revisions'), total=total)
234 ui.progress(_('building'), id, unit=_('revisions'), total=total)
235 tr.close()
235 tr.close()
236
236
237 if tags:
237 if tags:
238 repo.vfs.write("localtags", "".join(tags))
238 repo.vfs.write("localtags", "".join(tags))
239 finally:
239 finally:
240 ui.progress(_('building'), None)
240 ui.progress(_('building'), None)
241 release(tr, lock, wlock)
241 release(tr, lock, wlock)
242
242
243 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
243 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
244 indent_string = ' ' * indent
244 indent_string = ' ' * indent
245 if all:
245 if all:
246 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
246 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
247 % indent_string)
247 % indent_string)
248
248
249 def showchunks(named):
249 def showchunks(named):
250 ui.write("\n%s%s\n" % (indent_string, named))
250 ui.write("\n%s%s\n" % (indent_string, named))
251 chain = None
251 chain = None
252 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
252 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
253 node = chunkdata['node']
253 node = chunkdata['node']
254 p1 = chunkdata['p1']
254 p1 = chunkdata['p1']
255 p2 = chunkdata['p2']
255 p2 = chunkdata['p2']
256 cs = chunkdata['cs']
256 cs = chunkdata['cs']
257 deltabase = chunkdata['deltabase']
257 deltabase = chunkdata['deltabase']
258 delta = chunkdata['delta']
258 delta = chunkdata['delta']
259 ui.write("%s%s %s %s %s %s %s\n" %
259 ui.write("%s%s %s %s %s %s %s\n" %
260 (indent_string, hex(node), hex(p1), hex(p2),
260 (indent_string, hex(node), hex(p1), hex(p2),
261 hex(cs), hex(deltabase), len(delta)))
261 hex(cs), hex(deltabase), len(delta)))
262 chain = node
262 chain = node
263
263
264 chunkdata = gen.changelogheader()
264 chunkdata = gen.changelogheader()
265 showchunks("changelog")
265 showchunks("changelog")
266 chunkdata = gen.manifestheader()
266 chunkdata = gen.manifestheader()
267 showchunks("manifest")
267 showchunks("manifest")
268 for chunkdata in iter(gen.filelogheader, {}):
268 for chunkdata in iter(gen.filelogheader, {}):
269 fname = chunkdata['filename']
269 fname = chunkdata['filename']
270 showchunks(fname)
270 showchunks(fname)
271 else:
271 else:
272 if isinstance(gen, bundle2.unbundle20):
272 if isinstance(gen, bundle2.unbundle20):
273 raise error.Abort(_('use debugbundle2 for this file'))
273 raise error.Abort(_('use debugbundle2 for this file'))
274 chunkdata = gen.changelogheader()
274 chunkdata = gen.changelogheader()
275 chain = None
275 chain = None
276 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
276 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
277 node = chunkdata['node']
277 node = chunkdata['node']
278 ui.write("%s%s\n" % (indent_string, hex(node)))
278 ui.write("%s%s\n" % (indent_string, hex(node)))
279 chain = node
279 chain = node
280
280
281 def _debugbundle2(ui, gen, all=None, **opts):
281 def _debugbundle2(ui, gen, all=None, **opts):
282 """lists the contents of a bundle2"""
282 """lists the contents of a bundle2"""
283 if not isinstance(gen, bundle2.unbundle20):
283 if not isinstance(gen, bundle2.unbundle20):
284 raise error.Abort(_('not a bundle2 file'))
284 raise error.Abort(_('not a bundle2 file'))
285 ui.write(('Stream params: %s\n' % repr(gen.params)))
285 ui.write(('Stream params: %s\n' % repr(gen.params)))
286 for part in gen.iterparts():
286 for part in gen.iterparts():
287 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
287 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
288 if part.type == 'changegroup':
288 if part.type == 'changegroup':
289 version = part.params.get('version', '01')
289 version = part.params.get('version', '01')
290 cg = changegroup.getunbundler(version, part, 'UN')
290 cg = changegroup.getunbundler(version, part, 'UN')
291 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
291 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
292
292
293 @command('debugbundle',
293 @command('debugbundle',
294 [('a', 'all', None, _('show all details')),
294 [('a', 'all', None, _('show all details')),
295 ('', 'spec', None, _('print the bundlespec of the bundle'))],
295 ('', 'spec', None, _('print the bundlespec of the bundle'))],
296 _('FILE'),
296 _('FILE'),
297 norepo=True)
297 norepo=True)
298 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
298 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
299 """lists the contents of a bundle"""
299 """lists the contents of a bundle"""
300 with hg.openpath(ui, bundlepath) as f:
300 with hg.openpath(ui, bundlepath) as f:
301 if spec:
301 if spec:
302 spec = exchange.getbundlespec(ui, f)
302 spec = exchange.getbundlespec(ui, f)
303 ui.write('%s\n' % spec)
303 ui.write('%s\n' % spec)
304 return
304 return
305
305
306 gen = exchange.readbundle(ui, f, bundlepath)
306 gen = exchange.readbundle(ui, f, bundlepath)
307 if isinstance(gen, bundle2.unbundle20):
307 if isinstance(gen, bundle2.unbundle20):
308 return _debugbundle2(ui, gen, all=all, **opts)
308 return _debugbundle2(ui, gen, all=all, **opts)
309 _debugchangegroup(ui, gen, all=all, **opts)
309 _debugchangegroup(ui, gen, all=all, **opts)
310
310
311 @command('debugcheckstate', [], '')
311 @command('debugcheckstate', [], '')
312 def debugcheckstate(ui, repo):
312 def debugcheckstate(ui, repo):
313 """validate the correctness of the current dirstate"""
313 """validate the correctness of the current dirstate"""
314 parent1, parent2 = repo.dirstate.parents()
314 parent1, parent2 = repo.dirstate.parents()
315 m1 = repo[parent1].manifest()
315 m1 = repo[parent1].manifest()
316 m2 = repo[parent2].manifest()
316 m2 = repo[parent2].manifest()
317 errors = 0
317 errors = 0
318 for f in repo.dirstate:
318 for f in repo.dirstate:
319 state = repo.dirstate[f]
319 state = repo.dirstate[f]
320 if state in "nr" and f not in m1:
320 if state in "nr" and f not in m1:
321 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
321 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
322 errors += 1
322 errors += 1
323 if state in "a" and f in m1:
323 if state in "a" and f in m1:
324 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
324 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
325 errors += 1
325 errors += 1
326 if state in "m" and f not in m1 and f not in m2:
326 if state in "m" and f not in m1 and f not in m2:
327 ui.warn(_("%s in state %s, but not in either manifest\n") %
327 ui.warn(_("%s in state %s, but not in either manifest\n") %
328 (f, state))
328 (f, state))
329 errors += 1
329 errors += 1
330 for f in m1:
330 for f in m1:
331 state = repo.dirstate[f]
331 state = repo.dirstate[f]
332 if state not in "nrm":
332 if state not in "nrm":
333 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
333 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
334 errors += 1
334 errors += 1
335 if errors:
335 if errors:
336 error = _(".hg/dirstate inconsistent with current parent's manifest")
336 error = _(".hg/dirstate inconsistent with current parent's manifest")
337 raise error.Abort(error)
337 raise error.Abort(error)
338
338
339 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
339 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
340 def debugcommands(ui, cmd='', *args):
340 def debugcommands(ui, cmd='', *args):
341 """list all available commands and options"""
341 """list all available commands and options"""
342 for cmd, vals in sorted(commands.table.iteritems()):
342 for cmd, vals in sorted(commands.table.iteritems()):
343 cmd = cmd.split('|')[0].strip('^')
343 cmd = cmd.split('|')[0].strip('^')
344 opts = ', '.join([i[1] for i in vals[1]])
344 opts = ', '.join([i[1] for i in vals[1]])
345 ui.write('%s: %s\n' % (cmd, opts))
345 ui.write('%s: %s\n' % (cmd, opts))
346
346
347 @command('debugcomplete',
347 @command('debugcomplete',
348 [('o', 'options', None, _('show the command options'))],
348 [('o', 'options', None, _('show the command options'))],
349 _('[-o] CMD'),
349 _('[-o] CMD'),
350 norepo=True)
350 norepo=True)
351 def debugcomplete(ui, cmd='', **opts):
351 def debugcomplete(ui, cmd='', **opts):
352 """returns the completion list associated with the given command"""
352 """returns the completion list associated with the given command"""
353
353
354 if opts.get('options'):
354 if opts.get('options'):
355 options = []
355 options = []
356 otables = [commands.globalopts]
356 otables = [commands.globalopts]
357 if cmd:
357 if cmd:
358 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
358 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
359 otables.append(entry[1])
359 otables.append(entry[1])
360 for t in otables:
360 for t in otables:
361 for o in t:
361 for o in t:
362 if "(DEPRECATED)" in o[3]:
362 if "(DEPRECATED)" in o[3]:
363 continue
363 continue
364 if o[0]:
364 if o[0]:
365 options.append('-%s' % o[0])
365 options.append('-%s' % o[0])
366 options.append('--%s' % o[1])
366 options.append('--%s' % o[1])
367 ui.write("%s\n" % "\n".join(options))
367 ui.write("%s\n" % "\n".join(options))
368 return
368 return
369
369
370 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
370 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
371 if ui.verbose:
371 if ui.verbose:
372 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
372 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
373 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
373 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
374
374
375 @command('debugcreatestreamclonebundle', [], 'FILE')
375 @command('debugcreatestreamclonebundle', [], 'FILE')
376 def debugcreatestreamclonebundle(ui, repo, fname):
376 def debugcreatestreamclonebundle(ui, repo, fname):
377 """create a stream clone bundle file
377 """create a stream clone bundle file
378
378
379 Stream bundles are special bundles that are essentially archives of
379 Stream bundles are special bundles that are essentially archives of
380 revlog files. They are commonly used for cloning very quickly.
380 revlog files. They are commonly used for cloning very quickly.
381 """
381 """
382 requirements, gen = streamclone.generatebundlev1(repo)
382 requirements, gen = streamclone.generatebundlev1(repo)
383 changegroup.writechunks(ui, gen, fname)
383 changegroup.writechunks(ui, gen, fname)
384
384
385 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
385 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
386
386
387 @command('debugdag',
387 @command('debugdag',
388 [('t', 'tags', None, _('use tags as labels')),
388 [('t', 'tags', None, _('use tags as labels')),
389 ('b', 'branches', None, _('annotate with branch names')),
389 ('b', 'branches', None, _('annotate with branch names')),
390 ('', 'dots', None, _('use dots for runs')),
390 ('', 'dots', None, _('use dots for runs')),
391 ('s', 'spaces', None, _('separate elements by spaces'))],
391 ('s', 'spaces', None, _('separate elements by spaces'))],
392 _('[OPTION]... [FILE [REV]...]'),
392 _('[OPTION]... [FILE [REV]...]'),
393 optionalrepo=True)
393 optionalrepo=True)
394 def debugdag(ui, repo, file_=None, *revs, **opts):
394 def debugdag(ui, repo, file_=None, *revs, **opts):
395 """format the changelog or an index DAG as a concise textual description
395 """format the changelog or an index DAG as a concise textual description
396
396
397 If you pass a revlog index, the revlog's DAG is emitted. If you list
397 If you pass a revlog index, the revlog's DAG is emitted. If you list
398 revision numbers, they get labeled in the output as rN.
398 revision numbers, they get labeled in the output as rN.
399
399
400 Otherwise, the changelog DAG of the current repo is emitted.
400 Otherwise, the changelog DAG of the current repo is emitted.
401 """
401 """
402 spaces = opts.get('spaces')
402 spaces = opts.get('spaces')
403 dots = opts.get('dots')
403 dots = opts.get('dots')
404 if file_:
404 if file_:
405 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
405 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
406 file_)
406 file_)
407 revs = set((int(r) for r in revs))
407 revs = set((int(r) for r in revs))
408 def events():
408 def events():
409 for r in rlog:
409 for r in rlog:
410 yield 'n', (r, list(p for p in rlog.parentrevs(r)
410 yield 'n', (r, list(p for p in rlog.parentrevs(r)
411 if p != -1))
411 if p != -1))
412 if r in revs:
412 if r in revs:
413 yield 'l', (r, "r%i" % r)
413 yield 'l', (r, "r%i" % r)
414 elif repo:
414 elif repo:
415 cl = repo.changelog
415 cl = repo.changelog
416 tags = opts.get('tags')
416 tags = opts.get('tags')
417 branches = opts.get('branches')
417 branches = opts.get('branches')
418 if tags:
418 if tags:
419 labels = {}
419 labels = {}
420 for l, n in repo.tags().items():
420 for l, n in repo.tags().items():
421 labels.setdefault(cl.rev(n), []).append(l)
421 labels.setdefault(cl.rev(n), []).append(l)
422 def events():
422 def events():
423 b = "default"
423 b = "default"
424 for r in cl:
424 for r in cl:
425 if branches:
425 if branches:
426 newb = cl.read(cl.node(r))[5]['branch']
426 newb = cl.read(cl.node(r))[5]['branch']
427 if newb != b:
427 if newb != b:
428 yield 'a', newb
428 yield 'a', newb
429 b = newb
429 b = newb
430 yield 'n', (r, list(p for p in cl.parentrevs(r)
430 yield 'n', (r, list(p for p in cl.parentrevs(r)
431 if p != -1))
431 if p != -1))
432 if tags:
432 if tags:
433 ls = labels.get(r)
433 ls = labels.get(r)
434 if ls:
434 if ls:
435 for l in ls:
435 for l in ls:
436 yield 'l', (r, l)
436 yield 'l', (r, l)
437 else:
437 else:
438 raise error.Abort(_('need repo for changelog dag'))
438 raise error.Abort(_('need repo for changelog dag'))
439
439
440 for line in dagparser.dagtextlines(events(),
440 for line in dagparser.dagtextlines(events(),
441 addspaces=spaces,
441 addspaces=spaces,
442 wraplabels=True,
442 wraplabels=True,
443 wrapannotations=True,
443 wrapannotations=True,
444 wrapnonlinear=dots,
444 wrapnonlinear=dots,
445 usedots=dots,
445 usedots=dots,
446 maxlinewidth=70):
446 maxlinewidth=70):
447 ui.write(line)
447 ui.write(line)
448 ui.write("\n")
448 ui.write("\n")
449
449
450 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
450 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
451 def debugdata(ui, repo, file_, rev=None, **opts):
451 def debugdata(ui, repo, file_, rev=None, **opts):
452 """dump the contents of a data file revision"""
452 """dump the contents of a data file revision"""
453 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
453 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
454 if rev is not None:
454 if rev is not None:
455 raise error.CommandError('debugdata', _('invalid arguments'))
455 raise error.CommandError('debugdata', _('invalid arguments'))
456 file_, rev = None, file_
456 file_, rev = None, file_
457 elif rev is None:
457 elif rev is None:
458 raise error.CommandError('debugdata', _('invalid arguments'))
458 raise error.CommandError('debugdata', _('invalid arguments'))
459 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
459 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
460 try:
460 try:
461 ui.write(r.revision(r.lookup(rev), raw=True))
461 ui.write(r.revision(r.lookup(rev), raw=True))
462 except KeyError:
462 except KeyError:
463 raise error.Abort(_('invalid revision identifier %s') % rev)
463 raise error.Abort(_('invalid revision identifier %s') % rev)
464
464
465 @command('debugdate',
465 @command('debugdate',
466 [('e', 'extended', None, _('try extended date formats'))],
466 [('e', 'extended', None, _('try extended date formats'))],
467 _('[-e] DATE [RANGE]'),
467 _('[-e] DATE [RANGE]'),
468 norepo=True, optionalrepo=True)
468 norepo=True, optionalrepo=True)
469 def debugdate(ui, date, range=None, **opts):
469 def debugdate(ui, date, range=None, **opts):
470 """parse and display a date"""
470 """parse and display a date"""
471 if opts["extended"]:
471 if opts["extended"]:
472 d = util.parsedate(date, util.extendeddateformats)
472 d = util.parsedate(date, util.extendeddateformats)
473 else:
473 else:
474 d = util.parsedate(date)
474 d = util.parsedate(date)
475 ui.write(("internal: %s %s\n") % d)
475 ui.write(("internal: %s %s\n") % d)
476 ui.write(("standard: %s\n") % util.datestr(d))
476 ui.write(("standard: %s\n") % util.datestr(d))
477 if range:
477 if range:
478 m = util.matchdate(range)
478 m = util.matchdate(range)
479 ui.write(("match: %s\n") % m(d[0]))
479 ui.write(("match: %s\n") % m(d[0]))
480
480
481 @command('debugdeltachain',
481 @command('debugdeltachain',
482 commands.debugrevlogopts + commands.formatteropts,
482 commands.debugrevlogopts + commands.formatteropts,
483 _('-c|-m|FILE'),
483 _('-c|-m|FILE'),
484 optionalrepo=True)
484 optionalrepo=True)
485 def debugdeltachain(ui, repo, file_=None, **opts):
485 def debugdeltachain(ui, repo, file_=None, **opts):
486 """dump information about delta chains in a revlog
486 """dump information about delta chains in a revlog
487
487
488 Output can be templatized. Available template keywords are:
488 Output can be templatized. Available template keywords are:
489
489
490 :``rev``: revision number
490 :``rev``: revision number
491 :``chainid``: delta chain identifier (numbered by unique base)
491 :``chainid``: delta chain identifier (numbered by unique base)
492 :``chainlen``: delta chain length to this revision
492 :``chainlen``: delta chain length to this revision
493 :``prevrev``: previous revision in delta chain
493 :``prevrev``: previous revision in delta chain
494 :``deltatype``: role of delta / how it was computed
494 :``deltatype``: role of delta / how it was computed
495 :``compsize``: compressed size of revision
495 :``compsize``: compressed size of revision
496 :``uncompsize``: uncompressed size of revision
496 :``uncompsize``: uncompressed size of revision
497 :``chainsize``: total size of compressed revisions in chain
497 :``chainsize``: total size of compressed revisions in chain
498 :``chainratio``: total chain size divided by uncompressed revision size
498 :``chainratio``: total chain size divided by uncompressed revision size
499 (new delta chains typically start at ratio 2.00)
499 (new delta chains typically start at ratio 2.00)
500 :``lindist``: linear distance from base revision in delta chain to end
500 :``lindist``: linear distance from base revision in delta chain to end
501 of this revision
501 of this revision
502 :``extradist``: total size of revisions not part of this delta chain from
502 :``extradist``: total size of revisions not part of this delta chain from
503 base of delta chain to end of this revision; a measurement
503 base of delta chain to end of this revision; a measurement
504 of how much extra data we need to read/seek across to read
504 of how much extra data we need to read/seek across to read
505 the delta chain for this revision
505 the delta chain for this revision
506 :``extraratio``: extradist divided by chainsize; another representation of
506 :``extraratio``: extradist divided by chainsize; another representation of
507 how much unrelated data is needed to load this delta chain
507 how much unrelated data is needed to load this delta chain
508 """
508 """
509 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
509 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
510 index = r.index
510 index = r.index
511 generaldelta = r.version & revlog.REVLOGGENERALDELTA
511 generaldelta = r.version & revlog.REVLOGGENERALDELTA
512
512
513 def revinfo(rev):
513 def revinfo(rev):
514 e = index[rev]
514 e = index[rev]
515 compsize = e[1]
515 compsize = e[1]
516 uncompsize = e[2]
516 uncompsize = e[2]
517 chainsize = 0
517 chainsize = 0
518
518
519 if generaldelta:
519 if generaldelta:
520 if e[3] == e[5]:
520 if e[3] == e[5]:
521 deltatype = 'p1'
521 deltatype = 'p1'
522 elif e[3] == e[6]:
522 elif e[3] == e[6]:
523 deltatype = 'p2'
523 deltatype = 'p2'
524 elif e[3] == rev - 1:
524 elif e[3] == rev - 1:
525 deltatype = 'prev'
525 deltatype = 'prev'
526 elif e[3] == rev:
526 elif e[3] == rev:
527 deltatype = 'base'
527 deltatype = 'base'
528 else:
528 else:
529 deltatype = 'other'
529 deltatype = 'other'
530 else:
530 else:
531 if e[3] == rev:
531 if e[3] == rev:
532 deltatype = 'base'
532 deltatype = 'base'
533 else:
533 else:
534 deltatype = 'prev'
534 deltatype = 'prev'
535
535
536 chain = r._deltachain(rev)[0]
536 chain = r._deltachain(rev)[0]
537 for iterrev in chain:
537 for iterrev in chain:
538 e = index[iterrev]
538 e = index[iterrev]
539 chainsize += e[1]
539 chainsize += e[1]
540
540
541 return compsize, uncompsize, deltatype, chain, chainsize
541 return compsize, uncompsize, deltatype, chain, chainsize
542
542
543 fm = ui.formatter('debugdeltachain', opts)
543 fm = ui.formatter('debugdeltachain', opts)
544
544
545 fm.plain(' rev chain# chainlen prev delta '
545 fm.plain(' rev chain# chainlen prev delta '
546 'size rawsize chainsize ratio lindist extradist '
546 'size rawsize chainsize ratio lindist extradist '
547 'extraratio\n')
547 'extraratio\n')
548
548
549 chainbases = {}
549 chainbases = {}
550 for rev in r:
550 for rev in r:
551 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
551 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
552 chainbase = chain[0]
552 chainbase = chain[0]
553 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
553 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
554 basestart = r.start(chainbase)
554 basestart = r.start(chainbase)
555 revstart = r.start(rev)
555 revstart = r.start(rev)
556 lineardist = revstart + comp - basestart
556 lineardist = revstart + comp - basestart
557 extradist = lineardist - chainsize
557 extradist = lineardist - chainsize
558 try:
558 try:
559 prevrev = chain[-2]
559 prevrev = chain[-2]
560 except IndexError:
560 except IndexError:
561 prevrev = -1
561 prevrev = -1
562
562
563 chainratio = float(chainsize) / float(uncomp)
563 chainratio = float(chainsize) / float(uncomp)
564 extraratio = float(extradist) / float(chainsize)
564 extraratio = float(extradist) / float(chainsize)
565
565
566 fm.startitem()
566 fm.startitem()
567 fm.write('rev chainid chainlen prevrev deltatype compsize '
567 fm.write('rev chainid chainlen prevrev deltatype compsize '
568 'uncompsize chainsize chainratio lindist extradist '
568 'uncompsize chainsize chainratio lindist extradist '
569 'extraratio',
569 'extraratio',
570 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
570 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
571 rev, chainid, len(chain), prevrev, deltatype, comp,
571 rev, chainid, len(chain), prevrev, deltatype, comp,
572 uncomp, chainsize, chainratio, lineardist, extradist,
572 uncomp, chainsize, chainratio, lineardist, extradist,
573 extraratio,
573 extraratio,
574 rev=rev, chainid=chainid, chainlen=len(chain),
574 rev=rev, chainid=chainid, chainlen=len(chain),
575 prevrev=prevrev, deltatype=deltatype, compsize=comp,
575 prevrev=prevrev, deltatype=deltatype, compsize=comp,
576 uncompsize=uncomp, chainsize=chainsize,
576 uncompsize=uncomp, chainsize=chainsize,
577 chainratio=chainratio, lindist=lineardist,
577 chainratio=chainratio, lindist=lineardist,
578 extradist=extradist, extraratio=extraratio)
578 extradist=extradist, extraratio=extraratio)
579
579
580 fm.end()
580 fm.end()
581
581
582 @command('debugdiscovery',
582 @command('debugdiscovery',
583 [('', 'old', None, _('use old-style discovery')),
583 [('', 'old', None, _('use old-style discovery')),
584 ('', 'nonheads', None,
584 ('', 'nonheads', None,
585 _('use old-style discovery with non-heads included')),
585 _('use old-style discovery with non-heads included')),
586 ] + commands.remoteopts,
586 ] + commands.remoteopts,
587 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
587 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
588 def debugdiscovery(ui, repo, remoteurl="default", **opts):
588 def debugdiscovery(ui, repo, remoteurl="default", **opts):
589 """runs the changeset discovery protocol in isolation"""
589 """runs the changeset discovery protocol in isolation"""
590 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
590 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
591 opts.get('branch'))
591 opts.get('branch'))
592 remote = hg.peer(repo, opts, remoteurl)
592 remote = hg.peer(repo, opts, remoteurl)
593 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
593 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
594
594
595 # make sure tests are repeatable
595 # make sure tests are repeatable
596 random.seed(12323)
596 random.seed(12323)
597
597
598 def doit(localheads, remoteheads, remote=remote):
598 def doit(localheads, remoteheads, remote=remote):
599 if opts.get('old'):
599 if opts.get('old'):
600 if localheads:
600 if localheads:
601 raise error.Abort('cannot use localheads with old style '
601 raise error.Abort('cannot use localheads with old style '
602 'discovery')
602 'discovery')
603 if not util.safehasattr(remote, 'branches'):
603 if not util.safehasattr(remote, 'branches'):
604 # enable in-client legacy support
604 # enable in-client legacy support
605 remote = localrepo.locallegacypeer(remote.local())
605 remote = localrepo.locallegacypeer(remote.local())
606 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
606 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
607 force=True)
607 force=True)
608 common = set(common)
608 common = set(common)
609 if not opts.get('nonheads'):
609 if not opts.get('nonheads'):
610 ui.write(("unpruned common: %s\n") %
610 ui.write(("unpruned common: %s\n") %
611 " ".join(sorted(short(n) for n in common)))
611 " ".join(sorted(short(n) for n in common)))
612 dag = dagutil.revlogdag(repo.changelog)
612 dag = dagutil.revlogdag(repo.changelog)
613 all = dag.ancestorset(dag.internalizeall(common))
613 all = dag.ancestorset(dag.internalizeall(common))
614 common = dag.externalizeall(dag.headsetofconnecteds(all))
614 common = dag.externalizeall(dag.headsetofconnecteds(all))
615 else:
615 else:
616 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
616 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
617 common = set(common)
617 common = set(common)
618 rheads = set(hds)
618 rheads = set(hds)
619 lheads = set(repo.heads())
619 lheads = set(repo.heads())
620 ui.write(("common heads: %s\n") %
620 ui.write(("common heads: %s\n") %
621 " ".join(sorted(short(n) for n in common)))
621 " ".join(sorted(short(n) for n in common)))
622 if lheads <= common:
622 if lheads <= common:
623 ui.write(("local is subset\n"))
623 ui.write(("local is subset\n"))
624 elif rheads <= common:
624 elif rheads <= common:
625 ui.write(("remote is subset\n"))
625 ui.write(("remote is subset\n"))
626
626
627 serverlogs = opts.get('serverlog')
627 serverlogs = opts.get('serverlog')
628 if serverlogs:
628 if serverlogs:
629 for filename in serverlogs:
629 for filename in serverlogs:
630 with open(filename, 'r') as logfile:
630 with open(filename, 'r') as logfile:
631 line = logfile.readline()
631 line = logfile.readline()
632 while line:
632 while line:
633 parts = line.strip().split(';')
633 parts = line.strip().split(';')
634 op = parts[1]
634 op = parts[1]
635 if op == 'cg':
635 if op == 'cg':
636 pass
636 pass
637 elif op == 'cgss':
637 elif op == 'cgss':
638 doit(parts[2].split(' '), parts[3].split(' '))
638 doit(parts[2].split(' '), parts[3].split(' '))
639 elif op == 'unb':
639 elif op == 'unb':
640 doit(parts[3].split(' '), parts[2].split(' '))
640 doit(parts[3].split(' '), parts[2].split(' '))
641 line = logfile.readline()
641 line = logfile.readline()
642 else:
642 else:
643 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
643 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
644 opts.get('remote_head'))
644 opts.get('remote_head'))
645 localrevs = opts.get('local_head')
645 localrevs = opts.get('local_head')
646 doit(localrevs, remoterevs)
646 doit(localrevs, remoterevs)
647
647
648 @command('debugextensions', commands.formatteropts, [], norepo=True)
648 @command('debugextensions', commands.formatteropts, [], norepo=True)
649 def debugextensions(ui, **opts):
649 def debugextensions(ui, **opts):
650 '''show information about active extensions'''
650 '''show information about active extensions'''
651 exts = extensions.extensions(ui)
651 exts = extensions.extensions(ui)
652 hgver = util.version()
652 hgver = util.version()
653 fm = ui.formatter('debugextensions', opts)
653 fm = ui.formatter('debugextensions', opts)
654 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
654 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
655 isinternal = extensions.ismoduleinternal(extmod)
655 isinternal = extensions.ismoduleinternal(extmod)
656 extsource = extmod.__file__
656 extsource = extmod.__file__
657 if isinternal:
657 if isinternal:
658 exttestedwith = [] # never expose magic string to users
658 exttestedwith = [] # never expose magic string to users
659 else:
659 else:
660 exttestedwith = getattr(extmod, 'testedwith', '').split()
660 exttestedwith = getattr(extmod, 'testedwith', '').split()
661 extbuglink = getattr(extmod, 'buglink', None)
661 extbuglink = getattr(extmod, 'buglink', None)
662
662
663 fm.startitem()
663 fm.startitem()
664
664
665 if ui.quiet or ui.verbose:
665 if ui.quiet or ui.verbose:
666 fm.write('name', '%s\n', extname)
666 fm.write('name', '%s\n', extname)
667 else:
667 else:
668 fm.write('name', '%s', extname)
668 fm.write('name', '%s', extname)
669 if isinternal or hgver in exttestedwith:
669 if isinternal or hgver in exttestedwith:
670 fm.plain('\n')
670 fm.plain('\n')
671 elif not exttestedwith:
671 elif not exttestedwith:
672 fm.plain(_(' (untested!)\n'))
672 fm.plain(_(' (untested!)\n'))
673 else:
673 else:
674 lasttestedversion = exttestedwith[-1]
674 lasttestedversion = exttestedwith[-1]
675 fm.plain(' (%s!)\n' % lasttestedversion)
675 fm.plain(' (%s!)\n' % lasttestedversion)
676
676
677 fm.condwrite(ui.verbose and extsource, 'source',
677 fm.condwrite(ui.verbose and extsource, 'source',
678 _(' location: %s\n'), extsource or "")
678 _(' location: %s\n'), extsource or "")
679
679
680 if ui.verbose:
680 if ui.verbose:
681 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
681 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
682 fm.data(bundled=isinternal)
682 fm.data(bundled=isinternal)
683
683
684 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
684 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
685 _(' tested with: %s\n'),
685 _(' tested with: %s\n'),
686 fm.formatlist(exttestedwith, name='ver'))
686 fm.formatlist(exttestedwith, name='ver'))
687
687
688 fm.condwrite(ui.verbose and extbuglink, 'buglink',
688 fm.condwrite(ui.verbose and extbuglink, 'buglink',
689 _(' bug reporting: %s\n'), extbuglink or "")
689 _(' bug reporting: %s\n'), extbuglink or "")
690
690
691 fm.end()
691 fm.end()
692
692
693 @command('debugfileset',
693 @command('debugfileset',
694 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
694 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
695 _('[-r REV] FILESPEC'))
695 _('[-r REV] FILESPEC'))
696 def debugfileset(ui, repo, expr, **opts):
696 def debugfileset(ui, repo, expr, **opts):
697 '''parse and apply a fileset specification'''
697 '''parse and apply a fileset specification'''
698 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
698 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
699 if ui.verbose:
699 if ui.verbose:
700 tree = fileset.parse(expr)
700 tree = fileset.parse(expr)
701 ui.note(fileset.prettyformat(tree), "\n")
701 ui.note(fileset.prettyformat(tree), "\n")
702
702
703 for f in ctx.getfileset(expr):
703 for f in ctx.getfileset(expr):
704 ui.write("%s\n" % f)
704 ui.write("%s\n" % f)
705
705
706 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
706 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
707 def debugfsinfo(ui, path="."):
707 def debugfsinfo(ui, path="."):
708 """show information detected about current filesystem"""
708 """show information detected about current filesystem"""
709 util.writefile('.debugfsinfo', '')
709 util.writefile('.debugfsinfo', '')
710 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
710 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
711 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
711 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
712 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
712 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
713 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
713 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
714 and 'yes' or 'no'))
714 and 'yes' or 'no'))
715 os.unlink('.debugfsinfo')
715 os.unlink('.debugfsinfo')
716
716
717 @command('debuggetbundle',
717 @command('debuggetbundle',
718 [('H', 'head', [], _('id of head node'), _('ID')),
718 [('H', 'head', [], _('id of head node'), _('ID')),
719 ('C', 'common', [], _('id of common node'), _('ID')),
719 ('C', 'common', [], _('id of common node'), _('ID')),
720 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
720 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
721 _('REPO FILE [-H|-C ID]...'),
721 _('REPO FILE [-H|-C ID]...'),
722 norepo=True)
722 norepo=True)
723 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
723 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
724 """retrieves a bundle from a repo
724 """retrieves a bundle from a repo
725
725
726 Every ID must be a full-length hex node id string. Saves the bundle to the
726 Every ID must be a full-length hex node id string. Saves the bundle to the
727 given file.
727 given file.
728 """
728 """
729 repo = hg.peer(ui, opts, repopath)
729 repo = hg.peer(ui, opts, repopath)
730 if not repo.capable('getbundle'):
730 if not repo.capable('getbundle'):
731 raise error.Abort("getbundle() not supported by target repository")
731 raise error.Abort("getbundle() not supported by target repository")
732 args = {}
732 args = {}
733 if common:
733 if common:
734 args['common'] = [bin(s) for s in common]
734 args['common'] = [bin(s) for s in common]
735 if head:
735 if head:
736 args['heads'] = [bin(s) for s in head]
736 args['heads'] = [bin(s) for s in head]
737 # TODO: get desired bundlecaps from command line.
737 # TODO: get desired bundlecaps from command line.
738 args['bundlecaps'] = None
738 args['bundlecaps'] = None
739 bundle = repo.getbundle('debug', **args)
739 bundle = repo.getbundle('debug', **args)
740
740
741 bundletype = opts.get('type', 'bzip2').lower()
741 bundletype = opts.get('type', 'bzip2').lower()
742 btypes = {'none': 'HG10UN',
742 btypes = {'none': 'HG10UN',
743 'bzip2': 'HG10BZ',
743 'bzip2': 'HG10BZ',
744 'gzip': 'HG10GZ',
744 'gzip': 'HG10GZ',
745 'bundle2': 'HG20'}
745 'bundle2': 'HG20'}
746 bundletype = btypes.get(bundletype)
746 bundletype = btypes.get(bundletype)
747 if bundletype not in bundle2.bundletypes:
747 if bundletype not in bundle2.bundletypes:
748 raise error.Abort(_('unknown bundle type specified with --type'))
748 raise error.Abort(_('unknown bundle type specified with --type'))
749 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
749 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
750
750
751 @command('debugignore', [], '[FILE]')
751 @command('debugignore', [], '[FILE]')
752 def debugignore(ui, repo, *files, **opts):
752 def debugignore(ui, repo, *files, **opts):
753 """display the combined ignore pattern and information about ignored files
753 """display the combined ignore pattern and information about ignored files
754
754
755 With no argument display the combined ignore pattern.
755 With no argument display the combined ignore pattern.
756
756
757 Given space separated file names, shows if the given file is ignored and
757 Given space separated file names, shows if the given file is ignored and
758 if so, show the ignore rule (file and line number) that matched it.
758 if so, show the ignore rule (file and line number) that matched it.
759 """
759 """
760 ignore = repo.dirstate._ignore
760 ignore = repo.dirstate._ignore
761 if not files:
761 if not files:
762 # Show all the patterns
762 # Show all the patterns
763 includepat = getattr(ignore, 'includepat', None)
763 includepat = getattr(ignore, 'includepat', None)
764 if includepat is not None:
764 if includepat is not None:
765 ui.write("%s\n" % includepat)
765 ui.write("%s\n" % includepat)
766 else:
766 else:
767 raise error.Abort(_("no ignore patterns found"))
767 raise error.Abort(_("no ignore patterns found"))
768 else:
768 else:
769 for f in files:
769 for f in files:
770 nf = util.normpath(f)
770 nf = util.normpath(f)
771 ignored = None
771 ignored = None
772 ignoredata = None
772 ignoredata = None
773 if nf != '.':
773 if nf != '.':
774 if ignore(nf):
774 if ignore(nf):
775 ignored = nf
775 ignored = nf
776 ignoredata = repo.dirstate._ignorefileandline(nf)
776 ignoredata = repo.dirstate._ignorefileandline(nf)
777 else:
777 else:
778 for p in util.finddirs(nf):
778 for p in util.finddirs(nf):
779 if ignore(p):
779 if ignore(p):
780 ignored = p
780 ignored = p
781 ignoredata = repo.dirstate._ignorefileandline(p)
781 ignoredata = repo.dirstate._ignorefileandline(p)
782 break
782 break
783 if ignored:
783 if ignored:
784 if ignored == nf:
784 if ignored == nf:
785 ui.write(_("%s is ignored\n") % f)
785 ui.write(_("%s is ignored\n") % f)
786 else:
786 else:
787 ui.write(_("%s is ignored because of "
787 ui.write(_("%s is ignored because of "
788 "containing folder %s\n")
788 "containing folder %s\n")
789 % (f, ignored))
789 % (f, ignored))
790 ignorefile, lineno, line = ignoredata
790 ignorefile, lineno, line = ignoredata
791 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
791 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
792 % (ignorefile, lineno, line))
792 % (ignorefile, lineno, line))
793 else:
793 else:
794 ui.write(_("%s is not ignored\n") % f)
794 ui.write(_("%s is not ignored\n") % f)
795
795
796 @command('debugindex', commands.debugrevlogopts +
796 @command('debugindex', commands.debugrevlogopts +
797 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
797 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
798 _('[-f FORMAT] -c|-m|FILE'),
798 _('[-f FORMAT] -c|-m|FILE'),
799 optionalrepo=True)
799 optionalrepo=True)
800 def debugindex(ui, repo, file_=None, **opts):
800 def debugindex(ui, repo, file_=None, **opts):
801 """dump the contents of an index file"""
801 """dump the contents of an index file"""
802 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
802 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
803 format = opts.get('format', 0)
803 format = opts.get('format', 0)
804 if format not in (0, 1):
804 if format not in (0, 1):
805 raise error.Abort(_("unknown format %d") % format)
805 raise error.Abort(_("unknown format %d") % format)
806
806
807 generaldelta = r.version & revlog.REVLOGGENERALDELTA
807 generaldelta = r.version & revlog.REVLOGGENERALDELTA
808 if generaldelta:
808 if generaldelta:
809 basehdr = ' delta'
809 basehdr = ' delta'
810 else:
810 else:
811 basehdr = ' base'
811 basehdr = ' base'
812
812
813 if ui.debugflag:
813 if ui.debugflag:
814 shortfn = hex
814 shortfn = hex
815 else:
815 else:
816 shortfn = short
816 shortfn = short
817
817
818 # There might not be anything in r, so have a sane default
818 # There might not be anything in r, so have a sane default
819 idlen = 12
819 idlen = 12
820 for i in r:
820 for i in r:
821 idlen = len(shortfn(r.node(i)))
821 idlen = len(shortfn(r.node(i)))
822 break
822 break
823
823
824 if format == 0:
824 if format == 0:
825 ui.write((" rev offset length " + basehdr + " linkrev"
825 ui.write((" rev offset length " + basehdr + " linkrev"
826 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
826 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
827 elif format == 1:
827 elif format == 1:
828 ui.write((" rev flag offset length"
828 ui.write((" rev flag offset length"
829 " size " + basehdr + " link p1 p2"
829 " size " + basehdr + " link p1 p2"
830 " %s\n") % "nodeid".rjust(idlen))
830 " %s\n") % "nodeid".rjust(idlen))
831
831
832 for i in r:
832 for i in r:
833 node = r.node(i)
833 node = r.node(i)
834 if generaldelta:
834 if generaldelta:
835 base = r.deltaparent(i)
835 base = r.deltaparent(i)
836 else:
836 else:
837 base = r.chainbase(i)
837 base = r.chainbase(i)
838 if format == 0:
838 if format == 0:
839 try:
839 try:
840 pp = r.parents(node)
840 pp = r.parents(node)
841 except Exception:
841 except Exception:
842 pp = [nullid, nullid]
842 pp = [nullid, nullid]
843 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
843 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
844 i, r.start(i), r.length(i), base, r.linkrev(i),
844 i, r.start(i), r.length(i), base, r.linkrev(i),
845 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
845 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
846 elif format == 1:
846 elif format == 1:
847 pr = r.parentrevs(i)
847 pr = r.parentrevs(i)
848 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
848 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
849 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
849 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
850 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
850 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
851
851
852 @command('debugindexdot', commands.debugrevlogopts,
852 @command('debugindexdot', commands.debugrevlogopts,
853 _('-c|-m|FILE'), optionalrepo=True)
853 _('-c|-m|FILE'), optionalrepo=True)
854 def debugindexdot(ui, repo, file_=None, **opts):
854 def debugindexdot(ui, repo, file_=None, **opts):
855 """dump an index DAG as a graphviz dot file"""
855 """dump an index DAG as a graphviz dot file"""
856 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
856 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
857 ui.write(("digraph G {\n"))
857 ui.write(("digraph G {\n"))
858 for i in r:
858 for i in r:
859 node = r.node(i)
859 node = r.node(i)
860 pp = r.parents(node)
860 pp = r.parents(node)
861 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
861 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
862 if pp[1] != nullid:
862 if pp[1] != nullid:
863 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
863 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
864 ui.write("}\n")
864 ui.write("}\n")
865
865
866 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
866 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
867 def debuginstall(ui, **opts):
867 def debuginstall(ui, **opts):
868 '''test Mercurial installation
868 '''test Mercurial installation
869
869
870 Returns 0 on success.
870 Returns 0 on success.
871 '''
871 '''
872
872
873 def writetemp(contents):
873 def writetemp(contents):
874 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
874 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
875 f = os.fdopen(fd, "wb")
875 f = os.fdopen(fd, "wb")
876 f.write(contents)
876 f.write(contents)
877 f.close()
877 f.close()
878 return name
878 return name
879
879
880 problems = 0
880 problems = 0
881
881
882 fm = ui.formatter('debuginstall', opts)
882 fm = ui.formatter('debuginstall', opts)
883 fm.startitem()
883 fm.startitem()
884
884
885 # encoding
885 # encoding
886 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
886 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
887 err = None
887 err = None
888 try:
888 try:
889 encoding.fromlocal("test")
889 encoding.fromlocal("test")
890 except error.Abort as inst:
890 except error.Abort as inst:
891 err = inst
891 err = inst
892 problems += 1
892 problems += 1
893 fm.condwrite(err, 'encodingerror', _(" %s\n"
893 fm.condwrite(err, 'encodingerror', _(" %s\n"
894 " (check that your locale is properly set)\n"), err)
894 " (check that your locale is properly set)\n"), err)
895
895
896 # Python
896 # Python
897 fm.write('pythonexe', _("checking Python executable (%s)\n"),
897 fm.write('pythonexe', _("checking Python executable (%s)\n"),
898 pycompat.sysexecutable)
898 pycompat.sysexecutable)
899 fm.write('pythonver', _("checking Python version (%s)\n"),
899 fm.write('pythonver', _("checking Python version (%s)\n"),
900 ("%d.%d.%d" % sys.version_info[:3]))
900 ("%d.%d.%d" % sys.version_info[:3]))
901 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
901 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
902 os.path.dirname(pycompat.fsencode(os.__file__)))
902 os.path.dirname(pycompat.fsencode(os.__file__)))
903
903
904 security = set(sslutil.supportedprotocols)
904 security = set(sslutil.supportedprotocols)
905 if sslutil.hassni:
905 if sslutil.hassni:
906 security.add('sni')
906 security.add('sni')
907
907
908 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
908 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
909 fm.formatlist(sorted(security), name='protocol',
909 fm.formatlist(sorted(security), name='protocol',
910 fmt='%s', sep=','))
910 fmt='%s', sep=','))
911
911
912 # These are warnings, not errors. So don't increment problem count. This
912 # These are warnings, not errors. So don't increment problem count. This
913 # may change in the future.
913 # may change in the future.
914 if 'tls1.2' not in security:
914 if 'tls1.2' not in security:
915 fm.plain(_(' TLS 1.2 not supported by Python install; '
915 fm.plain(_(' TLS 1.2 not supported by Python install; '
916 'network connections lack modern security\n'))
916 'network connections lack modern security\n'))
917 if 'sni' not in security:
917 if 'sni' not in security:
918 fm.plain(_(' SNI not supported by Python install; may have '
918 fm.plain(_(' SNI not supported by Python install; may have '
919 'connectivity issues with some servers\n'))
919 'connectivity issues with some servers\n'))
920
920
921 # TODO print CA cert info
921 # TODO print CA cert info
922
922
923 # hg version
923 # hg version
924 hgver = util.version()
924 hgver = util.version()
925 fm.write('hgver', _("checking Mercurial version (%s)\n"),
925 fm.write('hgver', _("checking Mercurial version (%s)\n"),
926 hgver.split('+')[0])
926 hgver.split('+')[0])
927 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
927 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
928 '+'.join(hgver.split('+')[1:]))
928 '+'.join(hgver.split('+')[1:]))
929
929
930 # compiled modules
930 # compiled modules
931 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
931 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
932 policy.policy)
932 policy.policy)
933 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
933 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
934 os.path.dirname(__file__))
934 os.path.dirname(__file__))
935
935
936 err = None
936 err = None
937 try:
937 try:
938 from . import (
938 from . import (
939 base85,
939 base85,
940 bdiff,
940 bdiff,
941 mpatch,
941 mpatch,
942 osutil,
942 osutil,
943 )
943 )
944 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
944 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
945 except Exception as inst:
945 except Exception as inst:
946 err = inst
946 err = inst
947 problems += 1
947 problems += 1
948 fm.condwrite(err, 'extensionserror', " %s\n", err)
948 fm.condwrite(err, 'extensionserror', " %s\n", err)
949
949
950 compengines = util.compengines._engines.values()
950 compengines = util.compengines._engines.values()
951 fm.write('compengines', _('checking registered compression engines (%s)\n'),
951 fm.write('compengines', _('checking registered compression engines (%s)\n'),
952 fm.formatlist(sorted(e.name() for e in compengines),
952 fm.formatlist(sorted(e.name() for e in compengines),
953 name='compengine', fmt='%s', sep=', '))
953 name='compengine', fmt='%s', sep=', '))
954 fm.write('compenginesavail', _('checking available compression engines '
954 fm.write('compenginesavail', _('checking available compression engines '
955 '(%s)\n'),
955 '(%s)\n'),
956 fm.formatlist(sorted(e.name() for e in compengines
956 fm.formatlist(sorted(e.name() for e in compengines
957 if e.available()),
957 if e.available()),
958 name='compengine', fmt='%s', sep=', '))
958 name='compengine', fmt='%s', sep=', '))
959 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
959 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
960 fm.write('compenginesserver', _('checking available compression engines '
960 fm.write('compenginesserver', _('checking available compression engines '
961 'for wire protocol (%s)\n'),
961 'for wire protocol (%s)\n'),
962 fm.formatlist([e.name() for e in wirecompengines
962 fm.formatlist([e.name() for e in wirecompengines
963 if e.wireprotosupport()],
963 if e.wireprotosupport()],
964 name='compengine', fmt='%s', sep=', '))
964 name='compengine', fmt='%s', sep=', '))
965
965
966 # templates
966 # templates
967 p = templater.templatepaths()
967 p = templater.templatepaths()
968 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
968 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
969 fm.condwrite(not p, '', _(" no template directories found\n"))
969 fm.condwrite(not p, '', _(" no template directories found\n"))
970 if p:
970 if p:
971 m = templater.templatepath("map-cmdline.default")
971 m = templater.templatepath("map-cmdline.default")
972 if m:
972 if m:
973 # template found, check if it is working
973 # template found, check if it is working
974 err = None
974 err = None
975 try:
975 try:
976 templater.templater.frommapfile(m)
976 templater.templater.frommapfile(m)
977 except Exception as inst:
977 except Exception as inst:
978 err = inst
978 err = inst
979 p = None
979 p = None
980 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
980 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
981 else:
981 else:
982 p = None
982 p = None
983 fm.condwrite(p, 'defaulttemplate',
983 fm.condwrite(p, 'defaulttemplate',
984 _("checking default template (%s)\n"), m)
984 _("checking default template (%s)\n"), m)
985 fm.condwrite(not m, 'defaulttemplatenotfound',
985 fm.condwrite(not m, 'defaulttemplatenotfound',
986 _(" template '%s' not found\n"), "default")
986 _(" template '%s' not found\n"), "default")
987 if not p:
987 if not p:
988 problems += 1
988 problems += 1
989 fm.condwrite(not p, '',
989 fm.condwrite(not p, '',
990 _(" (templates seem to have been installed incorrectly)\n"))
990 _(" (templates seem to have been installed incorrectly)\n"))
991
991
992 # editor
992 # editor
993 editor = ui.geteditor()
993 editor = ui.geteditor()
994 editor = util.expandpath(editor)
994 editor = util.expandpath(editor)
995 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
995 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
996 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
996 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
997 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
997 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
998 _(" No commit editor set and can't find %s in PATH\n"
998 _(" No commit editor set and can't find %s in PATH\n"
999 " (specify a commit editor in your configuration"
999 " (specify a commit editor in your configuration"
1000 " file)\n"), not cmdpath and editor == 'vi' and editor)
1000 " file)\n"), not cmdpath and editor == 'vi' and editor)
1001 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1001 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1002 _(" Can't find editor '%s' in PATH\n"
1002 _(" Can't find editor '%s' in PATH\n"
1003 " (specify a commit editor in your configuration"
1003 " (specify a commit editor in your configuration"
1004 " file)\n"), not cmdpath and editor)
1004 " file)\n"), not cmdpath and editor)
1005 if not cmdpath and editor != 'vi':
1005 if not cmdpath and editor != 'vi':
1006 problems += 1
1006 problems += 1
1007
1007
1008 # check username
1008 # check username
1009 username = None
1009 username = None
1010 err = None
1010 err = None
1011 try:
1011 try:
1012 username = ui.username()
1012 username = ui.username()
1013 except error.Abort as e:
1013 except error.Abort as e:
1014 err = e
1014 err = e
1015 problems += 1
1015 problems += 1
1016
1016
1017 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1017 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1018 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1018 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1019 " (specify a username in your configuration file)\n"), err)
1019 " (specify a username in your configuration file)\n"), err)
1020
1020
1021 fm.condwrite(not problems, '',
1021 fm.condwrite(not problems, '',
1022 _("no problems detected\n"))
1022 _("no problems detected\n"))
1023 if not problems:
1023 if not problems:
1024 fm.data(problems=problems)
1024 fm.data(problems=problems)
1025 fm.condwrite(problems, 'problems',
1025 fm.condwrite(problems, 'problems',
1026 _("%d problems detected,"
1026 _("%d problems detected,"
1027 " please check your install!\n"), problems)
1027 " please check your install!\n"), problems)
1028 fm.end()
1028 fm.end()
1029
1029
1030 return problems
1030 return problems
1031
1031
1032 @command('debugknown', [], _('REPO ID...'), norepo=True)
1032 @command('debugknown', [], _('REPO ID...'), norepo=True)
1033 def debugknown(ui, repopath, *ids, **opts):
1033 def debugknown(ui, repopath, *ids, **opts):
1034 """test whether node ids are known to a repo
1034 """test whether node ids are known to a repo
1035
1035
1036 Every ID must be a full-length hex node id string. Returns a list of 0s
1036 Every ID must be a full-length hex node id string. Returns a list of 0s
1037 and 1s indicating unknown/known.
1037 and 1s indicating unknown/known.
1038 """
1038 """
1039 repo = hg.peer(ui, opts, repopath)
1039 repo = hg.peer(ui, opts, repopath)
1040 if not repo.capable('known'):
1040 if not repo.capable('known'):
1041 raise error.Abort("known() not supported by target repository")
1041 raise error.Abort("known() not supported by target repository")
1042 flags = repo.known([bin(s) for s in ids])
1042 flags = repo.known([bin(s) for s in ids])
1043 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1043 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1044
1044
1045 @command('debuglabelcomplete', [], _('LABEL...'))
1045 @command('debuglabelcomplete', [], _('LABEL...'))
1046 def debuglabelcomplete(ui, repo, *args):
1046 def debuglabelcomplete(ui, repo, *args):
1047 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1047 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1048 commands.debugnamecomplete(ui, repo, *args)
1048 commands.debugnamecomplete(ui, repo, *args)
1049
1049
1050 @command('debuglocks',
1050 @command('debuglocks',
1051 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1051 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1052 ('W', 'force-wlock', None,
1052 ('W', 'force-wlock', None,
1053 _('free the working state lock (DANGEROUS)'))],
1053 _('free the working state lock (DANGEROUS)'))],
1054 _('[OPTION]...'))
1054 _('[OPTION]...'))
1055 def debuglocks(ui, repo, **opts):
1055 def debuglocks(ui, repo, **opts):
1056 """show or modify state of locks
1056 """show or modify state of locks
1057
1057
1058 By default, this command will show which locks are held. This
1058 By default, this command will show which locks are held. This
1059 includes the user and process holding the lock, the amount of time
1059 includes the user and process holding the lock, the amount of time
1060 the lock has been held, and the machine name where the process is
1060 the lock has been held, and the machine name where the process is
1061 running if it's not local.
1061 running if it's not local.
1062
1062
1063 Locks protect the integrity of Mercurial's data, so should be
1063 Locks protect the integrity of Mercurial's data, so should be
1064 treated with care. System crashes or other interruptions may cause
1064 treated with care. System crashes or other interruptions may cause
1065 locks to not be properly released, though Mercurial will usually
1065 locks to not be properly released, though Mercurial will usually
1066 detect and remove such stale locks automatically.
1066 detect and remove such stale locks automatically.
1067
1067
1068 However, detecting stale locks may not always be possible (for
1068 However, detecting stale locks may not always be possible (for
1069 instance, on a shared filesystem). Removing locks may also be
1069 instance, on a shared filesystem). Removing locks may also be
1070 blocked by filesystem permissions.
1070 blocked by filesystem permissions.
1071
1071
1072 Returns 0 if no locks are held.
1072 Returns 0 if no locks are held.
1073
1073
1074 """
1074 """
1075
1075
1076 if opts.get('force_lock'):
1076 if opts.get('force_lock'):
1077 repo.svfs.unlink('lock')
1077 repo.svfs.unlink('lock')
1078 if opts.get('force_wlock'):
1078 if opts.get('force_wlock'):
1079 repo.vfs.unlink('wlock')
1079 repo.vfs.unlink('wlock')
1080 if opts.get('force_lock') or opts.get('force_lock'):
1080 if opts.get('force_lock') or opts.get('force_lock'):
1081 return 0
1081 return 0
1082
1082
1083 now = time.time()
1083 now = time.time()
1084 held = 0
1084 held = 0
1085
1085
1086 def report(vfs, name, method):
1086 def report(vfs, name, method):
1087 # this causes stale locks to get reaped for more accurate reporting
1087 # this causes stale locks to get reaped for more accurate reporting
1088 try:
1088 try:
1089 l = method(False)
1089 l = method(False)
1090 except error.LockHeld:
1090 except error.LockHeld:
1091 l = None
1091 l = None
1092
1092
1093 if l:
1093 if l:
1094 l.release()
1094 l.release()
1095 else:
1095 else:
1096 try:
1096 try:
1097 stat = vfs.lstat(name)
1097 stat = vfs.lstat(name)
1098 age = now - stat.st_mtime
1098 age = now - stat.st_mtime
1099 user = util.username(stat.st_uid)
1099 user = util.username(stat.st_uid)
1100 locker = vfs.readlock(name)
1100 locker = vfs.readlock(name)
1101 if ":" in locker:
1101 if ":" in locker:
1102 host, pid = locker.split(':')
1102 host, pid = locker.split(':')
1103 if host == socket.gethostname():
1103 if host == socket.gethostname():
1104 locker = 'user %s, process %s' % (user, pid)
1104 locker = 'user %s, process %s' % (user, pid)
1105 else:
1105 else:
1106 locker = 'user %s, process %s, host %s' \
1106 locker = 'user %s, process %s, host %s' \
1107 % (user, pid, host)
1107 % (user, pid, host)
1108 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1108 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1109 return 1
1109 return 1
1110 except OSError as e:
1110 except OSError as e:
1111 if e.errno != errno.ENOENT:
1111 if e.errno != errno.ENOENT:
1112 raise
1112 raise
1113
1113
1114 ui.write(("%-6s free\n") % (name + ":"))
1114 ui.write(("%-6s free\n") % (name + ":"))
1115 return 0
1115 return 0
1116
1116
1117 held += report(repo.svfs, "lock", repo.lock)
1117 held += report(repo.svfs, "lock", repo.lock)
1118 held += report(repo.vfs, "wlock", repo.wlock)
1118 held += report(repo.vfs, "wlock", repo.wlock)
1119
1119
1120 return held
1120 return held
1121
1121
1122 @command('debugmergestate', [], '')
1122 @command('debugmergestate', [], '')
1123 def debugmergestate(ui, repo, *args):
1123 def debugmergestate(ui, repo, *args):
1124 """print merge state
1124 """print merge state
1125
1125
1126 Use --verbose to print out information about whether v1 or v2 merge state
1126 Use --verbose to print out information about whether v1 or v2 merge state
1127 was chosen."""
1127 was chosen."""
1128 def _hashornull(h):
1128 def _hashornull(h):
1129 if h == nullhex:
1129 if h == nullhex:
1130 return 'null'
1130 return 'null'
1131 else:
1131 else:
1132 return h
1132 return h
1133
1133
1134 def printrecords(version):
1134 def printrecords(version):
1135 ui.write(('* version %s records\n') % version)
1135 ui.write(('* version %s records\n') % version)
1136 if version == 1:
1136 if version == 1:
1137 records = v1records
1137 records = v1records
1138 else:
1138 else:
1139 records = v2records
1139 records = v2records
1140
1140
1141 for rtype, record in records:
1141 for rtype, record in records:
1142 # pretty print some record types
1142 # pretty print some record types
1143 if rtype == 'L':
1143 if rtype == 'L':
1144 ui.write(('local: %s\n') % record)
1144 ui.write(('local: %s\n') % record)
1145 elif rtype == 'O':
1145 elif rtype == 'O':
1146 ui.write(('other: %s\n') % record)
1146 ui.write(('other: %s\n') % record)
1147 elif rtype == 'm':
1147 elif rtype == 'm':
1148 driver, mdstate = record.split('\0', 1)
1148 driver, mdstate = record.split('\0', 1)
1149 ui.write(('merge driver: %s (state "%s")\n')
1149 ui.write(('merge driver: %s (state "%s")\n')
1150 % (driver, mdstate))
1150 % (driver, mdstate))
1151 elif rtype in 'FDC':
1151 elif rtype in 'FDC':
1152 r = record.split('\0')
1152 r = record.split('\0')
1153 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1153 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1154 if version == 1:
1154 if version == 1:
1155 onode = 'not stored in v1 format'
1155 onode = 'not stored in v1 format'
1156 flags = r[7]
1156 flags = r[7]
1157 else:
1157 else:
1158 onode, flags = r[7:9]
1158 onode, flags = r[7:9]
1159 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1159 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1160 % (f, rtype, state, _hashornull(hash)))
1160 % (f, rtype, state, _hashornull(hash)))
1161 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1161 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1162 ui.write((' ancestor path: %s (node %s)\n')
1162 ui.write((' ancestor path: %s (node %s)\n')
1163 % (afile, _hashornull(anode)))
1163 % (afile, _hashornull(anode)))
1164 ui.write((' other path: %s (node %s)\n')
1164 ui.write((' other path: %s (node %s)\n')
1165 % (ofile, _hashornull(onode)))
1165 % (ofile, _hashornull(onode)))
1166 elif rtype == 'f':
1166 elif rtype == 'f':
1167 filename, rawextras = record.split('\0', 1)
1167 filename, rawextras = record.split('\0', 1)
1168 extras = rawextras.split('\0')
1168 extras = rawextras.split('\0')
1169 i = 0
1169 i = 0
1170 extrastrings = []
1170 extrastrings = []
1171 while i < len(extras):
1171 while i < len(extras):
1172 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1172 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1173 i += 2
1173 i += 2
1174
1174
1175 ui.write(('file extras: %s (%s)\n')
1175 ui.write(('file extras: %s (%s)\n')
1176 % (filename, ', '.join(extrastrings)))
1176 % (filename, ', '.join(extrastrings)))
1177 elif rtype == 'l':
1177 elif rtype == 'l':
1178 labels = record.split('\0', 2)
1178 labels = record.split('\0', 2)
1179 labels = [l for l in labels if len(l) > 0]
1179 labels = [l for l in labels if len(l) > 0]
1180 ui.write(('labels:\n'))
1180 ui.write(('labels:\n'))
1181 ui.write((' local: %s\n' % labels[0]))
1181 ui.write((' local: %s\n' % labels[0]))
1182 ui.write((' other: %s\n' % labels[1]))
1182 ui.write((' other: %s\n' % labels[1]))
1183 if len(labels) > 2:
1183 if len(labels) > 2:
1184 ui.write((' base: %s\n' % labels[2]))
1184 ui.write((' base: %s\n' % labels[2]))
1185 else:
1185 else:
1186 ui.write(('unrecognized entry: %s\t%s\n')
1186 ui.write(('unrecognized entry: %s\t%s\n')
1187 % (rtype, record.replace('\0', '\t')))
1187 % (rtype, record.replace('\0', '\t')))
1188
1188
1189 # Avoid mergestate.read() since it may raise an exception for unsupported
1189 # Avoid mergestate.read() since it may raise an exception for unsupported
1190 # merge state records. We shouldn't be doing this, but this is OK since this
1190 # merge state records. We shouldn't be doing this, but this is OK since this
1191 # command is pretty low-level.
1191 # command is pretty low-level.
1192 ms = mergemod.mergestate(repo)
1192 ms = mergemod.mergestate(repo)
1193
1193
1194 # sort so that reasonable information is on top
1194 # sort so that reasonable information is on top
1195 v1records = ms._readrecordsv1()
1195 v1records = ms._readrecordsv1()
1196 v2records = ms._readrecordsv2()
1196 v2records = ms._readrecordsv2()
1197 order = 'LOml'
1197 order = 'LOml'
1198 def key(r):
1198 def key(r):
1199 idx = order.find(r[0])
1199 idx = order.find(r[0])
1200 if idx == -1:
1200 if idx == -1:
1201 return (1, r[1])
1201 return (1, r[1])
1202 else:
1202 else:
1203 return (0, idx)
1203 return (0, idx)
1204 v1records.sort(key=key)
1204 v1records.sort(key=key)
1205 v2records.sort(key=key)
1205 v2records.sort(key=key)
1206
1206
1207 if not v1records and not v2records:
1207 if not v1records and not v2records:
1208 ui.write(('no merge state found\n'))
1208 ui.write(('no merge state found\n'))
1209 elif not v2records:
1209 elif not v2records:
1210 ui.note(('no version 2 merge state\n'))
1210 ui.note(('no version 2 merge state\n'))
1211 printrecords(1)
1211 printrecords(1)
1212 elif ms._v1v2match(v1records, v2records):
1212 elif ms._v1v2match(v1records, v2records):
1213 ui.note(('v1 and v2 states match: using v2\n'))
1213 ui.note(('v1 and v2 states match: using v2\n'))
1214 printrecords(2)
1214 printrecords(2)
1215 else:
1215 else:
1216 ui.note(('v1 and v2 states mismatch: using v1\n'))
1216 ui.note(('v1 and v2 states mismatch: using v1\n'))
1217 printrecords(1)
1217 printrecords(1)
1218 if ui.verbose:
1218 if ui.verbose:
1219 printrecords(2)
1219 printrecords(2)
1220
1220
1221 @command('debugnamecomplete', [], _('NAME...'))
1221 @command('debugnamecomplete', [], _('NAME...'))
1222 def debugnamecomplete(ui, repo, *args):
1222 def debugnamecomplete(ui, repo, *args):
1223 '''complete "names" - tags, open branch names, bookmark names'''
1223 '''complete "names" - tags, open branch names, bookmark names'''
1224
1224
1225 names = set()
1225 names = set()
1226 # since we previously only listed open branches, we will handle that
1226 # since we previously only listed open branches, we will handle that
1227 # specially (after this for loop)
1227 # specially (after this for loop)
1228 for name, ns in repo.names.iteritems():
1228 for name, ns in repo.names.iteritems():
1229 if name != 'branches':
1229 if name != 'branches':
1230 names.update(ns.listnames(repo))
1230 names.update(ns.listnames(repo))
1231 names.update(tag for (tag, heads, tip, closed)
1231 names.update(tag for (tag, heads, tip, closed)
1232 in repo.branchmap().iterbranches() if not closed)
1232 in repo.branchmap().iterbranches() if not closed)
1233 completions = set()
1233 completions = set()
1234 if not args:
1234 if not args:
1235 args = ['']
1235 args = ['']
1236 for a in args:
1236 for a in args:
1237 completions.update(n for n in names if n.startswith(a))
1237 completions.update(n for n in names if n.startswith(a))
1238 ui.write('\n'.join(sorted(completions)))
1238 ui.write('\n'.join(sorted(completions)))
1239 ui.write('\n')
1239 ui.write('\n')
1240
1240
1241 @command('debugobsolete',
1241 @command('debugobsolete',
1242 [('', 'flags', 0, _('markers flag')),
1242 [('', 'flags', 0, _('markers flag')),
1243 ('', 'record-parents', False,
1243 ('', 'record-parents', False,
1244 _('record parent information for the precursor')),
1244 _('record parent information for the precursor')),
1245 ('r', 'rev', [], _('display markers relevant to REV')),
1245 ('r', 'rev', [], _('display markers relevant to REV')),
1246 ('', 'index', False, _('display index of the marker')),
1246 ('', 'index', False, _('display index of the marker')),
1247 ('', 'delete', [], _('delete markers specified by indices')),
1247 ('', 'delete', [], _('delete markers specified by indices')),
1248 ] + commands.commitopts2 + commands.formatteropts,
1248 ] + commands.commitopts2 + commands.formatteropts,
1249 _('[OBSOLETED [REPLACEMENT ...]]'))
1249 _('[OBSOLETED [REPLACEMENT ...]]'))
1250 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1250 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1251 """create arbitrary obsolete marker
1251 """create arbitrary obsolete marker
1252
1252
1253 With no arguments, displays the list of obsolescence markers."""
1253 With no arguments, displays the list of obsolescence markers."""
1254
1254
1255 def parsenodeid(s):
1255 def parsenodeid(s):
1256 try:
1256 try:
1257 # We do not use revsingle/revrange functions here to accept
1257 # We do not use revsingle/revrange functions here to accept
1258 # arbitrary node identifiers, possibly not present in the
1258 # arbitrary node identifiers, possibly not present in the
1259 # local repository.
1259 # local repository.
1260 n = bin(s)
1260 n = bin(s)
1261 if len(n) != len(nullid):
1261 if len(n) != len(nullid):
1262 raise TypeError()
1262 raise TypeError()
1263 return n
1263 return n
1264 except TypeError:
1264 except TypeError:
1265 raise error.Abort('changeset references must be full hexadecimal '
1265 raise error.Abort('changeset references must be full hexadecimal '
1266 'node identifiers')
1266 'node identifiers')
1267
1267
1268 if opts.get('delete'):
1268 if opts.get('delete'):
1269 indices = []
1269 indices = []
1270 for v in opts.get('delete'):
1270 for v in opts.get('delete'):
1271 try:
1271 try:
1272 indices.append(int(v))
1272 indices.append(int(v))
1273 except ValueError:
1273 except ValueError:
1274 raise error.Abort(_('invalid index value: %r') % v,
1274 raise error.Abort(_('invalid index value: %r') % v,
1275 hint=_('use integers for indices'))
1275 hint=_('use integers for indices'))
1276
1276
1277 if repo.currenttransaction():
1277 if repo.currenttransaction():
1278 raise error.Abort(_('cannot delete obsmarkers in the middle '
1278 raise error.Abort(_('cannot delete obsmarkers in the middle '
1279 'of transaction.'))
1279 'of transaction.'))
1280
1280
1281 with repo.lock():
1281 with repo.lock():
1282 n = repair.deleteobsmarkers(repo.obsstore, indices)
1282 n = repair.deleteobsmarkers(repo.obsstore, indices)
1283 ui.write(_('deleted %i obsolescence markers\n') % n)
1283 ui.write(_('deleted %i obsolescence markers\n') % n)
1284
1284
1285 return
1285 return
1286
1286
1287 if precursor is not None:
1287 if precursor is not None:
1288 if opts['rev']:
1288 if opts['rev']:
1289 raise error.Abort('cannot select revision when creating marker')
1289 raise error.Abort('cannot select revision when creating marker')
1290 metadata = {}
1290 metadata = {}
1291 metadata['user'] = opts['user'] or ui.username()
1291 metadata['user'] = opts['user'] or ui.username()
1292 succs = tuple(parsenodeid(succ) for succ in successors)
1292 succs = tuple(parsenodeid(succ) for succ in successors)
1293 l = repo.lock()
1293 l = repo.lock()
1294 try:
1294 try:
1295 tr = repo.transaction('debugobsolete')
1295 tr = repo.transaction('debugobsolete')
1296 try:
1296 try:
1297 date = opts.get('date')
1297 date = opts.get('date')
1298 if date:
1298 if date:
1299 date = util.parsedate(date)
1299 date = util.parsedate(date)
1300 else:
1300 else:
1301 date = None
1301 date = None
1302 prec = parsenodeid(precursor)
1302 prec = parsenodeid(precursor)
1303 parents = None
1303 parents = None
1304 if opts['record_parents']:
1304 if opts['record_parents']:
1305 if prec not in repo.unfiltered():
1305 if prec not in repo.unfiltered():
1306 raise error.Abort('cannot used --record-parents on '
1306 raise error.Abort('cannot used --record-parents on '
1307 'unknown changesets')
1307 'unknown changesets')
1308 parents = repo.unfiltered()[prec].parents()
1308 parents = repo.unfiltered()[prec].parents()
1309 parents = tuple(p.node() for p in parents)
1309 parents = tuple(p.node() for p in parents)
1310 repo.obsstore.create(tr, prec, succs, opts['flags'],
1310 repo.obsstore.create(tr, prec, succs, opts['flags'],
1311 parents=parents, date=date,
1311 parents=parents, date=date,
1312 metadata=metadata)
1312 metadata=metadata)
1313 tr.close()
1313 tr.close()
1314 except ValueError as exc:
1314 except ValueError as exc:
1315 raise error.Abort(_('bad obsmarker input: %s') % exc)
1315 raise error.Abort(_('bad obsmarker input: %s') % exc)
1316 finally:
1316 finally:
1317 tr.release()
1317 tr.release()
1318 finally:
1318 finally:
1319 l.release()
1319 l.release()
1320 else:
1320 else:
1321 if opts['rev']:
1321 if opts['rev']:
1322 revs = scmutil.revrange(repo, opts['rev'])
1322 revs = scmutil.revrange(repo, opts['rev'])
1323 nodes = [repo[r].node() for r in revs]
1323 nodes = [repo[r].node() for r in revs]
1324 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1324 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1325 markers.sort(key=lambda x: x._data)
1325 markers.sort(key=lambda x: x._data)
1326 else:
1326 else:
1327 markers = obsolete.getmarkers(repo)
1327 markers = obsolete.getmarkers(repo)
1328
1328
1329 markerstoiter = markers
1329 markerstoiter = markers
1330 isrelevant = lambda m: True
1330 isrelevant = lambda m: True
1331 if opts.get('rev') and opts.get('index'):
1331 if opts.get('rev') and opts.get('index'):
1332 markerstoiter = obsolete.getmarkers(repo)
1332 markerstoiter = obsolete.getmarkers(repo)
1333 markerset = set(markers)
1333 markerset = set(markers)
1334 isrelevant = lambda m: m in markerset
1334 isrelevant = lambda m: m in markerset
1335
1335
1336 fm = ui.formatter('debugobsolete', opts)
1336 fm = ui.formatter('debugobsolete', opts)
1337 for i, m in enumerate(markerstoiter):
1337 for i, m in enumerate(markerstoiter):
1338 if not isrelevant(m):
1338 if not isrelevant(m):
1339 # marker can be irrelevant when we're iterating over a set
1339 # marker can be irrelevant when we're iterating over a set
1340 # of markers (markerstoiter) which is bigger than the set
1340 # of markers (markerstoiter) which is bigger than the set
1341 # of markers we want to display (markers)
1341 # of markers we want to display (markers)
1342 # this can happen if both --index and --rev options are
1342 # this can happen if both --index and --rev options are
1343 # provided and thus we need to iterate over all of the markers
1343 # provided and thus we need to iterate over all of the markers
1344 # to get the correct indices, but only display the ones that
1344 # to get the correct indices, but only display the ones that
1345 # are relevant to --rev value
1345 # are relevant to --rev value
1346 continue
1346 continue
1347 fm.startitem()
1347 fm.startitem()
1348 ind = i if opts.get('index') else None
1348 ind = i if opts.get('index') else None
1349 cmdutil.showmarker(fm, m, index=ind)
1349 cmdutil.showmarker(fm, m, index=ind)
1350 fm.end()
1350 fm.end()
1351
1351
1352 @command('debugpathcomplete',
1352 @command('debugpathcomplete',
1353 [('f', 'full', None, _('complete an entire path')),
1353 [('f', 'full', None, _('complete an entire path')),
1354 ('n', 'normal', None, _('show only normal files')),
1354 ('n', 'normal', None, _('show only normal files')),
1355 ('a', 'added', None, _('show only added files')),
1355 ('a', 'added', None, _('show only added files')),
1356 ('r', 'removed', None, _('show only removed files'))],
1356 ('r', 'removed', None, _('show only removed files'))],
1357 _('FILESPEC...'))
1357 _('FILESPEC...'))
1358 def debugpathcomplete(ui, repo, *specs, **opts):
1358 def debugpathcomplete(ui, repo, *specs, **opts):
1359 '''complete part or all of a tracked path
1359 '''complete part or all of a tracked path
1360
1360
1361 This command supports shells that offer path name completion. It
1361 This command supports shells that offer path name completion. It
1362 currently completes only files already known to the dirstate.
1362 currently completes only files already known to the dirstate.
1363
1363
1364 Completion extends only to the next path segment unless
1364 Completion extends only to the next path segment unless
1365 --full is specified, in which case entire paths are used.'''
1365 --full is specified, in which case entire paths are used.'''
1366
1366
1367 def complete(path, acceptable):
1367 def complete(path, acceptable):
1368 dirstate = repo.dirstate
1368 dirstate = repo.dirstate
1369 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1369 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1370 rootdir = repo.root + pycompat.ossep
1370 rootdir = repo.root + pycompat.ossep
1371 if spec != repo.root and not spec.startswith(rootdir):
1371 if spec != repo.root and not spec.startswith(rootdir):
1372 return [], []
1372 return [], []
1373 if os.path.isdir(spec):
1373 if os.path.isdir(spec):
1374 spec += '/'
1374 spec += '/'
1375 spec = spec[len(rootdir):]
1375 spec = spec[len(rootdir):]
1376 fixpaths = pycompat.ossep != '/'
1376 fixpaths = pycompat.ossep != '/'
1377 if fixpaths:
1377 if fixpaths:
1378 spec = spec.replace(pycompat.ossep, '/')
1378 spec = spec.replace(pycompat.ossep, '/')
1379 speclen = len(spec)
1379 speclen = len(spec)
1380 fullpaths = opts['full']
1380 fullpaths = opts['full']
1381 files, dirs = set(), set()
1381 files, dirs = set(), set()
1382 adddir, addfile = dirs.add, files.add
1382 adddir, addfile = dirs.add, files.add
1383 for f, st in dirstate.iteritems():
1383 for f, st in dirstate.iteritems():
1384 if f.startswith(spec) and st[0] in acceptable:
1384 if f.startswith(spec) and st[0] in acceptable:
1385 if fixpaths:
1385 if fixpaths:
1386 f = f.replace('/', pycompat.ossep)
1386 f = f.replace('/', pycompat.ossep)
1387 if fullpaths:
1387 if fullpaths:
1388 addfile(f)
1388 addfile(f)
1389 continue
1389 continue
1390 s = f.find(pycompat.ossep, speclen)
1390 s = f.find(pycompat.ossep, speclen)
1391 if s >= 0:
1391 if s >= 0:
1392 adddir(f[:s])
1392 adddir(f[:s])
1393 else:
1393 else:
1394 addfile(f)
1394 addfile(f)
1395 return files, dirs
1395 return files, dirs
1396
1396
1397 acceptable = ''
1397 acceptable = ''
1398 if opts['normal']:
1398 if opts['normal']:
1399 acceptable += 'nm'
1399 acceptable += 'nm'
1400 if opts['added']:
1400 if opts['added']:
1401 acceptable += 'a'
1401 acceptable += 'a'
1402 if opts['removed']:
1402 if opts['removed']:
1403 acceptable += 'r'
1403 acceptable += 'r'
1404 cwd = repo.getcwd()
1404 cwd = repo.getcwd()
1405 if not specs:
1405 if not specs:
1406 specs = ['.']
1406 specs = ['.']
1407
1407
1408 files, dirs = set(), set()
1408 files, dirs = set(), set()
1409 for spec in specs:
1409 for spec in specs:
1410 f, d = complete(spec, acceptable or 'nmar')
1410 f, d = complete(spec, acceptable or 'nmar')
1411 files.update(f)
1411 files.update(f)
1412 dirs.update(d)
1412 dirs.update(d)
1413 files.update(dirs)
1413 files.update(dirs)
1414 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1414 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1415 ui.write('\n')
1415 ui.write('\n')
1416
1416
1417 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1418 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1419 '''access the pushkey key/value protocol
1420
1421 With two args, list the keys in the given namespace.
1422
1423 With five args, set a key to new if it currently is set to old.
1424 Reports success or failure.
1425 '''
1426
1427 target = hg.peer(ui, {}, repopath)
1428 if keyinfo:
1429 key, old, new = keyinfo
1430 r = target.pushkey(namespace, key, old, new)
1431 ui.status(str(r) + '\n')
1432 return not r
1433 else:
1434 for k, v in sorted(target.listkeys(namespace).iteritems()):
1435 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1436 v.encode('string-escape')))
1437
1417 @command('debugupgraderepo', [
1438 @command('debugupgraderepo', [
1418 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1439 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1419 ('', 'run', False, _('performs an upgrade')),
1440 ('', 'run', False, _('performs an upgrade')),
1420 ])
1441 ])
1421 def debugupgraderepo(ui, repo, run=False, optimize=None):
1442 def debugupgraderepo(ui, repo, run=False, optimize=None):
1422 """upgrade a repository to use different features
1443 """upgrade a repository to use different features
1423
1444
1424 If no arguments are specified, the repository is evaluated for upgrade
1445 If no arguments are specified, the repository is evaluated for upgrade
1425 and a list of problems and potential optimizations is printed.
1446 and a list of problems and potential optimizations is printed.
1426
1447
1427 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1448 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1428 can be influenced via additional arguments. More details will be provided
1449 can be influenced via additional arguments. More details will be provided
1429 by the command output when run without ``--run``.
1450 by the command output when run without ``--run``.
1430
1451
1431 During the upgrade, the repository will be locked and no writes will be
1452 During the upgrade, the repository will be locked and no writes will be
1432 allowed.
1453 allowed.
1433
1454
1434 At the end of the upgrade, the repository may not be readable while new
1455 At the end of the upgrade, the repository may not be readable while new
1435 repository data is swapped in. This window will be as long as it takes to
1456 repository data is swapped in. This window will be as long as it takes to
1436 rename some directories inside the ``.hg`` directory. On most machines, this
1457 rename some directories inside the ``.hg`` directory. On most machines, this
1437 should complete almost instantaneously and the chances of a consumer being
1458 should complete almost instantaneously and the chances of a consumer being
1438 unable to access the repository should be low.
1459 unable to access the repository should be low.
1439 """
1460 """
1440 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1461 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now