##// END OF EJS Templates
debugcommands: move 'debuglabelcomplete' in the new module
Pierre-Yves David -
r30935:e46533c3 default
parent child Browse files
Show More
@@ -1,6444 +1,6439
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 socket
14 import socket
15 import string
15 import string
16 import time
16 import time
17
17
18 from .i18n import _
18 from .i18n import _
19 from .node import (
19 from .node import (
20 bin,
20 bin,
21 hex,
21 hex,
22 nullhex,
22 nullhex,
23 nullid,
23 nullid,
24 nullrev,
24 nullrev,
25 short,
25 short,
26 )
26 )
27 from . import (
27 from . import (
28 archival,
28 archival,
29 bookmarks,
29 bookmarks,
30 bundle2,
30 bundle2,
31 changegroup,
31 changegroup,
32 cmdutil,
32 cmdutil,
33 copies,
33 copies,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 lock as lockmod,
46 lock as lockmod,
47 merge as mergemod,
47 merge as mergemod,
48 minirst,
48 minirst,
49 obsolete,
49 obsolete,
50 patch,
50 patch,
51 phases,
51 phases,
52 pvec,
52 pvec,
53 pycompat,
53 pycompat,
54 repair,
54 repair,
55 revlog,
55 revlog,
56 revset,
56 revset,
57 scmutil,
57 scmutil,
58 server,
58 server,
59 smartset,
59 smartset,
60 sshserver,
60 sshserver,
61 streamclone,
61 streamclone,
62 templatekw,
62 templatekw,
63 templater,
63 templater,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 )
66 )
67
67
68 release = lockmod.release
68 release = lockmod.release
69
69
70 table = {}
70 table = {}
71
71
72 command = cmdutil.command(table)
72 command = cmdutil.command(table)
73
73
74 # label constants
74 # label constants
75 # until 3.5, bookmarks.current was the advertised name, not
75 # until 3.5, bookmarks.current was the advertised name, not
76 # bookmarks.active, so we must use both to avoid breaking old
76 # bookmarks.active, so we must use both to avoid breaking old
77 # custom styles
77 # custom styles
78 activebookmarklabel = 'bookmarks.active bookmarks.current'
78 activebookmarklabel = 'bookmarks.active bookmarks.current'
79
79
80 # common command options
80 # common command options
81
81
82 globalopts = [
82 globalopts = [
83 ('R', 'repository', '',
83 ('R', 'repository', '',
84 _('repository root directory or name of overlay bundle file'),
84 _('repository root directory or name of overlay bundle file'),
85 _('REPO')),
85 _('REPO')),
86 ('', 'cwd', '',
86 ('', 'cwd', '',
87 _('change working directory'), _('DIR')),
87 _('change working directory'), _('DIR')),
88 ('y', 'noninteractive', None,
88 ('y', 'noninteractive', None,
89 _('do not prompt, automatically pick the first choice for all prompts')),
89 _('do not prompt, automatically pick the first choice for all prompts')),
90 ('q', 'quiet', None, _('suppress output')),
90 ('q', 'quiet', None, _('suppress output')),
91 ('v', 'verbose', None, _('enable additional output')),
91 ('v', 'verbose', None, _('enable additional output')),
92 ('', 'config', [],
92 ('', 'config', [],
93 _('set/override config option (use \'section.name=value\')'),
93 _('set/override config option (use \'section.name=value\')'),
94 _('CONFIG')),
94 _('CONFIG')),
95 ('', 'debug', None, _('enable debugging output')),
95 ('', 'debug', None, _('enable debugging output')),
96 ('', 'debugger', None, _('start debugger')),
96 ('', 'debugger', None, _('start debugger')),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
98 _('ENCODE')),
98 _('ENCODE')),
99 ('', 'encodingmode', encoding.encodingmode,
99 ('', 'encodingmode', encoding.encodingmode,
100 _('set the charset encoding mode'), _('MODE')),
100 _('set the charset encoding mode'), _('MODE')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
102 ('', 'time', None, _('time how long the command takes')),
102 ('', 'time', None, _('time how long the command takes')),
103 ('', 'profile', None, _('print command execution profile')),
103 ('', 'profile', None, _('print command execution profile')),
104 ('', 'version', None, _('output version information and exit')),
104 ('', 'version', None, _('output version information and exit')),
105 ('h', 'help', None, _('display help and exit')),
105 ('h', 'help', None, _('display help and exit')),
106 ('', 'hidden', False, _('consider hidden changesets')),
106 ('', 'hidden', False, _('consider hidden changesets')),
107 ]
107 ]
108
108
109 dryrunopts = [('n', 'dry-run', None,
109 dryrunopts = [('n', 'dry-run', None,
110 _('do not perform actions, just print output'))]
110 _('do not perform actions, just print output'))]
111
111
112 remoteopts = [
112 remoteopts = [
113 ('e', 'ssh', '',
113 ('e', 'ssh', '',
114 _('specify ssh command to use'), _('CMD')),
114 _('specify ssh command to use'), _('CMD')),
115 ('', 'remotecmd', '',
115 ('', 'remotecmd', '',
116 _('specify hg command to run on the remote side'), _('CMD')),
116 _('specify hg command to run on the remote side'), _('CMD')),
117 ('', 'insecure', None,
117 ('', 'insecure', None,
118 _('do not verify server certificate (ignoring web.cacerts config)')),
118 _('do not verify server certificate (ignoring web.cacerts config)')),
119 ]
119 ]
120
120
121 walkopts = [
121 walkopts = [
122 ('I', 'include', [],
122 ('I', 'include', [],
123 _('include names matching the given patterns'), _('PATTERN')),
123 _('include names matching the given patterns'), _('PATTERN')),
124 ('X', 'exclude', [],
124 ('X', 'exclude', [],
125 _('exclude names matching the given patterns'), _('PATTERN')),
125 _('exclude names matching the given patterns'), _('PATTERN')),
126 ]
126 ]
127
127
128 commitopts = [
128 commitopts = [
129 ('m', 'message', '',
129 ('m', 'message', '',
130 _('use text as commit message'), _('TEXT')),
130 _('use text as commit message'), _('TEXT')),
131 ('l', 'logfile', '',
131 ('l', 'logfile', '',
132 _('read commit message from file'), _('FILE')),
132 _('read commit message from file'), _('FILE')),
133 ]
133 ]
134
134
135 commitopts2 = [
135 commitopts2 = [
136 ('d', 'date', '',
136 ('d', 'date', '',
137 _('record the specified date as commit date'), _('DATE')),
137 _('record the specified date as commit date'), _('DATE')),
138 ('u', 'user', '',
138 ('u', 'user', '',
139 _('record the specified user as committer'), _('USER')),
139 _('record the specified user as committer'), _('USER')),
140 ]
140 ]
141
141
142 # hidden for now
142 # hidden for now
143 formatteropts = [
143 formatteropts = [
144 ('T', 'template', '',
144 ('T', 'template', '',
145 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
145 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
146 ]
146 ]
147
147
148 templateopts = [
148 templateopts = [
149 ('', 'style', '',
149 ('', 'style', '',
150 _('display using template map file (DEPRECATED)'), _('STYLE')),
150 _('display using template map file (DEPRECATED)'), _('STYLE')),
151 ('T', 'template', '',
151 ('T', 'template', '',
152 _('display with template'), _('TEMPLATE')),
152 _('display with template'), _('TEMPLATE')),
153 ]
153 ]
154
154
155 logopts = [
155 logopts = [
156 ('p', 'patch', None, _('show patch')),
156 ('p', 'patch', None, _('show patch')),
157 ('g', 'git', None, _('use git extended diff format')),
157 ('g', 'git', None, _('use git extended diff format')),
158 ('l', 'limit', '',
158 ('l', 'limit', '',
159 _('limit number of changes displayed'), _('NUM')),
159 _('limit number of changes displayed'), _('NUM')),
160 ('M', 'no-merges', None, _('do not show merges')),
160 ('M', 'no-merges', None, _('do not show merges')),
161 ('', 'stat', None, _('output diffstat-style summary of changes')),
161 ('', 'stat', None, _('output diffstat-style summary of changes')),
162 ('G', 'graph', None, _("show the revision DAG")),
162 ('G', 'graph', None, _("show the revision DAG")),
163 ] + templateopts
163 ] + templateopts
164
164
165 diffopts = [
165 diffopts = [
166 ('a', 'text', None, _('treat all files as text')),
166 ('a', 'text', None, _('treat all files as text')),
167 ('g', 'git', None, _('use git extended diff format')),
167 ('g', 'git', None, _('use git extended diff format')),
168 ('', 'nodates', None, _('omit dates from diff headers'))
168 ('', 'nodates', None, _('omit dates from diff headers'))
169 ]
169 ]
170
170
171 diffwsopts = [
171 diffwsopts = [
172 ('w', 'ignore-all-space', None,
172 ('w', 'ignore-all-space', None,
173 _('ignore white space when comparing lines')),
173 _('ignore white space when comparing lines')),
174 ('b', 'ignore-space-change', None,
174 ('b', 'ignore-space-change', None,
175 _('ignore changes in the amount of white space')),
175 _('ignore changes in the amount of white space')),
176 ('B', 'ignore-blank-lines', None,
176 ('B', 'ignore-blank-lines', None,
177 _('ignore changes whose lines are all blank')),
177 _('ignore changes whose lines are all blank')),
178 ]
178 ]
179
179
180 diffopts2 = [
180 diffopts2 = [
181 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
181 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
182 ('p', 'show-function', None, _('show which function each change is in')),
182 ('p', 'show-function', None, _('show which function each change is in')),
183 ('', 'reverse', None, _('produce a diff that undoes the changes')),
183 ('', 'reverse', None, _('produce a diff that undoes the changes')),
184 ] + diffwsopts + [
184 ] + diffwsopts + [
185 ('U', 'unified', '',
185 ('U', 'unified', '',
186 _('number of lines of context to show'), _('NUM')),
186 _('number of lines of context to show'), _('NUM')),
187 ('', 'stat', None, _('output diffstat-style summary of changes')),
187 ('', 'stat', None, _('output diffstat-style summary of changes')),
188 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
188 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
189 ]
189 ]
190
190
191 mergetoolopts = [
191 mergetoolopts = [
192 ('t', 'tool', '', _('specify merge tool')),
192 ('t', 'tool', '', _('specify merge tool')),
193 ]
193 ]
194
194
195 similarityopts = [
195 similarityopts = [
196 ('s', 'similarity', '',
196 ('s', 'similarity', '',
197 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
197 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
198 ]
198 ]
199
199
200 subrepoopts = [
200 subrepoopts = [
201 ('S', 'subrepos', None,
201 ('S', 'subrepos', None,
202 _('recurse into subrepositories'))
202 _('recurse into subrepositories'))
203 ]
203 ]
204
204
205 debugrevlogopts = [
205 debugrevlogopts = [
206 ('c', 'changelog', False, _('open changelog')),
206 ('c', 'changelog', False, _('open changelog')),
207 ('m', 'manifest', False, _('open manifest')),
207 ('m', 'manifest', False, _('open manifest')),
208 ('', 'dir', '', _('open directory manifest')),
208 ('', 'dir', '', _('open directory manifest')),
209 ]
209 ]
210
210
211 # Commands start here, listed alphabetically
211 # Commands start here, listed alphabetically
212
212
213 @command('^add',
213 @command('^add',
214 walkopts + subrepoopts + dryrunopts,
214 walkopts + subrepoopts + dryrunopts,
215 _('[OPTION]... [FILE]...'),
215 _('[OPTION]... [FILE]...'),
216 inferrepo=True)
216 inferrepo=True)
217 def add(ui, repo, *pats, **opts):
217 def add(ui, repo, *pats, **opts):
218 """add the specified files on the next commit
218 """add the specified files on the next commit
219
219
220 Schedule files to be version controlled and added to the
220 Schedule files to be version controlled and added to the
221 repository.
221 repository.
222
222
223 The files will be added to the repository at the next commit. To
223 The files will be added to the repository at the next commit. To
224 undo an add before that, see :hg:`forget`.
224 undo an add before that, see :hg:`forget`.
225
225
226 If no names are given, add all files to the repository (except
226 If no names are given, add all files to the repository (except
227 files matching ``.hgignore``).
227 files matching ``.hgignore``).
228
228
229 .. container:: verbose
229 .. container:: verbose
230
230
231 Examples:
231 Examples:
232
232
233 - New (unknown) files are added
233 - New (unknown) files are added
234 automatically by :hg:`add`::
234 automatically by :hg:`add`::
235
235
236 $ ls
236 $ ls
237 foo.c
237 foo.c
238 $ hg status
238 $ hg status
239 ? foo.c
239 ? foo.c
240 $ hg add
240 $ hg add
241 adding foo.c
241 adding foo.c
242 $ hg status
242 $ hg status
243 A foo.c
243 A foo.c
244
244
245 - Specific files to be added can be specified::
245 - Specific files to be added can be specified::
246
246
247 $ ls
247 $ ls
248 bar.c foo.c
248 bar.c foo.c
249 $ hg status
249 $ hg status
250 ? bar.c
250 ? bar.c
251 ? foo.c
251 ? foo.c
252 $ hg add bar.c
252 $ hg add bar.c
253 $ hg status
253 $ hg status
254 A bar.c
254 A bar.c
255 ? foo.c
255 ? foo.c
256
256
257 Returns 0 if all files are successfully added.
257 Returns 0 if all files are successfully added.
258 """
258 """
259
259
260 m = scmutil.match(repo[None], pats, opts)
260 m = scmutil.match(repo[None], pats, opts)
261 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
261 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
262 return rejected and 1 or 0
262 return rejected and 1 or 0
263
263
264 @command('addremove',
264 @command('addremove',
265 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
266 _('[OPTION]... [FILE]...'),
266 _('[OPTION]... [FILE]...'),
267 inferrepo=True)
267 inferrepo=True)
268 def addremove(ui, repo, *pats, **opts):
268 def addremove(ui, repo, *pats, **opts):
269 """add all new files, delete all missing files
269 """add all new files, delete all missing files
270
270
271 Add all new files and remove all missing files from the
271 Add all new files and remove all missing files from the
272 repository.
272 repository.
273
273
274 Unless names are given, new files are ignored if they match any of
274 Unless names are given, new files are ignored if they match any of
275 the patterns in ``.hgignore``. As with add, these changes take
275 the patterns in ``.hgignore``. As with add, these changes take
276 effect at the next commit.
276 effect at the next commit.
277
277
278 Use the -s/--similarity option to detect renamed files. This
278 Use the -s/--similarity option to detect renamed files. This
279 option takes a percentage between 0 (disabled) and 100 (files must
279 option takes a percentage between 0 (disabled) and 100 (files must
280 be identical) as its parameter. With a parameter greater than 0,
280 be identical) as its parameter. With a parameter greater than 0,
281 this compares every removed file with every added file and records
281 this compares every removed file with every added file and records
282 those similar enough as renames. Detecting renamed files this way
282 those similar enough as renames. Detecting renamed files this way
283 can be expensive. After using this option, :hg:`status -C` can be
283 can be expensive. After using this option, :hg:`status -C` can be
284 used to check which files were identified as moved or renamed. If
284 used to check which files were identified as moved or renamed. If
285 not specified, -s/--similarity defaults to 100 and only renames of
285 not specified, -s/--similarity defaults to 100 and only renames of
286 identical files are detected.
286 identical files are detected.
287
287
288 .. container:: verbose
288 .. container:: verbose
289
289
290 Examples:
290 Examples:
291
291
292 - A number of files (bar.c and foo.c) are new,
292 - A number of files (bar.c and foo.c) are new,
293 while foobar.c has been removed (without using :hg:`remove`)
293 while foobar.c has been removed (without using :hg:`remove`)
294 from the repository::
294 from the repository::
295
295
296 $ ls
296 $ ls
297 bar.c foo.c
297 bar.c foo.c
298 $ hg status
298 $ hg status
299 ! foobar.c
299 ! foobar.c
300 ? bar.c
300 ? bar.c
301 ? foo.c
301 ? foo.c
302 $ hg addremove
302 $ hg addremove
303 adding bar.c
303 adding bar.c
304 adding foo.c
304 adding foo.c
305 removing foobar.c
305 removing foobar.c
306 $ hg status
306 $ hg status
307 A bar.c
307 A bar.c
308 A foo.c
308 A foo.c
309 R foobar.c
309 R foobar.c
310
310
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 Afterwards, it was edited slightly::
312 Afterwards, it was edited slightly::
313
313
314 $ ls
314 $ ls
315 foo.c
315 foo.c
316 $ hg status
316 $ hg status
317 ! foobar.c
317 ! foobar.c
318 ? foo.c
318 ? foo.c
319 $ hg addremove --similarity 90
319 $ hg addremove --similarity 90
320 removing foobar.c
320 removing foobar.c
321 adding foo.c
321 adding foo.c
322 recording removal of foobar.c as rename to foo.c (94% similar)
322 recording removal of foobar.c as rename to foo.c (94% similar)
323 $ hg status -C
323 $ hg status -C
324 A foo.c
324 A foo.c
325 foobar.c
325 foobar.c
326 R foobar.c
326 R foobar.c
327
327
328 Returns 0 if all files are successfully added.
328 Returns 0 if all files are successfully added.
329 """
329 """
330 try:
330 try:
331 sim = float(opts.get('similarity') or 100)
331 sim = float(opts.get('similarity') or 100)
332 except ValueError:
332 except ValueError:
333 raise error.Abort(_('similarity must be a number'))
333 raise error.Abort(_('similarity must be a number'))
334 if sim < 0 or sim > 100:
334 if sim < 0 or sim > 100:
335 raise error.Abort(_('similarity must be between 0 and 100'))
335 raise error.Abort(_('similarity must be between 0 and 100'))
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
338
338
339 @command('^annotate|blame',
339 @command('^annotate|blame',
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
341 ('', 'follow', None,
341 ('', 'follow', None,
342 _('follow copies/renames and list the filename (DEPRECATED)')),
342 _('follow copies/renames and list the filename (DEPRECATED)')),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
344 ('a', 'text', None, _('treat all files as text')),
344 ('a', 'text', None, _('treat all files as text')),
345 ('u', 'user', None, _('list the author (long with -v)')),
345 ('u', 'user', None, _('list the author (long with -v)')),
346 ('f', 'file', None, _('list the filename')),
346 ('f', 'file', None, _('list the filename')),
347 ('d', 'date', None, _('list the date (short with -q)')),
347 ('d', 'date', None, _('list the date (short with -q)')),
348 ('n', 'number', None, _('list the revision number (default)')),
348 ('n', 'number', None, _('list the revision number (default)')),
349 ('c', 'changeset', None, _('list the changeset')),
349 ('c', 'changeset', None, _('list the changeset')),
350 ('l', 'line-number', None, _('show line number at the first appearance'))
350 ('l', 'line-number', None, _('show line number at the first appearance'))
351 ] + diffwsopts + walkopts + formatteropts,
351 ] + diffwsopts + walkopts + formatteropts,
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
353 inferrepo=True)
353 inferrepo=True)
354 def annotate(ui, repo, *pats, **opts):
354 def annotate(ui, repo, *pats, **opts):
355 """show changeset information by line for each file
355 """show changeset information by line for each file
356
356
357 List changes in files, showing the revision id responsible for
357 List changes in files, showing the revision id responsible for
358 each line.
358 each line.
359
359
360 This command is useful for discovering when a change was made and
360 This command is useful for discovering when a change was made and
361 by whom.
361 by whom.
362
362
363 If you include --file, --user, or --date, the revision number is
363 If you include --file, --user, or --date, the revision number is
364 suppressed unless you also include --number.
364 suppressed unless you also include --number.
365
365
366 Without the -a/--text option, annotate will avoid processing files
366 Without the -a/--text option, annotate will avoid processing files
367 it detects as binary. With -a, annotate will annotate the file
367 it detects as binary. With -a, annotate will annotate the file
368 anyway, although the results will probably be neither useful
368 anyway, although the results will probably be neither useful
369 nor desirable.
369 nor desirable.
370
370
371 Returns 0 on success.
371 Returns 0 on success.
372 """
372 """
373 if not pats:
373 if not pats:
374 raise error.Abort(_('at least one filename or pattern is required'))
374 raise error.Abort(_('at least one filename or pattern is required'))
375
375
376 if opts.get('follow'):
376 if opts.get('follow'):
377 # --follow is deprecated and now just an alias for -f/--file
377 # --follow is deprecated and now just an alias for -f/--file
378 # to mimic the behavior of Mercurial before version 1.5
378 # to mimic the behavior of Mercurial before version 1.5
379 opts['file'] = True
379 opts['file'] = True
380
380
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
382
382
383 fm = ui.formatter('annotate', opts)
383 fm = ui.formatter('annotate', opts)
384 if ui.quiet:
384 if ui.quiet:
385 datefunc = util.shortdate
385 datefunc = util.shortdate
386 else:
386 else:
387 datefunc = util.datestr
387 datefunc = util.datestr
388 if ctx.rev() is None:
388 if ctx.rev() is None:
389 def hexfn(node):
389 def hexfn(node):
390 if node is None:
390 if node is None:
391 return None
391 return None
392 else:
392 else:
393 return fm.hexfunc(node)
393 return fm.hexfunc(node)
394 if opts.get('changeset'):
394 if opts.get('changeset'):
395 # omit "+" suffix which is appended to node hex
395 # omit "+" suffix which is appended to node hex
396 def formatrev(rev):
396 def formatrev(rev):
397 if rev is None:
397 if rev is None:
398 return '%d' % ctx.p1().rev()
398 return '%d' % ctx.p1().rev()
399 else:
399 else:
400 return '%d' % rev
400 return '%d' % rev
401 else:
401 else:
402 def formatrev(rev):
402 def formatrev(rev):
403 if rev is None:
403 if rev is None:
404 return '%d+' % ctx.p1().rev()
404 return '%d+' % ctx.p1().rev()
405 else:
405 else:
406 return '%d ' % rev
406 return '%d ' % rev
407 def formathex(hex):
407 def formathex(hex):
408 if hex is None:
408 if hex is None:
409 return '%s+' % fm.hexfunc(ctx.p1().node())
409 return '%s+' % fm.hexfunc(ctx.p1().node())
410 else:
410 else:
411 return '%s ' % hex
411 return '%s ' % hex
412 else:
412 else:
413 hexfn = fm.hexfunc
413 hexfn = fm.hexfunc
414 formatrev = formathex = str
414 formatrev = formathex = str
415
415
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
420 ('file', ' ', lambda x: x[0].path(), str),
420 ('file', ' ', lambda x: x[0].path(), str),
421 ('line_number', ':', lambda x: x[1], str),
421 ('line_number', ':', lambda x: x[1], str),
422 ]
422 ]
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
424
424
425 if (not opts.get('user') and not opts.get('changeset')
425 if (not opts.get('user') and not opts.get('changeset')
426 and not opts.get('date') and not opts.get('file')):
426 and not opts.get('date') and not opts.get('file')):
427 opts['number'] = True
427 opts['number'] = True
428
428
429 linenumber = opts.get('line_number') is not None
429 linenumber = opts.get('line_number') is not None
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
432
432
433 if fm.isplain():
433 if fm.isplain():
434 def makefunc(get, fmt):
434 def makefunc(get, fmt):
435 return lambda x: fmt(get(x))
435 return lambda x: fmt(get(x))
436 else:
436 else:
437 def makefunc(get, fmt):
437 def makefunc(get, fmt):
438 return get
438 return get
439 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
439 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
440 if opts.get(op)]
440 if opts.get(op)]
441 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
441 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
442 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
442 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
443 if opts.get(op))
443 if opts.get(op))
444
444
445 def bad(x, y):
445 def bad(x, y):
446 raise error.Abort("%s: %s" % (x, y))
446 raise error.Abort("%s: %s" % (x, y))
447
447
448 m = scmutil.match(ctx, pats, opts, badfn=bad)
448 m = scmutil.match(ctx, pats, opts, badfn=bad)
449
449
450 follow = not opts.get('no_follow')
450 follow = not opts.get('no_follow')
451 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
451 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
452 whitespace=True)
452 whitespace=True)
453 for abs in ctx.walk(m):
453 for abs in ctx.walk(m):
454 fctx = ctx[abs]
454 fctx = ctx[abs]
455 if not opts.get('text') and util.binary(fctx.data()):
455 if not opts.get('text') and util.binary(fctx.data()):
456 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
456 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
457 continue
457 continue
458
458
459 lines = fctx.annotate(follow=follow, linenumber=linenumber,
459 lines = fctx.annotate(follow=follow, linenumber=linenumber,
460 diffopts=diffopts)
460 diffopts=diffopts)
461 if not lines:
461 if not lines:
462 continue
462 continue
463 formats = []
463 formats = []
464 pieces = []
464 pieces = []
465
465
466 for f, sep in funcmap:
466 for f, sep in funcmap:
467 l = [f(n) for n, dummy in lines]
467 l = [f(n) for n, dummy in lines]
468 if fm.isplain():
468 if fm.isplain():
469 sizes = [encoding.colwidth(x) for x in l]
469 sizes = [encoding.colwidth(x) for x in l]
470 ml = max(sizes)
470 ml = max(sizes)
471 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
471 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
472 else:
472 else:
473 formats.append(['%s' for x in l])
473 formats.append(['%s' for x in l])
474 pieces.append(l)
474 pieces.append(l)
475
475
476 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
476 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
477 fm.startitem()
477 fm.startitem()
478 fm.write(fields, "".join(f), *p)
478 fm.write(fields, "".join(f), *p)
479 fm.write('line', ": %s", l[1])
479 fm.write('line', ": %s", l[1])
480
480
481 if not lines[-1][1].endswith('\n'):
481 if not lines[-1][1].endswith('\n'):
482 fm.plain('\n')
482 fm.plain('\n')
483
483
484 fm.end()
484 fm.end()
485
485
486 @command('archive',
486 @command('archive',
487 [('', 'no-decode', None, _('do not pass files through decoders')),
487 [('', 'no-decode', None, _('do not pass files through decoders')),
488 ('p', 'prefix', '', _('directory prefix for files in archive'),
488 ('p', 'prefix', '', _('directory prefix for files in archive'),
489 _('PREFIX')),
489 _('PREFIX')),
490 ('r', 'rev', '', _('revision to distribute'), _('REV')),
490 ('r', 'rev', '', _('revision to distribute'), _('REV')),
491 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
491 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
492 ] + subrepoopts + walkopts,
492 ] + subrepoopts + walkopts,
493 _('[OPTION]... DEST'))
493 _('[OPTION]... DEST'))
494 def archive(ui, repo, dest, **opts):
494 def archive(ui, repo, dest, **opts):
495 '''create an unversioned archive of a repository revision
495 '''create an unversioned archive of a repository revision
496
496
497 By default, the revision used is the parent of the working
497 By default, the revision used is the parent of the working
498 directory; use -r/--rev to specify a different revision.
498 directory; use -r/--rev to specify a different revision.
499
499
500 The archive type is automatically detected based on file
500 The archive type is automatically detected based on file
501 extension (to override, use -t/--type).
501 extension (to override, use -t/--type).
502
502
503 .. container:: verbose
503 .. container:: verbose
504
504
505 Examples:
505 Examples:
506
506
507 - create a zip file containing the 1.0 release::
507 - create a zip file containing the 1.0 release::
508
508
509 hg archive -r 1.0 project-1.0.zip
509 hg archive -r 1.0 project-1.0.zip
510
510
511 - create a tarball excluding .hg files::
511 - create a tarball excluding .hg files::
512
512
513 hg archive project.tar.gz -X ".hg*"
513 hg archive project.tar.gz -X ".hg*"
514
514
515 Valid types are:
515 Valid types are:
516
516
517 :``files``: a directory full of files (default)
517 :``files``: a directory full of files (default)
518 :``tar``: tar archive, uncompressed
518 :``tar``: tar archive, uncompressed
519 :``tbz2``: tar archive, compressed using bzip2
519 :``tbz2``: tar archive, compressed using bzip2
520 :``tgz``: tar archive, compressed using gzip
520 :``tgz``: tar archive, compressed using gzip
521 :``uzip``: zip archive, uncompressed
521 :``uzip``: zip archive, uncompressed
522 :``zip``: zip archive, compressed using deflate
522 :``zip``: zip archive, compressed using deflate
523
523
524 The exact name of the destination archive or directory is given
524 The exact name of the destination archive or directory is given
525 using a format string; see :hg:`help export` for details.
525 using a format string; see :hg:`help export` for details.
526
526
527 Each member added to an archive file has a directory prefix
527 Each member added to an archive file has a directory prefix
528 prepended. Use -p/--prefix to specify a format string for the
528 prepended. Use -p/--prefix to specify a format string for the
529 prefix. The default is the basename of the archive, with suffixes
529 prefix. The default is the basename of the archive, with suffixes
530 removed.
530 removed.
531
531
532 Returns 0 on success.
532 Returns 0 on success.
533 '''
533 '''
534
534
535 ctx = scmutil.revsingle(repo, opts.get('rev'))
535 ctx = scmutil.revsingle(repo, opts.get('rev'))
536 if not ctx:
536 if not ctx:
537 raise error.Abort(_('no working directory: please specify a revision'))
537 raise error.Abort(_('no working directory: please specify a revision'))
538 node = ctx.node()
538 node = ctx.node()
539 dest = cmdutil.makefilename(repo, dest, node)
539 dest = cmdutil.makefilename(repo, dest, node)
540 if os.path.realpath(dest) == repo.root:
540 if os.path.realpath(dest) == repo.root:
541 raise error.Abort(_('repository root cannot be destination'))
541 raise error.Abort(_('repository root cannot be destination'))
542
542
543 kind = opts.get('type') or archival.guesskind(dest) or 'files'
543 kind = opts.get('type') or archival.guesskind(dest) or 'files'
544 prefix = opts.get('prefix')
544 prefix = opts.get('prefix')
545
545
546 if dest == '-':
546 if dest == '-':
547 if kind == 'files':
547 if kind == 'files':
548 raise error.Abort(_('cannot archive plain files to stdout'))
548 raise error.Abort(_('cannot archive plain files to stdout'))
549 dest = cmdutil.makefileobj(repo, dest)
549 dest = cmdutil.makefileobj(repo, dest)
550 if not prefix:
550 if not prefix:
551 prefix = os.path.basename(repo.root) + '-%h'
551 prefix = os.path.basename(repo.root) + '-%h'
552
552
553 prefix = cmdutil.makefilename(repo, prefix, node)
553 prefix = cmdutil.makefilename(repo, prefix, node)
554 matchfn = scmutil.match(ctx, [], opts)
554 matchfn = scmutil.match(ctx, [], opts)
555 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
555 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
556 matchfn, prefix, subrepos=opts.get('subrepos'))
556 matchfn, prefix, subrepos=opts.get('subrepos'))
557
557
558 @command('backout',
558 @command('backout',
559 [('', 'merge', None, _('merge with old dirstate parent after backout')),
559 [('', 'merge', None, _('merge with old dirstate parent after backout')),
560 ('', 'commit', None,
560 ('', 'commit', None,
561 _('commit if no conflicts were encountered (DEPRECATED)')),
561 _('commit if no conflicts were encountered (DEPRECATED)')),
562 ('', 'no-commit', None, _('do not commit')),
562 ('', 'no-commit', None, _('do not commit')),
563 ('', 'parent', '',
563 ('', 'parent', '',
564 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
564 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
565 ('r', 'rev', '', _('revision to backout'), _('REV')),
565 ('r', 'rev', '', _('revision to backout'), _('REV')),
566 ('e', 'edit', False, _('invoke editor on commit messages')),
566 ('e', 'edit', False, _('invoke editor on commit messages')),
567 ] + mergetoolopts + walkopts + commitopts + commitopts2,
567 ] + mergetoolopts + walkopts + commitopts + commitopts2,
568 _('[OPTION]... [-r] REV'))
568 _('[OPTION]... [-r] REV'))
569 def backout(ui, repo, node=None, rev=None, **opts):
569 def backout(ui, repo, node=None, rev=None, **opts):
570 '''reverse effect of earlier changeset
570 '''reverse effect of earlier changeset
571
571
572 Prepare a new changeset with the effect of REV undone in the
572 Prepare a new changeset with the effect of REV undone in the
573 current working directory. If no conflicts were encountered,
573 current working directory. If no conflicts were encountered,
574 it will be committed immediately.
574 it will be committed immediately.
575
575
576 If REV is the parent of the working directory, then this new changeset
576 If REV is the parent of the working directory, then this new changeset
577 is committed automatically (unless --no-commit is specified).
577 is committed automatically (unless --no-commit is specified).
578
578
579 .. note::
579 .. note::
580
580
581 :hg:`backout` cannot be used to fix either an unwanted or
581 :hg:`backout` cannot be used to fix either an unwanted or
582 incorrect merge.
582 incorrect merge.
583
583
584 .. container:: verbose
584 .. container:: verbose
585
585
586 Examples:
586 Examples:
587
587
588 - Reverse the effect of the parent of the working directory.
588 - Reverse the effect of the parent of the working directory.
589 This backout will be committed immediately::
589 This backout will be committed immediately::
590
590
591 hg backout -r .
591 hg backout -r .
592
592
593 - Reverse the effect of previous bad revision 23::
593 - Reverse the effect of previous bad revision 23::
594
594
595 hg backout -r 23
595 hg backout -r 23
596
596
597 - Reverse the effect of previous bad revision 23 and
597 - Reverse the effect of previous bad revision 23 and
598 leave changes uncommitted::
598 leave changes uncommitted::
599
599
600 hg backout -r 23 --no-commit
600 hg backout -r 23 --no-commit
601 hg commit -m "Backout revision 23"
601 hg commit -m "Backout revision 23"
602
602
603 By default, the pending changeset will have one parent,
603 By default, the pending changeset will have one parent,
604 maintaining a linear history. With --merge, the pending
604 maintaining a linear history. With --merge, the pending
605 changeset will instead have two parents: the old parent of the
605 changeset will instead have two parents: the old parent of the
606 working directory and a new child of REV that simply undoes REV.
606 working directory and a new child of REV that simply undoes REV.
607
607
608 Before version 1.7, the behavior without --merge was equivalent
608 Before version 1.7, the behavior without --merge was equivalent
609 to specifying --merge followed by :hg:`update --clean .` to
609 to specifying --merge followed by :hg:`update --clean .` to
610 cancel the merge and leave the child of REV as a head to be
610 cancel the merge and leave the child of REV as a head to be
611 merged separately.
611 merged separately.
612
612
613 See :hg:`help dates` for a list of formats valid for -d/--date.
613 See :hg:`help dates` for a list of formats valid for -d/--date.
614
614
615 See :hg:`help revert` for a way to restore files to the state
615 See :hg:`help revert` for a way to restore files to the state
616 of another revision.
616 of another revision.
617
617
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
619 files.
619 files.
620 '''
620 '''
621 wlock = lock = None
621 wlock = lock = None
622 try:
622 try:
623 wlock = repo.wlock()
623 wlock = repo.wlock()
624 lock = repo.lock()
624 lock = repo.lock()
625 return _dobackout(ui, repo, node, rev, **opts)
625 return _dobackout(ui, repo, node, rev, **opts)
626 finally:
626 finally:
627 release(lock, wlock)
627 release(lock, wlock)
628
628
629 def _dobackout(ui, repo, node=None, rev=None, **opts):
629 def _dobackout(ui, repo, node=None, rev=None, **opts):
630 if opts.get('commit') and opts.get('no_commit'):
630 if opts.get('commit') and opts.get('no_commit'):
631 raise error.Abort(_("cannot use --commit with --no-commit"))
631 raise error.Abort(_("cannot use --commit with --no-commit"))
632 if opts.get('merge') and opts.get('no_commit'):
632 if opts.get('merge') and opts.get('no_commit'):
633 raise error.Abort(_("cannot use --merge with --no-commit"))
633 raise error.Abort(_("cannot use --merge with --no-commit"))
634
634
635 if rev and node:
635 if rev and node:
636 raise error.Abort(_("please specify just one revision"))
636 raise error.Abort(_("please specify just one revision"))
637
637
638 if not rev:
638 if not rev:
639 rev = node
639 rev = node
640
640
641 if not rev:
641 if not rev:
642 raise error.Abort(_("please specify a revision to backout"))
642 raise error.Abort(_("please specify a revision to backout"))
643
643
644 date = opts.get('date')
644 date = opts.get('date')
645 if date:
645 if date:
646 opts['date'] = util.parsedate(date)
646 opts['date'] = util.parsedate(date)
647
647
648 cmdutil.checkunfinished(repo)
648 cmdutil.checkunfinished(repo)
649 cmdutil.bailifchanged(repo)
649 cmdutil.bailifchanged(repo)
650 node = scmutil.revsingle(repo, rev).node()
650 node = scmutil.revsingle(repo, rev).node()
651
651
652 op1, op2 = repo.dirstate.parents()
652 op1, op2 = repo.dirstate.parents()
653 if not repo.changelog.isancestor(node, op1):
653 if not repo.changelog.isancestor(node, op1):
654 raise error.Abort(_('cannot backout change that is not an ancestor'))
654 raise error.Abort(_('cannot backout change that is not an ancestor'))
655
655
656 p1, p2 = repo.changelog.parents(node)
656 p1, p2 = repo.changelog.parents(node)
657 if p1 == nullid:
657 if p1 == nullid:
658 raise error.Abort(_('cannot backout a change with no parents'))
658 raise error.Abort(_('cannot backout a change with no parents'))
659 if p2 != nullid:
659 if p2 != nullid:
660 if not opts.get('parent'):
660 if not opts.get('parent'):
661 raise error.Abort(_('cannot backout a merge changeset'))
661 raise error.Abort(_('cannot backout a merge changeset'))
662 p = repo.lookup(opts['parent'])
662 p = repo.lookup(opts['parent'])
663 if p not in (p1, p2):
663 if p not in (p1, p2):
664 raise error.Abort(_('%s is not a parent of %s') %
664 raise error.Abort(_('%s is not a parent of %s') %
665 (short(p), short(node)))
665 (short(p), short(node)))
666 parent = p
666 parent = p
667 else:
667 else:
668 if opts.get('parent'):
668 if opts.get('parent'):
669 raise error.Abort(_('cannot use --parent on non-merge changeset'))
669 raise error.Abort(_('cannot use --parent on non-merge changeset'))
670 parent = p1
670 parent = p1
671
671
672 # the backout should appear on the same branch
672 # the backout should appear on the same branch
673 branch = repo.dirstate.branch()
673 branch = repo.dirstate.branch()
674 bheads = repo.branchheads(branch)
674 bheads = repo.branchheads(branch)
675 rctx = scmutil.revsingle(repo, hex(parent))
675 rctx = scmutil.revsingle(repo, hex(parent))
676 if not opts.get('merge') and op1 != node:
676 if not opts.get('merge') and op1 != node:
677 dsguard = dirstateguard.dirstateguard(repo, 'backout')
677 dsguard = dirstateguard.dirstateguard(repo, 'backout')
678 try:
678 try:
679 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
679 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
680 'backout')
680 'backout')
681 stats = mergemod.update(repo, parent, True, True, node, False)
681 stats = mergemod.update(repo, parent, True, True, node, False)
682 repo.setparents(op1, op2)
682 repo.setparents(op1, op2)
683 dsguard.close()
683 dsguard.close()
684 hg._showstats(repo, stats)
684 hg._showstats(repo, stats)
685 if stats[3]:
685 if stats[3]:
686 repo.ui.status(_("use 'hg resolve' to retry unresolved "
686 repo.ui.status(_("use 'hg resolve' to retry unresolved "
687 "file merges\n"))
687 "file merges\n"))
688 return 1
688 return 1
689 finally:
689 finally:
690 ui.setconfig('ui', 'forcemerge', '', '')
690 ui.setconfig('ui', 'forcemerge', '', '')
691 lockmod.release(dsguard)
691 lockmod.release(dsguard)
692 else:
692 else:
693 hg.clean(repo, node, show_stats=False)
693 hg.clean(repo, node, show_stats=False)
694 repo.dirstate.setbranch(branch)
694 repo.dirstate.setbranch(branch)
695 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
695 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
696
696
697 if opts.get('no_commit'):
697 if opts.get('no_commit'):
698 msg = _("changeset %s backed out, "
698 msg = _("changeset %s backed out, "
699 "don't forget to commit.\n")
699 "don't forget to commit.\n")
700 ui.status(msg % short(node))
700 ui.status(msg % short(node))
701 return 0
701 return 0
702
702
703 def commitfunc(ui, repo, message, match, opts):
703 def commitfunc(ui, repo, message, match, opts):
704 editform = 'backout'
704 editform = 'backout'
705 e = cmdutil.getcommiteditor(editform=editform, **opts)
705 e = cmdutil.getcommiteditor(editform=editform, **opts)
706 if not message:
706 if not message:
707 # we don't translate commit messages
707 # we don't translate commit messages
708 message = "Backed out changeset %s" % short(node)
708 message = "Backed out changeset %s" % short(node)
709 e = cmdutil.getcommiteditor(edit=True, editform=editform)
709 e = cmdutil.getcommiteditor(edit=True, editform=editform)
710 return repo.commit(message, opts.get('user'), opts.get('date'),
710 return repo.commit(message, opts.get('user'), opts.get('date'),
711 match, editor=e)
711 match, editor=e)
712 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
712 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
713 if not newnode:
713 if not newnode:
714 ui.status(_("nothing changed\n"))
714 ui.status(_("nothing changed\n"))
715 return 1
715 return 1
716 cmdutil.commitstatus(repo, newnode, branch, bheads)
716 cmdutil.commitstatus(repo, newnode, branch, bheads)
717
717
718 def nice(node):
718 def nice(node):
719 return '%d:%s' % (repo.changelog.rev(node), short(node))
719 return '%d:%s' % (repo.changelog.rev(node), short(node))
720 ui.status(_('changeset %s backs out changeset %s\n') %
720 ui.status(_('changeset %s backs out changeset %s\n') %
721 (nice(repo.changelog.tip()), nice(node)))
721 (nice(repo.changelog.tip()), nice(node)))
722 if opts.get('merge') and op1 != node:
722 if opts.get('merge') and op1 != node:
723 hg.clean(repo, op1, show_stats=False)
723 hg.clean(repo, op1, show_stats=False)
724 ui.status(_('merging with changeset %s\n')
724 ui.status(_('merging with changeset %s\n')
725 % nice(repo.changelog.tip()))
725 % nice(repo.changelog.tip()))
726 try:
726 try:
727 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
727 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
728 'backout')
728 'backout')
729 return hg.merge(repo, hex(repo.changelog.tip()))
729 return hg.merge(repo, hex(repo.changelog.tip()))
730 finally:
730 finally:
731 ui.setconfig('ui', 'forcemerge', '', '')
731 ui.setconfig('ui', 'forcemerge', '', '')
732 return 0
732 return 0
733
733
734 @command('bisect',
734 @command('bisect',
735 [('r', 'reset', False, _('reset bisect state')),
735 [('r', 'reset', False, _('reset bisect state')),
736 ('g', 'good', False, _('mark changeset good')),
736 ('g', 'good', False, _('mark changeset good')),
737 ('b', 'bad', False, _('mark changeset bad')),
737 ('b', 'bad', False, _('mark changeset bad')),
738 ('s', 'skip', False, _('skip testing changeset')),
738 ('s', 'skip', False, _('skip testing changeset')),
739 ('e', 'extend', False, _('extend the bisect range')),
739 ('e', 'extend', False, _('extend the bisect range')),
740 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
740 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
741 ('U', 'noupdate', False, _('do not update to target'))],
741 ('U', 'noupdate', False, _('do not update to target'))],
742 _("[-gbsr] [-U] [-c CMD] [REV]"))
742 _("[-gbsr] [-U] [-c CMD] [REV]"))
743 def bisect(ui, repo, rev=None, extra=None, command=None,
743 def bisect(ui, repo, rev=None, extra=None, command=None,
744 reset=None, good=None, bad=None, skip=None, extend=None,
744 reset=None, good=None, bad=None, skip=None, extend=None,
745 noupdate=None):
745 noupdate=None):
746 """subdivision search of changesets
746 """subdivision search of changesets
747
747
748 This command helps to find changesets which introduce problems. To
748 This command helps to find changesets which introduce problems. To
749 use, mark the earliest changeset you know exhibits the problem as
749 use, mark the earliest changeset you know exhibits the problem as
750 bad, then mark the latest changeset which is free from the problem
750 bad, then mark the latest changeset which is free from the problem
751 as good. Bisect will update your working directory to a revision
751 as good. Bisect will update your working directory to a revision
752 for testing (unless the -U/--noupdate option is specified). Once
752 for testing (unless the -U/--noupdate option is specified). Once
753 you have performed tests, mark the working directory as good or
753 you have performed tests, mark the working directory as good or
754 bad, and bisect will either update to another candidate changeset
754 bad, and bisect will either update to another candidate changeset
755 or announce that it has found the bad revision.
755 or announce that it has found the bad revision.
756
756
757 As a shortcut, you can also use the revision argument to mark a
757 As a shortcut, you can also use the revision argument to mark a
758 revision as good or bad without checking it out first.
758 revision as good or bad without checking it out first.
759
759
760 If you supply a command, it will be used for automatic bisection.
760 If you supply a command, it will be used for automatic bisection.
761 The environment variable HG_NODE will contain the ID of the
761 The environment variable HG_NODE will contain the ID of the
762 changeset being tested. The exit status of the command will be
762 changeset being tested. The exit status of the command will be
763 used to mark revisions as good or bad: status 0 means good, 125
763 used to mark revisions as good or bad: status 0 means good, 125
764 means to skip the revision, 127 (command not found) will abort the
764 means to skip the revision, 127 (command not found) will abort the
765 bisection, and any other non-zero exit status means the revision
765 bisection, and any other non-zero exit status means the revision
766 is bad.
766 is bad.
767
767
768 .. container:: verbose
768 .. container:: verbose
769
769
770 Some examples:
770 Some examples:
771
771
772 - start a bisection with known bad revision 34, and good revision 12::
772 - start a bisection with known bad revision 34, and good revision 12::
773
773
774 hg bisect --bad 34
774 hg bisect --bad 34
775 hg bisect --good 12
775 hg bisect --good 12
776
776
777 - advance the current bisection by marking current revision as good or
777 - advance the current bisection by marking current revision as good or
778 bad::
778 bad::
779
779
780 hg bisect --good
780 hg bisect --good
781 hg bisect --bad
781 hg bisect --bad
782
782
783 - mark the current revision, or a known revision, to be skipped (e.g. if
783 - mark the current revision, or a known revision, to be skipped (e.g. if
784 that revision is not usable because of another issue)::
784 that revision is not usable because of another issue)::
785
785
786 hg bisect --skip
786 hg bisect --skip
787 hg bisect --skip 23
787 hg bisect --skip 23
788
788
789 - skip all revisions that do not touch directories ``foo`` or ``bar``::
789 - skip all revisions that do not touch directories ``foo`` or ``bar``::
790
790
791 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
791 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
792
792
793 - forget the current bisection::
793 - forget the current bisection::
794
794
795 hg bisect --reset
795 hg bisect --reset
796
796
797 - use 'make && make tests' to automatically find the first broken
797 - use 'make && make tests' to automatically find the first broken
798 revision::
798 revision::
799
799
800 hg bisect --reset
800 hg bisect --reset
801 hg bisect --bad 34
801 hg bisect --bad 34
802 hg bisect --good 12
802 hg bisect --good 12
803 hg bisect --command "make && make tests"
803 hg bisect --command "make && make tests"
804
804
805 - see all changesets whose states are already known in the current
805 - see all changesets whose states are already known in the current
806 bisection::
806 bisection::
807
807
808 hg log -r "bisect(pruned)"
808 hg log -r "bisect(pruned)"
809
809
810 - see the changeset currently being bisected (especially useful
810 - see the changeset currently being bisected (especially useful
811 if running with -U/--noupdate)::
811 if running with -U/--noupdate)::
812
812
813 hg log -r "bisect(current)"
813 hg log -r "bisect(current)"
814
814
815 - see all changesets that took part in the current bisection::
815 - see all changesets that took part in the current bisection::
816
816
817 hg log -r "bisect(range)"
817 hg log -r "bisect(range)"
818
818
819 - you can even get a nice graph::
819 - you can even get a nice graph::
820
820
821 hg log --graph -r "bisect(range)"
821 hg log --graph -r "bisect(range)"
822
822
823 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
823 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
824
824
825 Returns 0 on success.
825 Returns 0 on success.
826 """
826 """
827 # backward compatibility
827 # backward compatibility
828 if rev in "good bad reset init".split():
828 if rev in "good bad reset init".split():
829 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
829 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
830 cmd, rev, extra = rev, extra, None
830 cmd, rev, extra = rev, extra, None
831 if cmd == "good":
831 if cmd == "good":
832 good = True
832 good = True
833 elif cmd == "bad":
833 elif cmd == "bad":
834 bad = True
834 bad = True
835 else:
835 else:
836 reset = True
836 reset = True
837 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
837 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
838 raise error.Abort(_('incompatible arguments'))
838 raise error.Abort(_('incompatible arguments'))
839
839
840 cmdutil.checkunfinished(repo)
840 cmdutil.checkunfinished(repo)
841
841
842 if reset:
842 if reset:
843 hbisect.resetstate(repo)
843 hbisect.resetstate(repo)
844 return
844 return
845
845
846 state = hbisect.load_state(repo)
846 state = hbisect.load_state(repo)
847
847
848 # update state
848 # update state
849 if good or bad or skip:
849 if good or bad or skip:
850 if rev:
850 if rev:
851 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
851 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
852 else:
852 else:
853 nodes = [repo.lookup('.')]
853 nodes = [repo.lookup('.')]
854 if good:
854 if good:
855 state['good'] += nodes
855 state['good'] += nodes
856 elif bad:
856 elif bad:
857 state['bad'] += nodes
857 state['bad'] += nodes
858 elif skip:
858 elif skip:
859 state['skip'] += nodes
859 state['skip'] += nodes
860 hbisect.save_state(repo, state)
860 hbisect.save_state(repo, state)
861 if not (state['good'] and state['bad']):
861 if not (state['good'] and state['bad']):
862 return
862 return
863
863
864 def mayupdate(repo, node, show_stats=True):
864 def mayupdate(repo, node, show_stats=True):
865 """common used update sequence"""
865 """common used update sequence"""
866 if noupdate:
866 if noupdate:
867 return
867 return
868 cmdutil.bailifchanged(repo)
868 cmdutil.bailifchanged(repo)
869 return hg.clean(repo, node, show_stats=show_stats)
869 return hg.clean(repo, node, show_stats=show_stats)
870
870
871 displayer = cmdutil.show_changeset(ui, repo, {})
871 displayer = cmdutil.show_changeset(ui, repo, {})
872
872
873 if command:
873 if command:
874 changesets = 1
874 changesets = 1
875 if noupdate:
875 if noupdate:
876 try:
876 try:
877 node = state['current'][0]
877 node = state['current'][0]
878 except LookupError:
878 except LookupError:
879 raise error.Abort(_('current bisect revision is unknown - '
879 raise error.Abort(_('current bisect revision is unknown - '
880 'start a new bisect to fix'))
880 'start a new bisect to fix'))
881 else:
881 else:
882 node, p2 = repo.dirstate.parents()
882 node, p2 = repo.dirstate.parents()
883 if p2 != nullid:
883 if p2 != nullid:
884 raise error.Abort(_('current bisect revision is a merge'))
884 raise error.Abort(_('current bisect revision is a merge'))
885 if rev:
885 if rev:
886 node = repo[scmutil.revsingle(repo, rev, node)].node()
886 node = repo[scmutil.revsingle(repo, rev, node)].node()
887 try:
887 try:
888 while changesets:
888 while changesets:
889 # update state
889 # update state
890 state['current'] = [node]
890 state['current'] = [node]
891 hbisect.save_state(repo, state)
891 hbisect.save_state(repo, state)
892 status = ui.system(command, environ={'HG_NODE': hex(node)})
892 status = ui.system(command, environ={'HG_NODE': hex(node)})
893 if status == 125:
893 if status == 125:
894 transition = "skip"
894 transition = "skip"
895 elif status == 0:
895 elif status == 0:
896 transition = "good"
896 transition = "good"
897 # status < 0 means process was killed
897 # status < 0 means process was killed
898 elif status == 127:
898 elif status == 127:
899 raise error.Abort(_("failed to execute %s") % command)
899 raise error.Abort(_("failed to execute %s") % command)
900 elif status < 0:
900 elif status < 0:
901 raise error.Abort(_("%s killed") % command)
901 raise error.Abort(_("%s killed") % command)
902 else:
902 else:
903 transition = "bad"
903 transition = "bad"
904 state[transition].append(node)
904 state[transition].append(node)
905 ctx = repo[node]
905 ctx = repo[node]
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
907 hbisect.checkstate(state)
907 hbisect.checkstate(state)
908 # bisect
908 # bisect
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
910 # update to next check
910 # update to next check
911 node = nodes[0]
911 node = nodes[0]
912 mayupdate(repo, node, show_stats=False)
912 mayupdate(repo, node, show_stats=False)
913 finally:
913 finally:
914 state['current'] = [node]
914 state['current'] = [node]
915 hbisect.save_state(repo, state)
915 hbisect.save_state(repo, state)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
917 return
917 return
918
918
919 hbisect.checkstate(state)
919 hbisect.checkstate(state)
920
920
921 # actually bisect
921 # actually bisect
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
923 if extend:
923 if extend:
924 if not changesets:
924 if not changesets:
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
926 if extendnode is not None:
926 if extendnode is not None:
927 ui.write(_("Extending search to changeset %d:%s\n")
927 ui.write(_("Extending search to changeset %d:%s\n")
928 % (extendnode.rev(), extendnode))
928 % (extendnode.rev(), extendnode))
929 state['current'] = [extendnode.node()]
929 state['current'] = [extendnode.node()]
930 hbisect.save_state(repo, state)
930 hbisect.save_state(repo, state)
931 return mayupdate(repo, extendnode.node())
931 return mayupdate(repo, extendnode.node())
932 raise error.Abort(_("nothing to extend"))
932 raise error.Abort(_("nothing to extend"))
933
933
934 if changesets == 0:
934 if changesets == 0:
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
936 else:
936 else:
937 assert len(nodes) == 1 # only a single node can be tested next
937 assert len(nodes) == 1 # only a single node can be tested next
938 node = nodes[0]
938 node = nodes[0]
939 # compute the approximate number of remaining tests
939 # compute the approximate number of remaining tests
940 tests, size = 0, 2
940 tests, size = 0, 2
941 while size <= changesets:
941 while size <= changesets:
942 tests, size = tests + 1, size * 2
942 tests, size = tests + 1, size * 2
943 rev = repo.changelog.rev(node)
943 rev = repo.changelog.rev(node)
944 ui.write(_("Testing changeset %d:%s "
944 ui.write(_("Testing changeset %d:%s "
945 "(%d changesets remaining, ~%d tests)\n")
945 "(%d changesets remaining, ~%d tests)\n")
946 % (rev, short(node), changesets, tests))
946 % (rev, short(node), changesets, tests))
947 state['current'] = [node]
947 state['current'] = [node]
948 hbisect.save_state(repo, state)
948 hbisect.save_state(repo, state)
949 return mayupdate(repo, node)
949 return mayupdate(repo, node)
950
950
951 @command('bookmarks|bookmark',
951 @command('bookmarks|bookmark',
952 [('f', 'force', False, _('force')),
952 [('f', 'force', False, _('force')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
954 ('d', 'delete', False, _('delete a given bookmark')),
954 ('d', 'delete', False, _('delete a given bookmark')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
957 ] + formatteropts,
957 ] + formatteropts,
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
959 def bookmark(ui, repo, *names, **opts):
959 def bookmark(ui, repo, *names, **opts):
960 '''create a new bookmark or list existing bookmarks
960 '''create a new bookmark or list existing bookmarks
961
961
962 Bookmarks are labels on changesets to help track lines of development.
962 Bookmarks are labels on changesets to help track lines of development.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
964 Deleting or moving a bookmark has no effect on the associated changesets.
964 Deleting or moving a bookmark has no effect on the associated changesets.
965
965
966 Creating or updating to a bookmark causes it to be marked as 'active'.
966 Creating or updating to a bookmark causes it to be marked as 'active'.
967 The active bookmark is indicated with a '*'.
967 The active bookmark is indicated with a '*'.
968 When a commit is made, the active bookmark will advance to the new commit.
968 When a commit is made, the active bookmark will advance to the new commit.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
970 Updating away from a bookmark will cause it to be deactivated.
970 Updating away from a bookmark will cause it to be deactivated.
971
971
972 Bookmarks can be pushed and pulled between repositories (see
972 Bookmarks can be pushed and pulled between repositories (see
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
975 be created. Using :hg:`merge` will resolve the divergence.
975 be created. Using :hg:`merge` will resolve the divergence.
976
976
977 A bookmark named '@' has the special property that :hg:`clone` will
977 A bookmark named '@' has the special property that :hg:`clone` will
978 check it out by default if it exists.
978 check it out by default if it exists.
979
979
980 .. container:: verbose
980 .. container:: verbose
981
981
982 Examples:
982 Examples:
983
983
984 - create an active bookmark for a new line of development::
984 - create an active bookmark for a new line of development::
985
985
986 hg book new-feature
986 hg book new-feature
987
987
988 - create an inactive bookmark as a place marker::
988 - create an inactive bookmark as a place marker::
989
989
990 hg book -i reviewed
990 hg book -i reviewed
991
991
992 - create an inactive bookmark on another changeset::
992 - create an inactive bookmark on another changeset::
993
993
994 hg book -r .^ tested
994 hg book -r .^ tested
995
995
996 - rename bookmark turkey to dinner::
996 - rename bookmark turkey to dinner::
997
997
998 hg book -m turkey dinner
998 hg book -m turkey dinner
999
999
1000 - move the '@' bookmark from another branch::
1000 - move the '@' bookmark from another branch::
1001
1001
1002 hg book -f @
1002 hg book -f @
1003 '''
1003 '''
1004 force = opts.get('force')
1004 force = opts.get('force')
1005 rev = opts.get('rev')
1005 rev = opts.get('rev')
1006 delete = opts.get('delete')
1006 delete = opts.get('delete')
1007 rename = opts.get('rename')
1007 rename = opts.get('rename')
1008 inactive = opts.get('inactive')
1008 inactive = opts.get('inactive')
1009
1009
1010 def checkformat(mark):
1010 def checkformat(mark):
1011 mark = mark.strip()
1011 mark = mark.strip()
1012 if not mark:
1012 if not mark:
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1014 "whitespace"))
1014 "whitespace"))
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1016 return mark
1016 return mark
1017
1017
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1019 if mark in marks and not force:
1019 if mark in marks and not force:
1020 if target:
1020 if target:
1021 if marks[mark] == target and target == cur:
1021 if marks[mark] == target and target == cur:
1022 # re-activating a bookmark
1022 # re-activating a bookmark
1023 return
1023 return
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1025 bmctx = repo[marks[mark]]
1025 bmctx = repo[marks[mark]]
1026 divs = [repo[b].node() for b in marks
1026 divs = [repo[b].node() for b in marks
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1028
1028
1029 # allow resolving a single divergent bookmark even if moving
1029 # allow resolving a single divergent bookmark even if moving
1030 # the bookmark across branches when a revision is specified
1030 # the bookmark across branches when a revision is specified
1031 # that contains a divergent bookmark
1031 # that contains a divergent bookmark
1032 if bmctx.rev() not in anc and target in divs:
1032 if bmctx.rev() not in anc and target in divs:
1033 bookmarks.deletedivergent(repo, [target], mark)
1033 bookmarks.deletedivergent(repo, [target], mark)
1034 return
1034 return
1035
1035
1036 deletefrom = [b for b in divs
1036 deletefrom = [b for b in divs
1037 if repo[b].rev() in anc or b == target]
1037 if repo[b].rev() in anc or b == target]
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1041 (mark, short(bmctx.node())))
1041 (mark, short(bmctx.node())))
1042 return
1042 return
1043 raise error.Abort(_("bookmark '%s' already exists "
1043 raise error.Abort(_("bookmark '%s' already exists "
1044 "(use -f to force)") % mark)
1044 "(use -f to force)") % mark)
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1046 and not force):
1046 and not force):
1047 raise error.Abort(
1047 raise error.Abort(
1048 _("a bookmark cannot have the name of an existing branch"))
1048 _("a bookmark cannot have the name of an existing branch"))
1049
1049
1050 if delete and rename:
1050 if delete and rename:
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1052 if delete and rev:
1052 if delete and rev:
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1054 if rename and rev:
1054 if rename and rev:
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1056 if not names and (delete or rev):
1056 if not names and (delete or rev):
1057 raise error.Abort(_("bookmark name required"))
1057 raise error.Abort(_("bookmark name required"))
1058
1058
1059 if delete or rename or names or inactive:
1059 if delete or rename or names or inactive:
1060 wlock = lock = tr = None
1060 wlock = lock = tr = None
1061 try:
1061 try:
1062 wlock = repo.wlock()
1062 wlock = repo.wlock()
1063 lock = repo.lock()
1063 lock = repo.lock()
1064 cur = repo.changectx('.').node()
1064 cur = repo.changectx('.').node()
1065 marks = repo._bookmarks
1065 marks = repo._bookmarks
1066 if delete:
1066 if delete:
1067 tr = repo.transaction('bookmark')
1067 tr = repo.transaction('bookmark')
1068 for mark in names:
1068 for mark in names:
1069 if mark not in marks:
1069 if mark not in marks:
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1071 mark)
1071 mark)
1072 if mark == repo._activebookmark:
1072 if mark == repo._activebookmark:
1073 bookmarks.deactivate(repo)
1073 bookmarks.deactivate(repo)
1074 del marks[mark]
1074 del marks[mark]
1075
1075
1076 elif rename:
1076 elif rename:
1077 tr = repo.transaction('bookmark')
1077 tr = repo.transaction('bookmark')
1078 if not names:
1078 if not names:
1079 raise error.Abort(_("new bookmark name required"))
1079 raise error.Abort(_("new bookmark name required"))
1080 elif len(names) > 1:
1080 elif len(names) > 1:
1081 raise error.Abort(_("only one new bookmark name allowed"))
1081 raise error.Abort(_("only one new bookmark name allowed"))
1082 mark = checkformat(names[0])
1082 mark = checkformat(names[0])
1083 if rename not in marks:
1083 if rename not in marks:
1084 raise error.Abort(_("bookmark '%s' does not exist")
1084 raise error.Abort(_("bookmark '%s' does not exist")
1085 % rename)
1085 % rename)
1086 checkconflict(repo, mark, cur, force)
1086 checkconflict(repo, mark, cur, force)
1087 marks[mark] = marks[rename]
1087 marks[mark] = marks[rename]
1088 if repo._activebookmark == rename and not inactive:
1088 if repo._activebookmark == rename and not inactive:
1089 bookmarks.activate(repo, mark)
1089 bookmarks.activate(repo, mark)
1090 del marks[rename]
1090 del marks[rename]
1091 elif names:
1091 elif names:
1092 tr = repo.transaction('bookmark')
1092 tr = repo.transaction('bookmark')
1093 newact = None
1093 newact = None
1094 for mark in names:
1094 for mark in names:
1095 mark = checkformat(mark)
1095 mark = checkformat(mark)
1096 if newact is None:
1096 if newact is None:
1097 newact = mark
1097 newact = mark
1098 if inactive and mark == repo._activebookmark:
1098 if inactive and mark == repo._activebookmark:
1099 bookmarks.deactivate(repo)
1099 bookmarks.deactivate(repo)
1100 return
1100 return
1101 tgt = cur
1101 tgt = cur
1102 if rev:
1102 if rev:
1103 tgt = scmutil.revsingle(repo, rev).node()
1103 tgt = scmutil.revsingle(repo, rev).node()
1104 checkconflict(repo, mark, cur, force, tgt)
1104 checkconflict(repo, mark, cur, force, tgt)
1105 marks[mark] = tgt
1105 marks[mark] = tgt
1106 if not inactive and cur == marks[newact] and not rev:
1106 if not inactive and cur == marks[newact] and not rev:
1107 bookmarks.activate(repo, newact)
1107 bookmarks.activate(repo, newact)
1108 elif cur != tgt and newact == repo._activebookmark:
1108 elif cur != tgt and newact == repo._activebookmark:
1109 bookmarks.deactivate(repo)
1109 bookmarks.deactivate(repo)
1110 elif inactive:
1110 elif inactive:
1111 if len(marks) == 0:
1111 if len(marks) == 0:
1112 ui.status(_("no bookmarks set\n"))
1112 ui.status(_("no bookmarks set\n"))
1113 elif not repo._activebookmark:
1113 elif not repo._activebookmark:
1114 ui.status(_("no active bookmark\n"))
1114 ui.status(_("no active bookmark\n"))
1115 else:
1115 else:
1116 bookmarks.deactivate(repo)
1116 bookmarks.deactivate(repo)
1117 if tr is not None:
1117 if tr is not None:
1118 marks.recordchange(tr)
1118 marks.recordchange(tr)
1119 tr.close()
1119 tr.close()
1120 finally:
1120 finally:
1121 lockmod.release(tr, lock, wlock)
1121 lockmod.release(tr, lock, wlock)
1122 else: # show bookmarks
1122 else: # show bookmarks
1123 fm = ui.formatter('bookmarks', opts)
1123 fm = ui.formatter('bookmarks', opts)
1124 hexfn = fm.hexfunc
1124 hexfn = fm.hexfunc
1125 marks = repo._bookmarks
1125 marks = repo._bookmarks
1126 if len(marks) == 0 and fm.isplain():
1126 if len(marks) == 0 and fm.isplain():
1127 ui.status(_("no bookmarks set\n"))
1127 ui.status(_("no bookmarks set\n"))
1128 for bmark, n in sorted(marks.iteritems()):
1128 for bmark, n in sorted(marks.iteritems()):
1129 active = repo._activebookmark
1129 active = repo._activebookmark
1130 if bmark == active:
1130 if bmark == active:
1131 prefix, label = '*', activebookmarklabel
1131 prefix, label = '*', activebookmarklabel
1132 else:
1132 else:
1133 prefix, label = ' ', ''
1133 prefix, label = ' ', ''
1134
1134
1135 fm.startitem()
1135 fm.startitem()
1136 if not ui.quiet:
1136 if not ui.quiet:
1137 fm.plain(' %s ' % prefix, label=label)
1137 fm.plain(' %s ' % prefix, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1139 pad = " " * (25 - encoding.colwidth(bmark))
1139 pad = " " * (25 - encoding.colwidth(bmark))
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1141 repo.changelog.rev(n), hexfn(n), label=label)
1141 repo.changelog.rev(n), hexfn(n), label=label)
1142 fm.data(active=(bmark == active))
1142 fm.data(active=(bmark == active))
1143 fm.plain('\n')
1143 fm.plain('\n')
1144 fm.end()
1144 fm.end()
1145
1145
1146 @command('branch',
1146 @command('branch',
1147 [('f', 'force', None,
1147 [('f', 'force', None,
1148 _('set branch name even if it shadows an existing branch')),
1148 _('set branch name even if it shadows an existing branch')),
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1150 _('[-fC] [NAME]'))
1150 _('[-fC] [NAME]'))
1151 def branch(ui, repo, label=None, **opts):
1151 def branch(ui, repo, label=None, **opts):
1152 """set or show the current branch name
1152 """set or show the current branch name
1153
1153
1154 .. note::
1154 .. note::
1155
1155
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1158 information about named branches and bookmarks.
1158 information about named branches and bookmarks.
1159
1159
1160 With no argument, show the current branch name. With one argument,
1160 With no argument, show the current branch name. With one argument,
1161 set the working directory branch name (the branch will not exist
1161 set the working directory branch name (the branch will not exist
1162 in the repository until the next commit). Standard practice
1162 in the repository until the next commit). Standard practice
1163 recommends that primary development take place on the 'default'
1163 recommends that primary development take place on the 'default'
1164 branch.
1164 branch.
1165
1165
1166 Unless -f/--force is specified, branch will not let you set a
1166 Unless -f/--force is specified, branch will not let you set a
1167 branch name that already exists.
1167 branch name that already exists.
1168
1168
1169 Use -C/--clean to reset the working directory branch to that of
1169 Use -C/--clean to reset the working directory branch to that of
1170 the parent of the working directory, negating a previous branch
1170 the parent of the working directory, negating a previous branch
1171 change.
1171 change.
1172
1172
1173 Use the command :hg:`update` to switch to an existing branch. Use
1173 Use the command :hg:`update` to switch to an existing branch. Use
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1175 When all heads of a branch are closed, the branch will be
1175 When all heads of a branch are closed, the branch will be
1176 considered closed.
1176 considered closed.
1177
1177
1178 Returns 0 on success.
1178 Returns 0 on success.
1179 """
1179 """
1180 if label:
1180 if label:
1181 label = label.strip()
1181 label = label.strip()
1182
1182
1183 if not opts.get('clean') and not label:
1183 if not opts.get('clean') and not label:
1184 ui.write("%s\n" % repo.dirstate.branch())
1184 ui.write("%s\n" % repo.dirstate.branch())
1185 return
1185 return
1186
1186
1187 with repo.wlock():
1187 with repo.wlock():
1188 if opts.get('clean'):
1188 if opts.get('clean'):
1189 label = repo[None].p1().branch()
1189 label = repo[None].p1().branch()
1190 repo.dirstate.setbranch(label)
1190 repo.dirstate.setbranch(label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1192 elif label:
1192 elif label:
1193 if not opts.get('force') and label in repo.branchmap():
1193 if not opts.get('force') and label in repo.branchmap():
1194 if label not in [p.branch() for p in repo[None].parents()]:
1194 if label not in [p.branch() for p in repo[None].parents()]:
1195 raise error.Abort(_('a branch of the same name already'
1195 raise error.Abort(_('a branch of the same name already'
1196 ' exists'),
1196 ' exists'),
1197 # i18n: "it" refers to an existing branch
1197 # i18n: "it" refers to an existing branch
1198 hint=_("use 'hg update' to switch to it"))
1198 hint=_("use 'hg update' to switch to it"))
1199 scmutil.checknewlabel(repo, label, 'branch')
1199 scmutil.checknewlabel(repo, label, 'branch')
1200 repo.dirstate.setbranch(label)
1200 repo.dirstate.setbranch(label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1202
1202
1203 # find any open named branches aside from default
1203 # find any open named branches aside from default
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1205 if n != "default" and not c]
1205 if n != "default" and not c]
1206 if not others:
1206 if not others:
1207 ui.status(_('(branches are permanent and global, '
1207 ui.status(_('(branches are permanent and global, '
1208 'did you want a bookmark?)\n'))
1208 'did you want a bookmark?)\n'))
1209
1209
1210 @command('branches',
1210 @command('branches',
1211 [('a', 'active', False,
1211 [('a', 'active', False,
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1214 ] + formatteropts,
1214 ] + formatteropts,
1215 _('[-c]'))
1215 _('[-c]'))
1216 def branches(ui, repo, active=False, closed=False, **opts):
1216 def branches(ui, repo, active=False, closed=False, **opts):
1217 """list repository named branches
1217 """list repository named branches
1218
1218
1219 List the repository's named branches, indicating which ones are
1219 List the repository's named branches, indicating which ones are
1220 inactive. If -c/--closed is specified, also list branches which have
1220 inactive. If -c/--closed is specified, also list branches which have
1221 been marked closed (see :hg:`commit --close-branch`).
1221 been marked closed (see :hg:`commit --close-branch`).
1222
1222
1223 Use the command :hg:`update` to switch to an existing branch.
1223 Use the command :hg:`update` to switch to an existing branch.
1224
1224
1225 Returns 0.
1225 Returns 0.
1226 """
1226 """
1227
1227
1228 fm = ui.formatter('branches', opts)
1228 fm = ui.formatter('branches', opts)
1229 hexfunc = fm.hexfunc
1229 hexfunc = fm.hexfunc
1230
1230
1231 allheads = set(repo.heads())
1231 allheads = set(repo.heads())
1232 branches = []
1232 branches = []
1233 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1233 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1234 isactive = not isclosed and bool(set(heads) & allheads)
1234 isactive = not isclosed and bool(set(heads) & allheads)
1235 branches.append((tag, repo[tip], isactive, not isclosed))
1235 branches.append((tag, repo[tip], isactive, not isclosed))
1236 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1236 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1237 reverse=True)
1237 reverse=True)
1238
1238
1239 for tag, ctx, isactive, isopen in branches:
1239 for tag, ctx, isactive, isopen in branches:
1240 if active and not isactive:
1240 if active and not isactive:
1241 continue
1241 continue
1242 if isactive:
1242 if isactive:
1243 label = 'branches.active'
1243 label = 'branches.active'
1244 notice = ''
1244 notice = ''
1245 elif not isopen:
1245 elif not isopen:
1246 if not closed:
1246 if not closed:
1247 continue
1247 continue
1248 label = 'branches.closed'
1248 label = 'branches.closed'
1249 notice = _(' (closed)')
1249 notice = _(' (closed)')
1250 else:
1250 else:
1251 label = 'branches.inactive'
1251 label = 'branches.inactive'
1252 notice = _(' (inactive)')
1252 notice = _(' (inactive)')
1253 current = (tag == repo.dirstate.branch())
1253 current = (tag == repo.dirstate.branch())
1254 if current:
1254 if current:
1255 label = 'branches.current'
1255 label = 'branches.current'
1256
1256
1257 fm.startitem()
1257 fm.startitem()
1258 fm.write('branch', '%s', tag, label=label)
1258 fm.write('branch', '%s', tag, label=label)
1259 rev = ctx.rev()
1259 rev = ctx.rev()
1260 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1260 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1261 fmt = ' ' * padsize + ' %d:%s'
1261 fmt = ' ' * padsize + ' %d:%s'
1262 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1262 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1263 label='log.changeset changeset.%s' % ctx.phasestr())
1263 label='log.changeset changeset.%s' % ctx.phasestr())
1264 fm.data(active=isactive, closed=not isopen, current=current)
1264 fm.data(active=isactive, closed=not isopen, current=current)
1265 if not ui.quiet:
1265 if not ui.quiet:
1266 fm.plain(notice)
1266 fm.plain(notice)
1267 fm.plain('\n')
1267 fm.plain('\n')
1268 fm.end()
1268 fm.end()
1269
1269
1270 @command('bundle',
1270 @command('bundle',
1271 [('f', 'force', None, _('run even when the destination is unrelated')),
1271 [('f', 'force', None, _('run even when the destination is unrelated')),
1272 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1272 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1273 _('REV')),
1273 _('REV')),
1274 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1274 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1275 _('BRANCH')),
1275 _('BRANCH')),
1276 ('', 'base', [],
1276 ('', 'base', [],
1277 _('a base changeset assumed to be available at the destination'),
1277 _('a base changeset assumed to be available at the destination'),
1278 _('REV')),
1278 _('REV')),
1279 ('a', 'all', None, _('bundle all changesets in the repository')),
1279 ('a', 'all', None, _('bundle all changesets in the repository')),
1280 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1280 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1281 ] + remoteopts,
1281 ] + remoteopts,
1282 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1282 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1283 def bundle(ui, repo, fname, dest=None, **opts):
1283 def bundle(ui, repo, fname, dest=None, **opts):
1284 """create a changegroup file
1284 """create a changegroup file
1285
1285
1286 Generate a changegroup file collecting changesets to be added
1286 Generate a changegroup file collecting changesets to be added
1287 to a repository.
1287 to a repository.
1288
1288
1289 To create a bundle containing all changesets, use -a/--all
1289 To create a bundle containing all changesets, use -a/--all
1290 (or --base null). Otherwise, hg assumes the destination will have
1290 (or --base null). Otherwise, hg assumes the destination will have
1291 all the nodes you specify with --base parameters. Otherwise, hg
1291 all the nodes you specify with --base parameters. Otherwise, hg
1292 will assume the repository has all the nodes in destination, or
1292 will assume the repository has all the nodes in destination, or
1293 default-push/default if no destination is specified.
1293 default-push/default if no destination is specified.
1294
1294
1295 You can change bundle format with the -t/--type option. You can
1295 You can change bundle format with the -t/--type option. You can
1296 specify a compression, a bundle version or both using a dash
1296 specify a compression, a bundle version or both using a dash
1297 (comp-version). The available compression methods are: none, bzip2,
1297 (comp-version). The available compression methods are: none, bzip2,
1298 and gzip (by default, bundles are compressed using bzip2). The
1298 and gzip (by default, bundles are compressed using bzip2). The
1299 available formats are: v1, v2 (default to most suitable).
1299 available formats are: v1, v2 (default to most suitable).
1300
1300
1301 The bundle file can then be transferred using conventional means
1301 The bundle file can then be transferred using conventional means
1302 and applied to another repository with the unbundle or pull
1302 and applied to another repository with the unbundle or pull
1303 command. This is useful when direct push and pull are not
1303 command. This is useful when direct push and pull are not
1304 available or when exporting an entire repository is undesirable.
1304 available or when exporting an entire repository is undesirable.
1305
1305
1306 Applying bundles preserves all changeset contents including
1306 Applying bundles preserves all changeset contents including
1307 permissions, copy/rename information, and revision history.
1307 permissions, copy/rename information, and revision history.
1308
1308
1309 Returns 0 on success, 1 if no changes found.
1309 Returns 0 on success, 1 if no changes found.
1310 """
1310 """
1311 revs = None
1311 revs = None
1312 if 'rev' in opts:
1312 if 'rev' in opts:
1313 revstrings = opts['rev']
1313 revstrings = opts['rev']
1314 revs = scmutil.revrange(repo, revstrings)
1314 revs = scmutil.revrange(repo, revstrings)
1315 if revstrings and not revs:
1315 if revstrings and not revs:
1316 raise error.Abort(_('no commits to bundle'))
1316 raise error.Abort(_('no commits to bundle'))
1317
1317
1318 bundletype = opts.get('type', 'bzip2').lower()
1318 bundletype = opts.get('type', 'bzip2').lower()
1319 try:
1319 try:
1320 bcompression, cgversion, params = exchange.parsebundlespec(
1320 bcompression, cgversion, params = exchange.parsebundlespec(
1321 repo, bundletype, strict=False)
1321 repo, bundletype, strict=False)
1322 except error.UnsupportedBundleSpecification as e:
1322 except error.UnsupportedBundleSpecification as e:
1323 raise error.Abort(str(e),
1323 raise error.Abort(str(e),
1324 hint=_("see 'hg help bundle' for supported "
1324 hint=_("see 'hg help bundle' for supported "
1325 "values for --type"))
1325 "values for --type"))
1326
1326
1327 # Packed bundles are a pseudo bundle format for now.
1327 # Packed bundles are a pseudo bundle format for now.
1328 if cgversion == 's1':
1328 if cgversion == 's1':
1329 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1329 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1330 hint=_("use 'hg debugcreatestreamclonebundle'"))
1330 hint=_("use 'hg debugcreatestreamclonebundle'"))
1331
1331
1332 if opts.get('all'):
1332 if opts.get('all'):
1333 if dest:
1333 if dest:
1334 raise error.Abort(_("--all is incompatible with specifying "
1334 raise error.Abort(_("--all is incompatible with specifying "
1335 "a destination"))
1335 "a destination"))
1336 if opts.get('base'):
1336 if opts.get('base'):
1337 ui.warn(_("ignoring --base because --all was specified\n"))
1337 ui.warn(_("ignoring --base because --all was specified\n"))
1338 base = ['null']
1338 base = ['null']
1339 else:
1339 else:
1340 base = scmutil.revrange(repo, opts.get('base'))
1340 base = scmutil.revrange(repo, opts.get('base'))
1341 # TODO: get desired bundlecaps from command line.
1341 # TODO: get desired bundlecaps from command line.
1342 bundlecaps = None
1342 bundlecaps = None
1343 if cgversion not in changegroup.supportedoutgoingversions(repo):
1343 if cgversion not in changegroup.supportedoutgoingversions(repo):
1344 raise error.Abort(_("repository does not support bundle version %s") %
1344 raise error.Abort(_("repository does not support bundle version %s") %
1345 cgversion)
1345 cgversion)
1346
1346
1347 if base:
1347 if base:
1348 if dest:
1348 if dest:
1349 raise error.Abort(_("--base is incompatible with specifying "
1349 raise error.Abort(_("--base is incompatible with specifying "
1350 "a destination"))
1350 "a destination"))
1351 common = [repo.lookup(rev) for rev in base]
1351 common = [repo.lookup(rev) for rev in base]
1352 heads = revs and map(repo.lookup, revs) or None
1352 heads = revs and map(repo.lookup, revs) or None
1353 outgoing = discovery.outgoing(repo, common, heads)
1353 outgoing = discovery.outgoing(repo, common, heads)
1354 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1354 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1355 bundlecaps=bundlecaps,
1355 bundlecaps=bundlecaps,
1356 version=cgversion)
1356 version=cgversion)
1357 outgoing = None
1357 outgoing = None
1358 else:
1358 else:
1359 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1359 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1360 dest, branches = hg.parseurl(dest, opts.get('branch'))
1360 dest, branches = hg.parseurl(dest, opts.get('branch'))
1361 other = hg.peer(repo, opts, dest)
1361 other = hg.peer(repo, opts, dest)
1362 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1362 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1363 heads = revs and map(repo.lookup, revs) or revs
1363 heads = revs and map(repo.lookup, revs) or revs
1364 outgoing = discovery.findcommonoutgoing(repo, other,
1364 outgoing = discovery.findcommonoutgoing(repo, other,
1365 onlyheads=heads,
1365 onlyheads=heads,
1366 force=opts.get('force'),
1366 force=opts.get('force'),
1367 portable=True)
1367 portable=True)
1368 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1368 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1369 bundlecaps, version=cgversion)
1369 bundlecaps, version=cgversion)
1370 if not cg:
1370 if not cg:
1371 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1371 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1372 return 1
1372 return 1
1373
1373
1374 if cgversion == '01': #bundle1
1374 if cgversion == '01': #bundle1
1375 if bcompression is None:
1375 if bcompression is None:
1376 bcompression = 'UN'
1376 bcompression = 'UN'
1377 bversion = 'HG10' + bcompression
1377 bversion = 'HG10' + bcompression
1378 bcompression = None
1378 bcompression = None
1379 else:
1379 else:
1380 assert cgversion == '02'
1380 assert cgversion == '02'
1381 bversion = 'HG20'
1381 bversion = 'HG20'
1382
1382
1383 # TODO compression options should be derived from bundlespec parsing.
1383 # TODO compression options should be derived from bundlespec parsing.
1384 # This is a temporary hack to allow adjusting bundle compression
1384 # This is a temporary hack to allow adjusting bundle compression
1385 # level without a) formalizing the bundlespec changes to declare it
1385 # level without a) formalizing the bundlespec changes to declare it
1386 # b) introducing a command flag.
1386 # b) introducing a command flag.
1387 compopts = {}
1387 compopts = {}
1388 complevel = ui.configint('experimental', 'bundlecomplevel')
1388 complevel = ui.configint('experimental', 'bundlecomplevel')
1389 if complevel is not None:
1389 if complevel is not None:
1390 compopts['level'] = complevel
1390 compopts['level'] = complevel
1391
1391
1392 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1392 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1393 compopts=compopts)
1393 compopts=compopts)
1394
1394
1395 @command('cat',
1395 @command('cat',
1396 [('o', 'output', '',
1396 [('o', 'output', '',
1397 _('print output to file with formatted name'), _('FORMAT')),
1397 _('print output to file with formatted name'), _('FORMAT')),
1398 ('r', 'rev', '', _('print the given revision'), _('REV')),
1398 ('r', 'rev', '', _('print the given revision'), _('REV')),
1399 ('', 'decode', None, _('apply any matching decode filter')),
1399 ('', 'decode', None, _('apply any matching decode filter')),
1400 ] + walkopts,
1400 ] + walkopts,
1401 _('[OPTION]... FILE...'),
1401 _('[OPTION]... FILE...'),
1402 inferrepo=True)
1402 inferrepo=True)
1403 def cat(ui, repo, file1, *pats, **opts):
1403 def cat(ui, repo, file1, *pats, **opts):
1404 """output the current or given revision of files
1404 """output the current or given revision of files
1405
1405
1406 Print the specified files as they were at the given revision. If
1406 Print the specified files as they were at the given revision. If
1407 no revision is given, the parent of the working directory is used.
1407 no revision is given, the parent of the working directory is used.
1408
1408
1409 Output may be to a file, in which case the name of the file is
1409 Output may be to a file, in which case the name of the file is
1410 given using a format string. The formatting rules as follows:
1410 given using a format string. The formatting rules as follows:
1411
1411
1412 :``%%``: literal "%" character
1412 :``%%``: literal "%" character
1413 :``%s``: basename of file being printed
1413 :``%s``: basename of file being printed
1414 :``%d``: dirname of file being printed, or '.' if in repository root
1414 :``%d``: dirname of file being printed, or '.' if in repository root
1415 :``%p``: root-relative path name of file being printed
1415 :``%p``: root-relative path name of file being printed
1416 :``%H``: changeset hash (40 hexadecimal digits)
1416 :``%H``: changeset hash (40 hexadecimal digits)
1417 :``%R``: changeset revision number
1417 :``%R``: changeset revision number
1418 :``%h``: short-form changeset hash (12 hexadecimal digits)
1418 :``%h``: short-form changeset hash (12 hexadecimal digits)
1419 :``%r``: zero-padded changeset revision number
1419 :``%r``: zero-padded changeset revision number
1420 :``%b``: basename of the exporting repository
1420 :``%b``: basename of the exporting repository
1421
1421
1422 Returns 0 on success.
1422 Returns 0 on success.
1423 """
1423 """
1424 ctx = scmutil.revsingle(repo, opts.get('rev'))
1424 ctx = scmutil.revsingle(repo, opts.get('rev'))
1425 m = scmutil.match(ctx, (file1,) + pats, opts)
1425 m = scmutil.match(ctx, (file1,) + pats, opts)
1426
1426
1427 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1427 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1428
1428
1429 @command('^clone',
1429 @command('^clone',
1430 [('U', 'noupdate', None, _('the clone will include an empty working '
1430 [('U', 'noupdate', None, _('the clone will include an empty working '
1431 'directory (only a repository)')),
1431 'directory (only a repository)')),
1432 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1432 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1433 _('REV')),
1433 _('REV')),
1434 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1434 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1435 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1435 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1436 ('', 'pull', None, _('use pull protocol to copy metadata')),
1436 ('', 'pull', None, _('use pull protocol to copy metadata')),
1437 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1437 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1438 ] + remoteopts,
1438 ] + remoteopts,
1439 _('[OPTION]... SOURCE [DEST]'),
1439 _('[OPTION]... SOURCE [DEST]'),
1440 norepo=True)
1440 norepo=True)
1441 def clone(ui, source, dest=None, **opts):
1441 def clone(ui, source, dest=None, **opts):
1442 """make a copy of an existing repository
1442 """make a copy of an existing repository
1443
1443
1444 Create a copy of an existing repository in a new directory.
1444 Create a copy of an existing repository in a new directory.
1445
1445
1446 If no destination directory name is specified, it defaults to the
1446 If no destination directory name is specified, it defaults to the
1447 basename of the source.
1447 basename of the source.
1448
1448
1449 The location of the source is added to the new repository's
1449 The location of the source is added to the new repository's
1450 ``.hg/hgrc`` file, as the default to be used for future pulls.
1450 ``.hg/hgrc`` file, as the default to be used for future pulls.
1451
1451
1452 Only local paths and ``ssh://`` URLs are supported as
1452 Only local paths and ``ssh://`` URLs are supported as
1453 destinations. For ``ssh://`` destinations, no working directory or
1453 destinations. For ``ssh://`` destinations, no working directory or
1454 ``.hg/hgrc`` will be created on the remote side.
1454 ``.hg/hgrc`` will be created on the remote side.
1455
1455
1456 If the source repository has a bookmark called '@' set, that
1456 If the source repository has a bookmark called '@' set, that
1457 revision will be checked out in the new repository by default.
1457 revision will be checked out in the new repository by default.
1458
1458
1459 To check out a particular version, use -u/--update, or
1459 To check out a particular version, use -u/--update, or
1460 -U/--noupdate to create a clone with no working directory.
1460 -U/--noupdate to create a clone with no working directory.
1461
1461
1462 To pull only a subset of changesets, specify one or more revisions
1462 To pull only a subset of changesets, specify one or more revisions
1463 identifiers with -r/--rev or branches with -b/--branch. The
1463 identifiers with -r/--rev or branches with -b/--branch. The
1464 resulting clone will contain only the specified changesets and
1464 resulting clone will contain only the specified changesets and
1465 their ancestors. These options (or 'clone src#rev dest') imply
1465 their ancestors. These options (or 'clone src#rev dest') imply
1466 --pull, even for local source repositories.
1466 --pull, even for local source repositories.
1467
1467
1468 .. note::
1468 .. note::
1469
1469
1470 Specifying a tag will include the tagged changeset but not the
1470 Specifying a tag will include the tagged changeset but not the
1471 changeset containing the tag.
1471 changeset containing the tag.
1472
1472
1473 .. container:: verbose
1473 .. container:: verbose
1474
1474
1475 For efficiency, hardlinks are used for cloning whenever the
1475 For efficiency, hardlinks are used for cloning whenever the
1476 source and destination are on the same filesystem (note this
1476 source and destination are on the same filesystem (note this
1477 applies only to the repository data, not to the working
1477 applies only to the repository data, not to the working
1478 directory). Some filesystems, such as AFS, implement hardlinking
1478 directory). Some filesystems, such as AFS, implement hardlinking
1479 incorrectly, but do not report errors. In these cases, use the
1479 incorrectly, but do not report errors. In these cases, use the
1480 --pull option to avoid hardlinking.
1480 --pull option to avoid hardlinking.
1481
1481
1482 In some cases, you can clone repositories and the working
1482 In some cases, you can clone repositories and the working
1483 directory using full hardlinks with ::
1483 directory using full hardlinks with ::
1484
1484
1485 $ cp -al REPO REPOCLONE
1485 $ cp -al REPO REPOCLONE
1486
1486
1487 This is the fastest way to clone, but it is not always safe. The
1487 This is the fastest way to clone, but it is not always safe. The
1488 operation is not atomic (making sure REPO is not modified during
1488 operation is not atomic (making sure REPO is not modified during
1489 the operation is up to you) and you have to make sure your
1489 the operation is up to you) and you have to make sure your
1490 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1490 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1491 so). Also, this is not compatible with certain extensions that
1491 so). Also, this is not compatible with certain extensions that
1492 place their metadata under the .hg directory, such as mq.
1492 place their metadata under the .hg directory, such as mq.
1493
1493
1494 Mercurial will update the working directory to the first applicable
1494 Mercurial will update the working directory to the first applicable
1495 revision from this list:
1495 revision from this list:
1496
1496
1497 a) null if -U or the source repository has no changesets
1497 a) null if -U or the source repository has no changesets
1498 b) if -u . and the source repository is local, the first parent of
1498 b) if -u . and the source repository is local, the first parent of
1499 the source repository's working directory
1499 the source repository's working directory
1500 c) the changeset specified with -u (if a branch name, this means the
1500 c) the changeset specified with -u (if a branch name, this means the
1501 latest head of that branch)
1501 latest head of that branch)
1502 d) the changeset specified with -r
1502 d) the changeset specified with -r
1503 e) the tipmost head specified with -b
1503 e) the tipmost head specified with -b
1504 f) the tipmost head specified with the url#branch source syntax
1504 f) the tipmost head specified with the url#branch source syntax
1505 g) the revision marked with the '@' bookmark, if present
1505 g) the revision marked with the '@' bookmark, if present
1506 h) the tipmost head of the default branch
1506 h) the tipmost head of the default branch
1507 i) tip
1507 i) tip
1508
1508
1509 When cloning from servers that support it, Mercurial may fetch
1509 When cloning from servers that support it, Mercurial may fetch
1510 pre-generated data from a server-advertised URL. When this is done,
1510 pre-generated data from a server-advertised URL. When this is done,
1511 hooks operating on incoming changesets and changegroups may fire twice,
1511 hooks operating on incoming changesets and changegroups may fire twice,
1512 once for the bundle fetched from the URL and another for any additional
1512 once for the bundle fetched from the URL and another for any additional
1513 data not fetched from this URL. In addition, if an error occurs, the
1513 data not fetched from this URL. In addition, if an error occurs, the
1514 repository may be rolled back to a partial clone. This behavior may
1514 repository may be rolled back to a partial clone. This behavior may
1515 change in future releases. See :hg:`help -e clonebundles` for more.
1515 change in future releases. See :hg:`help -e clonebundles` for more.
1516
1516
1517 Examples:
1517 Examples:
1518
1518
1519 - clone a remote repository to a new directory named hg/::
1519 - clone a remote repository to a new directory named hg/::
1520
1520
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1522
1522
1523 - create a lightweight local clone::
1523 - create a lightweight local clone::
1524
1524
1525 hg clone project/ project-feature/
1525 hg clone project/ project-feature/
1526
1526
1527 - clone from an absolute path on an ssh server (note double-slash)::
1527 - clone from an absolute path on an ssh server (note double-slash)::
1528
1528
1529 hg clone ssh://user@server//home/projects/alpha/
1529 hg clone ssh://user@server//home/projects/alpha/
1530
1530
1531 - do a high-speed clone over a LAN while checking out a
1531 - do a high-speed clone over a LAN while checking out a
1532 specified version::
1532 specified version::
1533
1533
1534 hg clone --uncompressed http://server/repo -u 1.5
1534 hg clone --uncompressed http://server/repo -u 1.5
1535
1535
1536 - create a repository without changesets after a particular revision::
1536 - create a repository without changesets after a particular revision::
1537
1537
1538 hg clone -r 04e544 experimental/ good/
1538 hg clone -r 04e544 experimental/ good/
1539
1539
1540 - clone (and track) a particular named branch::
1540 - clone (and track) a particular named branch::
1541
1541
1542 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1542 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1543
1543
1544 See :hg:`help urls` for details on specifying URLs.
1544 See :hg:`help urls` for details on specifying URLs.
1545
1545
1546 Returns 0 on success.
1546 Returns 0 on success.
1547 """
1547 """
1548 if opts.get('noupdate') and opts.get('updaterev'):
1548 if opts.get('noupdate') and opts.get('updaterev'):
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1550
1550
1551 r = hg.clone(ui, opts, source, dest,
1551 r = hg.clone(ui, opts, source, dest,
1552 pull=opts.get('pull'),
1552 pull=opts.get('pull'),
1553 stream=opts.get('uncompressed'),
1553 stream=opts.get('uncompressed'),
1554 rev=opts.get('rev'),
1554 rev=opts.get('rev'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1556 branch=opts.get('branch'),
1556 branch=opts.get('branch'),
1557 shareopts=opts.get('shareopts'))
1557 shareopts=opts.get('shareopts'))
1558
1558
1559 return r is None
1559 return r is None
1560
1560
1561 @command('^commit|ci',
1561 @command('^commit|ci',
1562 [('A', 'addremove', None,
1562 [('A', 'addremove', None,
1563 _('mark new/missing files as added/removed before committing')),
1563 _('mark new/missing files as added/removed before committing')),
1564 ('', 'close-branch', None,
1564 ('', 'close-branch', None,
1565 _('mark a branch head as closed')),
1565 _('mark a branch head as closed')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1571 _('[OPTION]... [FILE]...'),
1571 _('[OPTION]... [FILE]...'),
1572 inferrepo=True)
1572 inferrepo=True)
1573 def commit(ui, repo, *pats, **opts):
1573 def commit(ui, repo, *pats, **opts):
1574 """commit the specified files or all outstanding changes
1574 """commit the specified files or all outstanding changes
1575
1575
1576 Commit changes to the given files into the repository. Unlike a
1576 Commit changes to the given files into the repository. Unlike a
1577 centralized SCM, this operation is a local operation. See
1577 centralized SCM, this operation is a local operation. See
1578 :hg:`push` for a way to actively distribute your changes.
1578 :hg:`push` for a way to actively distribute your changes.
1579
1579
1580 If a list of files is omitted, all changes reported by :hg:`status`
1580 If a list of files is omitted, all changes reported by :hg:`status`
1581 will be committed.
1581 will be committed.
1582
1582
1583 If you are committing the result of a merge, do not provide any
1583 If you are committing the result of a merge, do not provide any
1584 filenames or -I/-X filters.
1584 filenames or -I/-X filters.
1585
1585
1586 If no commit message is specified, Mercurial starts your
1586 If no commit message is specified, Mercurial starts your
1587 configured editor where you can enter a message. In case your
1587 configured editor where you can enter a message. In case your
1588 commit fails, you will find a backup of your message in
1588 commit fails, you will find a backup of your message in
1589 ``.hg/last-message.txt``.
1589 ``.hg/last-message.txt``.
1590
1590
1591 The --close-branch flag can be used to mark the current branch
1591 The --close-branch flag can be used to mark the current branch
1592 head closed. When all heads of a branch are closed, the branch
1592 head closed. When all heads of a branch are closed, the branch
1593 will be considered closed and no longer listed.
1593 will be considered closed and no longer listed.
1594
1594
1595 The --amend flag can be used to amend the parent of the
1595 The --amend flag can be used to amend the parent of the
1596 working directory with a new commit that contains the changes
1596 working directory with a new commit that contains the changes
1597 in the parent in addition to those currently reported by :hg:`status`,
1597 in the parent in addition to those currently reported by :hg:`status`,
1598 if there are any. The old commit is stored in a backup bundle in
1598 if there are any. The old commit is stored in a backup bundle in
1599 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1599 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1600 on how to restore it).
1600 on how to restore it).
1601
1601
1602 Message, user and date are taken from the amended commit unless
1602 Message, user and date are taken from the amended commit unless
1603 specified. When a message isn't specified on the command line,
1603 specified. When a message isn't specified on the command line,
1604 the editor will open with the message of the amended commit.
1604 the editor will open with the message of the amended commit.
1605
1605
1606 It is not possible to amend public changesets (see :hg:`help phases`)
1606 It is not possible to amend public changesets (see :hg:`help phases`)
1607 or changesets that have children.
1607 or changesets that have children.
1608
1608
1609 See :hg:`help dates` for a list of formats valid for -d/--date.
1609 See :hg:`help dates` for a list of formats valid for -d/--date.
1610
1610
1611 Returns 0 on success, 1 if nothing changed.
1611 Returns 0 on success, 1 if nothing changed.
1612
1612
1613 .. container:: verbose
1613 .. container:: verbose
1614
1614
1615 Examples:
1615 Examples:
1616
1616
1617 - commit all files ending in .py::
1617 - commit all files ending in .py::
1618
1618
1619 hg commit --include "set:**.py"
1619 hg commit --include "set:**.py"
1620
1620
1621 - commit all non-binary files::
1621 - commit all non-binary files::
1622
1622
1623 hg commit --exclude "set:binary()"
1623 hg commit --exclude "set:binary()"
1624
1624
1625 - amend the current commit and set the date to now::
1625 - amend the current commit and set the date to now::
1626
1626
1627 hg commit --amend --date now
1627 hg commit --amend --date now
1628 """
1628 """
1629 wlock = lock = None
1629 wlock = lock = None
1630 try:
1630 try:
1631 wlock = repo.wlock()
1631 wlock = repo.wlock()
1632 lock = repo.lock()
1632 lock = repo.lock()
1633 return _docommit(ui, repo, *pats, **opts)
1633 return _docommit(ui, repo, *pats, **opts)
1634 finally:
1634 finally:
1635 release(lock, wlock)
1635 release(lock, wlock)
1636
1636
1637 def _docommit(ui, repo, *pats, **opts):
1637 def _docommit(ui, repo, *pats, **opts):
1638 if opts.get('interactive'):
1638 if opts.get('interactive'):
1639 opts.pop('interactive')
1639 opts.pop('interactive')
1640 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1640 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1641 cmdutil.recordfilter, *pats, **opts)
1641 cmdutil.recordfilter, *pats, **opts)
1642 # ret can be 0 (no changes to record) or the value returned by
1642 # ret can be 0 (no changes to record) or the value returned by
1643 # commit(), 1 if nothing changed or None on success.
1643 # commit(), 1 if nothing changed or None on success.
1644 return 1 if ret == 0 else ret
1644 return 1 if ret == 0 else ret
1645
1645
1646 if opts.get('subrepos'):
1646 if opts.get('subrepos'):
1647 if opts.get('amend'):
1647 if opts.get('amend'):
1648 raise error.Abort(_('cannot amend with --subrepos'))
1648 raise error.Abort(_('cannot amend with --subrepos'))
1649 # Let --subrepos on the command line override config setting.
1649 # Let --subrepos on the command line override config setting.
1650 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1650 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1651
1651
1652 cmdutil.checkunfinished(repo, commit=True)
1652 cmdutil.checkunfinished(repo, commit=True)
1653
1653
1654 branch = repo[None].branch()
1654 branch = repo[None].branch()
1655 bheads = repo.branchheads(branch)
1655 bheads = repo.branchheads(branch)
1656
1656
1657 extra = {}
1657 extra = {}
1658 if opts.get('close_branch'):
1658 if opts.get('close_branch'):
1659 extra['close'] = 1
1659 extra['close'] = 1
1660
1660
1661 if not bheads:
1661 if not bheads:
1662 raise error.Abort(_('can only close branch heads'))
1662 raise error.Abort(_('can only close branch heads'))
1663 elif opts.get('amend'):
1663 elif opts.get('amend'):
1664 if repo[None].parents()[0].p1().branch() != branch and \
1664 if repo[None].parents()[0].p1().branch() != branch and \
1665 repo[None].parents()[0].p2().branch() != branch:
1665 repo[None].parents()[0].p2().branch() != branch:
1666 raise error.Abort(_('can only close branch heads'))
1666 raise error.Abort(_('can only close branch heads'))
1667
1667
1668 if opts.get('amend'):
1668 if opts.get('amend'):
1669 if ui.configbool('ui', 'commitsubrepos'):
1669 if ui.configbool('ui', 'commitsubrepos'):
1670 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1670 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1671
1671
1672 old = repo['.']
1672 old = repo['.']
1673 if not old.mutable():
1673 if not old.mutable():
1674 raise error.Abort(_('cannot amend public changesets'))
1674 raise error.Abort(_('cannot amend public changesets'))
1675 if len(repo[None].parents()) > 1:
1675 if len(repo[None].parents()) > 1:
1676 raise error.Abort(_('cannot amend while merging'))
1676 raise error.Abort(_('cannot amend while merging'))
1677 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1677 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1678 if not allowunstable and old.children():
1678 if not allowunstable and old.children():
1679 raise error.Abort(_('cannot amend changeset with children'))
1679 raise error.Abort(_('cannot amend changeset with children'))
1680
1680
1681 # Currently histedit gets confused if an amend happens while histedit
1681 # Currently histedit gets confused if an amend happens while histedit
1682 # is in progress. Since we have a checkunfinished command, we are
1682 # is in progress. Since we have a checkunfinished command, we are
1683 # temporarily honoring it.
1683 # temporarily honoring it.
1684 #
1684 #
1685 # Note: eventually this guard will be removed. Please do not expect
1685 # Note: eventually this guard will be removed. Please do not expect
1686 # this behavior to remain.
1686 # this behavior to remain.
1687 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1687 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1688 cmdutil.checkunfinished(repo)
1688 cmdutil.checkunfinished(repo)
1689
1689
1690 # commitfunc is used only for temporary amend commit by cmdutil.amend
1690 # commitfunc is used only for temporary amend commit by cmdutil.amend
1691 def commitfunc(ui, repo, message, match, opts):
1691 def commitfunc(ui, repo, message, match, opts):
1692 return repo.commit(message,
1692 return repo.commit(message,
1693 opts.get('user') or old.user(),
1693 opts.get('user') or old.user(),
1694 opts.get('date') or old.date(),
1694 opts.get('date') or old.date(),
1695 match,
1695 match,
1696 extra=extra)
1696 extra=extra)
1697
1697
1698 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1698 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1699 if node == old.node():
1699 if node == old.node():
1700 ui.status(_("nothing changed\n"))
1700 ui.status(_("nothing changed\n"))
1701 return 1
1701 return 1
1702 else:
1702 else:
1703 def commitfunc(ui, repo, message, match, opts):
1703 def commitfunc(ui, repo, message, match, opts):
1704 backup = ui.backupconfig('phases', 'new-commit')
1704 backup = ui.backupconfig('phases', 'new-commit')
1705 baseui = repo.baseui
1705 baseui = repo.baseui
1706 basebackup = baseui.backupconfig('phases', 'new-commit')
1706 basebackup = baseui.backupconfig('phases', 'new-commit')
1707 try:
1707 try:
1708 if opts.get('secret'):
1708 if opts.get('secret'):
1709 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1709 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1710 # Propagate to subrepos
1710 # Propagate to subrepos
1711 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1711 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1712
1712
1713 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1713 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1714 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1714 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1715 return repo.commit(message, opts.get('user'), opts.get('date'),
1715 return repo.commit(message, opts.get('user'), opts.get('date'),
1716 match,
1716 match,
1717 editor=editor,
1717 editor=editor,
1718 extra=extra)
1718 extra=extra)
1719 finally:
1719 finally:
1720 ui.restoreconfig(backup)
1720 ui.restoreconfig(backup)
1721 repo.baseui.restoreconfig(basebackup)
1721 repo.baseui.restoreconfig(basebackup)
1722
1722
1723
1723
1724 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1724 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1725
1725
1726 if not node:
1726 if not node:
1727 stat = cmdutil.postcommitstatus(repo, pats, opts)
1727 stat = cmdutil.postcommitstatus(repo, pats, opts)
1728 if stat[3]:
1728 if stat[3]:
1729 ui.status(_("nothing changed (%d missing files, see "
1729 ui.status(_("nothing changed (%d missing files, see "
1730 "'hg status')\n") % len(stat[3]))
1730 "'hg status')\n") % len(stat[3]))
1731 else:
1731 else:
1732 ui.status(_("nothing changed\n"))
1732 ui.status(_("nothing changed\n"))
1733 return 1
1733 return 1
1734
1734
1735 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1735 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1736
1736
1737 @command('config|showconfig|debugconfig',
1737 @command('config|showconfig|debugconfig',
1738 [('u', 'untrusted', None, _('show untrusted configuration options')),
1738 [('u', 'untrusted', None, _('show untrusted configuration options')),
1739 ('e', 'edit', None, _('edit user config')),
1739 ('e', 'edit', None, _('edit user config')),
1740 ('l', 'local', None, _('edit repository config')),
1740 ('l', 'local', None, _('edit repository config')),
1741 ('g', 'global', None, _('edit global config'))] + formatteropts,
1741 ('g', 'global', None, _('edit global config'))] + formatteropts,
1742 _('[-u] [NAME]...'),
1742 _('[-u] [NAME]...'),
1743 optionalrepo=True)
1743 optionalrepo=True)
1744 def config(ui, repo, *values, **opts):
1744 def config(ui, repo, *values, **opts):
1745 """show combined config settings from all hgrc files
1745 """show combined config settings from all hgrc files
1746
1746
1747 With no arguments, print names and values of all config items.
1747 With no arguments, print names and values of all config items.
1748
1748
1749 With one argument of the form section.name, print just the value
1749 With one argument of the form section.name, print just the value
1750 of that config item.
1750 of that config item.
1751
1751
1752 With multiple arguments, print names and values of all config
1752 With multiple arguments, print names and values of all config
1753 items with matching section names.
1753 items with matching section names.
1754
1754
1755 With --edit, start an editor on the user-level config file. With
1755 With --edit, start an editor on the user-level config file. With
1756 --global, edit the system-wide config file. With --local, edit the
1756 --global, edit the system-wide config file. With --local, edit the
1757 repository-level config file.
1757 repository-level config file.
1758
1758
1759 With --debug, the source (filename and line number) is printed
1759 With --debug, the source (filename and line number) is printed
1760 for each config item.
1760 for each config item.
1761
1761
1762 See :hg:`help config` for more information about config files.
1762 See :hg:`help config` for more information about config files.
1763
1763
1764 Returns 0 on success, 1 if NAME does not exist.
1764 Returns 0 on success, 1 if NAME does not exist.
1765
1765
1766 """
1766 """
1767
1767
1768 if opts.get('edit') or opts.get('local') or opts.get('global'):
1768 if opts.get('edit') or opts.get('local') or opts.get('global'):
1769 if opts.get('local') and opts.get('global'):
1769 if opts.get('local') and opts.get('global'):
1770 raise error.Abort(_("can't use --local and --global together"))
1770 raise error.Abort(_("can't use --local and --global together"))
1771
1771
1772 if opts.get('local'):
1772 if opts.get('local'):
1773 if not repo:
1773 if not repo:
1774 raise error.Abort(_("can't use --local outside a repository"))
1774 raise error.Abort(_("can't use --local outside a repository"))
1775 paths = [repo.join('hgrc')]
1775 paths = [repo.join('hgrc')]
1776 elif opts.get('global'):
1776 elif opts.get('global'):
1777 paths = scmutil.systemrcpath()
1777 paths = scmutil.systemrcpath()
1778 else:
1778 else:
1779 paths = scmutil.userrcpath()
1779 paths = scmutil.userrcpath()
1780
1780
1781 for f in paths:
1781 for f in paths:
1782 if os.path.exists(f):
1782 if os.path.exists(f):
1783 break
1783 break
1784 else:
1784 else:
1785 if opts.get('global'):
1785 if opts.get('global'):
1786 samplehgrc = uimod.samplehgrcs['global']
1786 samplehgrc = uimod.samplehgrcs['global']
1787 elif opts.get('local'):
1787 elif opts.get('local'):
1788 samplehgrc = uimod.samplehgrcs['local']
1788 samplehgrc = uimod.samplehgrcs['local']
1789 else:
1789 else:
1790 samplehgrc = uimod.samplehgrcs['user']
1790 samplehgrc = uimod.samplehgrcs['user']
1791
1791
1792 f = paths[0]
1792 f = paths[0]
1793 fp = open(f, "w")
1793 fp = open(f, "w")
1794 fp.write(samplehgrc)
1794 fp.write(samplehgrc)
1795 fp.close()
1795 fp.close()
1796
1796
1797 editor = ui.geteditor()
1797 editor = ui.geteditor()
1798 ui.system("%s \"%s\"" % (editor, f),
1798 ui.system("%s \"%s\"" % (editor, f),
1799 onerr=error.Abort, errprefix=_("edit failed"))
1799 onerr=error.Abort, errprefix=_("edit failed"))
1800 return
1800 return
1801
1801
1802 fm = ui.formatter('config', opts)
1802 fm = ui.formatter('config', opts)
1803 for f in scmutil.rcpath():
1803 for f in scmutil.rcpath():
1804 ui.debug('read config from: %s\n' % f)
1804 ui.debug('read config from: %s\n' % f)
1805 untrusted = bool(opts.get('untrusted'))
1805 untrusted = bool(opts.get('untrusted'))
1806 if values:
1806 if values:
1807 sections = [v for v in values if '.' not in v]
1807 sections = [v for v in values if '.' not in v]
1808 items = [v for v in values if '.' in v]
1808 items = [v for v in values if '.' in v]
1809 if len(items) > 1 or items and sections:
1809 if len(items) > 1 or items and sections:
1810 raise error.Abort(_('only one config item permitted'))
1810 raise error.Abort(_('only one config item permitted'))
1811 matched = False
1811 matched = False
1812 for section, name, value in ui.walkconfig(untrusted=untrusted):
1812 for section, name, value in ui.walkconfig(untrusted=untrusted):
1813 source = ui.configsource(section, name, untrusted)
1813 source = ui.configsource(section, name, untrusted)
1814 value = str(value)
1814 value = str(value)
1815 if fm.isplain():
1815 if fm.isplain():
1816 source = source or 'none'
1816 source = source or 'none'
1817 value = value.replace('\n', '\\n')
1817 value = value.replace('\n', '\\n')
1818 entryname = section + '.' + name
1818 entryname = section + '.' + name
1819 if values:
1819 if values:
1820 for v in values:
1820 for v in values:
1821 if v == section:
1821 if v == section:
1822 fm.startitem()
1822 fm.startitem()
1823 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1823 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1824 fm.write('name value', '%s=%s\n', entryname, value)
1824 fm.write('name value', '%s=%s\n', entryname, value)
1825 matched = True
1825 matched = True
1826 elif v == entryname:
1826 elif v == entryname:
1827 fm.startitem()
1827 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 fm.write('value', '%s\n', value)
1829 fm.write('value', '%s\n', value)
1830 fm.data(name=entryname)
1830 fm.data(name=entryname)
1831 matched = True
1831 matched = True
1832 else:
1832 else:
1833 fm.startitem()
1833 fm.startitem()
1834 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1834 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1835 fm.write('name value', '%s=%s\n', entryname, value)
1835 fm.write('name value', '%s=%s\n', entryname, value)
1836 matched = True
1836 matched = True
1837 fm.end()
1837 fm.end()
1838 if matched:
1838 if matched:
1839 return 0
1839 return 0
1840 return 1
1840 return 1
1841
1841
1842 @command('copy|cp',
1842 @command('copy|cp',
1843 [('A', 'after', None, _('record a copy that has already occurred')),
1843 [('A', 'after', None, _('record a copy that has already occurred')),
1844 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1844 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1845 ] + walkopts + dryrunopts,
1845 ] + walkopts + dryrunopts,
1846 _('[OPTION]... [SOURCE]... DEST'))
1846 _('[OPTION]... [SOURCE]... DEST'))
1847 def copy(ui, repo, *pats, **opts):
1847 def copy(ui, repo, *pats, **opts):
1848 """mark files as copied for the next commit
1848 """mark files as copied for the next commit
1849
1849
1850 Mark dest as having copies of source files. If dest is a
1850 Mark dest as having copies of source files. If dest is a
1851 directory, copies are put in that directory. If dest is a file,
1851 directory, copies are put in that directory. If dest is a file,
1852 the source must be a single file.
1852 the source must be a single file.
1853
1853
1854 By default, this command copies the contents of files as they
1854 By default, this command copies the contents of files as they
1855 exist in the working directory. If invoked with -A/--after, the
1855 exist in the working directory. If invoked with -A/--after, the
1856 operation is recorded, but no copying is performed.
1856 operation is recorded, but no copying is performed.
1857
1857
1858 This command takes effect with the next commit. To undo a copy
1858 This command takes effect with the next commit. To undo a copy
1859 before that, see :hg:`revert`.
1859 before that, see :hg:`revert`.
1860
1860
1861 Returns 0 on success, 1 if errors are encountered.
1861 Returns 0 on success, 1 if errors are encountered.
1862 """
1862 """
1863 with repo.wlock(False):
1863 with repo.wlock(False):
1864 return cmdutil.copy(ui, repo, pats, opts)
1864 return cmdutil.copy(ui, repo, pats, opts)
1865
1865
1866 @command('debuglabelcomplete', [], _('LABEL...'))
1867 def debuglabelcomplete(ui, repo, *args):
1868 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1869 debugnamecomplete(ui, repo, *args)
1870
1871 @command('debugmergestate', [], '')
1866 @command('debugmergestate', [], '')
1872 def debugmergestate(ui, repo, *args):
1867 def debugmergestate(ui, repo, *args):
1873 """print merge state
1868 """print merge state
1874
1869
1875 Use --verbose to print out information about whether v1 or v2 merge state
1870 Use --verbose to print out information about whether v1 or v2 merge state
1876 was chosen."""
1871 was chosen."""
1877 def _hashornull(h):
1872 def _hashornull(h):
1878 if h == nullhex:
1873 if h == nullhex:
1879 return 'null'
1874 return 'null'
1880 else:
1875 else:
1881 return h
1876 return h
1882
1877
1883 def printrecords(version):
1878 def printrecords(version):
1884 ui.write(('* version %s records\n') % version)
1879 ui.write(('* version %s records\n') % version)
1885 if version == 1:
1880 if version == 1:
1886 records = v1records
1881 records = v1records
1887 else:
1882 else:
1888 records = v2records
1883 records = v2records
1889
1884
1890 for rtype, record in records:
1885 for rtype, record in records:
1891 # pretty print some record types
1886 # pretty print some record types
1892 if rtype == 'L':
1887 if rtype == 'L':
1893 ui.write(('local: %s\n') % record)
1888 ui.write(('local: %s\n') % record)
1894 elif rtype == 'O':
1889 elif rtype == 'O':
1895 ui.write(('other: %s\n') % record)
1890 ui.write(('other: %s\n') % record)
1896 elif rtype == 'm':
1891 elif rtype == 'm':
1897 driver, mdstate = record.split('\0', 1)
1892 driver, mdstate = record.split('\0', 1)
1898 ui.write(('merge driver: %s (state "%s")\n')
1893 ui.write(('merge driver: %s (state "%s")\n')
1899 % (driver, mdstate))
1894 % (driver, mdstate))
1900 elif rtype in 'FDC':
1895 elif rtype in 'FDC':
1901 r = record.split('\0')
1896 r = record.split('\0')
1902 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1897 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1903 if version == 1:
1898 if version == 1:
1904 onode = 'not stored in v1 format'
1899 onode = 'not stored in v1 format'
1905 flags = r[7]
1900 flags = r[7]
1906 else:
1901 else:
1907 onode, flags = r[7:9]
1902 onode, flags = r[7:9]
1908 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1903 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1909 % (f, rtype, state, _hashornull(hash)))
1904 % (f, rtype, state, _hashornull(hash)))
1910 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1905 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1911 ui.write((' ancestor path: %s (node %s)\n')
1906 ui.write((' ancestor path: %s (node %s)\n')
1912 % (afile, _hashornull(anode)))
1907 % (afile, _hashornull(anode)))
1913 ui.write((' other path: %s (node %s)\n')
1908 ui.write((' other path: %s (node %s)\n')
1914 % (ofile, _hashornull(onode)))
1909 % (ofile, _hashornull(onode)))
1915 elif rtype == 'f':
1910 elif rtype == 'f':
1916 filename, rawextras = record.split('\0', 1)
1911 filename, rawextras = record.split('\0', 1)
1917 extras = rawextras.split('\0')
1912 extras = rawextras.split('\0')
1918 i = 0
1913 i = 0
1919 extrastrings = []
1914 extrastrings = []
1920 while i < len(extras):
1915 while i < len(extras):
1921 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1916 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1922 i += 2
1917 i += 2
1923
1918
1924 ui.write(('file extras: %s (%s)\n')
1919 ui.write(('file extras: %s (%s)\n')
1925 % (filename, ', '.join(extrastrings)))
1920 % (filename, ', '.join(extrastrings)))
1926 elif rtype == 'l':
1921 elif rtype == 'l':
1927 labels = record.split('\0', 2)
1922 labels = record.split('\0', 2)
1928 labels = [l for l in labels if len(l) > 0]
1923 labels = [l for l in labels if len(l) > 0]
1929 ui.write(('labels:\n'))
1924 ui.write(('labels:\n'))
1930 ui.write((' local: %s\n' % labels[0]))
1925 ui.write((' local: %s\n' % labels[0]))
1931 ui.write((' other: %s\n' % labels[1]))
1926 ui.write((' other: %s\n' % labels[1]))
1932 if len(labels) > 2:
1927 if len(labels) > 2:
1933 ui.write((' base: %s\n' % labels[2]))
1928 ui.write((' base: %s\n' % labels[2]))
1934 else:
1929 else:
1935 ui.write(('unrecognized entry: %s\t%s\n')
1930 ui.write(('unrecognized entry: %s\t%s\n')
1936 % (rtype, record.replace('\0', '\t')))
1931 % (rtype, record.replace('\0', '\t')))
1937
1932
1938 # Avoid mergestate.read() since it may raise an exception for unsupported
1933 # Avoid mergestate.read() since it may raise an exception for unsupported
1939 # merge state records. We shouldn't be doing this, but this is OK since this
1934 # merge state records. We shouldn't be doing this, but this is OK since this
1940 # command is pretty low-level.
1935 # command is pretty low-level.
1941 ms = mergemod.mergestate(repo)
1936 ms = mergemod.mergestate(repo)
1942
1937
1943 # sort so that reasonable information is on top
1938 # sort so that reasonable information is on top
1944 v1records = ms._readrecordsv1()
1939 v1records = ms._readrecordsv1()
1945 v2records = ms._readrecordsv2()
1940 v2records = ms._readrecordsv2()
1946 order = 'LOml'
1941 order = 'LOml'
1947 def key(r):
1942 def key(r):
1948 idx = order.find(r[0])
1943 idx = order.find(r[0])
1949 if idx == -1:
1944 if idx == -1:
1950 return (1, r[1])
1945 return (1, r[1])
1951 else:
1946 else:
1952 return (0, idx)
1947 return (0, idx)
1953 v1records.sort(key=key)
1948 v1records.sort(key=key)
1954 v2records.sort(key=key)
1949 v2records.sort(key=key)
1955
1950
1956 if not v1records and not v2records:
1951 if not v1records and not v2records:
1957 ui.write(('no merge state found\n'))
1952 ui.write(('no merge state found\n'))
1958 elif not v2records:
1953 elif not v2records:
1959 ui.note(('no version 2 merge state\n'))
1954 ui.note(('no version 2 merge state\n'))
1960 printrecords(1)
1955 printrecords(1)
1961 elif ms._v1v2match(v1records, v2records):
1956 elif ms._v1v2match(v1records, v2records):
1962 ui.note(('v1 and v2 states match: using v2\n'))
1957 ui.note(('v1 and v2 states match: using v2\n'))
1963 printrecords(2)
1958 printrecords(2)
1964 else:
1959 else:
1965 ui.note(('v1 and v2 states mismatch: using v1\n'))
1960 ui.note(('v1 and v2 states mismatch: using v1\n'))
1966 printrecords(1)
1961 printrecords(1)
1967 if ui.verbose:
1962 if ui.verbose:
1968 printrecords(2)
1963 printrecords(2)
1969
1964
1970 @command('debugnamecomplete', [], _('NAME...'))
1965 @command('debugnamecomplete', [], _('NAME...'))
1971 def debugnamecomplete(ui, repo, *args):
1966 def debugnamecomplete(ui, repo, *args):
1972 '''complete "names" - tags, open branch names, bookmark names'''
1967 '''complete "names" - tags, open branch names, bookmark names'''
1973
1968
1974 names = set()
1969 names = set()
1975 # since we previously only listed open branches, we will handle that
1970 # since we previously only listed open branches, we will handle that
1976 # specially (after this for loop)
1971 # specially (after this for loop)
1977 for name, ns in repo.names.iteritems():
1972 for name, ns in repo.names.iteritems():
1978 if name != 'branches':
1973 if name != 'branches':
1979 names.update(ns.listnames(repo))
1974 names.update(ns.listnames(repo))
1980 names.update(tag for (tag, heads, tip, closed)
1975 names.update(tag for (tag, heads, tip, closed)
1981 in repo.branchmap().iterbranches() if not closed)
1976 in repo.branchmap().iterbranches() if not closed)
1982 completions = set()
1977 completions = set()
1983 if not args:
1978 if not args:
1984 args = ['']
1979 args = ['']
1985 for a in args:
1980 for a in args:
1986 completions.update(n for n in names if n.startswith(a))
1981 completions.update(n for n in names if n.startswith(a))
1987 ui.write('\n'.join(sorted(completions)))
1982 ui.write('\n'.join(sorted(completions)))
1988 ui.write('\n')
1983 ui.write('\n')
1989
1984
1990 @command('debuglocks',
1985 @command('debuglocks',
1991 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1986 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1992 ('W', 'force-wlock', None,
1987 ('W', 'force-wlock', None,
1993 _('free the working state lock (DANGEROUS)'))],
1988 _('free the working state lock (DANGEROUS)'))],
1994 _('[OPTION]...'))
1989 _('[OPTION]...'))
1995 def debuglocks(ui, repo, **opts):
1990 def debuglocks(ui, repo, **opts):
1996 """show or modify state of locks
1991 """show or modify state of locks
1997
1992
1998 By default, this command will show which locks are held. This
1993 By default, this command will show which locks are held. This
1999 includes the user and process holding the lock, the amount of time
1994 includes the user and process holding the lock, the amount of time
2000 the lock has been held, and the machine name where the process is
1995 the lock has been held, and the machine name where the process is
2001 running if it's not local.
1996 running if it's not local.
2002
1997
2003 Locks protect the integrity of Mercurial's data, so should be
1998 Locks protect the integrity of Mercurial's data, so should be
2004 treated with care. System crashes or other interruptions may cause
1999 treated with care. System crashes or other interruptions may cause
2005 locks to not be properly released, though Mercurial will usually
2000 locks to not be properly released, though Mercurial will usually
2006 detect and remove such stale locks automatically.
2001 detect and remove such stale locks automatically.
2007
2002
2008 However, detecting stale locks may not always be possible (for
2003 However, detecting stale locks may not always be possible (for
2009 instance, on a shared filesystem). Removing locks may also be
2004 instance, on a shared filesystem). Removing locks may also be
2010 blocked by filesystem permissions.
2005 blocked by filesystem permissions.
2011
2006
2012 Returns 0 if no locks are held.
2007 Returns 0 if no locks are held.
2013
2008
2014 """
2009 """
2015
2010
2016 if opts.get('force_lock'):
2011 if opts.get('force_lock'):
2017 repo.svfs.unlink('lock')
2012 repo.svfs.unlink('lock')
2018 if opts.get('force_wlock'):
2013 if opts.get('force_wlock'):
2019 repo.vfs.unlink('wlock')
2014 repo.vfs.unlink('wlock')
2020 if opts.get('force_lock') or opts.get('force_lock'):
2015 if opts.get('force_lock') or opts.get('force_lock'):
2021 return 0
2016 return 0
2022
2017
2023 now = time.time()
2018 now = time.time()
2024 held = 0
2019 held = 0
2025
2020
2026 def report(vfs, name, method):
2021 def report(vfs, name, method):
2027 # this causes stale locks to get reaped for more accurate reporting
2022 # this causes stale locks to get reaped for more accurate reporting
2028 try:
2023 try:
2029 l = method(False)
2024 l = method(False)
2030 except error.LockHeld:
2025 except error.LockHeld:
2031 l = None
2026 l = None
2032
2027
2033 if l:
2028 if l:
2034 l.release()
2029 l.release()
2035 else:
2030 else:
2036 try:
2031 try:
2037 stat = vfs.lstat(name)
2032 stat = vfs.lstat(name)
2038 age = now - stat.st_mtime
2033 age = now - stat.st_mtime
2039 user = util.username(stat.st_uid)
2034 user = util.username(stat.st_uid)
2040 locker = vfs.readlock(name)
2035 locker = vfs.readlock(name)
2041 if ":" in locker:
2036 if ":" in locker:
2042 host, pid = locker.split(':')
2037 host, pid = locker.split(':')
2043 if host == socket.gethostname():
2038 if host == socket.gethostname():
2044 locker = 'user %s, process %s' % (user, pid)
2039 locker = 'user %s, process %s' % (user, pid)
2045 else:
2040 else:
2046 locker = 'user %s, process %s, host %s' \
2041 locker = 'user %s, process %s, host %s' \
2047 % (user, pid, host)
2042 % (user, pid, host)
2048 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2043 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2049 return 1
2044 return 1
2050 except OSError as e:
2045 except OSError as e:
2051 if e.errno != errno.ENOENT:
2046 if e.errno != errno.ENOENT:
2052 raise
2047 raise
2053
2048
2054 ui.write(("%-6s free\n") % (name + ":"))
2049 ui.write(("%-6s free\n") % (name + ":"))
2055 return 0
2050 return 0
2056
2051
2057 held += report(repo.svfs, "lock", repo.lock)
2052 held += report(repo.svfs, "lock", repo.lock)
2058 held += report(repo.vfs, "wlock", repo.wlock)
2053 held += report(repo.vfs, "wlock", repo.wlock)
2059
2054
2060 return held
2055 return held
2061
2056
2062 @command('debugobsolete',
2057 @command('debugobsolete',
2063 [('', 'flags', 0, _('markers flag')),
2058 [('', 'flags', 0, _('markers flag')),
2064 ('', 'record-parents', False,
2059 ('', 'record-parents', False,
2065 _('record parent information for the precursor')),
2060 _('record parent information for the precursor')),
2066 ('r', 'rev', [], _('display markers relevant to REV')),
2061 ('r', 'rev', [], _('display markers relevant to REV')),
2067 ('', 'index', False, _('display index of the marker')),
2062 ('', 'index', False, _('display index of the marker')),
2068 ('', 'delete', [], _('delete markers specified by indices')),
2063 ('', 'delete', [], _('delete markers specified by indices')),
2069 ] + commitopts2 + formatteropts,
2064 ] + commitopts2 + formatteropts,
2070 _('[OBSOLETED [REPLACEMENT ...]]'))
2065 _('[OBSOLETED [REPLACEMENT ...]]'))
2071 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2066 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2072 """create arbitrary obsolete marker
2067 """create arbitrary obsolete marker
2073
2068
2074 With no arguments, displays the list of obsolescence markers."""
2069 With no arguments, displays the list of obsolescence markers."""
2075
2070
2076 def parsenodeid(s):
2071 def parsenodeid(s):
2077 try:
2072 try:
2078 # We do not use revsingle/revrange functions here to accept
2073 # We do not use revsingle/revrange functions here to accept
2079 # arbitrary node identifiers, possibly not present in the
2074 # arbitrary node identifiers, possibly not present in the
2080 # local repository.
2075 # local repository.
2081 n = bin(s)
2076 n = bin(s)
2082 if len(n) != len(nullid):
2077 if len(n) != len(nullid):
2083 raise TypeError()
2078 raise TypeError()
2084 return n
2079 return n
2085 except TypeError:
2080 except TypeError:
2086 raise error.Abort('changeset references must be full hexadecimal '
2081 raise error.Abort('changeset references must be full hexadecimal '
2087 'node identifiers')
2082 'node identifiers')
2088
2083
2089 if opts.get('delete'):
2084 if opts.get('delete'):
2090 indices = []
2085 indices = []
2091 for v in opts.get('delete'):
2086 for v in opts.get('delete'):
2092 try:
2087 try:
2093 indices.append(int(v))
2088 indices.append(int(v))
2094 except ValueError:
2089 except ValueError:
2095 raise error.Abort(_('invalid index value: %r') % v,
2090 raise error.Abort(_('invalid index value: %r') % v,
2096 hint=_('use integers for indices'))
2091 hint=_('use integers for indices'))
2097
2092
2098 if repo.currenttransaction():
2093 if repo.currenttransaction():
2099 raise error.Abort(_('cannot delete obsmarkers in the middle '
2094 raise error.Abort(_('cannot delete obsmarkers in the middle '
2100 'of transaction.'))
2095 'of transaction.'))
2101
2096
2102 with repo.lock():
2097 with repo.lock():
2103 n = repair.deleteobsmarkers(repo.obsstore, indices)
2098 n = repair.deleteobsmarkers(repo.obsstore, indices)
2104 ui.write(_('deleted %i obsolescence markers\n') % n)
2099 ui.write(_('deleted %i obsolescence markers\n') % n)
2105
2100
2106 return
2101 return
2107
2102
2108 if precursor is not None:
2103 if precursor is not None:
2109 if opts['rev']:
2104 if opts['rev']:
2110 raise error.Abort('cannot select revision when creating marker')
2105 raise error.Abort('cannot select revision when creating marker')
2111 metadata = {}
2106 metadata = {}
2112 metadata['user'] = opts['user'] or ui.username()
2107 metadata['user'] = opts['user'] or ui.username()
2113 succs = tuple(parsenodeid(succ) for succ in successors)
2108 succs = tuple(parsenodeid(succ) for succ in successors)
2114 l = repo.lock()
2109 l = repo.lock()
2115 try:
2110 try:
2116 tr = repo.transaction('debugobsolete')
2111 tr = repo.transaction('debugobsolete')
2117 try:
2112 try:
2118 date = opts.get('date')
2113 date = opts.get('date')
2119 if date:
2114 if date:
2120 date = util.parsedate(date)
2115 date = util.parsedate(date)
2121 else:
2116 else:
2122 date = None
2117 date = None
2123 prec = parsenodeid(precursor)
2118 prec = parsenodeid(precursor)
2124 parents = None
2119 parents = None
2125 if opts['record_parents']:
2120 if opts['record_parents']:
2126 if prec not in repo.unfiltered():
2121 if prec not in repo.unfiltered():
2127 raise error.Abort('cannot used --record-parents on '
2122 raise error.Abort('cannot used --record-parents on '
2128 'unknown changesets')
2123 'unknown changesets')
2129 parents = repo.unfiltered()[prec].parents()
2124 parents = repo.unfiltered()[prec].parents()
2130 parents = tuple(p.node() for p in parents)
2125 parents = tuple(p.node() for p in parents)
2131 repo.obsstore.create(tr, prec, succs, opts['flags'],
2126 repo.obsstore.create(tr, prec, succs, opts['flags'],
2132 parents=parents, date=date,
2127 parents=parents, date=date,
2133 metadata=metadata)
2128 metadata=metadata)
2134 tr.close()
2129 tr.close()
2135 except ValueError as exc:
2130 except ValueError as exc:
2136 raise error.Abort(_('bad obsmarker input: %s') % exc)
2131 raise error.Abort(_('bad obsmarker input: %s') % exc)
2137 finally:
2132 finally:
2138 tr.release()
2133 tr.release()
2139 finally:
2134 finally:
2140 l.release()
2135 l.release()
2141 else:
2136 else:
2142 if opts['rev']:
2137 if opts['rev']:
2143 revs = scmutil.revrange(repo, opts['rev'])
2138 revs = scmutil.revrange(repo, opts['rev'])
2144 nodes = [repo[r].node() for r in revs]
2139 nodes = [repo[r].node() for r in revs]
2145 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2140 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2146 markers.sort(key=lambda x: x._data)
2141 markers.sort(key=lambda x: x._data)
2147 else:
2142 else:
2148 markers = obsolete.getmarkers(repo)
2143 markers = obsolete.getmarkers(repo)
2149
2144
2150 markerstoiter = markers
2145 markerstoiter = markers
2151 isrelevant = lambda m: True
2146 isrelevant = lambda m: True
2152 if opts.get('rev') and opts.get('index'):
2147 if opts.get('rev') and opts.get('index'):
2153 markerstoiter = obsolete.getmarkers(repo)
2148 markerstoiter = obsolete.getmarkers(repo)
2154 markerset = set(markers)
2149 markerset = set(markers)
2155 isrelevant = lambda m: m in markerset
2150 isrelevant = lambda m: m in markerset
2156
2151
2157 fm = ui.formatter('debugobsolete', opts)
2152 fm = ui.formatter('debugobsolete', opts)
2158 for i, m in enumerate(markerstoiter):
2153 for i, m in enumerate(markerstoiter):
2159 if not isrelevant(m):
2154 if not isrelevant(m):
2160 # marker can be irrelevant when we're iterating over a set
2155 # marker can be irrelevant when we're iterating over a set
2161 # of markers (markerstoiter) which is bigger than the set
2156 # of markers (markerstoiter) which is bigger than the set
2162 # of markers we want to display (markers)
2157 # of markers we want to display (markers)
2163 # this can happen if both --index and --rev options are
2158 # this can happen if both --index and --rev options are
2164 # provided and thus we need to iterate over all of the markers
2159 # provided and thus we need to iterate over all of the markers
2165 # to get the correct indices, but only display the ones that
2160 # to get the correct indices, but only display the ones that
2166 # are relevant to --rev value
2161 # are relevant to --rev value
2167 continue
2162 continue
2168 fm.startitem()
2163 fm.startitem()
2169 ind = i if opts.get('index') else None
2164 ind = i if opts.get('index') else None
2170 cmdutil.showmarker(fm, m, index=ind)
2165 cmdutil.showmarker(fm, m, index=ind)
2171 fm.end()
2166 fm.end()
2172
2167
2173 @command('debugpathcomplete',
2168 @command('debugpathcomplete',
2174 [('f', 'full', None, _('complete an entire path')),
2169 [('f', 'full', None, _('complete an entire path')),
2175 ('n', 'normal', None, _('show only normal files')),
2170 ('n', 'normal', None, _('show only normal files')),
2176 ('a', 'added', None, _('show only added files')),
2171 ('a', 'added', None, _('show only added files')),
2177 ('r', 'removed', None, _('show only removed files'))],
2172 ('r', 'removed', None, _('show only removed files'))],
2178 _('FILESPEC...'))
2173 _('FILESPEC...'))
2179 def debugpathcomplete(ui, repo, *specs, **opts):
2174 def debugpathcomplete(ui, repo, *specs, **opts):
2180 '''complete part or all of a tracked path
2175 '''complete part or all of a tracked path
2181
2176
2182 This command supports shells that offer path name completion. It
2177 This command supports shells that offer path name completion. It
2183 currently completes only files already known to the dirstate.
2178 currently completes only files already known to the dirstate.
2184
2179
2185 Completion extends only to the next path segment unless
2180 Completion extends only to the next path segment unless
2186 --full is specified, in which case entire paths are used.'''
2181 --full is specified, in which case entire paths are used.'''
2187
2182
2188 def complete(path, acceptable):
2183 def complete(path, acceptable):
2189 dirstate = repo.dirstate
2184 dirstate = repo.dirstate
2190 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2185 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2191 rootdir = repo.root + pycompat.ossep
2186 rootdir = repo.root + pycompat.ossep
2192 if spec != repo.root and not spec.startswith(rootdir):
2187 if spec != repo.root and not spec.startswith(rootdir):
2193 return [], []
2188 return [], []
2194 if os.path.isdir(spec):
2189 if os.path.isdir(spec):
2195 spec += '/'
2190 spec += '/'
2196 spec = spec[len(rootdir):]
2191 spec = spec[len(rootdir):]
2197 fixpaths = pycompat.ossep != '/'
2192 fixpaths = pycompat.ossep != '/'
2198 if fixpaths:
2193 if fixpaths:
2199 spec = spec.replace(pycompat.ossep, '/')
2194 spec = spec.replace(pycompat.ossep, '/')
2200 speclen = len(spec)
2195 speclen = len(spec)
2201 fullpaths = opts['full']
2196 fullpaths = opts['full']
2202 files, dirs = set(), set()
2197 files, dirs = set(), set()
2203 adddir, addfile = dirs.add, files.add
2198 adddir, addfile = dirs.add, files.add
2204 for f, st in dirstate.iteritems():
2199 for f, st in dirstate.iteritems():
2205 if f.startswith(spec) and st[0] in acceptable:
2200 if f.startswith(spec) and st[0] in acceptable:
2206 if fixpaths:
2201 if fixpaths:
2207 f = f.replace('/', pycompat.ossep)
2202 f = f.replace('/', pycompat.ossep)
2208 if fullpaths:
2203 if fullpaths:
2209 addfile(f)
2204 addfile(f)
2210 continue
2205 continue
2211 s = f.find(pycompat.ossep, speclen)
2206 s = f.find(pycompat.ossep, speclen)
2212 if s >= 0:
2207 if s >= 0:
2213 adddir(f[:s])
2208 adddir(f[:s])
2214 else:
2209 else:
2215 addfile(f)
2210 addfile(f)
2216 return files, dirs
2211 return files, dirs
2217
2212
2218 acceptable = ''
2213 acceptable = ''
2219 if opts['normal']:
2214 if opts['normal']:
2220 acceptable += 'nm'
2215 acceptable += 'nm'
2221 if opts['added']:
2216 if opts['added']:
2222 acceptable += 'a'
2217 acceptable += 'a'
2223 if opts['removed']:
2218 if opts['removed']:
2224 acceptable += 'r'
2219 acceptable += 'r'
2225 cwd = repo.getcwd()
2220 cwd = repo.getcwd()
2226 if not specs:
2221 if not specs:
2227 specs = ['.']
2222 specs = ['.']
2228
2223
2229 files, dirs = set(), set()
2224 files, dirs = set(), set()
2230 for spec in specs:
2225 for spec in specs:
2231 f, d = complete(spec, acceptable or 'nmar')
2226 f, d = complete(spec, acceptable or 'nmar')
2232 files.update(f)
2227 files.update(f)
2233 dirs.update(d)
2228 dirs.update(d)
2234 files.update(dirs)
2229 files.update(dirs)
2235 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2230 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2236 ui.write('\n')
2231 ui.write('\n')
2237
2232
2238 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2233 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2239 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2234 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2240 '''access the pushkey key/value protocol
2235 '''access the pushkey key/value protocol
2241
2236
2242 With two args, list the keys in the given namespace.
2237 With two args, list the keys in the given namespace.
2243
2238
2244 With five args, set a key to new if it currently is set to old.
2239 With five args, set a key to new if it currently is set to old.
2245 Reports success or failure.
2240 Reports success or failure.
2246 '''
2241 '''
2247
2242
2248 target = hg.peer(ui, {}, repopath)
2243 target = hg.peer(ui, {}, repopath)
2249 if keyinfo:
2244 if keyinfo:
2250 key, old, new = keyinfo
2245 key, old, new = keyinfo
2251 r = target.pushkey(namespace, key, old, new)
2246 r = target.pushkey(namespace, key, old, new)
2252 ui.status(str(r) + '\n')
2247 ui.status(str(r) + '\n')
2253 return not r
2248 return not r
2254 else:
2249 else:
2255 for k, v in sorted(target.listkeys(namespace).iteritems()):
2250 for k, v in sorted(target.listkeys(namespace).iteritems()):
2256 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2251 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2257 v.encode('string-escape')))
2252 v.encode('string-escape')))
2258
2253
2259 @command('debugpvec', [], _('A B'))
2254 @command('debugpvec', [], _('A B'))
2260 def debugpvec(ui, repo, a, b=None):
2255 def debugpvec(ui, repo, a, b=None):
2261 ca = scmutil.revsingle(repo, a)
2256 ca = scmutil.revsingle(repo, a)
2262 cb = scmutil.revsingle(repo, b)
2257 cb = scmutil.revsingle(repo, b)
2263 pa = pvec.ctxpvec(ca)
2258 pa = pvec.ctxpvec(ca)
2264 pb = pvec.ctxpvec(cb)
2259 pb = pvec.ctxpvec(cb)
2265 if pa == pb:
2260 if pa == pb:
2266 rel = "="
2261 rel = "="
2267 elif pa > pb:
2262 elif pa > pb:
2268 rel = ">"
2263 rel = ">"
2269 elif pa < pb:
2264 elif pa < pb:
2270 rel = "<"
2265 rel = "<"
2271 elif pa | pb:
2266 elif pa | pb:
2272 rel = "|"
2267 rel = "|"
2273 ui.write(_("a: %s\n") % pa)
2268 ui.write(_("a: %s\n") % pa)
2274 ui.write(_("b: %s\n") % pb)
2269 ui.write(_("b: %s\n") % pb)
2275 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2270 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2276 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2271 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2277 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2272 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2278 pa.distance(pb), rel))
2273 pa.distance(pb), rel))
2279
2274
2280 @command('debugrebuilddirstate|debugrebuildstate',
2275 @command('debugrebuilddirstate|debugrebuildstate',
2281 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2276 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2282 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2277 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2283 'the working copy parent')),
2278 'the working copy parent')),
2284 ],
2279 ],
2285 _('[-r REV]'))
2280 _('[-r REV]'))
2286 def debugrebuilddirstate(ui, repo, rev, **opts):
2281 def debugrebuilddirstate(ui, repo, rev, **opts):
2287 """rebuild the dirstate as it would look like for the given revision
2282 """rebuild the dirstate as it would look like for the given revision
2288
2283
2289 If no revision is specified the first current parent will be used.
2284 If no revision is specified the first current parent will be used.
2290
2285
2291 The dirstate will be set to the files of the given revision.
2286 The dirstate will be set to the files of the given revision.
2292 The actual working directory content or existing dirstate
2287 The actual working directory content or existing dirstate
2293 information such as adds or removes is not considered.
2288 information such as adds or removes is not considered.
2294
2289
2295 ``minimal`` will only rebuild the dirstate status for files that claim to be
2290 ``minimal`` will only rebuild the dirstate status for files that claim to be
2296 tracked but are not in the parent manifest, or that exist in the parent
2291 tracked but are not in the parent manifest, or that exist in the parent
2297 manifest but are not in the dirstate. It will not change adds, removes, or
2292 manifest but are not in the dirstate. It will not change adds, removes, or
2298 modified files that are in the working copy parent.
2293 modified files that are in the working copy parent.
2299
2294
2300 One use of this command is to make the next :hg:`status` invocation
2295 One use of this command is to make the next :hg:`status` invocation
2301 check the actual file content.
2296 check the actual file content.
2302 """
2297 """
2303 ctx = scmutil.revsingle(repo, rev)
2298 ctx = scmutil.revsingle(repo, rev)
2304 with repo.wlock():
2299 with repo.wlock():
2305 dirstate = repo.dirstate
2300 dirstate = repo.dirstate
2306 changedfiles = None
2301 changedfiles = None
2307 # See command doc for what minimal does.
2302 # See command doc for what minimal does.
2308 if opts.get('minimal'):
2303 if opts.get('minimal'):
2309 manifestfiles = set(ctx.manifest().keys())
2304 manifestfiles = set(ctx.manifest().keys())
2310 dirstatefiles = set(dirstate)
2305 dirstatefiles = set(dirstate)
2311 manifestonly = manifestfiles - dirstatefiles
2306 manifestonly = manifestfiles - dirstatefiles
2312 dsonly = dirstatefiles - manifestfiles
2307 dsonly = dirstatefiles - manifestfiles
2313 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2308 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2314 changedfiles = manifestonly | dsnotadded
2309 changedfiles = manifestonly | dsnotadded
2315
2310
2316 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2311 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2317
2312
2318 @command('debugrebuildfncache', [], '')
2313 @command('debugrebuildfncache', [], '')
2319 def debugrebuildfncache(ui, repo):
2314 def debugrebuildfncache(ui, repo):
2320 """rebuild the fncache file"""
2315 """rebuild the fncache file"""
2321 repair.rebuildfncache(ui, repo)
2316 repair.rebuildfncache(ui, repo)
2322
2317
2323 @command('debugrename',
2318 @command('debugrename',
2324 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2319 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2325 _('[-r REV] FILE'))
2320 _('[-r REV] FILE'))
2326 def debugrename(ui, repo, file1, *pats, **opts):
2321 def debugrename(ui, repo, file1, *pats, **opts):
2327 """dump rename information"""
2322 """dump rename information"""
2328
2323
2329 ctx = scmutil.revsingle(repo, opts.get('rev'))
2324 ctx = scmutil.revsingle(repo, opts.get('rev'))
2330 m = scmutil.match(ctx, (file1,) + pats, opts)
2325 m = scmutil.match(ctx, (file1,) + pats, opts)
2331 for abs in ctx.walk(m):
2326 for abs in ctx.walk(m):
2332 fctx = ctx[abs]
2327 fctx = ctx[abs]
2333 o = fctx.filelog().renamed(fctx.filenode())
2328 o = fctx.filelog().renamed(fctx.filenode())
2334 rel = m.rel(abs)
2329 rel = m.rel(abs)
2335 if o:
2330 if o:
2336 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2331 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2337 else:
2332 else:
2338 ui.write(_("%s not renamed\n") % rel)
2333 ui.write(_("%s not renamed\n") % rel)
2339
2334
2340 @command('debugrevlog', debugrevlogopts +
2335 @command('debugrevlog', debugrevlogopts +
2341 [('d', 'dump', False, _('dump index data'))],
2336 [('d', 'dump', False, _('dump index data'))],
2342 _('-c|-m|FILE'),
2337 _('-c|-m|FILE'),
2343 optionalrepo=True)
2338 optionalrepo=True)
2344 def debugrevlog(ui, repo, file_=None, **opts):
2339 def debugrevlog(ui, repo, file_=None, **opts):
2345 """show data and statistics about a revlog"""
2340 """show data and statistics about a revlog"""
2346 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2341 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2347
2342
2348 if opts.get("dump"):
2343 if opts.get("dump"):
2349 numrevs = len(r)
2344 numrevs = len(r)
2350 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2345 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2351 " rawsize totalsize compression heads chainlen\n"))
2346 " rawsize totalsize compression heads chainlen\n"))
2352 ts = 0
2347 ts = 0
2353 heads = set()
2348 heads = set()
2354
2349
2355 for rev in xrange(numrevs):
2350 for rev in xrange(numrevs):
2356 dbase = r.deltaparent(rev)
2351 dbase = r.deltaparent(rev)
2357 if dbase == -1:
2352 if dbase == -1:
2358 dbase = rev
2353 dbase = rev
2359 cbase = r.chainbase(rev)
2354 cbase = r.chainbase(rev)
2360 clen = r.chainlen(rev)
2355 clen = r.chainlen(rev)
2361 p1, p2 = r.parentrevs(rev)
2356 p1, p2 = r.parentrevs(rev)
2362 rs = r.rawsize(rev)
2357 rs = r.rawsize(rev)
2363 ts = ts + rs
2358 ts = ts + rs
2364 heads -= set(r.parentrevs(rev))
2359 heads -= set(r.parentrevs(rev))
2365 heads.add(rev)
2360 heads.add(rev)
2366 try:
2361 try:
2367 compression = ts / r.end(rev)
2362 compression = ts / r.end(rev)
2368 except ZeroDivisionError:
2363 except ZeroDivisionError:
2369 compression = 0
2364 compression = 0
2370 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2365 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2371 "%11d %5d %8d\n" %
2366 "%11d %5d %8d\n" %
2372 (rev, p1, p2, r.start(rev), r.end(rev),
2367 (rev, p1, p2, r.start(rev), r.end(rev),
2373 r.start(dbase), r.start(cbase),
2368 r.start(dbase), r.start(cbase),
2374 r.start(p1), r.start(p2),
2369 r.start(p1), r.start(p2),
2375 rs, ts, compression, len(heads), clen))
2370 rs, ts, compression, len(heads), clen))
2376 return 0
2371 return 0
2377
2372
2378 v = r.version
2373 v = r.version
2379 format = v & 0xFFFF
2374 format = v & 0xFFFF
2380 flags = []
2375 flags = []
2381 gdelta = False
2376 gdelta = False
2382 if v & revlog.REVLOGNGINLINEDATA:
2377 if v & revlog.REVLOGNGINLINEDATA:
2383 flags.append('inline')
2378 flags.append('inline')
2384 if v & revlog.REVLOGGENERALDELTA:
2379 if v & revlog.REVLOGGENERALDELTA:
2385 gdelta = True
2380 gdelta = True
2386 flags.append('generaldelta')
2381 flags.append('generaldelta')
2387 if not flags:
2382 if not flags:
2388 flags = ['(none)']
2383 flags = ['(none)']
2389
2384
2390 nummerges = 0
2385 nummerges = 0
2391 numfull = 0
2386 numfull = 0
2392 numprev = 0
2387 numprev = 0
2393 nump1 = 0
2388 nump1 = 0
2394 nump2 = 0
2389 nump2 = 0
2395 numother = 0
2390 numother = 0
2396 nump1prev = 0
2391 nump1prev = 0
2397 nump2prev = 0
2392 nump2prev = 0
2398 chainlengths = []
2393 chainlengths = []
2399
2394
2400 datasize = [None, 0, 0]
2395 datasize = [None, 0, 0]
2401 fullsize = [None, 0, 0]
2396 fullsize = [None, 0, 0]
2402 deltasize = [None, 0, 0]
2397 deltasize = [None, 0, 0]
2403 chunktypecounts = {}
2398 chunktypecounts = {}
2404 chunktypesizes = {}
2399 chunktypesizes = {}
2405
2400
2406 def addsize(size, l):
2401 def addsize(size, l):
2407 if l[0] is None or size < l[0]:
2402 if l[0] is None or size < l[0]:
2408 l[0] = size
2403 l[0] = size
2409 if size > l[1]:
2404 if size > l[1]:
2410 l[1] = size
2405 l[1] = size
2411 l[2] += size
2406 l[2] += size
2412
2407
2413 numrevs = len(r)
2408 numrevs = len(r)
2414 for rev in xrange(numrevs):
2409 for rev in xrange(numrevs):
2415 p1, p2 = r.parentrevs(rev)
2410 p1, p2 = r.parentrevs(rev)
2416 delta = r.deltaparent(rev)
2411 delta = r.deltaparent(rev)
2417 if format > 0:
2412 if format > 0:
2418 addsize(r.rawsize(rev), datasize)
2413 addsize(r.rawsize(rev), datasize)
2419 if p2 != nullrev:
2414 if p2 != nullrev:
2420 nummerges += 1
2415 nummerges += 1
2421 size = r.length(rev)
2416 size = r.length(rev)
2422 if delta == nullrev:
2417 if delta == nullrev:
2423 chainlengths.append(0)
2418 chainlengths.append(0)
2424 numfull += 1
2419 numfull += 1
2425 addsize(size, fullsize)
2420 addsize(size, fullsize)
2426 else:
2421 else:
2427 chainlengths.append(chainlengths[delta] + 1)
2422 chainlengths.append(chainlengths[delta] + 1)
2428 addsize(size, deltasize)
2423 addsize(size, deltasize)
2429 if delta == rev - 1:
2424 if delta == rev - 1:
2430 numprev += 1
2425 numprev += 1
2431 if delta == p1:
2426 if delta == p1:
2432 nump1prev += 1
2427 nump1prev += 1
2433 elif delta == p2:
2428 elif delta == p2:
2434 nump2prev += 1
2429 nump2prev += 1
2435 elif delta == p1:
2430 elif delta == p1:
2436 nump1 += 1
2431 nump1 += 1
2437 elif delta == p2:
2432 elif delta == p2:
2438 nump2 += 1
2433 nump2 += 1
2439 elif delta != nullrev:
2434 elif delta != nullrev:
2440 numother += 1
2435 numother += 1
2441
2436
2442 # Obtain data on the raw chunks in the revlog.
2437 # Obtain data on the raw chunks in the revlog.
2443 chunk = r._chunkraw(rev, rev)[1]
2438 chunk = r._chunkraw(rev, rev)[1]
2444 if chunk:
2439 if chunk:
2445 chunktype = chunk[0]
2440 chunktype = chunk[0]
2446 else:
2441 else:
2447 chunktype = 'empty'
2442 chunktype = 'empty'
2448
2443
2449 if chunktype not in chunktypecounts:
2444 if chunktype not in chunktypecounts:
2450 chunktypecounts[chunktype] = 0
2445 chunktypecounts[chunktype] = 0
2451 chunktypesizes[chunktype] = 0
2446 chunktypesizes[chunktype] = 0
2452
2447
2453 chunktypecounts[chunktype] += 1
2448 chunktypecounts[chunktype] += 1
2454 chunktypesizes[chunktype] += size
2449 chunktypesizes[chunktype] += size
2455
2450
2456 # Adjust size min value for empty cases
2451 # Adjust size min value for empty cases
2457 for size in (datasize, fullsize, deltasize):
2452 for size in (datasize, fullsize, deltasize):
2458 if size[0] is None:
2453 if size[0] is None:
2459 size[0] = 0
2454 size[0] = 0
2460
2455
2461 numdeltas = numrevs - numfull
2456 numdeltas = numrevs - numfull
2462 numoprev = numprev - nump1prev - nump2prev
2457 numoprev = numprev - nump1prev - nump2prev
2463 totalrawsize = datasize[2]
2458 totalrawsize = datasize[2]
2464 datasize[2] /= numrevs
2459 datasize[2] /= numrevs
2465 fulltotal = fullsize[2]
2460 fulltotal = fullsize[2]
2466 fullsize[2] /= numfull
2461 fullsize[2] /= numfull
2467 deltatotal = deltasize[2]
2462 deltatotal = deltasize[2]
2468 if numrevs - numfull > 0:
2463 if numrevs - numfull > 0:
2469 deltasize[2] /= numrevs - numfull
2464 deltasize[2] /= numrevs - numfull
2470 totalsize = fulltotal + deltatotal
2465 totalsize = fulltotal + deltatotal
2471 avgchainlen = sum(chainlengths) / numrevs
2466 avgchainlen = sum(chainlengths) / numrevs
2472 maxchainlen = max(chainlengths)
2467 maxchainlen = max(chainlengths)
2473 compratio = 1
2468 compratio = 1
2474 if totalsize:
2469 if totalsize:
2475 compratio = totalrawsize / totalsize
2470 compratio = totalrawsize / totalsize
2476
2471
2477 basedfmtstr = '%%%dd\n'
2472 basedfmtstr = '%%%dd\n'
2478 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2473 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2479
2474
2480 def dfmtstr(max):
2475 def dfmtstr(max):
2481 return basedfmtstr % len(str(max))
2476 return basedfmtstr % len(str(max))
2482 def pcfmtstr(max, padding=0):
2477 def pcfmtstr(max, padding=0):
2483 return basepcfmtstr % (len(str(max)), ' ' * padding)
2478 return basepcfmtstr % (len(str(max)), ' ' * padding)
2484
2479
2485 def pcfmt(value, total):
2480 def pcfmt(value, total):
2486 if total:
2481 if total:
2487 return (value, 100 * float(value) / total)
2482 return (value, 100 * float(value) / total)
2488 else:
2483 else:
2489 return value, 100.0
2484 return value, 100.0
2490
2485
2491 ui.write(('format : %d\n') % format)
2486 ui.write(('format : %d\n') % format)
2492 ui.write(('flags : %s\n') % ', '.join(flags))
2487 ui.write(('flags : %s\n') % ', '.join(flags))
2493
2488
2494 ui.write('\n')
2489 ui.write('\n')
2495 fmt = pcfmtstr(totalsize)
2490 fmt = pcfmtstr(totalsize)
2496 fmt2 = dfmtstr(totalsize)
2491 fmt2 = dfmtstr(totalsize)
2497 ui.write(('revisions : ') + fmt2 % numrevs)
2492 ui.write(('revisions : ') + fmt2 % numrevs)
2498 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2493 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2499 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2494 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2500 ui.write(('revisions : ') + fmt2 % numrevs)
2495 ui.write(('revisions : ') + fmt2 % numrevs)
2501 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2496 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2502 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2497 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2503 ui.write(('revision size : ') + fmt2 % totalsize)
2498 ui.write(('revision size : ') + fmt2 % totalsize)
2504 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2499 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2505 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2500 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2506
2501
2507 def fmtchunktype(chunktype):
2502 def fmtchunktype(chunktype):
2508 if chunktype == 'empty':
2503 if chunktype == 'empty':
2509 return ' %s : ' % chunktype
2504 return ' %s : ' % chunktype
2510 elif chunktype in string.ascii_letters:
2505 elif chunktype in string.ascii_letters:
2511 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2506 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2512 else:
2507 else:
2513 return ' 0x%s : ' % hex(chunktype)
2508 return ' 0x%s : ' % hex(chunktype)
2514
2509
2515 ui.write('\n')
2510 ui.write('\n')
2516 ui.write(('chunks : ') + fmt2 % numrevs)
2511 ui.write(('chunks : ') + fmt2 % numrevs)
2517 for chunktype in sorted(chunktypecounts):
2512 for chunktype in sorted(chunktypecounts):
2518 ui.write(fmtchunktype(chunktype))
2513 ui.write(fmtchunktype(chunktype))
2519 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2514 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2520 ui.write(('chunks size : ') + fmt2 % totalsize)
2515 ui.write(('chunks size : ') + fmt2 % totalsize)
2521 for chunktype in sorted(chunktypecounts):
2516 for chunktype in sorted(chunktypecounts):
2522 ui.write(fmtchunktype(chunktype))
2517 ui.write(fmtchunktype(chunktype))
2523 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2518 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2524
2519
2525 ui.write('\n')
2520 ui.write('\n')
2526 fmt = dfmtstr(max(avgchainlen, compratio))
2521 fmt = dfmtstr(max(avgchainlen, compratio))
2527 ui.write(('avg chain length : ') + fmt % avgchainlen)
2522 ui.write(('avg chain length : ') + fmt % avgchainlen)
2528 ui.write(('max chain length : ') + fmt % maxchainlen)
2523 ui.write(('max chain length : ') + fmt % maxchainlen)
2529 ui.write(('compression ratio : ') + fmt % compratio)
2524 ui.write(('compression ratio : ') + fmt % compratio)
2530
2525
2531 if format > 0:
2526 if format > 0:
2532 ui.write('\n')
2527 ui.write('\n')
2533 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2528 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2534 % tuple(datasize))
2529 % tuple(datasize))
2535 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2530 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2536 % tuple(fullsize))
2531 % tuple(fullsize))
2537 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2532 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2538 % tuple(deltasize))
2533 % tuple(deltasize))
2539
2534
2540 if numdeltas > 0:
2535 if numdeltas > 0:
2541 ui.write('\n')
2536 ui.write('\n')
2542 fmt = pcfmtstr(numdeltas)
2537 fmt = pcfmtstr(numdeltas)
2543 fmt2 = pcfmtstr(numdeltas, 4)
2538 fmt2 = pcfmtstr(numdeltas, 4)
2544 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2539 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2545 if numprev > 0:
2540 if numprev > 0:
2546 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2541 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2547 numprev))
2542 numprev))
2548 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2543 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2549 numprev))
2544 numprev))
2550 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2545 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2551 numprev))
2546 numprev))
2552 if gdelta:
2547 if gdelta:
2553 ui.write(('deltas against p1 : ')
2548 ui.write(('deltas against p1 : ')
2554 + fmt % pcfmt(nump1, numdeltas))
2549 + fmt % pcfmt(nump1, numdeltas))
2555 ui.write(('deltas against p2 : ')
2550 ui.write(('deltas against p2 : ')
2556 + fmt % pcfmt(nump2, numdeltas))
2551 + fmt % pcfmt(nump2, numdeltas))
2557 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2552 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2558 numdeltas))
2553 numdeltas))
2559
2554
2560 @command('debugrevspec',
2555 @command('debugrevspec',
2561 [('', 'optimize', None,
2556 [('', 'optimize', None,
2562 _('print parsed tree after optimizing (DEPRECATED)')),
2557 _('print parsed tree after optimizing (DEPRECATED)')),
2563 ('p', 'show-stage', [],
2558 ('p', 'show-stage', [],
2564 _('print parsed tree at the given stage'), _('NAME')),
2559 _('print parsed tree at the given stage'), _('NAME')),
2565 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2560 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2566 ('', 'verify-optimized', False, _('verify optimized result')),
2561 ('', 'verify-optimized', False, _('verify optimized result')),
2567 ],
2562 ],
2568 ('REVSPEC'))
2563 ('REVSPEC'))
2569 def debugrevspec(ui, repo, expr, **opts):
2564 def debugrevspec(ui, repo, expr, **opts):
2570 """parse and apply a revision specification
2565 """parse and apply a revision specification
2571
2566
2572 Use -p/--show-stage option to print the parsed tree at the given stages.
2567 Use -p/--show-stage option to print the parsed tree at the given stages.
2573 Use -p all to print tree at every stage.
2568 Use -p all to print tree at every stage.
2574
2569
2575 Use --verify-optimized to compare the optimized result with the unoptimized
2570 Use --verify-optimized to compare the optimized result with the unoptimized
2576 one. Returns 1 if the optimized result differs.
2571 one. Returns 1 if the optimized result differs.
2577 """
2572 """
2578 stages = [
2573 stages = [
2579 ('parsed', lambda tree: tree),
2574 ('parsed', lambda tree: tree),
2580 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2575 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2581 ('concatenated', revset.foldconcat),
2576 ('concatenated', revset.foldconcat),
2582 ('analyzed', revset.analyze),
2577 ('analyzed', revset.analyze),
2583 ('optimized', revset.optimize),
2578 ('optimized', revset.optimize),
2584 ]
2579 ]
2585 if opts['no_optimized']:
2580 if opts['no_optimized']:
2586 stages = stages[:-1]
2581 stages = stages[:-1]
2587 if opts['verify_optimized'] and opts['no_optimized']:
2582 if opts['verify_optimized'] and opts['no_optimized']:
2588 raise error.Abort(_('cannot use --verify-optimized with '
2583 raise error.Abort(_('cannot use --verify-optimized with '
2589 '--no-optimized'))
2584 '--no-optimized'))
2590 stagenames = set(n for n, f in stages)
2585 stagenames = set(n for n, f in stages)
2591
2586
2592 showalways = set()
2587 showalways = set()
2593 showchanged = set()
2588 showchanged = set()
2594 if ui.verbose and not opts['show_stage']:
2589 if ui.verbose and not opts['show_stage']:
2595 # show parsed tree by --verbose (deprecated)
2590 # show parsed tree by --verbose (deprecated)
2596 showalways.add('parsed')
2591 showalways.add('parsed')
2597 showchanged.update(['expanded', 'concatenated'])
2592 showchanged.update(['expanded', 'concatenated'])
2598 if opts['optimize']:
2593 if opts['optimize']:
2599 showalways.add('optimized')
2594 showalways.add('optimized')
2600 if opts['show_stage'] and opts['optimize']:
2595 if opts['show_stage'] and opts['optimize']:
2601 raise error.Abort(_('cannot use --optimize with --show-stage'))
2596 raise error.Abort(_('cannot use --optimize with --show-stage'))
2602 if opts['show_stage'] == ['all']:
2597 if opts['show_stage'] == ['all']:
2603 showalways.update(stagenames)
2598 showalways.update(stagenames)
2604 else:
2599 else:
2605 for n in opts['show_stage']:
2600 for n in opts['show_stage']:
2606 if n not in stagenames:
2601 if n not in stagenames:
2607 raise error.Abort(_('invalid stage name: %s') % n)
2602 raise error.Abort(_('invalid stage name: %s') % n)
2608 showalways.update(opts['show_stage'])
2603 showalways.update(opts['show_stage'])
2609
2604
2610 treebystage = {}
2605 treebystage = {}
2611 printedtree = None
2606 printedtree = None
2612 tree = revset.parse(expr, lookup=repo.__contains__)
2607 tree = revset.parse(expr, lookup=repo.__contains__)
2613 for n, f in stages:
2608 for n, f in stages:
2614 treebystage[n] = tree = f(tree)
2609 treebystage[n] = tree = f(tree)
2615 if n in showalways or (n in showchanged and tree != printedtree):
2610 if n in showalways or (n in showchanged and tree != printedtree):
2616 if opts['show_stage'] or n != 'parsed':
2611 if opts['show_stage'] or n != 'parsed':
2617 ui.write(("* %s:\n") % n)
2612 ui.write(("* %s:\n") % n)
2618 ui.write(revset.prettyformat(tree), "\n")
2613 ui.write(revset.prettyformat(tree), "\n")
2619 printedtree = tree
2614 printedtree = tree
2620
2615
2621 if opts['verify_optimized']:
2616 if opts['verify_optimized']:
2622 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2617 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2623 brevs = revset.makematcher(treebystage['optimized'])(repo)
2618 brevs = revset.makematcher(treebystage['optimized'])(repo)
2624 if ui.verbose:
2619 if ui.verbose:
2625 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2620 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2626 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2621 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2627 arevs = list(arevs)
2622 arevs = list(arevs)
2628 brevs = list(brevs)
2623 brevs = list(brevs)
2629 if arevs == brevs:
2624 if arevs == brevs:
2630 return 0
2625 return 0
2631 ui.write(('--- analyzed\n'), label='diff.file_a')
2626 ui.write(('--- analyzed\n'), label='diff.file_a')
2632 ui.write(('+++ optimized\n'), label='diff.file_b')
2627 ui.write(('+++ optimized\n'), label='diff.file_b')
2633 sm = difflib.SequenceMatcher(None, arevs, brevs)
2628 sm = difflib.SequenceMatcher(None, arevs, brevs)
2634 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2629 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2635 if tag in ('delete', 'replace'):
2630 if tag in ('delete', 'replace'):
2636 for c in arevs[alo:ahi]:
2631 for c in arevs[alo:ahi]:
2637 ui.write('-%s\n' % c, label='diff.deleted')
2632 ui.write('-%s\n' % c, label='diff.deleted')
2638 if tag in ('insert', 'replace'):
2633 if tag in ('insert', 'replace'):
2639 for c in brevs[blo:bhi]:
2634 for c in brevs[blo:bhi]:
2640 ui.write('+%s\n' % c, label='diff.inserted')
2635 ui.write('+%s\n' % c, label='diff.inserted')
2641 if tag == 'equal':
2636 if tag == 'equal':
2642 for c in arevs[alo:ahi]:
2637 for c in arevs[alo:ahi]:
2643 ui.write(' %s\n' % c)
2638 ui.write(' %s\n' % c)
2644 return 1
2639 return 1
2645
2640
2646 func = revset.makematcher(tree)
2641 func = revset.makematcher(tree)
2647 revs = func(repo)
2642 revs = func(repo)
2648 if ui.verbose:
2643 if ui.verbose:
2649 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2644 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2650 for c in revs:
2645 for c in revs:
2651 ui.write("%s\n" % c)
2646 ui.write("%s\n" % c)
2652
2647
2653 @command('debugsetparents', [], _('REV1 [REV2]'))
2648 @command('debugsetparents', [], _('REV1 [REV2]'))
2654 def debugsetparents(ui, repo, rev1, rev2=None):
2649 def debugsetparents(ui, repo, rev1, rev2=None):
2655 """manually set the parents of the current working directory
2650 """manually set the parents of the current working directory
2656
2651
2657 This is useful for writing repository conversion tools, but should
2652 This is useful for writing repository conversion tools, but should
2658 be used with care. For example, neither the working directory nor the
2653 be used with care. For example, neither the working directory nor the
2659 dirstate is updated, so file status may be incorrect after running this
2654 dirstate is updated, so file status may be incorrect after running this
2660 command.
2655 command.
2661
2656
2662 Returns 0 on success.
2657 Returns 0 on success.
2663 """
2658 """
2664
2659
2665 r1 = scmutil.revsingle(repo, rev1).node()
2660 r1 = scmutil.revsingle(repo, rev1).node()
2666 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2661 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2667
2662
2668 with repo.wlock():
2663 with repo.wlock():
2669 repo.setparents(r1, r2)
2664 repo.setparents(r1, r2)
2670
2665
2671 @command('debugdirstate|debugstate',
2666 @command('debugdirstate|debugstate',
2672 [('', 'nodates', None, _('do not display the saved mtime')),
2667 [('', 'nodates', None, _('do not display the saved mtime')),
2673 ('', 'datesort', None, _('sort by saved mtime'))],
2668 ('', 'datesort', None, _('sort by saved mtime'))],
2674 _('[OPTION]...'))
2669 _('[OPTION]...'))
2675 def debugstate(ui, repo, **opts):
2670 def debugstate(ui, repo, **opts):
2676 """show the contents of the current dirstate"""
2671 """show the contents of the current dirstate"""
2677
2672
2678 nodates = opts.get('nodates')
2673 nodates = opts.get('nodates')
2679 datesort = opts.get('datesort')
2674 datesort = opts.get('datesort')
2680
2675
2681 timestr = ""
2676 timestr = ""
2682 if datesort:
2677 if datesort:
2683 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2678 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2684 else:
2679 else:
2685 keyfunc = None # sort by filename
2680 keyfunc = None # sort by filename
2686 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2681 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2687 if ent[3] == -1:
2682 if ent[3] == -1:
2688 timestr = 'unset '
2683 timestr = 'unset '
2689 elif nodates:
2684 elif nodates:
2690 timestr = 'set '
2685 timestr = 'set '
2691 else:
2686 else:
2692 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2687 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2693 time.localtime(ent[3]))
2688 time.localtime(ent[3]))
2694 if ent[1] & 0o20000:
2689 if ent[1] & 0o20000:
2695 mode = 'lnk'
2690 mode = 'lnk'
2696 else:
2691 else:
2697 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2692 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2698 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2693 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2699 for f in repo.dirstate.copies():
2694 for f in repo.dirstate.copies():
2700 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2695 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2701
2696
2702 @command('debugsub',
2697 @command('debugsub',
2703 [('r', 'rev', '',
2698 [('r', 'rev', '',
2704 _('revision to check'), _('REV'))],
2699 _('revision to check'), _('REV'))],
2705 _('[-r REV] [REV]'))
2700 _('[-r REV] [REV]'))
2706 def debugsub(ui, repo, rev=None):
2701 def debugsub(ui, repo, rev=None):
2707 ctx = scmutil.revsingle(repo, rev, None)
2702 ctx = scmutil.revsingle(repo, rev, None)
2708 for k, v in sorted(ctx.substate.items()):
2703 for k, v in sorted(ctx.substate.items()):
2709 ui.write(('path %s\n') % k)
2704 ui.write(('path %s\n') % k)
2710 ui.write((' source %s\n') % v[0])
2705 ui.write((' source %s\n') % v[0])
2711 ui.write((' revision %s\n') % v[1])
2706 ui.write((' revision %s\n') % v[1])
2712
2707
2713 @command('debugsuccessorssets',
2708 @command('debugsuccessorssets',
2714 [],
2709 [],
2715 _('[REV]'))
2710 _('[REV]'))
2716 def debugsuccessorssets(ui, repo, *revs):
2711 def debugsuccessorssets(ui, repo, *revs):
2717 """show set of successors for revision
2712 """show set of successors for revision
2718
2713
2719 A successors set of changeset A is a consistent group of revisions that
2714 A successors set of changeset A is a consistent group of revisions that
2720 succeed A. It contains non-obsolete changesets only.
2715 succeed A. It contains non-obsolete changesets only.
2721
2716
2722 In most cases a changeset A has a single successors set containing a single
2717 In most cases a changeset A has a single successors set containing a single
2723 successor (changeset A replaced by A').
2718 successor (changeset A replaced by A').
2724
2719
2725 A changeset that is made obsolete with no successors are called "pruned".
2720 A changeset that is made obsolete with no successors are called "pruned".
2726 Such changesets have no successors sets at all.
2721 Such changesets have no successors sets at all.
2727
2722
2728 A changeset that has been "split" will have a successors set containing
2723 A changeset that has been "split" will have a successors set containing
2729 more than one successor.
2724 more than one successor.
2730
2725
2731 A changeset that has been rewritten in multiple different ways is called
2726 A changeset that has been rewritten in multiple different ways is called
2732 "divergent". Such changesets have multiple successor sets (each of which
2727 "divergent". Such changesets have multiple successor sets (each of which
2733 may also be split, i.e. have multiple successors).
2728 may also be split, i.e. have multiple successors).
2734
2729
2735 Results are displayed as follows::
2730 Results are displayed as follows::
2736
2731
2737 <rev1>
2732 <rev1>
2738 <successors-1A>
2733 <successors-1A>
2739 <rev2>
2734 <rev2>
2740 <successors-2A>
2735 <successors-2A>
2741 <successors-2B1> <successors-2B2> <successors-2B3>
2736 <successors-2B1> <successors-2B2> <successors-2B3>
2742
2737
2743 Here rev2 has two possible (i.e. divergent) successors sets. The first
2738 Here rev2 has two possible (i.e. divergent) successors sets. The first
2744 holds one element, whereas the second holds three (i.e. the changeset has
2739 holds one element, whereas the second holds three (i.e. the changeset has
2745 been split).
2740 been split).
2746 """
2741 """
2747 # passed to successorssets caching computation from one call to another
2742 # passed to successorssets caching computation from one call to another
2748 cache = {}
2743 cache = {}
2749 ctx2str = str
2744 ctx2str = str
2750 node2str = short
2745 node2str = short
2751 if ui.debug():
2746 if ui.debug():
2752 def ctx2str(ctx):
2747 def ctx2str(ctx):
2753 return ctx.hex()
2748 return ctx.hex()
2754 node2str = hex
2749 node2str = hex
2755 for rev in scmutil.revrange(repo, revs):
2750 for rev in scmutil.revrange(repo, revs):
2756 ctx = repo[rev]
2751 ctx = repo[rev]
2757 ui.write('%s\n'% ctx2str(ctx))
2752 ui.write('%s\n'% ctx2str(ctx))
2758 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2753 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2759 if succsset:
2754 if succsset:
2760 ui.write(' ')
2755 ui.write(' ')
2761 ui.write(node2str(succsset[0]))
2756 ui.write(node2str(succsset[0]))
2762 for node in succsset[1:]:
2757 for node in succsset[1:]:
2763 ui.write(' ')
2758 ui.write(' ')
2764 ui.write(node2str(node))
2759 ui.write(node2str(node))
2765 ui.write('\n')
2760 ui.write('\n')
2766
2761
2767 @command('debugtemplate',
2762 @command('debugtemplate',
2768 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2763 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2769 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2764 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2770 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2765 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2771 optionalrepo=True)
2766 optionalrepo=True)
2772 def debugtemplate(ui, repo, tmpl, **opts):
2767 def debugtemplate(ui, repo, tmpl, **opts):
2773 """parse and apply a template
2768 """parse and apply a template
2774
2769
2775 If -r/--rev is given, the template is processed as a log template and
2770 If -r/--rev is given, the template is processed as a log template and
2776 applied to the given changesets. Otherwise, it is processed as a generic
2771 applied to the given changesets. Otherwise, it is processed as a generic
2777 template.
2772 template.
2778
2773
2779 Use --verbose to print the parsed tree.
2774 Use --verbose to print the parsed tree.
2780 """
2775 """
2781 revs = None
2776 revs = None
2782 if opts['rev']:
2777 if opts['rev']:
2783 if repo is None:
2778 if repo is None:
2784 raise error.RepoError(_('there is no Mercurial repository here '
2779 raise error.RepoError(_('there is no Mercurial repository here '
2785 '(.hg not found)'))
2780 '(.hg not found)'))
2786 revs = scmutil.revrange(repo, opts['rev'])
2781 revs = scmutil.revrange(repo, opts['rev'])
2787
2782
2788 props = {}
2783 props = {}
2789 for d in opts['define']:
2784 for d in opts['define']:
2790 try:
2785 try:
2791 k, v = (e.strip() for e in d.split('=', 1))
2786 k, v = (e.strip() for e in d.split('=', 1))
2792 if not k:
2787 if not k:
2793 raise ValueError
2788 raise ValueError
2794 props[k] = v
2789 props[k] = v
2795 except ValueError:
2790 except ValueError:
2796 raise error.Abort(_('malformed keyword definition: %s') % d)
2791 raise error.Abort(_('malformed keyword definition: %s') % d)
2797
2792
2798 if ui.verbose:
2793 if ui.verbose:
2799 aliases = ui.configitems('templatealias')
2794 aliases = ui.configitems('templatealias')
2800 tree = templater.parse(tmpl)
2795 tree = templater.parse(tmpl)
2801 ui.note(templater.prettyformat(tree), '\n')
2796 ui.note(templater.prettyformat(tree), '\n')
2802 newtree = templater.expandaliases(tree, aliases)
2797 newtree = templater.expandaliases(tree, aliases)
2803 if newtree != tree:
2798 if newtree != tree:
2804 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2799 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2805
2800
2806 mapfile = None
2801 mapfile = None
2807 if revs is None:
2802 if revs is None:
2808 k = 'debugtemplate'
2803 k = 'debugtemplate'
2809 t = formatter.maketemplater(ui, k, tmpl)
2804 t = formatter.maketemplater(ui, k, tmpl)
2810 ui.write(templater.stringify(t(k, **props)))
2805 ui.write(templater.stringify(t(k, **props)))
2811 else:
2806 else:
2812 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2807 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2813 mapfile, buffered=False)
2808 mapfile, buffered=False)
2814 for r in revs:
2809 for r in revs:
2815 displayer.show(repo[r], **props)
2810 displayer.show(repo[r], **props)
2816 displayer.close()
2811 displayer.close()
2817
2812
2818 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2813 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2819 def debugwalk(ui, repo, *pats, **opts):
2814 def debugwalk(ui, repo, *pats, **opts):
2820 """show how files match on given patterns"""
2815 """show how files match on given patterns"""
2821 m = scmutil.match(repo[None], pats, opts)
2816 m = scmutil.match(repo[None], pats, opts)
2822 items = list(repo.walk(m))
2817 items = list(repo.walk(m))
2823 if not items:
2818 if not items:
2824 return
2819 return
2825 f = lambda fn: fn
2820 f = lambda fn: fn
2826 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2821 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2827 f = lambda fn: util.normpath(fn)
2822 f = lambda fn: util.normpath(fn)
2828 fmt = 'f %%-%ds %%-%ds %%s' % (
2823 fmt = 'f %%-%ds %%-%ds %%s' % (
2829 max([len(abs) for abs in items]),
2824 max([len(abs) for abs in items]),
2830 max([len(m.rel(abs)) for abs in items]))
2825 max([len(m.rel(abs)) for abs in items]))
2831 for abs in items:
2826 for abs in items:
2832 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2827 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2833 ui.write("%s\n" % line.rstrip())
2828 ui.write("%s\n" % line.rstrip())
2834
2829
2835 @command('debugwireargs',
2830 @command('debugwireargs',
2836 [('', 'three', '', 'three'),
2831 [('', 'three', '', 'three'),
2837 ('', 'four', '', 'four'),
2832 ('', 'four', '', 'four'),
2838 ('', 'five', '', 'five'),
2833 ('', 'five', '', 'five'),
2839 ] + remoteopts,
2834 ] + remoteopts,
2840 _('REPO [OPTIONS]... [ONE [TWO]]'),
2835 _('REPO [OPTIONS]... [ONE [TWO]]'),
2841 norepo=True)
2836 norepo=True)
2842 def debugwireargs(ui, repopath, *vals, **opts):
2837 def debugwireargs(ui, repopath, *vals, **opts):
2843 repo = hg.peer(ui, opts, repopath)
2838 repo = hg.peer(ui, opts, repopath)
2844 for opt in remoteopts:
2839 for opt in remoteopts:
2845 del opts[opt[1]]
2840 del opts[opt[1]]
2846 args = {}
2841 args = {}
2847 for k, v in opts.iteritems():
2842 for k, v in opts.iteritems():
2848 if v:
2843 if v:
2849 args[k] = v
2844 args[k] = v
2850 # run twice to check that we don't mess up the stream for the next command
2845 # run twice to check that we don't mess up the stream for the next command
2851 res1 = repo.debugwireargs(*vals, **args)
2846 res1 = repo.debugwireargs(*vals, **args)
2852 res2 = repo.debugwireargs(*vals, **args)
2847 res2 = repo.debugwireargs(*vals, **args)
2853 ui.write("%s\n" % res1)
2848 ui.write("%s\n" % res1)
2854 if res1 != res2:
2849 if res1 != res2:
2855 ui.warn("%s\n" % res2)
2850 ui.warn("%s\n" % res2)
2856
2851
2857 @command('^diff',
2852 @command('^diff',
2858 [('r', 'rev', [], _('revision'), _('REV')),
2853 [('r', 'rev', [], _('revision'), _('REV')),
2859 ('c', 'change', '', _('change made by revision'), _('REV'))
2854 ('c', 'change', '', _('change made by revision'), _('REV'))
2860 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2855 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2861 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2856 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2862 inferrepo=True)
2857 inferrepo=True)
2863 def diff(ui, repo, *pats, **opts):
2858 def diff(ui, repo, *pats, **opts):
2864 """diff repository (or selected files)
2859 """diff repository (or selected files)
2865
2860
2866 Show differences between revisions for the specified files.
2861 Show differences between revisions for the specified files.
2867
2862
2868 Differences between files are shown using the unified diff format.
2863 Differences between files are shown using the unified diff format.
2869
2864
2870 .. note::
2865 .. note::
2871
2866
2872 :hg:`diff` may generate unexpected results for merges, as it will
2867 :hg:`diff` may generate unexpected results for merges, as it will
2873 default to comparing against the working directory's first
2868 default to comparing against the working directory's first
2874 parent changeset if no revisions are specified.
2869 parent changeset if no revisions are specified.
2875
2870
2876 When two revision arguments are given, then changes are shown
2871 When two revision arguments are given, then changes are shown
2877 between those revisions. If only one revision is specified then
2872 between those revisions. If only one revision is specified then
2878 that revision is compared to the working directory, and, when no
2873 that revision is compared to the working directory, and, when no
2879 revisions are specified, the working directory files are compared
2874 revisions are specified, the working directory files are compared
2880 to its first parent.
2875 to its first parent.
2881
2876
2882 Alternatively you can specify -c/--change with a revision to see
2877 Alternatively you can specify -c/--change with a revision to see
2883 the changes in that changeset relative to its first parent.
2878 the changes in that changeset relative to its first parent.
2884
2879
2885 Without the -a/--text option, diff will avoid generating diffs of
2880 Without the -a/--text option, diff will avoid generating diffs of
2886 files it detects as binary. With -a, diff will generate a diff
2881 files it detects as binary. With -a, diff will generate a diff
2887 anyway, probably with undesirable results.
2882 anyway, probably with undesirable results.
2888
2883
2889 Use the -g/--git option to generate diffs in the git extended diff
2884 Use the -g/--git option to generate diffs in the git extended diff
2890 format. For more information, read :hg:`help diffs`.
2885 format. For more information, read :hg:`help diffs`.
2891
2886
2892 .. container:: verbose
2887 .. container:: verbose
2893
2888
2894 Examples:
2889 Examples:
2895
2890
2896 - compare a file in the current working directory to its parent::
2891 - compare a file in the current working directory to its parent::
2897
2892
2898 hg diff foo.c
2893 hg diff foo.c
2899
2894
2900 - compare two historical versions of a directory, with rename info::
2895 - compare two historical versions of a directory, with rename info::
2901
2896
2902 hg diff --git -r 1.0:1.2 lib/
2897 hg diff --git -r 1.0:1.2 lib/
2903
2898
2904 - get change stats relative to the last change on some date::
2899 - get change stats relative to the last change on some date::
2905
2900
2906 hg diff --stat -r "date('may 2')"
2901 hg diff --stat -r "date('may 2')"
2907
2902
2908 - diff all newly-added files that contain a keyword::
2903 - diff all newly-added files that contain a keyword::
2909
2904
2910 hg diff "set:added() and grep(GNU)"
2905 hg diff "set:added() and grep(GNU)"
2911
2906
2912 - compare a revision and its parents::
2907 - compare a revision and its parents::
2913
2908
2914 hg diff -c 9353 # compare against first parent
2909 hg diff -c 9353 # compare against first parent
2915 hg diff -r 9353^:9353 # same using revset syntax
2910 hg diff -r 9353^:9353 # same using revset syntax
2916 hg diff -r 9353^2:9353 # compare against the second parent
2911 hg diff -r 9353^2:9353 # compare against the second parent
2917
2912
2918 Returns 0 on success.
2913 Returns 0 on success.
2919 """
2914 """
2920
2915
2921 revs = opts.get('rev')
2916 revs = opts.get('rev')
2922 change = opts.get('change')
2917 change = opts.get('change')
2923 stat = opts.get('stat')
2918 stat = opts.get('stat')
2924 reverse = opts.get('reverse')
2919 reverse = opts.get('reverse')
2925
2920
2926 if revs and change:
2921 if revs and change:
2927 msg = _('cannot specify --rev and --change at the same time')
2922 msg = _('cannot specify --rev and --change at the same time')
2928 raise error.Abort(msg)
2923 raise error.Abort(msg)
2929 elif change:
2924 elif change:
2930 node2 = scmutil.revsingle(repo, change, None).node()
2925 node2 = scmutil.revsingle(repo, change, None).node()
2931 node1 = repo[node2].p1().node()
2926 node1 = repo[node2].p1().node()
2932 else:
2927 else:
2933 node1, node2 = scmutil.revpair(repo, revs)
2928 node1, node2 = scmutil.revpair(repo, revs)
2934
2929
2935 if reverse:
2930 if reverse:
2936 node1, node2 = node2, node1
2931 node1, node2 = node2, node1
2937
2932
2938 diffopts = patch.diffallopts(ui, opts)
2933 diffopts = patch.diffallopts(ui, opts)
2939 m = scmutil.match(repo[node2], pats, opts)
2934 m = scmutil.match(repo[node2], pats, opts)
2940 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2935 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2941 listsubrepos=opts.get('subrepos'),
2936 listsubrepos=opts.get('subrepos'),
2942 root=opts.get('root'))
2937 root=opts.get('root'))
2943
2938
2944 @command('^export',
2939 @command('^export',
2945 [('o', 'output', '',
2940 [('o', 'output', '',
2946 _('print output to file with formatted name'), _('FORMAT')),
2941 _('print output to file with formatted name'), _('FORMAT')),
2947 ('', 'switch-parent', None, _('diff against the second parent')),
2942 ('', 'switch-parent', None, _('diff against the second parent')),
2948 ('r', 'rev', [], _('revisions to export'), _('REV')),
2943 ('r', 'rev', [], _('revisions to export'), _('REV')),
2949 ] + diffopts,
2944 ] + diffopts,
2950 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2945 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2951 def export(ui, repo, *changesets, **opts):
2946 def export(ui, repo, *changesets, **opts):
2952 """dump the header and diffs for one or more changesets
2947 """dump the header and diffs for one or more changesets
2953
2948
2954 Print the changeset header and diffs for one or more revisions.
2949 Print the changeset header and diffs for one or more revisions.
2955 If no revision is given, the parent of the working directory is used.
2950 If no revision is given, the parent of the working directory is used.
2956
2951
2957 The information shown in the changeset header is: author, date,
2952 The information shown in the changeset header is: author, date,
2958 branch name (if non-default), changeset hash, parent(s) and commit
2953 branch name (if non-default), changeset hash, parent(s) and commit
2959 comment.
2954 comment.
2960
2955
2961 .. note::
2956 .. note::
2962
2957
2963 :hg:`export` may generate unexpected diff output for merge
2958 :hg:`export` may generate unexpected diff output for merge
2964 changesets, as it will compare the merge changeset against its
2959 changesets, as it will compare the merge changeset against its
2965 first parent only.
2960 first parent only.
2966
2961
2967 Output may be to a file, in which case the name of the file is
2962 Output may be to a file, in which case the name of the file is
2968 given using a format string. The formatting rules are as follows:
2963 given using a format string. The formatting rules are as follows:
2969
2964
2970 :``%%``: literal "%" character
2965 :``%%``: literal "%" character
2971 :``%H``: changeset hash (40 hexadecimal digits)
2966 :``%H``: changeset hash (40 hexadecimal digits)
2972 :``%N``: number of patches being generated
2967 :``%N``: number of patches being generated
2973 :``%R``: changeset revision number
2968 :``%R``: changeset revision number
2974 :``%b``: basename of the exporting repository
2969 :``%b``: basename of the exporting repository
2975 :``%h``: short-form changeset hash (12 hexadecimal digits)
2970 :``%h``: short-form changeset hash (12 hexadecimal digits)
2976 :``%m``: first line of the commit message (only alphanumeric characters)
2971 :``%m``: first line of the commit message (only alphanumeric characters)
2977 :``%n``: zero-padded sequence number, starting at 1
2972 :``%n``: zero-padded sequence number, starting at 1
2978 :``%r``: zero-padded changeset revision number
2973 :``%r``: zero-padded changeset revision number
2979
2974
2980 Without the -a/--text option, export will avoid generating diffs
2975 Without the -a/--text option, export will avoid generating diffs
2981 of files it detects as binary. With -a, export will generate a
2976 of files it detects as binary. With -a, export will generate a
2982 diff anyway, probably with undesirable results.
2977 diff anyway, probably with undesirable results.
2983
2978
2984 Use the -g/--git option to generate diffs in the git extended diff
2979 Use the -g/--git option to generate diffs in the git extended diff
2985 format. See :hg:`help diffs` for more information.
2980 format. See :hg:`help diffs` for more information.
2986
2981
2987 With the --switch-parent option, the diff will be against the
2982 With the --switch-parent option, the diff will be against the
2988 second parent. It can be useful to review a merge.
2983 second parent. It can be useful to review a merge.
2989
2984
2990 .. container:: verbose
2985 .. container:: verbose
2991
2986
2992 Examples:
2987 Examples:
2993
2988
2994 - use export and import to transplant a bugfix to the current
2989 - use export and import to transplant a bugfix to the current
2995 branch::
2990 branch::
2996
2991
2997 hg export -r 9353 | hg import -
2992 hg export -r 9353 | hg import -
2998
2993
2999 - export all the changesets between two revisions to a file with
2994 - export all the changesets between two revisions to a file with
3000 rename information::
2995 rename information::
3001
2996
3002 hg export --git -r 123:150 > changes.txt
2997 hg export --git -r 123:150 > changes.txt
3003
2998
3004 - split outgoing changes into a series of patches with
2999 - split outgoing changes into a series of patches with
3005 descriptive names::
3000 descriptive names::
3006
3001
3007 hg export -r "outgoing()" -o "%n-%m.patch"
3002 hg export -r "outgoing()" -o "%n-%m.patch"
3008
3003
3009 Returns 0 on success.
3004 Returns 0 on success.
3010 """
3005 """
3011 changesets += tuple(opts.get('rev', []))
3006 changesets += tuple(opts.get('rev', []))
3012 if not changesets:
3007 if not changesets:
3013 changesets = ['.']
3008 changesets = ['.']
3014 revs = scmutil.revrange(repo, changesets)
3009 revs = scmutil.revrange(repo, changesets)
3015 if not revs:
3010 if not revs:
3016 raise error.Abort(_("export requires at least one changeset"))
3011 raise error.Abort(_("export requires at least one changeset"))
3017 if len(revs) > 1:
3012 if len(revs) > 1:
3018 ui.note(_('exporting patches:\n'))
3013 ui.note(_('exporting patches:\n'))
3019 else:
3014 else:
3020 ui.note(_('exporting patch:\n'))
3015 ui.note(_('exporting patch:\n'))
3021 cmdutil.export(repo, revs, template=opts.get('output'),
3016 cmdutil.export(repo, revs, template=opts.get('output'),
3022 switch_parent=opts.get('switch_parent'),
3017 switch_parent=opts.get('switch_parent'),
3023 opts=patch.diffallopts(ui, opts))
3018 opts=patch.diffallopts(ui, opts))
3024
3019
3025 @command('files',
3020 @command('files',
3026 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3021 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3027 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3022 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3028 ] + walkopts + formatteropts + subrepoopts,
3023 ] + walkopts + formatteropts + subrepoopts,
3029 _('[OPTION]... [FILE]...'))
3024 _('[OPTION]... [FILE]...'))
3030 def files(ui, repo, *pats, **opts):
3025 def files(ui, repo, *pats, **opts):
3031 """list tracked files
3026 """list tracked files
3032
3027
3033 Print files under Mercurial control in the working directory or
3028 Print files under Mercurial control in the working directory or
3034 specified revision for given files (excluding removed files).
3029 specified revision for given files (excluding removed files).
3035 Files can be specified as filenames or filesets.
3030 Files can be specified as filenames or filesets.
3036
3031
3037 If no files are given to match, this command prints the names
3032 If no files are given to match, this command prints the names
3038 of all files under Mercurial control.
3033 of all files under Mercurial control.
3039
3034
3040 .. container:: verbose
3035 .. container:: verbose
3041
3036
3042 Examples:
3037 Examples:
3043
3038
3044 - list all files under the current directory::
3039 - list all files under the current directory::
3045
3040
3046 hg files .
3041 hg files .
3047
3042
3048 - shows sizes and flags for current revision::
3043 - shows sizes and flags for current revision::
3049
3044
3050 hg files -vr .
3045 hg files -vr .
3051
3046
3052 - list all files named README::
3047 - list all files named README::
3053
3048
3054 hg files -I "**/README"
3049 hg files -I "**/README"
3055
3050
3056 - list all binary files::
3051 - list all binary files::
3057
3052
3058 hg files "set:binary()"
3053 hg files "set:binary()"
3059
3054
3060 - find files containing a regular expression::
3055 - find files containing a regular expression::
3061
3056
3062 hg files "set:grep('bob')"
3057 hg files "set:grep('bob')"
3063
3058
3064 - search tracked file contents with xargs and grep::
3059 - search tracked file contents with xargs and grep::
3065
3060
3066 hg files -0 | xargs -0 grep foo
3061 hg files -0 | xargs -0 grep foo
3067
3062
3068 See :hg:`help patterns` and :hg:`help filesets` for more information
3063 See :hg:`help patterns` and :hg:`help filesets` for more information
3069 on specifying file patterns.
3064 on specifying file patterns.
3070
3065
3071 Returns 0 if a match is found, 1 otherwise.
3066 Returns 0 if a match is found, 1 otherwise.
3072
3067
3073 """
3068 """
3074 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3069 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3075
3070
3076 end = '\n'
3071 end = '\n'
3077 if opts.get('print0'):
3072 if opts.get('print0'):
3078 end = '\0'
3073 end = '\0'
3079 fmt = '%s' + end
3074 fmt = '%s' + end
3080
3075
3081 m = scmutil.match(ctx, pats, opts)
3076 m = scmutil.match(ctx, pats, opts)
3082 with ui.formatter('files', opts) as fm:
3077 with ui.formatter('files', opts) as fm:
3083 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3078 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3084
3079
3085 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3080 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3086 def forget(ui, repo, *pats, **opts):
3081 def forget(ui, repo, *pats, **opts):
3087 """forget the specified files on the next commit
3082 """forget the specified files on the next commit
3088
3083
3089 Mark the specified files so they will no longer be tracked
3084 Mark the specified files so they will no longer be tracked
3090 after the next commit.
3085 after the next commit.
3091
3086
3092 This only removes files from the current branch, not from the
3087 This only removes files from the current branch, not from the
3093 entire project history, and it does not delete them from the
3088 entire project history, and it does not delete them from the
3094 working directory.
3089 working directory.
3095
3090
3096 To delete the file from the working directory, see :hg:`remove`.
3091 To delete the file from the working directory, see :hg:`remove`.
3097
3092
3098 To undo a forget before the next commit, see :hg:`add`.
3093 To undo a forget before the next commit, see :hg:`add`.
3099
3094
3100 .. container:: verbose
3095 .. container:: verbose
3101
3096
3102 Examples:
3097 Examples:
3103
3098
3104 - forget newly-added binary files::
3099 - forget newly-added binary files::
3105
3100
3106 hg forget "set:added() and binary()"
3101 hg forget "set:added() and binary()"
3107
3102
3108 - forget files that would be excluded by .hgignore::
3103 - forget files that would be excluded by .hgignore::
3109
3104
3110 hg forget "set:hgignore()"
3105 hg forget "set:hgignore()"
3111
3106
3112 Returns 0 on success.
3107 Returns 0 on success.
3113 """
3108 """
3114
3109
3115 if not pats:
3110 if not pats:
3116 raise error.Abort(_('no files specified'))
3111 raise error.Abort(_('no files specified'))
3117
3112
3118 m = scmutil.match(repo[None], pats, opts)
3113 m = scmutil.match(repo[None], pats, opts)
3119 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3114 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3120 return rejected and 1 or 0
3115 return rejected and 1 or 0
3121
3116
3122 @command(
3117 @command(
3123 'graft',
3118 'graft',
3124 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3119 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3125 ('c', 'continue', False, _('resume interrupted graft')),
3120 ('c', 'continue', False, _('resume interrupted graft')),
3126 ('e', 'edit', False, _('invoke editor on commit messages')),
3121 ('e', 'edit', False, _('invoke editor on commit messages')),
3127 ('', 'log', None, _('append graft info to log message')),
3122 ('', 'log', None, _('append graft info to log message')),
3128 ('f', 'force', False, _('force graft')),
3123 ('f', 'force', False, _('force graft')),
3129 ('D', 'currentdate', False,
3124 ('D', 'currentdate', False,
3130 _('record the current date as commit date')),
3125 _('record the current date as commit date')),
3131 ('U', 'currentuser', False,
3126 ('U', 'currentuser', False,
3132 _('record the current user as committer'), _('DATE'))]
3127 _('record the current user as committer'), _('DATE'))]
3133 + commitopts2 + mergetoolopts + dryrunopts,
3128 + commitopts2 + mergetoolopts + dryrunopts,
3134 _('[OPTION]... [-r REV]... REV...'))
3129 _('[OPTION]... [-r REV]... REV...'))
3135 def graft(ui, repo, *revs, **opts):
3130 def graft(ui, repo, *revs, **opts):
3136 '''copy changes from other branches onto the current branch
3131 '''copy changes from other branches onto the current branch
3137
3132
3138 This command uses Mercurial's merge logic to copy individual
3133 This command uses Mercurial's merge logic to copy individual
3139 changes from other branches without merging branches in the
3134 changes from other branches without merging branches in the
3140 history graph. This is sometimes known as 'backporting' or
3135 history graph. This is sometimes known as 'backporting' or
3141 'cherry-picking'. By default, graft will copy user, date, and
3136 'cherry-picking'. By default, graft will copy user, date, and
3142 description from the source changesets.
3137 description from the source changesets.
3143
3138
3144 Changesets that are ancestors of the current revision, that have
3139 Changesets that are ancestors of the current revision, that have
3145 already been grafted, or that are merges will be skipped.
3140 already been grafted, or that are merges will be skipped.
3146
3141
3147 If --log is specified, log messages will have a comment appended
3142 If --log is specified, log messages will have a comment appended
3148 of the form::
3143 of the form::
3149
3144
3150 (grafted from CHANGESETHASH)
3145 (grafted from CHANGESETHASH)
3151
3146
3152 If --force is specified, revisions will be grafted even if they
3147 If --force is specified, revisions will be grafted even if they
3153 are already ancestors of or have been grafted to the destination.
3148 are already ancestors of or have been grafted to the destination.
3154 This is useful when the revisions have since been backed out.
3149 This is useful when the revisions have since been backed out.
3155
3150
3156 If a graft merge results in conflicts, the graft process is
3151 If a graft merge results in conflicts, the graft process is
3157 interrupted so that the current merge can be manually resolved.
3152 interrupted so that the current merge can be manually resolved.
3158 Once all conflicts are addressed, the graft process can be
3153 Once all conflicts are addressed, the graft process can be
3159 continued with the -c/--continue option.
3154 continued with the -c/--continue option.
3160
3155
3161 .. note::
3156 .. note::
3162
3157
3163 The -c/--continue option does not reapply earlier options, except
3158 The -c/--continue option does not reapply earlier options, except
3164 for --force.
3159 for --force.
3165
3160
3166 .. container:: verbose
3161 .. container:: verbose
3167
3162
3168 Examples:
3163 Examples:
3169
3164
3170 - copy a single change to the stable branch and edit its description::
3165 - copy a single change to the stable branch and edit its description::
3171
3166
3172 hg update stable
3167 hg update stable
3173 hg graft --edit 9393
3168 hg graft --edit 9393
3174
3169
3175 - graft a range of changesets with one exception, updating dates::
3170 - graft a range of changesets with one exception, updating dates::
3176
3171
3177 hg graft -D "2085::2093 and not 2091"
3172 hg graft -D "2085::2093 and not 2091"
3178
3173
3179 - continue a graft after resolving conflicts::
3174 - continue a graft after resolving conflicts::
3180
3175
3181 hg graft -c
3176 hg graft -c
3182
3177
3183 - show the source of a grafted changeset::
3178 - show the source of a grafted changeset::
3184
3179
3185 hg log --debug -r .
3180 hg log --debug -r .
3186
3181
3187 - show revisions sorted by date::
3182 - show revisions sorted by date::
3188
3183
3189 hg log -r "sort(all(), date)"
3184 hg log -r "sort(all(), date)"
3190
3185
3191 See :hg:`help revisions` for more about specifying revisions.
3186 See :hg:`help revisions` for more about specifying revisions.
3192
3187
3193 Returns 0 on successful completion.
3188 Returns 0 on successful completion.
3194 '''
3189 '''
3195 with repo.wlock():
3190 with repo.wlock():
3196 return _dograft(ui, repo, *revs, **opts)
3191 return _dograft(ui, repo, *revs, **opts)
3197
3192
3198 def _dograft(ui, repo, *revs, **opts):
3193 def _dograft(ui, repo, *revs, **opts):
3199 if revs and opts.get('rev'):
3194 if revs and opts.get('rev'):
3200 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3195 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3201 'revision ordering!\n'))
3196 'revision ordering!\n'))
3202
3197
3203 revs = list(revs)
3198 revs = list(revs)
3204 revs.extend(opts.get('rev'))
3199 revs.extend(opts.get('rev'))
3205
3200
3206 if not opts.get('user') and opts.get('currentuser'):
3201 if not opts.get('user') and opts.get('currentuser'):
3207 opts['user'] = ui.username()
3202 opts['user'] = ui.username()
3208 if not opts.get('date') and opts.get('currentdate'):
3203 if not opts.get('date') and opts.get('currentdate'):
3209 opts['date'] = "%d %d" % util.makedate()
3204 opts['date'] = "%d %d" % util.makedate()
3210
3205
3211 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3206 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3212
3207
3213 cont = False
3208 cont = False
3214 if opts.get('continue'):
3209 if opts.get('continue'):
3215 cont = True
3210 cont = True
3216 if revs:
3211 if revs:
3217 raise error.Abort(_("can't specify --continue and revisions"))
3212 raise error.Abort(_("can't specify --continue and revisions"))
3218 # read in unfinished revisions
3213 # read in unfinished revisions
3219 try:
3214 try:
3220 nodes = repo.vfs.read('graftstate').splitlines()
3215 nodes = repo.vfs.read('graftstate').splitlines()
3221 revs = [repo[node].rev() for node in nodes]
3216 revs = [repo[node].rev() for node in nodes]
3222 except IOError as inst:
3217 except IOError as inst:
3223 if inst.errno != errno.ENOENT:
3218 if inst.errno != errno.ENOENT:
3224 raise
3219 raise
3225 cmdutil.wrongtooltocontinue(repo, _('graft'))
3220 cmdutil.wrongtooltocontinue(repo, _('graft'))
3226 else:
3221 else:
3227 cmdutil.checkunfinished(repo)
3222 cmdutil.checkunfinished(repo)
3228 cmdutil.bailifchanged(repo)
3223 cmdutil.bailifchanged(repo)
3229 if not revs:
3224 if not revs:
3230 raise error.Abort(_('no revisions specified'))
3225 raise error.Abort(_('no revisions specified'))
3231 revs = scmutil.revrange(repo, revs)
3226 revs = scmutil.revrange(repo, revs)
3232
3227
3233 skipped = set()
3228 skipped = set()
3234 # check for merges
3229 # check for merges
3235 for rev in repo.revs('%ld and merge()', revs):
3230 for rev in repo.revs('%ld and merge()', revs):
3236 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3231 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3237 skipped.add(rev)
3232 skipped.add(rev)
3238 revs = [r for r in revs if r not in skipped]
3233 revs = [r for r in revs if r not in skipped]
3239 if not revs:
3234 if not revs:
3240 return -1
3235 return -1
3241
3236
3242 # Don't check in the --continue case, in effect retaining --force across
3237 # Don't check in the --continue case, in effect retaining --force across
3243 # --continues. That's because without --force, any revisions we decided to
3238 # --continues. That's because without --force, any revisions we decided to
3244 # skip would have been filtered out here, so they wouldn't have made their
3239 # skip would have been filtered out here, so they wouldn't have made their
3245 # way to the graftstate. With --force, any revisions we would have otherwise
3240 # way to the graftstate. With --force, any revisions we would have otherwise
3246 # skipped would not have been filtered out, and if they hadn't been applied
3241 # skipped would not have been filtered out, and if they hadn't been applied
3247 # already, they'd have been in the graftstate.
3242 # already, they'd have been in the graftstate.
3248 if not (cont or opts.get('force')):
3243 if not (cont or opts.get('force')):
3249 # check for ancestors of dest branch
3244 # check for ancestors of dest branch
3250 crev = repo['.'].rev()
3245 crev = repo['.'].rev()
3251 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3246 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3252 # XXX make this lazy in the future
3247 # XXX make this lazy in the future
3253 # don't mutate while iterating, create a copy
3248 # don't mutate while iterating, create a copy
3254 for rev in list(revs):
3249 for rev in list(revs):
3255 if rev in ancestors:
3250 if rev in ancestors:
3256 ui.warn(_('skipping ancestor revision %d:%s\n') %
3251 ui.warn(_('skipping ancestor revision %d:%s\n') %
3257 (rev, repo[rev]))
3252 (rev, repo[rev]))
3258 # XXX remove on list is slow
3253 # XXX remove on list is slow
3259 revs.remove(rev)
3254 revs.remove(rev)
3260 if not revs:
3255 if not revs:
3261 return -1
3256 return -1
3262
3257
3263 # analyze revs for earlier grafts
3258 # analyze revs for earlier grafts
3264 ids = {}
3259 ids = {}
3265 for ctx in repo.set("%ld", revs):
3260 for ctx in repo.set("%ld", revs):
3266 ids[ctx.hex()] = ctx.rev()
3261 ids[ctx.hex()] = ctx.rev()
3267 n = ctx.extra().get('source')
3262 n = ctx.extra().get('source')
3268 if n:
3263 if n:
3269 ids[n] = ctx.rev()
3264 ids[n] = ctx.rev()
3270
3265
3271 # check ancestors for earlier grafts
3266 # check ancestors for earlier grafts
3272 ui.debug('scanning for duplicate grafts\n')
3267 ui.debug('scanning for duplicate grafts\n')
3273
3268
3274 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3269 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3275 ctx = repo[rev]
3270 ctx = repo[rev]
3276 n = ctx.extra().get('source')
3271 n = ctx.extra().get('source')
3277 if n in ids:
3272 if n in ids:
3278 try:
3273 try:
3279 r = repo[n].rev()
3274 r = repo[n].rev()
3280 except error.RepoLookupError:
3275 except error.RepoLookupError:
3281 r = None
3276 r = None
3282 if r in revs:
3277 if r in revs:
3283 ui.warn(_('skipping revision %d:%s '
3278 ui.warn(_('skipping revision %d:%s '
3284 '(already grafted to %d:%s)\n')
3279 '(already grafted to %d:%s)\n')
3285 % (r, repo[r], rev, ctx))
3280 % (r, repo[r], rev, ctx))
3286 revs.remove(r)
3281 revs.remove(r)
3287 elif ids[n] in revs:
3282 elif ids[n] in revs:
3288 if r is None:
3283 if r is None:
3289 ui.warn(_('skipping already grafted revision %d:%s '
3284 ui.warn(_('skipping already grafted revision %d:%s '
3290 '(%d:%s also has unknown origin %s)\n')
3285 '(%d:%s also has unknown origin %s)\n')
3291 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3286 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3292 else:
3287 else:
3293 ui.warn(_('skipping already grafted revision %d:%s '
3288 ui.warn(_('skipping already grafted revision %d:%s '
3294 '(%d:%s also has origin %d:%s)\n')
3289 '(%d:%s also has origin %d:%s)\n')
3295 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3290 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3296 revs.remove(ids[n])
3291 revs.remove(ids[n])
3297 elif ctx.hex() in ids:
3292 elif ctx.hex() in ids:
3298 r = ids[ctx.hex()]
3293 r = ids[ctx.hex()]
3299 ui.warn(_('skipping already grafted revision %d:%s '
3294 ui.warn(_('skipping already grafted revision %d:%s '
3300 '(was grafted from %d:%s)\n') %
3295 '(was grafted from %d:%s)\n') %
3301 (r, repo[r], rev, ctx))
3296 (r, repo[r], rev, ctx))
3302 revs.remove(r)
3297 revs.remove(r)
3303 if not revs:
3298 if not revs:
3304 return -1
3299 return -1
3305
3300
3306 for pos, ctx in enumerate(repo.set("%ld", revs)):
3301 for pos, ctx in enumerate(repo.set("%ld", revs)):
3307 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3302 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3308 ctx.description().split('\n', 1)[0])
3303 ctx.description().split('\n', 1)[0])
3309 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3304 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3310 if names:
3305 if names:
3311 desc += ' (%s)' % ' '.join(names)
3306 desc += ' (%s)' % ' '.join(names)
3312 ui.status(_('grafting %s\n') % desc)
3307 ui.status(_('grafting %s\n') % desc)
3313 if opts.get('dry_run'):
3308 if opts.get('dry_run'):
3314 continue
3309 continue
3315
3310
3316 source = ctx.extra().get('source')
3311 source = ctx.extra().get('source')
3317 extra = {}
3312 extra = {}
3318 if source:
3313 if source:
3319 extra['source'] = source
3314 extra['source'] = source
3320 extra['intermediate-source'] = ctx.hex()
3315 extra['intermediate-source'] = ctx.hex()
3321 else:
3316 else:
3322 extra['source'] = ctx.hex()
3317 extra['source'] = ctx.hex()
3323 user = ctx.user()
3318 user = ctx.user()
3324 if opts.get('user'):
3319 if opts.get('user'):
3325 user = opts['user']
3320 user = opts['user']
3326 date = ctx.date()
3321 date = ctx.date()
3327 if opts.get('date'):
3322 if opts.get('date'):
3328 date = opts['date']
3323 date = opts['date']
3329 message = ctx.description()
3324 message = ctx.description()
3330 if opts.get('log'):
3325 if opts.get('log'):
3331 message += '\n(grafted from %s)' % ctx.hex()
3326 message += '\n(grafted from %s)' % ctx.hex()
3332
3327
3333 # we don't merge the first commit when continuing
3328 # we don't merge the first commit when continuing
3334 if not cont:
3329 if not cont:
3335 # perform the graft merge with p1(rev) as 'ancestor'
3330 # perform the graft merge with p1(rev) as 'ancestor'
3336 try:
3331 try:
3337 # ui.forcemerge is an internal variable, do not document
3332 # ui.forcemerge is an internal variable, do not document
3338 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3333 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3339 'graft')
3334 'graft')
3340 stats = mergemod.graft(repo, ctx, ctx.p1(),
3335 stats = mergemod.graft(repo, ctx, ctx.p1(),
3341 ['local', 'graft'])
3336 ['local', 'graft'])
3342 finally:
3337 finally:
3343 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3338 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3344 # report any conflicts
3339 # report any conflicts
3345 if stats and stats[3] > 0:
3340 if stats and stats[3] > 0:
3346 # write out state for --continue
3341 # write out state for --continue
3347 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3342 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3348 repo.vfs.write('graftstate', ''.join(nodelines))
3343 repo.vfs.write('graftstate', ''.join(nodelines))
3349 extra = ''
3344 extra = ''
3350 if opts.get('user'):
3345 if opts.get('user'):
3351 extra += ' --user %s' % util.shellquote(opts['user'])
3346 extra += ' --user %s' % util.shellquote(opts['user'])
3352 if opts.get('date'):
3347 if opts.get('date'):
3353 extra += ' --date %s' % util.shellquote(opts['date'])
3348 extra += ' --date %s' % util.shellquote(opts['date'])
3354 if opts.get('log'):
3349 if opts.get('log'):
3355 extra += ' --log'
3350 extra += ' --log'
3356 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3351 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3357 raise error.Abort(
3352 raise error.Abort(
3358 _("unresolved conflicts, can't continue"),
3353 _("unresolved conflicts, can't continue"),
3359 hint=hint)
3354 hint=hint)
3360 else:
3355 else:
3361 cont = False
3356 cont = False
3362
3357
3363 # commit
3358 # commit
3364 node = repo.commit(text=message, user=user,
3359 node = repo.commit(text=message, user=user,
3365 date=date, extra=extra, editor=editor)
3360 date=date, extra=extra, editor=editor)
3366 if node is None:
3361 if node is None:
3367 ui.warn(
3362 ui.warn(
3368 _('note: graft of %d:%s created no changes to commit\n') %
3363 _('note: graft of %d:%s created no changes to commit\n') %
3369 (ctx.rev(), ctx))
3364 (ctx.rev(), ctx))
3370
3365
3371 # remove state when we complete successfully
3366 # remove state when we complete successfully
3372 if not opts.get('dry_run'):
3367 if not opts.get('dry_run'):
3373 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3368 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3374
3369
3375 return 0
3370 return 0
3376
3371
3377 @command('grep',
3372 @command('grep',
3378 [('0', 'print0', None, _('end fields with NUL')),
3373 [('0', 'print0', None, _('end fields with NUL')),
3379 ('', 'all', None, _('print all revisions that match')),
3374 ('', 'all', None, _('print all revisions that match')),
3380 ('a', 'text', None, _('treat all files as text')),
3375 ('a', 'text', None, _('treat all files as text')),
3381 ('f', 'follow', None,
3376 ('f', 'follow', None,
3382 _('follow changeset history,'
3377 _('follow changeset history,'
3383 ' or file history across copies and renames')),
3378 ' or file history across copies and renames')),
3384 ('i', 'ignore-case', None, _('ignore case when matching')),
3379 ('i', 'ignore-case', None, _('ignore case when matching')),
3385 ('l', 'files-with-matches', None,
3380 ('l', 'files-with-matches', None,
3386 _('print only filenames and revisions that match')),
3381 _('print only filenames and revisions that match')),
3387 ('n', 'line-number', None, _('print matching line numbers')),
3382 ('n', 'line-number', None, _('print matching line numbers')),
3388 ('r', 'rev', [],
3383 ('r', 'rev', [],
3389 _('only search files changed within revision range'), _('REV')),
3384 _('only search files changed within revision range'), _('REV')),
3390 ('u', 'user', None, _('list the author (long with -v)')),
3385 ('u', 'user', None, _('list the author (long with -v)')),
3391 ('d', 'date', None, _('list the date (short with -q)')),
3386 ('d', 'date', None, _('list the date (short with -q)')),
3392 ] + formatteropts + walkopts,
3387 ] + formatteropts + walkopts,
3393 _('[OPTION]... PATTERN [FILE]...'),
3388 _('[OPTION]... PATTERN [FILE]...'),
3394 inferrepo=True)
3389 inferrepo=True)
3395 def grep(ui, repo, pattern, *pats, **opts):
3390 def grep(ui, repo, pattern, *pats, **opts):
3396 """search revision history for a pattern in specified files
3391 """search revision history for a pattern in specified files
3397
3392
3398 Search revision history for a regular expression in the specified
3393 Search revision history for a regular expression in the specified
3399 files or the entire project.
3394 files or the entire project.
3400
3395
3401 By default, grep prints the most recent revision number for each
3396 By default, grep prints the most recent revision number for each
3402 file in which it finds a match. To get it to print every revision
3397 file in which it finds a match. To get it to print every revision
3403 that contains a change in match status ("-" for a match that becomes
3398 that contains a change in match status ("-" for a match that becomes
3404 a non-match, or "+" for a non-match that becomes a match), use the
3399 a non-match, or "+" for a non-match that becomes a match), use the
3405 --all flag.
3400 --all flag.
3406
3401
3407 PATTERN can be any Python (roughly Perl-compatible) regular
3402 PATTERN can be any Python (roughly Perl-compatible) regular
3408 expression.
3403 expression.
3409
3404
3410 If no FILEs are specified (and -f/--follow isn't set), all files in
3405 If no FILEs are specified (and -f/--follow isn't set), all files in
3411 the repository are searched, including those that don't exist in the
3406 the repository are searched, including those that don't exist in the
3412 current branch or have been deleted in a prior changeset.
3407 current branch or have been deleted in a prior changeset.
3413
3408
3414 Returns 0 if a match is found, 1 otherwise.
3409 Returns 0 if a match is found, 1 otherwise.
3415 """
3410 """
3416 reflags = re.M
3411 reflags = re.M
3417 if opts.get('ignore_case'):
3412 if opts.get('ignore_case'):
3418 reflags |= re.I
3413 reflags |= re.I
3419 try:
3414 try:
3420 regexp = util.re.compile(pattern, reflags)
3415 regexp = util.re.compile(pattern, reflags)
3421 except re.error as inst:
3416 except re.error as inst:
3422 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3417 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3423 return 1
3418 return 1
3424 sep, eol = ':', '\n'
3419 sep, eol = ':', '\n'
3425 if opts.get('print0'):
3420 if opts.get('print0'):
3426 sep = eol = '\0'
3421 sep = eol = '\0'
3427
3422
3428 getfile = util.lrucachefunc(repo.file)
3423 getfile = util.lrucachefunc(repo.file)
3429
3424
3430 def matchlines(body):
3425 def matchlines(body):
3431 begin = 0
3426 begin = 0
3432 linenum = 0
3427 linenum = 0
3433 while begin < len(body):
3428 while begin < len(body):
3434 match = regexp.search(body, begin)
3429 match = regexp.search(body, begin)
3435 if not match:
3430 if not match:
3436 break
3431 break
3437 mstart, mend = match.span()
3432 mstart, mend = match.span()
3438 linenum += body.count('\n', begin, mstart) + 1
3433 linenum += body.count('\n', begin, mstart) + 1
3439 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3434 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3440 begin = body.find('\n', mend) + 1 or len(body) + 1
3435 begin = body.find('\n', mend) + 1 or len(body) + 1
3441 lend = begin - 1
3436 lend = begin - 1
3442 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3437 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3443
3438
3444 class linestate(object):
3439 class linestate(object):
3445 def __init__(self, line, linenum, colstart, colend):
3440 def __init__(self, line, linenum, colstart, colend):
3446 self.line = line
3441 self.line = line
3447 self.linenum = linenum
3442 self.linenum = linenum
3448 self.colstart = colstart
3443 self.colstart = colstart
3449 self.colend = colend
3444 self.colend = colend
3450
3445
3451 def __hash__(self):
3446 def __hash__(self):
3452 return hash((self.linenum, self.line))
3447 return hash((self.linenum, self.line))
3453
3448
3454 def __eq__(self, other):
3449 def __eq__(self, other):
3455 return self.line == other.line
3450 return self.line == other.line
3456
3451
3457 def findpos(self):
3452 def findpos(self):
3458 """Iterate all (start, end) indices of matches"""
3453 """Iterate all (start, end) indices of matches"""
3459 yield self.colstart, self.colend
3454 yield self.colstart, self.colend
3460 p = self.colend
3455 p = self.colend
3461 while p < len(self.line):
3456 while p < len(self.line):
3462 m = regexp.search(self.line, p)
3457 m = regexp.search(self.line, p)
3463 if not m:
3458 if not m:
3464 break
3459 break
3465 yield m.span()
3460 yield m.span()
3466 p = m.end()
3461 p = m.end()
3467
3462
3468 matches = {}
3463 matches = {}
3469 copies = {}
3464 copies = {}
3470 def grepbody(fn, rev, body):
3465 def grepbody(fn, rev, body):
3471 matches[rev].setdefault(fn, [])
3466 matches[rev].setdefault(fn, [])
3472 m = matches[rev][fn]
3467 m = matches[rev][fn]
3473 for lnum, cstart, cend, line in matchlines(body):
3468 for lnum, cstart, cend, line in matchlines(body):
3474 s = linestate(line, lnum, cstart, cend)
3469 s = linestate(line, lnum, cstart, cend)
3475 m.append(s)
3470 m.append(s)
3476
3471
3477 def difflinestates(a, b):
3472 def difflinestates(a, b):
3478 sm = difflib.SequenceMatcher(None, a, b)
3473 sm = difflib.SequenceMatcher(None, a, b)
3479 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3474 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3480 if tag == 'insert':
3475 if tag == 'insert':
3481 for i in xrange(blo, bhi):
3476 for i in xrange(blo, bhi):
3482 yield ('+', b[i])
3477 yield ('+', b[i])
3483 elif tag == 'delete':
3478 elif tag == 'delete':
3484 for i in xrange(alo, ahi):
3479 for i in xrange(alo, ahi):
3485 yield ('-', a[i])
3480 yield ('-', a[i])
3486 elif tag == 'replace':
3481 elif tag == 'replace':
3487 for i in xrange(alo, ahi):
3482 for i in xrange(alo, ahi):
3488 yield ('-', a[i])
3483 yield ('-', a[i])
3489 for i in xrange(blo, bhi):
3484 for i in xrange(blo, bhi):
3490 yield ('+', b[i])
3485 yield ('+', b[i])
3491
3486
3492 def display(fm, fn, ctx, pstates, states):
3487 def display(fm, fn, ctx, pstates, states):
3493 rev = ctx.rev()
3488 rev = ctx.rev()
3494 if fm.isplain():
3489 if fm.isplain():
3495 formatuser = ui.shortuser
3490 formatuser = ui.shortuser
3496 else:
3491 else:
3497 formatuser = str
3492 formatuser = str
3498 if ui.quiet:
3493 if ui.quiet:
3499 datefmt = '%Y-%m-%d'
3494 datefmt = '%Y-%m-%d'
3500 else:
3495 else:
3501 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3496 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3502 found = False
3497 found = False
3503 @util.cachefunc
3498 @util.cachefunc
3504 def binary():
3499 def binary():
3505 flog = getfile(fn)
3500 flog = getfile(fn)
3506 return util.binary(flog.read(ctx.filenode(fn)))
3501 return util.binary(flog.read(ctx.filenode(fn)))
3507
3502
3508 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3503 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3509 if opts.get('all'):
3504 if opts.get('all'):
3510 iter = difflinestates(pstates, states)
3505 iter = difflinestates(pstates, states)
3511 else:
3506 else:
3512 iter = [('', l) for l in states]
3507 iter = [('', l) for l in states]
3513 for change, l in iter:
3508 for change, l in iter:
3514 fm.startitem()
3509 fm.startitem()
3515 fm.data(node=fm.hexfunc(ctx.node()))
3510 fm.data(node=fm.hexfunc(ctx.node()))
3516 cols = [
3511 cols = [
3517 ('filename', fn, True),
3512 ('filename', fn, True),
3518 ('rev', rev, True),
3513 ('rev', rev, True),
3519 ('linenumber', l.linenum, opts.get('line_number')),
3514 ('linenumber', l.linenum, opts.get('line_number')),
3520 ]
3515 ]
3521 if opts.get('all'):
3516 if opts.get('all'):
3522 cols.append(('change', change, True))
3517 cols.append(('change', change, True))
3523 cols.extend([
3518 cols.extend([
3524 ('user', formatuser(ctx.user()), opts.get('user')),
3519 ('user', formatuser(ctx.user()), opts.get('user')),
3525 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3520 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3526 ])
3521 ])
3527 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3522 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3528 for name, data, cond in cols:
3523 for name, data, cond in cols:
3529 field = fieldnamemap.get(name, name)
3524 field = fieldnamemap.get(name, name)
3530 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3525 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3531 if cond and name != lastcol:
3526 if cond and name != lastcol:
3532 fm.plain(sep, label='grep.sep')
3527 fm.plain(sep, label='grep.sep')
3533 if not opts.get('files_with_matches'):
3528 if not opts.get('files_with_matches'):
3534 fm.plain(sep, label='grep.sep')
3529 fm.plain(sep, label='grep.sep')
3535 if not opts.get('text') and binary():
3530 if not opts.get('text') and binary():
3536 fm.plain(_(" Binary file matches"))
3531 fm.plain(_(" Binary file matches"))
3537 else:
3532 else:
3538 displaymatches(fm.nested('texts'), l)
3533 displaymatches(fm.nested('texts'), l)
3539 fm.plain(eol)
3534 fm.plain(eol)
3540 found = True
3535 found = True
3541 if opts.get('files_with_matches'):
3536 if opts.get('files_with_matches'):
3542 break
3537 break
3543 return found
3538 return found
3544
3539
3545 def displaymatches(fm, l):
3540 def displaymatches(fm, l):
3546 p = 0
3541 p = 0
3547 for s, e in l.findpos():
3542 for s, e in l.findpos():
3548 if p < s:
3543 if p < s:
3549 fm.startitem()
3544 fm.startitem()
3550 fm.write('text', '%s', l.line[p:s])
3545 fm.write('text', '%s', l.line[p:s])
3551 fm.data(matched=False)
3546 fm.data(matched=False)
3552 fm.startitem()
3547 fm.startitem()
3553 fm.write('text', '%s', l.line[s:e], label='grep.match')
3548 fm.write('text', '%s', l.line[s:e], label='grep.match')
3554 fm.data(matched=True)
3549 fm.data(matched=True)
3555 p = e
3550 p = e
3556 if p < len(l.line):
3551 if p < len(l.line):
3557 fm.startitem()
3552 fm.startitem()
3558 fm.write('text', '%s', l.line[p:])
3553 fm.write('text', '%s', l.line[p:])
3559 fm.data(matched=False)
3554 fm.data(matched=False)
3560 fm.end()
3555 fm.end()
3561
3556
3562 skip = {}
3557 skip = {}
3563 revfiles = {}
3558 revfiles = {}
3564 matchfn = scmutil.match(repo[None], pats, opts)
3559 matchfn = scmutil.match(repo[None], pats, opts)
3565 found = False
3560 found = False
3566 follow = opts.get('follow')
3561 follow = opts.get('follow')
3567
3562
3568 def prep(ctx, fns):
3563 def prep(ctx, fns):
3569 rev = ctx.rev()
3564 rev = ctx.rev()
3570 pctx = ctx.p1()
3565 pctx = ctx.p1()
3571 parent = pctx.rev()
3566 parent = pctx.rev()
3572 matches.setdefault(rev, {})
3567 matches.setdefault(rev, {})
3573 matches.setdefault(parent, {})
3568 matches.setdefault(parent, {})
3574 files = revfiles.setdefault(rev, [])
3569 files = revfiles.setdefault(rev, [])
3575 for fn in fns:
3570 for fn in fns:
3576 flog = getfile(fn)
3571 flog = getfile(fn)
3577 try:
3572 try:
3578 fnode = ctx.filenode(fn)
3573 fnode = ctx.filenode(fn)
3579 except error.LookupError:
3574 except error.LookupError:
3580 continue
3575 continue
3581
3576
3582 copied = flog.renamed(fnode)
3577 copied = flog.renamed(fnode)
3583 copy = follow and copied and copied[0]
3578 copy = follow and copied and copied[0]
3584 if copy:
3579 if copy:
3585 copies.setdefault(rev, {})[fn] = copy
3580 copies.setdefault(rev, {})[fn] = copy
3586 if fn in skip:
3581 if fn in skip:
3587 if copy:
3582 if copy:
3588 skip[copy] = True
3583 skip[copy] = True
3589 continue
3584 continue
3590 files.append(fn)
3585 files.append(fn)
3591
3586
3592 if fn not in matches[rev]:
3587 if fn not in matches[rev]:
3593 grepbody(fn, rev, flog.read(fnode))
3588 grepbody(fn, rev, flog.read(fnode))
3594
3589
3595 pfn = copy or fn
3590 pfn = copy or fn
3596 if pfn not in matches[parent]:
3591 if pfn not in matches[parent]:
3597 try:
3592 try:
3598 fnode = pctx.filenode(pfn)
3593 fnode = pctx.filenode(pfn)
3599 grepbody(pfn, parent, flog.read(fnode))
3594 grepbody(pfn, parent, flog.read(fnode))
3600 except error.LookupError:
3595 except error.LookupError:
3601 pass
3596 pass
3602
3597
3603 fm = ui.formatter('grep', opts)
3598 fm = ui.formatter('grep', opts)
3604 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3599 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3605 rev = ctx.rev()
3600 rev = ctx.rev()
3606 parent = ctx.p1().rev()
3601 parent = ctx.p1().rev()
3607 for fn in sorted(revfiles.get(rev, [])):
3602 for fn in sorted(revfiles.get(rev, [])):
3608 states = matches[rev][fn]
3603 states = matches[rev][fn]
3609 copy = copies.get(rev, {}).get(fn)
3604 copy = copies.get(rev, {}).get(fn)
3610 if fn in skip:
3605 if fn in skip:
3611 if copy:
3606 if copy:
3612 skip[copy] = True
3607 skip[copy] = True
3613 continue
3608 continue
3614 pstates = matches.get(parent, {}).get(copy or fn, [])
3609 pstates = matches.get(parent, {}).get(copy or fn, [])
3615 if pstates or states:
3610 if pstates or states:
3616 r = display(fm, fn, ctx, pstates, states)
3611 r = display(fm, fn, ctx, pstates, states)
3617 found = found or r
3612 found = found or r
3618 if r and not opts.get('all'):
3613 if r and not opts.get('all'):
3619 skip[fn] = True
3614 skip[fn] = True
3620 if copy:
3615 if copy:
3621 skip[copy] = True
3616 skip[copy] = True
3622 del matches[rev]
3617 del matches[rev]
3623 del revfiles[rev]
3618 del revfiles[rev]
3624 fm.end()
3619 fm.end()
3625
3620
3626 return not found
3621 return not found
3627
3622
3628 @command('heads',
3623 @command('heads',
3629 [('r', 'rev', '',
3624 [('r', 'rev', '',
3630 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3625 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3631 ('t', 'topo', False, _('show topological heads only')),
3626 ('t', 'topo', False, _('show topological heads only')),
3632 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3627 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3633 ('c', 'closed', False, _('show normal and closed branch heads')),
3628 ('c', 'closed', False, _('show normal and closed branch heads')),
3634 ] + templateopts,
3629 ] + templateopts,
3635 _('[-ct] [-r STARTREV] [REV]...'))
3630 _('[-ct] [-r STARTREV] [REV]...'))
3636 def heads(ui, repo, *branchrevs, **opts):
3631 def heads(ui, repo, *branchrevs, **opts):
3637 """show branch heads
3632 """show branch heads
3638
3633
3639 With no arguments, show all open branch heads in the repository.
3634 With no arguments, show all open branch heads in the repository.
3640 Branch heads are changesets that have no descendants on the
3635 Branch heads are changesets that have no descendants on the
3641 same branch. They are where development generally takes place and
3636 same branch. They are where development generally takes place and
3642 are the usual targets for update and merge operations.
3637 are the usual targets for update and merge operations.
3643
3638
3644 If one or more REVs are given, only open branch heads on the
3639 If one or more REVs are given, only open branch heads on the
3645 branches associated with the specified changesets are shown. This
3640 branches associated with the specified changesets are shown. This
3646 means that you can use :hg:`heads .` to see the heads on the
3641 means that you can use :hg:`heads .` to see the heads on the
3647 currently checked-out branch.
3642 currently checked-out branch.
3648
3643
3649 If -c/--closed is specified, also show branch heads marked closed
3644 If -c/--closed is specified, also show branch heads marked closed
3650 (see :hg:`commit --close-branch`).
3645 (see :hg:`commit --close-branch`).
3651
3646
3652 If STARTREV is specified, only those heads that are descendants of
3647 If STARTREV is specified, only those heads that are descendants of
3653 STARTREV will be displayed.
3648 STARTREV will be displayed.
3654
3649
3655 If -t/--topo is specified, named branch mechanics will be ignored and only
3650 If -t/--topo is specified, named branch mechanics will be ignored and only
3656 topological heads (changesets with no children) will be shown.
3651 topological heads (changesets with no children) will be shown.
3657
3652
3658 Returns 0 if matching heads are found, 1 if not.
3653 Returns 0 if matching heads are found, 1 if not.
3659 """
3654 """
3660
3655
3661 start = None
3656 start = None
3662 if 'rev' in opts:
3657 if 'rev' in opts:
3663 start = scmutil.revsingle(repo, opts['rev'], None).node()
3658 start = scmutil.revsingle(repo, opts['rev'], None).node()
3664
3659
3665 if opts.get('topo'):
3660 if opts.get('topo'):
3666 heads = [repo[h] for h in repo.heads(start)]
3661 heads = [repo[h] for h in repo.heads(start)]
3667 else:
3662 else:
3668 heads = []
3663 heads = []
3669 for branch in repo.branchmap():
3664 for branch in repo.branchmap():
3670 heads += repo.branchheads(branch, start, opts.get('closed'))
3665 heads += repo.branchheads(branch, start, opts.get('closed'))
3671 heads = [repo[h] for h in heads]
3666 heads = [repo[h] for h in heads]
3672
3667
3673 if branchrevs:
3668 if branchrevs:
3674 branches = set(repo[br].branch() for br in branchrevs)
3669 branches = set(repo[br].branch() for br in branchrevs)
3675 heads = [h for h in heads if h.branch() in branches]
3670 heads = [h for h in heads if h.branch() in branches]
3676
3671
3677 if opts.get('active') and branchrevs:
3672 if opts.get('active') and branchrevs:
3678 dagheads = repo.heads(start)
3673 dagheads = repo.heads(start)
3679 heads = [h for h in heads if h.node() in dagheads]
3674 heads = [h for h in heads if h.node() in dagheads]
3680
3675
3681 if branchrevs:
3676 if branchrevs:
3682 haveheads = set(h.branch() for h in heads)
3677 haveheads = set(h.branch() for h in heads)
3683 if branches - haveheads:
3678 if branches - haveheads:
3684 headless = ', '.join(b for b in branches - haveheads)
3679 headless = ', '.join(b for b in branches - haveheads)
3685 msg = _('no open branch heads found on branches %s')
3680 msg = _('no open branch heads found on branches %s')
3686 if opts.get('rev'):
3681 if opts.get('rev'):
3687 msg += _(' (started at %s)') % opts['rev']
3682 msg += _(' (started at %s)') % opts['rev']
3688 ui.warn((msg + '\n') % headless)
3683 ui.warn((msg + '\n') % headless)
3689
3684
3690 if not heads:
3685 if not heads:
3691 return 1
3686 return 1
3692
3687
3693 heads = sorted(heads, key=lambda x: -x.rev())
3688 heads = sorted(heads, key=lambda x: -x.rev())
3694 displayer = cmdutil.show_changeset(ui, repo, opts)
3689 displayer = cmdutil.show_changeset(ui, repo, opts)
3695 for ctx in heads:
3690 for ctx in heads:
3696 displayer.show(ctx)
3691 displayer.show(ctx)
3697 displayer.close()
3692 displayer.close()
3698
3693
3699 @command('help',
3694 @command('help',
3700 [('e', 'extension', None, _('show only help for extensions')),
3695 [('e', 'extension', None, _('show only help for extensions')),
3701 ('c', 'command', None, _('show only help for commands')),
3696 ('c', 'command', None, _('show only help for commands')),
3702 ('k', 'keyword', None, _('show topics matching keyword')),
3697 ('k', 'keyword', None, _('show topics matching keyword')),
3703 ('s', 'system', [], _('show help for specific platform(s)')),
3698 ('s', 'system', [], _('show help for specific platform(s)')),
3704 ],
3699 ],
3705 _('[-ecks] [TOPIC]'),
3700 _('[-ecks] [TOPIC]'),
3706 norepo=True)
3701 norepo=True)
3707 def help_(ui, name=None, **opts):
3702 def help_(ui, name=None, **opts):
3708 """show help for a given topic or a help overview
3703 """show help for a given topic or a help overview
3709
3704
3710 With no arguments, print a list of commands with short help messages.
3705 With no arguments, print a list of commands with short help messages.
3711
3706
3712 Given a topic, extension, or command name, print help for that
3707 Given a topic, extension, or command name, print help for that
3713 topic.
3708 topic.
3714
3709
3715 Returns 0 if successful.
3710 Returns 0 if successful.
3716 """
3711 """
3717
3712
3718 textwidth = ui.configint('ui', 'textwidth', 78)
3713 textwidth = ui.configint('ui', 'textwidth', 78)
3719 termwidth = ui.termwidth() - 2
3714 termwidth = ui.termwidth() - 2
3720 if textwidth <= 0 or termwidth < textwidth:
3715 if textwidth <= 0 or termwidth < textwidth:
3721 textwidth = termwidth
3716 textwidth = termwidth
3722
3717
3723 keep = opts.get('system') or []
3718 keep = opts.get('system') or []
3724 if len(keep) == 0:
3719 if len(keep) == 0:
3725 if pycompat.sysplatform.startswith('win'):
3720 if pycompat.sysplatform.startswith('win'):
3726 keep.append('windows')
3721 keep.append('windows')
3727 elif pycompat.sysplatform == 'OpenVMS':
3722 elif pycompat.sysplatform == 'OpenVMS':
3728 keep.append('vms')
3723 keep.append('vms')
3729 elif pycompat.sysplatform == 'plan9':
3724 elif pycompat.sysplatform == 'plan9':
3730 keep.append('plan9')
3725 keep.append('plan9')
3731 else:
3726 else:
3732 keep.append('unix')
3727 keep.append('unix')
3733 keep.append(pycompat.sysplatform.lower())
3728 keep.append(pycompat.sysplatform.lower())
3734 if ui.verbose:
3729 if ui.verbose:
3735 keep.append('verbose')
3730 keep.append('verbose')
3736
3731
3737 fullname = name
3732 fullname = name
3738 section = None
3733 section = None
3739 subtopic = None
3734 subtopic = None
3740 if name and '.' in name:
3735 if name and '.' in name:
3741 name, remaining = name.split('.', 1)
3736 name, remaining = name.split('.', 1)
3742 remaining = encoding.lower(remaining)
3737 remaining = encoding.lower(remaining)
3743 if '.' in remaining:
3738 if '.' in remaining:
3744 subtopic, section = remaining.split('.', 1)
3739 subtopic, section = remaining.split('.', 1)
3745 else:
3740 else:
3746 if name in help.subtopics:
3741 if name in help.subtopics:
3747 subtopic = remaining
3742 subtopic = remaining
3748 else:
3743 else:
3749 section = remaining
3744 section = remaining
3750
3745
3751 text = help.help_(ui, name, subtopic=subtopic, **opts)
3746 text = help.help_(ui, name, subtopic=subtopic, **opts)
3752
3747
3753 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3748 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3754 section=section)
3749 section=section)
3755
3750
3756 # We could have been given a weird ".foo" section without a name
3751 # We could have been given a weird ".foo" section without a name
3757 # to look for, or we could have simply failed to found "foo.bar"
3752 # to look for, or we could have simply failed to found "foo.bar"
3758 # because bar isn't a section of foo
3753 # because bar isn't a section of foo
3759 if section and not (formatted and name):
3754 if section and not (formatted and name):
3760 raise error.Abort(_("help section not found: %s") % fullname)
3755 raise error.Abort(_("help section not found: %s") % fullname)
3761
3756
3762 if 'verbose' in pruned:
3757 if 'verbose' in pruned:
3763 keep.append('omitted')
3758 keep.append('omitted')
3764 else:
3759 else:
3765 keep.append('notomitted')
3760 keep.append('notomitted')
3766 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3761 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3767 section=section)
3762 section=section)
3768 ui.write(formatted)
3763 ui.write(formatted)
3769
3764
3770
3765
3771 @command('identify|id',
3766 @command('identify|id',
3772 [('r', 'rev', '',
3767 [('r', 'rev', '',
3773 _('identify the specified revision'), _('REV')),
3768 _('identify the specified revision'), _('REV')),
3774 ('n', 'num', None, _('show local revision number')),
3769 ('n', 'num', None, _('show local revision number')),
3775 ('i', 'id', None, _('show global revision id')),
3770 ('i', 'id', None, _('show global revision id')),
3776 ('b', 'branch', None, _('show branch')),
3771 ('b', 'branch', None, _('show branch')),
3777 ('t', 'tags', None, _('show tags')),
3772 ('t', 'tags', None, _('show tags')),
3778 ('B', 'bookmarks', None, _('show bookmarks')),
3773 ('B', 'bookmarks', None, _('show bookmarks')),
3779 ] + remoteopts,
3774 ] + remoteopts,
3780 _('[-nibtB] [-r REV] [SOURCE]'),
3775 _('[-nibtB] [-r REV] [SOURCE]'),
3781 optionalrepo=True)
3776 optionalrepo=True)
3782 def identify(ui, repo, source=None, rev=None,
3777 def identify(ui, repo, source=None, rev=None,
3783 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3778 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3784 """identify the working directory or specified revision
3779 """identify the working directory or specified revision
3785
3780
3786 Print a summary identifying the repository state at REV using one or
3781 Print a summary identifying the repository state at REV using one or
3787 two parent hash identifiers, followed by a "+" if the working
3782 two parent hash identifiers, followed by a "+" if the working
3788 directory has uncommitted changes, the branch name (if not default),
3783 directory has uncommitted changes, the branch name (if not default),
3789 a list of tags, and a list of bookmarks.
3784 a list of tags, and a list of bookmarks.
3790
3785
3791 When REV is not given, print a summary of the current state of the
3786 When REV is not given, print a summary of the current state of the
3792 repository.
3787 repository.
3793
3788
3794 Specifying a path to a repository root or Mercurial bundle will
3789 Specifying a path to a repository root or Mercurial bundle will
3795 cause lookup to operate on that repository/bundle.
3790 cause lookup to operate on that repository/bundle.
3796
3791
3797 .. container:: verbose
3792 .. container:: verbose
3798
3793
3799 Examples:
3794 Examples:
3800
3795
3801 - generate a build identifier for the working directory::
3796 - generate a build identifier for the working directory::
3802
3797
3803 hg id --id > build-id.dat
3798 hg id --id > build-id.dat
3804
3799
3805 - find the revision corresponding to a tag::
3800 - find the revision corresponding to a tag::
3806
3801
3807 hg id -n -r 1.3
3802 hg id -n -r 1.3
3808
3803
3809 - check the most recent revision of a remote repository::
3804 - check the most recent revision of a remote repository::
3810
3805
3811 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3806 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3812
3807
3813 See :hg:`log` for generating more information about specific revisions,
3808 See :hg:`log` for generating more information about specific revisions,
3814 including full hash identifiers.
3809 including full hash identifiers.
3815
3810
3816 Returns 0 if successful.
3811 Returns 0 if successful.
3817 """
3812 """
3818
3813
3819 if not repo and not source:
3814 if not repo and not source:
3820 raise error.Abort(_("there is no Mercurial repository here "
3815 raise error.Abort(_("there is no Mercurial repository here "
3821 "(.hg not found)"))
3816 "(.hg not found)"))
3822
3817
3823 if ui.debugflag:
3818 if ui.debugflag:
3824 hexfunc = hex
3819 hexfunc = hex
3825 else:
3820 else:
3826 hexfunc = short
3821 hexfunc = short
3827 default = not (num or id or branch or tags or bookmarks)
3822 default = not (num or id or branch or tags or bookmarks)
3828 output = []
3823 output = []
3829 revs = []
3824 revs = []
3830
3825
3831 if source:
3826 if source:
3832 source, branches = hg.parseurl(ui.expandpath(source))
3827 source, branches = hg.parseurl(ui.expandpath(source))
3833 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3828 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3834 repo = peer.local()
3829 repo = peer.local()
3835 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3830 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3836
3831
3837 if not repo:
3832 if not repo:
3838 if num or branch or tags:
3833 if num or branch or tags:
3839 raise error.Abort(
3834 raise error.Abort(
3840 _("can't query remote revision number, branch, or tags"))
3835 _("can't query remote revision number, branch, or tags"))
3841 if not rev and revs:
3836 if not rev and revs:
3842 rev = revs[0]
3837 rev = revs[0]
3843 if not rev:
3838 if not rev:
3844 rev = "tip"
3839 rev = "tip"
3845
3840
3846 remoterev = peer.lookup(rev)
3841 remoterev = peer.lookup(rev)
3847 if default or id:
3842 if default or id:
3848 output = [hexfunc(remoterev)]
3843 output = [hexfunc(remoterev)]
3849
3844
3850 def getbms():
3845 def getbms():
3851 bms = []
3846 bms = []
3852
3847
3853 if 'bookmarks' in peer.listkeys('namespaces'):
3848 if 'bookmarks' in peer.listkeys('namespaces'):
3854 hexremoterev = hex(remoterev)
3849 hexremoterev = hex(remoterev)
3855 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3850 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3856 if bmr == hexremoterev]
3851 if bmr == hexremoterev]
3857
3852
3858 return sorted(bms)
3853 return sorted(bms)
3859
3854
3860 if bookmarks:
3855 if bookmarks:
3861 output.extend(getbms())
3856 output.extend(getbms())
3862 elif default and not ui.quiet:
3857 elif default and not ui.quiet:
3863 # multiple bookmarks for a single parent separated by '/'
3858 # multiple bookmarks for a single parent separated by '/'
3864 bm = '/'.join(getbms())
3859 bm = '/'.join(getbms())
3865 if bm:
3860 if bm:
3866 output.append(bm)
3861 output.append(bm)
3867 else:
3862 else:
3868 ctx = scmutil.revsingle(repo, rev, None)
3863 ctx = scmutil.revsingle(repo, rev, None)
3869
3864
3870 if ctx.rev() is None:
3865 if ctx.rev() is None:
3871 ctx = repo[None]
3866 ctx = repo[None]
3872 parents = ctx.parents()
3867 parents = ctx.parents()
3873 taglist = []
3868 taglist = []
3874 for p in parents:
3869 for p in parents:
3875 taglist.extend(p.tags())
3870 taglist.extend(p.tags())
3876
3871
3877 changed = ""
3872 changed = ""
3878 if default or id or num:
3873 if default or id or num:
3879 if (any(repo.status())
3874 if (any(repo.status())
3880 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3875 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3881 changed = '+'
3876 changed = '+'
3882 if default or id:
3877 if default or id:
3883 output = ["%s%s" %
3878 output = ["%s%s" %
3884 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3879 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3885 if num:
3880 if num:
3886 output.append("%s%s" %
3881 output.append("%s%s" %
3887 ('+'.join([str(p.rev()) for p in parents]), changed))
3882 ('+'.join([str(p.rev()) for p in parents]), changed))
3888 else:
3883 else:
3889 if default or id:
3884 if default or id:
3890 output = [hexfunc(ctx.node())]
3885 output = [hexfunc(ctx.node())]
3891 if num:
3886 if num:
3892 output.append(str(ctx.rev()))
3887 output.append(str(ctx.rev()))
3893 taglist = ctx.tags()
3888 taglist = ctx.tags()
3894
3889
3895 if default and not ui.quiet:
3890 if default and not ui.quiet:
3896 b = ctx.branch()
3891 b = ctx.branch()
3897 if b != 'default':
3892 if b != 'default':
3898 output.append("(%s)" % b)
3893 output.append("(%s)" % b)
3899
3894
3900 # multiple tags for a single parent separated by '/'
3895 # multiple tags for a single parent separated by '/'
3901 t = '/'.join(taglist)
3896 t = '/'.join(taglist)
3902 if t:
3897 if t:
3903 output.append(t)
3898 output.append(t)
3904
3899
3905 # multiple bookmarks for a single parent separated by '/'
3900 # multiple bookmarks for a single parent separated by '/'
3906 bm = '/'.join(ctx.bookmarks())
3901 bm = '/'.join(ctx.bookmarks())
3907 if bm:
3902 if bm:
3908 output.append(bm)
3903 output.append(bm)
3909 else:
3904 else:
3910 if branch:
3905 if branch:
3911 output.append(ctx.branch())
3906 output.append(ctx.branch())
3912
3907
3913 if tags:
3908 if tags:
3914 output.extend(taglist)
3909 output.extend(taglist)
3915
3910
3916 if bookmarks:
3911 if bookmarks:
3917 output.extend(ctx.bookmarks())
3912 output.extend(ctx.bookmarks())
3918
3913
3919 ui.write("%s\n" % ' '.join(output))
3914 ui.write("%s\n" % ' '.join(output))
3920
3915
3921 @command('import|patch',
3916 @command('import|patch',
3922 [('p', 'strip', 1,
3917 [('p', 'strip', 1,
3923 _('directory strip option for patch. This has the same '
3918 _('directory strip option for patch. This has the same '
3924 'meaning as the corresponding patch option'), _('NUM')),
3919 'meaning as the corresponding patch option'), _('NUM')),
3925 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3920 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3926 ('e', 'edit', False, _('invoke editor on commit messages')),
3921 ('e', 'edit', False, _('invoke editor on commit messages')),
3927 ('f', 'force', None,
3922 ('f', 'force', None,
3928 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3923 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3929 ('', 'no-commit', None,
3924 ('', 'no-commit', None,
3930 _("don't commit, just update the working directory")),
3925 _("don't commit, just update the working directory")),
3931 ('', 'bypass', None,
3926 ('', 'bypass', None,
3932 _("apply patch without touching the working directory")),
3927 _("apply patch without touching the working directory")),
3933 ('', 'partial', None,
3928 ('', 'partial', None,
3934 _('commit even if some hunks fail')),
3929 _('commit even if some hunks fail')),
3935 ('', 'exact', None,
3930 ('', 'exact', None,
3936 _('abort if patch would apply lossily')),
3931 _('abort if patch would apply lossily')),
3937 ('', 'prefix', '',
3932 ('', 'prefix', '',
3938 _('apply patch to subdirectory'), _('DIR')),
3933 _('apply patch to subdirectory'), _('DIR')),
3939 ('', 'import-branch', None,
3934 ('', 'import-branch', None,
3940 _('use any branch information in patch (implied by --exact)'))] +
3935 _('use any branch information in patch (implied by --exact)'))] +
3941 commitopts + commitopts2 + similarityopts,
3936 commitopts + commitopts2 + similarityopts,
3942 _('[OPTION]... PATCH...'))
3937 _('[OPTION]... PATCH...'))
3943 def import_(ui, repo, patch1=None, *patches, **opts):
3938 def import_(ui, repo, patch1=None, *patches, **opts):
3944 """import an ordered set of patches
3939 """import an ordered set of patches
3945
3940
3946 Import a list of patches and commit them individually (unless
3941 Import a list of patches and commit them individually (unless
3947 --no-commit is specified).
3942 --no-commit is specified).
3948
3943
3949 To read a patch from standard input (stdin), use "-" as the patch
3944 To read a patch from standard input (stdin), use "-" as the patch
3950 name. If a URL is specified, the patch will be downloaded from
3945 name. If a URL is specified, the patch will be downloaded from
3951 there.
3946 there.
3952
3947
3953 Import first applies changes to the working directory (unless
3948 Import first applies changes to the working directory (unless
3954 --bypass is specified), import will abort if there are outstanding
3949 --bypass is specified), import will abort if there are outstanding
3955 changes.
3950 changes.
3956
3951
3957 Use --bypass to apply and commit patches directly to the
3952 Use --bypass to apply and commit patches directly to the
3958 repository, without affecting the working directory. Without
3953 repository, without affecting the working directory. Without
3959 --exact, patches will be applied on top of the working directory
3954 --exact, patches will be applied on top of the working directory
3960 parent revision.
3955 parent revision.
3961
3956
3962 You can import a patch straight from a mail message. Even patches
3957 You can import a patch straight from a mail message. Even patches
3963 as attachments work (to use the body part, it must have type
3958 as attachments work (to use the body part, it must have type
3964 text/plain or text/x-patch). From and Subject headers of email
3959 text/plain or text/x-patch). From and Subject headers of email
3965 message are used as default committer and commit message. All
3960 message are used as default committer and commit message. All
3966 text/plain body parts before first diff are added to the commit
3961 text/plain body parts before first diff are added to the commit
3967 message.
3962 message.
3968
3963
3969 If the imported patch was generated by :hg:`export`, user and
3964 If the imported patch was generated by :hg:`export`, user and
3970 description from patch override values from message headers and
3965 description from patch override values from message headers and
3971 body. Values given on command line with -m/--message and -u/--user
3966 body. Values given on command line with -m/--message and -u/--user
3972 override these.
3967 override these.
3973
3968
3974 If --exact is specified, import will set the working directory to
3969 If --exact is specified, import will set the working directory to
3975 the parent of each patch before applying it, and will abort if the
3970 the parent of each patch before applying it, and will abort if the
3976 resulting changeset has a different ID than the one recorded in
3971 resulting changeset has a different ID than the one recorded in
3977 the patch. This will guard against various ways that portable
3972 the patch. This will guard against various ways that portable
3978 patch formats and mail systems might fail to transfer Mercurial
3973 patch formats and mail systems might fail to transfer Mercurial
3979 data or metadata. See :hg:`bundle` for lossless transmission.
3974 data or metadata. See :hg:`bundle` for lossless transmission.
3980
3975
3981 Use --partial to ensure a changeset will be created from the patch
3976 Use --partial to ensure a changeset will be created from the patch
3982 even if some hunks fail to apply. Hunks that fail to apply will be
3977 even if some hunks fail to apply. Hunks that fail to apply will be
3983 written to a <target-file>.rej file. Conflicts can then be resolved
3978 written to a <target-file>.rej file. Conflicts can then be resolved
3984 by hand before :hg:`commit --amend` is run to update the created
3979 by hand before :hg:`commit --amend` is run to update the created
3985 changeset. This flag exists to let people import patches that
3980 changeset. This flag exists to let people import patches that
3986 partially apply without losing the associated metadata (author,
3981 partially apply without losing the associated metadata (author,
3987 date, description, ...).
3982 date, description, ...).
3988
3983
3989 .. note::
3984 .. note::
3990
3985
3991 When no hunks apply cleanly, :hg:`import --partial` will create
3986 When no hunks apply cleanly, :hg:`import --partial` will create
3992 an empty changeset, importing only the patch metadata.
3987 an empty changeset, importing only the patch metadata.
3993
3988
3994 With -s/--similarity, hg will attempt to discover renames and
3989 With -s/--similarity, hg will attempt to discover renames and
3995 copies in the patch in the same way as :hg:`addremove`.
3990 copies in the patch in the same way as :hg:`addremove`.
3996
3991
3997 It is possible to use external patch programs to perform the patch
3992 It is possible to use external patch programs to perform the patch
3998 by setting the ``ui.patch`` configuration option. For the default
3993 by setting the ``ui.patch`` configuration option. For the default
3999 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3994 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4000 See :hg:`help config` for more information about configuration
3995 See :hg:`help config` for more information about configuration
4001 files and how to use these options.
3996 files and how to use these options.
4002
3997
4003 See :hg:`help dates` for a list of formats valid for -d/--date.
3998 See :hg:`help dates` for a list of formats valid for -d/--date.
4004
3999
4005 .. container:: verbose
4000 .. container:: verbose
4006
4001
4007 Examples:
4002 Examples:
4008
4003
4009 - import a traditional patch from a website and detect renames::
4004 - import a traditional patch from a website and detect renames::
4010
4005
4011 hg import -s 80 http://example.com/bugfix.patch
4006 hg import -s 80 http://example.com/bugfix.patch
4012
4007
4013 - import a changeset from an hgweb server::
4008 - import a changeset from an hgweb server::
4014
4009
4015 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4010 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4016
4011
4017 - import all the patches in an Unix-style mbox::
4012 - import all the patches in an Unix-style mbox::
4018
4013
4019 hg import incoming-patches.mbox
4014 hg import incoming-patches.mbox
4020
4015
4021 - import patches from stdin::
4016 - import patches from stdin::
4022
4017
4023 hg import -
4018 hg import -
4024
4019
4025 - attempt to exactly restore an exported changeset (not always
4020 - attempt to exactly restore an exported changeset (not always
4026 possible)::
4021 possible)::
4027
4022
4028 hg import --exact proposed-fix.patch
4023 hg import --exact proposed-fix.patch
4029
4024
4030 - use an external tool to apply a patch which is too fuzzy for
4025 - use an external tool to apply a patch which is too fuzzy for
4031 the default internal tool.
4026 the default internal tool.
4032
4027
4033 hg import --config ui.patch="patch --merge" fuzzy.patch
4028 hg import --config ui.patch="patch --merge" fuzzy.patch
4034
4029
4035 - change the default fuzzing from 2 to a less strict 7
4030 - change the default fuzzing from 2 to a less strict 7
4036
4031
4037 hg import --config ui.fuzz=7 fuzz.patch
4032 hg import --config ui.fuzz=7 fuzz.patch
4038
4033
4039 Returns 0 on success, 1 on partial success (see --partial).
4034 Returns 0 on success, 1 on partial success (see --partial).
4040 """
4035 """
4041
4036
4042 if not patch1:
4037 if not patch1:
4043 raise error.Abort(_('need at least one patch to import'))
4038 raise error.Abort(_('need at least one patch to import'))
4044
4039
4045 patches = (patch1,) + patches
4040 patches = (patch1,) + patches
4046
4041
4047 date = opts.get('date')
4042 date = opts.get('date')
4048 if date:
4043 if date:
4049 opts['date'] = util.parsedate(date)
4044 opts['date'] = util.parsedate(date)
4050
4045
4051 exact = opts.get('exact')
4046 exact = opts.get('exact')
4052 update = not opts.get('bypass')
4047 update = not opts.get('bypass')
4053 if not update and opts.get('no_commit'):
4048 if not update and opts.get('no_commit'):
4054 raise error.Abort(_('cannot use --no-commit with --bypass'))
4049 raise error.Abort(_('cannot use --no-commit with --bypass'))
4055 try:
4050 try:
4056 sim = float(opts.get('similarity') or 0)
4051 sim = float(opts.get('similarity') or 0)
4057 except ValueError:
4052 except ValueError:
4058 raise error.Abort(_('similarity must be a number'))
4053 raise error.Abort(_('similarity must be a number'))
4059 if sim < 0 or sim > 100:
4054 if sim < 0 or sim > 100:
4060 raise error.Abort(_('similarity must be between 0 and 100'))
4055 raise error.Abort(_('similarity must be between 0 and 100'))
4061 if sim and not update:
4056 if sim and not update:
4062 raise error.Abort(_('cannot use --similarity with --bypass'))
4057 raise error.Abort(_('cannot use --similarity with --bypass'))
4063 if exact:
4058 if exact:
4064 if opts.get('edit'):
4059 if opts.get('edit'):
4065 raise error.Abort(_('cannot use --exact with --edit'))
4060 raise error.Abort(_('cannot use --exact with --edit'))
4066 if opts.get('prefix'):
4061 if opts.get('prefix'):
4067 raise error.Abort(_('cannot use --exact with --prefix'))
4062 raise error.Abort(_('cannot use --exact with --prefix'))
4068
4063
4069 base = opts["base"]
4064 base = opts["base"]
4070 wlock = dsguard = lock = tr = None
4065 wlock = dsguard = lock = tr = None
4071 msgs = []
4066 msgs = []
4072 ret = 0
4067 ret = 0
4073
4068
4074
4069
4075 try:
4070 try:
4076 wlock = repo.wlock()
4071 wlock = repo.wlock()
4077
4072
4078 if update:
4073 if update:
4079 cmdutil.checkunfinished(repo)
4074 cmdutil.checkunfinished(repo)
4080 if (exact or not opts.get('force')):
4075 if (exact or not opts.get('force')):
4081 cmdutil.bailifchanged(repo)
4076 cmdutil.bailifchanged(repo)
4082
4077
4083 if not opts.get('no_commit'):
4078 if not opts.get('no_commit'):
4084 lock = repo.lock()
4079 lock = repo.lock()
4085 tr = repo.transaction('import')
4080 tr = repo.transaction('import')
4086 else:
4081 else:
4087 dsguard = dirstateguard.dirstateguard(repo, 'import')
4082 dsguard = dirstateguard.dirstateguard(repo, 'import')
4088 parents = repo[None].parents()
4083 parents = repo[None].parents()
4089 for patchurl in patches:
4084 for patchurl in patches:
4090 if patchurl == '-':
4085 if patchurl == '-':
4091 ui.status(_('applying patch from stdin\n'))
4086 ui.status(_('applying patch from stdin\n'))
4092 patchfile = ui.fin
4087 patchfile = ui.fin
4093 patchurl = 'stdin' # for error message
4088 patchurl = 'stdin' # for error message
4094 else:
4089 else:
4095 patchurl = os.path.join(base, patchurl)
4090 patchurl = os.path.join(base, patchurl)
4096 ui.status(_('applying %s\n') % patchurl)
4091 ui.status(_('applying %s\n') % patchurl)
4097 patchfile = hg.openpath(ui, patchurl)
4092 patchfile = hg.openpath(ui, patchurl)
4098
4093
4099 haspatch = False
4094 haspatch = False
4100 for hunk in patch.split(patchfile):
4095 for hunk in patch.split(patchfile):
4101 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4096 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4102 parents, opts,
4097 parents, opts,
4103 msgs, hg.clean)
4098 msgs, hg.clean)
4104 if msg:
4099 if msg:
4105 haspatch = True
4100 haspatch = True
4106 ui.note(msg + '\n')
4101 ui.note(msg + '\n')
4107 if update or exact:
4102 if update or exact:
4108 parents = repo[None].parents()
4103 parents = repo[None].parents()
4109 else:
4104 else:
4110 parents = [repo[node]]
4105 parents = [repo[node]]
4111 if rej:
4106 if rej:
4112 ui.write_err(_("patch applied partially\n"))
4107 ui.write_err(_("patch applied partially\n"))
4113 ui.write_err(_("(fix the .rej files and run "
4108 ui.write_err(_("(fix the .rej files and run "
4114 "`hg commit --amend`)\n"))
4109 "`hg commit --amend`)\n"))
4115 ret = 1
4110 ret = 1
4116 break
4111 break
4117
4112
4118 if not haspatch:
4113 if not haspatch:
4119 raise error.Abort(_('%s: no diffs found') % patchurl)
4114 raise error.Abort(_('%s: no diffs found') % patchurl)
4120
4115
4121 if tr:
4116 if tr:
4122 tr.close()
4117 tr.close()
4123 if msgs:
4118 if msgs:
4124 repo.savecommitmessage('\n* * *\n'.join(msgs))
4119 repo.savecommitmessage('\n* * *\n'.join(msgs))
4125 if dsguard:
4120 if dsguard:
4126 dsguard.close()
4121 dsguard.close()
4127 return ret
4122 return ret
4128 finally:
4123 finally:
4129 if tr:
4124 if tr:
4130 tr.release()
4125 tr.release()
4131 release(lock, dsguard, wlock)
4126 release(lock, dsguard, wlock)
4132
4127
4133 @command('incoming|in',
4128 @command('incoming|in',
4134 [('f', 'force', None,
4129 [('f', 'force', None,
4135 _('run even if remote repository is unrelated')),
4130 _('run even if remote repository is unrelated')),
4136 ('n', 'newest-first', None, _('show newest record first')),
4131 ('n', 'newest-first', None, _('show newest record first')),
4137 ('', 'bundle', '',
4132 ('', 'bundle', '',
4138 _('file to store the bundles into'), _('FILE')),
4133 _('file to store the bundles into'), _('FILE')),
4139 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4134 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4140 ('B', 'bookmarks', False, _("compare bookmarks")),
4135 ('B', 'bookmarks', False, _("compare bookmarks")),
4141 ('b', 'branch', [],
4136 ('b', 'branch', [],
4142 _('a specific branch you would like to pull'), _('BRANCH')),
4137 _('a specific branch you would like to pull'), _('BRANCH')),
4143 ] + logopts + remoteopts + subrepoopts,
4138 ] + logopts + remoteopts + subrepoopts,
4144 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4139 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4145 def incoming(ui, repo, source="default", **opts):
4140 def incoming(ui, repo, source="default", **opts):
4146 """show new changesets found in source
4141 """show new changesets found in source
4147
4142
4148 Show new changesets found in the specified path/URL or the default
4143 Show new changesets found in the specified path/URL or the default
4149 pull location. These are the changesets that would have been pulled
4144 pull location. These are the changesets that would have been pulled
4150 if a pull at the time you issued this command.
4145 if a pull at the time you issued this command.
4151
4146
4152 See pull for valid source format details.
4147 See pull for valid source format details.
4153
4148
4154 .. container:: verbose
4149 .. container:: verbose
4155
4150
4156 With -B/--bookmarks, the result of bookmark comparison between
4151 With -B/--bookmarks, the result of bookmark comparison between
4157 local and remote repositories is displayed. With -v/--verbose,
4152 local and remote repositories is displayed. With -v/--verbose,
4158 status is also displayed for each bookmark like below::
4153 status is also displayed for each bookmark like below::
4159
4154
4160 BM1 01234567890a added
4155 BM1 01234567890a added
4161 BM2 1234567890ab advanced
4156 BM2 1234567890ab advanced
4162 BM3 234567890abc diverged
4157 BM3 234567890abc diverged
4163 BM4 34567890abcd changed
4158 BM4 34567890abcd changed
4164
4159
4165 The action taken locally when pulling depends on the
4160 The action taken locally when pulling depends on the
4166 status of each bookmark:
4161 status of each bookmark:
4167
4162
4168 :``added``: pull will create it
4163 :``added``: pull will create it
4169 :``advanced``: pull will update it
4164 :``advanced``: pull will update it
4170 :``diverged``: pull will create a divergent bookmark
4165 :``diverged``: pull will create a divergent bookmark
4171 :``changed``: result depends on remote changesets
4166 :``changed``: result depends on remote changesets
4172
4167
4173 From the point of view of pulling behavior, bookmark
4168 From the point of view of pulling behavior, bookmark
4174 existing only in the remote repository are treated as ``added``,
4169 existing only in the remote repository are treated as ``added``,
4175 even if it is in fact locally deleted.
4170 even if it is in fact locally deleted.
4176
4171
4177 .. container:: verbose
4172 .. container:: verbose
4178
4173
4179 For remote repository, using --bundle avoids downloading the
4174 For remote repository, using --bundle avoids downloading the
4180 changesets twice if the incoming is followed by a pull.
4175 changesets twice if the incoming is followed by a pull.
4181
4176
4182 Examples:
4177 Examples:
4183
4178
4184 - show incoming changes with patches and full description::
4179 - show incoming changes with patches and full description::
4185
4180
4186 hg incoming -vp
4181 hg incoming -vp
4187
4182
4188 - show incoming changes excluding merges, store a bundle::
4183 - show incoming changes excluding merges, store a bundle::
4189
4184
4190 hg in -vpM --bundle incoming.hg
4185 hg in -vpM --bundle incoming.hg
4191 hg pull incoming.hg
4186 hg pull incoming.hg
4192
4187
4193 - briefly list changes inside a bundle::
4188 - briefly list changes inside a bundle::
4194
4189
4195 hg in changes.hg -T "{desc|firstline}\\n"
4190 hg in changes.hg -T "{desc|firstline}\\n"
4196
4191
4197 Returns 0 if there are incoming changes, 1 otherwise.
4192 Returns 0 if there are incoming changes, 1 otherwise.
4198 """
4193 """
4199 if opts.get('graph'):
4194 if opts.get('graph'):
4200 cmdutil.checkunsupportedgraphflags([], opts)
4195 cmdutil.checkunsupportedgraphflags([], opts)
4201 def display(other, chlist, displayer):
4196 def display(other, chlist, displayer):
4202 revdag = cmdutil.graphrevs(other, chlist, opts)
4197 revdag = cmdutil.graphrevs(other, chlist, opts)
4203 cmdutil.displaygraph(ui, repo, revdag, displayer,
4198 cmdutil.displaygraph(ui, repo, revdag, displayer,
4204 graphmod.asciiedges)
4199 graphmod.asciiedges)
4205
4200
4206 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4201 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4207 return 0
4202 return 0
4208
4203
4209 if opts.get('bundle') and opts.get('subrepos'):
4204 if opts.get('bundle') and opts.get('subrepos'):
4210 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4205 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4211
4206
4212 if opts.get('bookmarks'):
4207 if opts.get('bookmarks'):
4213 source, branches = hg.parseurl(ui.expandpath(source),
4208 source, branches = hg.parseurl(ui.expandpath(source),
4214 opts.get('branch'))
4209 opts.get('branch'))
4215 other = hg.peer(repo, opts, source)
4210 other = hg.peer(repo, opts, source)
4216 if 'bookmarks' not in other.listkeys('namespaces'):
4211 if 'bookmarks' not in other.listkeys('namespaces'):
4217 ui.warn(_("remote doesn't support bookmarks\n"))
4212 ui.warn(_("remote doesn't support bookmarks\n"))
4218 return 0
4213 return 0
4219 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4214 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4220 return bookmarks.incoming(ui, repo, other)
4215 return bookmarks.incoming(ui, repo, other)
4221
4216
4222 repo._subtoppath = ui.expandpath(source)
4217 repo._subtoppath = ui.expandpath(source)
4223 try:
4218 try:
4224 return hg.incoming(ui, repo, source, opts)
4219 return hg.incoming(ui, repo, source, opts)
4225 finally:
4220 finally:
4226 del repo._subtoppath
4221 del repo._subtoppath
4227
4222
4228
4223
4229 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4224 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4230 norepo=True)
4225 norepo=True)
4231 def init(ui, dest=".", **opts):
4226 def init(ui, dest=".", **opts):
4232 """create a new repository in the given directory
4227 """create a new repository in the given directory
4233
4228
4234 Initialize a new repository in the given directory. If the given
4229 Initialize a new repository in the given directory. If the given
4235 directory does not exist, it will be created.
4230 directory does not exist, it will be created.
4236
4231
4237 If no directory is given, the current directory is used.
4232 If no directory is given, the current directory is used.
4238
4233
4239 It is possible to specify an ``ssh://`` URL as the destination.
4234 It is possible to specify an ``ssh://`` URL as the destination.
4240 See :hg:`help urls` for more information.
4235 See :hg:`help urls` for more information.
4241
4236
4242 Returns 0 on success.
4237 Returns 0 on success.
4243 """
4238 """
4244 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4239 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4245
4240
4246 @command('locate',
4241 @command('locate',
4247 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4242 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4248 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4243 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4249 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4244 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4250 ] + walkopts,
4245 ] + walkopts,
4251 _('[OPTION]... [PATTERN]...'))
4246 _('[OPTION]... [PATTERN]...'))
4252 def locate(ui, repo, *pats, **opts):
4247 def locate(ui, repo, *pats, **opts):
4253 """locate files matching specific patterns (DEPRECATED)
4248 """locate files matching specific patterns (DEPRECATED)
4254
4249
4255 Print files under Mercurial control in the working directory whose
4250 Print files under Mercurial control in the working directory whose
4256 names match the given patterns.
4251 names match the given patterns.
4257
4252
4258 By default, this command searches all directories in the working
4253 By default, this command searches all directories in the working
4259 directory. To search just the current directory and its
4254 directory. To search just the current directory and its
4260 subdirectories, use "--include .".
4255 subdirectories, use "--include .".
4261
4256
4262 If no patterns are given to match, this command prints the names
4257 If no patterns are given to match, this command prints the names
4263 of all files under Mercurial control in the working directory.
4258 of all files under Mercurial control in the working directory.
4264
4259
4265 If you want to feed the output of this command into the "xargs"
4260 If you want to feed the output of this command into the "xargs"
4266 command, use the -0 option to both this command and "xargs". This
4261 command, use the -0 option to both this command and "xargs". This
4267 will avoid the problem of "xargs" treating single filenames that
4262 will avoid the problem of "xargs" treating single filenames that
4268 contain whitespace as multiple filenames.
4263 contain whitespace as multiple filenames.
4269
4264
4270 See :hg:`help files` for a more versatile command.
4265 See :hg:`help files` for a more versatile command.
4271
4266
4272 Returns 0 if a match is found, 1 otherwise.
4267 Returns 0 if a match is found, 1 otherwise.
4273 """
4268 """
4274 if opts.get('print0'):
4269 if opts.get('print0'):
4275 end = '\0'
4270 end = '\0'
4276 else:
4271 else:
4277 end = '\n'
4272 end = '\n'
4278 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4273 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4279
4274
4280 ret = 1
4275 ret = 1
4281 ctx = repo[rev]
4276 ctx = repo[rev]
4282 m = scmutil.match(ctx, pats, opts, default='relglob',
4277 m = scmutil.match(ctx, pats, opts, default='relglob',
4283 badfn=lambda x, y: False)
4278 badfn=lambda x, y: False)
4284
4279
4285 for abs in ctx.matches(m):
4280 for abs in ctx.matches(m):
4286 if opts.get('fullpath'):
4281 if opts.get('fullpath'):
4287 ui.write(repo.wjoin(abs), end)
4282 ui.write(repo.wjoin(abs), end)
4288 else:
4283 else:
4289 ui.write(((pats and m.rel(abs)) or abs), end)
4284 ui.write(((pats and m.rel(abs)) or abs), end)
4290 ret = 0
4285 ret = 0
4291
4286
4292 return ret
4287 return ret
4293
4288
4294 @command('^log|history',
4289 @command('^log|history',
4295 [('f', 'follow', None,
4290 [('f', 'follow', None,
4296 _('follow changeset history, or file history across copies and renames')),
4291 _('follow changeset history, or file history across copies and renames')),
4297 ('', 'follow-first', None,
4292 ('', 'follow-first', None,
4298 _('only follow the first parent of merge changesets (DEPRECATED)')),
4293 _('only follow the first parent of merge changesets (DEPRECATED)')),
4299 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4294 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4300 ('C', 'copies', None, _('show copied files')),
4295 ('C', 'copies', None, _('show copied files')),
4301 ('k', 'keyword', [],
4296 ('k', 'keyword', [],
4302 _('do case-insensitive search for a given text'), _('TEXT')),
4297 _('do case-insensitive search for a given text'), _('TEXT')),
4303 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4298 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4304 ('', 'removed', None, _('include revisions where files were removed')),
4299 ('', 'removed', None, _('include revisions where files were removed')),
4305 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4300 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4306 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4301 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4307 ('', 'only-branch', [],
4302 ('', 'only-branch', [],
4308 _('show only changesets within the given named branch (DEPRECATED)'),
4303 _('show only changesets within the given named branch (DEPRECATED)'),
4309 _('BRANCH')),
4304 _('BRANCH')),
4310 ('b', 'branch', [],
4305 ('b', 'branch', [],
4311 _('show changesets within the given named branch'), _('BRANCH')),
4306 _('show changesets within the given named branch'), _('BRANCH')),
4312 ('P', 'prune', [],
4307 ('P', 'prune', [],
4313 _('do not display revision or any of its ancestors'), _('REV')),
4308 _('do not display revision or any of its ancestors'), _('REV')),
4314 ] + logopts + walkopts,
4309 ] + logopts + walkopts,
4315 _('[OPTION]... [FILE]'),
4310 _('[OPTION]... [FILE]'),
4316 inferrepo=True)
4311 inferrepo=True)
4317 def log(ui, repo, *pats, **opts):
4312 def log(ui, repo, *pats, **opts):
4318 """show revision history of entire repository or files
4313 """show revision history of entire repository or files
4319
4314
4320 Print the revision history of the specified files or the entire
4315 Print the revision history of the specified files or the entire
4321 project.
4316 project.
4322
4317
4323 If no revision range is specified, the default is ``tip:0`` unless
4318 If no revision range is specified, the default is ``tip:0`` unless
4324 --follow is set, in which case the working directory parent is
4319 --follow is set, in which case the working directory parent is
4325 used as the starting revision.
4320 used as the starting revision.
4326
4321
4327 File history is shown without following rename or copy history of
4322 File history is shown without following rename or copy history of
4328 files. Use -f/--follow with a filename to follow history across
4323 files. Use -f/--follow with a filename to follow history across
4329 renames and copies. --follow without a filename will only show
4324 renames and copies. --follow without a filename will only show
4330 ancestors or descendants of the starting revision.
4325 ancestors or descendants of the starting revision.
4331
4326
4332 By default this command prints revision number and changeset id,
4327 By default this command prints revision number and changeset id,
4333 tags, non-trivial parents, user, date and time, and a summary for
4328 tags, non-trivial parents, user, date and time, and a summary for
4334 each commit. When the -v/--verbose switch is used, the list of
4329 each commit. When the -v/--verbose switch is used, the list of
4335 changed files and full commit message are shown.
4330 changed files and full commit message are shown.
4336
4331
4337 With --graph the revisions are shown as an ASCII art DAG with the most
4332 With --graph the revisions are shown as an ASCII art DAG with the most
4338 recent changeset at the top.
4333 recent changeset at the top.
4339 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4334 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4340 and '+' represents a fork where the changeset from the lines below is a
4335 and '+' represents a fork where the changeset from the lines below is a
4341 parent of the 'o' merge on the same line.
4336 parent of the 'o' merge on the same line.
4342
4337
4343 .. note::
4338 .. note::
4344
4339
4345 :hg:`log --patch` may generate unexpected diff output for merge
4340 :hg:`log --patch` may generate unexpected diff output for merge
4346 changesets, as it will only compare the merge changeset against
4341 changesets, as it will only compare the merge changeset against
4347 its first parent. Also, only files different from BOTH parents
4342 its first parent. Also, only files different from BOTH parents
4348 will appear in files:.
4343 will appear in files:.
4349
4344
4350 .. note::
4345 .. note::
4351
4346
4352 For performance reasons, :hg:`log FILE` may omit duplicate changes
4347 For performance reasons, :hg:`log FILE` may omit duplicate changes
4353 made on branches and will not show removals or mode changes. To
4348 made on branches and will not show removals or mode changes. To
4354 see all such changes, use the --removed switch.
4349 see all such changes, use the --removed switch.
4355
4350
4356 .. container:: verbose
4351 .. container:: verbose
4357
4352
4358 Some examples:
4353 Some examples:
4359
4354
4360 - changesets with full descriptions and file lists::
4355 - changesets with full descriptions and file lists::
4361
4356
4362 hg log -v
4357 hg log -v
4363
4358
4364 - changesets ancestral to the working directory::
4359 - changesets ancestral to the working directory::
4365
4360
4366 hg log -f
4361 hg log -f
4367
4362
4368 - last 10 commits on the current branch::
4363 - last 10 commits on the current branch::
4369
4364
4370 hg log -l 10 -b .
4365 hg log -l 10 -b .
4371
4366
4372 - changesets showing all modifications of a file, including removals::
4367 - changesets showing all modifications of a file, including removals::
4373
4368
4374 hg log --removed file.c
4369 hg log --removed file.c
4375
4370
4376 - all changesets that touch a directory, with diffs, excluding merges::
4371 - all changesets that touch a directory, with diffs, excluding merges::
4377
4372
4378 hg log -Mp lib/
4373 hg log -Mp lib/
4379
4374
4380 - all revision numbers that match a keyword::
4375 - all revision numbers that match a keyword::
4381
4376
4382 hg log -k bug --template "{rev}\\n"
4377 hg log -k bug --template "{rev}\\n"
4383
4378
4384 - the full hash identifier of the working directory parent::
4379 - the full hash identifier of the working directory parent::
4385
4380
4386 hg log -r . --template "{node}\\n"
4381 hg log -r . --template "{node}\\n"
4387
4382
4388 - list available log templates::
4383 - list available log templates::
4389
4384
4390 hg log -T list
4385 hg log -T list
4391
4386
4392 - check if a given changeset is included in a tagged release::
4387 - check if a given changeset is included in a tagged release::
4393
4388
4394 hg log -r "a21ccf and ancestor(1.9)"
4389 hg log -r "a21ccf and ancestor(1.9)"
4395
4390
4396 - find all changesets by some user in a date range::
4391 - find all changesets by some user in a date range::
4397
4392
4398 hg log -k alice -d "may 2008 to jul 2008"
4393 hg log -k alice -d "may 2008 to jul 2008"
4399
4394
4400 - summary of all changesets after the last tag::
4395 - summary of all changesets after the last tag::
4401
4396
4402 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4397 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4403
4398
4404 See :hg:`help dates` for a list of formats valid for -d/--date.
4399 See :hg:`help dates` for a list of formats valid for -d/--date.
4405
4400
4406 See :hg:`help revisions` for more about specifying and ordering
4401 See :hg:`help revisions` for more about specifying and ordering
4407 revisions.
4402 revisions.
4408
4403
4409 See :hg:`help templates` for more about pre-packaged styles and
4404 See :hg:`help templates` for more about pre-packaged styles and
4410 specifying custom templates.
4405 specifying custom templates.
4411
4406
4412 Returns 0 on success.
4407 Returns 0 on success.
4413
4408
4414 """
4409 """
4415 if opts.get('follow') and opts.get('rev'):
4410 if opts.get('follow') and opts.get('rev'):
4416 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4411 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4417 del opts['follow']
4412 del opts['follow']
4418
4413
4419 if opts.get('graph'):
4414 if opts.get('graph'):
4420 return cmdutil.graphlog(ui, repo, *pats, **opts)
4415 return cmdutil.graphlog(ui, repo, *pats, **opts)
4421
4416
4422 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4417 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4423 limit = cmdutil.loglimit(opts)
4418 limit = cmdutil.loglimit(opts)
4424 count = 0
4419 count = 0
4425
4420
4426 getrenamed = None
4421 getrenamed = None
4427 if opts.get('copies'):
4422 if opts.get('copies'):
4428 endrev = None
4423 endrev = None
4429 if opts.get('rev'):
4424 if opts.get('rev'):
4430 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4425 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4431 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4426 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4432
4427
4433 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4428 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4434 for rev in revs:
4429 for rev in revs:
4435 if count == limit:
4430 if count == limit:
4436 break
4431 break
4437 ctx = repo[rev]
4432 ctx = repo[rev]
4438 copies = None
4433 copies = None
4439 if getrenamed is not None and rev:
4434 if getrenamed is not None and rev:
4440 copies = []
4435 copies = []
4441 for fn in ctx.files():
4436 for fn in ctx.files():
4442 rename = getrenamed(fn, rev)
4437 rename = getrenamed(fn, rev)
4443 if rename:
4438 if rename:
4444 copies.append((fn, rename[0]))
4439 copies.append((fn, rename[0]))
4445 if filematcher:
4440 if filematcher:
4446 revmatchfn = filematcher(ctx.rev())
4441 revmatchfn = filematcher(ctx.rev())
4447 else:
4442 else:
4448 revmatchfn = None
4443 revmatchfn = None
4449 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4444 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4450 if displayer.flush(ctx):
4445 if displayer.flush(ctx):
4451 count += 1
4446 count += 1
4452
4447
4453 displayer.close()
4448 displayer.close()
4454
4449
4455 @command('manifest',
4450 @command('manifest',
4456 [('r', 'rev', '', _('revision to display'), _('REV')),
4451 [('r', 'rev', '', _('revision to display'), _('REV')),
4457 ('', 'all', False, _("list files from all revisions"))]
4452 ('', 'all', False, _("list files from all revisions"))]
4458 + formatteropts,
4453 + formatteropts,
4459 _('[-r REV]'))
4454 _('[-r REV]'))
4460 def manifest(ui, repo, node=None, rev=None, **opts):
4455 def manifest(ui, repo, node=None, rev=None, **opts):
4461 """output the current or given revision of the project manifest
4456 """output the current or given revision of the project manifest
4462
4457
4463 Print a list of version controlled files for the given revision.
4458 Print a list of version controlled files for the given revision.
4464 If no revision is given, the first parent of the working directory
4459 If no revision is given, the first parent of the working directory
4465 is used, or the null revision if no revision is checked out.
4460 is used, or the null revision if no revision is checked out.
4466
4461
4467 With -v, print file permissions, symlink and executable bits.
4462 With -v, print file permissions, symlink and executable bits.
4468 With --debug, print file revision hashes.
4463 With --debug, print file revision hashes.
4469
4464
4470 If option --all is specified, the list of all files from all revisions
4465 If option --all is specified, the list of all files from all revisions
4471 is printed. This includes deleted and renamed files.
4466 is printed. This includes deleted and renamed files.
4472
4467
4473 Returns 0 on success.
4468 Returns 0 on success.
4474 """
4469 """
4475
4470
4476 fm = ui.formatter('manifest', opts)
4471 fm = ui.formatter('manifest', opts)
4477
4472
4478 if opts.get('all'):
4473 if opts.get('all'):
4479 if rev or node:
4474 if rev or node:
4480 raise error.Abort(_("can't specify a revision with --all"))
4475 raise error.Abort(_("can't specify a revision with --all"))
4481
4476
4482 res = []
4477 res = []
4483 prefix = "data/"
4478 prefix = "data/"
4484 suffix = ".i"
4479 suffix = ".i"
4485 plen = len(prefix)
4480 plen = len(prefix)
4486 slen = len(suffix)
4481 slen = len(suffix)
4487 with repo.lock():
4482 with repo.lock():
4488 for fn, b, size in repo.store.datafiles():
4483 for fn, b, size in repo.store.datafiles():
4489 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4484 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4490 res.append(fn[plen:-slen])
4485 res.append(fn[plen:-slen])
4491 for f in res:
4486 for f in res:
4492 fm.startitem()
4487 fm.startitem()
4493 fm.write("path", '%s\n', f)
4488 fm.write("path", '%s\n', f)
4494 fm.end()
4489 fm.end()
4495 return
4490 return
4496
4491
4497 if rev and node:
4492 if rev and node:
4498 raise error.Abort(_("please specify just one revision"))
4493 raise error.Abort(_("please specify just one revision"))
4499
4494
4500 if not node:
4495 if not node:
4501 node = rev
4496 node = rev
4502
4497
4503 char = {'l': '@', 'x': '*', '': ''}
4498 char = {'l': '@', 'x': '*', '': ''}
4504 mode = {'l': '644', 'x': '755', '': '644'}
4499 mode = {'l': '644', 'x': '755', '': '644'}
4505 ctx = scmutil.revsingle(repo, node)
4500 ctx = scmutil.revsingle(repo, node)
4506 mf = ctx.manifest()
4501 mf = ctx.manifest()
4507 for f in ctx:
4502 for f in ctx:
4508 fm.startitem()
4503 fm.startitem()
4509 fl = ctx[f].flags()
4504 fl = ctx[f].flags()
4510 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4505 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4511 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4506 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4512 fm.write('path', '%s\n', f)
4507 fm.write('path', '%s\n', f)
4513 fm.end()
4508 fm.end()
4514
4509
4515 @command('^merge',
4510 @command('^merge',
4516 [('f', 'force', None,
4511 [('f', 'force', None,
4517 _('force a merge including outstanding changes (DEPRECATED)')),
4512 _('force a merge including outstanding changes (DEPRECATED)')),
4518 ('r', 'rev', '', _('revision to merge'), _('REV')),
4513 ('r', 'rev', '', _('revision to merge'), _('REV')),
4519 ('P', 'preview', None,
4514 ('P', 'preview', None,
4520 _('review revisions to merge (no merge is performed)'))
4515 _('review revisions to merge (no merge is performed)'))
4521 ] + mergetoolopts,
4516 ] + mergetoolopts,
4522 _('[-P] [[-r] REV]'))
4517 _('[-P] [[-r] REV]'))
4523 def merge(ui, repo, node=None, **opts):
4518 def merge(ui, repo, node=None, **opts):
4524 """merge another revision into working directory
4519 """merge another revision into working directory
4525
4520
4526 The current working directory is updated with all changes made in
4521 The current working directory is updated with all changes made in
4527 the requested revision since the last common predecessor revision.
4522 the requested revision since the last common predecessor revision.
4528
4523
4529 Files that changed between either parent are marked as changed for
4524 Files that changed between either parent are marked as changed for
4530 the next commit and a commit must be performed before any further
4525 the next commit and a commit must be performed before any further
4531 updates to the repository are allowed. The next commit will have
4526 updates to the repository are allowed. The next commit will have
4532 two parents.
4527 two parents.
4533
4528
4534 ``--tool`` can be used to specify the merge tool used for file
4529 ``--tool`` can be used to specify the merge tool used for file
4535 merges. It overrides the HGMERGE environment variable and your
4530 merges. It overrides the HGMERGE environment variable and your
4536 configuration files. See :hg:`help merge-tools` for options.
4531 configuration files. See :hg:`help merge-tools` for options.
4537
4532
4538 If no revision is specified, the working directory's parent is a
4533 If no revision is specified, the working directory's parent is a
4539 head revision, and the current branch contains exactly one other
4534 head revision, and the current branch contains exactly one other
4540 head, the other head is merged with by default. Otherwise, an
4535 head, the other head is merged with by default. Otherwise, an
4541 explicit revision with which to merge with must be provided.
4536 explicit revision with which to merge with must be provided.
4542
4537
4543 See :hg:`help resolve` for information on handling file conflicts.
4538 See :hg:`help resolve` for information on handling file conflicts.
4544
4539
4545 To undo an uncommitted merge, use :hg:`update --clean .` which
4540 To undo an uncommitted merge, use :hg:`update --clean .` which
4546 will check out a clean copy of the original merge parent, losing
4541 will check out a clean copy of the original merge parent, losing
4547 all changes.
4542 all changes.
4548
4543
4549 Returns 0 on success, 1 if there are unresolved files.
4544 Returns 0 on success, 1 if there are unresolved files.
4550 """
4545 """
4551
4546
4552 if opts.get('rev') and node:
4547 if opts.get('rev') and node:
4553 raise error.Abort(_("please specify just one revision"))
4548 raise error.Abort(_("please specify just one revision"))
4554 if not node:
4549 if not node:
4555 node = opts.get('rev')
4550 node = opts.get('rev')
4556
4551
4557 if node:
4552 if node:
4558 node = scmutil.revsingle(repo, node).node()
4553 node = scmutil.revsingle(repo, node).node()
4559
4554
4560 if not node:
4555 if not node:
4561 node = repo[destutil.destmerge(repo)].node()
4556 node = repo[destutil.destmerge(repo)].node()
4562
4557
4563 if opts.get('preview'):
4558 if opts.get('preview'):
4564 # find nodes that are ancestors of p2 but not of p1
4559 # find nodes that are ancestors of p2 but not of p1
4565 p1 = repo.lookup('.')
4560 p1 = repo.lookup('.')
4566 p2 = repo.lookup(node)
4561 p2 = repo.lookup(node)
4567 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4562 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4568
4563
4569 displayer = cmdutil.show_changeset(ui, repo, opts)
4564 displayer = cmdutil.show_changeset(ui, repo, opts)
4570 for node in nodes:
4565 for node in nodes:
4571 displayer.show(repo[node])
4566 displayer.show(repo[node])
4572 displayer.close()
4567 displayer.close()
4573 return 0
4568 return 0
4574
4569
4575 try:
4570 try:
4576 # ui.forcemerge is an internal variable, do not document
4571 # ui.forcemerge is an internal variable, do not document
4577 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4572 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4578 force = opts.get('force')
4573 force = opts.get('force')
4579 labels = ['working copy', 'merge rev']
4574 labels = ['working copy', 'merge rev']
4580 return hg.merge(repo, node, force=force, mergeforce=force,
4575 return hg.merge(repo, node, force=force, mergeforce=force,
4581 labels=labels)
4576 labels=labels)
4582 finally:
4577 finally:
4583 ui.setconfig('ui', 'forcemerge', '', 'merge')
4578 ui.setconfig('ui', 'forcemerge', '', 'merge')
4584
4579
4585 @command('outgoing|out',
4580 @command('outgoing|out',
4586 [('f', 'force', None, _('run even when the destination is unrelated')),
4581 [('f', 'force', None, _('run even when the destination is unrelated')),
4587 ('r', 'rev', [],
4582 ('r', 'rev', [],
4588 _('a changeset intended to be included in the destination'), _('REV')),
4583 _('a changeset intended to be included in the destination'), _('REV')),
4589 ('n', 'newest-first', None, _('show newest record first')),
4584 ('n', 'newest-first', None, _('show newest record first')),
4590 ('B', 'bookmarks', False, _('compare bookmarks')),
4585 ('B', 'bookmarks', False, _('compare bookmarks')),
4591 ('b', 'branch', [], _('a specific branch you would like to push'),
4586 ('b', 'branch', [], _('a specific branch you would like to push'),
4592 _('BRANCH')),
4587 _('BRANCH')),
4593 ] + logopts + remoteopts + subrepoopts,
4588 ] + logopts + remoteopts + subrepoopts,
4594 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4589 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4595 def outgoing(ui, repo, dest=None, **opts):
4590 def outgoing(ui, repo, dest=None, **opts):
4596 """show changesets not found in the destination
4591 """show changesets not found in the destination
4597
4592
4598 Show changesets not found in the specified destination repository
4593 Show changesets not found in the specified destination repository
4599 or the default push location. These are the changesets that would
4594 or the default push location. These are the changesets that would
4600 be pushed if a push was requested.
4595 be pushed if a push was requested.
4601
4596
4602 See pull for details of valid destination formats.
4597 See pull for details of valid destination formats.
4603
4598
4604 .. container:: verbose
4599 .. container:: verbose
4605
4600
4606 With -B/--bookmarks, the result of bookmark comparison between
4601 With -B/--bookmarks, the result of bookmark comparison between
4607 local and remote repositories is displayed. With -v/--verbose,
4602 local and remote repositories is displayed. With -v/--verbose,
4608 status is also displayed for each bookmark like below::
4603 status is also displayed for each bookmark like below::
4609
4604
4610 BM1 01234567890a added
4605 BM1 01234567890a added
4611 BM2 deleted
4606 BM2 deleted
4612 BM3 234567890abc advanced
4607 BM3 234567890abc advanced
4613 BM4 34567890abcd diverged
4608 BM4 34567890abcd diverged
4614 BM5 4567890abcde changed
4609 BM5 4567890abcde changed
4615
4610
4616 The action taken when pushing depends on the
4611 The action taken when pushing depends on the
4617 status of each bookmark:
4612 status of each bookmark:
4618
4613
4619 :``added``: push with ``-B`` will create it
4614 :``added``: push with ``-B`` will create it
4620 :``deleted``: push with ``-B`` will delete it
4615 :``deleted``: push with ``-B`` will delete it
4621 :``advanced``: push will update it
4616 :``advanced``: push will update it
4622 :``diverged``: push with ``-B`` will update it
4617 :``diverged``: push with ``-B`` will update it
4623 :``changed``: push with ``-B`` will update it
4618 :``changed``: push with ``-B`` will update it
4624
4619
4625 From the point of view of pushing behavior, bookmarks
4620 From the point of view of pushing behavior, bookmarks
4626 existing only in the remote repository are treated as
4621 existing only in the remote repository are treated as
4627 ``deleted``, even if it is in fact added remotely.
4622 ``deleted``, even if it is in fact added remotely.
4628
4623
4629 Returns 0 if there are outgoing changes, 1 otherwise.
4624 Returns 0 if there are outgoing changes, 1 otherwise.
4630 """
4625 """
4631 if opts.get('graph'):
4626 if opts.get('graph'):
4632 cmdutil.checkunsupportedgraphflags([], opts)
4627 cmdutil.checkunsupportedgraphflags([], opts)
4633 o, other = hg._outgoing(ui, repo, dest, opts)
4628 o, other = hg._outgoing(ui, repo, dest, opts)
4634 if not o:
4629 if not o:
4635 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4630 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4636 return
4631 return
4637
4632
4638 revdag = cmdutil.graphrevs(repo, o, opts)
4633 revdag = cmdutil.graphrevs(repo, o, opts)
4639 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4634 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4640 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4635 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4641 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4636 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4642 return 0
4637 return 0
4643
4638
4644 if opts.get('bookmarks'):
4639 if opts.get('bookmarks'):
4645 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4640 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4646 dest, branches = hg.parseurl(dest, opts.get('branch'))
4641 dest, branches = hg.parseurl(dest, opts.get('branch'))
4647 other = hg.peer(repo, opts, dest)
4642 other = hg.peer(repo, opts, dest)
4648 if 'bookmarks' not in other.listkeys('namespaces'):
4643 if 'bookmarks' not in other.listkeys('namespaces'):
4649 ui.warn(_("remote doesn't support bookmarks\n"))
4644 ui.warn(_("remote doesn't support bookmarks\n"))
4650 return 0
4645 return 0
4651 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4646 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4652 return bookmarks.outgoing(ui, repo, other)
4647 return bookmarks.outgoing(ui, repo, other)
4653
4648
4654 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4649 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4655 try:
4650 try:
4656 return hg.outgoing(ui, repo, dest, opts)
4651 return hg.outgoing(ui, repo, dest, opts)
4657 finally:
4652 finally:
4658 del repo._subtoppath
4653 del repo._subtoppath
4659
4654
4660 @command('parents',
4655 @command('parents',
4661 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4656 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4662 ] + templateopts,
4657 ] + templateopts,
4663 _('[-r REV] [FILE]'),
4658 _('[-r REV] [FILE]'),
4664 inferrepo=True)
4659 inferrepo=True)
4665 def parents(ui, repo, file_=None, **opts):
4660 def parents(ui, repo, file_=None, **opts):
4666 """show the parents of the working directory or revision (DEPRECATED)
4661 """show the parents of the working directory or revision (DEPRECATED)
4667
4662
4668 Print the working directory's parent revisions. If a revision is
4663 Print the working directory's parent revisions. If a revision is
4669 given via -r/--rev, the parent of that revision will be printed.
4664 given via -r/--rev, the parent of that revision will be printed.
4670 If a file argument is given, the revision in which the file was
4665 If a file argument is given, the revision in which the file was
4671 last changed (before the working directory revision or the
4666 last changed (before the working directory revision or the
4672 argument to --rev if given) is printed.
4667 argument to --rev if given) is printed.
4673
4668
4674 This command is equivalent to::
4669 This command is equivalent to::
4675
4670
4676 hg log -r "p1()+p2()" or
4671 hg log -r "p1()+p2()" or
4677 hg log -r "p1(REV)+p2(REV)" or
4672 hg log -r "p1(REV)+p2(REV)" or
4678 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4673 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4679 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4674 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4680
4675
4681 See :hg:`summary` and :hg:`help revsets` for related information.
4676 See :hg:`summary` and :hg:`help revsets` for related information.
4682
4677
4683 Returns 0 on success.
4678 Returns 0 on success.
4684 """
4679 """
4685
4680
4686 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4681 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4687
4682
4688 if file_:
4683 if file_:
4689 m = scmutil.match(ctx, (file_,), opts)
4684 m = scmutil.match(ctx, (file_,), opts)
4690 if m.anypats() or len(m.files()) != 1:
4685 if m.anypats() or len(m.files()) != 1:
4691 raise error.Abort(_('can only specify an explicit filename'))
4686 raise error.Abort(_('can only specify an explicit filename'))
4692 file_ = m.files()[0]
4687 file_ = m.files()[0]
4693 filenodes = []
4688 filenodes = []
4694 for cp in ctx.parents():
4689 for cp in ctx.parents():
4695 if not cp:
4690 if not cp:
4696 continue
4691 continue
4697 try:
4692 try:
4698 filenodes.append(cp.filenode(file_))
4693 filenodes.append(cp.filenode(file_))
4699 except error.LookupError:
4694 except error.LookupError:
4700 pass
4695 pass
4701 if not filenodes:
4696 if not filenodes:
4702 raise error.Abort(_("'%s' not found in manifest!") % file_)
4697 raise error.Abort(_("'%s' not found in manifest!") % file_)
4703 p = []
4698 p = []
4704 for fn in filenodes:
4699 for fn in filenodes:
4705 fctx = repo.filectx(file_, fileid=fn)
4700 fctx = repo.filectx(file_, fileid=fn)
4706 p.append(fctx.node())
4701 p.append(fctx.node())
4707 else:
4702 else:
4708 p = [cp.node() for cp in ctx.parents()]
4703 p = [cp.node() for cp in ctx.parents()]
4709
4704
4710 displayer = cmdutil.show_changeset(ui, repo, opts)
4705 displayer = cmdutil.show_changeset(ui, repo, opts)
4711 for n in p:
4706 for n in p:
4712 if n != nullid:
4707 if n != nullid:
4713 displayer.show(repo[n])
4708 displayer.show(repo[n])
4714 displayer.close()
4709 displayer.close()
4715
4710
4716 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4711 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4717 def paths(ui, repo, search=None, **opts):
4712 def paths(ui, repo, search=None, **opts):
4718 """show aliases for remote repositories
4713 """show aliases for remote repositories
4719
4714
4720 Show definition of symbolic path name NAME. If no name is given,
4715 Show definition of symbolic path name NAME. If no name is given,
4721 show definition of all available names.
4716 show definition of all available names.
4722
4717
4723 Option -q/--quiet suppresses all output when searching for NAME
4718 Option -q/--quiet suppresses all output when searching for NAME
4724 and shows only the path names when listing all definitions.
4719 and shows only the path names when listing all definitions.
4725
4720
4726 Path names are defined in the [paths] section of your
4721 Path names are defined in the [paths] section of your
4727 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4722 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4728 repository, ``.hg/hgrc`` is used, too.
4723 repository, ``.hg/hgrc`` is used, too.
4729
4724
4730 The path names ``default`` and ``default-push`` have a special
4725 The path names ``default`` and ``default-push`` have a special
4731 meaning. When performing a push or pull operation, they are used
4726 meaning. When performing a push or pull operation, they are used
4732 as fallbacks if no location is specified on the command-line.
4727 as fallbacks if no location is specified on the command-line.
4733 When ``default-push`` is set, it will be used for push and
4728 When ``default-push`` is set, it will be used for push and
4734 ``default`` will be used for pull; otherwise ``default`` is used
4729 ``default`` will be used for pull; otherwise ``default`` is used
4735 as the fallback for both. When cloning a repository, the clone
4730 as the fallback for both. When cloning a repository, the clone
4736 source is written as ``default`` in ``.hg/hgrc``.
4731 source is written as ``default`` in ``.hg/hgrc``.
4737
4732
4738 .. note::
4733 .. note::
4739
4734
4740 ``default`` and ``default-push`` apply to all inbound (e.g.
4735 ``default`` and ``default-push`` apply to all inbound (e.g.
4741 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4736 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4742 and :hg:`bundle`) operations.
4737 and :hg:`bundle`) operations.
4743
4738
4744 See :hg:`help urls` for more information.
4739 See :hg:`help urls` for more information.
4745
4740
4746 Returns 0 on success.
4741 Returns 0 on success.
4747 """
4742 """
4748 if search:
4743 if search:
4749 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4744 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4750 if name == search]
4745 if name == search]
4751 else:
4746 else:
4752 pathitems = sorted(ui.paths.iteritems())
4747 pathitems = sorted(ui.paths.iteritems())
4753
4748
4754 fm = ui.formatter('paths', opts)
4749 fm = ui.formatter('paths', opts)
4755 if fm.isplain():
4750 if fm.isplain():
4756 hidepassword = util.hidepassword
4751 hidepassword = util.hidepassword
4757 else:
4752 else:
4758 hidepassword = str
4753 hidepassword = str
4759 if ui.quiet:
4754 if ui.quiet:
4760 namefmt = '%s\n'
4755 namefmt = '%s\n'
4761 else:
4756 else:
4762 namefmt = '%s = '
4757 namefmt = '%s = '
4763 showsubopts = not search and not ui.quiet
4758 showsubopts = not search and not ui.quiet
4764
4759
4765 for name, path in pathitems:
4760 for name, path in pathitems:
4766 fm.startitem()
4761 fm.startitem()
4767 fm.condwrite(not search, 'name', namefmt, name)
4762 fm.condwrite(not search, 'name', namefmt, name)
4768 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4763 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4769 for subopt, value in sorted(path.suboptions.items()):
4764 for subopt, value in sorted(path.suboptions.items()):
4770 assert subopt not in ('name', 'url')
4765 assert subopt not in ('name', 'url')
4771 if showsubopts:
4766 if showsubopts:
4772 fm.plain('%s:%s = ' % (name, subopt))
4767 fm.plain('%s:%s = ' % (name, subopt))
4773 fm.condwrite(showsubopts, subopt, '%s\n', value)
4768 fm.condwrite(showsubopts, subopt, '%s\n', value)
4774
4769
4775 fm.end()
4770 fm.end()
4776
4771
4777 if search and not pathitems:
4772 if search and not pathitems:
4778 if not ui.quiet:
4773 if not ui.quiet:
4779 ui.warn(_("not found!\n"))
4774 ui.warn(_("not found!\n"))
4780 return 1
4775 return 1
4781 else:
4776 else:
4782 return 0
4777 return 0
4783
4778
4784 @command('phase',
4779 @command('phase',
4785 [('p', 'public', False, _('set changeset phase to public')),
4780 [('p', 'public', False, _('set changeset phase to public')),
4786 ('d', 'draft', False, _('set changeset phase to draft')),
4781 ('d', 'draft', False, _('set changeset phase to draft')),
4787 ('s', 'secret', False, _('set changeset phase to secret')),
4782 ('s', 'secret', False, _('set changeset phase to secret')),
4788 ('f', 'force', False, _('allow to move boundary backward')),
4783 ('f', 'force', False, _('allow to move boundary backward')),
4789 ('r', 'rev', [], _('target revision'), _('REV')),
4784 ('r', 'rev', [], _('target revision'), _('REV')),
4790 ],
4785 ],
4791 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4786 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4792 def phase(ui, repo, *revs, **opts):
4787 def phase(ui, repo, *revs, **opts):
4793 """set or show the current phase name
4788 """set or show the current phase name
4794
4789
4795 With no argument, show the phase name of the current revision(s).
4790 With no argument, show the phase name of the current revision(s).
4796
4791
4797 With one of -p/--public, -d/--draft or -s/--secret, change the
4792 With one of -p/--public, -d/--draft or -s/--secret, change the
4798 phase value of the specified revisions.
4793 phase value of the specified revisions.
4799
4794
4800 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4795 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4801 lower phase to an higher phase. Phases are ordered as follows::
4796 lower phase to an higher phase. Phases are ordered as follows::
4802
4797
4803 public < draft < secret
4798 public < draft < secret
4804
4799
4805 Returns 0 on success, 1 if some phases could not be changed.
4800 Returns 0 on success, 1 if some phases could not be changed.
4806
4801
4807 (For more information about the phases concept, see :hg:`help phases`.)
4802 (For more information about the phases concept, see :hg:`help phases`.)
4808 """
4803 """
4809 # search for a unique phase argument
4804 # search for a unique phase argument
4810 targetphase = None
4805 targetphase = None
4811 for idx, name in enumerate(phases.phasenames):
4806 for idx, name in enumerate(phases.phasenames):
4812 if opts[name]:
4807 if opts[name]:
4813 if targetphase is not None:
4808 if targetphase is not None:
4814 raise error.Abort(_('only one phase can be specified'))
4809 raise error.Abort(_('only one phase can be specified'))
4815 targetphase = idx
4810 targetphase = idx
4816
4811
4817 # look for specified revision
4812 # look for specified revision
4818 revs = list(revs)
4813 revs = list(revs)
4819 revs.extend(opts['rev'])
4814 revs.extend(opts['rev'])
4820 if not revs:
4815 if not revs:
4821 # display both parents as the second parent phase can influence
4816 # display both parents as the second parent phase can influence
4822 # the phase of a merge commit
4817 # the phase of a merge commit
4823 revs = [c.rev() for c in repo[None].parents()]
4818 revs = [c.rev() for c in repo[None].parents()]
4824
4819
4825 revs = scmutil.revrange(repo, revs)
4820 revs = scmutil.revrange(repo, revs)
4826
4821
4827 lock = None
4822 lock = None
4828 ret = 0
4823 ret = 0
4829 if targetphase is None:
4824 if targetphase is None:
4830 # display
4825 # display
4831 for r in revs:
4826 for r in revs:
4832 ctx = repo[r]
4827 ctx = repo[r]
4833 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4828 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4834 else:
4829 else:
4835 tr = None
4830 tr = None
4836 lock = repo.lock()
4831 lock = repo.lock()
4837 try:
4832 try:
4838 tr = repo.transaction("phase")
4833 tr = repo.transaction("phase")
4839 # set phase
4834 # set phase
4840 if not revs:
4835 if not revs:
4841 raise error.Abort(_('empty revision set'))
4836 raise error.Abort(_('empty revision set'))
4842 nodes = [repo[r].node() for r in revs]
4837 nodes = [repo[r].node() for r in revs]
4843 # moving revision from public to draft may hide them
4838 # moving revision from public to draft may hide them
4844 # We have to check result on an unfiltered repository
4839 # We have to check result on an unfiltered repository
4845 unfi = repo.unfiltered()
4840 unfi = repo.unfiltered()
4846 getphase = unfi._phasecache.phase
4841 getphase = unfi._phasecache.phase
4847 olddata = [getphase(unfi, r) for r in unfi]
4842 olddata = [getphase(unfi, r) for r in unfi]
4848 phases.advanceboundary(repo, tr, targetphase, nodes)
4843 phases.advanceboundary(repo, tr, targetphase, nodes)
4849 if opts['force']:
4844 if opts['force']:
4850 phases.retractboundary(repo, tr, targetphase, nodes)
4845 phases.retractboundary(repo, tr, targetphase, nodes)
4851 tr.close()
4846 tr.close()
4852 finally:
4847 finally:
4853 if tr is not None:
4848 if tr is not None:
4854 tr.release()
4849 tr.release()
4855 lock.release()
4850 lock.release()
4856 getphase = unfi._phasecache.phase
4851 getphase = unfi._phasecache.phase
4857 newdata = [getphase(unfi, r) for r in unfi]
4852 newdata = [getphase(unfi, r) for r in unfi]
4858 changes = sum(newdata[r] != olddata[r] for r in unfi)
4853 changes = sum(newdata[r] != olddata[r] for r in unfi)
4859 cl = unfi.changelog
4854 cl = unfi.changelog
4860 rejected = [n for n in nodes
4855 rejected = [n for n in nodes
4861 if newdata[cl.rev(n)] < targetphase]
4856 if newdata[cl.rev(n)] < targetphase]
4862 if rejected:
4857 if rejected:
4863 ui.warn(_('cannot move %i changesets to a higher '
4858 ui.warn(_('cannot move %i changesets to a higher '
4864 'phase, use --force\n') % len(rejected))
4859 'phase, use --force\n') % len(rejected))
4865 ret = 1
4860 ret = 1
4866 if changes:
4861 if changes:
4867 msg = _('phase changed for %i changesets\n') % changes
4862 msg = _('phase changed for %i changesets\n') % changes
4868 if ret:
4863 if ret:
4869 ui.status(msg)
4864 ui.status(msg)
4870 else:
4865 else:
4871 ui.note(msg)
4866 ui.note(msg)
4872 else:
4867 else:
4873 ui.warn(_('no phases changed\n'))
4868 ui.warn(_('no phases changed\n'))
4874 return ret
4869 return ret
4875
4870
4876 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4871 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4877 """Run after a changegroup has been added via pull/unbundle
4872 """Run after a changegroup has been added via pull/unbundle
4878
4873
4879 This takes arguments below:
4874 This takes arguments below:
4880
4875
4881 :modheads: change of heads by pull/unbundle
4876 :modheads: change of heads by pull/unbundle
4882 :optupdate: updating working directory is needed or not
4877 :optupdate: updating working directory is needed or not
4883 :checkout: update destination revision (or None to default destination)
4878 :checkout: update destination revision (or None to default destination)
4884 :brev: a name, which might be a bookmark to be activated after updating
4879 :brev: a name, which might be a bookmark to be activated after updating
4885 """
4880 """
4886 if modheads == 0:
4881 if modheads == 0:
4887 return
4882 return
4888 if optupdate:
4883 if optupdate:
4889 try:
4884 try:
4890 return hg.updatetotally(ui, repo, checkout, brev)
4885 return hg.updatetotally(ui, repo, checkout, brev)
4891 except error.UpdateAbort as inst:
4886 except error.UpdateAbort as inst:
4892 msg = _("not updating: %s") % str(inst)
4887 msg = _("not updating: %s") % str(inst)
4893 hint = inst.hint
4888 hint = inst.hint
4894 raise error.UpdateAbort(msg, hint=hint)
4889 raise error.UpdateAbort(msg, hint=hint)
4895 if modheads > 1:
4890 if modheads > 1:
4896 currentbranchheads = len(repo.branchheads())
4891 currentbranchheads = len(repo.branchheads())
4897 if currentbranchheads == modheads:
4892 if currentbranchheads == modheads:
4898 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4893 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4899 elif currentbranchheads > 1:
4894 elif currentbranchheads > 1:
4900 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4895 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4901 "merge)\n"))
4896 "merge)\n"))
4902 else:
4897 else:
4903 ui.status(_("(run 'hg heads' to see heads)\n"))
4898 ui.status(_("(run 'hg heads' to see heads)\n"))
4904 else:
4899 else:
4905 ui.status(_("(run 'hg update' to get a working copy)\n"))
4900 ui.status(_("(run 'hg update' to get a working copy)\n"))
4906
4901
4907 @command('^pull',
4902 @command('^pull',
4908 [('u', 'update', None,
4903 [('u', 'update', None,
4909 _('update to new branch head if changesets were pulled')),
4904 _('update to new branch head if changesets were pulled')),
4910 ('f', 'force', None, _('run even when remote repository is unrelated')),
4905 ('f', 'force', None, _('run even when remote repository is unrelated')),
4911 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4906 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4912 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4907 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4913 ('b', 'branch', [], _('a specific branch you would like to pull'),
4908 ('b', 'branch', [], _('a specific branch you would like to pull'),
4914 _('BRANCH')),
4909 _('BRANCH')),
4915 ] + remoteopts,
4910 ] + remoteopts,
4916 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4911 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4917 def pull(ui, repo, source="default", **opts):
4912 def pull(ui, repo, source="default", **opts):
4918 """pull changes from the specified source
4913 """pull changes from the specified source
4919
4914
4920 Pull changes from a remote repository to a local one.
4915 Pull changes from a remote repository to a local one.
4921
4916
4922 This finds all changes from the repository at the specified path
4917 This finds all changes from the repository at the specified path
4923 or URL and adds them to a local repository (the current one unless
4918 or URL and adds them to a local repository (the current one unless
4924 -R is specified). By default, this does not update the copy of the
4919 -R is specified). By default, this does not update the copy of the
4925 project in the working directory.
4920 project in the working directory.
4926
4921
4927 Use :hg:`incoming` if you want to see what would have been added
4922 Use :hg:`incoming` if you want to see what would have been added
4928 by a pull at the time you issued this command. If you then decide
4923 by a pull at the time you issued this command. If you then decide
4929 to add those changes to the repository, you should use :hg:`pull
4924 to add those changes to the repository, you should use :hg:`pull
4930 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4925 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4931
4926
4932 If SOURCE is omitted, the 'default' path will be used.
4927 If SOURCE is omitted, the 'default' path will be used.
4933 See :hg:`help urls` for more information.
4928 See :hg:`help urls` for more information.
4934
4929
4935 Specifying bookmark as ``.`` is equivalent to specifying the active
4930 Specifying bookmark as ``.`` is equivalent to specifying the active
4936 bookmark's name.
4931 bookmark's name.
4937
4932
4938 Returns 0 on success, 1 if an update had unresolved files.
4933 Returns 0 on success, 1 if an update had unresolved files.
4939 """
4934 """
4940 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4935 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4941 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4936 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4942 other = hg.peer(repo, opts, source)
4937 other = hg.peer(repo, opts, source)
4943 try:
4938 try:
4944 revs, checkout = hg.addbranchrevs(repo, other, branches,
4939 revs, checkout = hg.addbranchrevs(repo, other, branches,
4945 opts.get('rev'))
4940 opts.get('rev'))
4946
4941
4947
4942
4948 pullopargs = {}
4943 pullopargs = {}
4949 if opts.get('bookmark'):
4944 if opts.get('bookmark'):
4950 if not revs:
4945 if not revs:
4951 revs = []
4946 revs = []
4952 # The list of bookmark used here is not the one used to actually
4947 # The list of bookmark used here is not the one used to actually
4953 # update the bookmark name. This can result in the revision pulled
4948 # update the bookmark name. This can result in the revision pulled
4954 # not ending up with the name of the bookmark because of a race
4949 # not ending up with the name of the bookmark because of a race
4955 # condition on the server. (See issue 4689 for details)
4950 # condition on the server. (See issue 4689 for details)
4956 remotebookmarks = other.listkeys('bookmarks')
4951 remotebookmarks = other.listkeys('bookmarks')
4957 pullopargs['remotebookmarks'] = remotebookmarks
4952 pullopargs['remotebookmarks'] = remotebookmarks
4958 for b in opts['bookmark']:
4953 for b in opts['bookmark']:
4959 b = repo._bookmarks.expandname(b)
4954 b = repo._bookmarks.expandname(b)
4960 if b not in remotebookmarks:
4955 if b not in remotebookmarks:
4961 raise error.Abort(_('remote bookmark %s not found!') % b)
4956 raise error.Abort(_('remote bookmark %s not found!') % b)
4962 revs.append(remotebookmarks[b])
4957 revs.append(remotebookmarks[b])
4963
4958
4964 if revs:
4959 if revs:
4965 try:
4960 try:
4966 # When 'rev' is a bookmark name, we cannot guarantee that it
4961 # When 'rev' is a bookmark name, we cannot guarantee that it
4967 # will be updated with that name because of a race condition
4962 # will be updated with that name because of a race condition
4968 # server side. (See issue 4689 for details)
4963 # server side. (See issue 4689 for details)
4969 oldrevs = revs
4964 oldrevs = revs
4970 revs = [] # actually, nodes
4965 revs = [] # actually, nodes
4971 for r in oldrevs:
4966 for r in oldrevs:
4972 node = other.lookup(r)
4967 node = other.lookup(r)
4973 revs.append(node)
4968 revs.append(node)
4974 if r == checkout:
4969 if r == checkout:
4975 checkout = node
4970 checkout = node
4976 except error.CapabilityError:
4971 except error.CapabilityError:
4977 err = _("other repository doesn't support revision lookup, "
4972 err = _("other repository doesn't support revision lookup, "
4978 "so a rev cannot be specified.")
4973 "so a rev cannot be specified.")
4979 raise error.Abort(err)
4974 raise error.Abort(err)
4980
4975
4981 pullopargs.update(opts.get('opargs', {}))
4976 pullopargs.update(opts.get('opargs', {}))
4982 modheads = exchange.pull(repo, other, heads=revs,
4977 modheads = exchange.pull(repo, other, heads=revs,
4983 force=opts.get('force'),
4978 force=opts.get('force'),
4984 bookmarks=opts.get('bookmark', ()),
4979 bookmarks=opts.get('bookmark', ()),
4985 opargs=pullopargs).cgresult
4980 opargs=pullopargs).cgresult
4986
4981
4987 # brev is a name, which might be a bookmark to be activated at
4982 # brev is a name, which might be a bookmark to be activated at
4988 # the end of the update. In other words, it is an explicit
4983 # the end of the update. In other words, it is an explicit
4989 # destination of the update
4984 # destination of the update
4990 brev = None
4985 brev = None
4991
4986
4992 if checkout:
4987 if checkout:
4993 checkout = str(repo.changelog.rev(checkout))
4988 checkout = str(repo.changelog.rev(checkout))
4994
4989
4995 # order below depends on implementation of
4990 # order below depends on implementation of
4996 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4991 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4997 # because 'checkout' is determined without it.
4992 # because 'checkout' is determined without it.
4998 if opts.get('rev'):
4993 if opts.get('rev'):
4999 brev = opts['rev'][0]
4994 brev = opts['rev'][0]
5000 elif opts.get('branch'):
4995 elif opts.get('branch'):
5001 brev = opts['branch'][0]
4996 brev = opts['branch'][0]
5002 else:
4997 else:
5003 brev = branches[0]
4998 brev = branches[0]
5004 repo._subtoppath = source
4999 repo._subtoppath = source
5005 try:
5000 try:
5006 ret = postincoming(ui, repo, modheads, opts.get('update'),
5001 ret = postincoming(ui, repo, modheads, opts.get('update'),
5007 checkout, brev)
5002 checkout, brev)
5008
5003
5009 finally:
5004 finally:
5010 del repo._subtoppath
5005 del repo._subtoppath
5011
5006
5012 finally:
5007 finally:
5013 other.close()
5008 other.close()
5014 return ret
5009 return ret
5015
5010
5016 @command('^push',
5011 @command('^push',
5017 [('f', 'force', None, _('force push')),
5012 [('f', 'force', None, _('force push')),
5018 ('r', 'rev', [],
5013 ('r', 'rev', [],
5019 _('a changeset intended to be included in the destination'),
5014 _('a changeset intended to be included in the destination'),
5020 _('REV')),
5015 _('REV')),
5021 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5016 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5022 ('b', 'branch', [],
5017 ('b', 'branch', [],
5023 _('a specific branch you would like to push'), _('BRANCH')),
5018 _('a specific branch you would like to push'), _('BRANCH')),
5024 ('', 'new-branch', False, _('allow pushing a new branch')),
5019 ('', 'new-branch', False, _('allow pushing a new branch')),
5025 ] + remoteopts,
5020 ] + remoteopts,
5026 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5021 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5027 def push(ui, repo, dest=None, **opts):
5022 def push(ui, repo, dest=None, **opts):
5028 """push changes to the specified destination
5023 """push changes to the specified destination
5029
5024
5030 Push changesets from the local repository to the specified
5025 Push changesets from the local repository to the specified
5031 destination.
5026 destination.
5032
5027
5033 This operation is symmetrical to pull: it is identical to a pull
5028 This operation is symmetrical to pull: it is identical to a pull
5034 in the destination repository from the current one.
5029 in the destination repository from the current one.
5035
5030
5036 By default, push will not allow creation of new heads at the
5031 By default, push will not allow creation of new heads at the
5037 destination, since multiple heads would make it unclear which head
5032 destination, since multiple heads would make it unclear which head
5038 to use. In this situation, it is recommended to pull and merge
5033 to use. In this situation, it is recommended to pull and merge
5039 before pushing.
5034 before pushing.
5040
5035
5041 Use --new-branch if you want to allow push to create a new named
5036 Use --new-branch if you want to allow push to create a new named
5042 branch that is not present at the destination. This allows you to
5037 branch that is not present at the destination. This allows you to
5043 only create a new branch without forcing other changes.
5038 only create a new branch without forcing other changes.
5044
5039
5045 .. note::
5040 .. note::
5046
5041
5047 Extra care should be taken with the -f/--force option,
5042 Extra care should be taken with the -f/--force option,
5048 which will push all new heads on all branches, an action which will
5043 which will push all new heads on all branches, an action which will
5049 almost always cause confusion for collaborators.
5044 almost always cause confusion for collaborators.
5050
5045
5051 If -r/--rev is used, the specified revision and all its ancestors
5046 If -r/--rev is used, the specified revision and all its ancestors
5052 will be pushed to the remote repository.
5047 will be pushed to the remote repository.
5053
5048
5054 If -B/--bookmark is used, the specified bookmarked revision, its
5049 If -B/--bookmark is used, the specified bookmarked revision, its
5055 ancestors, and the bookmark will be pushed to the remote
5050 ancestors, and the bookmark will be pushed to the remote
5056 repository. Specifying ``.`` is equivalent to specifying the active
5051 repository. Specifying ``.`` is equivalent to specifying the active
5057 bookmark's name.
5052 bookmark's name.
5058
5053
5059 Please see :hg:`help urls` for important details about ``ssh://``
5054 Please see :hg:`help urls` for important details about ``ssh://``
5060 URLs. If DESTINATION is omitted, a default path will be used.
5055 URLs. If DESTINATION is omitted, a default path will be used.
5061
5056
5062 Returns 0 if push was successful, 1 if nothing to push.
5057 Returns 0 if push was successful, 1 if nothing to push.
5063 """
5058 """
5064
5059
5065 if opts.get('bookmark'):
5060 if opts.get('bookmark'):
5066 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5061 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5067 for b in opts['bookmark']:
5062 for b in opts['bookmark']:
5068 # translate -B options to -r so changesets get pushed
5063 # translate -B options to -r so changesets get pushed
5069 b = repo._bookmarks.expandname(b)
5064 b = repo._bookmarks.expandname(b)
5070 if b in repo._bookmarks:
5065 if b in repo._bookmarks:
5071 opts.setdefault('rev', []).append(b)
5066 opts.setdefault('rev', []).append(b)
5072 else:
5067 else:
5073 # if we try to push a deleted bookmark, translate it to null
5068 # if we try to push a deleted bookmark, translate it to null
5074 # this lets simultaneous -r, -b options continue working
5069 # this lets simultaneous -r, -b options continue working
5075 opts.setdefault('rev', []).append("null")
5070 opts.setdefault('rev', []).append("null")
5076
5071
5077 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5072 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5078 if not path:
5073 if not path:
5079 raise error.Abort(_('default repository not configured!'),
5074 raise error.Abort(_('default repository not configured!'),
5080 hint=_("see 'hg help config.paths'"))
5075 hint=_("see 'hg help config.paths'"))
5081 dest = path.pushloc or path.loc
5076 dest = path.pushloc or path.loc
5082 branches = (path.branch, opts.get('branch') or [])
5077 branches = (path.branch, opts.get('branch') or [])
5083 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5078 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5084 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5079 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5085 other = hg.peer(repo, opts, dest)
5080 other = hg.peer(repo, opts, dest)
5086
5081
5087 if revs:
5082 if revs:
5088 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5083 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5089 if not revs:
5084 if not revs:
5090 raise error.Abort(_("specified revisions evaluate to an empty set"),
5085 raise error.Abort(_("specified revisions evaluate to an empty set"),
5091 hint=_("use different revision arguments"))
5086 hint=_("use different revision arguments"))
5092 elif path.pushrev:
5087 elif path.pushrev:
5093 # It doesn't make any sense to specify ancestor revisions. So limit
5088 # It doesn't make any sense to specify ancestor revisions. So limit
5094 # to DAG heads to make discovery simpler.
5089 # to DAG heads to make discovery simpler.
5095 expr = revset.formatspec('heads(%r)', path.pushrev)
5090 expr = revset.formatspec('heads(%r)', path.pushrev)
5096 revs = scmutil.revrange(repo, [expr])
5091 revs = scmutil.revrange(repo, [expr])
5097 revs = [repo[rev].node() for rev in revs]
5092 revs = [repo[rev].node() for rev in revs]
5098 if not revs:
5093 if not revs:
5099 raise error.Abort(_('default push revset for path evaluates to an '
5094 raise error.Abort(_('default push revset for path evaluates to an '
5100 'empty set'))
5095 'empty set'))
5101
5096
5102 repo._subtoppath = dest
5097 repo._subtoppath = dest
5103 try:
5098 try:
5104 # push subrepos depth-first for coherent ordering
5099 # push subrepos depth-first for coherent ordering
5105 c = repo['']
5100 c = repo['']
5106 subs = c.substate # only repos that are committed
5101 subs = c.substate # only repos that are committed
5107 for s in sorted(subs):
5102 for s in sorted(subs):
5108 result = c.sub(s).push(opts)
5103 result = c.sub(s).push(opts)
5109 if result == 0:
5104 if result == 0:
5110 return not result
5105 return not result
5111 finally:
5106 finally:
5112 del repo._subtoppath
5107 del repo._subtoppath
5113 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5108 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5114 newbranch=opts.get('new_branch'),
5109 newbranch=opts.get('new_branch'),
5115 bookmarks=opts.get('bookmark', ()),
5110 bookmarks=opts.get('bookmark', ()),
5116 opargs=opts.get('opargs'))
5111 opargs=opts.get('opargs'))
5117
5112
5118 result = not pushop.cgresult
5113 result = not pushop.cgresult
5119
5114
5120 if pushop.bkresult is not None:
5115 if pushop.bkresult is not None:
5121 if pushop.bkresult == 2:
5116 if pushop.bkresult == 2:
5122 result = 2
5117 result = 2
5123 elif not result and pushop.bkresult:
5118 elif not result and pushop.bkresult:
5124 result = 2
5119 result = 2
5125
5120
5126 return result
5121 return result
5127
5122
5128 @command('recover', [])
5123 @command('recover', [])
5129 def recover(ui, repo):
5124 def recover(ui, repo):
5130 """roll back an interrupted transaction
5125 """roll back an interrupted transaction
5131
5126
5132 Recover from an interrupted commit or pull.
5127 Recover from an interrupted commit or pull.
5133
5128
5134 This command tries to fix the repository status after an
5129 This command tries to fix the repository status after an
5135 interrupted operation. It should only be necessary when Mercurial
5130 interrupted operation. It should only be necessary when Mercurial
5136 suggests it.
5131 suggests it.
5137
5132
5138 Returns 0 if successful, 1 if nothing to recover or verify fails.
5133 Returns 0 if successful, 1 if nothing to recover or verify fails.
5139 """
5134 """
5140 if repo.recover():
5135 if repo.recover():
5141 return hg.verify(repo)
5136 return hg.verify(repo)
5142 return 1
5137 return 1
5143
5138
5144 @command('^remove|rm',
5139 @command('^remove|rm',
5145 [('A', 'after', None, _('record delete for missing files')),
5140 [('A', 'after', None, _('record delete for missing files')),
5146 ('f', 'force', None,
5141 ('f', 'force', None,
5147 _('forget added files, delete modified files')),
5142 _('forget added files, delete modified files')),
5148 ] + subrepoopts + walkopts,
5143 ] + subrepoopts + walkopts,
5149 _('[OPTION]... FILE...'),
5144 _('[OPTION]... FILE...'),
5150 inferrepo=True)
5145 inferrepo=True)
5151 def remove(ui, repo, *pats, **opts):
5146 def remove(ui, repo, *pats, **opts):
5152 """remove the specified files on the next commit
5147 """remove the specified files on the next commit
5153
5148
5154 Schedule the indicated files for removal from the current branch.
5149 Schedule the indicated files for removal from the current branch.
5155
5150
5156 This command schedules the files to be removed at the next commit.
5151 This command schedules the files to be removed at the next commit.
5157 To undo a remove before that, see :hg:`revert`. To undo added
5152 To undo a remove before that, see :hg:`revert`. To undo added
5158 files, see :hg:`forget`.
5153 files, see :hg:`forget`.
5159
5154
5160 .. container:: verbose
5155 .. container:: verbose
5161
5156
5162 -A/--after can be used to remove only files that have already
5157 -A/--after can be used to remove only files that have already
5163 been deleted, -f/--force can be used to force deletion, and -Af
5158 been deleted, -f/--force can be used to force deletion, and -Af
5164 can be used to remove files from the next revision without
5159 can be used to remove files from the next revision without
5165 deleting them from the working directory.
5160 deleting them from the working directory.
5166
5161
5167 The following table details the behavior of remove for different
5162 The following table details the behavior of remove for different
5168 file states (columns) and option combinations (rows). The file
5163 file states (columns) and option combinations (rows). The file
5169 states are Added [A], Clean [C], Modified [M] and Missing [!]
5164 states are Added [A], Clean [C], Modified [M] and Missing [!]
5170 (as reported by :hg:`status`). The actions are Warn, Remove
5165 (as reported by :hg:`status`). The actions are Warn, Remove
5171 (from branch) and Delete (from disk):
5166 (from branch) and Delete (from disk):
5172
5167
5173 ========= == == == ==
5168 ========= == == == ==
5174 opt/state A C M !
5169 opt/state A C M !
5175 ========= == == == ==
5170 ========= == == == ==
5176 none W RD W R
5171 none W RD W R
5177 -f R RD RD R
5172 -f R RD RD R
5178 -A W W W R
5173 -A W W W R
5179 -Af R R R R
5174 -Af R R R R
5180 ========= == == == ==
5175 ========= == == == ==
5181
5176
5182 .. note::
5177 .. note::
5183
5178
5184 :hg:`remove` never deletes files in Added [A] state from the
5179 :hg:`remove` never deletes files in Added [A] state from the
5185 working directory, not even if ``--force`` is specified.
5180 working directory, not even if ``--force`` is specified.
5186
5181
5187 Returns 0 on success, 1 if any warnings encountered.
5182 Returns 0 on success, 1 if any warnings encountered.
5188 """
5183 """
5189
5184
5190 after, force = opts.get('after'), opts.get('force')
5185 after, force = opts.get('after'), opts.get('force')
5191 if not pats and not after:
5186 if not pats and not after:
5192 raise error.Abort(_('no files specified'))
5187 raise error.Abort(_('no files specified'))
5193
5188
5194 m = scmutil.match(repo[None], pats, opts)
5189 m = scmutil.match(repo[None], pats, opts)
5195 subrepos = opts.get('subrepos')
5190 subrepos = opts.get('subrepos')
5196 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5191 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5197
5192
5198 @command('rename|move|mv',
5193 @command('rename|move|mv',
5199 [('A', 'after', None, _('record a rename that has already occurred')),
5194 [('A', 'after', None, _('record a rename that has already occurred')),
5200 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5195 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5201 ] + walkopts + dryrunopts,
5196 ] + walkopts + dryrunopts,
5202 _('[OPTION]... SOURCE... DEST'))
5197 _('[OPTION]... SOURCE... DEST'))
5203 def rename(ui, repo, *pats, **opts):
5198 def rename(ui, repo, *pats, **opts):
5204 """rename files; equivalent of copy + remove
5199 """rename files; equivalent of copy + remove
5205
5200
5206 Mark dest as copies of sources; mark sources for deletion. If dest
5201 Mark dest as copies of sources; mark sources for deletion. If dest
5207 is a directory, copies are put in that directory. If dest is a
5202 is a directory, copies are put in that directory. If dest is a
5208 file, there can only be one source.
5203 file, there can only be one source.
5209
5204
5210 By default, this command copies the contents of files as they
5205 By default, this command copies the contents of files as they
5211 exist in the working directory. If invoked with -A/--after, the
5206 exist in the working directory. If invoked with -A/--after, the
5212 operation is recorded, but no copying is performed.
5207 operation is recorded, but no copying is performed.
5213
5208
5214 This command takes effect at the next commit. To undo a rename
5209 This command takes effect at the next commit. To undo a rename
5215 before that, see :hg:`revert`.
5210 before that, see :hg:`revert`.
5216
5211
5217 Returns 0 on success, 1 if errors are encountered.
5212 Returns 0 on success, 1 if errors are encountered.
5218 """
5213 """
5219 with repo.wlock(False):
5214 with repo.wlock(False):
5220 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5215 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5221
5216
5222 @command('resolve',
5217 @command('resolve',
5223 [('a', 'all', None, _('select all unresolved files')),
5218 [('a', 'all', None, _('select all unresolved files')),
5224 ('l', 'list', None, _('list state of files needing merge')),
5219 ('l', 'list', None, _('list state of files needing merge')),
5225 ('m', 'mark', None, _('mark files as resolved')),
5220 ('m', 'mark', None, _('mark files as resolved')),
5226 ('u', 'unmark', None, _('mark files as unresolved')),
5221 ('u', 'unmark', None, _('mark files as unresolved')),
5227 ('n', 'no-status', None, _('hide status prefix'))]
5222 ('n', 'no-status', None, _('hide status prefix'))]
5228 + mergetoolopts + walkopts + formatteropts,
5223 + mergetoolopts + walkopts + formatteropts,
5229 _('[OPTION]... [FILE]...'),
5224 _('[OPTION]... [FILE]...'),
5230 inferrepo=True)
5225 inferrepo=True)
5231 def resolve(ui, repo, *pats, **opts):
5226 def resolve(ui, repo, *pats, **opts):
5232 """redo merges or set/view the merge status of files
5227 """redo merges or set/view the merge status of files
5233
5228
5234 Merges with unresolved conflicts are often the result of
5229 Merges with unresolved conflicts are often the result of
5235 non-interactive merging using the ``internal:merge`` configuration
5230 non-interactive merging using the ``internal:merge`` configuration
5236 setting, or a command-line merge tool like ``diff3``. The resolve
5231 setting, or a command-line merge tool like ``diff3``. The resolve
5237 command is used to manage the files involved in a merge, after
5232 command is used to manage the files involved in a merge, after
5238 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5233 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5239 working directory must have two parents). See :hg:`help
5234 working directory must have two parents). See :hg:`help
5240 merge-tools` for information on configuring merge tools.
5235 merge-tools` for information on configuring merge tools.
5241
5236
5242 The resolve command can be used in the following ways:
5237 The resolve command can be used in the following ways:
5243
5238
5244 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5239 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5245 files, discarding any previous merge attempts. Re-merging is not
5240 files, discarding any previous merge attempts. Re-merging is not
5246 performed for files already marked as resolved. Use ``--all/-a``
5241 performed for files already marked as resolved. Use ``--all/-a``
5247 to select all unresolved files. ``--tool`` can be used to specify
5242 to select all unresolved files. ``--tool`` can be used to specify
5248 the merge tool used for the given files. It overrides the HGMERGE
5243 the merge tool used for the given files. It overrides the HGMERGE
5249 environment variable and your configuration files. Previous file
5244 environment variable and your configuration files. Previous file
5250 contents are saved with a ``.orig`` suffix.
5245 contents are saved with a ``.orig`` suffix.
5251
5246
5252 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5247 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5253 (e.g. after having manually fixed-up the files). The default is
5248 (e.g. after having manually fixed-up the files). The default is
5254 to mark all unresolved files.
5249 to mark all unresolved files.
5255
5250
5256 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5251 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5257 default is to mark all resolved files.
5252 default is to mark all resolved files.
5258
5253
5259 - :hg:`resolve -l`: list files which had or still have conflicts.
5254 - :hg:`resolve -l`: list files which had or still have conflicts.
5260 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5255 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5261
5256
5262 .. note::
5257 .. note::
5263
5258
5264 Mercurial will not let you commit files with unresolved merge
5259 Mercurial will not let you commit files with unresolved merge
5265 conflicts. You must use :hg:`resolve -m ...` before you can
5260 conflicts. You must use :hg:`resolve -m ...` before you can
5266 commit after a conflicting merge.
5261 commit after a conflicting merge.
5267
5262
5268 Returns 0 on success, 1 if any files fail a resolve attempt.
5263 Returns 0 on success, 1 if any files fail a resolve attempt.
5269 """
5264 """
5270
5265
5271 flaglist = 'all mark unmark list no_status'.split()
5266 flaglist = 'all mark unmark list no_status'.split()
5272 all, mark, unmark, show, nostatus = \
5267 all, mark, unmark, show, nostatus = \
5273 [opts.get(o) for o in flaglist]
5268 [opts.get(o) for o in flaglist]
5274
5269
5275 if (show and (mark or unmark)) or (mark and unmark):
5270 if (show and (mark or unmark)) or (mark and unmark):
5276 raise error.Abort(_("too many options specified"))
5271 raise error.Abort(_("too many options specified"))
5277 if pats and all:
5272 if pats and all:
5278 raise error.Abort(_("can't specify --all and patterns"))
5273 raise error.Abort(_("can't specify --all and patterns"))
5279 if not (all or pats or show or mark or unmark):
5274 if not (all or pats or show or mark or unmark):
5280 raise error.Abort(_('no files or directories specified'),
5275 raise error.Abort(_('no files or directories specified'),
5281 hint=('use --all to re-merge all unresolved files'))
5276 hint=('use --all to re-merge all unresolved files'))
5282
5277
5283 if show:
5278 if show:
5284 fm = ui.formatter('resolve', opts)
5279 fm = ui.formatter('resolve', opts)
5285 ms = mergemod.mergestate.read(repo)
5280 ms = mergemod.mergestate.read(repo)
5286 m = scmutil.match(repo[None], pats, opts)
5281 m = scmutil.match(repo[None], pats, opts)
5287 for f in ms:
5282 for f in ms:
5288 if not m(f):
5283 if not m(f):
5289 continue
5284 continue
5290 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5285 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5291 'd': 'driverresolved'}[ms[f]]
5286 'd': 'driverresolved'}[ms[f]]
5292 fm.startitem()
5287 fm.startitem()
5293 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5288 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5294 fm.write('path', '%s\n', f, label=l)
5289 fm.write('path', '%s\n', f, label=l)
5295 fm.end()
5290 fm.end()
5296 return 0
5291 return 0
5297
5292
5298 with repo.wlock():
5293 with repo.wlock():
5299 ms = mergemod.mergestate.read(repo)
5294 ms = mergemod.mergestate.read(repo)
5300
5295
5301 if not (ms.active() or repo.dirstate.p2() != nullid):
5296 if not (ms.active() or repo.dirstate.p2() != nullid):
5302 raise error.Abort(
5297 raise error.Abort(
5303 _('resolve command not applicable when not merging'))
5298 _('resolve command not applicable when not merging'))
5304
5299
5305 wctx = repo[None]
5300 wctx = repo[None]
5306
5301
5307 if ms.mergedriver and ms.mdstate() == 'u':
5302 if ms.mergedriver and ms.mdstate() == 'u':
5308 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5303 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5309 ms.commit()
5304 ms.commit()
5310 # allow mark and unmark to go through
5305 # allow mark and unmark to go through
5311 if not mark and not unmark and not proceed:
5306 if not mark and not unmark and not proceed:
5312 return 1
5307 return 1
5313
5308
5314 m = scmutil.match(wctx, pats, opts)
5309 m = scmutil.match(wctx, pats, opts)
5315 ret = 0
5310 ret = 0
5316 didwork = False
5311 didwork = False
5317 runconclude = False
5312 runconclude = False
5318
5313
5319 tocomplete = []
5314 tocomplete = []
5320 for f in ms:
5315 for f in ms:
5321 if not m(f):
5316 if not m(f):
5322 continue
5317 continue
5323
5318
5324 didwork = True
5319 didwork = True
5325
5320
5326 # don't let driver-resolved files be marked, and run the conclude
5321 # don't let driver-resolved files be marked, and run the conclude
5327 # step if asked to resolve
5322 # step if asked to resolve
5328 if ms[f] == "d":
5323 if ms[f] == "d":
5329 exact = m.exact(f)
5324 exact = m.exact(f)
5330 if mark:
5325 if mark:
5331 if exact:
5326 if exact:
5332 ui.warn(_('not marking %s as it is driver-resolved\n')
5327 ui.warn(_('not marking %s as it is driver-resolved\n')
5333 % f)
5328 % f)
5334 elif unmark:
5329 elif unmark:
5335 if exact:
5330 if exact:
5336 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5331 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5337 % f)
5332 % f)
5338 else:
5333 else:
5339 runconclude = True
5334 runconclude = True
5340 continue
5335 continue
5341
5336
5342 if mark:
5337 if mark:
5343 ms.mark(f, "r")
5338 ms.mark(f, "r")
5344 elif unmark:
5339 elif unmark:
5345 ms.mark(f, "u")
5340 ms.mark(f, "u")
5346 else:
5341 else:
5347 # backup pre-resolve (merge uses .orig for its own purposes)
5342 # backup pre-resolve (merge uses .orig for its own purposes)
5348 a = repo.wjoin(f)
5343 a = repo.wjoin(f)
5349 try:
5344 try:
5350 util.copyfile(a, a + ".resolve")
5345 util.copyfile(a, a + ".resolve")
5351 except (IOError, OSError) as inst:
5346 except (IOError, OSError) as inst:
5352 if inst.errno != errno.ENOENT:
5347 if inst.errno != errno.ENOENT:
5353 raise
5348 raise
5354
5349
5355 try:
5350 try:
5356 # preresolve file
5351 # preresolve file
5357 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5352 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5358 'resolve')
5353 'resolve')
5359 complete, r = ms.preresolve(f, wctx)
5354 complete, r = ms.preresolve(f, wctx)
5360 if not complete:
5355 if not complete:
5361 tocomplete.append(f)
5356 tocomplete.append(f)
5362 elif r:
5357 elif r:
5363 ret = 1
5358 ret = 1
5364 finally:
5359 finally:
5365 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5360 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5366 ms.commit()
5361 ms.commit()
5367
5362
5368 # replace filemerge's .orig file with our resolve file, but only
5363 # replace filemerge's .orig file with our resolve file, but only
5369 # for merges that are complete
5364 # for merges that are complete
5370 if complete:
5365 if complete:
5371 try:
5366 try:
5372 util.rename(a + ".resolve",
5367 util.rename(a + ".resolve",
5373 scmutil.origpath(ui, repo, a))
5368 scmutil.origpath(ui, repo, a))
5374 except OSError as inst:
5369 except OSError as inst:
5375 if inst.errno != errno.ENOENT:
5370 if inst.errno != errno.ENOENT:
5376 raise
5371 raise
5377
5372
5378 for f in tocomplete:
5373 for f in tocomplete:
5379 try:
5374 try:
5380 # resolve file
5375 # resolve file
5381 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5376 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5382 'resolve')
5377 'resolve')
5383 r = ms.resolve(f, wctx)
5378 r = ms.resolve(f, wctx)
5384 if r:
5379 if r:
5385 ret = 1
5380 ret = 1
5386 finally:
5381 finally:
5387 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5382 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5388 ms.commit()
5383 ms.commit()
5389
5384
5390 # replace filemerge's .orig file with our resolve file
5385 # replace filemerge's .orig file with our resolve file
5391 a = repo.wjoin(f)
5386 a = repo.wjoin(f)
5392 try:
5387 try:
5393 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5388 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5394 except OSError as inst:
5389 except OSError as inst:
5395 if inst.errno != errno.ENOENT:
5390 if inst.errno != errno.ENOENT:
5396 raise
5391 raise
5397
5392
5398 ms.commit()
5393 ms.commit()
5399 ms.recordactions()
5394 ms.recordactions()
5400
5395
5401 if not didwork and pats:
5396 if not didwork and pats:
5402 hint = None
5397 hint = None
5403 if not any([p for p in pats if p.find(':') >= 0]):
5398 if not any([p for p in pats if p.find(':') >= 0]):
5404 pats = ['path:%s' % p for p in pats]
5399 pats = ['path:%s' % p for p in pats]
5405 m = scmutil.match(wctx, pats, opts)
5400 m = scmutil.match(wctx, pats, opts)
5406 for f in ms:
5401 for f in ms:
5407 if not m(f):
5402 if not m(f):
5408 continue
5403 continue
5409 flags = ''.join(['-%s ' % o[0] for o in flaglist
5404 flags = ''.join(['-%s ' % o[0] for o in flaglist
5410 if opts.get(o)])
5405 if opts.get(o)])
5411 hint = _("(try: hg resolve %s%s)\n") % (
5406 hint = _("(try: hg resolve %s%s)\n") % (
5412 flags,
5407 flags,
5413 ' '.join(pats))
5408 ' '.join(pats))
5414 break
5409 break
5415 ui.warn(_("arguments do not match paths that need resolving\n"))
5410 ui.warn(_("arguments do not match paths that need resolving\n"))
5416 if hint:
5411 if hint:
5417 ui.warn(hint)
5412 ui.warn(hint)
5418 elif ms.mergedriver and ms.mdstate() != 's':
5413 elif ms.mergedriver and ms.mdstate() != 's':
5419 # run conclude step when either a driver-resolved file is requested
5414 # run conclude step when either a driver-resolved file is requested
5420 # or there are no driver-resolved files
5415 # or there are no driver-resolved files
5421 # we can't use 'ret' to determine whether any files are unresolved
5416 # we can't use 'ret' to determine whether any files are unresolved
5422 # because we might not have tried to resolve some
5417 # because we might not have tried to resolve some
5423 if ((runconclude or not list(ms.driverresolved()))
5418 if ((runconclude or not list(ms.driverresolved()))
5424 and not list(ms.unresolved())):
5419 and not list(ms.unresolved())):
5425 proceed = mergemod.driverconclude(repo, ms, wctx)
5420 proceed = mergemod.driverconclude(repo, ms, wctx)
5426 ms.commit()
5421 ms.commit()
5427 if not proceed:
5422 if not proceed:
5428 return 1
5423 return 1
5429
5424
5430 # Nudge users into finishing an unfinished operation
5425 # Nudge users into finishing an unfinished operation
5431 unresolvedf = list(ms.unresolved())
5426 unresolvedf = list(ms.unresolved())
5432 driverresolvedf = list(ms.driverresolved())
5427 driverresolvedf = list(ms.driverresolved())
5433 if not unresolvedf and not driverresolvedf:
5428 if not unresolvedf and not driverresolvedf:
5434 ui.status(_('(no more unresolved files)\n'))
5429 ui.status(_('(no more unresolved files)\n'))
5435 cmdutil.checkafterresolved(repo)
5430 cmdutil.checkafterresolved(repo)
5436 elif not unresolvedf:
5431 elif not unresolvedf:
5437 ui.status(_('(no more unresolved files -- '
5432 ui.status(_('(no more unresolved files -- '
5438 'run "hg resolve --all" to conclude)\n'))
5433 'run "hg resolve --all" to conclude)\n'))
5439
5434
5440 return ret
5435 return ret
5441
5436
5442 @command('revert',
5437 @command('revert',
5443 [('a', 'all', None, _('revert all changes when no arguments given')),
5438 [('a', 'all', None, _('revert all changes when no arguments given')),
5444 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5439 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5445 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5440 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5446 ('C', 'no-backup', None, _('do not save backup copies of files')),
5441 ('C', 'no-backup', None, _('do not save backup copies of files')),
5447 ('i', 'interactive', None,
5442 ('i', 'interactive', None,
5448 _('interactively select the changes (EXPERIMENTAL)')),
5443 _('interactively select the changes (EXPERIMENTAL)')),
5449 ] + walkopts + dryrunopts,
5444 ] + walkopts + dryrunopts,
5450 _('[OPTION]... [-r REV] [NAME]...'))
5445 _('[OPTION]... [-r REV] [NAME]...'))
5451 def revert(ui, repo, *pats, **opts):
5446 def revert(ui, repo, *pats, **opts):
5452 """restore files to their checkout state
5447 """restore files to their checkout state
5453
5448
5454 .. note::
5449 .. note::
5455
5450
5456 To check out earlier revisions, you should use :hg:`update REV`.
5451 To check out earlier revisions, you should use :hg:`update REV`.
5457 To cancel an uncommitted merge (and lose your changes),
5452 To cancel an uncommitted merge (and lose your changes),
5458 use :hg:`update --clean .`.
5453 use :hg:`update --clean .`.
5459
5454
5460 With no revision specified, revert the specified files or directories
5455 With no revision specified, revert the specified files or directories
5461 to the contents they had in the parent of the working directory.
5456 to the contents they had in the parent of the working directory.
5462 This restores the contents of files to an unmodified
5457 This restores the contents of files to an unmodified
5463 state and unschedules adds, removes, copies, and renames. If the
5458 state and unschedules adds, removes, copies, and renames. If the
5464 working directory has two parents, you must explicitly specify a
5459 working directory has two parents, you must explicitly specify a
5465 revision.
5460 revision.
5466
5461
5467 Using the -r/--rev or -d/--date options, revert the given files or
5462 Using the -r/--rev or -d/--date options, revert the given files or
5468 directories to their states as of a specific revision. Because
5463 directories to their states as of a specific revision. Because
5469 revert does not change the working directory parents, this will
5464 revert does not change the working directory parents, this will
5470 cause these files to appear modified. This can be helpful to "back
5465 cause these files to appear modified. This can be helpful to "back
5471 out" some or all of an earlier change. See :hg:`backout` for a
5466 out" some or all of an earlier change. See :hg:`backout` for a
5472 related method.
5467 related method.
5473
5468
5474 Modified files are saved with a .orig suffix before reverting.
5469 Modified files are saved with a .orig suffix before reverting.
5475 To disable these backups, use --no-backup. It is possible to store
5470 To disable these backups, use --no-backup. It is possible to store
5476 the backup files in a custom directory relative to the root of the
5471 the backup files in a custom directory relative to the root of the
5477 repository by setting the ``ui.origbackuppath`` configuration
5472 repository by setting the ``ui.origbackuppath`` configuration
5478 option.
5473 option.
5479
5474
5480 See :hg:`help dates` for a list of formats valid for -d/--date.
5475 See :hg:`help dates` for a list of formats valid for -d/--date.
5481
5476
5482 See :hg:`help backout` for a way to reverse the effect of an
5477 See :hg:`help backout` for a way to reverse the effect of an
5483 earlier changeset.
5478 earlier changeset.
5484
5479
5485 Returns 0 on success.
5480 Returns 0 on success.
5486 """
5481 """
5487
5482
5488 if opts.get("date"):
5483 if opts.get("date"):
5489 if opts.get("rev"):
5484 if opts.get("rev"):
5490 raise error.Abort(_("you can't specify a revision and a date"))
5485 raise error.Abort(_("you can't specify a revision and a date"))
5491 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5486 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5492
5487
5493 parent, p2 = repo.dirstate.parents()
5488 parent, p2 = repo.dirstate.parents()
5494 if not opts.get('rev') and p2 != nullid:
5489 if not opts.get('rev') and p2 != nullid:
5495 # revert after merge is a trap for new users (issue2915)
5490 # revert after merge is a trap for new users (issue2915)
5496 raise error.Abort(_('uncommitted merge with no revision specified'),
5491 raise error.Abort(_('uncommitted merge with no revision specified'),
5497 hint=_("use 'hg update' or see 'hg help revert'"))
5492 hint=_("use 'hg update' or see 'hg help revert'"))
5498
5493
5499 ctx = scmutil.revsingle(repo, opts.get('rev'))
5494 ctx = scmutil.revsingle(repo, opts.get('rev'))
5500
5495
5501 if (not (pats or opts.get('include') or opts.get('exclude') or
5496 if (not (pats or opts.get('include') or opts.get('exclude') or
5502 opts.get('all') or opts.get('interactive'))):
5497 opts.get('all') or opts.get('interactive'))):
5503 msg = _("no files or directories specified")
5498 msg = _("no files or directories specified")
5504 if p2 != nullid:
5499 if p2 != nullid:
5505 hint = _("uncommitted merge, use --all to discard all changes,"
5500 hint = _("uncommitted merge, use --all to discard all changes,"
5506 " or 'hg update -C .' to abort the merge")
5501 " or 'hg update -C .' to abort the merge")
5507 raise error.Abort(msg, hint=hint)
5502 raise error.Abort(msg, hint=hint)
5508 dirty = any(repo.status())
5503 dirty = any(repo.status())
5509 node = ctx.node()
5504 node = ctx.node()
5510 if node != parent:
5505 if node != parent:
5511 if dirty:
5506 if dirty:
5512 hint = _("uncommitted changes, use --all to discard all"
5507 hint = _("uncommitted changes, use --all to discard all"
5513 " changes, or 'hg update %s' to update") % ctx.rev()
5508 " changes, or 'hg update %s' to update") % ctx.rev()
5514 else:
5509 else:
5515 hint = _("use --all to revert all files,"
5510 hint = _("use --all to revert all files,"
5516 " or 'hg update %s' to update") % ctx.rev()
5511 " or 'hg update %s' to update") % ctx.rev()
5517 elif dirty:
5512 elif dirty:
5518 hint = _("uncommitted changes, use --all to discard all changes")
5513 hint = _("uncommitted changes, use --all to discard all changes")
5519 else:
5514 else:
5520 hint = _("use --all to revert all files")
5515 hint = _("use --all to revert all files")
5521 raise error.Abort(msg, hint=hint)
5516 raise error.Abort(msg, hint=hint)
5522
5517
5523 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5518 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5524
5519
5525 @command('rollback', dryrunopts +
5520 @command('rollback', dryrunopts +
5526 [('f', 'force', False, _('ignore safety measures'))])
5521 [('f', 'force', False, _('ignore safety measures'))])
5527 def rollback(ui, repo, **opts):
5522 def rollback(ui, repo, **opts):
5528 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5523 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5529
5524
5530 Please use :hg:`commit --amend` instead of rollback to correct
5525 Please use :hg:`commit --amend` instead of rollback to correct
5531 mistakes in the last commit.
5526 mistakes in the last commit.
5532
5527
5533 This command should be used with care. There is only one level of
5528 This command should be used with care. There is only one level of
5534 rollback, and there is no way to undo a rollback. It will also
5529 rollback, and there is no way to undo a rollback. It will also
5535 restore the dirstate at the time of the last transaction, losing
5530 restore the dirstate at the time of the last transaction, losing
5536 any dirstate changes since that time. This command does not alter
5531 any dirstate changes since that time. This command does not alter
5537 the working directory.
5532 the working directory.
5538
5533
5539 Transactions are used to encapsulate the effects of all commands
5534 Transactions are used to encapsulate the effects of all commands
5540 that create new changesets or propagate existing changesets into a
5535 that create new changesets or propagate existing changesets into a
5541 repository.
5536 repository.
5542
5537
5543 .. container:: verbose
5538 .. container:: verbose
5544
5539
5545 For example, the following commands are transactional, and their
5540 For example, the following commands are transactional, and their
5546 effects can be rolled back:
5541 effects can be rolled back:
5547
5542
5548 - commit
5543 - commit
5549 - import
5544 - import
5550 - pull
5545 - pull
5551 - push (with this repository as the destination)
5546 - push (with this repository as the destination)
5552 - unbundle
5547 - unbundle
5553
5548
5554 To avoid permanent data loss, rollback will refuse to rollback a
5549 To avoid permanent data loss, rollback will refuse to rollback a
5555 commit transaction if it isn't checked out. Use --force to
5550 commit transaction if it isn't checked out. Use --force to
5556 override this protection.
5551 override this protection.
5557
5552
5558 The rollback command can be entirely disabled by setting the
5553 The rollback command can be entirely disabled by setting the
5559 ``ui.rollback`` configuration setting to false. If you're here
5554 ``ui.rollback`` configuration setting to false. If you're here
5560 because you want to use rollback and it's disabled, you can
5555 because you want to use rollback and it's disabled, you can
5561 re-enable the command by setting ``ui.rollback`` to true.
5556 re-enable the command by setting ``ui.rollback`` to true.
5562
5557
5563 This command is not intended for use on public repositories. Once
5558 This command is not intended for use on public repositories. Once
5564 changes are visible for pull by other users, rolling a transaction
5559 changes are visible for pull by other users, rolling a transaction
5565 back locally is ineffective (someone else may already have pulled
5560 back locally is ineffective (someone else may already have pulled
5566 the changes). Furthermore, a race is possible with readers of the
5561 the changes). Furthermore, a race is possible with readers of the
5567 repository; for example an in-progress pull from the repository
5562 repository; for example an in-progress pull from the repository
5568 may fail if a rollback is performed.
5563 may fail if a rollback is performed.
5569
5564
5570 Returns 0 on success, 1 if no rollback data is available.
5565 Returns 0 on success, 1 if no rollback data is available.
5571 """
5566 """
5572 if not ui.configbool('ui', 'rollback', True):
5567 if not ui.configbool('ui', 'rollback', True):
5573 raise error.Abort(_('rollback is disabled because it is unsafe'),
5568 raise error.Abort(_('rollback is disabled because it is unsafe'),
5574 hint=('see `hg help -v rollback` for information'))
5569 hint=('see `hg help -v rollback` for information'))
5575 return repo.rollback(dryrun=opts.get('dry_run'),
5570 return repo.rollback(dryrun=opts.get('dry_run'),
5576 force=opts.get('force'))
5571 force=opts.get('force'))
5577
5572
5578 @command('root', [])
5573 @command('root', [])
5579 def root(ui, repo):
5574 def root(ui, repo):
5580 """print the root (top) of the current working directory
5575 """print the root (top) of the current working directory
5581
5576
5582 Print the root directory of the current repository.
5577 Print the root directory of the current repository.
5583
5578
5584 Returns 0 on success.
5579 Returns 0 on success.
5585 """
5580 """
5586 ui.write(repo.root + "\n")
5581 ui.write(repo.root + "\n")
5587
5582
5588 @command('^serve',
5583 @command('^serve',
5589 [('A', 'accesslog', '', _('name of access log file to write to'),
5584 [('A', 'accesslog', '', _('name of access log file to write to'),
5590 _('FILE')),
5585 _('FILE')),
5591 ('d', 'daemon', None, _('run server in background')),
5586 ('d', 'daemon', None, _('run server in background')),
5592 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5587 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5593 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5588 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5594 # use string type, then we can check if something was passed
5589 # use string type, then we can check if something was passed
5595 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5590 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5596 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5591 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5597 _('ADDR')),
5592 _('ADDR')),
5598 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5593 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5599 _('PREFIX')),
5594 _('PREFIX')),
5600 ('n', 'name', '',
5595 ('n', 'name', '',
5601 _('name to show in web pages (default: working directory)'), _('NAME')),
5596 _('name to show in web pages (default: working directory)'), _('NAME')),
5602 ('', 'web-conf', '',
5597 ('', 'web-conf', '',
5603 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5598 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5604 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5599 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5605 _('FILE')),
5600 _('FILE')),
5606 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5601 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5607 ('', 'stdio', None, _('for remote clients')),
5602 ('', 'stdio', None, _('for remote clients')),
5608 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5603 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5609 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5604 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5610 ('', 'style', '', _('template style to use'), _('STYLE')),
5605 ('', 'style', '', _('template style to use'), _('STYLE')),
5611 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5606 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5612 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5607 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5613 _('[OPTION]...'),
5608 _('[OPTION]...'),
5614 optionalrepo=True)
5609 optionalrepo=True)
5615 def serve(ui, repo, **opts):
5610 def serve(ui, repo, **opts):
5616 """start stand-alone webserver
5611 """start stand-alone webserver
5617
5612
5618 Start a local HTTP repository browser and pull server. You can use
5613 Start a local HTTP repository browser and pull server. You can use
5619 this for ad-hoc sharing and browsing of repositories. It is
5614 this for ad-hoc sharing and browsing of repositories. It is
5620 recommended to use a real web server to serve a repository for
5615 recommended to use a real web server to serve a repository for
5621 longer periods of time.
5616 longer periods of time.
5622
5617
5623 Please note that the server does not implement access control.
5618 Please note that the server does not implement access control.
5624 This means that, by default, anybody can read from the server and
5619 This means that, by default, anybody can read from the server and
5625 nobody can write to it by default. Set the ``web.allow_push``
5620 nobody can write to it by default. Set the ``web.allow_push``
5626 option to ``*`` to allow everybody to push to the server. You
5621 option to ``*`` to allow everybody to push to the server. You
5627 should use a real web server if you need to authenticate users.
5622 should use a real web server if you need to authenticate users.
5628
5623
5629 By default, the server logs accesses to stdout and errors to
5624 By default, the server logs accesses to stdout and errors to
5630 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5625 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5631 files.
5626 files.
5632
5627
5633 To have the server choose a free port number to listen on, specify
5628 To have the server choose a free port number to listen on, specify
5634 a port number of 0; in this case, the server will print the port
5629 a port number of 0; in this case, the server will print the port
5635 number it uses.
5630 number it uses.
5636
5631
5637 Returns 0 on success.
5632 Returns 0 on success.
5638 """
5633 """
5639
5634
5640 if opts["stdio"] and opts["cmdserver"]:
5635 if opts["stdio"] and opts["cmdserver"]:
5641 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5636 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5642
5637
5643 if opts["stdio"]:
5638 if opts["stdio"]:
5644 if repo is None:
5639 if repo is None:
5645 raise error.RepoError(_("there is no Mercurial repository here"
5640 raise error.RepoError(_("there is no Mercurial repository here"
5646 " (.hg not found)"))
5641 " (.hg not found)"))
5647 s = sshserver.sshserver(ui, repo)
5642 s = sshserver.sshserver(ui, repo)
5648 s.serve_forever()
5643 s.serve_forever()
5649
5644
5650 service = server.createservice(ui, repo, opts)
5645 service = server.createservice(ui, repo, opts)
5651 return server.runservice(opts, initfn=service.init, runfn=service.run)
5646 return server.runservice(opts, initfn=service.init, runfn=service.run)
5652
5647
5653 @command('^status|st',
5648 @command('^status|st',
5654 [('A', 'all', None, _('show status of all files')),
5649 [('A', 'all', None, _('show status of all files')),
5655 ('m', 'modified', None, _('show only modified files')),
5650 ('m', 'modified', None, _('show only modified files')),
5656 ('a', 'added', None, _('show only added files')),
5651 ('a', 'added', None, _('show only added files')),
5657 ('r', 'removed', None, _('show only removed files')),
5652 ('r', 'removed', None, _('show only removed files')),
5658 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5653 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5659 ('c', 'clean', None, _('show only files without changes')),
5654 ('c', 'clean', None, _('show only files without changes')),
5660 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5655 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5661 ('i', 'ignored', None, _('show only ignored files')),
5656 ('i', 'ignored', None, _('show only ignored files')),
5662 ('n', 'no-status', None, _('hide status prefix')),
5657 ('n', 'no-status', None, _('hide status prefix')),
5663 ('C', 'copies', None, _('show source of copied files')),
5658 ('C', 'copies', None, _('show source of copied files')),
5664 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5659 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5665 ('', 'rev', [], _('show difference from revision'), _('REV')),
5660 ('', 'rev', [], _('show difference from revision'), _('REV')),
5666 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5661 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5667 ] + walkopts + subrepoopts + formatteropts,
5662 ] + walkopts + subrepoopts + formatteropts,
5668 _('[OPTION]... [FILE]...'),
5663 _('[OPTION]... [FILE]...'),
5669 inferrepo=True)
5664 inferrepo=True)
5670 def status(ui, repo, *pats, **opts):
5665 def status(ui, repo, *pats, **opts):
5671 """show changed files in the working directory
5666 """show changed files in the working directory
5672
5667
5673 Show status of files in the repository. If names are given, only
5668 Show status of files in the repository. If names are given, only
5674 files that match are shown. Files that are clean or ignored or
5669 files that match are shown. Files that are clean or ignored or
5675 the source of a copy/move operation, are not listed unless
5670 the source of a copy/move operation, are not listed unless
5676 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5671 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5677 Unless options described with "show only ..." are given, the
5672 Unless options described with "show only ..." are given, the
5678 options -mardu are used.
5673 options -mardu are used.
5679
5674
5680 Option -q/--quiet hides untracked (unknown and ignored) files
5675 Option -q/--quiet hides untracked (unknown and ignored) files
5681 unless explicitly requested with -u/--unknown or -i/--ignored.
5676 unless explicitly requested with -u/--unknown or -i/--ignored.
5682
5677
5683 .. note::
5678 .. note::
5684
5679
5685 :hg:`status` may appear to disagree with diff if permissions have
5680 :hg:`status` may appear to disagree with diff if permissions have
5686 changed or a merge has occurred. The standard diff format does
5681 changed or a merge has occurred. The standard diff format does
5687 not report permission changes and diff only reports changes
5682 not report permission changes and diff only reports changes
5688 relative to one merge parent.
5683 relative to one merge parent.
5689
5684
5690 If one revision is given, it is used as the base revision.
5685 If one revision is given, it is used as the base revision.
5691 If two revisions are given, the differences between them are
5686 If two revisions are given, the differences between them are
5692 shown. The --change option can also be used as a shortcut to list
5687 shown. The --change option can also be used as a shortcut to list
5693 the changed files of a revision from its first parent.
5688 the changed files of a revision from its first parent.
5694
5689
5695 The codes used to show the status of files are::
5690 The codes used to show the status of files are::
5696
5691
5697 M = modified
5692 M = modified
5698 A = added
5693 A = added
5699 R = removed
5694 R = removed
5700 C = clean
5695 C = clean
5701 ! = missing (deleted by non-hg command, but still tracked)
5696 ! = missing (deleted by non-hg command, but still tracked)
5702 ? = not tracked
5697 ? = not tracked
5703 I = ignored
5698 I = ignored
5704 = origin of the previous file (with --copies)
5699 = origin of the previous file (with --copies)
5705
5700
5706 .. container:: verbose
5701 .. container:: verbose
5707
5702
5708 Examples:
5703 Examples:
5709
5704
5710 - show changes in the working directory relative to a
5705 - show changes in the working directory relative to a
5711 changeset::
5706 changeset::
5712
5707
5713 hg status --rev 9353
5708 hg status --rev 9353
5714
5709
5715 - show changes in the working directory relative to the
5710 - show changes in the working directory relative to the
5716 current directory (see :hg:`help patterns` for more information)::
5711 current directory (see :hg:`help patterns` for more information)::
5717
5712
5718 hg status re:
5713 hg status re:
5719
5714
5720 - show all changes including copies in an existing changeset::
5715 - show all changes including copies in an existing changeset::
5721
5716
5722 hg status --copies --change 9353
5717 hg status --copies --change 9353
5723
5718
5724 - get a NUL separated list of added files, suitable for xargs::
5719 - get a NUL separated list of added files, suitable for xargs::
5725
5720
5726 hg status -an0
5721 hg status -an0
5727
5722
5728 Returns 0 on success.
5723 Returns 0 on success.
5729 """
5724 """
5730
5725
5731 revs = opts.get('rev')
5726 revs = opts.get('rev')
5732 change = opts.get('change')
5727 change = opts.get('change')
5733
5728
5734 if revs and change:
5729 if revs and change:
5735 msg = _('cannot specify --rev and --change at the same time')
5730 msg = _('cannot specify --rev and --change at the same time')
5736 raise error.Abort(msg)
5731 raise error.Abort(msg)
5737 elif change:
5732 elif change:
5738 node2 = scmutil.revsingle(repo, change, None).node()
5733 node2 = scmutil.revsingle(repo, change, None).node()
5739 node1 = repo[node2].p1().node()
5734 node1 = repo[node2].p1().node()
5740 else:
5735 else:
5741 node1, node2 = scmutil.revpair(repo, revs)
5736 node1, node2 = scmutil.revpair(repo, revs)
5742
5737
5743 if pats:
5738 if pats:
5744 cwd = repo.getcwd()
5739 cwd = repo.getcwd()
5745 else:
5740 else:
5746 cwd = ''
5741 cwd = ''
5747
5742
5748 if opts.get('print0'):
5743 if opts.get('print0'):
5749 end = '\0'
5744 end = '\0'
5750 else:
5745 else:
5751 end = '\n'
5746 end = '\n'
5752 copy = {}
5747 copy = {}
5753 states = 'modified added removed deleted unknown ignored clean'.split()
5748 states = 'modified added removed deleted unknown ignored clean'.split()
5754 show = [k for k in states if opts.get(k)]
5749 show = [k for k in states if opts.get(k)]
5755 if opts.get('all'):
5750 if opts.get('all'):
5756 show += ui.quiet and (states[:4] + ['clean']) or states
5751 show += ui.quiet and (states[:4] + ['clean']) or states
5757 if not show:
5752 if not show:
5758 if ui.quiet:
5753 if ui.quiet:
5759 show = states[:4]
5754 show = states[:4]
5760 else:
5755 else:
5761 show = states[:5]
5756 show = states[:5]
5762
5757
5763 m = scmutil.match(repo[node2], pats, opts)
5758 m = scmutil.match(repo[node2], pats, opts)
5764 stat = repo.status(node1, node2, m,
5759 stat = repo.status(node1, node2, m,
5765 'ignored' in show, 'clean' in show, 'unknown' in show,
5760 'ignored' in show, 'clean' in show, 'unknown' in show,
5766 opts.get('subrepos'))
5761 opts.get('subrepos'))
5767 changestates = zip(states, 'MAR!?IC', stat)
5762 changestates = zip(states, 'MAR!?IC', stat)
5768
5763
5769 if (opts.get('all') or opts.get('copies')
5764 if (opts.get('all') or opts.get('copies')
5770 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5765 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5771 copy = copies.pathcopies(repo[node1], repo[node2], m)
5766 copy = copies.pathcopies(repo[node1], repo[node2], m)
5772
5767
5773 fm = ui.formatter('status', opts)
5768 fm = ui.formatter('status', opts)
5774 fmt = '%s' + end
5769 fmt = '%s' + end
5775 showchar = not opts.get('no_status')
5770 showchar = not opts.get('no_status')
5776
5771
5777 for state, char, files in changestates:
5772 for state, char, files in changestates:
5778 if state in show:
5773 if state in show:
5779 label = 'status.' + state
5774 label = 'status.' + state
5780 for f in files:
5775 for f in files:
5781 fm.startitem()
5776 fm.startitem()
5782 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5777 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5783 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5778 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5784 if f in copy:
5779 if f in copy:
5785 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5780 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5786 label='status.copied')
5781 label='status.copied')
5787 fm.end()
5782 fm.end()
5788
5783
5789 @command('^summary|sum',
5784 @command('^summary|sum',
5790 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5785 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5791 def summary(ui, repo, **opts):
5786 def summary(ui, repo, **opts):
5792 """summarize working directory state
5787 """summarize working directory state
5793
5788
5794 This generates a brief summary of the working directory state,
5789 This generates a brief summary of the working directory state,
5795 including parents, branch, commit status, phase and available updates.
5790 including parents, branch, commit status, phase and available updates.
5796
5791
5797 With the --remote option, this will check the default paths for
5792 With the --remote option, this will check the default paths for
5798 incoming and outgoing changes. This can be time-consuming.
5793 incoming and outgoing changes. This can be time-consuming.
5799
5794
5800 Returns 0 on success.
5795 Returns 0 on success.
5801 """
5796 """
5802
5797
5803 ctx = repo[None]
5798 ctx = repo[None]
5804 parents = ctx.parents()
5799 parents = ctx.parents()
5805 pnode = parents[0].node()
5800 pnode = parents[0].node()
5806 marks = []
5801 marks = []
5807
5802
5808 ms = None
5803 ms = None
5809 try:
5804 try:
5810 ms = mergemod.mergestate.read(repo)
5805 ms = mergemod.mergestate.read(repo)
5811 except error.UnsupportedMergeRecords as e:
5806 except error.UnsupportedMergeRecords as e:
5812 s = ' '.join(e.recordtypes)
5807 s = ' '.join(e.recordtypes)
5813 ui.warn(
5808 ui.warn(
5814 _('warning: merge state has unsupported record types: %s\n') % s)
5809 _('warning: merge state has unsupported record types: %s\n') % s)
5815 unresolved = 0
5810 unresolved = 0
5816 else:
5811 else:
5817 unresolved = [f for f in ms if ms[f] == 'u']
5812 unresolved = [f for f in ms if ms[f] == 'u']
5818
5813
5819 for p in parents:
5814 for p in parents:
5820 # label with log.changeset (instead of log.parent) since this
5815 # label with log.changeset (instead of log.parent) since this
5821 # shows a working directory parent *changeset*:
5816 # shows a working directory parent *changeset*:
5822 # i18n: column positioning for "hg summary"
5817 # i18n: column positioning for "hg summary"
5823 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5818 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5824 label=cmdutil._changesetlabels(p))
5819 label=cmdutil._changesetlabels(p))
5825 ui.write(' '.join(p.tags()), label='log.tag')
5820 ui.write(' '.join(p.tags()), label='log.tag')
5826 if p.bookmarks():
5821 if p.bookmarks():
5827 marks.extend(p.bookmarks())
5822 marks.extend(p.bookmarks())
5828 if p.rev() == -1:
5823 if p.rev() == -1:
5829 if not len(repo):
5824 if not len(repo):
5830 ui.write(_(' (empty repository)'))
5825 ui.write(_(' (empty repository)'))
5831 else:
5826 else:
5832 ui.write(_(' (no revision checked out)'))
5827 ui.write(_(' (no revision checked out)'))
5833 if p.troubled():
5828 if p.troubled():
5834 ui.write(' ('
5829 ui.write(' ('
5835 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5830 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5836 for trouble in p.troubles())
5831 for trouble in p.troubles())
5837 + ')')
5832 + ')')
5838 ui.write('\n')
5833 ui.write('\n')
5839 if p.description():
5834 if p.description():
5840 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5835 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5841 label='log.summary')
5836 label='log.summary')
5842
5837
5843 branch = ctx.branch()
5838 branch = ctx.branch()
5844 bheads = repo.branchheads(branch)
5839 bheads = repo.branchheads(branch)
5845 # i18n: column positioning for "hg summary"
5840 # i18n: column positioning for "hg summary"
5846 m = _('branch: %s\n') % branch
5841 m = _('branch: %s\n') % branch
5847 if branch != 'default':
5842 if branch != 'default':
5848 ui.write(m, label='log.branch')
5843 ui.write(m, label='log.branch')
5849 else:
5844 else:
5850 ui.status(m, label='log.branch')
5845 ui.status(m, label='log.branch')
5851
5846
5852 if marks:
5847 if marks:
5853 active = repo._activebookmark
5848 active = repo._activebookmark
5854 # i18n: column positioning for "hg summary"
5849 # i18n: column positioning for "hg summary"
5855 ui.write(_('bookmarks:'), label='log.bookmark')
5850 ui.write(_('bookmarks:'), label='log.bookmark')
5856 if active is not None:
5851 if active is not None:
5857 if active in marks:
5852 if active in marks:
5858 ui.write(' *' + active, label=activebookmarklabel)
5853 ui.write(' *' + active, label=activebookmarklabel)
5859 marks.remove(active)
5854 marks.remove(active)
5860 else:
5855 else:
5861 ui.write(' [%s]' % active, label=activebookmarklabel)
5856 ui.write(' [%s]' % active, label=activebookmarklabel)
5862 for m in marks:
5857 for m in marks:
5863 ui.write(' ' + m, label='log.bookmark')
5858 ui.write(' ' + m, label='log.bookmark')
5864 ui.write('\n', label='log.bookmark')
5859 ui.write('\n', label='log.bookmark')
5865
5860
5866 status = repo.status(unknown=True)
5861 status = repo.status(unknown=True)
5867
5862
5868 c = repo.dirstate.copies()
5863 c = repo.dirstate.copies()
5869 copied, renamed = [], []
5864 copied, renamed = [], []
5870 for d, s in c.iteritems():
5865 for d, s in c.iteritems():
5871 if s in status.removed:
5866 if s in status.removed:
5872 status.removed.remove(s)
5867 status.removed.remove(s)
5873 renamed.append(d)
5868 renamed.append(d)
5874 else:
5869 else:
5875 copied.append(d)
5870 copied.append(d)
5876 if d in status.added:
5871 if d in status.added:
5877 status.added.remove(d)
5872 status.added.remove(d)
5878
5873
5879 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5874 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5880
5875
5881 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5876 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5882 (ui.label(_('%d added'), 'status.added'), status.added),
5877 (ui.label(_('%d added'), 'status.added'), status.added),
5883 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5878 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5884 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5879 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5885 (ui.label(_('%d copied'), 'status.copied'), copied),
5880 (ui.label(_('%d copied'), 'status.copied'), copied),
5886 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5881 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5887 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5882 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5888 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5883 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5889 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5884 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5890 t = []
5885 t = []
5891 for l, s in labels:
5886 for l, s in labels:
5892 if s:
5887 if s:
5893 t.append(l % len(s))
5888 t.append(l % len(s))
5894
5889
5895 t = ', '.join(t)
5890 t = ', '.join(t)
5896 cleanworkdir = False
5891 cleanworkdir = False
5897
5892
5898 if repo.vfs.exists('graftstate'):
5893 if repo.vfs.exists('graftstate'):
5899 t += _(' (graft in progress)')
5894 t += _(' (graft in progress)')
5900 if repo.vfs.exists('updatestate'):
5895 if repo.vfs.exists('updatestate'):
5901 t += _(' (interrupted update)')
5896 t += _(' (interrupted update)')
5902 elif len(parents) > 1:
5897 elif len(parents) > 1:
5903 t += _(' (merge)')
5898 t += _(' (merge)')
5904 elif branch != parents[0].branch():
5899 elif branch != parents[0].branch():
5905 t += _(' (new branch)')
5900 t += _(' (new branch)')
5906 elif (parents[0].closesbranch() and
5901 elif (parents[0].closesbranch() and
5907 pnode in repo.branchheads(branch, closed=True)):
5902 pnode in repo.branchheads(branch, closed=True)):
5908 t += _(' (head closed)')
5903 t += _(' (head closed)')
5909 elif not (status.modified or status.added or status.removed or renamed or
5904 elif not (status.modified or status.added or status.removed or renamed or
5910 copied or subs):
5905 copied or subs):
5911 t += _(' (clean)')
5906 t += _(' (clean)')
5912 cleanworkdir = True
5907 cleanworkdir = True
5913 elif pnode not in bheads:
5908 elif pnode not in bheads:
5914 t += _(' (new branch head)')
5909 t += _(' (new branch head)')
5915
5910
5916 if parents:
5911 if parents:
5917 pendingphase = max(p.phase() for p in parents)
5912 pendingphase = max(p.phase() for p in parents)
5918 else:
5913 else:
5919 pendingphase = phases.public
5914 pendingphase = phases.public
5920
5915
5921 if pendingphase > phases.newcommitphase(ui):
5916 if pendingphase > phases.newcommitphase(ui):
5922 t += ' (%s)' % phases.phasenames[pendingphase]
5917 t += ' (%s)' % phases.phasenames[pendingphase]
5923
5918
5924 if cleanworkdir:
5919 if cleanworkdir:
5925 # i18n: column positioning for "hg summary"
5920 # i18n: column positioning for "hg summary"
5926 ui.status(_('commit: %s\n') % t.strip())
5921 ui.status(_('commit: %s\n') % t.strip())
5927 else:
5922 else:
5928 # i18n: column positioning for "hg summary"
5923 # i18n: column positioning for "hg summary"
5929 ui.write(_('commit: %s\n') % t.strip())
5924 ui.write(_('commit: %s\n') % t.strip())
5930
5925
5931 # all ancestors of branch heads - all ancestors of parent = new csets
5926 # all ancestors of branch heads - all ancestors of parent = new csets
5932 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5927 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5933 bheads))
5928 bheads))
5934
5929
5935 if new == 0:
5930 if new == 0:
5936 # i18n: column positioning for "hg summary"
5931 # i18n: column positioning for "hg summary"
5937 ui.status(_('update: (current)\n'))
5932 ui.status(_('update: (current)\n'))
5938 elif pnode not in bheads:
5933 elif pnode not in bheads:
5939 # i18n: column positioning for "hg summary"
5934 # i18n: column positioning for "hg summary"
5940 ui.write(_('update: %d new changesets (update)\n') % new)
5935 ui.write(_('update: %d new changesets (update)\n') % new)
5941 else:
5936 else:
5942 # i18n: column positioning for "hg summary"
5937 # i18n: column positioning for "hg summary"
5943 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5938 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5944 (new, len(bheads)))
5939 (new, len(bheads)))
5945
5940
5946 t = []
5941 t = []
5947 draft = len(repo.revs('draft()'))
5942 draft = len(repo.revs('draft()'))
5948 if draft:
5943 if draft:
5949 t.append(_('%d draft') % draft)
5944 t.append(_('%d draft') % draft)
5950 secret = len(repo.revs('secret()'))
5945 secret = len(repo.revs('secret()'))
5951 if secret:
5946 if secret:
5952 t.append(_('%d secret') % secret)
5947 t.append(_('%d secret') % secret)
5953
5948
5954 if draft or secret:
5949 if draft or secret:
5955 ui.status(_('phases: %s\n') % ', '.join(t))
5950 ui.status(_('phases: %s\n') % ', '.join(t))
5956
5951
5957 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5952 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5958 for trouble in ("unstable", "divergent", "bumped"):
5953 for trouble in ("unstable", "divergent", "bumped"):
5959 numtrouble = len(repo.revs(trouble + "()"))
5954 numtrouble = len(repo.revs(trouble + "()"))
5960 # We write all the possibilities to ease translation
5955 # We write all the possibilities to ease translation
5961 troublemsg = {
5956 troublemsg = {
5962 "unstable": _("unstable: %d changesets"),
5957 "unstable": _("unstable: %d changesets"),
5963 "divergent": _("divergent: %d changesets"),
5958 "divergent": _("divergent: %d changesets"),
5964 "bumped": _("bumped: %d changesets"),
5959 "bumped": _("bumped: %d changesets"),
5965 }
5960 }
5966 if numtrouble > 0:
5961 if numtrouble > 0:
5967 ui.status(troublemsg[trouble] % numtrouble + "\n")
5962 ui.status(troublemsg[trouble] % numtrouble + "\n")
5968
5963
5969 cmdutil.summaryhooks(ui, repo)
5964 cmdutil.summaryhooks(ui, repo)
5970
5965
5971 if opts.get('remote'):
5966 if opts.get('remote'):
5972 needsincoming, needsoutgoing = True, True
5967 needsincoming, needsoutgoing = True, True
5973 else:
5968 else:
5974 needsincoming, needsoutgoing = False, False
5969 needsincoming, needsoutgoing = False, False
5975 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5970 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5976 if i:
5971 if i:
5977 needsincoming = True
5972 needsincoming = True
5978 if o:
5973 if o:
5979 needsoutgoing = True
5974 needsoutgoing = True
5980 if not needsincoming and not needsoutgoing:
5975 if not needsincoming and not needsoutgoing:
5981 return
5976 return
5982
5977
5983 def getincoming():
5978 def getincoming():
5984 source, branches = hg.parseurl(ui.expandpath('default'))
5979 source, branches = hg.parseurl(ui.expandpath('default'))
5985 sbranch = branches[0]
5980 sbranch = branches[0]
5986 try:
5981 try:
5987 other = hg.peer(repo, {}, source)
5982 other = hg.peer(repo, {}, source)
5988 except error.RepoError:
5983 except error.RepoError:
5989 if opts.get('remote'):
5984 if opts.get('remote'):
5990 raise
5985 raise
5991 return source, sbranch, None, None, None
5986 return source, sbranch, None, None, None
5992 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5987 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5993 if revs:
5988 if revs:
5994 revs = [other.lookup(rev) for rev in revs]
5989 revs = [other.lookup(rev) for rev in revs]
5995 ui.debug('comparing with %s\n' % util.hidepassword(source))
5990 ui.debug('comparing with %s\n' % util.hidepassword(source))
5996 repo.ui.pushbuffer()
5991 repo.ui.pushbuffer()
5997 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5992 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5998 repo.ui.popbuffer()
5993 repo.ui.popbuffer()
5999 return source, sbranch, other, commoninc, commoninc[1]
5994 return source, sbranch, other, commoninc, commoninc[1]
6000
5995
6001 if needsincoming:
5996 if needsincoming:
6002 source, sbranch, sother, commoninc, incoming = getincoming()
5997 source, sbranch, sother, commoninc, incoming = getincoming()
6003 else:
5998 else:
6004 source = sbranch = sother = commoninc = incoming = None
5999 source = sbranch = sother = commoninc = incoming = None
6005
6000
6006 def getoutgoing():
6001 def getoutgoing():
6007 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6002 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6008 dbranch = branches[0]
6003 dbranch = branches[0]
6009 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6004 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6010 if source != dest:
6005 if source != dest:
6011 try:
6006 try:
6012 dother = hg.peer(repo, {}, dest)
6007 dother = hg.peer(repo, {}, dest)
6013 except error.RepoError:
6008 except error.RepoError:
6014 if opts.get('remote'):
6009 if opts.get('remote'):
6015 raise
6010 raise
6016 return dest, dbranch, None, None
6011 return dest, dbranch, None, None
6017 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6012 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6018 elif sother is None:
6013 elif sother is None:
6019 # there is no explicit destination peer, but source one is invalid
6014 # there is no explicit destination peer, but source one is invalid
6020 return dest, dbranch, None, None
6015 return dest, dbranch, None, None
6021 else:
6016 else:
6022 dother = sother
6017 dother = sother
6023 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6018 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6024 common = None
6019 common = None
6025 else:
6020 else:
6026 common = commoninc
6021 common = commoninc
6027 if revs:
6022 if revs:
6028 revs = [repo.lookup(rev) for rev in revs]
6023 revs = [repo.lookup(rev) for rev in revs]
6029 repo.ui.pushbuffer()
6024 repo.ui.pushbuffer()
6030 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6025 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6031 commoninc=common)
6026 commoninc=common)
6032 repo.ui.popbuffer()
6027 repo.ui.popbuffer()
6033 return dest, dbranch, dother, outgoing
6028 return dest, dbranch, dother, outgoing
6034
6029
6035 if needsoutgoing:
6030 if needsoutgoing:
6036 dest, dbranch, dother, outgoing = getoutgoing()
6031 dest, dbranch, dother, outgoing = getoutgoing()
6037 else:
6032 else:
6038 dest = dbranch = dother = outgoing = None
6033 dest = dbranch = dother = outgoing = None
6039
6034
6040 if opts.get('remote'):
6035 if opts.get('remote'):
6041 t = []
6036 t = []
6042 if incoming:
6037 if incoming:
6043 t.append(_('1 or more incoming'))
6038 t.append(_('1 or more incoming'))
6044 o = outgoing.missing
6039 o = outgoing.missing
6045 if o:
6040 if o:
6046 t.append(_('%d outgoing') % len(o))
6041 t.append(_('%d outgoing') % len(o))
6047 other = dother or sother
6042 other = dother or sother
6048 if 'bookmarks' in other.listkeys('namespaces'):
6043 if 'bookmarks' in other.listkeys('namespaces'):
6049 counts = bookmarks.summary(repo, other)
6044 counts = bookmarks.summary(repo, other)
6050 if counts[0] > 0:
6045 if counts[0] > 0:
6051 t.append(_('%d incoming bookmarks') % counts[0])
6046 t.append(_('%d incoming bookmarks') % counts[0])
6052 if counts[1] > 0:
6047 if counts[1] > 0:
6053 t.append(_('%d outgoing bookmarks') % counts[1])
6048 t.append(_('%d outgoing bookmarks') % counts[1])
6054
6049
6055 if t:
6050 if t:
6056 # i18n: column positioning for "hg summary"
6051 # i18n: column positioning for "hg summary"
6057 ui.write(_('remote: %s\n') % (', '.join(t)))
6052 ui.write(_('remote: %s\n') % (', '.join(t)))
6058 else:
6053 else:
6059 # i18n: column positioning for "hg summary"
6054 # i18n: column positioning for "hg summary"
6060 ui.status(_('remote: (synced)\n'))
6055 ui.status(_('remote: (synced)\n'))
6061
6056
6062 cmdutil.summaryremotehooks(ui, repo, opts,
6057 cmdutil.summaryremotehooks(ui, repo, opts,
6063 ((source, sbranch, sother, commoninc),
6058 ((source, sbranch, sother, commoninc),
6064 (dest, dbranch, dother, outgoing)))
6059 (dest, dbranch, dother, outgoing)))
6065
6060
6066 @command('tag',
6061 @command('tag',
6067 [('f', 'force', None, _('force tag')),
6062 [('f', 'force', None, _('force tag')),
6068 ('l', 'local', None, _('make the tag local')),
6063 ('l', 'local', None, _('make the tag local')),
6069 ('r', 'rev', '', _('revision to tag'), _('REV')),
6064 ('r', 'rev', '', _('revision to tag'), _('REV')),
6070 ('', 'remove', None, _('remove a tag')),
6065 ('', 'remove', None, _('remove a tag')),
6071 # -l/--local is already there, commitopts cannot be used
6066 # -l/--local is already there, commitopts cannot be used
6072 ('e', 'edit', None, _('invoke editor on commit messages')),
6067 ('e', 'edit', None, _('invoke editor on commit messages')),
6073 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6068 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6074 ] + commitopts2,
6069 ] + commitopts2,
6075 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6070 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6076 def tag(ui, repo, name1, *names, **opts):
6071 def tag(ui, repo, name1, *names, **opts):
6077 """add one or more tags for the current or given revision
6072 """add one or more tags for the current or given revision
6078
6073
6079 Name a particular revision using <name>.
6074 Name a particular revision using <name>.
6080
6075
6081 Tags are used to name particular revisions of the repository and are
6076 Tags are used to name particular revisions of the repository and are
6082 very useful to compare different revisions, to go back to significant
6077 very useful to compare different revisions, to go back to significant
6083 earlier versions or to mark branch points as releases, etc. Changing
6078 earlier versions or to mark branch points as releases, etc. Changing
6084 an existing tag is normally disallowed; use -f/--force to override.
6079 an existing tag is normally disallowed; use -f/--force to override.
6085
6080
6086 If no revision is given, the parent of the working directory is
6081 If no revision is given, the parent of the working directory is
6087 used.
6082 used.
6088
6083
6089 To facilitate version control, distribution, and merging of tags,
6084 To facilitate version control, distribution, and merging of tags,
6090 they are stored as a file named ".hgtags" which is managed similarly
6085 they are stored as a file named ".hgtags" which is managed similarly
6091 to other project files and can be hand-edited if necessary. This
6086 to other project files and can be hand-edited if necessary. This
6092 also means that tagging creates a new commit. The file
6087 also means that tagging creates a new commit. The file
6093 ".hg/localtags" is used for local tags (not shared among
6088 ".hg/localtags" is used for local tags (not shared among
6094 repositories).
6089 repositories).
6095
6090
6096 Tag commits are usually made at the head of a branch. If the parent
6091 Tag commits are usually made at the head of a branch. If the parent
6097 of the working directory is not a branch head, :hg:`tag` aborts; use
6092 of the working directory is not a branch head, :hg:`tag` aborts; use
6098 -f/--force to force the tag commit to be based on a non-head
6093 -f/--force to force the tag commit to be based on a non-head
6099 changeset.
6094 changeset.
6100
6095
6101 See :hg:`help dates` for a list of formats valid for -d/--date.
6096 See :hg:`help dates` for a list of formats valid for -d/--date.
6102
6097
6103 Since tag names have priority over branch names during revision
6098 Since tag names have priority over branch names during revision
6104 lookup, using an existing branch name as a tag name is discouraged.
6099 lookup, using an existing branch name as a tag name is discouraged.
6105
6100
6106 Returns 0 on success.
6101 Returns 0 on success.
6107 """
6102 """
6108 wlock = lock = None
6103 wlock = lock = None
6109 try:
6104 try:
6110 wlock = repo.wlock()
6105 wlock = repo.wlock()
6111 lock = repo.lock()
6106 lock = repo.lock()
6112 rev_ = "."
6107 rev_ = "."
6113 names = [t.strip() for t in (name1,) + names]
6108 names = [t.strip() for t in (name1,) + names]
6114 if len(names) != len(set(names)):
6109 if len(names) != len(set(names)):
6115 raise error.Abort(_('tag names must be unique'))
6110 raise error.Abort(_('tag names must be unique'))
6116 for n in names:
6111 for n in names:
6117 scmutil.checknewlabel(repo, n, 'tag')
6112 scmutil.checknewlabel(repo, n, 'tag')
6118 if not n:
6113 if not n:
6119 raise error.Abort(_('tag names cannot consist entirely of '
6114 raise error.Abort(_('tag names cannot consist entirely of '
6120 'whitespace'))
6115 'whitespace'))
6121 if opts.get('rev') and opts.get('remove'):
6116 if opts.get('rev') and opts.get('remove'):
6122 raise error.Abort(_("--rev and --remove are incompatible"))
6117 raise error.Abort(_("--rev and --remove are incompatible"))
6123 if opts.get('rev'):
6118 if opts.get('rev'):
6124 rev_ = opts['rev']
6119 rev_ = opts['rev']
6125 message = opts.get('message')
6120 message = opts.get('message')
6126 if opts.get('remove'):
6121 if opts.get('remove'):
6127 if opts.get('local'):
6122 if opts.get('local'):
6128 expectedtype = 'local'
6123 expectedtype = 'local'
6129 else:
6124 else:
6130 expectedtype = 'global'
6125 expectedtype = 'global'
6131
6126
6132 for n in names:
6127 for n in names:
6133 if not repo.tagtype(n):
6128 if not repo.tagtype(n):
6134 raise error.Abort(_("tag '%s' does not exist") % n)
6129 raise error.Abort(_("tag '%s' does not exist") % n)
6135 if repo.tagtype(n) != expectedtype:
6130 if repo.tagtype(n) != expectedtype:
6136 if expectedtype == 'global':
6131 if expectedtype == 'global':
6137 raise error.Abort(_("tag '%s' is not a global tag") % n)
6132 raise error.Abort(_("tag '%s' is not a global tag") % n)
6138 else:
6133 else:
6139 raise error.Abort(_("tag '%s' is not a local tag") % n)
6134 raise error.Abort(_("tag '%s' is not a local tag") % n)
6140 rev_ = 'null'
6135 rev_ = 'null'
6141 if not message:
6136 if not message:
6142 # we don't translate commit messages
6137 # we don't translate commit messages
6143 message = 'Removed tag %s' % ', '.join(names)
6138 message = 'Removed tag %s' % ', '.join(names)
6144 elif not opts.get('force'):
6139 elif not opts.get('force'):
6145 for n in names:
6140 for n in names:
6146 if n in repo.tags():
6141 if n in repo.tags():
6147 raise error.Abort(_("tag '%s' already exists "
6142 raise error.Abort(_("tag '%s' already exists "
6148 "(use -f to force)") % n)
6143 "(use -f to force)") % n)
6149 if not opts.get('local'):
6144 if not opts.get('local'):
6150 p1, p2 = repo.dirstate.parents()
6145 p1, p2 = repo.dirstate.parents()
6151 if p2 != nullid:
6146 if p2 != nullid:
6152 raise error.Abort(_('uncommitted merge'))
6147 raise error.Abort(_('uncommitted merge'))
6153 bheads = repo.branchheads()
6148 bheads = repo.branchheads()
6154 if not opts.get('force') and bheads and p1 not in bheads:
6149 if not opts.get('force') and bheads and p1 not in bheads:
6155 raise error.Abort(_('working directory is not at a branch head '
6150 raise error.Abort(_('working directory is not at a branch head '
6156 '(use -f to force)'))
6151 '(use -f to force)'))
6157 r = scmutil.revsingle(repo, rev_).node()
6152 r = scmutil.revsingle(repo, rev_).node()
6158
6153
6159 if not message:
6154 if not message:
6160 # we don't translate commit messages
6155 # we don't translate commit messages
6161 message = ('Added tag %s for changeset %s' %
6156 message = ('Added tag %s for changeset %s' %
6162 (', '.join(names), short(r)))
6157 (', '.join(names), short(r)))
6163
6158
6164 date = opts.get('date')
6159 date = opts.get('date')
6165 if date:
6160 if date:
6166 date = util.parsedate(date)
6161 date = util.parsedate(date)
6167
6162
6168 if opts.get('remove'):
6163 if opts.get('remove'):
6169 editform = 'tag.remove'
6164 editform = 'tag.remove'
6170 else:
6165 else:
6171 editform = 'tag.add'
6166 editform = 'tag.add'
6172 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6167 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6173
6168
6174 # don't allow tagging the null rev
6169 # don't allow tagging the null rev
6175 if (not opts.get('remove') and
6170 if (not opts.get('remove') and
6176 scmutil.revsingle(repo, rev_).rev() == nullrev):
6171 scmutil.revsingle(repo, rev_).rev() == nullrev):
6177 raise error.Abort(_("cannot tag null revision"))
6172 raise error.Abort(_("cannot tag null revision"))
6178
6173
6179 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6174 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6180 editor=editor)
6175 editor=editor)
6181 finally:
6176 finally:
6182 release(lock, wlock)
6177 release(lock, wlock)
6183
6178
6184 @command('tags', formatteropts, '')
6179 @command('tags', formatteropts, '')
6185 def tags(ui, repo, **opts):
6180 def tags(ui, repo, **opts):
6186 """list repository tags
6181 """list repository tags
6187
6182
6188 This lists both regular and local tags. When the -v/--verbose
6183 This lists both regular and local tags. When the -v/--verbose
6189 switch is used, a third column "local" is printed for local tags.
6184 switch is used, a third column "local" is printed for local tags.
6190 When the -q/--quiet switch is used, only the tag name is printed.
6185 When the -q/--quiet switch is used, only the tag name is printed.
6191
6186
6192 Returns 0 on success.
6187 Returns 0 on success.
6193 """
6188 """
6194
6189
6195 fm = ui.formatter('tags', opts)
6190 fm = ui.formatter('tags', opts)
6196 hexfunc = fm.hexfunc
6191 hexfunc = fm.hexfunc
6197 tagtype = ""
6192 tagtype = ""
6198
6193
6199 for t, n in reversed(repo.tagslist()):
6194 for t, n in reversed(repo.tagslist()):
6200 hn = hexfunc(n)
6195 hn = hexfunc(n)
6201 label = 'tags.normal'
6196 label = 'tags.normal'
6202 tagtype = ''
6197 tagtype = ''
6203 if repo.tagtype(t) == 'local':
6198 if repo.tagtype(t) == 'local':
6204 label = 'tags.local'
6199 label = 'tags.local'
6205 tagtype = 'local'
6200 tagtype = 'local'
6206
6201
6207 fm.startitem()
6202 fm.startitem()
6208 fm.write('tag', '%s', t, label=label)
6203 fm.write('tag', '%s', t, label=label)
6209 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6204 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6210 fm.condwrite(not ui.quiet, 'rev node', fmt,
6205 fm.condwrite(not ui.quiet, 'rev node', fmt,
6211 repo.changelog.rev(n), hn, label=label)
6206 repo.changelog.rev(n), hn, label=label)
6212 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6207 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6213 tagtype, label=label)
6208 tagtype, label=label)
6214 fm.plain('\n')
6209 fm.plain('\n')
6215 fm.end()
6210 fm.end()
6216
6211
6217 @command('tip',
6212 @command('tip',
6218 [('p', 'patch', None, _('show patch')),
6213 [('p', 'patch', None, _('show patch')),
6219 ('g', 'git', None, _('use git extended diff format')),
6214 ('g', 'git', None, _('use git extended diff format')),
6220 ] + templateopts,
6215 ] + templateopts,
6221 _('[-p] [-g]'))
6216 _('[-p] [-g]'))
6222 def tip(ui, repo, **opts):
6217 def tip(ui, repo, **opts):
6223 """show the tip revision (DEPRECATED)
6218 """show the tip revision (DEPRECATED)
6224
6219
6225 The tip revision (usually just called the tip) is the changeset
6220 The tip revision (usually just called the tip) is the changeset
6226 most recently added to the repository (and therefore the most
6221 most recently added to the repository (and therefore the most
6227 recently changed head).
6222 recently changed head).
6228
6223
6229 If you have just made a commit, that commit will be the tip. If
6224 If you have just made a commit, that commit will be the tip. If
6230 you have just pulled changes from another repository, the tip of
6225 you have just pulled changes from another repository, the tip of
6231 that repository becomes the current tip. The "tip" tag is special
6226 that repository becomes the current tip. The "tip" tag is special
6232 and cannot be renamed or assigned to a different changeset.
6227 and cannot be renamed or assigned to a different changeset.
6233
6228
6234 This command is deprecated, please use :hg:`heads` instead.
6229 This command is deprecated, please use :hg:`heads` instead.
6235
6230
6236 Returns 0 on success.
6231 Returns 0 on success.
6237 """
6232 """
6238 displayer = cmdutil.show_changeset(ui, repo, opts)
6233 displayer = cmdutil.show_changeset(ui, repo, opts)
6239 displayer.show(repo['tip'])
6234 displayer.show(repo['tip'])
6240 displayer.close()
6235 displayer.close()
6241
6236
6242 @command('unbundle',
6237 @command('unbundle',
6243 [('u', 'update', None,
6238 [('u', 'update', None,
6244 _('update to new branch head if changesets were unbundled'))],
6239 _('update to new branch head if changesets were unbundled'))],
6245 _('[-u] FILE...'))
6240 _('[-u] FILE...'))
6246 def unbundle(ui, repo, fname1, *fnames, **opts):
6241 def unbundle(ui, repo, fname1, *fnames, **opts):
6247 """apply one or more changegroup files
6242 """apply one or more changegroup files
6248
6243
6249 Apply one or more compressed changegroup files generated by the
6244 Apply one or more compressed changegroup files generated by the
6250 bundle command.
6245 bundle command.
6251
6246
6252 Returns 0 on success, 1 if an update has unresolved files.
6247 Returns 0 on success, 1 if an update has unresolved files.
6253 """
6248 """
6254 fnames = (fname1,) + fnames
6249 fnames = (fname1,) + fnames
6255
6250
6256 with repo.lock():
6251 with repo.lock():
6257 for fname in fnames:
6252 for fname in fnames:
6258 f = hg.openpath(ui, fname)
6253 f = hg.openpath(ui, fname)
6259 gen = exchange.readbundle(ui, f, fname)
6254 gen = exchange.readbundle(ui, f, fname)
6260 if isinstance(gen, bundle2.unbundle20):
6255 if isinstance(gen, bundle2.unbundle20):
6261 tr = repo.transaction('unbundle')
6256 tr = repo.transaction('unbundle')
6262 try:
6257 try:
6263 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6258 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6264 url='bundle:' + fname)
6259 url='bundle:' + fname)
6265 tr.close()
6260 tr.close()
6266 except error.BundleUnknownFeatureError as exc:
6261 except error.BundleUnknownFeatureError as exc:
6267 raise error.Abort(_('%s: unknown bundle feature, %s')
6262 raise error.Abort(_('%s: unknown bundle feature, %s')
6268 % (fname, exc),
6263 % (fname, exc),
6269 hint=_("see https://mercurial-scm.org/"
6264 hint=_("see https://mercurial-scm.org/"
6270 "wiki/BundleFeature for more "
6265 "wiki/BundleFeature for more "
6271 "information"))
6266 "information"))
6272 finally:
6267 finally:
6273 if tr:
6268 if tr:
6274 tr.release()
6269 tr.release()
6275 changes = [r.get('return', 0)
6270 changes = [r.get('return', 0)
6276 for r in op.records['changegroup']]
6271 for r in op.records['changegroup']]
6277 modheads = changegroup.combineresults(changes)
6272 modheads = changegroup.combineresults(changes)
6278 elif isinstance(gen, streamclone.streamcloneapplier):
6273 elif isinstance(gen, streamclone.streamcloneapplier):
6279 raise error.Abort(
6274 raise error.Abort(
6280 _('packed bundles cannot be applied with '
6275 _('packed bundles cannot be applied with '
6281 '"hg unbundle"'),
6276 '"hg unbundle"'),
6282 hint=_('use "hg debugapplystreamclonebundle"'))
6277 hint=_('use "hg debugapplystreamclonebundle"'))
6283 else:
6278 else:
6284 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6279 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6285
6280
6286 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6281 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6287
6282
6288 @command('^update|up|checkout|co',
6283 @command('^update|up|checkout|co',
6289 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6284 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6290 ('c', 'check', None, _('require clean working directory')),
6285 ('c', 'check', None, _('require clean working directory')),
6291 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6286 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6292 ('r', 'rev', '', _('revision'), _('REV'))
6287 ('r', 'rev', '', _('revision'), _('REV'))
6293 ] + mergetoolopts,
6288 ] + mergetoolopts,
6294 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6289 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6295 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6290 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6296 tool=None):
6291 tool=None):
6297 """update working directory (or switch revisions)
6292 """update working directory (or switch revisions)
6298
6293
6299 Update the repository's working directory to the specified
6294 Update the repository's working directory to the specified
6300 changeset. If no changeset is specified, update to the tip of the
6295 changeset. If no changeset is specified, update to the tip of the
6301 current named branch and move the active bookmark (see :hg:`help
6296 current named branch and move the active bookmark (see :hg:`help
6302 bookmarks`).
6297 bookmarks`).
6303
6298
6304 Update sets the working directory's parent revision to the specified
6299 Update sets the working directory's parent revision to the specified
6305 changeset (see :hg:`help parents`).
6300 changeset (see :hg:`help parents`).
6306
6301
6307 If the changeset is not a descendant or ancestor of the working
6302 If the changeset is not a descendant or ancestor of the working
6308 directory's parent and there are uncommitted changes, the update is
6303 directory's parent and there are uncommitted changes, the update is
6309 aborted. With the -c/--check option, the working directory is checked
6304 aborted. With the -c/--check option, the working directory is checked
6310 for uncommitted changes; if none are found, the working directory is
6305 for uncommitted changes; if none are found, the working directory is
6311 updated to the specified changeset.
6306 updated to the specified changeset.
6312
6307
6313 .. container:: verbose
6308 .. container:: verbose
6314
6309
6315 The following rules apply when the working directory contains
6310 The following rules apply when the working directory contains
6316 uncommitted changes:
6311 uncommitted changes:
6317
6312
6318 1. If neither -c/--check nor -C/--clean is specified, and if
6313 1. If neither -c/--check nor -C/--clean is specified, and if
6319 the requested changeset is an ancestor or descendant of
6314 the requested changeset is an ancestor or descendant of
6320 the working directory's parent, the uncommitted changes
6315 the working directory's parent, the uncommitted changes
6321 are merged into the requested changeset and the merged
6316 are merged into the requested changeset and the merged
6322 result is left uncommitted. If the requested changeset is
6317 result is left uncommitted. If the requested changeset is
6323 not an ancestor or descendant (that is, it is on another
6318 not an ancestor or descendant (that is, it is on another
6324 branch), the update is aborted and the uncommitted changes
6319 branch), the update is aborted and the uncommitted changes
6325 are preserved.
6320 are preserved.
6326
6321
6327 2. With the -c/--check option, the update is aborted and the
6322 2. With the -c/--check option, the update is aborted and the
6328 uncommitted changes are preserved.
6323 uncommitted changes are preserved.
6329
6324
6330 3. With the -C/--clean option, uncommitted changes are discarded and
6325 3. With the -C/--clean option, uncommitted changes are discarded and
6331 the working directory is updated to the requested changeset.
6326 the working directory is updated to the requested changeset.
6332
6327
6333 To cancel an uncommitted merge (and lose your changes), use
6328 To cancel an uncommitted merge (and lose your changes), use
6334 :hg:`update --clean .`.
6329 :hg:`update --clean .`.
6335
6330
6336 Use null as the changeset to remove the working directory (like
6331 Use null as the changeset to remove the working directory (like
6337 :hg:`clone -U`).
6332 :hg:`clone -U`).
6338
6333
6339 If you want to revert just one file to an older revision, use
6334 If you want to revert just one file to an older revision, use
6340 :hg:`revert [-r REV] NAME`.
6335 :hg:`revert [-r REV] NAME`.
6341
6336
6342 See :hg:`help dates` for a list of formats valid for -d/--date.
6337 See :hg:`help dates` for a list of formats valid for -d/--date.
6343
6338
6344 Returns 0 on success, 1 if there are unresolved files.
6339 Returns 0 on success, 1 if there are unresolved files.
6345 """
6340 """
6346 if rev and node:
6341 if rev and node:
6347 raise error.Abort(_("please specify just one revision"))
6342 raise error.Abort(_("please specify just one revision"))
6348
6343
6349 if rev is None or rev == '':
6344 if rev is None or rev == '':
6350 rev = node
6345 rev = node
6351
6346
6352 if date and rev is not None:
6347 if date and rev is not None:
6353 raise error.Abort(_("you can't specify a revision and a date"))
6348 raise error.Abort(_("you can't specify a revision and a date"))
6354
6349
6355 if check and clean:
6350 if check and clean:
6356 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6351 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6357
6352
6358 with repo.wlock():
6353 with repo.wlock():
6359 cmdutil.clearunfinished(repo)
6354 cmdutil.clearunfinished(repo)
6360
6355
6361 if date:
6356 if date:
6362 rev = cmdutil.finddate(ui, repo, date)
6357 rev = cmdutil.finddate(ui, repo, date)
6363
6358
6364 # if we defined a bookmark, we have to remember the original name
6359 # if we defined a bookmark, we have to remember the original name
6365 brev = rev
6360 brev = rev
6366 rev = scmutil.revsingle(repo, rev, rev).rev()
6361 rev = scmutil.revsingle(repo, rev, rev).rev()
6367
6362
6368 if check:
6363 if check:
6369 cmdutil.bailifchanged(repo, merge=False)
6364 cmdutil.bailifchanged(repo, merge=False)
6370
6365
6371 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6366 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6372
6367
6373 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6368 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6374
6369
6375 @command('verify', [])
6370 @command('verify', [])
6376 def verify(ui, repo):
6371 def verify(ui, repo):
6377 """verify the integrity of the repository
6372 """verify the integrity of the repository
6378
6373
6379 Verify the integrity of the current repository.
6374 Verify the integrity of the current repository.
6380
6375
6381 This will perform an extensive check of the repository's
6376 This will perform an extensive check of the repository's
6382 integrity, validating the hashes and checksums of each entry in
6377 integrity, validating the hashes and checksums of each entry in
6383 the changelog, manifest, and tracked files, as well as the
6378 the changelog, manifest, and tracked files, as well as the
6384 integrity of their crosslinks and indices.
6379 integrity of their crosslinks and indices.
6385
6380
6386 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6381 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6387 for more information about recovery from corruption of the
6382 for more information about recovery from corruption of the
6388 repository.
6383 repository.
6389
6384
6390 Returns 0 on success, 1 if errors are encountered.
6385 Returns 0 on success, 1 if errors are encountered.
6391 """
6386 """
6392 return hg.verify(repo)
6387 return hg.verify(repo)
6393
6388
6394 @command('version', [] + formatteropts, norepo=True)
6389 @command('version', [] + formatteropts, norepo=True)
6395 def version_(ui, **opts):
6390 def version_(ui, **opts):
6396 """output version and copyright information"""
6391 """output version and copyright information"""
6397 fm = ui.formatter("version", opts)
6392 fm = ui.formatter("version", opts)
6398 fm.startitem()
6393 fm.startitem()
6399 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6394 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6400 util.version())
6395 util.version())
6401 license = _(
6396 license = _(
6402 "(see https://mercurial-scm.org for more information)\n"
6397 "(see https://mercurial-scm.org for more information)\n"
6403 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6398 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6404 "This is free software; see the source for copying conditions. "
6399 "This is free software; see the source for copying conditions. "
6405 "There is NO\nwarranty; "
6400 "There is NO\nwarranty; "
6406 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6401 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6407 )
6402 )
6408 if not ui.quiet:
6403 if not ui.quiet:
6409 fm.plain(license)
6404 fm.plain(license)
6410
6405
6411 if ui.verbose:
6406 if ui.verbose:
6412 fm.plain(_("\nEnabled extensions:\n\n"))
6407 fm.plain(_("\nEnabled extensions:\n\n"))
6413 # format names and versions into columns
6408 # format names and versions into columns
6414 names = []
6409 names = []
6415 vers = []
6410 vers = []
6416 isinternals = []
6411 isinternals = []
6417 for name, module in extensions.extensions():
6412 for name, module in extensions.extensions():
6418 names.append(name)
6413 names.append(name)
6419 vers.append(extensions.moduleversion(module) or None)
6414 vers.append(extensions.moduleversion(module) or None)
6420 isinternals.append(extensions.ismoduleinternal(module))
6415 isinternals.append(extensions.ismoduleinternal(module))
6421 fn = fm.nested("extensions")
6416 fn = fm.nested("extensions")
6422 if names:
6417 if names:
6423 namefmt = " %%-%ds " % max(len(n) for n in names)
6418 namefmt = " %%-%ds " % max(len(n) for n in names)
6424 places = [_("external"), _("internal")]
6419 places = [_("external"), _("internal")]
6425 for n, v, p in zip(names, vers, isinternals):
6420 for n, v, p in zip(names, vers, isinternals):
6426 fn.startitem()
6421 fn.startitem()
6427 fn.condwrite(ui.verbose, "name", namefmt, n)
6422 fn.condwrite(ui.verbose, "name", namefmt, n)
6428 if ui.verbose:
6423 if ui.verbose:
6429 fn.plain("%s " % places[p])
6424 fn.plain("%s " % places[p])
6430 fn.data(bundled=p)
6425 fn.data(bundled=p)
6431 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6426 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6432 if ui.verbose:
6427 if ui.verbose:
6433 fn.plain("\n")
6428 fn.plain("\n")
6434 fn.end()
6429 fn.end()
6435 fm.end()
6430 fm.end()
6436
6431
6437 def loadcmdtable(ui, name, cmdtable):
6432 def loadcmdtable(ui, name, cmdtable):
6438 """Load command functions from specified cmdtable
6433 """Load command functions from specified cmdtable
6439 """
6434 """
6440 overrides = [cmd for cmd in cmdtable if cmd in table]
6435 overrides = [cmd for cmd in cmdtable if cmd in table]
6441 if overrides:
6436 if overrides:
6442 ui.warn(_("extension '%s' overrides commands: %s\n")
6437 ui.warn(_("extension '%s' overrides commands: %s\n")
6443 % (name, " ".join(overrides)))
6438 % (name, " ".join(overrides)))
6444 table.update(cmdtable)
6439 table.update(cmdtable)
@@ -1,1062 +1,1067
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 operator
10 import operator
11 import os
11 import os
12 import random
12 import random
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 bin,
18 bin,
19 hex,
19 hex,
20 nullid,
20 nullid,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 bundle2,
24 bundle2,
25 changegroup,
25 changegroup,
26 cmdutil,
26 cmdutil,
27 commands,
27 commands,
28 context,
28 context,
29 dagparser,
29 dagparser,
30 dagutil,
30 dagutil,
31 encoding,
31 encoding,
32 error,
32 error,
33 exchange,
33 exchange,
34 extensions,
34 extensions,
35 fileset,
35 fileset,
36 hg,
36 hg,
37 localrepo,
37 localrepo,
38 lock as lockmod,
38 lock as lockmod,
39 policy,
39 policy,
40 pycompat,
40 pycompat,
41 repair,
41 repair,
42 revlog,
42 revlog,
43 scmutil,
43 scmutil,
44 setdiscovery,
44 setdiscovery,
45 simplemerge,
45 simplemerge,
46 sslutil,
46 sslutil,
47 streamclone,
47 streamclone,
48 templater,
48 templater,
49 treediscovery,
49 treediscovery,
50 util,
50 util,
51 )
51 )
52
52
53 release = lockmod.release
53 release = lockmod.release
54
54
55 # We reuse the command table from commands because it is easier than
55 # We reuse the command table from commands because it is easier than
56 # teaching dispatch about multiple tables.
56 # teaching dispatch about multiple tables.
57 command = cmdutil.command(commands.table)
57 command = cmdutil.command(commands.table)
58
58
59 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
59 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
60 def debugancestor(ui, repo, *args):
60 def debugancestor(ui, repo, *args):
61 """find the ancestor revision of two revisions in a given index"""
61 """find the ancestor revision of two revisions in a given index"""
62 if len(args) == 3:
62 if len(args) == 3:
63 index, rev1, rev2 = args
63 index, rev1, rev2 = args
64 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
64 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
65 lookup = r.lookup
65 lookup = r.lookup
66 elif len(args) == 2:
66 elif len(args) == 2:
67 if not repo:
67 if not repo:
68 raise error.Abort(_('there is no Mercurial repository here '
68 raise error.Abort(_('there is no Mercurial repository here '
69 '(.hg not found)'))
69 '(.hg not found)'))
70 rev1, rev2 = args
70 rev1, rev2 = args
71 r = repo.changelog
71 r = repo.changelog
72 lookup = repo.lookup
72 lookup = repo.lookup
73 else:
73 else:
74 raise error.Abort(_('either two or three arguments required'))
74 raise error.Abort(_('either two or three arguments required'))
75 a = r.ancestor(lookup(rev1), lookup(rev2))
75 a = r.ancestor(lookup(rev1), lookup(rev2))
76 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
76 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
77
77
78 @command('debugapplystreamclonebundle', [], 'FILE')
78 @command('debugapplystreamclonebundle', [], 'FILE')
79 def debugapplystreamclonebundle(ui, repo, fname):
79 def debugapplystreamclonebundle(ui, repo, fname):
80 """apply a stream clone bundle file"""
80 """apply a stream clone bundle file"""
81 f = hg.openpath(ui, fname)
81 f = hg.openpath(ui, fname)
82 gen = exchange.readbundle(ui, f, fname)
82 gen = exchange.readbundle(ui, f, fname)
83 gen.apply(repo)
83 gen.apply(repo)
84
84
85 @command('debugbuilddag',
85 @command('debugbuilddag',
86 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
86 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
87 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
87 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
88 ('n', 'new-file', None, _('add new file at each rev'))],
88 ('n', 'new-file', None, _('add new file at each rev'))],
89 _('[OPTION]... [TEXT]'))
89 _('[OPTION]... [TEXT]'))
90 def debugbuilddag(ui, repo, text=None,
90 def debugbuilddag(ui, repo, text=None,
91 mergeable_file=False,
91 mergeable_file=False,
92 overwritten_file=False,
92 overwritten_file=False,
93 new_file=False):
93 new_file=False):
94 """builds a repo with a given DAG from scratch in the current empty repo
94 """builds a repo with a given DAG from scratch in the current empty repo
95
95
96 The description of the DAG is read from stdin if not given on the
96 The description of the DAG is read from stdin if not given on the
97 command line.
97 command line.
98
98
99 Elements:
99 Elements:
100
100
101 - "+n" is a linear run of n nodes based on the current default parent
101 - "+n" is a linear run of n nodes based on the current default parent
102 - "." is a single node based on the current default parent
102 - "." is a single node based on the current default parent
103 - "$" resets the default parent to null (implied at the start);
103 - "$" resets the default parent to null (implied at the start);
104 otherwise the default parent is always the last node created
104 otherwise the default parent is always the last node created
105 - "<p" sets the default parent to the backref p
105 - "<p" sets the default parent to the backref p
106 - "*p" is a fork at parent p, which is a backref
106 - "*p" is a fork at parent p, which is a backref
107 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
107 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
108 - "/p2" is a merge of the preceding node and p2
108 - "/p2" is a merge of the preceding node and p2
109 - ":tag" defines a local tag for the preceding node
109 - ":tag" defines a local tag for the preceding node
110 - "@branch" sets the named branch for subsequent nodes
110 - "@branch" sets the named branch for subsequent nodes
111 - "#...\\n" is a comment up to the end of the line
111 - "#...\\n" is a comment up to the end of the line
112
112
113 Whitespace between the above elements is ignored.
113 Whitespace between the above elements is ignored.
114
114
115 A backref is either
115 A backref is either
116
116
117 - a number n, which references the node curr-n, where curr is the current
117 - a number n, which references the node curr-n, where curr is the current
118 node, or
118 node, or
119 - the name of a local tag you placed earlier using ":tag", or
119 - the name of a local tag you placed earlier using ":tag", or
120 - empty to denote the default parent.
120 - empty to denote the default parent.
121
121
122 All string valued-elements are either strictly alphanumeric, or must
122 All string valued-elements are either strictly alphanumeric, or must
123 be enclosed in double quotes ("..."), with "\\" as escape character.
123 be enclosed in double quotes ("..."), with "\\" as escape character.
124 """
124 """
125
125
126 if text is None:
126 if text is None:
127 ui.status(_("reading DAG from stdin\n"))
127 ui.status(_("reading DAG from stdin\n"))
128 text = ui.fin.read()
128 text = ui.fin.read()
129
129
130 cl = repo.changelog
130 cl = repo.changelog
131 if len(cl) > 0:
131 if len(cl) > 0:
132 raise error.Abort(_('repository is not empty'))
132 raise error.Abort(_('repository is not empty'))
133
133
134 # determine number of revs in DAG
134 # determine number of revs in DAG
135 total = 0
135 total = 0
136 for type, data in dagparser.parsedag(text):
136 for type, data in dagparser.parsedag(text):
137 if type == 'n':
137 if type == 'n':
138 total += 1
138 total += 1
139
139
140 if mergeable_file:
140 if mergeable_file:
141 linesperrev = 2
141 linesperrev = 2
142 # make a file with k lines per rev
142 # make a file with k lines per rev
143 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
143 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
144 initialmergedlines.append("")
144 initialmergedlines.append("")
145
145
146 tags = []
146 tags = []
147
147
148 wlock = lock = tr = None
148 wlock = lock = tr = None
149 try:
149 try:
150 wlock = repo.wlock()
150 wlock = repo.wlock()
151 lock = repo.lock()
151 lock = repo.lock()
152 tr = repo.transaction("builddag")
152 tr = repo.transaction("builddag")
153
153
154 at = -1
154 at = -1
155 atbranch = 'default'
155 atbranch = 'default'
156 nodeids = []
156 nodeids = []
157 id = 0
157 id = 0
158 ui.progress(_('building'), id, unit=_('revisions'), total=total)
158 ui.progress(_('building'), id, unit=_('revisions'), total=total)
159 for type, data in dagparser.parsedag(text):
159 for type, data in dagparser.parsedag(text):
160 if type == 'n':
160 if type == 'n':
161 ui.note(('node %s\n' % str(data)))
161 ui.note(('node %s\n' % str(data)))
162 id, ps = data
162 id, ps = data
163
163
164 files = []
164 files = []
165 fctxs = {}
165 fctxs = {}
166
166
167 p2 = None
167 p2 = None
168 if mergeable_file:
168 if mergeable_file:
169 fn = "mf"
169 fn = "mf"
170 p1 = repo[ps[0]]
170 p1 = repo[ps[0]]
171 if len(ps) > 1:
171 if len(ps) > 1:
172 p2 = repo[ps[1]]
172 p2 = repo[ps[1]]
173 pa = p1.ancestor(p2)
173 pa = p1.ancestor(p2)
174 base, local, other = [x[fn].data() for x in (pa, p1,
174 base, local, other = [x[fn].data() for x in (pa, p1,
175 p2)]
175 p2)]
176 m3 = simplemerge.Merge3Text(base, local, other)
176 m3 = simplemerge.Merge3Text(base, local, other)
177 ml = [l.strip() for l in m3.merge_lines()]
177 ml = [l.strip() for l in m3.merge_lines()]
178 ml.append("")
178 ml.append("")
179 elif at > 0:
179 elif at > 0:
180 ml = p1[fn].data().split("\n")
180 ml = p1[fn].data().split("\n")
181 else:
181 else:
182 ml = initialmergedlines
182 ml = initialmergedlines
183 ml[id * linesperrev] += " r%i" % id
183 ml[id * linesperrev] += " r%i" % id
184 mergedtext = "\n".join(ml)
184 mergedtext = "\n".join(ml)
185 files.append(fn)
185 files.append(fn)
186 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
186 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
187
187
188 if overwritten_file:
188 if overwritten_file:
189 fn = "of"
189 fn = "of"
190 files.append(fn)
190 files.append(fn)
191 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
191 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
192
192
193 if new_file:
193 if new_file:
194 fn = "nf%i" % id
194 fn = "nf%i" % id
195 files.append(fn)
195 files.append(fn)
196 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
196 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
197 if len(ps) > 1:
197 if len(ps) > 1:
198 if not p2:
198 if not p2:
199 p2 = repo[ps[1]]
199 p2 = repo[ps[1]]
200 for fn in p2:
200 for fn in p2:
201 if fn.startswith("nf"):
201 if fn.startswith("nf"):
202 files.append(fn)
202 files.append(fn)
203 fctxs[fn] = p2[fn]
203 fctxs[fn] = p2[fn]
204
204
205 def fctxfn(repo, cx, path):
205 def fctxfn(repo, cx, path):
206 return fctxs.get(path)
206 return fctxs.get(path)
207
207
208 if len(ps) == 0 or ps[0] < 0:
208 if len(ps) == 0 or ps[0] < 0:
209 pars = [None, None]
209 pars = [None, None]
210 elif len(ps) == 1:
210 elif len(ps) == 1:
211 pars = [nodeids[ps[0]], None]
211 pars = [nodeids[ps[0]], None]
212 else:
212 else:
213 pars = [nodeids[p] for p in ps]
213 pars = [nodeids[p] for p in ps]
214 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
214 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
215 date=(id, 0),
215 date=(id, 0),
216 user="debugbuilddag",
216 user="debugbuilddag",
217 extra={'branch': atbranch})
217 extra={'branch': atbranch})
218 nodeid = repo.commitctx(cx)
218 nodeid = repo.commitctx(cx)
219 nodeids.append(nodeid)
219 nodeids.append(nodeid)
220 at = id
220 at = id
221 elif type == 'l':
221 elif type == 'l':
222 id, name = data
222 id, name = data
223 ui.note(('tag %s\n' % name))
223 ui.note(('tag %s\n' % name))
224 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
224 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
225 elif type == 'a':
225 elif type == 'a':
226 ui.note(('branch %s\n' % data))
226 ui.note(('branch %s\n' % data))
227 atbranch = data
227 atbranch = data
228 ui.progress(_('building'), id, unit=_('revisions'), total=total)
228 ui.progress(_('building'), id, unit=_('revisions'), total=total)
229 tr.close()
229 tr.close()
230
230
231 if tags:
231 if tags:
232 repo.vfs.write("localtags", "".join(tags))
232 repo.vfs.write("localtags", "".join(tags))
233 finally:
233 finally:
234 ui.progress(_('building'), None)
234 ui.progress(_('building'), None)
235 release(tr, lock, wlock)
235 release(tr, lock, wlock)
236
236
237 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
237 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
238 indent_string = ' ' * indent
238 indent_string = ' ' * indent
239 if all:
239 if all:
240 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
240 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
241 % indent_string)
241 % indent_string)
242
242
243 def showchunks(named):
243 def showchunks(named):
244 ui.write("\n%s%s\n" % (indent_string, named))
244 ui.write("\n%s%s\n" % (indent_string, named))
245 chain = None
245 chain = None
246 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
246 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
247 node = chunkdata['node']
247 node = chunkdata['node']
248 p1 = chunkdata['p1']
248 p1 = chunkdata['p1']
249 p2 = chunkdata['p2']
249 p2 = chunkdata['p2']
250 cs = chunkdata['cs']
250 cs = chunkdata['cs']
251 deltabase = chunkdata['deltabase']
251 deltabase = chunkdata['deltabase']
252 delta = chunkdata['delta']
252 delta = chunkdata['delta']
253 ui.write("%s%s %s %s %s %s %s\n" %
253 ui.write("%s%s %s %s %s %s %s\n" %
254 (indent_string, hex(node), hex(p1), hex(p2),
254 (indent_string, hex(node), hex(p1), hex(p2),
255 hex(cs), hex(deltabase), len(delta)))
255 hex(cs), hex(deltabase), len(delta)))
256 chain = node
256 chain = node
257
257
258 chunkdata = gen.changelogheader()
258 chunkdata = gen.changelogheader()
259 showchunks("changelog")
259 showchunks("changelog")
260 chunkdata = gen.manifestheader()
260 chunkdata = gen.manifestheader()
261 showchunks("manifest")
261 showchunks("manifest")
262 for chunkdata in iter(gen.filelogheader, {}):
262 for chunkdata in iter(gen.filelogheader, {}):
263 fname = chunkdata['filename']
263 fname = chunkdata['filename']
264 showchunks(fname)
264 showchunks(fname)
265 else:
265 else:
266 if isinstance(gen, bundle2.unbundle20):
266 if isinstance(gen, bundle2.unbundle20):
267 raise error.Abort(_('use debugbundle2 for this file'))
267 raise error.Abort(_('use debugbundle2 for this file'))
268 chunkdata = gen.changelogheader()
268 chunkdata = gen.changelogheader()
269 chain = None
269 chain = None
270 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
270 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
271 node = chunkdata['node']
271 node = chunkdata['node']
272 ui.write("%s%s\n" % (indent_string, hex(node)))
272 ui.write("%s%s\n" % (indent_string, hex(node)))
273 chain = node
273 chain = node
274
274
275 def _debugbundle2(ui, gen, all=None, **opts):
275 def _debugbundle2(ui, gen, all=None, **opts):
276 """lists the contents of a bundle2"""
276 """lists the contents of a bundle2"""
277 if not isinstance(gen, bundle2.unbundle20):
277 if not isinstance(gen, bundle2.unbundle20):
278 raise error.Abort(_('not a bundle2 file'))
278 raise error.Abort(_('not a bundle2 file'))
279 ui.write(('Stream params: %s\n' % repr(gen.params)))
279 ui.write(('Stream params: %s\n' % repr(gen.params)))
280 for part in gen.iterparts():
280 for part in gen.iterparts():
281 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
281 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
282 if part.type == 'changegroup':
282 if part.type == 'changegroup':
283 version = part.params.get('version', '01')
283 version = part.params.get('version', '01')
284 cg = changegroup.getunbundler(version, part, 'UN')
284 cg = changegroup.getunbundler(version, part, 'UN')
285 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
285 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
286
286
287 @command('debugbundle',
287 @command('debugbundle',
288 [('a', 'all', None, _('show all details')),
288 [('a', 'all', None, _('show all details')),
289 ('', 'spec', None, _('print the bundlespec of the bundle'))],
289 ('', 'spec', None, _('print the bundlespec of the bundle'))],
290 _('FILE'),
290 _('FILE'),
291 norepo=True)
291 norepo=True)
292 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
292 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
293 """lists the contents of a bundle"""
293 """lists the contents of a bundle"""
294 with hg.openpath(ui, bundlepath) as f:
294 with hg.openpath(ui, bundlepath) as f:
295 if spec:
295 if spec:
296 spec = exchange.getbundlespec(ui, f)
296 spec = exchange.getbundlespec(ui, f)
297 ui.write('%s\n' % spec)
297 ui.write('%s\n' % spec)
298 return
298 return
299
299
300 gen = exchange.readbundle(ui, f, bundlepath)
300 gen = exchange.readbundle(ui, f, bundlepath)
301 if isinstance(gen, bundle2.unbundle20):
301 if isinstance(gen, bundle2.unbundle20):
302 return _debugbundle2(ui, gen, all=all, **opts)
302 return _debugbundle2(ui, gen, all=all, **opts)
303 _debugchangegroup(ui, gen, all=all, **opts)
303 _debugchangegroup(ui, gen, all=all, **opts)
304
304
305 @command('debugcheckstate', [], '')
305 @command('debugcheckstate', [], '')
306 def debugcheckstate(ui, repo):
306 def debugcheckstate(ui, repo):
307 """validate the correctness of the current dirstate"""
307 """validate the correctness of the current dirstate"""
308 parent1, parent2 = repo.dirstate.parents()
308 parent1, parent2 = repo.dirstate.parents()
309 m1 = repo[parent1].manifest()
309 m1 = repo[parent1].manifest()
310 m2 = repo[parent2].manifest()
310 m2 = repo[parent2].manifest()
311 errors = 0
311 errors = 0
312 for f in repo.dirstate:
312 for f in repo.dirstate:
313 state = repo.dirstate[f]
313 state = repo.dirstate[f]
314 if state in "nr" and f not in m1:
314 if state in "nr" and f not in m1:
315 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
315 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
316 errors += 1
316 errors += 1
317 if state in "a" and f in m1:
317 if state in "a" and f in m1:
318 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
318 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
319 errors += 1
319 errors += 1
320 if state in "m" and f not in m1 and f not in m2:
320 if state in "m" and f not in m1 and f not in m2:
321 ui.warn(_("%s in state %s, but not in either manifest\n") %
321 ui.warn(_("%s in state %s, but not in either manifest\n") %
322 (f, state))
322 (f, state))
323 errors += 1
323 errors += 1
324 for f in m1:
324 for f in m1:
325 state = repo.dirstate[f]
325 state = repo.dirstate[f]
326 if state not in "nrm":
326 if state not in "nrm":
327 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
327 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
328 errors += 1
328 errors += 1
329 if errors:
329 if errors:
330 error = _(".hg/dirstate inconsistent with current parent's manifest")
330 error = _(".hg/dirstate inconsistent with current parent's manifest")
331 raise error.Abort(error)
331 raise error.Abort(error)
332
332
333 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
333 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
334 def debugcommands(ui, cmd='', *args):
334 def debugcommands(ui, cmd='', *args):
335 """list all available commands and options"""
335 """list all available commands and options"""
336 for cmd, vals in sorted(commands.table.iteritems()):
336 for cmd, vals in sorted(commands.table.iteritems()):
337 cmd = cmd.split('|')[0].strip('^')
337 cmd = cmd.split('|')[0].strip('^')
338 opts = ', '.join([i[1] for i in vals[1]])
338 opts = ', '.join([i[1] for i in vals[1]])
339 ui.write('%s: %s\n' % (cmd, opts))
339 ui.write('%s: %s\n' % (cmd, opts))
340
340
341 @command('debugcomplete',
341 @command('debugcomplete',
342 [('o', 'options', None, _('show the command options'))],
342 [('o', 'options', None, _('show the command options'))],
343 _('[-o] CMD'),
343 _('[-o] CMD'),
344 norepo=True)
344 norepo=True)
345 def debugcomplete(ui, cmd='', **opts):
345 def debugcomplete(ui, cmd='', **opts):
346 """returns the completion list associated with the given command"""
346 """returns the completion list associated with the given command"""
347
347
348 if opts.get('options'):
348 if opts.get('options'):
349 options = []
349 options = []
350 otables = [commands.globalopts]
350 otables = [commands.globalopts]
351 if cmd:
351 if cmd:
352 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
352 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
353 otables.append(entry[1])
353 otables.append(entry[1])
354 for t in otables:
354 for t in otables:
355 for o in t:
355 for o in t:
356 if "(DEPRECATED)" in o[3]:
356 if "(DEPRECATED)" in o[3]:
357 continue
357 continue
358 if o[0]:
358 if o[0]:
359 options.append('-%s' % o[0])
359 options.append('-%s' % o[0])
360 options.append('--%s' % o[1])
360 options.append('--%s' % o[1])
361 ui.write("%s\n" % "\n".join(options))
361 ui.write("%s\n" % "\n".join(options))
362 return
362 return
363
363
364 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
364 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
365 if ui.verbose:
365 if ui.verbose:
366 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
366 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
367 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
367 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
368
368
369 @command('debugcreatestreamclonebundle', [], 'FILE')
369 @command('debugcreatestreamclonebundle', [], 'FILE')
370 def debugcreatestreamclonebundle(ui, repo, fname):
370 def debugcreatestreamclonebundle(ui, repo, fname):
371 """create a stream clone bundle file
371 """create a stream clone bundle file
372
372
373 Stream bundles are special bundles that are essentially archives of
373 Stream bundles are special bundles that are essentially archives of
374 revlog files. They are commonly used for cloning very quickly.
374 revlog files. They are commonly used for cloning very quickly.
375 """
375 """
376 requirements, gen = streamclone.generatebundlev1(repo)
376 requirements, gen = streamclone.generatebundlev1(repo)
377 changegroup.writechunks(ui, gen, fname)
377 changegroup.writechunks(ui, gen, fname)
378
378
379 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
379 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
380
380
381 @command('debugdag',
381 @command('debugdag',
382 [('t', 'tags', None, _('use tags as labels')),
382 [('t', 'tags', None, _('use tags as labels')),
383 ('b', 'branches', None, _('annotate with branch names')),
383 ('b', 'branches', None, _('annotate with branch names')),
384 ('', 'dots', None, _('use dots for runs')),
384 ('', 'dots', None, _('use dots for runs')),
385 ('s', 'spaces', None, _('separate elements by spaces'))],
385 ('s', 'spaces', None, _('separate elements by spaces'))],
386 _('[OPTION]... [FILE [REV]...]'),
386 _('[OPTION]... [FILE [REV]...]'),
387 optionalrepo=True)
387 optionalrepo=True)
388 def debugdag(ui, repo, file_=None, *revs, **opts):
388 def debugdag(ui, repo, file_=None, *revs, **opts):
389 """format the changelog or an index DAG as a concise textual description
389 """format the changelog or an index DAG as a concise textual description
390
390
391 If you pass a revlog index, the revlog's DAG is emitted. If you list
391 If you pass a revlog index, the revlog's DAG is emitted. If you list
392 revision numbers, they get labeled in the output as rN.
392 revision numbers, they get labeled in the output as rN.
393
393
394 Otherwise, the changelog DAG of the current repo is emitted.
394 Otherwise, the changelog DAG of the current repo is emitted.
395 """
395 """
396 spaces = opts.get('spaces')
396 spaces = opts.get('spaces')
397 dots = opts.get('dots')
397 dots = opts.get('dots')
398 if file_:
398 if file_:
399 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
399 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
400 file_)
400 file_)
401 revs = set((int(r) for r in revs))
401 revs = set((int(r) for r in revs))
402 def events():
402 def events():
403 for r in rlog:
403 for r in rlog:
404 yield 'n', (r, list(p for p in rlog.parentrevs(r)
404 yield 'n', (r, list(p for p in rlog.parentrevs(r)
405 if p != -1))
405 if p != -1))
406 if r in revs:
406 if r in revs:
407 yield 'l', (r, "r%i" % r)
407 yield 'l', (r, "r%i" % r)
408 elif repo:
408 elif repo:
409 cl = repo.changelog
409 cl = repo.changelog
410 tags = opts.get('tags')
410 tags = opts.get('tags')
411 branches = opts.get('branches')
411 branches = opts.get('branches')
412 if tags:
412 if tags:
413 labels = {}
413 labels = {}
414 for l, n in repo.tags().items():
414 for l, n in repo.tags().items():
415 labels.setdefault(cl.rev(n), []).append(l)
415 labels.setdefault(cl.rev(n), []).append(l)
416 def events():
416 def events():
417 b = "default"
417 b = "default"
418 for r in cl:
418 for r in cl:
419 if branches:
419 if branches:
420 newb = cl.read(cl.node(r))[5]['branch']
420 newb = cl.read(cl.node(r))[5]['branch']
421 if newb != b:
421 if newb != b:
422 yield 'a', newb
422 yield 'a', newb
423 b = newb
423 b = newb
424 yield 'n', (r, list(p for p in cl.parentrevs(r)
424 yield 'n', (r, list(p for p in cl.parentrevs(r)
425 if p != -1))
425 if p != -1))
426 if tags:
426 if tags:
427 ls = labels.get(r)
427 ls = labels.get(r)
428 if ls:
428 if ls:
429 for l in ls:
429 for l in ls:
430 yield 'l', (r, l)
430 yield 'l', (r, l)
431 else:
431 else:
432 raise error.Abort(_('need repo for changelog dag'))
432 raise error.Abort(_('need repo for changelog dag'))
433
433
434 for line in dagparser.dagtextlines(events(),
434 for line in dagparser.dagtextlines(events(),
435 addspaces=spaces,
435 addspaces=spaces,
436 wraplabels=True,
436 wraplabels=True,
437 wrapannotations=True,
437 wrapannotations=True,
438 wrapnonlinear=dots,
438 wrapnonlinear=dots,
439 usedots=dots,
439 usedots=dots,
440 maxlinewidth=70):
440 maxlinewidth=70):
441 ui.write(line)
441 ui.write(line)
442 ui.write("\n")
442 ui.write("\n")
443
443
444 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
444 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
445 def debugdata(ui, repo, file_, rev=None, **opts):
445 def debugdata(ui, repo, file_, rev=None, **opts):
446 """dump the contents of a data file revision"""
446 """dump the contents of a data file revision"""
447 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
447 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
448 if rev is not None:
448 if rev is not None:
449 raise error.CommandError('debugdata', _('invalid arguments'))
449 raise error.CommandError('debugdata', _('invalid arguments'))
450 file_, rev = None, file_
450 file_, rev = None, file_
451 elif rev is None:
451 elif rev is None:
452 raise error.CommandError('debugdata', _('invalid arguments'))
452 raise error.CommandError('debugdata', _('invalid arguments'))
453 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
453 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
454 try:
454 try:
455 ui.write(r.revision(r.lookup(rev), raw=True))
455 ui.write(r.revision(r.lookup(rev), raw=True))
456 except KeyError:
456 except KeyError:
457 raise error.Abort(_('invalid revision identifier %s') % rev)
457 raise error.Abort(_('invalid revision identifier %s') % rev)
458
458
459 @command('debugdate',
459 @command('debugdate',
460 [('e', 'extended', None, _('try extended date formats'))],
460 [('e', 'extended', None, _('try extended date formats'))],
461 _('[-e] DATE [RANGE]'),
461 _('[-e] DATE [RANGE]'),
462 norepo=True, optionalrepo=True)
462 norepo=True, optionalrepo=True)
463 def debugdate(ui, date, range=None, **opts):
463 def debugdate(ui, date, range=None, **opts):
464 """parse and display a date"""
464 """parse and display a date"""
465 if opts["extended"]:
465 if opts["extended"]:
466 d = util.parsedate(date, util.extendeddateformats)
466 d = util.parsedate(date, util.extendeddateformats)
467 else:
467 else:
468 d = util.parsedate(date)
468 d = util.parsedate(date)
469 ui.write(("internal: %s %s\n") % d)
469 ui.write(("internal: %s %s\n") % d)
470 ui.write(("standard: %s\n") % util.datestr(d))
470 ui.write(("standard: %s\n") % util.datestr(d))
471 if range:
471 if range:
472 m = util.matchdate(range)
472 m = util.matchdate(range)
473 ui.write(("match: %s\n") % m(d[0]))
473 ui.write(("match: %s\n") % m(d[0]))
474
474
475 @command('debugdeltachain',
475 @command('debugdeltachain',
476 commands.debugrevlogopts + commands.formatteropts,
476 commands.debugrevlogopts + commands.formatteropts,
477 _('-c|-m|FILE'),
477 _('-c|-m|FILE'),
478 optionalrepo=True)
478 optionalrepo=True)
479 def debugdeltachain(ui, repo, file_=None, **opts):
479 def debugdeltachain(ui, repo, file_=None, **opts):
480 """dump information about delta chains in a revlog
480 """dump information about delta chains in a revlog
481
481
482 Output can be templatized. Available template keywords are:
482 Output can be templatized. Available template keywords are:
483
483
484 :``rev``: revision number
484 :``rev``: revision number
485 :``chainid``: delta chain identifier (numbered by unique base)
485 :``chainid``: delta chain identifier (numbered by unique base)
486 :``chainlen``: delta chain length to this revision
486 :``chainlen``: delta chain length to this revision
487 :``prevrev``: previous revision in delta chain
487 :``prevrev``: previous revision in delta chain
488 :``deltatype``: role of delta / how it was computed
488 :``deltatype``: role of delta / how it was computed
489 :``compsize``: compressed size of revision
489 :``compsize``: compressed size of revision
490 :``uncompsize``: uncompressed size of revision
490 :``uncompsize``: uncompressed size of revision
491 :``chainsize``: total size of compressed revisions in chain
491 :``chainsize``: total size of compressed revisions in chain
492 :``chainratio``: total chain size divided by uncompressed revision size
492 :``chainratio``: total chain size divided by uncompressed revision size
493 (new delta chains typically start at ratio 2.00)
493 (new delta chains typically start at ratio 2.00)
494 :``lindist``: linear distance from base revision in delta chain to end
494 :``lindist``: linear distance from base revision in delta chain to end
495 of this revision
495 of this revision
496 :``extradist``: total size of revisions not part of this delta chain from
496 :``extradist``: total size of revisions not part of this delta chain from
497 base of delta chain to end of this revision; a measurement
497 base of delta chain to end of this revision; a measurement
498 of how much extra data we need to read/seek across to read
498 of how much extra data we need to read/seek across to read
499 the delta chain for this revision
499 the delta chain for this revision
500 :``extraratio``: extradist divided by chainsize; another representation of
500 :``extraratio``: extradist divided by chainsize; another representation of
501 how much unrelated data is needed to load this delta chain
501 how much unrelated data is needed to load this delta chain
502 """
502 """
503 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
503 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
504 index = r.index
504 index = r.index
505 generaldelta = r.version & revlog.REVLOGGENERALDELTA
505 generaldelta = r.version & revlog.REVLOGGENERALDELTA
506
506
507 def revinfo(rev):
507 def revinfo(rev):
508 e = index[rev]
508 e = index[rev]
509 compsize = e[1]
509 compsize = e[1]
510 uncompsize = e[2]
510 uncompsize = e[2]
511 chainsize = 0
511 chainsize = 0
512
512
513 if generaldelta:
513 if generaldelta:
514 if e[3] == e[5]:
514 if e[3] == e[5]:
515 deltatype = 'p1'
515 deltatype = 'p1'
516 elif e[3] == e[6]:
516 elif e[3] == e[6]:
517 deltatype = 'p2'
517 deltatype = 'p2'
518 elif e[3] == rev - 1:
518 elif e[3] == rev - 1:
519 deltatype = 'prev'
519 deltatype = 'prev'
520 elif e[3] == rev:
520 elif e[3] == rev:
521 deltatype = 'base'
521 deltatype = 'base'
522 else:
522 else:
523 deltatype = 'other'
523 deltatype = 'other'
524 else:
524 else:
525 if e[3] == rev:
525 if e[3] == rev:
526 deltatype = 'base'
526 deltatype = 'base'
527 else:
527 else:
528 deltatype = 'prev'
528 deltatype = 'prev'
529
529
530 chain = r._deltachain(rev)[0]
530 chain = r._deltachain(rev)[0]
531 for iterrev in chain:
531 for iterrev in chain:
532 e = index[iterrev]
532 e = index[iterrev]
533 chainsize += e[1]
533 chainsize += e[1]
534
534
535 return compsize, uncompsize, deltatype, chain, chainsize
535 return compsize, uncompsize, deltatype, chain, chainsize
536
536
537 fm = ui.formatter('debugdeltachain', opts)
537 fm = ui.formatter('debugdeltachain', opts)
538
538
539 fm.plain(' rev chain# chainlen prev delta '
539 fm.plain(' rev chain# chainlen prev delta '
540 'size rawsize chainsize ratio lindist extradist '
540 'size rawsize chainsize ratio lindist extradist '
541 'extraratio\n')
541 'extraratio\n')
542
542
543 chainbases = {}
543 chainbases = {}
544 for rev in r:
544 for rev in r:
545 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
545 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
546 chainbase = chain[0]
546 chainbase = chain[0]
547 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
547 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
548 basestart = r.start(chainbase)
548 basestart = r.start(chainbase)
549 revstart = r.start(rev)
549 revstart = r.start(rev)
550 lineardist = revstart + comp - basestart
550 lineardist = revstart + comp - basestart
551 extradist = lineardist - chainsize
551 extradist = lineardist - chainsize
552 try:
552 try:
553 prevrev = chain[-2]
553 prevrev = chain[-2]
554 except IndexError:
554 except IndexError:
555 prevrev = -1
555 prevrev = -1
556
556
557 chainratio = float(chainsize) / float(uncomp)
557 chainratio = float(chainsize) / float(uncomp)
558 extraratio = float(extradist) / float(chainsize)
558 extraratio = float(extradist) / float(chainsize)
559
559
560 fm.startitem()
560 fm.startitem()
561 fm.write('rev chainid chainlen prevrev deltatype compsize '
561 fm.write('rev chainid chainlen prevrev deltatype compsize '
562 'uncompsize chainsize chainratio lindist extradist '
562 'uncompsize chainsize chainratio lindist extradist '
563 'extraratio',
563 'extraratio',
564 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
564 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
565 rev, chainid, len(chain), prevrev, deltatype, comp,
565 rev, chainid, len(chain), prevrev, deltatype, comp,
566 uncomp, chainsize, chainratio, lineardist, extradist,
566 uncomp, chainsize, chainratio, lineardist, extradist,
567 extraratio,
567 extraratio,
568 rev=rev, chainid=chainid, chainlen=len(chain),
568 rev=rev, chainid=chainid, chainlen=len(chain),
569 prevrev=prevrev, deltatype=deltatype, compsize=comp,
569 prevrev=prevrev, deltatype=deltatype, compsize=comp,
570 uncompsize=uncomp, chainsize=chainsize,
570 uncompsize=uncomp, chainsize=chainsize,
571 chainratio=chainratio, lindist=lineardist,
571 chainratio=chainratio, lindist=lineardist,
572 extradist=extradist, extraratio=extraratio)
572 extradist=extradist, extraratio=extraratio)
573
573
574 fm.end()
574 fm.end()
575
575
576 @command('debugdiscovery',
576 @command('debugdiscovery',
577 [('', 'old', None, _('use old-style discovery')),
577 [('', 'old', None, _('use old-style discovery')),
578 ('', 'nonheads', None,
578 ('', 'nonheads', None,
579 _('use old-style discovery with non-heads included')),
579 _('use old-style discovery with non-heads included')),
580 ] + commands.remoteopts,
580 ] + commands.remoteopts,
581 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
581 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
582 def debugdiscovery(ui, repo, remoteurl="default", **opts):
582 def debugdiscovery(ui, repo, remoteurl="default", **opts):
583 """runs the changeset discovery protocol in isolation"""
583 """runs the changeset discovery protocol in isolation"""
584 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
584 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
585 opts.get('branch'))
585 opts.get('branch'))
586 remote = hg.peer(repo, opts, remoteurl)
586 remote = hg.peer(repo, opts, remoteurl)
587 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
587 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
588
588
589 # make sure tests are repeatable
589 # make sure tests are repeatable
590 random.seed(12323)
590 random.seed(12323)
591
591
592 def doit(localheads, remoteheads, remote=remote):
592 def doit(localheads, remoteheads, remote=remote):
593 if opts.get('old'):
593 if opts.get('old'):
594 if localheads:
594 if localheads:
595 raise error.Abort('cannot use localheads with old style '
595 raise error.Abort('cannot use localheads with old style '
596 'discovery')
596 'discovery')
597 if not util.safehasattr(remote, 'branches'):
597 if not util.safehasattr(remote, 'branches'):
598 # enable in-client legacy support
598 # enable in-client legacy support
599 remote = localrepo.locallegacypeer(remote.local())
599 remote = localrepo.locallegacypeer(remote.local())
600 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
600 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
601 force=True)
601 force=True)
602 common = set(common)
602 common = set(common)
603 if not opts.get('nonheads'):
603 if not opts.get('nonheads'):
604 ui.write(("unpruned common: %s\n") %
604 ui.write(("unpruned common: %s\n") %
605 " ".join(sorted(short(n) for n in common)))
605 " ".join(sorted(short(n) for n in common)))
606 dag = dagutil.revlogdag(repo.changelog)
606 dag = dagutil.revlogdag(repo.changelog)
607 all = dag.ancestorset(dag.internalizeall(common))
607 all = dag.ancestorset(dag.internalizeall(common))
608 common = dag.externalizeall(dag.headsetofconnecteds(all))
608 common = dag.externalizeall(dag.headsetofconnecteds(all))
609 else:
609 else:
610 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
610 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
611 common = set(common)
611 common = set(common)
612 rheads = set(hds)
612 rheads = set(hds)
613 lheads = set(repo.heads())
613 lheads = set(repo.heads())
614 ui.write(("common heads: %s\n") %
614 ui.write(("common heads: %s\n") %
615 " ".join(sorted(short(n) for n in common)))
615 " ".join(sorted(short(n) for n in common)))
616 if lheads <= common:
616 if lheads <= common:
617 ui.write(("local is subset\n"))
617 ui.write(("local is subset\n"))
618 elif rheads <= common:
618 elif rheads <= common:
619 ui.write(("remote is subset\n"))
619 ui.write(("remote is subset\n"))
620
620
621 serverlogs = opts.get('serverlog')
621 serverlogs = opts.get('serverlog')
622 if serverlogs:
622 if serverlogs:
623 for filename in serverlogs:
623 for filename in serverlogs:
624 with open(filename, 'r') as logfile:
624 with open(filename, 'r') as logfile:
625 line = logfile.readline()
625 line = logfile.readline()
626 while line:
626 while line:
627 parts = line.strip().split(';')
627 parts = line.strip().split(';')
628 op = parts[1]
628 op = parts[1]
629 if op == 'cg':
629 if op == 'cg':
630 pass
630 pass
631 elif op == 'cgss':
631 elif op == 'cgss':
632 doit(parts[2].split(' '), parts[3].split(' '))
632 doit(parts[2].split(' '), parts[3].split(' '))
633 elif op == 'unb':
633 elif op == 'unb':
634 doit(parts[3].split(' '), parts[2].split(' '))
634 doit(parts[3].split(' '), parts[2].split(' '))
635 line = logfile.readline()
635 line = logfile.readline()
636 else:
636 else:
637 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
637 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
638 opts.get('remote_head'))
638 opts.get('remote_head'))
639 localrevs = opts.get('local_head')
639 localrevs = opts.get('local_head')
640 doit(localrevs, remoterevs)
640 doit(localrevs, remoterevs)
641
641
642 @command('debugextensions', commands.formatteropts, [], norepo=True)
642 @command('debugextensions', commands.formatteropts, [], norepo=True)
643 def debugextensions(ui, **opts):
643 def debugextensions(ui, **opts):
644 '''show information about active extensions'''
644 '''show information about active extensions'''
645 exts = extensions.extensions(ui)
645 exts = extensions.extensions(ui)
646 hgver = util.version()
646 hgver = util.version()
647 fm = ui.formatter('debugextensions', opts)
647 fm = ui.formatter('debugextensions', opts)
648 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
648 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
649 isinternal = extensions.ismoduleinternal(extmod)
649 isinternal = extensions.ismoduleinternal(extmod)
650 extsource = extmod.__file__
650 extsource = extmod.__file__
651 if isinternal:
651 if isinternal:
652 exttestedwith = [] # never expose magic string to users
652 exttestedwith = [] # never expose magic string to users
653 else:
653 else:
654 exttestedwith = getattr(extmod, 'testedwith', '').split()
654 exttestedwith = getattr(extmod, 'testedwith', '').split()
655 extbuglink = getattr(extmod, 'buglink', None)
655 extbuglink = getattr(extmod, 'buglink', None)
656
656
657 fm.startitem()
657 fm.startitem()
658
658
659 if ui.quiet or ui.verbose:
659 if ui.quiet or ui.verbose:
660 fm.write('name', '%s\n', extname)
660 fm.write('name', '%s\n', extname)
661 else:
661 else:
662 fm.write('name', '%s', extname)
662 fm.write('name', '%s', extname)
663 if isinternal or hgver in exttestedwith:
663 if isinternal or hgver in exttestedwith:
664 fm.plain('\n')
664 fm.plain('\n')
665 elif not exttestedwith:
665 elif not exttestedwith:
666 fm.plain(_(' (untested!)\n'))
666 fm.plain(_(' (untested!)\n'))
667 else:
667 else:
668 lasttestedversion = exttestedwith[-1]
668 lasttestedversion = exttestedwith[-1]
669 fm.plain(' (%s!)\n' % lasttestedversion)
669 fm.plain(' (%s!)\n' % lasttestedversion)
670
670
671 fm.condwrite(ui.verbose and extsource, 'source',
671 fm.condwrite(ui.verbose and extsource, 'source',
672 _(' location: %s\n'), extsource or "")
672 _(' location: %s\n'), extsource or "")
673
673
674 if ui.verbose:
674 if ui.verbose:
675 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
675 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
676 fm.data(bundled=isinternal)
676 fm.data(bundled=isinternal)
677
677
678 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
678 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
679 _(' tested with: %s\n'),
679 _(' tested with: %s\n'),
680 fm.formatlist(exttestedwith, name='ver'))
680 fm.formatlist(exttestedwith, name='ver'))
681
681
682 fm.condwrite(ui.verbose and extbuglink, 'buglink',
682 fm.condwrite(ui.verbose and extbuglink, 'buglink',
683 _(' bug reporting: %s\n'), extbuglink or "")
683 _(' bug reporting: %s\n'), extbuglink or "")
684
684
685 fm.end()
685 fm.end()
686
686
687 @command('debugfileset',
687 @command('debugfileset',
688 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
688 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
689 _('[-r REV] FILESPEC'))
689 _('[-r REV] FILESPEC'))
690 def debugfileset(ui, repo, expr, **opts):
690 def debugfileset(ui, repo, expr, **opts):
691 '''parse and apply a fileset specification'''
691 '''parse and apply a fileset specification'''
692 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
692 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
693 if ui.verbose:
693 if ui.verbose:
694 tree = fileset.parse(expr)
694 tree = fileset.parse(expr)
695 ui.note(fileset.prettyformat(tree), "\n")
695 ui.note(fileset.prettyformat(tree), "\n")
696
696
697 for f in ctx.getfileset(expr):
697 for f in ctx.getfileset(expr):
698 ui.write("%s\n" % f)
698 ui.write("%s\n" % f)
699
699
700 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
700 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
701 def debugfsinfo(ui, path="."):
701 def debugfsinfo(ui, path="."):
702 """show information detected about current filesystem"""
702 """show information detected about current filesystem"""
703 util.writefile('.debugfsinfo', '')
703 util.writefile('.debugfsinfo', '')
704 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
704 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
705 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
705 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
706 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
706 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
707 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
707 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
708 and 'yes' or 'no'))
708 and 'yes' or 'no'))
709 os.unlink('.debugfsinfo')
709 os.unlink('.debugfsinfo')
710
710
711 @command('debuggetbundle',
711 @command('debuggetbundle',
712 [('H', 'head', [], _('id of head node'), _('ID')),
712 [('H', 'head', [], _('id of head node'), _('ID')),
713 ('C', 'common', [], _('id of common node'), _('ID')),
713 ('C', 'common', [], _('id of common node'), _('ID')),
714 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
714 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
715 _('REPO FILE [-H|-C ID]...'),
715 _('REPO FILE [-H|-C ID]...'),
716 norepo=True)
716 norepo=True)
717 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
717 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
718 """retrieves a bundle from a repo
718 """retrieves a bundle from a repo
719
719
720 Every ID must be a full-length hex node id string. Saves the bundle to the
720 Every ID must be a full-length hex node id string. Saves the bundle to the
721 given file.
721 given file.
722 """
722 """
723 repo = hg.peer(ui, opts, repopath)
723 repo = hg.peer(ui, opts, repopath)
724 if not repo.capable('getbundle'):
724 if not repo.capable('getbundle'):
725 raise error.Abort("getbundle() not supported by target repository")
725 raise error.Abort("getbundle() not supported by target repository")
726 args = {}
726 args = {}
727 if common:
727 if common:
728 args['common'] = [bin(s) for s in common]
728 args['common'] = [bin(s) for s in common]
729 if head:
729 if head:
730 args['heads'] = [bin(s) for s in head]
730 args['heads'] = [bin(s) for s in head]
731 # TODO: get desired bundlecaps from command line.
731 # TODO: get desired bundlecaps from command line.
732 args['bundlecaps'] = None
732 args['bundlecaps'] = None
733 bundle = repo.getbundle('debug', **args)
733 bundle = repo.getbundle('debug', **args)
734
734
735 bundletype = opts.get('type', 'bzip2').lower()
735 bundletype = opts.get('type', 'bzip2').lower()
736 btypes = {'none': 'HG10UN',
736 btypes = {'none': 'HG10UN',
737 'bzip2': 'HG10BZ',
737 'bzip2': 'HG10BZ',
738 'gzip': 'HG10GZ',
738 'gzip': 'HG10GZ',
739 'bundle2': 'HG20'}
739 'bundle2': 'HG20'}
740 bundletype = btypes.get(bundletype)
740 bundletype = btypes.get(bundletype)
741 if bundletype not in bundle2.bundletypes:
741 if bundletype not in bundle2.bundletypes:
742 raise error.Abort(_('unknown bundle type specified with --type'))
742 raise error.Abort(_('unknown bundle type specified with --type'))
743 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
743 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
744
744
745 @command('debugignore', [], '[FILE]')
745 @command('debugignore', [], '[FILE]')
746 def debugignore(ui, repo, *files, **opts):
746 def debugignore(ui, repo, *files, **opts):
747 """display the combined ignore pattern and information about ignored files
747 """display the combined ignore pattern and information about ignored files
748
748
749 With no argument display the combined ignore pattern.
749 With no argument display the combined ignore pattern.
750
750
751 Given space separated file names, shows if the given file is ignored and
751 Given space separated file names, shows if the given file is ignored and
752 if so, show the ignore rule (file and line number) that matched it.
752 if so, show the ignore rule (file and line number) that matched it.
753 """
753 """
754 ignore = repo.dirstate._ignore
754 ignore = repo.dirstate._ignore
755 if not files:
755 if not files:
756 # Show all the patterns
756 # Show all the patterns
757 includepat = getattr(ignore, 'includepat', None)
757 includepat = getattr(ignore, 'includepat', None)
758 if includepat is not None:
758 if includepat is not None:
759 ui.write("%s\n" % includepat)
759 ui.write("%s\n" % includepat)
760 else:
760 else:
761 raise error.Abort(_("no ignore patterns found"))
761 raise error.Abort(_("no ignore patterns found"))
762 else:
762 else:
763 for f in files:
763 for f in files:
764 nf = util.normpath(f)
764 nf = util.normpath(f)
765 ignored = None
765 ignored = None
766 ignoredata = None
766 ignoredata = None
767 if nf != '.':
767 if nf != '.':
768 if ignore(nf):
768 if ignore(nf):
769 ignored = nf
769 ignored = nf
770 ignoredata = repo.dirstate._ignorefileandline(nf)
770 ignoredata = repo.dirstate._ignorefileandline(nf)
771 else:
771 else:
772 for p in util.finddirs(nf):
772 for p in util.finddirs(nf):
773 if ignore(p):
773 if ignore(p):
774 ignored = p
774 ignored = p
775 ignoredata = repo.dirstate._ignorefileandline(p)
775 ignoredata = repo.dirstate._ignorefileandline(p)
776 break
776 break
777 if ignored:
777 if ignored:
778 if ignored == nf:
778 if ignored == nf:
779 ui.write(_("%s is ignored\n") % f)
779 ui.write(_("%s is ignored\n") % f)
780 else:
780 else:
781 ui.write(_("%s is ignored because of "
781 ui.write(_("%s is ignored because of "
782 "containing folder %s\n")
782 "containing folder %s\n")
783 % (f, ignored))
783 % (f, ignored))
784 ignorefile, lineno, line = ignoredata
784 ignorefile, lineno, line = ignoredata
785 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
785 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
786 % (ignorefile, lineno, line))
786 % (ignorefile, lineno, line))
787 else:
787 else:
788 ui.write(_("%s is not ignored\n") % f)
788 ui.write(_("%s is not ignored\n") % f)
789
789
790 @command('debugindex', commands.debugrevlogopts +
790 @command('debugindex', commands.debugrevlogopts +
791 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
791 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
792 _('[-f FORMAT] -c|-m|FILE'),
792 _('[-f FORMAT] -c|-m|FILE'),
793 optionalrepo=True)
793 optionalrepo=True)
794 def debugindex(ui, repo, file_=None, **opts):
794 def debugindex(ui, repo, file_=None, **opts):
795 """dump the contents of an index file"""
795 """dump the contents of an index file"""
796 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
796 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
797 format = opts.get('format', 0)
797 format = opts.get('format', 0)
798 if format not in (0, 1):
798 if format not in (0, 1):
799 raise error.Abort(_("unknown format %d") % format)
799 raise error.Abort(_("unknown format %d") % format)
800
800
801 generaldelta = r.version & revlog.REVLOGGENERALDELTA
801 generaldelta = r.version & revlog.REVLOGGENERALDELTA
802 if generaldelta:
802 if generaldelta:
803 basehdr = ' delta'
803 basehdr = ' delta'
804 else:
804 else:
805 basehdr = ' base'
805 basehdr = ' base'
806
806
807 if ui.debugflag:
807 if ui.debugflag:
808 shortfn = hex
808 shortfn = hex
809 else:
809 else:
810 shortfn = short
810 shortfn = short
811
811
812 # There might not be anything in r, so have a sane default
812 # There might not be anything in r, so have a sane default
813 idlen = 12
813 idlen = 12
814 for i in r:
814 for i in r:
815 idlen = len(shortfn(r.node(i)))
815 idlen = len(shortfn(r.node(i)))
816 break
816 break
817
817
818 if format == 0:
818 if format == 0:
819 ui.write((" rev offset length " + basehdr + " linkrev"
819 ui.write((" rev offset length " + basehdr + " linkrev"
820 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
820 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
821 elif format == 1:
821 elif format == 1:
822 ui.write((" rev flag offset length"
822 ui.write((" rev flag offset length"
823 " size " + basehdr + " link p1 p2"
823 " size " + basehdr + " link p1 p2"
824 " %s\n") % "nodeid".rjust(idlen))
824 " %s\n") % "nodeid".rjust(idlen))
825
825
826 for i in r:
826 for i in r:
827 node = r.node(i)
827 node = r.node(i)
828 if generaldelta:
828 if generaldelta:
829 base = r.deltaparent(i)
829 base = r.deltaparent(i)
830 else:
830 else:
831 base = r.chainbase(i)
831 base = r.chainbase(i)
832 if format == 0:
832 if format == 0:
833 try:
833 try:
834 pp = r.parents(node)
834 pp = r.parents(node)
835 except Exception:
835 except Exception:
836 pp = [nullid, nullid]
836 pp = [nullid, nullid]
837 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
837 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
838 i, r.start(i), r.length(i), base, r.linkrev(i),
838 i, r.start(i), r.length(i), base, r.linkrev(i),
839 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
839 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
840 elif format == 1:
840 elif format == 1:
841 pr = r.parentrevs(i)
841 pr = r.parentrevs(i)
842 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
842 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
843 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
843 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
844 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
844 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
845
845
846 @command('debugindexdot', commands.debugrevlogopts,
846 @command('debugindexdot', commands.debugrevlogopts,
847 _('-c|-m|FILE'), optionalrepo=True)
847 _('-c|-m|FILE'), optionalrepo=True)
848 def debugindexdot(ui, repo, file_=None, **opts):
848 def debugindexdot(ui, repo, file_=None, **opts):
849 """dump an index DAG as a graphviz dot file"""
849 """dump an index DAG as a graphviz dot file"""
850 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
850 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
851 ui.write(("digraph G {\n"))
851 ui.write(("digraph G {\n"))
852 for i in r:
852 for i in r:
853 node = r.node(i)
853 node = r.node(i)
854 pp = r.parents(node)
854 pp = r.parents(node)
855 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
855 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
856 if pp[1] != nullid:
856 if pp[1] != nullid:
857 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
857 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
858 ui.write("}\n")
858 ui.write("}\n")
859
859
860 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
860 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
861 def debuginstall(ui, **opts):
861 def debuginstall(ui, **opts):
862 '''test Mercurial installation
862 '''test Mercurial installation
863
863
864 Returns 0 on success.
864 Returns 0 on success.
865 '''
865 '''
866
866
867 def writetemp(contents):
867 def writetemp(contents):
868 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
868 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
869 f = os.fdopen(fd, "wb")
869 f = os.fdopen(fd, "wb")
870 f.write(contents)
870 f.write(contents)
871 f.close()
871 f.close()
872 return name
872 return name
873
873
874 problems = 0
874 problems = 0
875
875
876 fm = ui.formatter('debuginstall', opts)
876 fm = ui.formatter('debuginstall', opts)
877 fm.startitem()
877 fm.startitem()
878
878
879 # encoding
879 # encoding
880 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
880 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
881 err = None
881 err = None
882 try:
882 try:
883 encoding.fromlocal("test")
883 encoding.fromlocal("test")
884 except error.Abort as inst:
884 except error.Abort as inst:
885 err = inst
885 err = inst
886 problems += 1
886 problems += 1
887 fm.condwrite(err, 'encodingerror', _(" %s\n"
887 fm.condwrite(err, 'encodingerror', _(" %s\n"
888 " (check that your locale is properly set)\n"), err)
888 " (check that your locale is properly set)\n"), err)
889
889
890 # Python
890 # Python
891 fm.write('pythonexe', _("checking Python executable (%s)\n"),
891 fm.write('pythonexe', _("checking Python executable (%s)\n"),
892 pycompat.sysexecutable)
892 pycompat.sysexecutable)
893 fm.write('pythonver', _("checking Python version (%s)\n"),
893 fm.write('pythonver', _("checking Python version (%s)\n"),
894 ("%d.%d.%d" % sys.version_info[:3]))
894 ("%d.%d.%d" % sys.version_info[:3]))
895 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
895 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
896 os.path.dirname(pycompat.fsencode(os.__file__)))
896 os.path.dirname(pycompat.fsencode(os.__file__)))
897
897
898 security = set(sslutil.supportedprotocols)
898 security = set(sslutil.supportedprotocols)
899 if sslutil.hassni:
899 if sslutil.hassni:
900 security.add('sni')
900 security.add('sni')
901
901
902 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
902 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
903 fm.formatlist(sorted(security), name='protocol',
903 fm.formatlist(sorted(security), name='protocol',
904 fmt='%s', sep=','))
904 fmt='%s', sep=','))
905
905
906 # These are warnings, not errors. So don't increment problem count. This
906 # These are warnings, not errors. So don't increment problem count. This
907 # may change in the future.
907 # may change in the future.
908 if 'tls1.2' not in security:
908 if 'tls1.2' not in security:
909 fm.plain(_(' TLS 1.2 not supported by Python install; '
909 fm.plain(_(' TLS 1.2 not supported by Python install; '
910 'network connections lack modern security\n'))
910 'network connections lack modern security\n'))
911 if 'sni' not in security:
911 if 'sni' not in security:
912 fm.plain(_(' SNI not supported by Python install; may have '
912 fm.plain(_(' SNI not supported by Python install; may have '
913 'connectivity issues with some servers\n'))
913 'connectivity issues with some servers\n'))
914
914
915 # TODO print CA cert info
915 # TODO print CA cert info
916
916
917 # hg version
917 # hg version
918 hgver = util.version()
918 hgver = util.version()
919 fm.write('hgver', _("checking Mercurial version (%s)\n"),
919 fm.write('hgver', _("checking Mercurial version (%s)\n"),
920 hgver.split('+')[0])
920 hgver.split('+')[0])
921 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
921 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
922 '+'.join(hgver.split('+')[1:]))
922 '+'.join(hgver.split('+')[1:]))
923
923
924 # compiled modules
924 # compiled modules
925 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
925 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
926 policy.policy)
926 policy.policy)
927 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
927 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
928 os.path.dirname(__file__))
928 os.path.dirname(__file__))
929
929
930 err = None
930 err = None
931 try:
931 try:
932 from . import (
932 from . import (
933 base85,
933 base85,
934 bdiff,
934 bdiff,
935 mpatch,
935 mpatch,
936 osutil,
936 osutil,
937 )
937 )
938 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
938 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
939 except Exception as inst:
939 except Exception as inst:
940 err = inst
940 err = inst
941 problems += 1
941 problems += 1
942 fm.condwrite(err, 'extensionserror', " %s\n", err)
942 fm.condwrite(err, 'extensionserror', " %s\n", err)
943
943
944 compengines = util.compengines._engines.values()
944 compengines = util.compengines._engines.values()
945 fm.write('compengines', _('checking registered compression engines (%s)\n'),
945 fm.write('compengines', _('checking registered compression engines (%s)\n'),
946 fm.formatlist(sorted(e.name() for e in compengines),
946 fm.formatlist(sorted(e.name() for e in compengines),
947 name='compengine', fmt='%s', sep=', '))
947 name='compengine', fmt='%s', sep=', '))
948 fm.write('compenginesavail', _('checking available compression engines '
948 fm.write('compenginesavail', _('checking available compression engines '
949 '(%s)\n'),
949 '(%s)\n'),
950 fm.formatlist(sorted(e.name() for e in compengines
950 fm.formatlist(sorted(e.name() for e in compengines
951 if e.available()),
951 if e.available()),
952 name='compengine', fmt='%s', sep=', '))
952 name='compengine', fmt='%s', sep=', '))
953 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
953 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
954 fm.write('compenginesserver', _('checking available compression engines '
954 fm.write('compenginesserver', _('checking available compression engines '
955 'for wire protocol (%s)\n'),
955 'for wire protocol (%s)\n'),
956 fm.formatlist([e.name() for e in wirecompengines
956 fm.formatlist([e.name() for e in wirecompengines
957 if e.wireprotosupport()],
957 if e.wireprotosupport()],
958 name='compengine', fmt='%s', sep=', '))
958 name='compengine', fmt='%s', sep=', '))
959
959
960 # templates
960 # templates
961 p = templater.templatepaths()
961 p = templater.templatepaths()
962 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
962 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
963 fm.condwrite(not p, '', _(" no template directories found\n"))
963 fm.condwrite(not p, '', _(" no template directories found\n"))
964 if p:
964 if p:
965 m = templater.templatepath("map-cmdline.default")
965 m = templater.templatepath("map-cmdline.default")
966 if m:
966 if m:
967 # template found, check if it is working
967 # template found, check if it is working
968 err = None
968 err = None
969 try:
969 try:
970 templater.templater.frommapfile(m)
970 templater.templater.frommapfile(m)
971 except Exception as inst:
971 except Exception as inst:
972 err = inst
972 err = inst
973 p = None
973 p = None
974 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
974 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
975 else:
975 else:
976 p = None
976 p = None
977 fm.condwrite(p, 'defaulttemplate',
977 fm.condwrite(p, 'defaulttemplate',
978 _("checking default template (%s)\n"), m)
978 _("checking default template (%s)\n"), m)
979 fm.condwrite(not m, 'defaulttemplatenotfound',
979 fm.condwrite(not m, 'defaulttemplatenotfound',
980 _(" template '%s' not found\n"), "default")
980 _(" template '%s' not found\n"), "default")
981 if not p:
981 if not p:
982 problems += 1
982 problems += 1
983 fm.condwrite(not p, '',
983 fm.condwrite(not p, '',
984 _(" (templates seem to have been installed incorrectly)\n"))
984 _(" (templates seem to have been installed incorrectly)\n"))
985
985
986 # editor
986 # editor
987 editor = ui.geteditor()
987 editor = ui.geteditor()
988 editor = util.expandpath(editor)
988 editor = util.expandpath(editor)
989 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
989 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
990 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
990 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
991 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
991 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
992 _(" No commit editor set and can't find %s in PATH\n"
992 _(" No commit editor set and can't find %s in PATH\n"
993 " (specify a commit editor in your configuration"
993 " (specify a commit editor in your configuration"
994 " file)\n"), not cmdpath and editor == 'vi' and editor)
994 " file)\n"), not cmdpath and editor == 'vi' and editor)
995 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
995 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
996 _(" Can't find editor '%s' in PATH\n"
996 _(" Can't find editor '%s' in PATH\n"
997 " (specify a commit editor in your configuration"
997 " (specify a commit editor in your configuration"
998 " file)\n"), not cmdpath and editor)
998 " file)\n"), not cmdpath and editor)
999 if not cmdpath and editor != 'vi':
999 if not cmdpath and editor != 'vi':
1000 problems += 1
1000 problems += 1
1001
1001
1002 # check username
1002 # check username
1003 username = None
1003 username = None
1004 err = None
1004 err = None
1005 try:
1005 try:
1006 username = ui.username()
1006 username = ui.username()
1007 except error.Abort as e:
1007 except error.Abort as e:
1008 err = e
1008 err = e
1009 problems += 1
1009 problems += 1
1010
1010
1011 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1011 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1012 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1012 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1013 " (specify a username in your configuration file)\n"), err)
1013 " (specify a username in your configuration file)\n"), err)
1014
1014
1015 fm.condwrite(not problems, '',
1015 fm.condwrite(not problems, '',
1016 _("no problems detected\n"))
1016 _("no problems detected\n"))
1017 if not problems:
1017 if not problems:
1018 fm.data(problems=problems)
1018 fm.data(problems=problems)
1019 fm.condwrite(problems, 'problems',
1019 fm.condwrite(problems, 'problems',
1020 _("%d problems detected,"
1020 _("%d problems detected,"
1021 " please check your install!\n"), problems)
1021 " please check your install!\n"), problems)
1022 fm.end()
1022 fm.end()
1023
1023
1024 return problems
1024 return problems
1025
1025
1026 @command('debugknown', [], _('REPO ID...'), norepo=True)
1026 @command('debugknown', [], _('REPO ID...'), norepo=True)
1027 def debugknown(ui, repopath, *ids, **opts):
1027 def debugknown(ui, repopath, *ids, **opts):
1028 """test whether node ids are known to a repo
1028 """test whether node ids are known to a repo
1029
1029
1030 Every ID must be a full-length hex node id string. Returns a list of 0s
1030 Every ID must be a full-length hex node id string. Returns a list of 0s
1031 and 1s indicating unknown/known.
1031 and 1s indicating unknown/known.
1032 """
1032 """
1033 repo = hg.peer(ui, opts, repopath)
1033 repo = hg.peer(ui, opts, repopath)
1034 if not repo.capable('known'):
1034 if not repo.capable('known'):
1035 raise error.Abort("known() not supported by target repository")
1035 raise error.Abort("known() not supported by target repository")
1036 flags = repo.known([bin(s) for s in ids])
1036 flags = repo.known([bin(s) for s in ids])
1037 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1037 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1038
1038
1039 @command('debuglabelcomplete', [], _('LABEL...'))
1040 def debuglabelcomplete(ui, repo, *args):
1041 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1042 commands.debugnamecomplete(ui, repo, *args)
1043
1039 @command('debugupgraderepo', [
1044 @command('debugupgraderepo', [
1040 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1045 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1041 ('', 'run', False, _('performs an upgrade')),
1046 ('', 'run', False, _('performs an upgrade')),
1042 ])
1047 ])
1043 def debugupgraderepo(ui, repo, run=False, optimize=None):
1048 def debugupgraderepo(ui, repo, run=False, optimize=None):
1044 """upgrade a repository to use different features
1049 """upgrade a repository to use different features
1045
1050
1046 If no arguments are specified, the repository is evaluated for upgrade
1051 If no arguments are specified, the repository is evaluated for upgrade
1047 and a list of problems and potential optimizations is printed.
1052 and a list of problems and potential optimizations is printed.
1048
1053
1049 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1054 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1050 can be influenced via additional arguments. More details will be provided
1055 can be influenced via additional arguments. More details will be provided
1051 by the command output when run without ``--run``.
1056 by the command output when run without ``--run``.
1052
1057
1053 During the upgrade, the repository will be locked and no writes will be
1058 During the upgrade, the repository will be locked and no writes will be
1054 allowed.
1059 allowed.
1055
1060
1056 At the end of the upgrade, the repository may not be readable while new
1061 At the end of the upgrade, the repository may not be readable while new
1057 repository data is swapped in. This window will be as long as it takes to
1062 repository data is swapped in. This window will be as long as it takes to
1058 rename some directories inside the ``.hg`` directory. On most machines, this
1063 rename some directories inside the ``.hg`` directory. On most machines, this
1059 should complete almost instantaneously and the chances of a consumer being
1064 should complete almost instantaneously and the chances of a consumer being
1060 unable to access the repository should be low.
1065 unable to access the repository should be low.
1061 """
1066 """
1062 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1067 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now