##// END OF EJS Templates
bisect: simplify conditional in 'check_state'...
Pierre-Yves David -
r30125:3528117c default
parent child Browse files
Show More
@@ -1,7353 +1,7353 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __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 operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 formatter,
49 formatter,
50 graphmod,
50 graphmod,
51 hbisect,
51 hbisect,
52 help,
52 help,
53 hg,
53 hg,
54 hgweb,
54 hgweb,
55 localrepo,
55 localrepo,
56 lock as lockmod,
56 lock as lockmod,
57 merge as mergemod,
57 merge as mergemod,
58 minirst,
58 minirst,
59 obsolete,
59 obsolete,
60 patch,
60 patch,
61 phases,
61 phases,
62 policy,
62 policy,
63 pvec,
63 pvec,
64 repair,
64 repair,
65 revlog,
65 revlog,
66 revset,
66 revset,
67 scmutil,
67 scmutil,
68 setdiscovery,
68 setdiscovery,
69 simplemerge,
69 simplemerge,
70 sshserver,
70 sshserver,
71 streamclone,
71 streamclone,
72 templatekw,
72 templatekw,
73 templater,
73 templater,
74 treediscovery,
74 treediscovery,
75 ui as uimod,
75 ui as uimod,
76 util,
76 util,
77 )
77 )
78
78
79 release = lockmod.release
79 release = lockmod.release
80
80
81 table = {}
81 table = {}
82
82
83 command = cmdutil.command(table)
83 command = cmdutil.command(table)
84
84
85 # label constants
85 # label constants
86 # until 3.5, bookmarks.current was the advertised name, not
86 # until 3.5, bookmarks.current was the advertised name, not
87 # bookmarks.active, so we must use both to avoid breaking old
87 # bookmarks.active, so we must use both to avoid breaking old
88 # custom styles
88 # custom styles
89 activebookmarklabel = 'bookmarks.active bookmarks.current'
89 activebookmarklabel = 'bookmarks.active bookmarks.current'
90
90
91 # common command options
91 # common command options
92
92
93 globalopts = [
93 globalopts = [
94 ('R', 'repository', '',
94 ('R', 'repository', '',
95 _('repository root directory or name of overlay bundle file'),
95 _('repository root directory or name of overlay bundle file'),
96 _('REPO')),
96 _('REPO')),
97 ('', 'cwd', '',
97 ('', 'cwd', '',
98 _('change working directory'), _('DIR')),
98 _('change working directory'), _('DIR')),
99 ('y', 'noninteractive', None,
99 ('y', 'noninteractive', None,
100 _('do not prompt, automatically pick the first choice for all prompts')),
100 _('do not prompt, automatically pick the first choice for all prompts')),
101 ('q', 'quiet', None, _('suppress output')),
101 ('q', 'quiet', None, _('suppress output')),
102 ('v', 'verbose', None, _('enable additional output')),
102 ('v', 'verbose', None, _('enable additional output')),
103 ('', 'config', [],
103 ('', 'config', [],
104 _('set/override config option (use \'section.name=value\')'),
104 _('set/override config option (use \'section.name=value\')'),
105 _('CONFIG')),
105 _('CONFIG')),
106 ('', 'debug', None, _('enable debugging output')),
106 ('', 'debug', None, _('enable debugging output')),
107 ('', 'debugger', None, _('start debugger')),
107 ('', 'debugger', None, _('start debugger')),
108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 _('ENCODE')),
109 _('ENCODE')),
110 ('', 'encodingmode', encoding.encodingmode,
110 ('', 'encodingmode', encoding.encodingmode,
111 _('set the charset encoding mode'), _('MODE')),
111 _('set the charset encoding mode'), _('MODE')),
112 ('', 'traceback', None, _('always print a traceback on exception')),
112 ('', 'traceback', None, _('always print a traceback on exception')),
113 ('', 'time', None, _('time how long the command takes')),
113 ('', 'time', None, _('time how long the command takes')),
114 ('', 'profile', None, _('print command execution profile')),
114 ('', 'profile', None, _('print command execution profile')),
115 ('', 'version', None, _('output version information and exit')),
115 ('', 'version', None, _('output version information and exit')),
116 ('h', 'help', None, _('display help and exit')),
116 ('h', 'help', None, _('display help and exit')),
117 ('', 'hidden', False, _('consider hidden changesets')),
117 ('', 'hidden', False, _('consider hidden changesets')),
118 ]
118 ]
119
119
120 dryrunopts = [('n', 'dry-run', None,
120 dryrunopts = [('n', 'dry-run', None,
121 _('do not perform actions, just print output'))]
121 _('do not perform actions, just print output'))]
122
122
123 remoteopts = [
123 remoteopts = [
124 ('e', 'ssh', '',
124 ('e', 'ssh', '',
125 _('specify ssh command to use'), _('CMD')),
125 _('specify ssh command to use'), _('CMD')),
126 ('', 'remotecmd', '',
126 ('', 'remotecmd', '',
127 _('specify hg command to run on the remote side'), _('CMD')),
127 _('specify hg command to run on the remote side'), _('CMD')),
128 ('', 'insecure', None,
128 ('', 'insecure', None,
129 _('do not verify server certificate (ignoring web.cacerts config)')),
129 _('do not verify server certificate (ignoring web.cacerts config)')),
130 ]
130 ]
131
131
132 walkopts = [
132 walkopts = [
133 ('I', 'include', [],
133 ('I', 'include', [],
134 _('include names matching the given patterns'), _('PATTERN')),
134 _('include names matching the given patterns'), _('PATTERN')),
135 ('X', 'exclude', [],
135 ('X', 'exclude', [],
136 _('exclude names matching the given patterns'), _('PATTERN')),
136 _('exclude names matching the given patterns'), _('PATTERN')),
137 ]
137 ]
138
138
139 commitopts = [
139 commitopts = [
140 ('m', 'message', '',
140 ('m', 'message', '',
141 _('use text as commit message'), _('TEXT')),
141 _('use text as commit message'), _('TEXT')),
142 ('l', 'logfile', '',
142 ('l', 'logfile', '',
143 _('read commit message from file'), _('FILE')),
143 _('read commit message from file'), _('FILE')),
144 ]
144 ]
145
145
146 commitopts2 = [
146 commitopts2 = [
147 ('d', 'date', '',
147 ('d', 'date', '',
148 _('record the specified date as commit date'), _('DATE')),
148 _('record the specified date as commit date'), _('DATE')),
149 ('u', 'user', '',
149 ('u', 'user', '',
150 _('record the specified user as committer'), _('USER')),
150 _('record the specified user as committer'), _('USER')),
151 ]
151 ]
152
152
153 # hidden for now
153 # hidden for now
154 formatteropts = [
154 formatteropts = [
155 ('T', 'template', '',
155 ('T', 'template', '',
156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 ]
157 ]
158
158
159 templateopts = [
159 templateopts = [
160 ('', 'style', '',
160 ('', 'style', '',
161 _('display using template map file (DEPRECATED)'), _('STYLE')),
161 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 ('T', 'template', '',
162 ('T', 'template', '',
163 _('display with template'), _('TEMPLATE')),
163 _('display with template'), _('TEMPLATE')),
164 ]
164 ]
165
165
166 logopts = [
166 logopts = [
167 ('p', 'patch', None, _('show patch')),
167 ('p', 'patch', None, _('show patch')),
168 ('g', 'git', None, _('use git extended diff format')),
168 ('g', 'git', None, _('use git extended diff format')),
169 ('l', 'limit', '',
169 ('l', 'limit', '',
170 _('limit number of changes displayed'), _('NUM')),
170 _('limit number of changes displayed'), _('NUM')),
171 ('M', 'no-merges', None, _('do not show merges')),
171 ('M', 'no-merges', None, _('do not show merges')),
172 ('', 'stat', None, _('output diffstat-style summary of changes')),
172 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 ('G', 'graph', None, _("show the revision DAG")),
173 ('G', 'graph', None, _("show the revision DAG")),
174 ] + templateopts
174 ] + templateopts
175
175
176 diffopts = [
176 diffopts = [
177 ('a', 'text', None, _('treat all files as text')),
177 ('a', 'text', None, _('treat all files as text')),
178 ('g', 'git', None, _('use git extended diff format')),
178 ('g', 'git', None, _('use git extended diff format')),
179 ('', 'nodates', None, _('omit dates from diff headers'))
179 ('', 'nodates', None, _('omit dates from diff headers'))
180 ]
180 ]
181
181
182 diffwsopts = [
182 diffwsopts = [
183 ('w', 'ignore-all-space', None,
183 ('w', 'ignore-all-space', None,
184 _('ignore white space when comparing lines')),
184 _('ignore white space when comparing lines')),
185 ('b', 'ignore-space-change', None,
185 ('b', 'ignore-space-change', None,
186 _('ignore changes in the amount of white space')),
186 _('ignore changes in the amount of white space')),
187 ('B', 'ignore-blank-lines', None,
187 ('B', 'ignore-blank-lines', None,
188 _('ignore changes whose lines are all blank')),
188 _('ignore changes whose lines are all blank')),
189 ]
189 ]
190
190
191 diffopts2 = [
191 diffopts2 = [
192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 ('p', 'show-function', None, _('show which function each change is in')),
193 ('p', 'show-function', None, _('show which function each change is in')),
194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 ] + diffwsopts + [
195 ] + diffwsopts + [
196 ('U', 'unified', '',
196 ('U', 'unified', '',
197 _('number of lines of context to show'), _('NUM')),
197 _('number of lines of context to show'), _('NUM')),
198 ('', 'stat', None, _('output diffstat-style summary of changes')),
198 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 ]
200 ]
201
201
202 mergetoolopts = [
202 mergetoolopts = [
203 ('t', 'tool', '', _('specify merge tool')),
203 ('t', 'tool', '', _('specify merge tool')),
204 ]
204 ]
205
205
206 similarityopts = [
206 similarityopts = [
207 ('s', 'similarity', '',
207 ('s', 'similarity', '',
208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 ]
209 ]
210
210
211 subrepoopts = [
211 subrepoopts = [
212 ('S', 'subrepos', None,
212 ('S', 'subrepos', None,
213 _('recurse into subrepositories'))
213 _('recurse into subrepositories'))
214 ]
214 ]
215
215
216 debugrevlogopts = [
216 debugrevlogopts = [
217 ('c', 'changelog', False, _('open changelog')),
217 ('c', 'changelog', False, _('open changelog')),
218 ('m', 'manifest', False, _('open manifest')),
218 ('m', 'manifest', False, _('open manifest')),
219 ('', 'dir', '', _('open directory manifest')),
219 ('', 'dir', '', _('open directory manifest')),
220 ]
220 ]
221
221
222 # Commands start here, listed alphabetically
222 # Commands start here, listed alphabetically
223
223
224 @command('^add',
224 @command('^add',
225 walkopts + subrepoopts + dryrunopts,
225 walkopts + subrepoopts + dryrunopts,
226 _('[OPTION]... [FILE]...'),
226 _('[OPTION]... [FILE]...'),
227 inferrepo=True)
227 inferrepo=True)
228 def add(ui, repo, *pats, **opts):
228 def add(ui, repo, *pats, **opts):
229 """add the specified files on the next commit
229 """add the specified files on the next commit
230
230
231 Schedule files to be version controlled and added to the
231 Schedule files to be version controlled and added to the
232 repository.
232 repository.
233
233
234 The files will be added to the repository at the next commit. To
234 The files will be added to the repository at the next commit. To
235 undo an add before that, see :hg:`forget`.
235 undo an add before that, see :hg:`forget`.
236
236
237 If no names are given, add all files to the repository (except
237 If no names are given, add all files to the repository (except
238 files matching ``.hgignore``).
238 files matching ``.hgignore``).
239
239
240 .. container:: verbose
240 .. container:: verbose
241
241
242 Examples:
242 Examples:
243
243
244 - New (unknown) files are added
244 - New (unknown) files are added
245 automatically by :hg:`add`::
245 automatically by :hg:`add`::
246
246
247 $ ls
247 $ ls
248 foo.c
248 foo.c
249 $ hg status
249 $ hg status
250 ? foo.c
250 ? foo.c
251 $ hg add
251 $ hg add
252 adding foo.c
252 adding foo.c
253 $ hg status
253 $ hg status
254 A foo.c
254 A foo.c
255
255
256 - Specific files to be added can be specified::
256 - Specific files to be added can be specified::
257
257
258 $ ls
258 $ ls
259 bar.c foo.c
259 bar.c foo.c
260 $ hg status
260 $ hg status
261 ? bar.c
261 ? bar.c
262 ? foo.c
262 ? foo.c
263 $ hg add bar.c
263 $ hg add bar.c
264 $ hg status
264 $ hg status
265 A bar.c
265 A bar.c
266 ? foo.c
266 ? foo.c
267
267
268 Returns 0 if all files are successfully added.
268 Returns 0 if all files are successfully added.
269 """
269 """
270
270
271 m = scmutil.match(repo[None], pats, opts)
271 m = scmutil.match(repo[None], pats, opts)
272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 return rejected and 1 or 0
273 return rejected and 1 or 0
274
274
275 @command('addremove',
275 @command('addremove',
276 similarityopts + subrepoopts + walkopts + dryrunopts,
276 similarityopts + subrepoopts + walkopts + dryrunopts,
277 _('[OPTION]... [FILE]...'),
277 _('[OPTION]... [FILE]...'),
278 inferrepo=True)
278 inferrepo=True)
279 def addremove(ui, repo, *pats, **opts):
279 def addremove(ui, repo, *pats, **opts):
280 """add all new files, delete all missing files
280 """add all new files, delete all missing files
281
281
282 Add all new files and remove all missing files from the
282 Add all new files and remove all missing files from the
283 repository.
283 repository.
284
284
285 Unless names are given, new files are ignored if they match any of
285 Unless names are given, new files are ignored if they match any of
286 the patterns in ``.hgignore``. As with add, these changes take
286 the patterns in ``.hgignore``. As with add, these changes take
287 effect at the next commit.
287 effect at the next commit.
288
288
289 Use the -s/--similarity option to detect renamed files. This
289 Use the -s/--similarity option to detect renamed files. This
290 option takes a percentage between 0 (disabled) and 100 (files must
290 option takes a percentage between 0 (disabled) and 100 (files must
291 be identical) as its parameter. With a parameter greater than 0,
291 be identical) as its parameter. With a parameter greater than 0,
292 this compares every removed file with every added file and records
292 this compares every removed file with every added file and records
293 those similar enough as renames. Detecting renamed files this way
293 those similar enough as renames. Detecting renamed files this way
294 can be expensive. After using this option, :hg:`status -C` can be
294 can be expensive. After using this option, :hg:`status -C` can be
295 used to check which files were identified as moved or renamed. If
295 used to check which files were identified as moved or renamed. If
296 not specified, -s/--similarity defaults to 100 and only renames of
296 not specified, -s/--similarity defaults to 100 and only renames of
297 identical files are detected.
297 identical files are detected.
298
298
299 .. container:: verbose
299 .. container:: verbose
300
300
301 Examples:
301 Examples:
302
302
303 - A number of files (bar.c and foo.c) are new,
303 - A number of files (bar.c and foo.c) are new,
304 while foobar.c has been removed (without using :hg:`remove`)
304 while foobar.c has been removed (without using :hg:`remove`)
305 from the repository::
305 from the repository::
306
306
307 $ ls
307 $ ls
308 bar.c foo.c
308 bar.c foo.c
309 $ hg status
309 $ hg status
310 ! foobar.c
310 ! foobar.c
311 ? bar.c
311 ? bar.c
312 ? foo.c
312 ? foo.c
313 $ hg addremove
313 $ hg addremove
314 adding bar.c
314 adding bar.c
315 adding foo.c
315 adding foo.c
316 removing foobar.c
316 removing foobar.c
317 $ hg status
317 $ hg status
318 A bar.c
318 A bar.c
319 A foo.c
319 A foo.c
320 R foobar.c
320 R foobar.c
321
321
322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
323 Afterwards, it was edited slightly::
323 Afterwards, it was edited slightly::
324
324
325 $ ls
325 $ ls
326 foo.c
326 foo.c
327 $ hg status
327 $ hg status
328 ! foobar.c
328 ! foobar.c
329 ? foo.c
329 ? foo.c
330 $ hg addremove --similarity 90
330 $ hg addremove --similarity 90
331 removing foobar.c
331 removing foobar.c
332 adding foo.c
332 adding foo.c
333 recording removal of foobar.c as rename to foo.c (94% similar)
333 recording removal of foobar.c as rename to foo.c (94% similar)
334 $ hg status -C
334 $ hg status -C
335 A foo.c
335 A foo.c
336 foobar.c
336 foobar.c
337 R foobar.c
337 R foobar.c
338
338
339 Returns 0 if all files are successfully added.
339 Returns 0 if all files are successfully added.
340 """
340 """
341 try:
341 try:
342 sim = float(opts.get('similarity') or 100)
342 sim = float(opts.get('similarity') or 100)
343 except ValueError:
343 except ValueError:
344 raise error.Abort(_('similarity must be a number'))
344 raise error.Abort(_('similarity must be a number'))
345 if sim < 0 or sim > 100:
345 if sim < 0 or sim > 100:
346 raise error.Abort(_('similarity must be between 0 and 100'))
346 raise error.Abort(_('similarity must be between 0 and 100'))
347 matcher = scmutil.match(repo[None], pats, opts)
347 matcher = scmutil.match(repo[None], pats, opts)
348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349
349
350 @command('^annotate|blame',
350 @command('^annotate|blame',
351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 ('', 'follow', None,
352 ('', 'follow', None,
353 _('follow copies/renames and list the filename (DEPRECATED)')),
353 _('follow copies/renames and list the filename (DEPRECATED)')),
354 ('', 'no-follow', None, _("don't follow copies and renames")),
354 ('', 'no-follow', None, _("don't follow copies and renames")),
355 ('a', 'text', None, _('treat all files as text')),
355 ('a', 'text', None, _('treat all files as text')),
356 ('u', 'user', None, _('list the author (long with -v)')),
356 ('u', 'user', None, _('list the author (long with -v)')),
357 ('f', 'file', None, _('list the filename')),
357 ('f', 'file', None, _('list the filename')),
358 ('d', 'date', None, _('list the date (short with -q)')),
358 ('d', 'date', None, _('list the date (short with -q)')),
359 ('n', 'number', None, _('list the revision number (default)')),
359 ('n', 'number', None, _('list the revision number (default)')),
360 ('c', 'changeset', None, _('list the changeset')),
360 ('c', 'changeset', None, _('list the changeset')),
361 ('l', 'line-number', None, _('show line number at the first appearance'))
361 ('l', 'line-number', None, _('show line number at the first appearance'))
362 ] + diffwsopts + walkopts + formatteropts,
362 ] + diffwsopts + walkopts + formatteropts,
363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 inferrepo=True)
364 inferrepo=True)
365 def annotate(ui, repo, *pats, **opts):
365 def annotate(ui, repo, *pats, **opts):
366 """show changeset information by line for each file
366 """show changeset information by line for each file
367
367
368 List changes in files, showing the revision id responsible for
368 List changes in files, showing the revision id responsible for
369 each line.
369 each line.
370
370
371 This command is useful for discovering when a change was made and
371 This command is useful for discovering when a change was made and
372 by whom.
372 by whom.
373
373
374 If you include --file, --user, or --date, the revision number is
374 If you include --file, --user, or --date, the revision number is
375 suppressed unless you also include --number.
375 suppressed unless you also include --number.
376
376
377 Without the -a/--text option, annotate will avoid processing files
377 Without the -a/--text option, annotate will avoid processing files
378 it detects as binary. With -a, annotate will annotate the file
378 it detects as binary. With -a, annotate will annotate the file
379 anyway, although the results will probably be neither useful
379 anyway, although the results will probably be neither useful
380 nor desirable.
380 nor desirable.
381
381
382 Returns 0 on success.
382 Returns 0 on success.
383 """
383 """
384 if not pats:
384 if not pats:
385 raise error.Abort(_('at least one filename or pattern is required'))
385 raise error.Abort(_('at least one filename or pattern is required'))
386
386
387 if opts.get('follow'):
387 if opts.get('follow'):
388 # --follow is deprecated and now just an alias for -f/--file
388 # --follow is deprecated and now just an alias for -f/--file
389 # to mimic the behavior of Mercurial before version 1.5
389 # to mimic the behavior of Mercurial before version 1.5
390 opts['file'] = True
390 opts['file'] = True
391
391
392 ctx = scmutil.revsingle(repo, opts.get('rev'))
392 ctx = scmutil.revsingle(repo, opts.get('rev'))
393
393
394 fm = ui.formatter('annotate', opts)
394 fm = ui.formatter('annotate', opts)
395 if ui.quiet:
395 if ui.quiet:
396 datefunc = util.shortdate
396 datefunc = util.shortdate
397 else:
397 else:
398 datefunc = util.datestr
398 datefunc = util.datestr
399 if ctx.rev() is None:
399 if ctx.rev() is None:
400 def hexfn(node):
400 def hexfn(node):
401 if node is None:
401 if node is None:
402 return None
402 return None
403 else:
403 else:
404 return fm.hexfunc(node)
404 return fm.hexfunc(node)
405 if opts.get('changeset'):
405 if opts.get('changeset'):
406 # omit "+" suffix which is appended to node hex
406 # omit "+" suffix which is appended to node hex
407 def formatrev(rev):
407 def formatrev(rev):
408 if rev is None:
408 if rev is None:
409 return '%d' % ctx.p1().rev()
409 return '%d' % ctx.p1().rev()
410 else:
410 else:
411 return '%d' % rev
411 return '%d' % rev
412 else:
412 else:
413 def formatrev(rev):
413 def formatrev(rev):
414 if rev is None:
414 if rev is None:
415 return '%d+' % ctx.p1().rev()
415 return '%d+' % ctx.p1().rev()
416 else:
416 else:
417 return '%d ' % rev
417 return '%d ' % rev
418 def formathex(hex):
418 def formathex(hex):
419 if hex is None:
419 if hex is None:
420 return '%s+' % fm.hexfunc(ctx.p1().node())
420 return '%s+' % fm.hexfunc(ctx.p1().node())
421 else:
421 else:
422 return '%s ' % hex
422 return '%s ' % hex
423 else:
423 else:
424 hexfn = fm.hexfunc
424 hexfn = fm.hexfunc
425 formatrev = formathex = str
425 formatrev = formathex = str
426
426
427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 ('number', ' ', lambda x: x[0].rev(), formatrev),
428 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 ('file', ' ', lambda x: x[0].path(), str),
431 ('file', ' ', lambda x: x[0].path(), str),
432 ('line_number', ':', lambda x: x[1], str),
432 ('line_number', ':', lambda x: x[1], str),
433 ]
433 ]
434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435
435
436 if (not opts.get('user') and not opts.get('changeset')
436 if (not opts.get('user') and not opts.get('changeset')
437 and not opts.get('date') and not opts.get('file')):
437 and not opts.get('date') and not opts.get('file')):
438 opts['number'] = True
438 opts['number'] = True
439
439
440 linenumber = opts.get('line_number') is not None
440 linenumber = opts.get('line_number') is not None
441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
442 raise error.Abort(_('at least one of -n/-c is required for -l'))
442 raise error.Abort(_('at least one of -n/-c is required for -l'))
443
443
444 if fm.isplain():
444 if fm.isplain():
445 def makefunc(get, fmt):
445 def makefunc(get, fmt):
446 return lambda x: fmt(get(x))
446 return lambda x: fmt(get(x))
447 else:
447 else:
448 def makefunc(get, fmt):
448 def makefunc(get, fmt):
449 return get
449 return get
450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
451 if opts.get(op)]
451 if opts.get(op)]
452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
454 if opts.get(op))
454 if opts.get(op))
455
455
456 def bad(x, y):
456 def bad(x, y):
457 raise error.Abort("%s: %s" % (x, y))
457 raise error.Abort("%s: %s" % (x, y))
458
458
459 m = scmutil.match(ctx, pats, opts, badfn=bad)
459 m = scmutil.match(ctx, pats, opts, badfn=bad)
460
460
461 follow = not opts.get('no_follow')
461 follow = not opts.get('no_follow')
462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 whitespace=True)
463 whitespace=True)
464 for abs in ctx.walk(m):
464 for abs in ctx.walk(m):
465 fctx = ctx[abs]
465 fctx = ctx[abs]
466 if not opts.get('text') and util.binary(fctx.data()):
466 if not opts.get('text') and util.binary(fctx.data()):
467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
468 continue
468 continue
469
469
470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 diffopts=diffopts)
471 diffopts=diffopts)
472 if not lines:
472 if not lines:
473 continue
473 continue
474 formats = []
474 formats = []
475 pieces = []
475 pieces = []
476
476
477 for f, sep in funcmap:
477 for f, sep in funcmap:
478 l = [f(n) for n, dummy in lines]
478 l = [f(n) for n, dummy in lines]
479 if fm.isplain():
479 if fm.isplain():
480 sizes = [encoding.colwidth(x) for x in l]
480 sizes = [encoding.colwidth(x) for x in l]
481 ml = max(sizes)
481 ml = max(sizes)
482 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
482 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 else:
483 else:
484 formats.append(['%s' for x in l])
484 formats.append(['%s' for x in l])
485 pieces.append(l)
485 pieces.append(l)
486
486
487 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
487 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
488 fm.startitem()
488 fm.startitem()
489 fm.write(fields, "".join(f), *p)
489 fm.write(fields, "".join(f), *p)
490 fm.write('line', ": %s", l[1])
490 fm.write('line', ": %s", l[1])
491
491
492 if not lines[-1][1].endswith('\n'):
492 if not lines[-1][1].endswith('\n'):
493 fm.plain('\n')
493 fm.plain('\n')
494
494
495 fm.end()
495 fm.end()
496
496
497 @command('archive',
497 @command('archive',
498 [('', 'no-decode', None, _('do not pass files through decoders')),
498 [('', 'no-decode', None, _('do not pass files through decoders')),
499 ('p', 'prefix', '', _('directory prefix for files in archive'),
499 ('p', 'prefix', '', _('directory prefix for files in archive'),
500 _('PREFIX')),
500 _('PREFIX')),
501 ('r', 'rev', '', _('revision to distribute'), _('REV')),
501 ('r', 'rev', '', _('revision to distribute'), _('REV')),
502 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
502 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
503 ] + subrepoopts + walkopts,
503 ] + subrepoopts + walkopts,
504 _('[OPTION]... DEST'))
504 _('[OPTION]... DEST'))
505 def archive(ui, repo, dest, **opts):
505 def archive(ui, repo, dest, **opts):
506 '''create an unversioned archive of a repository revision
506 '''create an unversioned archive of a repository revision
507
507
508 By default, the revision used is the parent of the working
508 By default, the revision used is the parent of the working
509 directory; use -r/--rev to specify a different revision.
509 directory; use -r/--rev to specify a different revision.
510
510
511 The archive type is automatically detected based on file
511 The archive type is automatically detected based on file
512 extension (to override, use -t/--type).
512 extension (to override, use -t/--type).
513
513
514 .. container:: verbose
514 .. container:: verbose
515
515
516 Examples:
516 Examples:
517
517
518 - create a zip file containing the 1.0 release::
518 - create a zip file containing the 1.0 release::
519
519
520 hg archive -r 1.0 project-1.0.zip
520 hg archive -r 1.0 project-1.0.zip
521
521
522 - create a tarball excluding .hg files::
522 - create a tarball excluding .hg files::
523
523
524 hg archive project.tar.gz -X ".hg*"
524 hg archive project.tar.gz -X ".hg*"
525
525
526 Valid types are:
526 Valid types are:
527
527
528 :``files``: a directory full of files (default)
528 :``files``: a directory full of files (default)
529 :``tar``: tar archive, uncompressed
529 :``tar``: tar archive, uncompressed
530 :``tbz2``: tar archive, compressed using bzip2
530 :``tbz2``: tar archive, compressed using bzip2
531 :``tgz``: tar archive, compressed using gzip
531 :``tgz``: tar archive, compressed using gzip
532 :``uzip``: zip archive, uncompressed
532 :``uzip``: zip archive, uncompressed
533 :``zip``: zip archive, compressed using deflate
533 :``zip``: zip archive, compressed using deflate
534
534
535 The exact name of the destination archive or directory is given
535 The exact name of the destination archive or directory is given
536 using a format string; see :hg:`help export` for details.
536 using a format string; see :hg:`help export` for details.
537
537
538 Each member added to an archive file has a directory prefix
538 Each member added to an archive file has a directory prefix
539 prepended. Use -p/--prefix to specify a format string for the
539 prepended. Use -p/--prefix to specify a format string for the
540 prefix. The default is the basename of the archive, with suffixes
540 prefix. The default is the basename of the archive, with suffixes
541 removed.
541 removed.
542
542
543 Returns 0 on success.
543 Returns 0 on success.
544 '''
544 '''
545
545
546 ctx = scmutil.revsingle(repo, opts.get('rev'))
546 ctx = scmutil.revsingle(repo, opts.get('rev'))
547 if not ctx:
547 if not ctx:
548 raise error.Abort(_('no working directory: please specify a revision'))
548 raise error.Abort(_('no working directory: please specify a revision'))
549 node = ctx.node()
549 node = ctx.node()
550 dest = cmdutil.makefilename(repo, dest, node)
550 dest = cmdutil.makefilename(repo, dest, node)
551 if os.path.realpath(dest) == repo.root:
551 if os.path.realpath(dest) == repo.root:
552 raise error.Abort(_('repository root cannot be destination'))
552 raise error.Abort(_('repository root cannot be destination'))
553
553
554 kind = opts.get('type') or archival.guesskind(dest) or 'files'
554 kind = opts.get('type') or archival.guesskind(dest) or 'files'
555 prefix = opts.get('prefix')
555 prefix = opts.get('prefix')
556
556
557 if dest == '-':
557 if dest == '-':
558 if kind == 'files':
558 if kind == 'files':
559 raise error.Abort(_('cannot archive plain files to stdout'))
559 raise error.Abort(_('cannot archive plain files to stdout'))
560 dest = cmdutil.makefileobj(repo, dest)
560 dest = cmdutil.makefileobj(repo, dest)
561 if not prefix:
561 if not prefix:
562 prefix = os.path.basename(repo.root) + '-%h'
562 prefix = os.path.basename(repo.root) + '-%h'
563
563
564 prefix = cmdutil.makefilename(repo, prefix, node)
564 prefix = cmdutil.makefilename(repo, prefix, node)
565 matchfn = scmutil.match(ctx, [], opts)
565 matchfn = scmutil.match(ctx, [], opts)
566 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
566 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
567 matchfn, prefix, subrepos=opts.get('subrepos'))
567 matchfn, prefix, subrepos=opts.get('subrepos'))
568
568
569 @command('backout',
569 @command('backout',
570 [('', 'merge', None, _('merge with old dirstate parent after backout')),
570 [('', 'merge', None, _('merge with old dirstate parent after backout')),
571 ('', 'commit', None,
571 ('', 'commit', None,
572 _('commit if no conflicts were encountered (DEPRECATED)')),
572 _('commit if no conflicts were encountered (DEPRECATED)')),
573 ('', 'no-commit', None, _('do not commit')),
573 ('', 'no-commit', None, _('do not commit')),
574 ('', 'parent', '',
574 ('', 'parent', '',
575 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
575 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
576 ('r', 'rev', '', _('revision to backout'), _('REV')),
576 ('r', 'rev', '', _('revision to backout'), _('REV')),
577 ('e', 'edit', False, _('invoke editor on commit messages')),
577 ('e', 'edit', False, _('invoke editor on commit messages')),
578 ] + mergetoolopts + walkopts + commitopts + commitopts2,
578 ] + mergetoolopts + walkopts + commitopts + commitopts2,
579 _('[OPTION]... [-r] REV'))
579 _('[OPTION]... [-r] REV'))
580 def backout(ui, repo, node=None, rev=None, **opts):
580 def backout(ui, repo, node=None, rev=None, **opts):
581 '''reverse effect of earlier changeset
581 '''reverse effect of earlier changeset
582
582
583 Prepare a new changeset with the effect of REV undone in the
583 Prepare a new changeset with the effect of REV undone in the
584 current working directory. If no conflicts were encountered,
584 current working directory. If no conflicts were encountered,
585 it will be committed immediately.
585 it will be committed immediately.
586
586
587 If REV is the parent of the working directory, then this new changeset
587 If REV is the parent of the working directory, then this new changeset
588 is committed automatically (unless --no-commit is specified).
588 is committed automatically (unless --no-commit is specified).
589
589
590 .. note::
590 .. note::
591
591
592 :hg:`backout` cannot be used to fix either an unwanted or
592 :hg:`backout` cannot be used to fix either an unwanted or
593 incorrect merge.
593 incorrect merge.
594
594
595 .. container:: verbose
595 .. container:: verbose
596
596
597 Examples:
597 Examples:
598
598
599 - Reverse the effect of the parent of the working directory.
599 - Reverse the effect of the parent of the working directory.
600 This backout will be committed immediately::
600 This backout will be committed immediately::
601
601
602 hg backout -r .
602 hg backout -r .
603
603
604 - Reverse the effect of previous bad revision 23::
604 - Reverse the effect of previous bad revision 23::
605
605
606 hg backout -r 23
606 hg backout -r 23
607
607
608 - Reverse the effect of previous bad revision 23 and
608 - Reverse the effect of previous bad revision 23 and
609 leave changes uncommitted::
609 leave changes uncommitted::
610
610
611 hg backout -r 23 --no-commit
611 hg backout -r 23 --no-commit
612 hg commit -m "Backout revision 23"
612 hg commit -m "Backout revision 23"
613
613
614 By default, the pending changeset will have one parent,
614 By default, the pending changeset will have one parent,
615 maintaining a linear history. With --merge, the pending
615 maintaining a linear history. With --merge, the pending
616 changeset will instead have two parents: the old parent of the
616 changeset will instead have two parents: the old parent of the
617 working directory and a new child of REV that simply undoes REV.
617 working directory and a new child of REV that simply undoes REV.
618
618
619 Before version 1.7, the behavior without --merge was equivalent
619 Before version 1.7, the behavior without --merge was equivalent
620 to specifying --merge followed by :hg:`update --clean .` to
620 to specifying --merge followed by :hg:`update --clean .` to
621 cancel the merge and leave the child of REV as a head to be
621 cancel the merge and leave the child of REV as a head to be
622 merged separately.
622 merged separately.
623
623
624 See :hg:`help dates` for a list of formats valid for -d/--date.
624 See :hg:`help dates` for a list of formats valid for -d/--date.
625
625
626 See :hg:`help revert` for a way to restore files to the state
626 See :hg:`help revert` for a way to restore files to the state
627 of another revision.
627 of another revision.
628
628
629 Returns 0 on success, 1 if nothing to backout or there are unresolved
629 Returns 0 on success, 1 if nothing to backout or there are unresolved
630 files.
630 files.
631 '''
631 '''
632 wlock = lock = None
632 wlock = lock = None
633 try:
633 try:
634 wlock = repo.wlock()
634 wlock = repo.wlock()
635 lock = repo.lock()
635 lock = repo.lock()
636 return _dobackout(ui, repo, node, rev, **opts)
636 return _dobackout(ui, repo, node, rev, **opts)
637 finally:
637 finally:
638 release(lock, wlock)
638 release(lock, wlock)
639
639
640 def _dobackout(ui, repo, node=None, rev=None, **opts):
640 def _dobackout(ui, repo, node=None, rev=None, **opts):
641 if opts.get('commit') and opts.get('no_commit'):
641 if opts.get('commit') and opts.get('no_commit'):
642 raise error.Abort(_("cannot use --commit with --no-commit"))
642 raise error.Abort(_("cannot use --commit with --no-commit"))
643 if opts.get('merge') and opts.get('no_commit'):
643 if opts.get('merge') and opts.get('no_commit'):
644 raise error.Abort(_("cannot use --merge with --no-commit"))
644 raise error.Abort(_("cannot use --merge with --no-commit"))
645
645
646 if rev and node:
646 if rev and node:
647 raise error.Abort(_("please specify just one revision"))
647 raise error.Abort(_("please specify just one revision"))
648
648
649 if not rev:
649 if not rev:
650 rev = node
650 rev = node
651
651
652 if not rev:
652 if not rev:
653 raise error.Abort(_("please specify a revision to backout"))
653 raise error.Abort(_("please specify a revision to backout"))
654
654
655 date = opts.get('date')
655 date = opts.get('date')
656 if date:
656 if date:
657 opts['date'] = util.parsedate(date)
657 opts['date'] = util.parsedate(date)
658
658
659 cmdutil.checkunfinished(repo)
659 cmdutil.checkunfinished(repo)
660 cmdutil.bailifchanged(repo)
660 cmdutil.bailifchanged(repo)
661 node = scmutil.revsingle(repo, rev).node()
661 node = scmutil.revsingle(repo, rev).node()
662
662
663 op1, op2 = repo.dirstate.parents()
663 op1, op2 = repo.dirstate.parents()
664 if not repo.changelog.isancestor(node, op1):
664 if not repo.changelog.isancestor(node, op1):
665 raise error.Abort(_('cannot backout change that is not an ancestor'))
665 raise error.Abort(_('cannot backout change that is not an ancestor'))
666
666
667 p1, p2 = repo.changelog.parents(node)
667 p1, p2 = repo.changelog.parents(node)
668 if p1 == nullid:
668 if p1 == nullid:
669 raise error.Abort(_('cannot backout a change with no parents'))
669 raise error.Abort(_('cannot backout a change with no parents'))
670 if p2 != nullid:
670 if p2 != nullid:
671 if not opts.get('parent'):
671 if not opts.get('parent'):
672 raise error.Abort(_('cannot backout a merge changeset'))
672 raise error.Abort(_('cannot backout a merge changeset'))
673 p = repo.lookup(opts['parent'])
673 p = repo.lookup(opts['parent'])
674 if p not in (p1, p2):
674 if p not in (p1, p2):
675 raise error.Abort(_('%s is not a parent of %s') %
675 raise error.Abort(_('%s is not a parent of %s') %
676 (short(p), short(node)))
676 (short(p), short(node)))
677 parent = p
677 parent = p
678 else:
678 else:
679 if opts.get('parent'):
679 if opts.get('parent'):
680 raise error.Abort(_('cannot use --parent on non-merge changeset'))
680 raise error.Abort(_('cannot use --parent on non-merge changeset'))
681 parent = p1
681 parent = p1
682
682
683 # the backout should appear on the same branch
683 # the backout should appear on the same branch
684 branch = repo.dirstate.branch()
684 branch = repo.dirstate.branch()
685 bheads = repo.branchheads(branch)
685 bheads = repo.branchheads(branch)
686 rctx = scmutil.revsingle(repo, hex(parent))
686 rctx = scmutil.revsingle(repo, hex(parent))
687 if not opts.get('merge') and op1 != node:
687 if not opts.get('merge') and op1 != node:
688 dsguard = cmdutil.dirstateguard(repo, 'backout')
688 dsguard = cmdutil.dirstateguard(repo, 'backout')
689 try:
689 try:
690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 'backout')
691 'backout')
692 stats = mergemod.update(repo, parent, True, True, node, False)
692 stats = mergemod.update(repo, parent, True, True, node, False)
693 repo.setparents(op1, op2)
693 repo.setparents(op1, op2)
694 dsguard.close()
694 dsguard.close()
695 hg._showstats(repo, stats)
695 hg._showstats(repo, stats)
696 if stats[3]:
696 if stats[3]:
697 repo.ui.status(_("use 'hg resolve' to retry unresolved "
697 repo.ui.status(_("use 'hg resolve' to retry unresolved "
698 "file merges\n"))
698 "file merges\n"))
699 return 1
699 return 1
700 finally:
700 finally:
701 ui.setconfig('ui', 'forcemerge', '', '')
701 ui.setconfig('ui', 'forcemerge', '', '')
702 lockmod.release(dsguard)
702 lockmod.release(dsguard)
703 else:
703 else:
704 hg.clean(repo, node, show_stats=False)
704 hg.clean(repo, node, show_stats=False)
705 repo.dirstate.setbranch(branch)
705 repo.dirstate.setbranch(branch)
706 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
706 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
707
707
708 if opts.get('no_commit'):
708 if opts.get('no_commit'):
709 msg = _("changeset %s backed out, "
709 msg = _("changeset %s backed out, "
710 "don't forget to commit.\n")
710 "don't forget to commit.\n")
711 ui.status(msg % short(node))
711 ui.status(msg % short(node))
712 return 0
712 return 0
713
713
714 def commitfunc(ui, repo, message, match, opts):
714 def commitfunc(ui, repo, message, match, opts):
715 editform = 'backout'
715 editform = 'backout'
716 e = cmdutil.getcommiteditor(editform=editform, **opts)
716 e = cmdutil.getcommiteditor(editform=editform, **opts)
717 if not message:
717 if not message:
718 # we don't translate commit messages
718 # we don't translate commit messages
719 message = "Backed out changeset %s" % short(node)
719 message = "Backed out changeset %s" % short(node)
720 e = cmdutil.getcommiteditor(edit=True, editform=editform)
720 e = cmdutil.getcommiteditor(edit=True, editform=editform)
721 return repo.commit(message, opts.get('user'), opts.get('date'),
721 return repo.commit(message, opts.get('user'), opts.get('date'),
722 match, editor=e)
722 match, editor=e)
723 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
723 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
724 if not newnode:
724 if not newnode:
725 ui.status(_("nothing changed\n"))
725 ui.status(_("nothing changed\n"))
726 return 1
726 return 1
727 cmdutil.commitstatus(repo, newnode, branch, bheads)
727 cmdutil.commitstatus(repo, newnode, branch, bheads)
728
728
729 def nice(node):
729 def nice(node):
730 return '%d:%s' % (repo.changelog.rev(node), short(node))
730 return '%d:%s' % (repo.changelog.rev(node), short(node))
731 ui.status(_('changeset %s backs out changeset %s\n') %
731 ui.status(_('changeset %s backs out changeset %s\n') %
732 (nice(repo.changelog.tip()), nice(node)))
732 (nice(repo.changelog.tip()), nice(node)))
733 if opts.get('merge') and op1 != node:
733 if opts.get('merge') and op1 != node:
734 hg.clean(repo, op1, show_stats=False)
734 hg.clean(repo, op1, show_stats=False)
735 ui.status(_('merging with changeset %s\n')
735 ui.status(_('merging with changeset %s\n')
736 % nice(repo.changelog.tip()))
736 % nice(repo.changelog.tip()))
737 try:
737 try:
738 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
738 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
739 'backout')
739 'backout')
740 return hg.merge(repo, hex(repo.changelog.tip()))
740 return hg.merge(repo, hex(repo.changelog.tip()))
741 finally:
741 finally:
742 ui.setconfig('ui', 'forcemerge', '', '')
742 ui.setconfig('ui', 'forcemerge', '', '')
743 return 0
743 return 0
744
744
745 @command('bisect',
745 @command('bisect',
746 [('r', 'reset', False, _('reset bisect state')),
746 [('r', 'reset', False, _('reset bisect state')),
747 ('g', 'good', False, _('mark changeset good')),
747 ('g', 'good', False, _('mark changeset good')),
748 ('b', 'bad', False, _('mark changeset bad')),
748 ('b', 'bad', False, _('mark changeset bad')),
749 ('s', 'skip', False, _('skip testing changeset')),
749 ('s', 'skip', False, _('skip testing changeset')),
750 ('e', 'extend', False, _('extend the bisect range')),
750 ('e', 'extend', False, _('extend the bisect range')),
751 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
751 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
752 ('U', 'noupdate', False, _('do not update to target'))],
752 ('U', 'noupdate', False, _('do not update to target'))],
753 _("[-gbsr] [-U] [-c CMD] [REV]"))
753 _("[-gbsr] [-U] [-c CMD] [REV]"))
754 def bisect(ui, repo, rev=None, extra=None, command=None,
754 def bisect(ui, repo, rev=None, extra=None, command=None,
755 reset=None, good=None, bad=None, skip=None, extend=None,
755 reset=None, good=None, bad=None, skip=None, extend=None,
756 noupdate=None):
756 noupdate=None):
757 """subdivision search of changesets
757 """subdivision search of changesets
758
758
759 This command helps to find changesets which introduce problems. To
759 This command helps to find changesets which introduce problems. To
760 use, mark the earliest changeset you know exhibits the problem as
760 use, mark the earliest changeset you know exhibits the problem as
761 bad, then mark the latest changeset which is free from the problem
761 bad, then mark the latest changeset which is free from the problem
762 as good. Bisect will update your working directory to a revision
762 as good. Bisect will update your working directory to a revision
763 for testing (unless the -U/--noupdate option is specified). Once
763 for testing (unless the -U/--noupdate option is specified). Once
764 you have performed tests, mark the working directory as good or
764 you have performed tests, mark the working directory as good or
765 bad, and bisect will either update to another candidate changeset
765 bad, and bisect will either update to another candidate changeset
766 or announce that it has found the bad revision.
766 or announce that it has found the bad revision.
767
767
768 As a shortcut, you can also use the revision argument to mark a
768 As a shortcut, you can also use the revision argument to mark a
769 revision as good or bad without checking it out first.
769 revision as good or bad without checking it out first.
770
770
771 If you supply a command, it will be used for automatic bisection.
771 If you supply a command, it will be used for automatic bisection.
772 The environment variable HG_NODE will contain the ID of the
772 The environment variable HG_NODE will contain the ID of the
773 changeset being tested. The exit status of the command will be
773 changeset being tested. The exit status of the command will be
774 used to mark revisions as good or bad: status 0 means good, 125
774 used to mark revisions as good or bad: status 0 means good, 125
775 means to skip the revision, 127 (command not found) will abort the
775 means to skip the revision, 127 (command not found) will abort the
776 bisection, and any other non-zero exit status means the revision
776 bisection, and any other non-zero exit status means the revision
777 is bad.
777 is bad.
778
778
779 .. container:: verbose
779 .. container:: verbose
780
780
781 Some examples:
781 Some examples:
782
782
783 - start a bisection with known bad revision 34, and good revision 12::
783 - start a bisection with known bad revision 34, and good revision 12::
784
784
785 hg bisect --bad 34
785 hg bisect --bad 34
786 hg bisect --good 12
786 hg bisect --good 12
787
787
788 - advance the current bisection by marking current revision as good or
788 - advance the current bisection by marking current revision as good or
789 bad::
789 bad::
790
790
791 hg bisect --good
791 hg bisect --good
792 hg bisect --bad
792 hg bisect --bad
793
793
794 - mark the current revision, or a known revision, to be skipped (e.g. if
794 - mark the current revision, or a known revision, to be skipped (e.g. if
795 that revision is not usable because of another issue)::
795 that revision is not usable because of another issue)::
796
796
797 hg bisect --skip
797 hg bisect --skip
798 hg bisect --skip 23
798 hg bisect --skip 23
799
799
800 - skip all revisions that do not touch directories ``foo`` or ``bar``::
800 - skip all revisions that do not touch directories ``foo`` or ``bar``::
801
801
802 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
802 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
803
803
804 - forget the current bisection::
804 - forget the current bisection::
805
805
806 hg bisect --reset
806 hg bisect --reset
807
807
808 - use 'make && make tests' to automatically find the first broken
808 - use 'make && make tests' to automatically find the first broken
809 revision::
809 revision::
810
810
811 hg bisect --reset
811 hg bisect --reset
812 hg bisect --bad 34
812 hg bisect --bad 34
813 hg bisect --good 12
813 hg bisect --good 12
814 hg bisect --command "make && make tests"
814 hg bisect --command "make && make tests"
815
815
816 - see all changesets whose states are already known in the current
816 - see all changesets whose states are already known in the current
817 bisection::
817 bisection::
818
818
819 hg log -r "bisect(pruned)"
819 hg log -r "bisect(pruned)"
820
820
821 - see the changeset currently being bisected (especially useful
821 - see the changeset currently being bisected (especially useful
822 if running with -U/--noupdate)::
822 if running with -U/--noupdate)::
823
823
824 hg log -r "bisect(current)"
824 hg log -r "bisect(current)"
825
825
826 - see all changesets that took part in the current bisection::
826 - see all changesets that took part in the current bisection::
827
827
828 hg log -r "bisect(range)"
828 hg log -r "bisect(range)"
829
829
830 - you can even get a nice graph::
830 - you can even get a nice graph::
831
831
832 hg log --graph -r "bisect(range)"
832 hg log --graph -r "bisect(range)"
833
833
834 See :hg:`help revsets` for more about the `bisect()` keyword.
834 See :hg:`help revsets` for more about the `bisect()` keyword.
835
835
836 Returns 0 on success.
836 Returns 0 on success.
837 """
837 """
838 def checkstate(state):
838 def checkstate(state):
839 if not state['good'] or not state['bad']:
839 if state['good'] and state['bad']:
840 return True
840 if not state['good']:
841 if not state['good']:
841 raise error.Abort(_('cannot bisect (no known good revisions)'))
842 raise error.Abort(_('cannot bisect (no known good revisions)'))
842 else:
843 else:
843 raise error.Abort(_('cannot bisect (no known bad revisions)'))
844 raise error.Abort(_('cannot bisect (no known bad revisions)'))
844 return True
845
845
846 # backward compatibility
846 # backward compatibility
847 if rev in "good bad reset init".split():
847 if rev in "good bad reset init".split():
848 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
848 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
849 cmd, rev, extra = rev, extra, None
849 cmd, rev, extra = rev, extra, None
850 if cmd == "good":
850 if cmd == "good":
851 good = True
851 good = True
852 elif cmd == "bad":
852 elif cmd == "bad":
853 bad = True
853 bad = True
854 else:
854 else:
855 reset = True
855 reset = True
856 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
856 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
857 raise error.Abort(_('incompatible arguments'))
857 raise error.Abort(_('incompatible arguments'))
858
858
859 cmdutil.checkunfinished(repo)
859 cmdutil.checkunfinished(repo)
860
860
861 if reset:
861 if reset:
862 hbisect.resetstate(repo)
862 hbisect.resetstate(repo)
863 return
863 return
864
864
865 state = hbisect.load_state(repo)
865 state = hbisect.load_state(repo)
866
866
867 # update state
867 # update state
868 if good or bad or skip:
868 if good or bad or skip:
869 if rev:
869 if rev:
870 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
870 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
871 else:
871 else:
872 nodes = [repo.lookup('.')]
872 nodes = [repo.lookup('.')]
873 if good:
873 if good:
874 state['good'] += nodes
874 state['good'] += nodes
875 elif bad:
875 elif bad:
876 state['bad'] += nodes
876 state['bad'] += nodes
877 elif skip:
877 elif skip:
878 state['skip'] += nodes
878 state['skip'] += nodes
879 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
880 if not (state['good'] and state['bad']):
880 if not (state['good'] and state['bad']):
881 return
881 return
882
882
883 if command:
883 if command:
884 changesets = 1
884 changesets = 1
885 if noupdate:
885 if noupdate:
886 try:
886 try:
887 node = state['current'][0]
887 node = state['current'][0]
888 except LookupError:
888 except LookupError:
889 raise error.Abort(_('current bisect revision is unknown - '
889 raise error.Abort(_('current bisect revision is unknown - '
890 'start a new bisect to fix'))
890 'start a new bisect to fix'))
891 else:
891 else:
892 node, p2 = repo.dirstate.parents()
892 node, p2 = repo.dirstate.parents()
893 if p2 != nullid:
893 if p2 != nullid:
894 raise error.Abort(_('current bisect revision is a merge'))
894 raise error.Abort(_('current bisect revision is a merge'))
895 try:
895 try:
896 while changesets:
896 while changesets:
897 # update state
897 # update state
898 state['current'] = [node]
898 state['current'] = [node]
899 hbisect.save_state(repo, state)
899 hbisect.save_state(repo, state)
900 status = ui.system(command, environ={'HG_NODE': hex(node)})
900 status = ui.system(command, environ={'HG_NODE': hex(node)})
901 if status == 125:
901 if status == 125:
902 transition = "skip"
902 transition = "skip"
903 elif status == 0:
903 elif status == 0:
904 transition = "good"
904 transition = "good"
905 # status < 0 means process was killed
905 # status < 0 means process was killed
906 elif status == 127:
906 elif status == 127:
907 raise error.Abort(_("failed to execute %s") % command)
907 raise error.Abort(_("failed to execute %s") % command)
908 elif status < 0:
908 elif status < 0:
909 raise error.Abort(_("%s killed") % command)
909 raise error.Abort(_("%s killed") % command)
910 else:
910 else:
911 transition = "bad"
911 transition = "bad"
912 ctx = scmutil.revsingle(repo, rev, node)
912 ctx = scmutil.revsingle(repo, rev, node)
913 rev = None # clear for future iterations
913 rev = None # clear for future iterations
914 state[transition].append(ctx.node())
914 state[transition].append(ctx.node())
915 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
915 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
916 checkstate(state)
916 checkstate(state)
917 # bisect
917 # bisect
918 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
918 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
919 # update to next check
919 # update to next check
920 node = nodes[0]
920 node = nodes[0]
921 if not noupdate:
921 if not noupdate:
922 cmdutil.bailifchanged(repo)
922 cmdutil.bailifchanged(repo)
923 hg.clean(repo, node, show_stats=False)
923 hg.clean(repo, node, show_stats=False)
924 finally:
924 finally:
925 state['current'] = [node]
925 state['current'] = [node]
926 hbisect.save_state(repo, state)
926 hbisect.save_state(repo, state)
927 displayer = cmdutil.show_changeset(ui, repo, {})
927 displayer = cmdutil.show_changeset(ui, repo, {})
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
929 return
929 return
930
930
931 checkstate(state)
931 checkstate(state)
932
932
933 # actually bisect
933 # actually bisect
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 if extend:
935 if extend:
936 if not changesets:
936 if not changesets:
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
938 if extendnode is not None:
938 if extendnode is not None:
939 ui.write(_("Extending search to changeset %d:%s\n")
939 ui.write(_("Extending search to changeset %d:%s\n")
940 % (extendnode.rev(), extendnode))
940 % (extendnode.rev(), extendnode))
941 state['current'] = [extendnode.node()]
941 state['current'] = [extendnode.node()]
942 hbisect.save_state(repo, state)
942 hbisect.save_state(repo, state)
943 if noupdate:
943 if noupdate:
944 return
944 return
945 cmdutil.bailifchanged(repo)
945 cmdutil.bailifchanged(repo)
946 return hg.clean(repo, extendnode.node())
946 return hg.clean(repo, extendnode.node())
947 raise error.Abort(_("nothing to extend"))
947 raise error.Abort(_("nothing to extend"))
948
948
949 if changesets == 0:
949 if changesets == 0:
950 displayer = cmdutil.show_changeset(ui, repo, {})
950 displayer = cmdutil.show_changeset(ui, repo, {})
951 hbisect.printresult(ui, repo, state, displayer, nodes, good)
951 hbisect.printresult(ui, repo, state, displayer, nodes, good)
952 else:
952 else:
953 assert len(nodes) == 1 # only a single node can be tested next
953 assert len(nodes) == 1 # only a single node can be tested next
954 node = nodes[0]
954 node = nodes[0]
955 # compute the approximate number of remaining tests
955 # compute the approximate number of remaining tests
956 tests, size = 0, 2
956 tests, size = 0, 2
957 while size <= changesets:
957 while size <= changesets:
958 tests, size = tests + 1, size * 2
958 tests, size = tests + 1, size * 2
959 rev = repo.changelog.rev(node)
959 rev = repo.changelog.rev(node)
960 ui.write(_("Testing changeset %d:%s "
960 ui.write(_("Testing changeset %d:%s "
961 "(%d changesets remaining, ~%d tests)\n")
961 "(%d changesets remaining, ~%d tests)\n")
962 % (rev, short(node), changesets, tests))
962 % (rev, short(node), changesets, tests))
963 state['current'] = [node]
963 state['current'] = [node]
964 hbisect.save_state(repo, state)
964 hbisect.save_state(repo, state)
965 if not noupdate:
965 if not noupdate:
966 cmdutil.bailifchanged(repo)
966 cmdutil.bailifchanged(repo)
967 return hg.clean(repo, node)
967 return hg.clean(repo, node)
968
968
969 @command('bookmarks|bookmark',
969 @command('bookmarks|bookmark',
970 [('f', 'force', False, _('force')),
970 [('f', 'force', False, _('force')),
971 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
971 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
972 ('d', 'delete', False, _('delete a given bookmark')),
972 ('d', 'delete', False, _('delete a given bookmark')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
975 ] + formatteropts,
975 ] + formatteropts,
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
977 def bookmark(ui, repo, *names, **opts):
977 def bookmark(ui, repo, *names, **opts):
978 '''create a new bookmark or list existing bookmarks
978 '''create a new bookmark or list existing bookmarks
979
979
980 Bookmarks are labels on changesets to help track lines of development.
980 Bookmarks are labels on changesets to help track lines of development.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
982 Deleting or moving a bookmark has no effect on the associated changesets.
982 Deleting or moving a bookmark has no effect on the associated changesets.
983
983
984 Creating or updating to a bookmark causes it to be marked as 'active'.
984 Creating or updating to a bookmark causes it to be marked as 'active'.
985 The active bookmark is indicated with a '*'.
985 The active bookmark is indicated with a '*'.
986 When a commit is made, the active bookmark will advance to the new commit.
986 When a commit is made, the active bookmark will advance to the new commit.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
988 Updating away from a bookmark will cause it to be deactivated.
988 Updating away from a bookmark will cause it to be deactivated.
989
989
990 Bookmarks can be pushed and pulled between repositories (see
990 Bookmarks can be pushed and pulled between repositories (see
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
993 be created. Using :hg:`merge` will resolve the divergence.
993 be created. Using :hg:`merge` will resolve the divergence.
994
994
995 A bookmark named '@' has the special property that :hg:`clone` will
995 A bookmark named '@' has the special property that :hg:`clone` will
996 check it out by default if it exists.
996 check it out by default if it exists.
997
997
998 .. container:: verbose
998 .. container:: verbose
999
999
1000 Examples:
1000 Examples:
1001
1001
1002 - create an active bookmark for a new line of development::
1002 - create an active bookmark for a new line of development::
1003
1003
1004 hg book new-feature
1004 hg book new-feature
1005
1005
1006 - create an inactive bookmark as a place marker::
1006 - create an inactive bookmark as a place marker::
1007
1007
1008 hg book -i reviewed
1008 hg book -i reviewed
1009
1009
1010 - create an inactive bookmark on another changeset::
1010 - create an inactive bookmark on another changeset::
1011
1011
1012 hg book -r .^ tested
1012 hg book -r .^ tested
1013
1013
1014 - rename bookmark turkey to dinner::
1014 - rename bookmark turkey to dinner::
1015
1015
1016 hg book -m turkey dinner
1016 hg book -m turkey dinner
1017
1017
1018 - move the '@' bookmark from another branch::
1018 - move the '@' bookmark from another branch::
1019
1019
1020 hg book -f @
1020 hg book -f @
1021 '''
1021 '''
1022 force = opts.get('force')
1022 force = opts.get('force')
1023 rev = opts.get('rev')
1023 rev = opts.get('rev')
1024 delete = opts.get('delete')
1024 delete = opts.get('delete')
1025 rename = opts.get('rename')
1025 rename = opts.get('rename')
1026 inactive = opts.get('inactive')
1026 inactive = opts.get('inactive')
1027
1027
1028 def checkformat(mark):
1028 def checkformat(mark):
1029 mark = mark.strip()
1029 mark = mark.strip()
1030 if not mark:
1030 if not mark:
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1032 "whitespace"))
1032 "whitespace"))
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1034 return mark
1034 return mark
1035
1035
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1037 if mark in marks and not force:
1037 if mark in marks and not force:
1038 if target:
1038 if target:
1039 if marks[mark] == target and target == cur:
1039 if marks[mark] == target and target == cur:
1040 # re-activating a bookmark
1040 # re-activating a bookmark
1041 return
1041 return
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1043 bmctx = repo[marks[mark]]
1043 bmctx = repo[marks[mark]]
1044 divs = [repo[b].node() for b in marks
1044 divs = [repo[b].node() for b in marks
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1046
1046
1047 # allow resolving a single divergent bookmark even if moving
1047 # allow resolving a single divergent bookmark even if moving
1048 # the bookmark across branches when a revision is specified
1048 # the bookmark across branches when a revision is specified
1049 # that contains a divergent bookmark
1049 # that contains a divergent bookmark
1050 if bmctx.rev() not in anc and target in divs:
1050 if bmctx.rev() not in anc and target in divs:
1051 bookmarks.deletedivergent(repo, [target], mark)
1051 bookmarks.deletedivergent(repo, [target], mark)
1052 return
1052 return
1053
1053
1054 deletefrom = [b for b in divs
1054 deletefrom = [b for b in divs
1055 if repo[b].rev() in anc or b == target]
1055 if repo[b].rev() in anc or b == target]
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1059 (mark, short(bmctx.node())))
1059 (mark, short(bmctx.node())))
1060 return
1060 return
1061 raise error.Abort(_("bookmark '%s' already exists "
1061 raise error.Abort(_("bookmark '%s' already exists "
1062 "(use -f to force)") % mark)
1062 "(use -f to force)") % mark)
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1064 and not force):
1064 and not force):
1065 raise error.Abort(
1065 raise error.Abort(
1066 _("a bookmark cannot have the name of an existing branch"))
1066 _("a bookmark cannot have the name of an existing branch"))
1067
1067
1068 if delete and rename:
1068 if delete and rename:
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1070 if delete and rev:
1070 if delete and rev:
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1072 if rename and rev:
1072 if rename and rev:
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1074 if not names and (delete or rev):
1074 if not names and (delete or rev):
1075 raise error.Abort(_("bookmark name required"))
1075 raise error.Abort(_("bookmark name required"))
1076
1076
1077 if delete or rename or names or inactive:
1077 if delete or rename or names or inactive:
1078 wlock = lock = tr = None
1078 wlock = lock = tr = None
1079 try:
1079 try:
1080 wlock = repo.wlock()
1080 wlock = repo.wlock()
1081 lock = repo.lock()
1081 lock = repo.lock()
1082 cur = repo.changectx('.').node()
1082 cur = repo.changectx('.').node()
1083 marks = repo._bookmarks
1083 marks = repo._bookmarks
1084 if delete:
1084 if delete:
1085 tr = repo.transaction('bookmark')
1085 tr = repo.transaction('bookmark')
1086 for mark in names:
1086 for mark in names:
1087 if mark not in marks:
1087 if mark not in marks:
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1089 mark)
1089 mark)
1090 if mark == repo._activebookmark:
1090 if mark == repo._activebookmark:
1091 bookmarks.deactivate(repo)
1091 bookmarks.deactivate(repo)
1092 del marks[mark]
1092 del marks[mark]
1093
1093
1094 elif rename:
1094 elif rename:
1095 tr = repo.transaction('bookmark')
1095 tr = repo.transaction('bookmark')
1096 if not names:
1096 if not names:
1097 raise error.Abort(_("new bookmark name required"))
1097 raise error.Abort(_("new bookmark name required"))
1098 elif len(names) > 1:
1098 elif len(names) > 1:
1099 raise error.Abort(_("only one new bookmark name allowed"))
1099 raise error.Abort(_("only one new bookmark name allowed"))
1100 mark = checkformat(names[0])
1100 mark = checkformat(names[0])
1101 if rename not in marks:
1101 if rename not in marks:
1102 raise error.Abort(_("bookmark '%s' does not exist")
1102 raise error.Abort(_("bookmark '%s' does not exist")
1103 % rename)
1103 % rename)
1104 checkconflict(repo, mark, cur, force)
1104 checkconflict(repo, mark, cur, force)
1105 marks[mark] = marks[rename]
1105 marks[mark] = marks[rename]
1106 if repo._activebookmark == rename and not inactive:
1106 if repo._activebookmark == rename and not inactive:
1107 bookmarks.activate(repo, mark)
1107 bookmarks.activate(repo, mark)
1108 del marks[rename]
1108 del marks[rename]
1109 elif names:
1109 elif names:
1110 tr = repo.transaction('bookmark')
1110 tr = repo.transaction('bookmark')
1111 newact = None
1111 newact = None
1112 for mark in names:
1112 for mark in names:
1113 mark = checkformat(mark)
1113 mark = checkformat(mark)
1114 if newact is None:
1114 if newact is None:
1115 newact = mark
1115 newact = mark
1116 if inactive and mark == repo._activebookmark:
1116 if inactive and mark == repo._activebookmark:
1117 bookmarks.deactivate(repo)
1117 bookmarks.deactivate(repo)
1118 return
1118 return
1119 tgt = cur
1119 tgt = cur
1120 if rev:
1120 if rev:
1121 tgt = scmutil.revsingle(repo, rev).node()
1121 tgt = scmutil.revsingle(repo, rev).node()
1122 checkconflict(repo, mark, cur, force, tgt)
1122 checkconflict(repo, mark, cur, force, tgt)
1123 marks[mark] = tgt
1123 marks[mark] = tgt
1124 if not inactive and cur == marks[newact] and not rev:
1124 if not inactive and cur == marks[newact] and not rev:
1125 bookmarks.activate(repo, newact)
1125 bookmarks.activate(repo, newact)
1126 elif cur != tgt and newact == repo._activebookmark:
1126 elif cur != tgt and newact == repo._activebookmark:
1127 bookmarks.deactivate(repo)
1127 bookmarks.deactivate(repo)
1128 elif inactive:
1128 elif inactive:
1129 if len(marks) == 0:
1129 if len(marks) == 0:
1130 ui.status(_("no bookmarks set\n"))
1130 ui.status(_("no bookmarks set\n"))
1131 elif not repo._activebookmark:
1131 elif not repo._activebookmark:
1132 ui.status(_("no active bookmark\n"))
1132 ui.status(_("no active bookmark\n"))
1133 else:
1133 else:
1134 bookmarks.deactivate(repo)
1134 bookmarks.deactivate(repo)
1135 if tr is not None:
1135 if tr is not None:
1136 marks.recordchange(tr)
1136 marks.recordchange(tr)
1137 tr.close()
1137 tr.close()
1138 finally:
1138 finally:
1139 lockmod.release(tr, lock, wlock)
1139 lockmod.release(tr, lock, wlock)
1140 else: # show bookmarks
1140 else: # show bookmarks
1141 fm = ui.formatter('bookmarks', opts)
1141 fm = ui.formatter('bookmarks', opts)
1142 hexfn = fm.hexfunc
1142 hexfn = fm.hexfunc
1143 marks = repo._bookmarks
1143 marks = repo._bookmarks
1144 if len(marks) == 0 and fm.isplain():
1144 if len(marks) == 0 and fm.isplain():
1145 ui.status(_("no bookmarks set\n"))
1145 ui.status(_("no bookmarks set\n"))
1146 for bmark, n in sorted(marks.iteritems()):
1146 for bmark, n in sorted(marks.iteritems()):
1147 active = repo._activebookmark
1147 active = repo._activebookmark
1148 if bmark == active:
1148 if bmark == active:
1149 prefix, label = '*', activebookmarklabel
1149 prefix, label = '*', activebookmarklabel
1150 else:
1150 else:
1151 prefix, label = ' ', ''
1151 prefix, label = ' ', ''
1152
1152
1153 fm.startitem()
1153 fm.startitem()
1154 if not ui.quiet:
1154 if not ui.quiet:
1155 fm.plain(' %s ' % prefix, label=label)
1155 fm.plain(' %s ' % prefix, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1157 pad = " " * (25 - encoding.colwidth(bmark))
1157 pad = " " * (25 - encoding.colwidth(bmark))
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1159 repo.changelog.rev(n), hexfn(n), label=label)
1159 repo.changelog.rev(n), hexfn(n), label=label)
1160 fm.data(active=(bmark == active))
1160 fm.data(active=(bmark == active))
1161 fm.plain('\n')
1161 fm.plain('\n')
1162 fm.end()
1162 fm.end()
1163
1163
1164 @command('branch',
1164 @command('branch',
1165 [('f', 'force', None,
1165 [('f', 'force', None,
1166 _('set branch name even if it shadows an existing branch')),
1166 _('set branch name even if it shadows an existing branch')),
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1168 _('[-fC] [NAME]'))
1168 _('[-fC] [NAME]'))
1169 def branch(ui, repo, label=None, **opts):
1169 def branch(ui, repo, label=None, **opts):
1170 """set or show the current branch name
1170 """set or show the current branch name
1171
1171
1172 .. note::
1172 .. note::
1173
1173
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1176 information about named branches and bookmarks.
1176 information about named branches and bookmarks.
1177
1177
1178 With no argument, show the current branch name. With one argument,
1178 With no argument, show the current branch name. With one argument,
1179 set the working directory branch name (the branch will not exist
1179 set the working directory branch name (the branch will not exist
1180 in the repository until the next commit). Standard practice
1180 in the repository until the next commit). Standard practice
1181 recommends that primary development take place on the 'default'
1181 recommends that primary development take place on the 'default'
1182 branch.
1182 branch.
1183
1183
1184 Unless -f/--force is specified, branch will not let you set a
1184 Unless -f/--force is specified, branch will not let you set a
1185 branch name that already exists.
1185 branch name that already exists.
1186
1186
1187 Use -C/--clean to reset the working directory branch to that of
1187 Use -C/--clean to reset the working directory branch to that of
1188 the parent of the working directory, negating a previous branch
1188 the parent of the working directory, negating a previous branch
1189 change.
1189 change.
1190
1190
1191 Use the command :hg:`update` to switch to an existing branch. Use
1191 Use the command :hg:`update` to switch to an existing branch. Use
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1193 When all heads of a branch are closed, the branch will be
1193 When all heads of a branch are closed, the branch will be
1194 considered closed.
1194 considered closed.
1195
1195
1196 Returns 0 on success.
1196 Returns 0 on success.
1197 """
1197 """
1198 if label:
1198 if label:
1199 label = label.strip()
1199 label = label.strip()
1200
1200
1201 if not opts.get('clean') and not label:
1201 if not opts.get('clean') and not label:
1202 ui.write("%s\n" % repo.dirstate.branch())
1202 ui.write("%s\n" % repo.dirstate.branch())
1203 return
1203 return
1204
1204
1205 with repo.wlock():
1205 with repo.wlock():
1206 if opts.get('clean'):
1206 if opts.get('clean'):
1207 label = repo[None].p1().branch()
1207 label = repo[None].p1().branch()
1208 repo.dirstate.setbranch(label)
1208 repo.dirstate.setbranch(label)
1209 ui.status(_('reset working directory to branch %s\n') % label)
1209 ui.status(_('reset working directory to branch %s\n') % label)
1210 elif label:
1210 elif label:
1211 if not opts.get('force') and label in repo.branchmap():
1211 if not opts.get('force') and label in repo.branchmap():
1212 if label not in [p.branch() for p in repo[None].parents()]:
1212 if label not in [p.branch() for p in repo[None].parents()]:
1213 raise error.Abort(_('a branch of the same name already'
1213 raise error.Abort(_('a branch of the same name already'
1214 ' exists'),
1214 ' exists'),
1215 # i18n: "it" refers to an existing branch
1215 # i18n: "it" refers to an existing branch
1216 hint=_("use 'hg update' to switch to it"))
1216 hint=_("use 'hg update' to switch to it"))
1217 scmutil.checknewlabel(repo, label, 'branch')
1217 scmutil.checknewlabel(repo, label, 'branch')
1218 repo.dirstate.setbranch(label)
1218 repo.dirstate.setbranch(label)
1219 ui.status(_('marked working directory as branch %s\n') % label)
1219 ui.status(_('marked working directory as branch %s\n') % label)
1220
1220
1221 # find any open named branches aside from default
1221 # find any open named branches aside from default
1222 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1222 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1223 if n != "default" and not c]
1223 if n != "default" and not c]
1224 if not others:
1224 if not others:
1225 ui.status(_('(branches are permanent and global, '
1225 ui.status(_('(branches are permanent and global, '
1226 'did you want a bookmark?)\n'))
1226 'did you want a bookmark?)\n'))
1227
1227
1228 @command('branches',
1228 @command('branches',
1229 [('a', 'active', False,
1229 [('a', 'active', False,
1230 _('show only branches that have unmerged heads (DEPRECATED)')),
1230 _('show only branches that have unmerged heads (DEPRECATED)')),
1231 ('c', 'closed', False, _('show normal and closed branches')),
1231 ('c', 'closed', False, _('show normal and closed branches')),
1232 ] + formatteropts,
1232 ] + formatteropts,
1233 _('[-c]'))
1233 _('[-c]'))
1234 def branches(ui, repo, active=False, closed=False, **opts):
1234 def branches(ui, repo, active=False, closed=False, **opts):
1235 """list repository named branches
1235 """list repository named branches
1236
1236
1237 List the repository's named branches, indicating which ones are
1237 List the repository's named branches, indicating which ones are
1238 inactive. If -c/--closed is specified, also list branches which have
1238 inactive. If -c/--closed is specified, also list branches which have
1239 been marked closed (see :hg:`commit --close-branch`).
1239 been marked closed (see :hg:`commit --close-branch`).
1240
1240
1241 Use the command :hg:`update` to switch to an existing branch.
1241 Use the command :hg:`update` to switch to an existing branch.
1242
1242
1243 Returns 0.
1243 Returns 0.
1244 """
1244 """
1245
1245
1246 fm = ui.formatter('branches', opts)
1246 fm = ui.formatter('branches', opts)
1247 hexfunc = fm.hexfunc
1247 hexfunc = fm.hexfunc
1248
1248
1249 allheads = set(repo.heads())
1249 allheads = set(repo.heads())
1250 branches = []
1250 branches = []
1251 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1251 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1252 isactive = not isclosed and bool(set(heads) & allheads)
1252 isactive = not isclosed and bool(set(heads) & allheads)
1253 branches.append((tag, repo[tip], isactive, not isclosed))
1253 branches.append((tag, repo[tip], isactive, not isclosed))
1254 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1254 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1255 reverse=True)
1255 reverse=True)
1256
1256
1257 for tag, ctx, isactive, isopen in branches:
1257 for tag, ctx, isactive, isopen in branches:
1258 if active and not isactive:
1258 if active and not isactive:
1259 continue
1259 continue
1260 if isactive:
1260 if isactive:
1261 label = 'branches.active'
1261 label = 'branches.active'
1262 notice = ''
1262 notice = ''
1263 elif not isopen:
1263 elif not isopen:
1264 if not closed:
1264 if not closed:
1265 continue
1265 continue
1266 label = 'branches.closed'
1266 label = 'branches.closed'
1267 notice = _(' (closed)')
1267 notice = _(' (closed)')
1268 else:
1268 else:
1269 label = 'branches.inactive'
1269 label = 'branches.inactive'
1270 notice = _(' (inactive)')
1270 notice = _(' (inactive)')
1271 current = (tag == repo.dirstate.branch())
1271 current = (tag == repo.dirstate.branch())
1272 if current:
1272 if current:
1273 label = 'branches.current'
1273 label = 'branches.current'
1274
1274
1275 fm.startitem()
1275 fm.startitem()
1276 fm.write('branch', '%s', tag, label=label)
1276 fm.write('branch', '%s', tag, label=label)
1277 rev = ctx.rev()
1277 rev = ctx.rev()
1278 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1278 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1279 fmt = ' ' * padsize + ' %d:%s'
1279 fmt = ' ' * padsize + ' %d:%s'
1280 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1280 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1281 label='log.changeset changeset.%s' % ctx.phasestr())
1281 label='log.changeset changeset.%s' % ctx.phasestr())
1282 fm.data(active=isactive, closed=not isopen, current=current)
1282 fm.data(active=isactive, closed=not isopen, current=current)
1283 if not ui.quiet:
1283 if not ui.quiet:
1284 fm.plain(notice)
1284 fm.plain(notice)
1285 fm.plain('\n')
1285 fm.plain('\n')
1286 fm.end()
1286 fm.end()
1287
1287
1288 @command('bundle',
1288 @command('bundle',
1289 [('f', 'force', None, _('run even when the destination is unrelated')),
1289 [('f', 'force', None, _('run even when the destination is unrelated')),
1290 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1290 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1291 _('REV')),
1291 _('REV')),
1292 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1292 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1293 _('BRANCH')),
1293 _('BRANCH')),
1294 ('', 'base', [],
1294 ('', 'base', [],
1295 _('a base changeset assumed to be available at the destination'),
1295 _('a base changeset assumed to be available at the destination'),
1296 _('REV')),
1296 _('REV')),
1297 ('a', 'all', None, _('bundle all changesets in the repository')),
1297 ('a', 'all', None, _('bundle all changesets in the repository')),
1298 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1298 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1299 ] + remoteopts,
1299 ] + remoteopts,
1300 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1300 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1301 def bundle(ui, repo, fname, dest=None, **opts):
1301 def bundle(ui, repo, fname, dest=None, **opts):
1302 """create a changegroup file
1302 """create a changegroup file
1303
1303
1304 Generate a changegroup file collecting changesets to be added
1304 Generate a changegroup file collecting changesets to be added
1305 to a repository.
1305 to a repository.
1306
1306
1307 To create a bundle containing all changesets, use -a/--all
1307 To create a bundle containing all changesets, use -a/--all
1308 (or --base null). Otherwise, hg assumes the destination will have
1308 (or --base null). Otherwise, hg assumes the destination will have
1309 all the nodes you specify with --base parameters. Otherwise, hg
1309 all the nodes you specify with --base parameters. Otherwise, hg
1310 will assume the repository has all the nodes in destination, or
1310 will assume the repository has all the nodes in destination, or
1311 default-push/default if no destination is specified.
1311 default-push/default if no destination is specified.
1312
1312
1313 You can change bundle format with the -t/--type option. You can
1313 You can change bundle format with the -t/--type option. You can
1314 specify a compression, a bundle version or both using a dash
1314 specify a compression, a bundle version or both using a dash
1315 (comp-version). The available compression methods are: none, bzip2,
1315 (comp-version). The available compression methods are: none, bzip2,
1316 and gzip (by default, bundles are compressed using bzip2). The
1316 and gzip (by default, bundles are compressed using bzip2). The
1317 available formats are: v1, v2 (default to most suitable).
1317 available formats are: v1, v2 (default to most suitable).
1318
1318
1319 The bundle file can then be transferred using conventional means
1319 The bundle file can then be transferred using conventional means
1320 and applied to another repository with the unbundle or pull
1320 and applied to another repository with the unbundle or pull
1321 command. This is useful when direct push and pull are not
1321 command. This is useful when direct push and pull are not
1322 available or when exporting an entire repository is undesirable.
1322 available or when exporting an entire repository is undesirable.
1323
1323
1324 Applying bundles preserves all changeset contents including
1324 Applying bundles preserves all changeset contents including
1325 permissions, copy/rename information, and revision history.
1325 permissions, copy/rename information, and revision history.
1326
1326
1327 Returns 0 on success, 1 if no changes found.
1327 Returns 0 on success, 1 if no changes found.
1328 """
1328 """
1329 revs = None
1329 revs = None
1330 if 'rev' in opts:
1330 if 'rev' in opts:
1331 revstrings = opts['rev']
1331 revstrings = opts['rev']
1332 revs = scmutil.revrange(repo, revstrings)
1332 revs = scmutil.revrange(repo, revstrings)
1333 if revstrings and not revs:
1333 if revstrings and not revs:
1334 raise error.Abort(_('no commits to bundle'))
1334 raise error.Abort(_('no commits to bundle'))
1335
1335
1336 bundletype = opts.get('type', 'bzip2').lower()
1336 bundletype = opts.get('type', 'bzip2').lower()
1337 try:
1337 try:
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1339 repo, bundletype, strict=False)
1339 repo, bundletype, strict=False)
1340 except error.UnsupportedBundleSpecification as e:
1340 except error.UnsupportedBundleSpecification as e:
1341 raise error.Abort(str(e),
1341 raise error.Abort(str(e),
1342 hint=_("see 'hg help bundle' for supported "
1342 hint=_("see 'hg help bundle' for supported "
1343 "values for --type"))
1343 "values for --type"))
1344
1344
1345 # Packed bundles are a pseudo bundle format for now.
1345 # Packed bundles are a pseudo bundle format for now.
1346 if cgversion == 's1':
1346 if cgversion == 's1':
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1348 hint=_("use 'hg debugcreatestreamclonebundle'"))
1348 hint=_("use 'hg debugcreatestreamclonebundle'"))
1349
1349
1350 if opts.get('all'):
1350 if opts.get('all'):
1351 if dest:
1351 if dest:
1352 raise error.Abort(_("--all is incompatible with specifying "
1352 raise error.Abort(_("--all is incompatible with specifying "
1353 "a destination"))
1353 "a destination"))
1354 if opts.get('base'):
1354 if opts.get('base'):
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1356 base = ['null']
1356 base = ['null']
1357 else:
1357 else:
1358 base = scmutil.revrange(repo, opts.get('base'))
1358 base = scmutil.revrange(repo, opts.get('base'))
1359 # TODO: get desired bundlecaps from command line.
1359 # TODO: get desired bundlecaps from command line.
1360 bundlecaps = None
1360 bundlecaps = None
1361 if cgversion not in changegroup.supportedoutgoingversions(repo):
1361 if cgversion not in changegroup.supportedoutgoingversions(repo):
1362 raise error.Abort(_("repository does not support bundle version %s") %
1362 raise error.Abort(_("repository does not support bundle version %s") %
1363 cgversion)
1363 cgversion)
1364
1364
1365 if base:
1365 if base:
1366 if dest:
1366 if dest:
1367 raise error.Abort(_("--base is incompatible with specifying "
1367 raise error.Abort(_("--base is incompatible with specifying "
1368 "a destination"))
1368 "a destination"))
1369 common = [repo.lookup(rev) for rev in base]
1369 common = [repo.lookup(rev) for rev in base]
1370 heads = revs and map(repo.lookup, revs) or None
1370 heads = revs and map(repo.lookup, revs) or None
1371 outgoing = discovery.outgoing(repo, common, heads)
1371 outgoing = discovery.outgoing(repo, common, heads)
1372 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1372 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1373 bundlecaps=bundlecaps,
1373 bundlecaps=bundlecaps,
1374 version=cgversion)
1374 version=cgversion)
1375 outgoing = None
1375 outgoing = None
1376 else:
1376 else:
1377 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1377 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1378 dest, branches = hg.parseurl(dest, opts.get('branch'))
1378 dest, branches = hg.parseurl(dest, opts.get('branch'))
1379 other = hg.peer(repo, opts, dest)
1379 other = hg.peer(repo, opts, dest)
1380 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1380 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1381 heads = revs and map(repo.lookup, revs) or revs
1381 heads = revs and map(repo.lookup, revs) or revs
1382 outgoing = discovery.findcommonoutgoing(repo, other,
1382 outgoing = discovery.findcommonoutgoing(repo, other,
1383 onlyheads=heads,
1383 onlyheads=heads,
1384 force=opts.get('force'),
1384 force=opts.get('force'),
1385 portable=True)
1385 portable=True)
1386 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1386 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1387 bundlecaps, version=cgversion)
1387 bundlecaps, version=cgversion)
1388 if not cg:
1388 if not cg:
1389 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1389 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1390 return 1
1390 return 1
1391
1391
1392 if cgversion == '01': #bundle1
1392 if cgversion == '01': #bundle1
1393 if bcompression is None:
1393 if bcompression is None:
1394 bcompression = 'UN'
1394 bcompression = 'UN'
1395 bversion = 'HG10' + bcompression
1395 bversion = 'HG10' + bcompression
1396 bcompression = None
1396 bcompression = None
1397 else:
1397 else:
1398 assert cgversion == '02'
1398 assert cgversion == '02'
1399 bversion = 'HG20'
1399 bversion = 'HG20'
1400
1400
1401 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1401 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1402
1402
1403 @command('cat',
1403 @command('cat',
1404 [('o', 'output', '',
1404 [('o', 'output', '',
1405 _('print output to file with formatted name'), _('FORMAT')),
1405 _('print output to file with formatted name'), _('FORMAT')),
1406 ('r', 'rev', '', _('print the given revision'), _('REV')),
1406 ('r', 'rev', '', _('print the given revision'), _('REV')),
1407 ('', 'decode', None, _('apply any matching decode filter')),
1407 ('', 'decode', None, _('apply any matching decode filter')),
1408 ] + walkopts,
1408 ] + walkopts,
1409 _('[OPTION]... FILE...'),
1409 _('[OPTION]... FILE...'),
1410 inferrepo=True)
1410 inferrepo=True)
1411 def cat(ui, repo, file1, *pats, **opts):
1411 def cat(ui, repo, file1, *pats, **opts):
1412 """output the current or given revision of files
1412 """output the current or given revision of files
1413
1413
1414 Print the specified files as they were at the given revision. If
1414 Print the specified files as they were at the given revision. If
1415 no revision is given, the parent of the working directory is used.
1415 no revision is given, the parent of the working directory is used.
1416
1416
1417 Output may be to a file, in which case the name of the file is
1417 Output may be to a file, in which case the name of the file is
1418 given using a format string. The formatting rules as follows:
1418 given using a format string. The formatting rules as follows:
1419
1419
1420 :``%%``: literal "%" character
1420 :``%%``: literal "%" character
1421 :``%s``: basename of file being printed
1421 :``%s``: basename of file being printed
1422 :``%d``: dirname of file being printed, or '.' if in repository root
1422 :``%d``: dirname of file being printed, or '.' if in repository root
1423 :``%p``: root-relative path name of file being printed
1423 :``%p``: root-relative path name of file being printed
1424 :``%H``: changeset hash (40 hexadecimal digits)
1424 :``%H``: changeset hash (40 hexadecimal digits)
1425 :``%R``: changeset revision number
1425 :``%R``: changeset revision number
1426 :``%h``: short-form changeset hash (12 hexadecimal digits)
1426 :``%h``: short-form changeset hash (12 hexadecimal digits)
1427 :``%r``: zero-padded changeset revision number
1427 :``%r``: zero-padded changeset revision number
1428 :``%b``: basename of the exporting repository
1428 :``%b``: basename of the exporting repository
1429
1429
1430 Returns 0 on success.
1430 Returns 0 on success.
1431 """
1431 """
1432 ctx = scmutil.revsingle(repo, opts.get('rev'))
1432 ctx = scmutil.revsingle(repo, opts.get('rev'))
1433 m = scmutil.match(ctx, (file1,) + pats, opts)
1433 m = scmutil.match(ctx, (file1,) + pats, opts)
1434
1434
1435 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1435 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1436
1436
1437 @command('^clone',
1437 @command('^clone',
1438 [('U', 'noupdate', None, _('the clone will include an empty working '
1438 [('U', 'noupdate', None, _('the clone will include an empty working '
1439 'directory (only a repository)')),
1439 'directory (only a repository)')),
1440 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1440 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1441 _('REV')),
1441 _('REV')),
1442 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1442 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1443 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1443 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1444 ('', 'pull', None, _('use pull protocol to copy metadata')),
1444 ('', 'pull', None, _('use pull protocol to copy metadata')),
1445 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1445 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1446 ] + remoteopts,
1446 ] + remoteopts,
1447 _('[OPTION]... SOURCE [DEST]'),
1447 _('[OPTION]... SOURCE [DEST]'),
1448 norepo=True)
1448 norepo=True)
1449 def clone(ui, source, dest=None, **opts):
1449 def clone(ui, source, dest=None, **opts):
1450 """make a copy of an existing repository
1450 """make a copy of an existing repository
1451
1451
1452 Create a copy of an existing repository in a new directory.
1452 Create a copy of an existing repository in a new directory.
1453
1453
1454 If no destination directory name is specified, it defaults to the
1454 If no destination directory name is specified, it defaults to the
1455 basename of the source.
1455 basename of the source.
1456
1456
1457 The location of the source is added to the new repository's
1457 The location of the source is added to the new repository's
1458 ``.hg/hgrc`` file, as the default to be used for future pulls.
1458 ``.hg/hgrc`` file, as the default to be used for future pulls.
1459
1459
1460 Only local paths and ``ssh://`` URLs are supported as
1460 Only local paths and ``ssh://`` URLs are supported as
1461 destinations. For ``ssh://`` destinations, no working directory or
1461 destinations. For ``ssh://`` destinations, no working directory or
1462 ``.hg/hgrc`` will be created on the remote side.
1462 ``.hg/hgrc`` will be created on the remote side.
1463
1463
1464 If the source repository has a bookmark called '@' set, that
1464 If the source repository has a bookmark called '@' set, that
1465 revision will be checked out in the new repository by default.
1465 revision will be checked out in the new repository by default.
1466
1466
1467 To check out a particular version, use -u/--update, or
1467 To check out a particular version, use -u/--update, or
1468 -U/--noupdate to create a clone with no working directory.
1468 -U/--noupdate to create a clone with no working directory.
1469
1469
1470 To pull only a subset of changesets, specify one or more revisions
1470 To pull only a subset of changesets, specify one or more revisions
1471 identifiers with -r/--rev or branches with -b/--branch. The
1471 identifiers with -r/--rev or branches with -b/--branch. The
1472 resulting clone will contain only the specified changesets and
1472 resulting clone will contain only the specified changesets and
1473 their ancestors. These options (or 'clone src#rev dest') imply
1473 their ancestors. These options (or 'clone src#rev dest') imply
1474 --pull, even for local source repositories.
1474 --pull, even for local source repositories.
1475
1475
1476 .. note::
1476 .. note::
1477
1477
1478 Specifying a tag will include the tagged changeset but not the
1478 Specifying a tag will include the tagged changeset but not the
1479 changeset containing the tag.
1479 changeset containing the tag.
1480
1480
1481 .. container:: verbose
1481 .. container:: verbose
1482
1482
1483 For efficiency, hardlinks are used for cloning whenever the
1483 For efficiency, hardlinks are used for cloning whenever the
1484 source and destination are on the same filesystem (note this
1484 source and destination are on the same filesystem (note this
1485 applies only to the repository data, not to the working
1485 applies only to the repository data, not to the working
1486 directory). Some filesystems, such as AFS, implement hardlinking
1486 directory). Some filesystems, such as AFS, implement hardlinking
1487 incorrectly, but do not report errors. In these cases, use the
1487 incorrectly, but do not report errors. In these cases, use the
1488 --pull option to avoid hardlinking.
1488 --pull option to avoid hardlinking.
1489
1489
1490 In some cases, you can clone repositories and the working
1490 In some cases, you can clone repositories and the working
1491 directory using full hardlinks with ::
1491 directory using full hardlinks with ::
1492
1492
1493 $ cp -al REPO REPOCLONE
1493 $ cp -al REPO REPOCLONE
1494
1494
1495 This is the fastest way to clone, but it is not always safe. The
1495 This is the fastest way to clone, but it is not always safe. The
1496 operation is not atomic (making sure REPO is not modified during
1496 operation is not atomic (making sure REPO is not modified during
1497 the operation is up to you) and you have to make sure your
1497 the operation is up to you) and you have to make sure your
1498 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1498 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1499 so). Also, this is not compatible with certain extensions that
1499 so). Also, this is not compatible with certain extensions that
1500 place their metadata under the .hg directory, such as mq.
1500 place their metadata under the .hg directory, such as mq.
1501
1501
1502 Mercurial will update the working directory to the first applicable
1502 Mercurial will update the working directory to the first applicable
1503 revision from this list:
1503 revision from this list:
1504
1504
1505 a) null if -U or the source repository has no changesets
1505 a) null if -U or the source repository has no changesets
1506 b) if -u . and the source repository is local, the first parent of
1506 b) if -u . and the source repository is local, the first parent of
1507 the source repository's working directory
1507 the source repository's working directory
1508 c) the changeset specified with -u (if a branch name, this means the
1508 c) the changeset specified with -u (if a branch name, this means the
1509 latest head of that branch)
1509 latest head of that branch)
1510 d) the changeset specified with -r
1510 d) the changeset specified with -r
1511 e) the tipmost head specified with -b
1511 e) the tipmost head specified with -b
1512 f) the tipmost head specified with the url#branch source syntax
1512 f) the tipmost head specified with the url#branch source syntax
1513 g) the revision marked with the '@' bookmark, if present
1513 g) the revision marked with the '@' bookmark, if present
1514 h) the tipmost head of the default branch
1514 h) the tipmost head of the default branch
1515 i) tip
1515 i) tip
1516
1516
1517 When cloning from servers that support it, Mercurial may fetch
1517 When cloning from servers that support it, Mercurial may fetch
1518 pre-generated data from a server-advertised URL. When this is done,
1518 pre-generated data from a server-advertised URL. When this is done,
1519 hooks operating on incoming changesets and changegroups may fire twice,
1519 hooks operating on incoming changesets and changegroups may fire twice,
1520 once for the bundle fetched from the URL and another for any additional
1520 once for the bundle fetched from the URL and another for any additional
1521 data not fetched from this URL. In addition, if an error occurs, the
1521 data not fetched from this URL. In addition, if an error occurs, the
1522 repository may be rolled back to a partial clone. This behavior may
1522 repository may be rolled back to a partial clone. This behavior may
1523 change in future releases. See :hg:`help -e clonebundles` for more.
1523 change in future releases. See :hg:`help -e clonebundles` for more.
1524
1524
1525 Examples:
1525 Examples:
1526
1526
1527 - clone a remote repository to a new directory named hg/::
1527 - clone a remote repository to a new directory named hg/::
1528
1528
1529 hg clone http://selenic.com/hg
1529 hg clone http://selenic.com/hg
1530
1530
1531 - create a lightweight local clone::
1531 - create a lightweight local clone::
1532
1532
1533 hg clone project/ project-feature/
1533 hg clone project/ project-feature/
1534
1534
1535 - clone from an absolute path on an ssh server (note double-slash)::
1535 - clone from an absolute path on an ssh server (note double-slash)::
1536
1536
1537 hg clone ssh://user@server//home/projects/alpha/
1537 hg clone ssh://user@server//home/projects/alpha/
1538
1538
1539 - do a high-speed clone over a LAN while checking out a
1539 - do a high-speed clone over a LAN while checking out a
1540 specified version::
1540 specified version::
1541
1541
1542 hg clone --uncompressed http://server/repo -u 1.5
1542 hg clone --uncompressed http://server/repo -u 1.5
1543
1543
1544 - create a repository without changesets after a particular revision::
1544 - create a repository without changesets after a particular revision::
1545
1545
1546 hg clone -r 04e544 experimental/ good/
1546 hg clone -r 04e544 experimental/ good/
1547
1547
1548 - clone (and track) a particular named branch::
1548 - clone (and track) a particular named branch::
1549
1549
1550 hg clone http://selenic.com/hg#stable
1550 hg clone http://selenic.com/hg#stable
1551
1551
1552 See :hg:`help urls` for details on specifying URLs.
1552 See :hg:`help urls` for details on specifying URLs.
1553
1553
1554 Returns 0 on success.
1554 Returns 0 on success.
1555 """
1555 """
1556 if opts.get('noupdate') and opts.get('updaterev'):
1556 if opts.get('noupdate') and opts.get('updaterev'):
1557 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1557 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1558
1558
1559 r = hg.clone(ui, opts, source, dest,
1559 r = hg.clone(ui, opts, source, dest,
1560 pull=opts.get('pull'),
1560 pull=opts.get('pull'),
1561 stream=opts.get('uncompressed'),
1561 stream=opts.get('uncompressed'),
1562 rev=opts.get('rev'),
1562 rev=opts.get('rev'),
1563 update=opts.get('updaterev') or not opts.get('noupdate'),
1563 update=opts.get('updaterev') or not opts.get('noupdate'),
1564 branch=opts.get('branch'),
1564 branch=opts.get('branch'),
1565 shareopts=opts.get('shareopts'))
1565 shareopts=opts.get('shareopts'))
1566
1566
1567 return r is None
1567 return r is None
1568
1568
1569 @command('^commit|ci',
1569 @command('^commit|ci',
1570 [('A', 'addremove', None,
1570 [('A', 'addremove', None,
1571 _('mark new/missing files as added/removed before committing')),
1571 _('mark new/missing files as added/removed before committing')),
1572 ('', 'close-branch', None,
1572 ('', 'close-branch', None,
1573 _('mark a branch head as closed')),
1573 _('mark a branch head as closed')),
1574 ('', 'amend', None, _('amend the parent of the working directory')),
1574 ('', 'amend', None, _('amend the parent of the working directory')),
1575 ('s', 'secret', None, _('use the secret phase for committing')),
1575 ('s', 'secret', None, _('use the secret phase for committing')),
1576 ('e', 'edit', None, _('invoke editor on commit messages')),
1576 ('e', 'edit', None, _('invoke editor on commit messages')),
1577 ('i', 'interactive', None, _('use interactive mode')),
1577 ('i', 'interactive', None, _('use interactive mode')),
1578 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1578 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1579 _('[OPTION]... [FILE]...'),
1579 _('[OPTION]... [FILE]...'),
1580 inferrepo=True)
1580 inferrepo=True)
1581 def commit(ui, repo, *pats, **opts):
1581 def commit(ui, repo, *pats, **opts):
1582 """commit the specified files or all outstanding changes
1582 """commit the specified files or all outstanding changes
1583
1583
1584 Commit changes to the given files into the repository. Unlike a
1584 Commit changes to the given files into the repository. Unlike a
1585 centralized SCM, this operation is a local operation. See
1585 centralized SCM, this operation is a local operation. See
1586 :hg:`push` for a way to actively distribute your changes.
1586 :hg:`push` for a way to actively distribute your changes.
1587
1587
1588 If a list of files is omitted, all changes reported by :hg:`status`
1588 If a list of files is omitted, all changes reported by :hg:`status`
1589 will be committed.
1589 will be committed.
1590
1590
1591 If you are committing the result of a merge, do not provide any
1591 If you are committing the result of a merge, do not provide any
1592 filenames or -I/-X filters.
1592 filenames or -I/-X filters.
1593
1593
1594 If no commit message is specified, Mercurial starts your
1594 If no commit message is specified, Mercurial starts your
1595 configured editor where you can enter a message. In case your
1595 configured editor where you can enter a message. In case your
1596 commit fails, you will find a backup of your message in
1596 commit fails, you will find a backup of your message in
1597 ``.hg/last-message.txt``.
1597 ``.hg/last-message.txt``.
1598
1598
1599 The --close-branch flag can be used to mark the current branch
1599 The --close-branch flag can be used to mark the current branch
1600 head closed. When all heads of a branch are closed, the branch
1600 head closed. When all heads of a branch are closed, the branch
1601 will be considered closed and no longer listed.
1601 will be considered closed and no longer listed.
1602
1602
1603 The --amend flag can be used to amend the parent of the
1603 The --amend flag can be used to amend the parent of the
1604 working directory with a new commit that contains the changes
1604 working directory with a new commit that contains the changes
1605 in the parent in addition to those currently reported by :hg:`status`,
1605 in the parent in addition to those currently reported by :hg:`status`,
1606 if there are any. The old commit is stored in a backup bundle in
1606 if there are any. The old commit is stored in a backup bundle in
1607 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1607 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1608 on how to restore it).
1608 on how to restore it).
1609
1609
1610 Message, user and date are taken from the amended commit unless
1610 Message, user and date are taken from the amended commit unless
1611 specified. When a message isn't specified on the command line,
1611 specified. When a message isn't specified on the command line,
1612 the editor will open with the message of the amended commit.
1612 the editor will open with the message of the amended commit.
1613
1613
1614 It is not possible to amend public changesets (see :hg:`help phases`)
1614 It is not possible to amend public changesets (see :hg:`help phases`)
1615 or changesets that have children.
1615 or changesets that have children.
1616
1616
1617 See :hg:`help dates` for a list of formats valid for -d/--date.
1617 See :hg:`help dates` for a list of formats valid for -d/--date.
1618
1618
1619 Returns 0 on success, 1 if nothing changed.
1619 Returns 0 on success, 1 if nothing changed.
1620
1620
1621 .. container:: verbose
1621 .. container:: verbose
1622
1622
1623 Examples:
1623 Examples:
1624
1624
1625 - commit all files ending in .py::
1625 - commit all files ending in .py::
1626
1626
1627 hg commit --include "set:**.py"
1627 hg commit --include "set:**.py"
1628
1628
1629 - commit all non-binary files::
1629 - commit all non-binary files::
1630
1630
1631 hg commit --exclude "set:binary()"
1631 hg commit --exclude "set:binary()"
1632
1632
1633 - amend the current commit and set the date to now::
1633 - amend the current commit and set the date to now::
1634
1634
1635 hg commit --amend --date now
1635 hg commit --amend --date now
1636 """
1636 """
1637 wlock = lock = None
1637 wlock = lock = None
1638 try:
1638 try:
1639 wlock = repo.wlock()
1639 wlock = repo.wlock()
1640 lock = repo.lock()
1640 lock = repo.lock()
1641 return _docommit(ui, repo, *pats, **opts)
1641 return _docommit(ui, repo, *pats, **opts)
1642 finally:
1642 finally:
1643 release(lock, wlock)
1643 release(lock, wlock)
1644
1644
1645 def _docommit(ui, repo, *pats, **opts):
1645 def _docommit(ui, repo, *pats, **opts):
1646 if opts.get('interactive'):
1646 if opts.get('interactive'):
1647 opts.pop('interactive')
1647 opts.pop('interactive')
1648 cmdutil.dorecord(ui, repo, commit, None, False,
1648 cmdutil.dorecord(ui, repo, commit, None, False,
1649 cmdutil.recordfilter, *pats, **opts)
1649 cmdutil.recordfilter, *pats, **opts)
1650 return
1650 return
1651
1651
1652 if opts.get('subrepos'):
1652 if opts.get('subrepos'):
1653 if opts.get('amend'):
1653 if opts.get('amend'):
1654 raise error.Abort(_('cannot amend with --subrepos'))
1654 raise error.Abort(_('cannot amend with --subrepos'))
1655 # Let --subrepos on the command line override config setting.
1655 # Let --subrepos on the command line override config setting.
1656 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1656 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1657
1657
1658 cmdutil.checkunfinished(repo, commit=True)
1658 cmdutil.checkunfinished(repo, commit=True)
1659
1659
1660 branch = repo[None].branch()
1660 branch = repo[None].branch()
1661 bheads = repo.branchheads(branch)
1661 bheads = repo.branchheads(branch)
1662
1662
1663 extra = {}
1663 extra = {}
1664 if opts.get('close_branch'):
1664 if opts.get('close_branch'):
1665 extra['close'] = 1
1665 extra['close'] = 1
1666
1666
1667 if not bheads:
1667 if not bheads:
1668 raise error.Abort(_('can only close branch heads'))
1668 raise error.Abort(_('can only close branch heads'))
1669 elif opts.get('amend'):
1669 elif opts.get('amend'):
1670 if repo[None].parents()[0].p1().branch() != branch and \
1670 if repo[None].parents()[0].p1().branch() != branch and \
1671 repo[None].parents()[0].p2().branch() != branch:
1671 repo[None].parents()[0].p2().branch() != branch:
1672 raise error.Abort(_('can only close branch heads'))
1672 raise error.Abort(_('can only close branch heads'))
1673
1673
1674 if opts.get('amend'):
1674 if opts.get('amend'):
1675 if ui.configbool('ui', 'commitsubrepos'):
1675 if ui.configbool('ui', 'commitsubrepos'):
1676 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1676 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1677
1677
1678 old = repo['.']
1678 old = repo['.']
1679 if not old.mutable():
1679 if not old.mutable():
1680 raise error.Abort(_('cannot amend public changesets'))
1680 raise error.Abort(_('cannot amend public changesets'))
1681 if len(repo[None].parents()) > 1:
1681 if len(repo[None].parents()) > 1:
1682 raise error.Abort(_('cannot amend while merging'))
1682 raise error.Abort(_('cannot amend while merging'))
1683 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1683 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1684 if not allowunstable and old.children():
1684 if not allowunstable and old.children():
1685 raise error.Abort(_('cannot amend changeset with children'))
1685 raise error.Abort(_('cannot amend changeset with children'))
1686
1686
1687 # Currently histedit gets confused if an amend happens while histedit
1687 # Currently histedit gets confused if an amend happens while histedit
1688 # is in progress. Since we have a checkunfinished command, we are
1688 # is in progress. Since we have a checkunfinished command, we are
1689 # temporarily honoring it.
1689 # temporarily honoring it.
1690 #
1690 #
1691 # Note: eventually this guard will be removed. Please do not expect
1691 # Note: eventually this guard will be removed. Please do not expect
1692 # this behavior to remain.
1692 # this behavior to remain.
1693 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1693 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1694 cmdutil.checkunfinished(repo)
1694 cmdutil.checkunfinished(repo)
1695
1695
1696 # commitfunc is used only for temporary amend commit by cmdutil.amend
1696 # commitfunc is used only for temporary amend commit by cmdutil.amend
1697 def commitfunc(ui, repo, message, match, opts):
1697 def commitfunc(ui, repo, message, match, opts):
1698 return repo.commit(message,
1698 return repo.commit(message,
1699 opts.get('user') or old.user(),
1699 opts.get('user') or old.user(),
1700 opts.get('date') or old.date(),
1700 opts.get('date') or old.date(),
1701 match,
1701 match,
1702 extra=extra)
1702 extra=extra)
1703
1703
1704 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1704 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1705 if node == old.node():
1705 if node == old.node():
1706 ui.status(_("nothing changed\n"))
1706 ui.status(_("nothing changed\n"))
1707 return 1
1707 return 1
1708 else:
1708 else:
1709 def commitfunc(ui, repo, message, match, opts):
1709 def commitfunc(ui, repo, message, match, opts):
1710 backup = ui.backupconfig('phases', 'new-commit')
1710 backup = ui.backupconfig('phases', 'new-commit')
1711 baseui = repo.baseui
1711 baseui = repo.baseui
1712 basebackup = baseui.backupconfig('phases', 'new-commit')
1712 basebackup = baseui.backupconfig('phases', 'new-commit')
1713 try:
1713 try:
1714 if opts.get('secret'):
1714 if opts.get('secret'):
1715 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1715 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1716 # Propagate to subrepos
1716 # Propagate to subrepos
1717 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1717 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1718
1718
1719 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1719 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1720 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1720 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1721 return repo.commit(message, opts.get('user'), opts.get('date'),
1721 return repo.commit(message, opts.get('user'), opts.get('date'),
1722 match,
1722 match,
1723 editor=editor,
1723 editor=editor,
1724 extra=extra)
1724 extra=extra)
1725 finally:
1725 finally:
1726 ui.restoreconfig(backup)
1726 ui.restoreconfig(backup)
1727 repo.baseui.restoreconfig(basebackup)
1727 repo.baseui.restoreconfig(basebackup)
1728
1728
1729
1729
1730 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1730 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1731
1731
1732 if not node:
1732 if not node:
1733 stat = cmdutil.postcommitstatus(repo, pats, opts)
1733 stat = cmdutil.postcommitstatus(repo, pats, opts)
1734 if stat[3]:
1734 if stat[3]:
1735 ui.status(_("nothing changed (%d missing files, see "
1735 ui.status(_("nothing changed (%d missing files, see "
1736 "'hg status')\n") % len(stat[3]))
1736 "'hg status')\n") % len(stat[3]))
1737 else:
1737 else:
1738 ui.status(_("nothing changed\n"))
1738 ui.status(_("nothing changed\n"))
1739 return 1
1739 return 1
1740
1740
1741 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1741 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1742
1742
1743 @command('config|showconfig|debugconfig',
1743 @command('config|showconfig|debugconfig',
1744 [('u', 'untrusted', None, _('show untrusted configuration options')),
1744 [('u', 'untrusted', None, _('show untrusted configuration options')),
1745 ('e', 'edit', None, _('edit user config')),
1745 ('e', 'edit', None, _('edit user config')),
1746 ('l', 'local', None, _('edit repository config')),
1746 ('l', 'local', None, _('edit repository config')),
1747 ('g', 'global', None, _('edit global config'))] + formatteropts,
1747 ('g', 'global', None, _('edit global config'))] + formatteropts,
1748 _('[-u] [NAME]...'),
1748 _('[-u] [NAME]...'),
1749 optionalrepo=True)
1749 optionalrepo=True)
1750 def config(ui, repo, *values, **opts):
1750 def config(ui, repo, *values, **opts):
1751 """show combined config settings from all hgrc files
1751 """show combined config settings from all hgrc files
1752
1752
1753 With no arguments, print names and values of all config items.
1753 With no arguments, print names and values of all config items.
1754
1754
1755 With one argument of the form section.name, print just the value
1755 With one argument of the form section.name, print just the value
1756 of that config item.
1756 of that config item.
1757
1757
1758 With multiple arguments, print names and values of all config
1758 With multiple arguments, print names and values of all config
1759 items with matching section names.
1759 items with matching section names.
1760
1760
1761 With --edit, start an editor on the user-level config file. With
1761 With --edit, start an editor on the user-level config file. With
1762 --global, edit the system-wide config file. With --local, edit the
1762 --global, edit the system-wide config file. With --local, edit the
1763 repository-level config file.
1763 repository-level config file.
1764
1764
1765 With --debug, the source (filename and line number) is printed
1765 With --debug, the source (filename and line number) is printed
1766 for each config item.
1766 for each config item.
1767
1767
1768 See :hg:`help config` for more information about config files.
1768 See :hg:`help config` for more information about config files.
1769
1769
1770 Returns 0 on success, 1 if NAME does not exist.
1770 Returns 0 on success, 1 if NAME does not exist.
1771
1771
1772 """
1772 """
1773
1773
1774 if opts.get('edit') or opts.get('local') or opts.get('global'):
1774 if opts.get('edit') or opts.get('local') or opts.get('global'):
1775 if opts.get('local') and opts.get('global'):
1775 if opts.get('local') and opts.get('global'):
1776 raise error.Abort(_("can't use --local and --global together"))
1776 raise error.Abort(_("can't use --local and --global together"))
1777
1777
1778 if opts.get('local'):
1778 if opts.get('local'):
1779 if not repo:
1779 if not repo:
1780 raise error.Abort(_("can't use --local outside a repository"))
1780 raise error.Abort(_("can't use --local outside a repository"))
1781 paths = [repo.join('hgrc')]
1781 paths = [repo.join('hgrc')]
1782 elif opts.get('global'):
1782 elif opts.get('global'):
1783 paths = scmutil.systemrcpath()
1783 paths = scmutil.systemrcpath()
1784 else:
1784 else:
1785 paths = scmutil.userrcpath()
1785 paths = scmutil.userrcpath()
1786
1786
1787 for f in paths:
1787 for f in paths:
1788 if os.path.exists(f):
1788 if os.path.exists(f):
1789 break
1789 break
1790 else:
1790 else:
1791 if opts.get('global'):
1791 if opts.get('global'):
1792 samplehgrc = uimod.samplehgrcs['global']
1792 samplehgrc = uimod.samplehgrcs['global']
1793 elif opts.get('local'):
1793 elif opts.get('local'):
1794 samplehgrc = uimod.samplehgrcs['local']
1794 samplehgrc = uimod.samplehgrcs['local']
1795 else:
1795 else:
1796 samplehgrc = uimod.samplehgrcs['user']
1796 samplehgrc = uimod.samplehgrcs['user']
1797
1797
1798 f = paths[0]
1798 f = paths[0]
1799 fp = open(f, "w")
1799 fp = open(f, "w")
1800 fp.write(samplehgrc)
1800 fp.write(samplehgrc)
1801 fp.close()
1801 fp.close()
1802
1802
1803 editor = ui.geteditor()
1803 editor = ui.geteditor()
1804 ui.system("%s \"%s\"" % (editor, f),
1804 ui.system("%s \"%s\"" % (editor, f),
1805 onerr=error.Abort, errprefix=_("edit failed"))
1805 onerr=error.Abort, errprefix=_("edit failed"))
1806 return
1806 return
1807
1807
1808 fm = ui.formatter('config', opts)
1808 fm = ui.formatter('config', opts)
1809 for f in scmutil.rcpath():
1809 for f in scmutil.rcpath():
1810 ui.debug('read config from: %s\n' % f)
1810 ui.debug('read config from: %s\n' % f)
1811 untrusted = bool(opts.get('untrusted'))
1811 untrusted = bool(opts.get('untrusted'))
1812 if values:
1812 if values:
1813 sections = [v for v in values if '.' not in v]
1813 sections = [v for v in values if '.' not in v]
1814 items = [v for v in values if '.' in v]
1814 items = [v for v in values if '.' in v]
1815 if len(items) > 1 or items and sections:
1815 if len(items) > 1 or items and sections:
1816 raise error.Abort(_('only one config item permitted'))
1816 raise error.Abort(_('only one config item permitted'))
1817 matched = False
1817 matched = False
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1819 value = str(value)
1819 value = str(value)
1820 if fm.isplain():
1820 if fm.isplain():
1821 value = value.replace('\n', '\\n')
1821 value = value.replace('\n', '\\n')
1822 entryname = section + '.' + name
1822 entryname = section + '.' + name
1823 if values:
1823 if values:
1824 for v in values:
1824 for v in values:
1825 if v == section:
1825 if v == section:
1826 fm.startitem()
1826 fm.startitem()
1827 fm.condwrite(ui.debugflag, 'source', '%s: ',
1827 fm.condwrite(ui.debugflag, 'source', '%s: ',
1828 ui.configsource(section, name, untrusted))
1828 ui.configsource(section, name, untrusted))
1829 fm.write('name value', '%s=%s\n', entryname, value)
1829 fm.write('name value', '%s=%s\n', entryname, value)
1830 matched = True
1830 matched = True
1831 elif v == entryname:
1831 elif v == entryname:
1832 fm.startitem()
1832 fm.startitem()
1833 fm.condwrite(ui.debugflag, 'source', '%s: ',
1833 fm.condwrite(ui.debugflag, 'source', '%s: ',
1834 ui.configsource(section, name, untrusted))
1834 ui.configsource(section, name, untrusted))
1835 fm.write('value', '%s\n', value)
1835 fm.write('value', '%s\n', value)
1836 fm.data(name=entryname)
1836 fm.data(name=entryname)
1837 matched = True
1837 matched = True
1838 else:
1838 else:
1839 fm.startitem()
1839 fm.startitem()
1840 fm.condwrite(ui.debugflag, 'source', '%s: ',
1840 fm.condwrite(ui.debugflag, 'source', '%s: ',
1841 ui.configsource(section, name, untrusted))
1841 ui.configsource(section, name, untrusted))
1842 fm.write('name value', '%s=%s\n', entryname, value)
1842 fm.write('name value', '%s=%s\n', entryname, value)
1843 matched = True
1843 matched = True
1844 fm.end()
1844 fm.end()
1845 if matched:
1845 if matched:
1846 return 0
1846 return 0
1847 return 1
1847 return 1
1848
1848
1849 @command('copy|cp',
1849 @command('copy|cp',
1850 [('A', 'after', None, _('record a copy that has already occurred')),
1850 [('A', 'after', None, _('record a copy that has already occurred')),
1851 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1851 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1852 ] + walkopts + dryrunopts,
1852 ] + walkopts + dryrunopts,
1853 _('[OPTION]... [SOURCE]... DEST'))
1853 _('[OPTION]... [SOURCE]... DEST'))
1854 def copy(ui, repo, *pats, **opts):
1854 def copy(ui, repo, *pats, **opts):
1855 """mark files as copied for the next commit
1855 """mark files as copied for the next commit
1856
1856
1857 Mark dest as having copies of source files. If dest is a
1857 Mark dest as having copies of source files. If dest is a
1858 directory, copies are put in that directory. If dest is a file,
1858 directory, copies are put in that directory. If dest is a file,
1859 the source must be a single file.
1859 the source must be a single file.
1860
1860
1861 By default, this command copies the contents of files as they
1861 By default, this command copies the contents of files as they
1862 exist in the working directory. If invoked with -A/--after, the
1862 exist in the working directory. If invoked with -A/--after, the
1863 operation is recorded, but no copying is performed.
1863 operation is recorded, but no copying is performed.
1864
1864
1865 This command takes effect with the next commit. To undo a copy
1865 This command takes effect with the next commit. To undo a copy
1866 before that, see :hg:`revert`.
1866 before that, see :hg:`revert`.
1867
1867
1868 Returns 0 on success, 1 if errors are encountered.
1868 Returns 0 on success, 1 if errors are encountered.
1869 """
1869 """
1870 with repo.wlock(False):
1870 with repo.wlock(False):
1871 return cmdutil.copy(ui, repo, pats, opts)
1871 return cmdutil.copy(ui, repo, pats, opts)
1872
1872
1873 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1873 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1874 def debugancestor(ui, repo, *args):
1874 def debugancestor(ui, repo, *args):
1875 """find the ancestor revision of two revisions in a given index"""
1875 """find the ancestor revision of two revisions in a given index"""
1876 if len(args) == 3:
1876 if len(args) == 3:
1877 index, rev1, rev2 = args
1877 index, rev1, rev2 = args
1878 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1878 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1879 lookup = r.lookup
1879 lookup = r.lookup
1880 elif len(args) == 2:
1880 elif len(args) == 2:
1881 if not repo:
1881 if not repo:
1882 raise error.Abort(_("there is no Mercurial repository here "
1882 raise error.Abort(_("there is no Mercurial repository here "
1883 "(.hg not found)"))
1883 "(.hg not found)"))
1884 rev1, rev2 = args
1884 rev1, rev2 = args
1885 r = repo.changelog
1885 r = repo.changelog
1886 lookup = repo.lookup
1886 lookup = repo.lookup
1887 else:
1887 else:
1888 raise error.Abort(_('either two or three arguments required'))
1888 raise error.Abort(_('either two or three arguments required'))
1889 a = r.ancestor(lookup(rev1), lookup(rev2))
1889 a = r.ancestor(lookup(rev1), lookup(rev2))
1890 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1890 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1891
1891
1892 @command('debugbuilddag',
1892 @command('debugbuilddag',
1893 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1893 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1894 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1894 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1895 ('n', 'new-file', None, _('add new file at each rev'))],
1895 ('n', 'new-file', None, _('add new file at each rev'))],
1896 _('[OPTION]... [TEXT]'))
1896 _('[OPTION]... [TEXT]'))
1897 def debugbuilddag(ui, repo, text=None,
1897 def debugbuilddag(ui, repo, text=None,
1898 mergeable_file=False,
1898 mergeable_file=False,
1899 overwritten_file=False,
1899 overwritten_file=False,
1900 new_file=False):
1900 new_file=False):
1901 """builds a repo with a given DAG from scratch in the current empty repo
1901 """builds a repo with a given DAG from scratch in the current empty repo
1902
1902
1903 The description of the DAG is read from stdin if not given on the
1903 The description of the DAG is read from stdin if not given on the
1904 command line.
1904 command line.
1905
1905
1906 Elements:
1906 Elements:
1907
1907
1908 - "+n" is a linear run of n nodes based on the current default parent
1908 - "+n" is a linear run of n nodes based on the current default parent
1909 - "." is a single node based on the current default parent
1909 - "." is a single node based on the current default parent
1910 - "$" resets the default parent to null (implied at the start);
1910 - "$" resets the default parent to null (implied at the start);
1911 otherwise the default parent is always the last node created
1911 otherwise the default parent is always the last node created
1912 - "<p" sets the default parent to the backref p
1912 - "<p" sets the default parent to the backref p
1913 - "*p" is a fork at parent p, which is a backref
1913 - "*p" is a fork at parent p, which is a backref
1914 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1914 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1915 - "/p2" is a merge of the preceding node and p2
1915 - "/p2" is a merge of the preceding node and p2
1916 - ":tag" defines a local tag for the preceding node
1916 - ":tag" defines a local tag for the preceding node
1917 - "@branch" sets the named branch for subsequent nodes
1917 - "@branch" sets the named branch for subsequent nodes
1918 - "#...\\n" is a comment up to the end of the line
1918 - "#...\\n" is a comment up to the end of the line
1919
1919
1920 Whitespace between the above elements is ignored.
1920 Whitespace between the above elements is ignored.
1921
1921
1922 A backref is either
1922 A backref is either
1923
1923
1924 - a number n, which references the node curr-n, where curr is the current
1924 - a number n, which references the node curr-n, where curr is the current
1925 node, or
1925 node, or
1926 - the name of a local tag you placed earlier using ":tag", or
1926 - the name of a local tag you placed earlier using ":tag", or
1927 - empty to denote the default parent.
1927 - empty to denote the default parent.
1928
1928
1929 All string valued-elements are either strictly alphanumeric, or must
1929 All string valued-elements are either strictly alphanumeric, or must
1930 be enclosed in double quotes ("..."), with "\\" as escape character.
1930 be enclosed in double quotes ("..."), with "\\" as escape character.
1931 """
1931 """
1932
1932
1933 if text is None:
1933 if text is None:
1934 ui.status(_("reading DAG from stdin\n"))
1934 ui.status(_("reading DAG from stdin\n"))
1935 text = ui.fin.read()
1935 text = ui.fin.read()
1936
1936
1937 cl = repo.changelog
1937 cl = repo.changelog
1938 if len(cl) > 0:
1938 if len(cl) > 0:
1939 raise error.Abort(_('repository is not empty'))
1939 raise error.Abort(_('repository is not empty'))
1940
1940
1941 # determine number of revs in DAG
1941 # determine number of revs in DAG
1942 total = 0
1942 total = 0
1943 for type, data in dagparser.parsedag(text):
1943 for type, data in dagparser.parsedag(text):
1944 if type == 'n':
1944 if type == 'n':
1945 total += 1
1945 total += 1
1946
1946
1947 if mergeable_file:
1947 if mergeable_file:
1948 linesperrev = 2
1948 linesperrev = 2
1949 # make a file with k lines per rev
1949 # make a file with k lines per rev
1950 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1950 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1951 initialmergedlines.append("")
1951 initialmergedlines.append("")
1952
1952
1953 tags = []
1953 tags = []
1954
1954
1955 wlock = lock = tr = None
1955 wlock = lock = tr = None
1956 try:
1956 try:
1957 wlock = repo.wlock()
1957 wlock = repo.wlock()
1958 lock = repo.lock()
1958 lock = repo.lock()
1959 tr = repo.transaction("builddag")
1959 tr = repo.transaction("builddag")
1960
1960
1961 at = -1
1961 at = -1
1962 atbranch = 'default'
1962 atbranch = 'default'
1963 nodeids = []
1963 nodeids = []
1964 id = 0
1964 id = 0
1965 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1965 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1966 for type, data in dagparser.parsedag(text):
1966 for type, data in dagparser.parsedag(text):
1967 if type == 'n':
1967 if type == 'n':
1968 ui.note(('node %s\n' % str(data)))
1968 ui.note(('node %s\n' % str(data)))
1969 id, ps = data
1969 id, ps = data
1970
1970
1971 files = []
1971 files = []
1972 fctxs = {}
1972 fctxs = {}
1973
1973
1974 p2 = None
1974 p2 = None
1975 if mergeable_file:
1975 if mergeable_file:
1976 fn = "mf"
1976 fn = "mf"
1977 p1 = repo[ps[0]]
1977 p1 = repo[ps[0]]
1978 if len(ps) > 1:
1978 if len(ps) > 1:
1979 p2 = repo[ps[1]]
1979 p2 = repo[ps[1]]
1980 pa = p1.ancestor(p2)
1980 pa = p1.ancestor(p2)
1981 base, local, other = [x[fn].data() for x in (pa, p1,
1981 base, local, other = [x[fn].data() for x in (pa, p1,
1982 p2)]
1982 p2)]
1983 m3 = simplemerge.Merge3Text(base, local, other)
1983 m3 = simplemerge.Merge3Text(base, local, other)
1984 ml = [l.strip() for l in m3.merge_lines()]
1984 ml = [l.strip() for l in m3.merge_lines()]
1985 ml.append("")
1985 ml.append("")
1986 elif at > 0:
1986 elif at > 0:
1987 ml = p1[fn].data().split("\n")
1987 ml = p1[fn].data().split("\n")
1988 else:
1988 else:
1989 ml = initialmergedlines
1989 ml = initialmergedlines
1990 ml[id * linesperrev] += " r%i" % id
1990 ml[id * linesperrev] += " r%i" % id
1991 mergedtext = "\n".join(ml)
1991 mergedtext = "\n".join(ml)
1992 files.append(fn)
1992 files.append(fn)
1993 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1993 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1994
1994
1995 if overwritten_file:
1995 if overwritten_file:
1996 fn = "of"
1996 fn = "of"
1997 files.append(fn)
1997 files.append(fn)
1998 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1998 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1999
1999
2000 if new_file:
2000 if new_file:
2001 fn = "nf%i" % id
2001 fn = "nf%i" % id
2002 files.append(fn)
2002 files.append(fn)
2003 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2003 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2004 if len(ps) > 1:
2004 if len(ps) > 1:
2005 if not p2:
2005 if not p2:
2006 p2 = repo[ps[1]]
2006 p2 = repo[ps[1]]
2007 for fn in p2:
2007 for fn in p2:
2008 if fn.startswith("nf"):
2008 if fn.startswith("nf"):
2009 files.append(fn)
2009 files.append(fn)
2010 fctxs[fn] = p2[fn]
2010 fctxs[fn] = p2[fn]
2011
2011
2012 def fctxfn(repo, cx, path):
2012 def fctxfn(repo, cx, path):
2013 return fctxs.get(path)
2013 return fctxs.get(path)
2014
2014
2015 if len(ps) == 0 or ps[0] < 0:
2015 if len(ps) == 0 or ps[0] < 0:
2016 pars = [None, None]
2016 pars = [None, None]
2017 elif len(ps) == 1:
2017 elif len(ps) == 1:
2018 pars = [nodeids[ps[0]], None]
2018 pars = [nodeids[ps[0]], None]
2019 else:
2019 else:
2020 pars = [nodeids[p] for p in ps]
2020 pars = [nodeids[p] for p in ps]
2021 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2021 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2022 date=(id, 0),
2022 date=(id, 0),
2023 user="debugbuilddag",
2023 user="debugbuilddag",
2024 extra={'branch': atbranch})
2024 extra={'branch': atbranch})
2025 nodeid = repo.commitctx(cx)
2025 nodeid = repo.commitctx(cx)
2026 nodeids.append(nodeid)
2026 nodeids.append(nodeid)
2027 at = id
2027 at = id
2028 elif type == 'l':
2028 elif type == 'l':
2029 id, name = data
2029 id, name = data
2030 ui.note(('tag %s\n' % name))
2030 ui.note(('tag %s\n' % name))
2031 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2031 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2032 elif type == 'a':
2032 elif type == 'a':
2033 ui.note(('branch %s\n' % data))
2033 ui.note(('branch %s\n' % data))
2034 atbranch = data
2034 atbranch = data
2035 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2035 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2036 tr.close()
2036 tr.close()
2037
2037
2038 if tags:
2038 if tags:
2039 repo.vfs.write("localtags", "".join(tags))
2039 repo.vfs.write("localtags", "".join(tags))
2040 finally:
2040 finally:
2041 ui.progress(_('building'), None)
2041 ui.progress(_('building'), None)
2042 release(tr, lock, wlock)
2042 release(tr, lock, wlock)
2043
2043
2044 @command('debugbundle',
2044 @command('debugbundle',
2045 [('a', 'all', None, _('show all details')),
2045 [('a', 'all', None, _('show all details')),
2046 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2046 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2047 _('FILE'),
2047 _('FILE'),
2048 norepo=True)
2048 norepo=True)
2049 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2049 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2050 """lists the contents of a bundle"""
2050 """lists the contents of a bundle"""
2051 with hg.openpath(ui, bundlepath) as f:
2051 with hg.openpath(ui, bundlepath) as f:
2052 if spec:
2052 if spec:
2053 spec = exchange.getbundlespec(ui, f)
2053 spec = exchange.getbundlespec(ui, f)
2054 ui.write('%s\n' % spec)
2054 ui.write('%s\n' % spec)
2055 return
2055 return
2056
2056
2057 gen = exchange.readbundle(ui, f, bundlepath)
2057 gen = exchange.readbundle(ui, f, bundlepath)
2058 if isinstance(gen, bundle2.unbundle20):
2058 if isinstance(gen, bundle2.unbundle20):
2059 return _debugbundle2(ui, gen, all=all, **opts)
2059 return _debugbundle2(ui, gen, all=all, **opts)
2060 _debugchangegroup(ui, gen, all=all, **opts)
2060 _debugchangegroup(ui, gen, all=all, **opts)
2061
2061
2062 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2062 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2063 indent_string = ' ' * indent
2063 indent_string = ' ' * indent
2064 if all:
2064 if all:
2065 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2065 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2066 % indent_string)
2066 % indent_string)
2067
2067
2068 def showchunks(named):
2068 def showchunks(named):
2069 ui.write("\n%s%s\n" % (indent_string, named))
2069 ui.write("\n%s%s\n" % (indent_string, named))
2070 chain = None
2070 chain = None
2071 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2071 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2072 node = chunkdata['node']
2072 node = chunkdata['node']
2073 p1 = chunkdata['p1']
2073 p1 = chunkdata['p1']
2074 p2 = chunkdata['p2']
2074 p2 = chunkdata['p2']
2075 cs = chunkdata['cs']
2075 cs = chunkdata['cs']
2076 deltabase = chunkdata['deltabase']
2076 deltabase = chunkdata['deltabase']
2077 delta = chunkdata['delta']
2077 delta = chunkdata['delta']
2078 ui.write("%s%s %s %s %s %s %s\n" %
2078 ui.write("%s%s %s %s %s %s %s\n" %
2079 (indent_string, hex(node), hex(p1), hex(p2),
2079 (indent_string, hex(node), hex(p1), hex(p2),
2080 hex(cs), hex(deltabase), len(delta)))
2080 hex(cs), hex(deltabase), len(delta)))
2081 chain = node
2081 chain = node
2082
2082
2083 chunkdata = gen.changelogheader()
2083 chunkdata = gen.changelogheader()
2084 showchunks("changelog")
2084 showchunks("changelog")
2085 chunkdata = gen.manifestheader()
2085 chunkdata = gen.manifestheader()
2086 showchunks("manifest")
2086 showchunks("manifest")
2087 for chunkdata in iter(gen.filelogheader, {}):
2087 for chunkdata in iter(gen.filelogheader, {}):
2088 fname = chunkdata['filename']
2088 fname = chunkdata['filename']
2089 showchunks(fname)
2089 showchunks(fname)
2090 else:
2090 else:
2091 if isinstance(gen, bundle2.unbundle20):
2091 if isinstance(gen, bundle2.unbundle20):
2092 raise error.Abort(_('use debugbundle2 for this file'))
2092 raise error.Abort(_('use debugbundle2 for this file'))
2093 chunkdata = gen.changelogheader()
2093 chunkdata = gen.changelogheader()
2094 chain = None
2094 chain = None
2095 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2095 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2096 node = chunkdata['node']
2096 node = chunkdata['node']
2097 ui.write("%s%s\n" % (indent_string, hex(node)))
2097 ui.write("%s%s\n" % (indent_string, hex(node)))
2098 chain = node
2098 chain = node
2099
2099
2100 def _debugbundle2(ui, gen, all=None, **opts):
2100 def _debugbundle2(ui, gen, all=None, **opts):
2101 """lists the contents of a bundle2"""
2101 """lists the contents of a bundle2"""
2102 if not isinstance(gen, bundle2.unbundle20):
2102 if not isinstance(gen, bundle2.unbundle20):
2103 raise error.Abort(_('not a bundle2 file'))
2103 raise error.Abort(_('not a bundle2 file'))
2104 ui.write(('Stream params: %s\n' % repr(gen.params)))
2104 ui.write(('Stream params: %s\n' % repr(gen.params)))
2105 for part in gen.iterparts():
2105 for part in gen.iterparts():
2106 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2106 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2107 if part.type == 'changegroup':
2107 if part.type == 'changegroup':
2108 version = part.params.get('version', '01')
2108 version = part.params.get('version', '01')
2109 cg = changegroup.getunbundler(version, part, 'UN')
2109 cg = changegroup.getunbundler(version, part, 'UN')
2110 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2110 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2111
2111
2112 @command('debugcreatestreamclonebundle', [], 'FILE')
2112 @command('debugcreatestreamclonebundle', [], 'FILE')
2113 def debugcreatestreamclonebundle(ui, repo, fname):
2113 def debugcreatestreamclonebundle(ui, repo, fname):
2114 """create a stream clone bundle file
2114 """create a stream clone bundle file
2115
2115
2116 Stream bundles are special bundles that are essentially archives of
2116 Stream bundles are special bundles that are essentially archives of
2117 revlog files. They are commonly used for cloning very quickly.
2117 revlog files. They are commonly used for cloning very quickly.
2118 """
2118 """
2119 requirements, gen = streamclone.generatebundlev1(repo)
2119 requirements, gen = streamclone.generatebundlev1(repo)
2120 changegroup.writechunks(ui, gen, fname)
2120 changegroup.writechunks(ui, gen, fname)
2121
2121
2122 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2122 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2123
2123
2124 @command('debugapplystreamclonebundle', [], 'FILE')
2124 @command('debugapplystreamclonebundle', [], 'FILE')
2125 def debugapplystreamclonebundle(ui, repo, fname):
2125 def debugapplystreamclonebundle(ui, repo, fname):
2126 """apply a stream clone bundle file"""
2126 """apply a stream clone bundle file"""
2127 f = hg.openpath(ui, fname)
2127 f = hg.openpath(ui, fname)
2128 gen = exchange.readbundle(ui, f, fname)
2128 gen = exchange.readbundle(ui, f, fname)
2129 gen.apply(repo)
2129 gen.apply(repo)
2130
2130
2131 @command('debugcheckstate', [], '')
2131 @command('debugcheckstate', [], '')
2132 def debugcheckstate(ui, repo):
2132 def debugcheckstate(ui, repo):
2133 """validate the correctness of the current dirstate"""
2133 """validate the correctness of the current dirstate"""
2134 parent1, parent2 = repo.dirstate.parents()
2134 parent1, parent2 = repo.dirstate.parents()
2135 m1 = repo[parent1].manifest()
2135 m1 = repo[parent1].manifest()
2136 m2 = repo[parent2].manifest()
2136 m2 = repo[parent2].manifest()
2137 errors = 0
2137 errors = 0
2138 for f in repo.dirstate:
2138 for f in repo.dirstate:
2139 state = repo.dirstate[f]
2139 state = repo.dirstate[f]
2140 if state in "nr" and f not in m1:
2140 if state in "nr" and f not in m1:
2141 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2141 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2142 errors += 1
2142 errors += 1
2143 if state in "a" and f in m1:
2143 if state in "a" and f in m1:
2144 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2144 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2145 errors += 1
2145 errors += 1
2146 if state in "m" and f not in m1 and f not in m2:
2146 if state in "m" and f not in m1 and f not in m2:
2147 ui.warn(_("%s in state %s, but not in either manifest\n") %
2147 ui.warn(_("%s in state %s, but not in either manifest\n") %
2148 (f, state))
2148 (f, state))
2149 errors += 1
2149 errors += 1
2150 for f in m1:
2150 for f in m1:
2151 state = repo.dirstate[f]
2151 state = repo.dirstate[f]
2152 if state not in "nrm":
2152 if state not in "nrm":
2153 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2153 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2154 errors += 1
2154 errors += 1
2155 if errors:
2155 if errors:
2156 error = _(".hg/dirstate inconsistent with current parent's manifest")
2156 error = _(".hg/dirstate inconsistent with current parent's manifest")
2157 raise error.Abort(error)
2157 raise error.Abort(error)
2158
2158
2159 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2159 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2160 def debugcommands(ui, cmd='', *args):
2160 def debugcommands(ui, cmd='', *args):
2161 """list all available commands and options"""
2161 """list all available commands and options"""
2162 for cmd, vals in sorted(table.iteritems()):
2162 for cmd, vals in sorted(table.iteritems()):
2163 cmd = cmd.split('|')[0].strip('^')
2163 cmd = cmd.split('|')[0].strip('^')
2164 opts = ', '.join([i[1] for i in vals[1]])
2164 opts = ', '.join([i[1] for i in vals[1]])
2165 ui.write('%s: %s\n' % (cmd, opts))
2165 ui.write('%s: %s\n' % (cmd, opts))
2166
2166
2167 @command('debugcomplete',
2167 @command('debugcomplete',
2168 [('o', 'options', None, _('show the command options'))],
2168 [('o', 'options', None, _('show the command options'))],
2169 _('[-o] CMD'),
2169 _('[-o] CMD'),
2170 norepo=True)
2170 norepo=True)
2171 def debugcomplete(ui, cmd='', **opts):
2171 def debugcomplete(ui, cmd='', **opts):
2172 """returns the completion list associated with the given command"""
2172 """returns the completion list associated with the given command"""
2173
2173
2174 if opts.get('options'):
2174 if opts.get('options'):
2175 options = []
2175 options = []
2176 otables = [globalopts]
2176 otables = [globalopts]
2177 if cmd:
2177 if cmd:
2178 aliases, entry = cmdutil.findcmd(cmd, table, False)
2178 aliases, entry = cmdutil.findcmd(cmd, table, False)
2179 otables.append(entry[1])
2179 otables.append(entry[1])
2180 for t in otables:
2180 for t in otables:
2181 for o in t:
2181 for o in t:
2182 if "(DEPRECATED)" in o[3]:
2182 if "(DEPRECATED)" in o[3]:
2183 continue
2183 continue
2184 if o[0]:
2184 if o[0]:
2185 options.append('-%s' % o[0])
2185 options.append('-%s' % o[0])
2186 options.append('--%s' % o[1])
2186 options.append('--%s' % o[1])
2187 ui.write("%s\n" % "\n".join(options))
2187 ui.write("%s\n" % "\n".join(options))
2188 return
2188 return
2189
2189
2190 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2190 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2191 if ui.verbose:
2191 if ui.verbose:
2192 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2192 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2193 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2193 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2194
2194
2195 @command('debugdag',
2195 @command('debugdag',
2196 [('t', 'tags', None, _('use tags as labels')),
2196 [('t', 'tags', None, _('use tags as labels')),
2197 ('b', 'branches', None, _('annotate with branch names')),
2197 ('b', 'branches', None, _('annotate with branch names')),
2198 ('', 'dots', None, _('use dots for runs')),
2198 ('', 'dots', None, _('use dots for runs')),
2199 ('s', 'spaces', None, _('separate elements by spaces'))],
2199 ('s', 'spaces', None, _('separate elements by spaces'))],
2200 _('[OPTION]... [FILE [REV]...]'),
2200 _('[OPTION]... [FILE [REV]...]'),
2201 optionalrepo=True)
2201 optionalrepo=True)
2202 def debugdag(ui, repo, file_=None, *revs, **opts):
2202 def debugdag(ui, repo, file_=None, *revs, **opts):
2203 """format the changelog or an index DAG as a concise textual description
2203 """format the changelog or an index DAG as a concise textual description
2204
2204
2205 If you pass a revlog index, the revlog's DAG is emitted. If you list
2205 If you pass a revlog index, the revlog's DAG is emitted. If you list
2206 revision numbers, they get labeled in the output as rN.
2206 revision numbers, they get labeled in the output as rN.
2207
2207
2208 Otherwise, the changelog DAG of the current repo is emitted.
2208 Otherwise, the changelog DAG of the current repo is emitted.
2209 """
2209 """
2210 spaces = opts.get('spaces')
2210 spaces = opts.get('spaces')
2211 dots = opts.get('dots')
2211 dots = opts.get('dots')
2212 if file_:
2212 if file_:
2213 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2213 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2214 revs = set((int(r) for r in revs))
2214 revs = set((int(r) for r in revs))
2215 def events():
2215 def events():
2216 for r in rlog:
2216 for r in rlog:
2217 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2217 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2218 if p != -1))
2218 if p != -1))
2219 if r in revs:
2219 if r in revs:
2220 yield 'l', (r, "r%i" % r)
2220 yield 'l', (r, "r%i" % r)
2221 elif repo:
2221 elif repo:
2222 cl = repo.changelog
2222 cl = repo.changelog
2223 tags = opts.get('tags')
2223 tags = opts.get('tags')
2224 branches = opts.get('branches')
2224 branches = opts.get('branches')
2225 if tags:
2225 if tags:
2226 labels = {}
2226 labels = {}
2227 for l, n in repo.tags().items():
2227 for l, n in repo.tags().items():
2228 labels.setdefault(cl.rev(n), []).append(l)
2228 labels.setdefault(cl.rev(n), []).append(l)
2229 def events():
2229 def events():
2230 b = "default"
2230 b = "default"
2231 for r in cl:
2231 for r in cl:
2232 if branches:
2232 if branches:
2233 newb = cl.read(cl.node(r))[5]['branch']
2233 newb = cl.read(cl.node(r))[5]['branch']
2234 if newb != b:
2234 if newb != b:
2235 yield 'a', newb
2235 yield 'a', newb
2236 b = newb
2236 b = newb
2237 yield 'n', (r, list(p for p in cl.parentrevs(r)
2237 yield 'n', (r, list(p for p in cl.parentrevs(r)
2238 if p != -1))
2238 if p != -1))
2239 if tags:
2239 if tags:
2240 ls = labels.get(r)
2240 ls = labels.get(r)
2241 if ls:
2241 if ls:
2242 for l in ls:
2242 for l in ls:
2243 yield 'l', (r, l)
2243 yield 'l', (r, l)
2244 else:
2244 else:
2245 raise error.Abort(_('need repo for changelog dag'))
2245 raise error.Abort(_('need repo for changelog dag'))
2246
2246
2247 for line in dagparser.dagtextlines(events(),
2247 for line in dagparser.dagtextlines(events(),
2248 addspaces=spaces,
2248 addspaces=spaces,
2249 wraplabels=True,
2249 wraplabels=True,
2250 wrapannotations=True,
2250 wrapannotations=True,
2251 wrapnonlinear=dots,
2251 wrapnonlinear=dots,
2252 usedots=dots,
2252 usedots=dots,
2253 maxlinewidth=70):
2253 maxlinewidth=70):
2254 ui.write(line)
2254 ui.write(line)
2255 ui.write("\n")
2255 ui.write("\n")
2256
2256
2257 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2257 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2258 def debugdata(ui, repo, file_, rev=None, **opts):
2258 def debugdata(ui, repo, file_, rev=None, **opts):
2259 """dump the contents of a data file revision"""
2259 """dump the contents of a data file revision"""
2260 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2260 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2261 if rev is not None:
2261 if rev is not None:
2262 raise error.CommandError('debugdata', _('invalid arguments'))
2262 raise error.CommandError('debugdata', _('invalid arguments'))
2263 file_, rev = None, file_
2263 file_, rev = None, file_
2264 elif rev is None:
2264 elif rev is None:
2265 raise error.CommandError('debugdata', _('invalid arguments'))
2265 raise error.CommandError('debugdata', _('invalid arguments'))
2266 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2266 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2267 try:
2267 try:
2268 ui.write(r.revision(r.lookup(rev)))
2268 ui.write(r.revision(r.lookup(rev)))
2269 except KeyError:
2269 except KeyError:
2270 raise error.Abort(_('invalid revision identifier %s') % rev)
2270 raise error.Abort(_('invalid revision identifier %s') % rev)
2271
2271
2272 @command('debugdate',
2272 @command('debugdate',
2273 [('e', 'extended', None, _('try extended date formats'))],
2273 [('e', 'extended', None, _('try extended date formats'))],
2274 _('[-e] DATE [RANGE]'),
2274 _('[-e] DATE [RANGE]'),
2275 norepo=True, optionalrepo=True)
2275 norepo=True, optionalrepo=True)
2276 def debugdate(ui, date, range=None, **opts):
2276 def debugdate(ui, date, range=None, **opts):
2277 """parse and display a date"""
2277 """parse and display a date"""
2278 if opts["extended"]:
2278 if opts["extended"]:
2279 d = util.parsedate(date, util.extendeddateformats)
2279 d = util.parsedate(date, util.extendeddateformats)
2280 else:
2280 else:
2281 d = util.parsedate(date)
2281 d = util.parsedate(date)
2282 ui.write(("internal: %s %s\n") % d)
2282 ui.write(("internal: %s %s\n") % d)
2283 ui.write(("standard: %s\n") % util.datestr(d))
2283 ui.write(("standard: %s\n") % util.datestr(d))
2284 if range:
2284 if range:
2285 m = util.matchdate(range)
2285 m = util.matchdate(range)
2286 ui.write(("match: %s\n") % m(d[0]))
2286 ui.write(("match: %s\n") % m(d[0]))
2287
2287
2288 @command('debugdiscovery',
2288 @command('debugdiscovery',
2289 [('', 'old', None, _('use old-style discovery')),
2289 [('', 'old', None, _('use old-style discovery')),
2290 ('', 'nonheads', None,
2290 ('', 'nonheads', None,
2291 _('use old-style discovery with non-heads included')),
2291 _('use old-style discovery with non-heads included')),
2292 ] + remoteopts,
2292 ] + remoteopts,
2293 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2293 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2294 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2294 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2295 """runs the changeset discovery protocol in isolation"""
2295 """runs the changeset discovery protocol in isolation"""
2296 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2296 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2297 opts.get('branch'))
2297 opts.get('branch'))
2298 remote = hg.peer(repo, opts, remoteurl)
2298 remote = hg.peer(repo, opts, remoteurl)
2299 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2299 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2300
2300
2301 # make sure tests are repeatable
2301 # make sure tests are repeatable
2302 random.seed(12323)
2302 random.seed(12323)
2303
2303
2304 def doit(localheads, remoteheads, remote=remote):
2304 def doit(localheads, remoteheads, remote=remote):
2305 if opts.get('old'):
2305 if opts.get('old'):
2306 if localheads:
2306 if localheads:
2307 raise error.Abort('cannot use localheads with old style '
2307 raise error.Abort('cannot use localheads with old style '
2308 'discovery')
2308 'discovery')
2309 if not util.safehasattr(remote, 'branches'):
2309 if not util.safehasattr(remote, 'branches'):
2310 # enable in-client legacy support
2310 # enable in-client legacy support
2311 remote = localrepo.locallegacypeer(remote.local())
2311 remote = localrepo.locallegacypeer(remote.local())
2312 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2312 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2313 force=True)
2313 force=True)
2314 common = set(common)
2314 common = set(common)
2315 if not opts.get('nonheads'):
2315 if not opts.get('nonheads'):
2316 ui.write(("unpruned common: %s\n") %
2316 ui.write(("unpruned common: %s\n") %
2317 " ".join(sorted(short(n) for n in common)))
2317 " ".join(sorted(short(n) for n in common)))
2318 dag = dagutil.revlogdag(repo.changelog)
2318 dag = dagutil.revlogdag(repo.changelog)
2319 all = dag.ancestorset(dag.internalizeall(common))
2319 all = dag.ancestorset(dag.internalizeall(common))
2320 common = dag.externalizeall(dag.headsetofconnecteds(all))
2320 common = dag.externalizeall(dag.headsetofconnecteds(all))
2321 else:
2321 else:
2322 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2322 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2323 common = set(common)
2323 common = set(common)
2324 rheads = set(hds)
2324 rheads = set(hds)
2325 lheads = set(repo.heads())
2325 lheads = set(repo.heads())
2326 ui.write(("common heads: %s\n") %
2326 ui.write(("common heads: %s\n") %
2327 " ".join(sorted(short(n) for n in common)))
2327 " ".join(sorted(short(n) for n in common)))
2328 if lheads <= common:
2328 if lheads <= common:
2329 ui.write(("local is subset\n"))
2329 ui.write(("local is subset\n"))
2330 elif rheads <= common:
2330 elif rheads <= common:
2331 ui.write(("remote is subset\n"))
2331 ui.write(("remote is subset\n"))
2332
2332
2333 serverlogs = opts.get('serverlog')
2333 serverlogs = opts.get('serverlog')
2334 if serverlogs:
2334 if serverlogs:
2335 for filename in serverlogs:
2335 for filename in serverlogs:
2336 with open(filename, 'r') as logfile:
2336 with open(filename, 'r') as logfile:
2337 line = logfile.readline()
2337 line = logfile.readline()
2338 while line:
2338 while line:
2339 parts = line.strip().split(';')
2339 parts = line.strip().split(';')
2340 op = parts[1]
2340 op = parts[1]
2341 if op == 'cg':
2341 if op == 'cg':
2342 pass
2342 pass
2343 elif op == 'cgss':
2343 elif op == 'cgss':
2344 doit(parts[2].split(' '), parts[3].split(' '))
2344 doit(parts[2].split(' '), parts[3].split(' '))
2345 elif op == 'unb':
2345 elif op == 'unb':
2346 doit(parts[3].split(' '), parts[2].split(' '))
2346 doit(parts[3].split(' '), parts[2].split(' '))
2347 line = logfile.readline()
2347 line = logfile.readline()
2348 else:
2348 else:
2349 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2349 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2350 opts.get('remote_head'))
2350 opts.get('remote_head'))
2351 localrevs = opts.get('local_head')
2351 localrevs = opts.get('local_head')
2352 doit(localrevs, remoterevs)
2352 doit(localrevs, remoterevs)
2353
2353
2354 @command('debugextensions', formatteropts, [], norepo=True)
2354 @command('debugextensions', formatteropts, [], norepo=True)
2355 def debugextensions(ui, **opts):
2355 def debugextensions(ui, **opts):
2356 '''show information about active extensions'''
2356 '''show information about active extensions'''
2357 exts = extensions.extensions(ui)
2357 exts = extensions.extensions(ui)
2358 hgver = util.version()
2358 hgver = util.version()
2359 fm = ui.formatter('debugextensions', opts)
2359 fm = ui.formatter('debugextensions', opts)
2360 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2360 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2361 isinternal = extensions.ismoduleinternal(extmod)
2361 isinternal = extensions.ismoduleinternal(extmod)
2362 extsource = extmod.__file__
2362 extsource = extmod.__file__
2363 if isinternal:
2363 if isinternal:
2364 exttestedwith = [] # never expose magic string to users
2364 exttestedwith = [] # never expose magic string to users
2365 else:
2365 else:
2366 exttestedwith = getattr(extmod, 'testedwith', '').split()
2366 exttestedwith = getattr(extmod, 'testedwith', '').split()
2367 extbuglink = getattr(extmod, 'buglink', None)
2367 extbuglink = getattr(extmod, 'buglink', None)
2368
2368
2369 fm.startitem()
2369 fm.startitem()
2370
2370
2371 if ui.quiet or ui.verbose:
2371 if ui.quiet or ui.verbose:
2372 fm.write('name', '%s\n', extname)
2372 fm.write('name', '%s\n', extname)
2373 else:
2373 else:
2374 fm.write('name', '%s', extname)
2374 fm.write('name', '%s', extname)
2375 if isinternal or hgver in exttestedwith:
2375 if isinternal or hgver in exttestedwith:
2376 fm.plain('\n')
2376 fm.plain('\n')
2377 elif not exttestedwith:
2377 elif not exttestedwith:
2378 fm.plain(_(' (untested!)\n'))
2378 fm.plain(_(' (untested!)\n'))
2379 else:
2379 else:
2380 lasttestedversion = exttestedwith[-1]
2380 lasttestedversion = exttestedwith[-1]
2381 fm.plain(' (%s!)\n' % lasttestedversion)
2381 fm.plain(' (%s!)\n' % lasttestedversion)
2382
2382
2383 fm.condwrite(ui.verbose and extsource, 'source',
2383 fm.condwrite(ui.verbose and extsource, 'source',
2384 _(' location: %s\n'), extsource or "")
2384 _(' location: %s\n'), extsource or "")
2385
2385
2386 if ui.verbose:
2386 if ui.verbose:
2387 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2387 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2388 fm.data(bundled=isinternal)
2388 fm.data(bundled=isinternal)
2389
2389
2390 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2390 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2391 _(' tested with: %s\n'),
2391 _(' tested with: %s\n'),
2392 fm.formatlist(exttestedwith, name='ver'))
2392 fm.formatlist(exttestedwith, name='ver'))
2393
2393
2394 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2394 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2395 _(' bug reporting: %s\n'), extbuglink or "")
2395 _(' bug reporting: %s\n'), extbuglink or "")
2396
2396
2397 fm.end()
2397 fm.end()
2398
2398
2399 @command('debugfileset',
2399 @command('debugfileset',
2400 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2400 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2401 _('[-r REV] FILESPEC'))
2401 _('[-r REV] FILESPEC'))
2402 def debugfileset(ui, repo, expr, **opts):
2402 def debugfileset(ui, repo, expr, **opts):
2403 '''parse and apply a fileset specification'''
2403 '''parse and apply a fileset specification'''
2404 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2404 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2405 if ui.verbose:
2405 if ui.verbose:
2406 tree = fileset.parse(expr)
2406 tree = fileset.parse(expr)
2407 ui.note(fileset.prettyformat(tree), "\n")
2407 ui.note(fileset.prettyformat(tree), "\n")
2408
2408
2409 for f in ctx.getfileset(expr):
2409 for f in ctx.getfileset(expr):
2410 ui.write("%s\n" % f)
2410 ui.write("%s\n" % f)
2411
2411
2412 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2412 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2413 def debugfsinfo(ui, path="."):
2413 def debugfsinfo(ui, path="."):
2414 """show information detected about current filesystem"""
2414 """show information detected about current filesystem"""
2415 util.writefile('.debugfsinfo', '')
2415 util.writefile('.debugfsinfo', '')
2416 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2416 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2417 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2417 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2418 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2418 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2419 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2419 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2420 and 'yes' or 'no'))
2420 and 'yes' or 'no'))
2421 os.unlink('.debugfsinfo')
2421 os.unlink('.debugfsinfo')
2422
2422
2423 @command('debuggetbundle',
2423 @command('debuggetbundle',
2424 [('H', 'head', [], _('id of head node'), _('ID')),
2424 [('H', 'head', [], _('id of head node'), _('ID')),
2425 ('C', 'common', [], _('id of common node'), _('ID')),
2425 ('C', 'common', [], _('id of common node'), _('ID')),
2426 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2426 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2427 _('REPO FILE [-H|-C ID]...'),
2427 _('REPO FILE [-H|-C ID]...'),
2428 norepo=True)
2428 norepo=True)
2429 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2429 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2430 """retrieves a bundle from a repo
2430 """retrieves a bundle from a repo
2431
2431
2432 Every ID must be a full-length hex node id string. Saves the bundle to the
2432 Every ID must be a full-length hex node id string. Saves the bundle to the
2433 given file.
2433 given file.
2434 """
2434 """
2435 repo = hg.peer(ui, opts, repopath)
2435 repo = hg.peer(ui, opts, repopath)
2436 if not repo.capable('getbundle'):
2436 if not repo.capable('getbundle'):
2437 raise error.Abort("getbundle() not supported by target repository")
2437 raise error.Abort("getbundle() not supported by target repository")
2438 args = {}
2438 args = {}
2439 if common:
2439 if common:
2440 args['common'] = [bin(s) for s in common]
2440 args['common'] = [bin(s) for s in common]
2441 if head:
2441 if head:
2442 args['heads'] = [bin(s) for s in head]
2442 args['heads'] = [bin(s) for s in head]
2443 # TODO: get desired bundlecaps from command line.
2443 # TODO: get desired bundlecaps from command line.
2444 args['bundlecaps'] = None
2444 args['bundlecaps'] = None
2445 bundle = repo.getbundle('debug', **args)
2445 bundle = repo.getbundle('debug', **args)
2446
2446
2447 bundletype = opts.get('type', 'bzip2').lower()
2447 bundletype = opts.get('type', 'bzip2').lower()
2448 btypes = {'none': 'HG10UN',
2448 btypes = {'none': 'HG10UN',
2449 'bzip2': 'HG10BZ',
2449 'bzip2': 'HG10BZ',
2450 'gzip': 'HG10GZ',
2450 'gzip': 'HG10GZ',
2451 'bundle2': 'HG20'}
2451 'bundle2': 'HG20'}
2452 bundletype = btypes.get(bundletype)
2452 bundletype = btypes.get(bundletype)
2453 if bundletype not in bundle2.bundletypes:
2453 if bundletype not in bundle2.bundletypes:
2454 raise error.Abort(_('unknown bundle type specified with --type'))
2454 raise error.Abort(_('unknown bundle type specified with --type'))
2455 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2455 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2456
2456
2457 @command('debugignore', [], '[FILE]')
2457 @command('debugignore', [], '[FILE]')
2458 def debugignore(ui, repo, *files, **opts):
2458 def debugignore(ui, repo, *files, **opts):
2459 """display the combined ignore pattern and information about ignored files
2459 """display the combined ignore pattern and information about ignored files
2460
2460
2461 With no argument display the combined ignore pattern.
2461 With no argument display the combined ignore pattern.
2462
2462
2463 Given space separated file names, shows if the given file is ignored and
2463 Given space separated file names, shows if the given file is ignored and
2464 if so, show the ignore rule (file and line number) that matched it.
2464 if so, show the ignore rule (file and line number) that matched it.
2465 """
2465 """
2466 ignore = repo.dirstate._ignore
2466 ignore = repo.dirstate._ignore
2467 if not files:
2467 if not files:
2468 # Show all the patterns
2468 # Show all the patterns
2469 includepat = getattr(ignore, 'includepat', None)
2469 includepat = getattr(ignore, 'includepat', None)
2470 if includepat is not None:
2470 if includepat is not None:
2471 ui.write("%s\n" % includepat)
2471 ui.write("%s\n" % includepat)
2472 else:
2472 else:
2473 raise error.Abort(_("no ignore patterns found"))
2473 raise error.Abort(_("no ignore patterns found"))
2474 else:
2474 else:
2475 for f in files:
2475 for f in files:
2476 nf = util.normpath(f)
2476 nf = util.normpath(f)
2477 ignored = None
2477 ignored = None
2478 ignoredata = None
2478 ignoredata = None
2479 if nf != '.':
2479 if nf != '.':
2480 if ignore(nf):
2480 if ignore(nf):
2481 ignored = nf
2481 ignored = nf
2482 ignoredata = repo.dirstate._ignorefileandline(nf)
2482 ignoredata = repo.dirstate._ignorefileandline(nf)
2483 else:
2483 else:
2484 for p in util.finddirs(nf):
2484 for p in util.finddirs(nf):
2485 if ignore(p):
2485 if ignore(p):
2486 ignored = p
2486 ignored = p
2487 ignoredata = repo.dirstate._ignorefileandline(p)
2487 ignoredata = repo.dirstate._ignorefileandline(p)
2488 break
2488 break
2489 if ignored:
2489 if ignored:
2490 if ignored == nf:
2490 if ignored == nf:
2491 ui.write(_("%s is ignored\n") % f)
2491 ui.write(_("%s is ignored\n") % f)
2492 else:
2492 else:
2493 ui.write(_("%s is ignored because of "
2493 ui.write(_("%s is ignored because of "
2494 "containing folder %s\n")
2494 "containing folder %s\n")
2495 % (f, ignored))
2495 % (f, ignored))
2496 ignorefile, lineno, line = ignoredata
2496 ignorefile, lineno, line = ignoredata
2497 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2497 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2498 % (ignorefile, lineno, line))
2498 % (ignorefile, lineno, line))
2499 else:
2499 else:
2500 ui.write(_("%s is not ignored\n") % f)
2500 ui.write(_("%s is not ignored\n") % f)
2501
2501
2502 @command('debugindex', debugrevlogopts +
2502 @command('debugindex', debugrevlogopts +
2503 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2503 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2504 _('[-f FORMAT] -c|-m|FILE'),
2504 _('[-f FORMAT] -c|-m|FILE'),
2505 optionalrepo=True)
2505 optionalrepo=True)
2506 def debugindex(ui, repo, file_=None, **opts):
2506 def debugindex(ui, repo, file_=None, **opts):
2507 """dump the contents of an index file"""
2507 """dump the contents of an index file"""
2508 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2508 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2509 format = opts.get('format', 0)
2509 format = opts.get('format', 0)
2510 if format not in (0, 1):
2510 if format not in (0, 1):
2511 raise error.Abort(_("unknown format %d") % format)
2511 raise error.Abort(_("unknown format %d") % format)
2512
2512
2513 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2513 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2514 if generaldelta:
2514 if generaldelta:
2515 basehdr = ' delta'
2515 basehdr = ' delta'
2516 else:
2516 else:
2517 basehdr = ' base'
2517 basehdr = ' base'
2518
2518
2519 if ui.debugflag:
2519 if ui.debugflag:
2520 shortfn = hex
2520 shortfn = hex
2521 else:
2521 else:
2522 shortfn = short
2522 shortfn = short
2523
2523
2524 # There might not be anything in r, so have a sane default
2524 # There might not be anything in r, so have a sane default
2525 idlen = 12
2525 idlen = 12
2526 for i in r:
2526 for i in r:
2527 idlen = len(shortfn(r.node(i)))
2527 idlen = len(shortfn(r.node(i)))
2528 break
2528 break
2529
2529
2530 if format == 0:
2530 if format == 0:
2531 ui.write((" rev offset length " + basehdr + " linkrev"
2531 ui.write((" rev offset length " + basehdr + " linkrev"
2532 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2532 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2533 elif format == 1:
2533 elif format == 1:
2534 ui.write((" rev flag offset length"
2534 ui.write((" rev flag offset length"
2535 " size " + basehdr + " link p1 p2"
2535 " size " + basehdr + " link p1 p2"
2536 " %s\n") % "nodeid".rjust(idlen))
2536 " %s\n") % "nodeid".rjust(idlen))
2537
2537
2538 for i in r:
2538 for i in r:
2539 node = r.node(i)
2539 node = r.node(i)
2540 if generaldelta:
2540 if generaldelta:
2541 base = r.deltaparent(i)
2541 base = r.deltaparent(i)
2542 else:
2542 else:
2543 base = r.chainbase(i)
2543 base = r.chainbase(i)
2544 if format == 0:
2544 if format == 0:
2545 try:
2545 try:
2546 pp = r.parents(node)
2546 pp = r.parents(node)
2547 except Exception:
2547 except Exception:
2548 pp = [nullid, nullid]
2548 pp = [nullid, nullid]
2549 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2549 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2550 i, r.start(i), r.length(i), base, r.linkrev(i),
2550 i, r.start(i), r.length(i), base, r.linkrev(i),
2551 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2551 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2552 elif format == 1:
2552 elif format == 1:
2553 pr = r.parentrevs(i)
2553 pr = r.parentrevs(i)
2554 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2554 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2555 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2555 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2556 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2556 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2557
2557
2558 @command('debugindexdot', debugrevlogopts,
2558 @command('debugindexdot', debugrevlogopts,
2559 _('-c|-m|FILE'), optionalrepo=True)
2559 _('-c|-m|FILE'), optionalrepo=True)
2560 def debugindexdot(ui, repo, file_=None, **opts):
2560 def debugindexdot(ui, repo, file_=None, **opts):
2561 """dump an index DAG as a graphviz dot file"""
2561 """dump an index DAG as a graphviz dot file"""
2562 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2562 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2563 ui.write(("digraph G {\n"))
2563 ui.write(("digraph G {\n"))
2564 for i in r:
2564 for i in r:
2565 node = r.node(i)
2565 node = r.node(i)
2566 pp = r.parents(node)
2566 pp = r.parents(node)
2567 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2567 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2568 if pp[1] != nullid:
2568 if pp[1] != nullid:
2569 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2569 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2570 ui.write("}\n")
2570 ui.write("}\n")
2571
2571
2572 @command('debugdeltachain',
2572 @command('debugdeltachain',
2573 debugrevlogopts + formatteropts,
2573 debugrevlogopts + formatteropts,
2574 _('-c|-m|FILE'),
2574 _('-c|-m|FILE'),
2575 optionalrepo=True)
2575 optionalrepo=True)
2576 def debugdeltachain(ui, repo, file_=None, **opts):
2576 def debugdeltachain(ui, repo, file_=None, **opts):
2577 """dump information about delta chains in a revlog
2577 """dump information about delta chains in a revlog
2578
2578
2579 Output can be templatized. Available template keywords are:
2579 Output can be templatized. Available template keywords are:
2580
2580
2581 :``rev``: revision number
2581 :``rev``: revision number
2582 :``chainid``: delta chain identifier (numbered by unique base)
2582 :``chainid``: delta chain identifier (numbered by unique base)
2583 :``chainlen``: delta chain length to this revision
2583 :``chainlen``: delta chain length to this revision
2584 :``prevrev``: previous revision in delta chain
2584 :``prevrev``: previous revision in delta chain
2585 :``deltatype``: role of delta / how it was computed
2585 :``deltatype``: role of delta / how it was computed
2586 :``compsize``: compressed size of revision
2586 :``compsize``: compressed size of revision
2587 :``uncompsize``: uncompressed size of revision
2587 :``uncompsize``: uncompressed size of revision
2588 :``chainsize``: total size of compressed revisions in chain
2588 :``chainsize``: total size of compressed revisions in chain
2589 :``chainratio``: total chain size divided by uncompressed revision size
2589 :``chainratio``: total chain size divided by uncompressed revision size
2590 (new delta chains typically start at ratio 2.00)
2590 (new delta chains typically start at ratio 2.00)
2591 :``lindist``: linear distance from base revision in delta chain to end
2591 :``lindist``: linear distance from base revision in delta chain to end
2592 of this revision
2592 of this revision
2593 :``extradist``: total size of revisions not part of this delta chain from
2593 :``extradist``: total size of revisions not part of this delta chain from
2594 base of delta chain to end of this revision; a measurement
2594 base of delta chain to end of this revision; a measurement
2595 of how much extra data we need to read/seek across to read
2595 of how much extra data we need to read/seek across to read
2596 the delta chain for this revision
2596 the delta chain for this revision
2597 :``extraratio``: extradist divided by chainsize; another representation of
2597 :``extraratio``: extradist divided by chainsize; another representation of
2598 how much unrelated data is needed to load this delta chain
2598 how much unrelated data is needed to load this delta chain
2599 """
2599 """
2600 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2600 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2601 index = r.index
2601 index = r.index
2602 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2602 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2603
2603
2604 def revinfo(rev):
2604 def revinfo(rev):
2605 e = index[rev]
2605 e = index[rev]
2606 compsize = e[1]
2606 compsize = e[1]
2607 uncompsize = e[2]
2607 uncompsize = e[2]
2608 chainsize = 0
2608 chainsize = 0
2609
2609
2610 if generaldelta:
2610 if generaldelta:
2611 if e[3] == e[5]:
2611 if e[3] == e[5]:
2612 deltatype = 'p1'
2612 deltatype = 'p1'
2613 elif e[3] == e[6]:
2613 elif e[3] == e[6]:
2614 deltatype = 'p2'
2614 deltatype = 'p2'
2615 elif e[3] == rev - 1:
2615 elif e[3] == rev - 1:
2616 deltatype = 'prev'
2616 deltatype = 'prev'
2617 elif e[3] == rev:
2617 elif e[3] == rev:
2618 deltatype = 'base'
2618 deltatype = 'base'
2619 else:
2619 else:
2620 deltatype = 'other'
2620 deltatype = 'other'
2621 else:
2621 else:
2622 if e[3] == rev:
2622 if e[3] == rev:
2623 deltatype = 'base'
2623 deltatype = 'base'
2624 else:
2624 else:
2625 deltatype = 'prev'
2625 deltatype = 'prev'
2626
2626
2627 chain = r._deltachain(rev)[0]
2627 chain = r._deltachain(rev)[0]
2628 for iterrev in chain:
2628 for iterrev in chain:
2629 e = index[iterrev]
2629 e = index[iterrev]
2630 chainsize += e[1]
2630 chainsize += e[1]
2631
2631
2632 return compsize, uncompsize, deltatype, chain, chainsize
2632 return compsize, uncompsize, deltatype, chain, chainsize
2633
2633
2634 fm = ui.formatter('debugdeltachain', opts)
2634 fm = ui.formatter('debugdeltachain', opts)
2635
2635
2636 fm.plain(' rev chain# chainlen prev delta '
2636 fm.plain(' rev chain# chainlen prev delta '
2637 'size rawsize chainsize ratio lindist extradist '
2637 'size rawsize chainsize ratio lindist extradist '
2638 'extraratio\n')
2638 'extraratio\n')
2639
2639
2640 chainbases = {}
2640 chainbases = {}
2641 for rev in r:
2641 for rev in r:
2642 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2642 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2643 chainbase = chain[0]
2643 chainbase = chain[0]
2644 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2644 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2645 basestart = r.start(chainbase)
2645 basestart = r.start(chainbase)
2646 revstart = r.start(rev)
2646 revstart = r.start(rev)
2647 lineardist = revstart + comp - basestart
2647 lineardist = revstart + comp - basestart
2648 extradist = lineardist - chainsize
2648 extradist = lineardist - chainsize
2649 try:
2649 try:
2650 prevrev = chain[-2]
2650 prevrev = chain[-2]
2651 except IndexError:
2651 except IndexError:
2652 prevrev = -1
2652 prevrev = -1
2653
2653
2654 chainratio = float(chainsize) / float(uncomp)
2654 chainratio = float(chainsize) / float(uncomp)
2655 extraratio = float(extradist) / float(chainsize)
2655 extraratio = float(extradist) / float(chainsize)
2656
2656
2657 fm.startitem()
2657 fm.startitem()
2658 fm.write('rev chainid chainlen prevrev deltatype compsize '
2658 fm.write('rev chainid chainlen prevrev deltatype compsize '
2659 'uncompsize chainsize chainratio lindist extradist '
2659 'uncompsize chainsize chainratio lindist extradist '
2660 'extraratio',
2660 'extraratio',
2661 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2661 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2662 rev, chainid, len(chain), prevrev, deltatype, comp,
2662 rev, chainid, len(chain), prevrev, deltatype, comp,
2663 uncomp, chainsize, chainratio, lineardist, extradist,
2663 uncomp, chainsize, chainratio, lineardist, extradist,
2664 extraratio,
2664 extraratio,
2665 rev=rev, chainid=chainid, chainlen=len(chain),
2665 rev=rev, chainid=chainid, chainlen=len(chain),
2666 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2666 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2667 uncompsize=uncomp, chainsize=chainsize,
2667 uncompsize=uncomp, chainsize=chainsize,
2668 chainratio=chainratio, lindist=lineardist,
2668 chainratio=chainratio, lindist=lineardist,
2669 extradist=extradist, extraratio=extraratio)
2669 extradist=extradist, extraratio=extraratio)
2670
2670
2671 fm.end()
2671 fm.end()
2672
2672
2673 @command('debuginstall', [] + formatteropts, '', norepo=True)
2673 @command('debuginstall', [] + formatteropts, '', norepo=True)
2674 def debuginstall(ui, **opts):
2674 def debuginstall(ui, **opts):
2675 '''test Mercurial installation
2675 '''test Mercurial installation
2676
2676
2677 Returns 0 on success.
2677 Returns 0 on success.
2678 '''
2678 '''
2679
2679
2680 def writetemp(contents):
2680 def writetemp(contents):
2681 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2681 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2682 f = os.fdopen(fd, "wb")
2682 f = os.fdopen(fd, "wb")
2683 f.write(contents)
2683 f.write(contents)
2684 f.close()
2684 f.close()
2685 return name
2685 return name
2686
2686
2687 problems = 0
2687 problems = 0
2688
2688
2689 fm = ui.formatter('debuginstall', opts)
2689 fm = ui.formatter('debuginstall', opts)
2690 fm.startitem()
2690 fm.startitem()
2691
2691
2692 # encoding
2692 # encoding
2693 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2693 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2694 err = None
2694 err = None
2695 try:
2695 try:
2696 encoding.fromlocal("test")
2696 encoding.fromlocal("test")
2697 except error.Abort as inst:
2697 except error.Abort as inst:
2698 err = inst
2698 err = inst
2699 problems += 1
2699 problems += 1
2700 fm.condwrite(err, 'encodingerror', _(" %s\n"
2700 fm.condwrite(err, 'encodingerror', _(" %s\n"
2701 " (check that your locale is properly set)\n"), err)
2701 " (check that your locale is properly set)\n"), err)
2702
2702
2703 # Python
2703 # Python
2704 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2704 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2705 sys.executable)
2705 sys.executable)
2706 fm.write('pythonver', _("checking Python version (%s)\n"),
2706 fm.write('pythonver', _("checking Python version (%s)\n"),
2707 ("%s.%s.%s" % sys.version_info[:3]))
2707 ("%s.%s.%s" % sys.version_info[:3]))
2708 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2708 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2709 os.path.dirname(os.__file__))
2709 os.path.dirname(os.__file__))
2710
2710
2711 # hg version
2711 # hg version
2712 hgver = util.version()
2712 hgver = util.version()
2713 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2713 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2714 hgver.split('+')[0])
2714 hgver.split('+')[0])
2715 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2715 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2716 '+'.join(hgver.split('+')[1:]))
2716 '+'.join(hgver.split('+')[1:]))
2717
2717
2718 # compiled modules
2718 # compiled modules
2719 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2719 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2720 policy.policy)
2720 policy.policy)
2721 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2721 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2722 os.path.dirname(__file__))
2722 os.path.dirname(__file__))
2723
2723
2724 err = None
2724 err = None
2725 try:
2725 try:
2726 from . import (
2726 from . import (
2727 base85,
2727 base85,
2728 bdiff,
2728 bdiff,
2729 mpatch,
2729 mpatch,
2730 osutil,
2730 osutil,
2731 )
2731 )
2732 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2732 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2733 except Exception as inst:
2733 except Exception as inst:
2734 err = inst
2734 err = inst
2735 problems += 1
2735 problems += 1
2736 fm.condwrite(err, 'extensionserror', " %s\n", err)
2736 fm.condwrite(err, 'extensionserror', " %s\n", err)
2737
2737
2738 # templates
2738 # templates
2739 p = templater.templatepaths()
2739 p = templater.templatepaths()
2740 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2740 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2741 fm.condwrite(not p, '', _(" no template directories found\n"))
2741 fm.condwrite(not p, '', _(" no template directories found\n"))
2742 if p:
2742 if p:
2743 m = templater.templatepath("map-cmdline.default")
2743 m = templater.templatepath("map-cmdline.default")
2744 if m:
2744 if m:
2745 # template found, check if it is working
2745 # template found, check if it is working
2746 err = None
2746 err = None
2747 try:
2747 try:
2748 templater.templater.frommapfile(m)
2748 templater.templater.frommapfile(m)
2749 except Exception as inst:
2749 except Exception as inst:
2750 err = inst
2750 err = inst
2751 p = None
2751 p = None
2752 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2752 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2753 else:
2753 else:
2754 p = None
2754 p = None
2755 fm.condwrite(p, 'defaulttemplate',
2755 fm.condwrite(p, 'defaulttemplate',
2756 _("checking default template (%s)\n"), m)
2756 _("checking default template (%s)\n"), m)
2757 fm.condwrite(not m, 'defaulttemplatenotfound',
2757 fm.condwrite(not m, 'defaulttemplatenotfound',
2758 _(" template '%s' not found\n"), "default")
2758 _(" template '%s' not found\n"), "default")
2759 if not p:
2759 if not p:
2760 problems += 1
2760 problems += 1
2761 fm.condwrite(not p, '',
2761 fm.condwrite(not p, '',
2762 _(" (templates seem to have been installed incorrectly)\n"))
2762 _(" (templates seem to have been installed incorrectly)\n"))
2763
2763
2764 # editor
2764 # editor
2765 editor = ui.geteditor()
2765 editor = ui.geteditor()
2766 editor = util.expandpath(editor)
2766 editor = util.expandpath(editor)
2767 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2767 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2768 cmdpath = util.findexe(shlex.split(editor)[0])
2768 cmdpath = util.findexe(shlex.split(editor)[0])
2769 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2769 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2770 _(" No commit editor set and can't find %s in PATH\n"
2770 _(" No commit editor set and can't find %s in PATH\n"
2771 " (specify a commit editor in your configuration"
2771 " (specify a commit editor in your configuration"
2772 " file)\n"), not cmdpath and editor == 'vi' and editor)
2772 " file)\n"), not cmdpath and editor == 'vi' and editor)
2773 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2773 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2774 _(" Can't find editor '%s' in PATH\n"
2774 _(" Can't find editor '%s' in PATH\n"
2775 " (specify a commit editor in your configuration"
2775 " (specify a commit editor in your configuration"
2776 " file)\n"), not cmdpath and editor)
2776 " file)\n"), not cmdpath and editor)
2777 if not cmdpath and editor != 'vi':
2777 if not cmdpath and editor != 'vi':
2778 problems += 1
2778 problems += 1
2779
2779
2780 # check username
2780 # check username
2781 username = None
2781 username = None
2782 err = None
2782 err = None
2783 try:
2783 try:
2784 username = ui.username()
2784 username = ui.username()
2785 except error.Abort as e:
2785 except error.Abort as e:
2786 err = e
2786 err = e
2787 problems += 1
2787 problems += 1
2788
2788
2789 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2789 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2790 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2790 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2791 " (specify a username in your configuration file)\n"), err)
2791 " (specify a username in your configuration file)\n"), err)
2792
2792
2793 fm.condwrite(not problems, '',
2793 fm.condwrite(not problems, '',
2794 _("no problems detected\n"))
2794 _("no problems detected\n"))
2795 if not problems:
2795 if not problems:
2796 fm.data(problems=problems)
2796 fm.data(problems=problems)
2797 fm.condwrite(problems, 'problems',
2797 fm.condwrite(problems, 'problems',
2798 _("%s problems detected,"
2798 _("%s problems detected,"
2799 " please check your install!\n"), problems)
2799 " please check your install!\n"), problems)
2800 fm.end()
2800 fm.end()
2801
2801
2802 return problems
2802 return problems
2803
2803
2804 @command('debugknown', [], _('REPO ID...'), norepo=True)
2804 @command('debugknown', [], _('REPO ID...'), norepo=True)
2805 def debugknown(ui, repopath, *ids, **opts):
2805 def debugknown(ui, repopath, *ids, **opts):
2806 """test whether node ids are known to a repo
2806 """test whether node ids are known to a repo
2807
2807
2808 Every ID must be a full-length hex node id string. Returns a list of 0s
2808 Every ID must be a full-length hex node id string. Returns a list of 0s
2809 and 1s indicating unknown/known.
2809 and 1s indicating unknown/known.
2810 """
2810 """
2811 repo = hg.peer(ui, opts, repopath)
2811 repo = hg.peer(ui, opts, repopath)
2812 if not repo.capable('known'):
2812 if not repo.capable('known'):
2813 raise error.Abort("known() not supported by target repository")
2813 raise error.Abort("known() not supported by target repository")
2814 flags = repo.known([bin(s) for s in ids])
2814 flags = repo.known([bin(s) for s in ids])
2815 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2815 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2816
2816
2817 @command('debuglabelcomplete', [], _('LABEL...'))
2817 @command('debuglabelcomplete', [], _('LABEL...'))
2818 def debuglabelcomplete(ui, repo, *args):
2818 def debuglabelcomplete(ui, repo, *args):
2819 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2819 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2820 debugnamecomplete(ui, repo, *args)
2820 debugnamecomplete(ui, repo, *args)
2821
2821
2822 @command('debugmergestate', [], '')
2822 @command('debugmergestate', [], '')
2823 def debugmergestate(ui, repo, *args):
2823 def debugmergestate(ui, repo, *args):
2824 """print merge state
2824 """print merge state
2825
2825
2826 Use --verbose to print out information about whether v1 or v2 merge state
2826 Use --verbose to print out information about whether v1 or v2 merge state
2827 was chosen."""
2827 was chosen."""
2828 def _hashornull(h):
2828 def _hashornull(h):
2829 if h == nullhex:
2829 if h == nullhex:
2830 return 'null'
2830 return 'null'
2831 else:
2831 else:
2832 return h
2832 return h
2833
2833
2834 def printrecords(version):
2834 def printrecords(version):
2835 ui.write(('* version %s records\n') % version)
2835 ui.write(('* version %s records\n') % version)
2836 if version == 1:
2836 if version == 1:
2837 records = v1records
2837 records = v1records
2838 else:
2838 else:
2839 records = v2records
2839 records = v2records
2840
2840
2841 for rtype, record in records:
2841 for rtype, record in records:
2842 # pretty print some record types
2842 # pretty print some record types
2843 if rtype == 'L':
2843 if rtype == 'L':
2844 ui.write(('local: %s\n') % record)
2844 ui.write(('local: %s\n') % record)
2845 elif rtype == 'O':
2845 elif rtype == 'O':
2846 ui.write(('other: %s\n') % record)
2846 ui.write(('other: %s\n') % record)
2847 elif rtype == 'm':
2847 elif rtype == 'm':
2848 driver, mdstate = record.split('\0', 1)
2848 driver, mdstate = record.split('\0', 1)
2849 ui.write(('merge driver: %s (state "%s")\n')
2849 ui.write(('merge driver: %s (state "%s")\n')
2850 % (driver, mdstate))
2850 % (driver, mdstate))
2851 elif rtype in 'FDC':
2851 elif rtype in 'FDC':
2852 r = record.split('\0')
2852 r = record.split('\0')
2853 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2853 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2854 if version == 1:
2854 if version == 1:
2855 onode = 'not stored in v1 format'
2855 onode = 'not stored in v1 format'
2856 flags = r[7]
2856 flags = r[7]
2857 else:
2857 else:
2858 onode, flags = r[7:9]
2858 onode, flags = r[7:9]
2859 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2859 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2860 % (f, rtype, state, _hashornull(hash)))
2860 % (f, rtype, state, _hashornull(hash)))
2861 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2861 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2862 ui.write((' ancestor path: %s (node %s)\n')
2862 ui.write((' ancestor path: %s (node %s)\n')
2863 % (afile, _hashornull(anode)))
2863 % (afile, _hashornull(anode)))
2864 ui.write((' other path: %s (node %s)\n')
2864 ui.write((' other path: %s (node %s)\n')
2865 % (ofile, _hashornull(onode)))
2865 % (ofile, _hashornull(onode)))
2866 elif rtype == 'f':
2866 elif rtype == 'f':
2867 filename, rawextras = record.split('\0', 1)
2867 filename, rawextras = record.split('\0', 1)
2868 extras = rawextras.split('\0')
2868 extras = rawextras.split('\0')
2869 i = 0
2869 i = 0
2870 extrastrings = []
2870 extrastrings = []
2871 while i < len(extras):
2871 while i < len(extras):
2872 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2872 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2873 i += 2
2873 i += 2
2874
2874
2875 ui.write(('file extras: %s (%s)\n')
2875 ui.write(('file extras: %s (%s)\n')
2876 % (filename, ', '.join(extrastrings)))
2876 % (filename, ', '.join(extrastrings)))
2877 elif rtype == 'l':
2877 elif rtype == 'l':
2878 labels = record.split('\0', 2)
2878 labels = record.split('\0', 2)
2879 labels = [l for l in labels if len(l) > 0]
2879 labels = [l for l in labels if len(l) > 0]
2880 ui.write(('labels:\n'))
2880 ui.write(('labels:\n'))
2881 ui.write((' local: %s\n' % labels[0]))
2881 ui.write((' local: %s\n' % labels[0]))
2882 ui.write((' other: %s\n' % labels[1]))
2882 ui.write((' other: %s\n' % labels[1]))
2883 if len(labels) > 2:
2883 if len(labels) > 2:
2884 ui.write((' base: %s\n' % labels[2]))
2884 ui.write((' base: %s\n' % labels[2]))
2885 else:
2885 else:
2886 ui.write(('unrecognized entry: %s\t%s\n')
2886 ui.write(('unrecognized entry: %s\t%s\n')
2887 % (rtype, record.replace('\0', '\t')))
2887 % (rtype, record.replace('\0', '\t')))
2888
2888
2889 # Avoid mergestate.read() since it may raise an exception for unsupported
2889 # Avoid mergestate.read() since it may raise an exception for unsupported
2890 # merge state records. We shouldn't be doing this, but this is OK since this
2890 # merge state records. We shouldn't be doing this, but this is OK since this
2891 # command is pretty low-level.
2891 # command is pretty low-level.
2892 ms = mergemod.mergestate(repo)
2892 ms = mergemod.mergestate(repo)
2893
2893
2894 # sort so that reasonable information is on top
2894 # sort so that reasonable information is on top
2895 v1records = ms._readrecordsv1()
2895 v1records = ms._readrecordsv1()
2896 v2records = ms._readrecordsv2()
2896 v2records = ms._readrecordsv2()
2897 order = 'LOml'
2897 order = 'LOml'
2898 def key(r):
2898 def key(r):
2899 idx = order.find(r[0])
2899 idx = order.find(r[0])
2900 if idx == -1:
2900 if idx == -1:
2901 return (1, r[1])
2901 return (1, r[1])
2902 else:
2902 else:
2903 return (0, idx)
2903 return (0, idx)
2904 v1records.sort(key=key)
2904 v1records.sort(key=key)
2905 v2records.sort(key=key)
2905 v2records.sort(key=key)
2906
2906
2907 if not v1records and not v2records:
2907 if not v1records and not v2records:
2908 ui.write(('no merge state found\n'))
2908 ui.write(('no merge state found\n'))
2909 elif not v2records:
2909 elif not v2records:
2910 ui.note(('no version 2 merge state\n'))
2910 ui.note(('no version 2 merge state\n'))
2911 printrecords(1)
2911 printrecords(1)
2912 elif ms._v1v2match(v1records, v2records):
2912 elif ms._v1v2match(v1records, v2records):
2913 ui.note(('v1 and v2 states match: using v2\n'))
2913 ui.note(('v1 and v2 states match: using v2\n'))
2914 printrecords(2)
2914 printrecords(2)
2915 else:
2915 else:
2916 ui.note(('v1 and v2 states mismatch: using v1\n'))
2916 ui.note(('v1 and v2 states mismatch: using v1\n'))
2917 printrecords(1)
2917 printrecords(1)
2918 if ui.verbose:
2918 if ui.verbose:
2919 printrecords(2)
2919 printrecords(2)
2920
2920
2921 @command('debugnamecomplete', [], _('NAME...'))
2921 @command('debugnamecomplete', [], _('NAME...'))
2922 def debugnamecomplete(ui, repo, *args):
2922 def debugnamecomplete(ui, repo, *args):
2923 '''complete "names" - tags, open branch names, bookmark names'''
2923 '''complete "names" - tags, open branch names, bookmark names'''
2924
2924
2925 names = set()
2925 names = set()
2926 # since we previously only listed open branches, we will handle that
2926 # since we previously only listed open branches, we will handle that
2927 # specially (after this for loop)
2927 # specially (after this for loop)
2928 for name, ns in repo.names.iteritems():
2928 for name, ns in repo.names.iteritems():
2929 if name != 'branches':
2929 if name != 'branches':
2930 names.update(ns.listnames(repo))
2930 names.update(ns.listnames(repo))
2931 names.update(tag for (tag, heads, tip, closed)
2931 names.update(tag for (tag, heads, tip, closed)
2932 in repo.branchmap().iterbranches() if not closed)
2932 in repo.branchmap().iterbranches() if not closed)
2933 completions = set()
2933 completions = set()
2934 if not args:
2934 if not args:
2935 args = ['']
2935 args = ['']
2936 for a in args:
2936 for a in args:
2937 completions.update(n for n in names if n.startswith(a))
2937 completions.update(n for n in names if n.startswith(a))
2938 ui.write('\n'.join(sorted(completions)))
2938 ui.write('\n'.join(sorted(completions)))
2939 ui.write('\n')
2939 ui.write('\n')
2940
2940
2941 @command('debuglocks',
2941 @command('debuglocks',
2942 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2942 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2943 ('W', 'force-wlock', None,
2943 ('W', 'force-wlock', None,
2944 _('free the working state lock (DANGEROUS)'))],
2944 _('free the working state lock (DANGEROUS)'))],
2945 _('[OPTION]...'))
2945 _('[OPTION]...'))
2946 def debuglocks(ui, repo, **opts):
2946 def debuglocks(ui, repo, **opts):
2947 """show or modify state of locks
2947 """show or modify state of locks
2948
2948
2949 By default, this command will show which locks are held. This
2949 By default, this command will show which locks are held. This
2950 includes the user and process holding the lock, the amount of time
2950 includes the user and process holding the lock, the amount of time
2951 the lock has been held, and the machine name where the process is
2951 the lock has been held, and the machine name where the process is
2952 running if it's not local.
2952 running if it's not local.
2953
2953
2954 Locks protect the integrity of Mercurial's data, so should be
2954 Locks protect the integrity of Mercurial's data, so should be
2955 treated with care. System crashes or other interruptions may cause
2955 treated with care. System crashes or other interruptions may cause
2956 locks to not be properly released, though Mercurial will usually
2956 locks to not be properly released, though Mercurial will usually
2957 detect and remove such stale locks automatically.
2957 detect and remove such stale locks automatically.
2958
2958
2959 However, detecting stale locks may not always be possible (for
2959 However, detecting stale locks may not always be possible (for
2960 instance, on a shared filesystem). Removing locks may also be
2960 instance, on a shared filesystem). Removing locks may also be
2961 blocked by filesystem permissions.
2961 blocked by filesystem permissions.
2962
2962
2963 Returns 0 if no locks are held.
2963 Returns 0 if no locks are held.
2964
2964
2965 """
2965 """
2966
2966
2967 if opts.get('force_lock'):
2967 if opts.get('force_lock'):
2968 repo.svfs.unlink('lock')
2968 repo.svfs.unlink('lock')
2969 if opts.get('force_wlock'):
2969 if opts.get('force_wlock'):
2970 repo.vfs.unlink('wlock')
2970 repo.vfs.unlink('wlock')
2971 if opts.get('force_lock') or opts.get('force_lock'):
2971 if opts.get('force_lock') or opts.get('force_lock'):
2972 return 0
2972 return 0
2973
2973
2974 now = time.time()
2974 now = time.time()
2975 held = 0
2975 held = 0
2976
2976
2977 def report(vfs, name, method):
2977 def report(vfs, name, method):
2978 # this causes stale locks to get reaped for more accurate reporting
2978 # this causes stale locks to get reaped for more accurate reporting
2979 try:
2979 try:
2980 l = method(False)
2980 l = method(False)
2981 except error.LockHeld:
2981 except error.LockHeld:
2982 l = None
2982 l = None
2983
2983
2984 if l:
2984 if l:
2985 l.release()
2985 l.release()
2986 else:
2986 else:
2987 try:
2987 try:
2988 stat = vfs.lstat(name)
2988 stat = vfs.lstat(name)
2989 age = now - stat.st_mtime
2989 age = now - stat.st_mtime
2990 user = util.username(stat.st_uid)
2990 user = util.username(stat.st_uid)
2991 locker = vfs.readlock(name)
2991 locker = vfs.readlock(name)
2992 if ":" in locker:
2992 if ":" in locker:
2993 host, pid = locker.split(':')
2993 host, pid = locker.split(':')
2994 if host == socket.gethostname():
2994 if host == socket.gethostname():
2995 locker = 'user %s, process %s' % (user, pid)
2995 locker = 'user %s, process %s' % (user, pid)
2996 else:
2996 else:
2997 locker = 'user %s, process %s, host %s' \
2997 locker = 'user %s, process %s, host %s' \
2998 % (user, pid, host)
2998 % (user, pid, host)
2999 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2999 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3000 return 1
3000 return 1
3001 except OSError as e:
3001 except OSError as e:
3002 if e.errno != errno.ENOENT:
3002 if e.errno != errno.ENOENT:
3003 raise
3003 raise
3004
3004
3005 ui.write(("%-6s free\n") % (name + ":"))
3005 ui.write(("%-6s free\n") % (name + ":"))
3006 return 0
3006 return 0
3007
3007
3008 held += report(repo.svfs, "lock", repo.lock)
3008 held += report(repo.svfs, "lock", repo.lock)
3009 held += report(repo.vfs, "wlock", repo.wlock)
3009 held += report(repo.vfs, "wlock", repo.wlock)
3010
3010
3011 return held
3011 return held
3012
3012
3013 @command('debugobsolete',
3013 @command('debugobsolete',
3014 [('', 'flags', 0, _('markers flag')),
3014 [('', 'flags', 0, _('markers flag')),
3015 ('', 'record-parents', False,
3015 ('', 'record-parents', False,
3016 _('record parent information for the precursor')),
3016 _('record parent information for the precursor')),
3017 ('r', 'rev', [], _('display markers relevant to REV')),
3017 ('r', 'rev', [], _('display markers relevant to REV')),
3018 ('', 'index', False, _('display index of the marker')),
3018 ('', 'index', False, _('display index of the marker')),
3019 ('', 'delete', [], _('delete markers specified by indices')),
3019 ('', 'delete', [], _('delete markers specified by indices')),
3020 ] + commitopts2 + formatteropts,
3020 ] + commitopts2 + formatteropts,
3021 _('[OBSOLETED [REPLACEMENT ...]]'))
3021 _('[OBSOLETED [REPLACEMENT ...]]'))
3022 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3022 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3023 """create arbitrary obsolete marker
3023 """create arbitrary obsolete marker
3024
3024
3025 With no arguments, displays the list of obsolescence markers."""
3025 With no arguments, displays the list of obsolescence markers."""
3026
3026
3027 def parsenodeid(s):
3027 def parsenodeid(s):
3028 try:
3028 try:
3029 # We do not use revsingle/revrange functions here to accept
3029 # We do not use revsingle/revrange functions here to accept
3030 # arbitrary node identifiers, possibly not present in the
3030 # arbitrary node identifiers, possibly not present in the
3031 # local repository.
3031 # local repository.
3032 n = bin(s)
3032 n = bin(s)
3033 if len(n) != len(nullid):
3033 if len(n) != len(nullid):
3034 raise TypeError()
3034 raise TypeError()
3035 return n
3035 return n
3036 except TypeError:
3036 except TypeError:
3037 raise error.Abort('changeset references must be full hexadecimal '
3037 raise error.Abort('changeset references must be full hexadecimal '
3038 'node identifiers')
3038 'node identifiers')
3039
3039
3040 if opts.get('delete'):
3040 if opts.get('delete'):
3041 indices = []
3041 indices = []
3042 for v in opts.get('delete'):
3042 for v in opts.get('delete'):
3043 try:
3043 try:
3044 indices.append(int(v))
3044 indices.append(int(v))
3045 except ValueError:
3045 except ValueError:
3046 raise error.Abort(_('invalid index value: %r') % v,
3046 raise error.Abort(_('invalid index value: %r') % v,
3047 hint=_('use integers for indices'))
3047 hint=_('use integers for indices'))
3048
3048
3049 if repo.currenttransaction():
3049 if repo.currenttransaction():
3050 raise error.Abort(_('cannot delete obsmarkers in the middle '
3050 raise error.Abort(_('cannot delete obsmarkers in the middle '
3051 'of transaction.'))
3051 'of transaction.'))
3052
3052
3053 with repo.lock():
3053 with repo.lock():
3054 n = repair.deleteobsmarkers(repo.obsstore, indices)
3054 n = repair.deleteobsmarkers(repo.obsstore, indices)
3055 ui.write(_('deleted %i obsolescense markers\n') % n)
3055 ui.write(_('deleted %i obsolescense markers\n') % n)
3056
3056
3057 return
3057 return
3058
3058
3059 if precursor is not None:
3059 if precursor is not None:
3060 if opts['rev']:
3060 if opts['rev']:
3061 raise error.Abort('cannot select revision when creating marker')
3061 raise error.Abort('cannot select revision when creating marker')
3062 metadata = {}
3062 metadata = {}
3063 metadata['user'] = opts['user'] or ui.username()
3063 metadata['user'] = opts['user'] or ui.username()
3064 succs = tuple(parsenodeid(succ) for succ in successors)
3064 succs = tuple(parsenodeid(succ) for succ in successors)
3065 l = repo.lock()
3065 l = repo.lock()
3066 try:
3066 try:
3067 tr = repo.transaction('debugobsolete')
3067 tr = repo.transaction('debugobsolete')
3068 try:
3068 try:
3069 date = opts.get('date')
3069 date = opts.get('date')
3070 if date:
3070 if date:
3071 date = util.parsedate(date)
3071 date = util.parsedate(date)
3072 else:
3072 else:
3073 date = None
3073 date = None
3074 prec = parsenodeid(precursor)
3074 prec = parsenodeid(precursor)
3075 parents = None
3075 parents = None
3076 if opts['record_parents']:
3076 if opts['record_parents']:
3077 if prec not in repo.unfiltered():
3077 if prec not in repo.unfiltered():
3078 raise error.Abort('cannot used --record-parents on '
3078 raise error.Abort('cannot used --record-parents on '
3079 'unknown changesets')
3079 'unknown changesets')
3080 parents = repo.unfiltered()[prec].parents()
3080 parents = repo.unfiltered()[prec].parents()
3081 parents = tuple(p.node() for p in parents)
3081 parents = tuple(p.node() for p in parents)
3082 repo.obsstore.create(tr, prec, succs, opts['flags'],
3082 repo.obsstore.create(tr, prec, succs, opts['flags'],
3083 parents=parents, date=date,
3083 parents=parents, date=date,
3084 metadata=metadata)
3084 metadata=metadata)
3085 tr.close()
3085 tr.close()
3086 except ValueError as exc:
3086 except ValueError as exc:
3087 raise error.Abort(_('bad obsmarker input: %s') % exc)
3087 raise error.Abort(_('bad obsmarker input: %s') % exc)
3088 finally:
3088 finally:
3089 tr.release()
3089 tr.release()
3090 finally:
3090 finally:
3091 l.release()
3091 l.release()
3092 else:
3092 else:
3093 if opts['rev']:
3093 if opts['rev']:
3094 revs = scmutil.revrange(repo, opts['rev'])
3094 revs = scmutil.revrange(repo, opts['rev'])
3095 nodes = [repo[r].node() for r in revs]
3095 nodes = [repo[r].node() for r in revs]
3096 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3096 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3097 markers.sort(key=lambda x: x._data)
3097 markers.sort(key=lambda x: x._data)
3098 else:
3098 else:
3099 markers = obsolete.getmarkers(repo)
3099 markers = obsolete.getmarkers(repo)
3100
3100
3101 markerstoiter = markers
3101 markerstoiter = markers
3102 isrelevant = lambda m: True
3102 isrelevant = lambda m: True
3103 if opts.get('rev') and opts.get('index'):
3103 if opts.get('rev') and opts.get('index'):
3104 markerstoiter = obsolete.getmarkers(repo)
3104 markerstoiter = obsolete.getmarkers(repo)
3105 markerset = set(markers)
3105 markerset = set(markers)
3106 isrelevant = lambda m: m in markerset
3106 isrelevant = lambda m: m in markerset
3107
3107
3108 fm = ui.formatter('debugobsolete', opts)
3108 fm = ui.formatter('debugobsolete', opts)
3109 for i, m in enumerate(markerstoiter):
3109 for i, m in enumerate(markerstoiter):
3110 if not isrelevant(m):
3110 if not isrelevant(m):
3111 # marker can be irrelevant when we're iterating over a set
3111 # marker can be irrelevant when we're iterating over a set
3112 # of markers (markerstoiter) which is bigger than the set
3112 # of markers (markerstoiter) which is bigger than the set
3113 # of markers we want to display (markers)
3113 # of markers we want to display (markers)
3114 # this can happen if both --index and --rev options are
3114 # this can happen if both --index and --rev options are
3115 # provided and thus we need to iterate over all of the markers
3115 # provided and thus we need to iterate over all of the markers
3116 # to get the correct indices, but only display the ones that
3116 # to get the correct indices, but only display the ones that
3117 # are relevant to --rev value
3117 # are relevant to --rev value
3118 continue
3118 continue
3119 fm.startitem()
3119 fm.startitem()
3120 ind = i if opts.get('index') else None
3120 ind = i if opts.get('index') else None
3121 cmdutil.showmarker(fm, m, index=ind)
3121 cmdutil.showmarker(fm, m, index=ind)
3122 fm.end()
3122 fm.end()
3123
3123
3124 @command('debugpathcomplete',
3124 @command('debugpathcomplete',
3125 [('f', 'full', None, _('complete an entire path')),
3125 [('f', 'full', None, _('complete an entire path')),
3126 ('n', 'normal', None, _('show only normal files')),
3126 ('n', 'normal', None, _('show only normal files')),
3127 ('a', 'added', None, _('show only added files')),
3127 ('a', 'added', None, _('show only added files')),
3128 ('r', 'removed', None, _('show only removed files'))],
3128 ('r', 'removed', None, _('show only removed files'))],
3129 _('FILESPEC...'))
3129 _('FILESPEC...'))
3130 def debugpathcomplete(ui, repo, *specs, **opts):
3130 def debugpathcomplete(ui, repo, *specs, **opts):
3131 '''complete part or all of a tracked path
3131 '''complete part or all of a tracked path
3132
3132
3133 This command supports shells that offer path name completion. It
3133 This command supports shells that offer path name completion. It
3134 currently completes only files already known to the dirstate.
3134 currently completes only files already known to the dirstate.
3135
3135
3136 Completion extends only to the next path segment unless
3136 Completion extends only to the next path segment unless
3137 --full is specified, in which case entire paths are used.'''
3137 --full is specified, in which case entire paths are used.'''
3138
3138
3139 def complete(path, acceptable):
3139 def complete(path, acceptable):
3140 dirstate = repo.dirstate
3140 dirstate = repo.dirstate
3141 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3141 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3142 rootdir = repo.root + os.sep
3142 rootdir = repo.root + os.sep
3143 if spec != repo.root and not spec.startswith(rootdir):
3143 if spec != repo.root and not spec.startswith(rootdir):
3144 return [], []
3144 return [], []
3145 if os.path.isdir(spec):
3145 if os.path.isdir(spec):
3146 spec += '/'
3146 spec += '/'
3147 spec = spec[len(rootdir):]
3147 spec = spec[len(rootdir):]
3148 fixpaths = os.sep != '/'
3148 fixpaths = os.sep != '/'
3149 if fixpaths:
3149 if fixpaths:
3150 spec = spec.replace(os.sep, '/')
3150 spec = spec.replace(os.sep, '/')
3151 speclen = len(spec)
3151 speclen = len(spec)
3152 fullpaths = opts['full']
3152 fullpaths = opts['full']
3153 files, dirs = set(), set()
3153 files, dirs = set(), set()
3154 adddir, addfile = dirs.add, files.add
3154 adddir, addfile = dirs.add, files.add
3155 for f, st in dirstate.iteritems():
3155 for f, st in dirstate.iteritems():
3156 if f.startswith(spec) and st[0] in acceptable:
3156 if f.startswith(spec) and st[0] in acceptable:
3157 if fixpaths:
3157 if fixpaths:
3158 f = f.replace('/', os.sep)
3158 f = f.replace('/', os.sep)
3159 if fullpaths:
3159 if fullpaths:
3160 addfile(f)
3160 addfile(f)
3161 continue
3161 continue
3162 s = f.find(os.sep, speclen)
3162 s = f.find(os.sep, speclen)
3163 if s >= 0:
3163 if s >= 0:
3164 adddir(f[:s])
3164 adddir(f[:s])
3165 else:
3165 else:
3166 addfile(f)
3166 addfile(f)
3167 return files, dirs
3167 return files, dirs
3168
3168
3169 acceptable = ''
3169 acceptable = ''
3170 if opts['normal']:
3170 if opts['normal']:
3171 acceptable += 'nm'
3171 acceptable += 'nm'
3172 if opts['added']:
3172 if opts['added']:
3173 acceptable += 'a'
3173 acceptable += 'a'
3174 if opts['removed']:
3174 if opts['removed']:
3175 acceptable += 'r'
3175 acceptable += 'r'
3176 cwd = repo.getcwd()
3176 cwd = repo.getcwd()
3177 if not specs:
3177 if not specs:
3178 specs = ['.']
3178 specs = ['.']
3179
3179
3180 files, dirs = set(), set()
3180 files, dirs = set(), set()
3181 for spec in specs:
3181 for spec in specs:
3182 f, d = complete(spec, acceptable or 'nmar')
3182 f, d = complete(spec, acceptable or 'nmar')
3183 files.update(f)
3183 files.update(f)
3184 dirs.update(d)
3184 dirs.update(d)
3185 files.update(dirs)
3185 files.update(dirs)
3186 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3186 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3187 ui.write('\n')
3187 ui.write('\n')
3188
3188
3189 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3189 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3190 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3190 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3191 '''access the pushkey key/value protocol
3191 '''access the pushkey key/value protocol
3192
3192
3193 With two args, list the keys in the given namespace.
3193 With two args, list the keys in the given namespace.
3194
3194
3195 With five args, set a key to new if it currently is set to old.
3195 With five args, set a key to new if it currently is set to old.
3196 Reports success or failure.
3196 Reports success or failure.
3197 '''
3197 '''
3198
3198
3199 target = hg.peer(ui, {}, repopath)
3199 target = hg.peer(ui, {}, repopath)
3200 if keyinfo:
3200 if keyinfo:
3201 key, old, new = keyinfo
3201 key, old, new = keyinfo
3202 r = target.pushkey(namespace, key, old, new)
3202 r = target.pushkey(namespace, key, old, new)
3203 ui.status(str(r) + '\n')
3203 ui.status(str(r) + '\n')
3204 return not r
3204 return not r
3205 else:
3205 else:
3206 for k, v in sorted(target.listkeys(namespace).iteritems()):
3206 for k, v in sorted(target.listkeys(namespace).iteritems()):
3207 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3207 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3208 v.encode('string-escape')))
3208 v.encode('string-escape')))
3209
3209
3210 @command('debugpvec', [], _('A B'))
3210 @command('debugpvec', [], _('A B'))
3211 def debugpvec(ui, repo, a, b=None):
3211 def debugpvec(ui, repo, a, b=None):
3212 ca = scmutil.revsingle(repo, a)
3212 ca = scmutil.revsingle(repo, a)
3213 cb = scmutil.revsingle(repo, b)
3213 cb = scmutil.revsingle(repo, b)
3214 pa = pvec.ctxpvec(ca)
3214 pa = pvec.ctxpvec(ca)
3215 pb = pvec.ctxpvec(cb)
3215 pb = pvec.ctxpvec(cb)
3216 if pa == pb:
3216 if pa == pb:
3217 rel = "="
3217 rel = "="
3218 elif pa > pb:
3218 elif pa > pb:
3219 rel = ">"
3219 rel = ">"
3220 elif pa < pb:
3220 elif pa < pb:
3221 rel = "<"
3221 rel = "<"
3222 elif pa | pb:
3222 elif pa | pb:
3223 rel = "|"
3223 rel = "|"
3224 ui.write(_("a: %s\n") % pa)
3224 ui.write(_("a: %s\n") % pa)
3225 ui.write(_("b: %s\n") % pb)
3225 ui.write(_("b: %s\n") % pb)
3226 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3226 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3227 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3227 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3228 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3228 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3229 pa.distance(pb), rel))
3229 pa.distance(pb), rel))
3230
3230
3231 @command('debugrebuilddirstate|debugrebuildstate',
3231 @command('debugrebuilddirstate|debugrebuildstate',
3232 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3232 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3233 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3233 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3234 'the working copy parent')),
3234 'the working copy parent')),
3235 ],
3235 ],
3236 _('[-r REV]'))
3236 _('[-r REV]'))
3237 def debugrebuilddirstate(ui, repo, rev, **opts):
3237 def debugrebuilddirstate(ui, repo, rev, **opts):
3238 """rebuild the dirstate as it would look like for the given revision
3238 """rebuild the dirstate as it would look like for the given revision
3239
3239
3240 If no revision is specified the first current parent will be used.
3240 If no revision is specified the first current parent will be used.
3241
3241
3242 The dirstate will be set to the files of the given revision.
3242 The dirstate will be set to the files of the given revision.
3243 The actual working directory content or existing dirstate
3243 The actual working directory content or existing dirstate
3244 information such as adds or removes is not considered.
3244 information such as adds or removes is not considered.
3245
3245
3246 ``minimal`` will only rebuild the dirstate status for files that claim to be
3246 ``minimal`` will only rebuild the dirstate status for files that claim to be
3247 tracked but are not in the parent manifest, or that exist in the parent
3247 tracked but are not in the parent manifest, or that exist in the parent
3248 manifest but are not in the dirstate. It will not change adds, removes, or
3248 manifest but are not in the dirstate. It will not change adds, removes, or
3249 modified files that are in the working copy parent.
3249 modified files that are in the working copy parent.
3250
3250
3251 One use of this command is to make the next :hg:`status` invocation
3251 One use of this command is to make the next :hg:`status` invocation
3252 check the actual file content.
3252 check the actual file content.
3253 """
3253 """
3254 ctx = scmutil.revsingle(repo, rev)
3254 ctx = scmutil.revsingle(repo, rev)
3255 with repo.wlock():
3255 with repo.wlock():
3256 dirstate = repo.dirstate
3256 dirstate = repo.dirstate
3257 changedfiles = None
3257 changedfiles = None
3258 # See command doc for what minimal does.
3258 # See command doc for what minimal does.
3259 if opts.get('minimal'):
3259 if opts.get('minimal'):
3260 manifestfiles = set(ctx.manifest().keys())
3260 manifestfiles = set(ctx.manifest().keys())
3261 dirstatefiles = set(dirstate)
3261 dirstatefiles = set(dirstate)
3262 manifestonly = manifestfiles - dirstatefiles
3262 manifestonly = manifestfiles - dirstatefiles
3263 dsonly = dirstatefiles - manifestfiles
3263 dsonly = dirstatefiles - manifestfiles
3264 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3264 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3265 changedfiles = manifestonly | dsnotadded
3265 changedfiles = manifestonly | dsnotadded
3266
3266
3267 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3267 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3268
3268
3269 @command('debugrebuildfncache', [], '')
3269 @command('debugrebuildfncache', [], '')
3270 def debugrebuildfncache(ui, repo):
3270 def debugrebuildfncache(ui, repo):
3271 """rebuild the fncache file"""
3271 """rebuild the fncache file"""
3272 repair.rebuildfncache(ui, repo)
3272 repair.rebuildfncache(ui, repo)
3273
3273
3274 @command('debugrename',
3274 @command('debugrename',
3275 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3275 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3276 _('[-r REV] FILE'))
3276 _('[-r REV] FILE'))
3277 def debugrename(ui, repo, file1, *pats, **opts):
3277 def debugrename(ui, repo, file1, *pats, **opts):
3278 """dump rename information"""
3278 """dump rename information"""
3279
3279
3280 ctx = scmutil.revsingle(repo, opts.get('rev'))
3280 ctx = scmutil.revsingle(repo, opts.get('rev'))
3281 m = scmutil.match(ctx, (file1,) + pats, opts)
3281 m = scmutil.match(ctx, (file1,) + pats, opts)
3282 for abs in ctx.walk(m):
3282 for abs in ctx.walk(m):
3283 fctx = ctx[abs]
3283 fctx = ctx[abs]
3284 o = fctx.filelog().renamed(fctx.filenode())
3284 o = fctx.filelog().renamed(fctx.filenode())
3285 rel = m.rel(abs)
3285 rel = m.rel(abs)
3286 if o:
3286 if o:
3287 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3287 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3288 else:
3288 else:
3289 ui.write(_("%s not renamed\n") % rel)
3289 ui.write(_("%s not renamed\n") % rel)
3290
3290
3291 @command('debugrevlog', debugrevlogopts +
3291 @command('debugrevlog', debugrevlogopts +
3292 [('d', 'dump', False, _('dump index data'))],
3292 [('d', 'dump', False, _('dump index data'))],
3293 _('-c|-m|FILE'),
3293 _('-c|-m|FILE'),
3294 optionalrepo=True)
3294 optionalrepo=True)
3295 def debugrevlog(ui, repo, file_=None, **opts):
3295 def debugrevlog(ui, repo, file_=None, **opts):
3296 """show data and statistics about a revlog"""
3296 """show data and statistics about a revlog"""
3297 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3297 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3298
3298
3299 if opts.get("dump"):
3299 if opts.get("dump"):
3300 numrevs = len(r)
3300 numrevs = len(r)
3301 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3301 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3302 " rawsize totalsize compression heads chainlen\n"))
3302 " rawsize totalsize compression heads chainlen\n"))
3303 ts = 0
3303 ts = 0
3304 heads = set()
3304 heads = set()
3305
3305
3306 for rev in xrange(numrevs):
3306 for rev in xrange(numrevs):
3307 dbase = r.deltaparent(rev)
3307 dbase = r.deltaparent(rev)
3308 if dbase == -1:
3308 if dbase == -1:
3309 dbase = rev
3309 dbase = rev
3310 cbase = r.chainbase(rev)
3310 cbase = r.chainbase(rev)
3311 clen = r.chainlen(rev)
3311 clen = r.chainlen(rev)
3312 p1, p2 = r.parentrevs(rev)
3312 p1, p2 = r.parentrevs(rev)
3313 rs = r.rawsize(rev)
3313 rs = r.rawsize(rev)
3314 ts = ts + rs
3314 ts = ts + rs
3315 heads -= set(r.parentrevs(rev))
3315 heads -= set(r.parentrevs(rev))
3316 heads.add(rev)
3316 heads.add(rev)
3317 try:
3317 try:
3318 compression = ts / r.end(rev)
3318 compression = ts / r.end(rev)
3319 except ZeroDivisionError:
3319 except ZeroDivisionError:
3320 compression = 0
3320 compression = 0
3321 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3321 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3322 "%11d %5d %8d\n" %
3322 "%11d %5d %8d\n" %
3323 (rev, p1, p2, r.start(rev), r.end(rev),
3323 (rev, p1, p2, r.start(rev), r.end(rev),
3324 r.start(dbase), r.start(cbase),
3324 r.start(dbase), r.start(cbase),
3325 r.start(p1), r.start(p2),
3325 r.start(p1), r.start(p2),
3326 rs, ts, compression, len(heads), clen))
3326 rs, ts, compression, len(heads), clen))
3327 return 0
3327 return 0
3328
3328
3329 v = r.version
3329 v = r.version
3330 format = v & 0xFFFF
3330 format = v & 0xFFFF
3331 flags = []
3331 flags = []
3332 gdelta = False
3332 gdelta = False
3333 if v & revlog.REVLOGNGINLINEDATA:
3333 if v & revlog.REVLOGNGINLINEDATA:
3334 flags.append('inline')
3334 flags.append('inline')
3335 if v & revlog.REVLOGGENERALDELTA:
3335 if v & revlog.REVLOGGENERALDELTA:
3336 gdelta = True
3336 gdelta = True
3337 flags.append('generaldelta')
3337 flags.append('generaldelta')
3338 if not flags:
3338 if not flags:
3339 flags = ['(none)']
3339 flags = ['(none)']
3340
3340
3341 nummerges = 0
3341 nummerges = 0
3342 numfull = 0
3342 numfull = 0
3343 numprev = 0
3343 numprev = 0
3344 nump1 = 0
3344 nump1 = 0
3345 nump2 = 0
3345 nump2 = 0
3346 numother = 0
3346 numother = 0
3347 nump1prev = 0
3347 nump1prev = 0
3348 nump2prev = 0
3348 nump2prev = 0
3349 chainlengths = []
3349 chainlengths = []
3350
3350
3351 datasize = [None, 0, 0]
3351 datasize = [None, 0, 0]
3352 fullsize = [None, 0, 0]
3352 fullsize = [None, 0, 0]
3353 deltasize = [None, 0, 0]
3353 deltasize = [None, 0, 0]
3354
3354
3355 def addsize(size, l):
3355 def addsize(size, l):
3356 if l[0] is None or size < l[0]:
3356 if l[0] is None or size < l[0]:
3357 l[0] = size
3357 l[0] = size
3358 if size > l[1]:
3358 if size > l[1]:
3359 l[1] = size
3359 l[1] = size
3360 l[2] += size
3360 l[2] += size
3361
3361
3362 numrevs = len(r)
3362 numrevs = len(r)
3363 for rev in xrange(numrevs):
3363 for rev in xrange(numrevs):
3364 p1, p2 = r.parentrevs(rev)
3364 p1, p2 = r.parentrevs(rev)
3365 delta = r.deltaparent(rev)
3365 delta = r.deltaparent(rev)
3366 if format > 0:
3366 if format > 0:
3367 addsize(r.rawsize(rev), datasize)
3367 addsize(r.rawsize(rev), datasize)
3368 if p2 != nullrev:
3368 if p2 != nullrev:
3369 nummerges += 1
3369 nummerges += 1
3370 size = r.length(rev)
3370 size = r.length(rev)
3371 if delta == nullrev:
3371 if delta == nullrev:
3372 chainlengths.append(0)
3372 chainlengths.append(0)
3373 numfull += 1
3373 numfull += 1
3374 addsize(size, fullsize)
3374 addsize(size, fullsize)
3375 else:
3375 else:
3376 chainlengths.append(chainlengths[delta] + 1)
3376 chainlengths.append(chainlengths[delta] + 1)
3377 addsize(size, deltasize)
3377 addsize(size, deltasize)
3378 if delta == rev - 1:
3378 if delta == rev - 1:
3379 numprev += 1
3379 numprev += 1
3380 if delta == p1:
3380 if delta == p1:
3381 nump1prev += 1
3381 nump1prev += 1
3382 elif delta == p2:
3382 elif delta == p2:
3383 nump2prev += 1
3383 nump2prev += 1
3384 elif delta == p1:
3384 elif delta == p1:
3385 nump1 += 1
3385 nump1 += 1
3386 elif delta == p2:
3386 elif delta == p2:
3387 nump2 += 1
3387 nump2 += 1
3388 elif delta != nullrev:
3388 elif delta != nullrev:
3389 numother += 1
3389 numother += 1
3390
3390
3391 # Adjust size min value for empty cases
3391 # Adjust size min value for empty cases
3392 for size in (datasize, fullsize, deltasize):
3392 for size in (datasize, fullsize, deltasize):
3393 if size[0] is None:
3393 if size[0] is None:
3394 size[0] = 0
3394 size[0] = 0
3395
3395
3396 numdeltas = numrevs - numfull
3396 numdeltas = numrevs - numfull
3397 numoprev = numprev - nump1prev - nump2prev
3397 numoprev = numprev - nump1prev - nump2prev
3398 totalrawsize = datasize[2]
3398 totalrawsize = datasize[2]
3399 datasize[2] /= numrevs
3399 datasize[2] /= numrevs
3400 fulltotal = fullsize[2]
3400 fulltotal = fullsize[2]
3401 fullsize[2] /= numfull
3401 fullsize[2] /= numfull
3402 deltatotal = deltasize[2]
3402 deltatotal = deltasize[2]
3403 if numrevs - numfull > 0:
3403 if numrevs - numfull > 0:
3404 deltasize[2] /= numrevs - numfull
3404 deltasize[2] /= numrevs - numfull
3405 totalsize = fulltotal + deltatotal
3405 totalsize = fulltotal + deltatotal
3406 avgchainlen = sum(chainlengths) / numrevs
3406 avgchainlen = sum(chainlengths) / numrevs
3407 maxchainlen = max(chainlengths)
3407 maxchainlen = max(chainlengths)
3408 compratio = 1
3408 compratio = 1
3409 if totalsize:
3409 if totalsize:
3410 compratio = totalrawsize / totalsize
3410 compratio = totalrawsize / totalsize
3411
3411
3412 basedfmtstr = '%%%dd\n'
3412 basedfmtstr = '%%%dd\n'
3413 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3413 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3414
3414
3415 def dfmtstr(max):
3415 def dfmtstr(max):
3416 return basedfmtstr % len(str(max))
3416 return basedfmtstr % len(str(max))
3417 def pcfmtstr(max, padding=0):
3417 def pcfmtstr(max, padding=0):
3418 return basepcfmtstr % (len(str(max)), ' ' * padding)
3418 return basepcfmtstr % (len(str(max)), ' ' * padding)
3419
3419
3420 def pcfmt(value, total):
3420 def pcfmt(value, total):
3421 if total:
3421 if total:
3422 return (value, 100 * float(value) / total)
3422 return (value, 100 * float(value) / total)
3423 else:
3423 else:
3424 return value, 100.0
3424 return value, 100.0
3425
3425
3426 ui.write(('format : %d\n') % format)
3426 ui.write(('format : %d\n') % format)
3427 ui.write(('flags : %s\n') % ', '.join(flags))
3427 ui.write(('flags : %s\n') % ', '.join(flags))
3428
3428
3429 ui.write('\n')
3429 ui.write('\n')
3430 fmt = pcfmtstr(totalsize)
3430 fmt = pcfmtstr(totalsize)
3431 fmt2 = dfmtstr(totalsize)
3431 fmt2 = dfmtstr(totalsize)
3432 ui.write(('revisions : ') + fmt2 % numrevs)
3432 ui.write(('revisions : ') + fmt2 % numrevs)
3433 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3433 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3434 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3434 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3435 ui.write(('revisions : ') + fmt2 % numrevs)
3435 ui.write(('revisions : ') + fmt2 % numrevs)
3436 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3436 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3437 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3437 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3438 ui.write(('revision size : ') + fmt2 % totalsize)
3438 ui.write(('revision size : ') + fmt2 % totalsize)
3439 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3439 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3440 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3440 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3441
3441
3442 ui.write('\n')
3442 ui.write('\n')
3443 fmt = dfmtstr(max(avgchainlen, compratio))
3443 fmt = dfmtstr(max(avgchainlen, compratio))
3444 ui.write(('avg chain length : ') + fmt % avgchainlen)
3444 ui.write(('avg chain length : ') + fmt % avgchainlen)
3445 ui.write(('max chain length : ') + fmt % maxchainlen)
3445 ui.write(('max chain length : ') + fmt % maxchainlen)
3446 ui.write(('compression ratio : ') + fmt % compratio)
3446 ui.write(('compression ratio : ') + fmt % compratio)
3447
3447
3448 if format > 0:
3448 if format > 0:
3449 ui.write('\n')
3449 ui.write('\n')
3450 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3450 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3451 % tuple(datasize))
3451 % tuple(datasize))
3452 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3452 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3453 % tuple(fullsize))
3453 % tuple(fullsize))
3454 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3454 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3455 % tuple(deltasize))
3455 % tuple(deltasize))
3456
3456
3457 if numdeltas > 0:
3457 if numdeltas > 0:
3458 ui.write('\n')
3458 ui.write('\n')
3459 fmt = pcfmtstr(numdeltas)
3459 fmt = pcfmtstr(numdeltas)
3460 fmt2 = pcfmtstr(numdeltas, 4)
3460 fmt2 = pcfmtstr(numdeltas, 4)
3461 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3461 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3462 if numprev > 0:
3462 if numprev > 0:
3463 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3463 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3464 numprev))
3464 numprev))
3465 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3465 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3466 numprev))
3466 numprev))
3467 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3467 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3468 numprev))
3468 numprev))
3469 if gdelta:
3469 if gdelta:
3470 ui.write(('deltas against p1 : ')
3470 ui.write(('deltas against p1 : ')
3471 + fmt % pcfmt(nump1, numdeltas))
3471 + fmt % pcfmt(nump1, numdeltas))
3472 ui.write(('deltas against p2 : ')
3472 ui.write(('deltas against p2 : ')
3473 + fmt % pcfmt(nump2, numdeltas))
3473 + fmt % pcfmt(nump2, numdeltas))
3474 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3474 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3475 numdeltas))
3475 numdeltas))
3476
3476
3477 @command('debugrevspec',
3477 @command('debugrevspec',
3478 [('', 'optimize', None,
3478 [('', 'optimize', None,
3479 _('print parsed tree after optimizing (DEPRECATED)')),
3479 _('print parsed tree after optimizing (DEPRECATED)')),
3480 ('p', 'show-stage', [],
3480 ('p', 'show-stage', [],
3481 _('print parsed tree at the given stage'), _('NAME')),
3481 _('print parsed tree at the given stage'), _('NAME')),
3482 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3482 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3483 ('', 'verify-optimized', False, _('verify optimized result')),
3483 ('', 'verify-optimized', False, _('verify optimized result')),
3484 ],
3484 ],
3485 ('REVSPEC'))
3485 ('REVSPEC'))
3486 def debugrevspec(ui, repo, expr, **opts):
3486 def debugrevspec(ui, repo, expr, **opts):
3487 """parse and apply a revision specification
3487 """parse and apply a revision specification
3488
3488
3489 Use -p/--show-stage option to print the parsed tree at the given stages.
3489 Use -p/--show-stage option to print the parsed tree at the given stages.
3490 Use -p all to print tree at every stage.
3490 Use -p all to print tree at every stage.
3491
3491
3492 Use --verify-optimized to compare the optimized result with the unoptimized
3492 Use --verify-optimized to compare the optimized result with the unoptimized
3493 one. Returns 1 if the optimized result differs.
3493 one. Returns 1 if the optimized result differs.
3494 """
3494 """
3495 stages = [
3495 stages = [
3496 ('parsed', lambda tree: tree),
3496 ('parsed', lambda tree: tree),
3497 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3497 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3498 ('concatenated', revset.foldconcat),
3498 ('concatenated', revset.foldconcat),
3499 ('analyzed', revset.analyze),
3499 ('analyzed', revset.analyze),
3500 ('optimized', revset.optimize),
3500 ('optimized', revset.optimize),
3501 ]
3501 ]
3502 if opts['no_optimized']:
3502 if opts['no_optimized']:
3503 stages = stages[:-1]
3503 stages = stages[:-1]
3504 if opts['verify_optimized'] and opts['no_optimized']:
3504 if opts['verify_optimized'] and opts['no_optimized']:
3505 raise error.Abort(_('cannot use --verify-optimized with '
3505 raise error.Abort(_('cannot use --verify-optimized with '
3506 '--no-optimized'))
3506 '--no-optimized'))
3507 stagenames = set(n for n, f in stages)
3507 stagenames = set(n for n, f in stages)
3508
3508
3509 showalways = set()
3509 showalways = set()
3510 showchanged = set()
3510 showchanged = set()
3511 if ui.verbose and not opts['show_stage']:
3511 if ui.verbose and not opts['show_stage']:
3512 # show parsed tree by --verbose (deprecated)
3512 # show parsed tree by --verbose (deprecated)
3513 showalways.add('parsed')
3513 showalways.add('parsed')
3514 showchanged.update(['expanded', 'concatenated'])
3514 showchanged.update(['expanded', 'concatenated'])
3515 if opts['optimize']:
3515 if opts['optimize']:
3516 showalways.add('optimized')
3516 showalways.add('optimized')
3517 if opts['show_stage'] and opts['optimize']:
3517 if opts['show_stage'] and opts['optimize']:
3518 raise error.Abort(_('cannot use --optimize with --show-stage'))
3518 raise error.Abort(_('cannot use --optimize with --show-stage'))
3519 if opts['show_stage'] == ['all']:
3519 if opts['show_stage'] == ['all']:
3520 showalways.update(stagenames)
3520 showalways.update(stagenames)
3521 else:
3521 else:
3522 for n in opts['show_stage']:
3522 for n in opts['show_stage']:
3523 if n not in stagenames:
3523 if n not in stagenames:
3524 raise error.Abort(_('invalid stage name: %s') % n)
3524 raise error.Abort(_('invalid stage name: %s') % n)
3525 showalways.update(opts['show_stage'])
3525 showalways.update(opts['show_stage'])
3526
3526
3527 treebystage = {}
3527 treebystage = {}
3528 printedtree = None
3528 printedtree = None
3529 tree = revset.parse(expr, lookup=repo.__contains__)
3529 tree = revset.parse(expr, lookup=repo.__contains__)
3530 for n, f in stages:
3530 for n, f in stages:
3531 treebystage[n] = tree = f(tree)
3531 treebystage[n] = tree = f(tree)
3532 if n in showalways or (n in showchanged and tree != printedtree):
3532 if n in showalways or (n in showchanged and tree != printedtree):
3533 if opts['show_stage'] or n != 'parsed':
3533 if opts['show_stage'] or n != 'parsed':
3534 ui.write(("* %s:\n") % n)
3534 ui.write(("* %s:\n") % n)
3535 ui.write(revset.prettyformat(tree), "\n")
3535 ui.write(revset.prettyformat(tree), "\n")
3536 printedtree = tree
3536 printedtree = tree
3537
3537
3538 if opts['verify_optimized']:
3538 if opts['verify_optimized']:
3539 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3539 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3540 brevs = revset.makematcher(treebystage['optimized'])(repo)
3540 brevs = revset.makematcher(treebystage['optimized'])(repo)
3541 if ui.verbose:
3541 if ui.verbose:
3542 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3542 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3543 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3543 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3544 arevs = list(arevs)
3544 arevs = list(arevs)
3545 brevs = list(brevs)
3545 brevs = list(brevs)
3546 if arevs == brevs:
3546 if arevs == brevs:
3547 return 0
3547 return 0
3548 ui.write(('--- analyzed\n'), label='diff.file_a')
3548 ui.write(('--- analyzed\n'), label='diff.file_a')
3549 ui.write(('+++ optimized\n'), label='diff.file_b')
3549 ui.write(('+++ optimized\n'), label='diff.file_b')
3550 sm = difflib.SequenceMatcher(None, arevs, brevs)
3550 sm = difflib.SequenceMatcher(None, arevs, brevs)
3551 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3551 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3552 if tag in ('delete', 'replace'):
3552 if tag in ('delete', 'replace'):
3553 for c in arevs[alo:ahi]:
3553 for c in arevs[alo:ahi]:
3554 ui.write('-%s\n' % c, label='diff.deleted')
3554 ui.write('-%s\n' % c, label='diff.deleted')
3555 if tag in ('insert', 'replace'):
3555 if tag in ('insert', 'replace'):
3556 for c in brevs[blo:bhi]:
3556 for c in brevs[blo:bhi]:
3557 ui.write('+%s\n' % c, label='diff.inserted')
3557 ui.write('+%s\n' % c, label='diff.inserted')
3558 if tag == 'equal':
3558 if tag == 'equal':
3559 for c in arevs[alo:ahi]:
3559 for c in arevs[alo:ahi]:
3560 ui.write(' %s\n' % c)
3560 ui.write(' %s\n' % c)
3561 return 1
3561 return 1
3562
3562
3563 func = revset.makematcher(tree)
3563 func = revset.makematcher(tree)
3564 revs = func(repo)
3564 revs = func(repo)
3565 if ui.verbose:
3565 if ui.verbose:
3566 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3566 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3567 for c in revs:
3567 for c in revs:
3568 ui.write("%s\n" % c)
3568 ui.write("%s\n" % c)
3569
3569
3570 @command('debugsetparents', [], _('REV1 [REV2]'))
3570 @command('debugsetparents', [], _('REV1 [REV2]'))
3571 def debugsetparents(ui, repo, rev1, rev2=None):
3571 def debugsetparents(ui, repo, rev1, rev2=None):
3572 """manually set the parents of the current working directory
3572 """manually set the parents of the current working directory
3573
3573
3574 This is useful for writing repository conversion tools, but should
3574 This is useful for writing repository conversion tools, but should
3575 be used with care. For example, neither the working directory nor the
3575 be used with care. For example, neither the working directory nor the
3576 dirstate is updated, so file status may be incorrect after running this
3576 dirstate is updated, so file status may be incorrect after running this
3577 command.
3577 command.
3578
3578
3579 Returns 0 on success.
3579 Returns 0 on success.
3580 """
3580 """
3581
3581
3582 r1 = scmutil.revsingle(repo, rev1).node()
3582 r1 = scmutil.revsingle(repo, rev1).node()
3583 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3583 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3584
3584
3585 with repo.wlock():
3585 with repo.wlock():
3586 repo.setparents(r1, r2)
3586 repo.setparents(r1, r2)
3587
3587
3588 @command('debugdirstate|debugstate',
3588 @command('debugdirstate|debugstate',
3589 [('', 'nodates', None, _('do not display the saved mtime')),
3589 [('', 'nodates', None, _('do not display the saved mtime')),
3590 ('', 'datesort', None, _('sort by saved mtime'))],
3590 ('', 'datesort', None, _('sort by saved mtime'))],
3591 _('[OPTION]...'))
3591 _('[OPTION]...'))
3592 def debugstate(ui, repo, **opts):
3592 def debugstate(ui, repo, **opts):
3593 """show the contents of the current dirstate"""
3593 """show the contents of the current dirstate"""
3594
3594
3595 nodates = opts.get('nodates')
3595 nodates = opts.get('nodates')
3596 datesort = opts.get('datesort')
3596 datesort = opts.get('datesort')
3597
3597
3598 timestr = ""
3598 timestr = ""
3599 if datesort:
3599 if datesort:
3600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3601 else:
3601 else:
3602 keyfunc = None # sort by filename
3602 keyfunc = None # sort by filename
3603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3604 if ent[3] == -1:
3604 if ent[3] == -1:
3605 timestr = 'unset '
3605 timestr = 'unset '
3606 elif nodates:
3606 elif nodates:
3607 timestr = 'set '
3607 timestr = 'set '
3608 else:
3608 else:
3609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3610 time.localtime(ent[3]))
3610 time.localtime(ent[3]))
3611 if ent[1] & 0o20000:
3611 if ent[1] & 0o20000:
3612 mode = 'lnk'
3612 mode = 'lnk'
3613 else:
3613 else:
3614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3616 for f in repo.dirstate.copies():
3616 for f in repo.dirstate.copies():
3617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3618
3618
3619 @command('debugsub',
3619 @command('debugsub',
3620 [('r', 'rev', '',
3620 [('r', 'rev', '',
3621 _('revision to check'), _('REV'))],
3621 _('revision to check'), _('REV'))],
3622 _('[-r REV] [REV]'))
3622 _('[-r REV] [REV]'))
3623 def debugsub(ui, repo, rev=None):
3623 def debugsub(ui, repo, rev=None):
3624 ctx = scmutil.revsingle(repo, rev, None)
3624 ctx = scmutil.revsingle(repo, rev, None)
3625 for k, v in sorted(ctx.substate.items()):
3625 for k, v in sorted(ctx.substate.items()):
3626 ui.write(('path %s\n') % k)
3626 ui.write(('path %s\n') % k)
3627 ui.write((' source %s\n') % v[0])
3627 ui.write((' source %s\n') % v[0])
3628 ui.write((' revision %s\n') % v[1])
3628 ui.write((' revision %s\n') % v[1])
3629
3629
3630 @command('debugsuccessorssets',
3630 @command('debugsuccessorssets',
3631 [],
3631 [],
3632 _('[REV]'))
3632 _('[REV]'))
3633 def debugsuccessorssets(ui, repo, *revs):
3633 def debugsuccessorssets(ui, repo, *revs):
3634 """show set of successors for revision
3634 """show set of successors for revision
3635
3635
3636 A successors set of changeset A is a consistent group of revisions that
3636 A successors set of changeset A is a consistent group of revisions that
3637 succeed A. It contains non-obsolete changesets only.
3637 succeed A. It contains non-obsolete changesets only.
3638
3638
3639 In most cases a changeset A has a single successors set containing a single
3639 In most cases a changeset A has a single successors set containing a single
3640 successor (changeset A replaced by A').
3640 successor (changeset A replaced by A').
3641
3641
3642 A changeset that is made obsolete with no successors are called "pruned".
3642 A changeset that is made obsolete with no successors are called "pruned".
3643 Such changesets have no successors sets at all.
3643 Such changesets have no successors sets at all.
3644
3644
3645 A changeset that has been "split" will have a successors set containing
3645 A changeset that has been "split" will have a successors set containing
3646 more than one successor.
3646 more than one successor.
3647
3647
3648 A changeset that has been rewritten in multiple different ways is called
3648 A changeset that has been rewritten in multiple different ways is called
3649 "divergent". Such changesets have multiple successor sets (each of which
3649 "divergent". Such changesets have multiple successor sets (each of which
3650 may also be split, i.e. have multiple successors).
3650 may also be split, i.e. have multiple successors).
3651
3651
3652 Results are displayed as follows::
3652 Results are displayed as follows::
3653
3653
3654 <rev1>
3654 <rev1>
3655 <successors-1A>
3655 <successors-1A>
3656 <rev2>
3656 <rev2>
3657 <successors-2A>
3657 <successors-2A>
3658 <successors-2B1> <successors-2B2> <successors-2B3>
3658 <successors-2B1> <successors-2B2> <successors-2B3>
3659
3659
3660 Here rev2 has two possible (i.e. divergent) successors sets. The first
3660 Here rev2 has two possible (i.e. divergent) successors sets. The first
3661 holds one element, whereas the second holds three (i.e. the changeset has
3661 holds one element, whereas the second holds three (i.e. the changeset has
3662 been split).
3662 been split).
3663 """
3663 """
3664 # passed to successorssets caching computation from one call to another
3664 # passed to successorssets caching computation from one call to another
3665 cache = {}
3665 cache = {}
3666 ctx2str = str
3666 ctx2str = str
3667 node2str = short
3667 node2str = short
3668 if ui.debug():
3668 if ui.debug():
3669 def ctx2str(ctx):
3669 def ctx2str(ctx):
3670 return ctx.hex()
3670 return ctx.hex()
3671 node2str = hex
3671 node2str = hex
3672 for rev in scmutil.revrange(repo, revs):
3672 for rev in scmutil.revrange(repo, revs):
3673 ctx = repo[rev]
3673 ctx = repo[rev]
3674 ui.write('%s\n'% ctx2str(ctx))
3674 ui.write('%s\n'% ctx2str(ctx))
3675 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3675 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3676 if succsset:
3676 if succsset:
3677 ui.write(' ')
3677 ui.write(' ')
3678 ui.write(node2str(succsset[0]))
3678 ui.write(node2str(succsset[0]))
3679 for node in succsset[1:]:
3679 for node in succsset[1:]:
3680 ui.write(' ')
3680 ui.write(' ')
3681 ui.write(node2str(node))
3681 ui.write(node2str(node))
3682 ui.write('\n')
3682 ui.write('\n')
3683
3683
3684 @command('debugtemplate',
3684 @command('debugtemplate',
3685 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3685 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3686 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3686 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3687 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3687 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3688 optionalrepo=True)
3688 optionalrepo=True)
3689 def debugtemplate(ui, repo, tmpl, **opts):
3689 def debugtemplate(ui, repo, tmpl, **opts):
3690 """parse and apply a template
3690 """parse and apply a template
3691
3691
3692 If -r/--rev is given, the template is processed as a log template and
3692 If -r/--rev is given, the template is processed as a log template and
3693 applied to the given changesets. Otherwise, it is processed as a generic
3693 applied to the given changesets. Otherwise, it is processed as a generic
3694 template.
3694 template.
3695
3695
3696 Use --verbose to print the parsed tree.
3696 Use --verbose to print the parsed tree.
3697 """
3697 """
3698 revs = None
3698 revs = None
3699 if opts['rev']:
3699 if opts['rev']:
3700 if repo is None:
3700 if repo is None:
3701 raise error.RepoError(_('there is no Mercurial repository here '
3701 raise error.RepoError(_('there is no Mercurial repository here '
3702 '(.hg not found)'))
3702 '(.hg not found)'))
3703 revs = scmutil.revrange(repo, opts['rev'])
3703 revs = scmutil.revrange(repo, opts['rev'])
3704
3704
3705 props = {}
3705 props = {}
3706 for d in opts['define']:
3706 for d in opts['define']:
3707 try:
3707 try:
3708 k, v = (e.strip() for e in d.split('=', 1))
3708 k, v = (e.strip() for e in d.split('=', 1))
3709 if not k:
3709 if not k:
3710 raise ValueError
3710 raise ValueError
3711 props[k] = v
3711 props[k] = v
3712 except ValueError:
3712 except ValueError:
3713 raise error.Abort(_('malformed keyword definition: %s') % d)
3713 raise error.Abort(_('malformed keyword definition: %s') % d)
3714
3714
3715 if ui.verbose:
3715 if ui.verbose:
3716 aliases = ui.configitems('templatealias')
3716 aliases = ui.configitems('templatealias')
3717 tree = templater.parse(tmpl)
3717 tree = templater.parse(tmpl)
3718 ui.note(templater.prettyformat(tree), '\n')
3718 ui.note(templater.prettyformat(tree), '\n')
3719 newtree = templater.expandaliases(tree, aliases)
3719 newtree = templater.expandaliases(tree, aliases)
3720 if newtree != tree:
3720 if newtree != tree:
3721 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3721 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3722
3722
3723 mapfile = None
3723 mapfile = None
3724 if revs is None:
3724 if revs is None:
3725 k = 'debugtemplate'
3725 k = 'debugtemplate'
3726 t = formatter.maketemplater(ui, k, tmpl)
3726 t = formatter.maketemplater(ui, k, tmpl)
3727 ui.write(templater.stringify(t(k, **props)))
3727 ui.write(templater.stringify(t(k, **props)))
3728 else:
3728 else:
3729 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3729 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3730 mapfile, buffered=False)
3730 mapfile, buffered=False)
3731 for r in revs:
3731 for r in revs:
3732 displayer.show(repo[r], **props)
3732 displayer.show(repo[r], **props)
3733 displayer.close()
3733 displayer.close()
3734
3734
3735 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3735 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3736 def debugwalk(ui, repo, *pats, **opts):
3736 def debugwalk(ui, repo, *pats, **opts):
3737 """show how files match on given patterns"""
3737 """show how files match on given patterns"""
3738 m = scmutil.match(repo[None], pats, opts)
3738 m = scmutil.match(repo[None], pats, opts)
3739 items = list(repo.walk(m))
3739 items = list(repo.walk(m))
3740 if not items:
3740 if not items:
3741 return
3741 return
3742 f = lambda fn: fn
3742 f = lambda fn: fn
3743 if ui.configbool('ui', 'slash') and os.sep != '/':
3743 if ui.configbool('ui', 'slash') and os.sep != '/':
3744 f = lambda fn: util.normpath(fn)
3744 f = lambda fn: util.normpath(fn)
3745 fmt = 'f %%-%ds %%-%ds %%s' % (
3745 fmt = 'f %%-%ds %%-%ds %%s' % (
3746 max([len(abs) for abs in items]),
3746 max([len(abs) for abs in items]),
3747 max([len(m.rel(abs)) for abs in items]))
3747 max([len(m.rel(abs)) for abs in items]))
3748 for abs in items:
3748 for abs in items:
3749 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3749 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3750 ui.write("%s\n" % line.rstrip())
3750 ui.write("%s\n" % line.rstrip())
3751
3751
3752 @command('debugwireargs',
3752 @command('debugwireargs',
3753 [('', 'three', '', 'three'),
3753 [('', 'three', '', 'three'),
3754 ('', 'four', '', 'four'),
3754 ('', 'four', '', 'four'),
3755 ('', 'five', '', 'five'),
3755 ('', 'five', '', 'five'),
3756 ] + remoteopts,
3756 ] + remoteopts,
3757 _('REPO [OPTIONS]... [ONE [TWO]]'),
3757 _('REPO [OPTIONS]... [ONE [TWO]]'),
3758 norepo=True)
3758 norepo=True)
3759 def debugwireargs(ui, repopath, *vals, **opts):
3759 def debugwireargs(ui, repopath, *vals, **opts):
3760 repo = hg.peer(ui, opts, repopath)
3760 repo = hg.peer(ui, opts, repopath)
3761 for opt in remoteopts:
3761 for opt in remoteopts:
3762 del opts[opt[1]]
3762 del opts[opt[1]]
3763 args = {}
3763 args = {}
3764 for k, v in opts.iteritems():
3764 for k, v in opts.iteritems():
3765 if v:
3765 if v:
3766 args[k] = v
3766 args[k] = v
3767 # run twice to check that we don't mess up the stream for the next command
3767 # run twice to check that we don't mess up the stream for the next command
3768 res1 = repo.debugwireargs(*vals, **args)
3768 res1 = repo.debugwireargs(*vals, **args)
3769 res2 = repo.debugwireargs(*vals, **args)
3769 res2 = repo.debugwireargs(*vals, **args)
3770 ui.write("%s\n" % res1)
3770 ui.write("%s\n" % res1)
3771 if res1 != res2:
3771 if res1 != res2:
3772 ui.warn("%s\n" % res2)
3772 ui.warn("%s\n" % res2)
3773
3773
3774 @command('^diff',
3774 @command('^diff',
3775 [('r', 'rev', [], _('revision'), _('REV')),
3775 [('r', 'rev', [], _('revision'), _('REV')),
3776 ('c', 'change', '', _('change made by revision'), _('REV'))
3776 ('c', 'change', '', _('change made by revision'), _('REV'))
3777 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3777 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3778 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3778 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3779 inferrepo=True)
3779 inferrepo=True)
3780 def diff(ui, repo, *pats, **opts):
3780 def diff(ui, repo, *pats, **opts):
3781 """diff repository (or selected files)
3781 """diff repository (or selected files)
3782
3782
3783 Show differences between revisions for the specified files.
3783 Show differences between revisions for the specified files.
3784
3784
3785 Differences between files are shown using the unified diff format.
3785 Differences between files are shown using the unified diff format.
3786
3786
3787 .. note::
3787 .. note::
3788
3788
3789 :hg:`diff` may generate unexpected results for merges, as it will
3789 :hg:`diff` may generate unexpected results for merges, as it will
3790 default to comparing against the working directory's first
3790 default to comparing against the working directory's first
3791 parent changeset if no revisions are specified.
3791 parent changeset if no revisions are specified.
3792
3792
3793 When two revision arguments are given, then changes are shown
3793 When two revision arguments are given, then changes are shown
3794 between those revisions. If only one revision is specified then
3794 between those revisions. If only one revision is specified then
3795 that revision is compared to the working directory, and, when no
3795 that revision is compared to the working directory, and, when no
3796 revisions are specified, the working directory files are compared
3796 revisions are specified, the working directory files are compared
3797 to its first parent.
3797 to its first parent.
3798
3798
3799 Alternatively you can specify -c/--change with a revision to see
3799 Alternatively you can specify -c/--change with a revision to see
3800 the changes in that changeset relative to its first parent.
3800 the changes in that changeset relative to its first parent.
3801
3801
3802 Without the -a/--text option, diff will avoid generating diffs of
3802 Without the -a/--text option, diff will avoid generating diffs of
3803 files it detects as binary. With -a, diff will generate a diff
3803 files it detects as binary. With -a, diff will generate a diff
3804 anyway, probably with undesirable results.
3804 anyway, probably with undesirable results.
3805
3805
3806 Use the -g/--git option to generate diffs in the git extended diff
3806 Use the -g/--git option to generate diffs in the git extended diff
3807 format. For more information, read :hg:`help diffs`.
3807 format. For more information, read :hg:`help diffs`.
3808
3808
3809 .. container:: verbose
3809 .. container:: verbose
3810
3810
3811 Examples:
3811 Examples:
3812
3812
3813 - compare a file in the current working directory to its parent::
3813 - compare a file in the current working directory to its parent::
3814
3814
3815 hg diff foo.c
3815 hg diff foo.c
3816
3816
3817 - compare two historical versions of a directory, with rename info::
3817 - compare two historical versions of a directory, with rename info::
3818
3818
3819 hg diff --git -r 1.0:1.2 lib/
3819 hg diff --git -r 1.0:1.2 lib/
3820
3820
3821 - get change stats relative to the last change on some date::
3821 - get change stats relative to the last change on some date::
3822
3822
3823 hg diff --stat -r "date('may 2')"
3823 hg diff --stat -r "date('may 2')"
3824
3824
3825 - diff all newly-added files that contain a keyword::
3825 - diff all newly-added files that contain a keyword::
3826
3826
3827 hg diff "set:added() and grep(GNU)"
3827 hg diff "set:added() and grep(GNU)"
3828
3828
3829 - compare a revision and its parents::
3829 - compare a revision and its parents::
3830
3830
3831 hg diff -c 9353 # compare against first parent
3831 hg diff -c 9353 # compare against first parent
3832 hg diff -r 9353^:9353 # same using revset syntax
3832 hg diff -r 9353^:9353 # same using revset syntax
3833 hg diff -r 9353^2:9353 # compare against the second parent
3833 hg diff -r 9353^2:9353 # compare against the second parent
3834
3834
3835 Returns 0 on success.
3835 Returns 0 on success.
3836 """
3836 """
3837
3837
3838 revs = opts.get('rev')
3838 revs = opts.get('rev')
3839 change = opts.get('change')
3839 change = opts.get('change')
3840 stat = opts.get('stat')
3840 stat = opts.get('stat')
3841 reverse = opts.get('reverse')
3841 reverse = opts.get('reverse')
3842
3842
3843 if revs and change:
3843 if revs and change:
3844 msg = _('cannot specify --rev and --change at the same time')
3844 msg = _('cannot specify --rev and --change at the same time')
3845 raise error.Abort(msg)
3845 raise error.Abort(msg)
3846 elif change:
3846 elif change:
3847 node2 = scmutil.revsingle(repo, change, None).node()
3847 node2 = scmutil.revsingle(repo, change, None).node()
3848 node1 = repo[node2].p1().node()
3848 node1 = repo[node2].p1().node()
3849 else:
3849 else:
3850 node1, node2 = scmutil.revpair(repo, revs)
3850 node1, node2 = scmutil.revpair(repo, revs)
3851
3851
3852 if reverse:
3852 if reverse:
3853 node1, node2 = node2, node1
3853 node1, node2 = node2, node1
3854
3854
3855 diffopts = patch.diffallopts(ui, opts)
3855 diffopts = patch.diffallopts(ui, opts)
3856 m = scmutil.match(repo[node2], pats, opts)
3856 m = scmutil.match(repo[node2], pats, opts)
3857 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3857 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3858 listsubrepos=opts.get('subrepos'),
3858 listsubrepos=opts.get('subrepos'),
3859 root=opts.get('root'))
3859 root=opts.get('root'))
3860
3860
3861 @command('^export',
3861 @command('^export',
3862 [('o', 'output', '',
3862 [('o', 'output', '',
3863 _('print output to file with formatted name'), _('FORMAT')),
3863 _('print output to file with formatted name'), _('FORMAT')),
3864 ('', 'switch-parent', None, _('diff against the second parent')),
3864 ('', 'switch-parent', None, _('diff against the second parent')),
3865 ('r', 'rev', [], _('revisions to export'), _('REV')),
3865 ('r', 'rev', [], _('revisions to export'), _('REV')),
3866 ] + diffopts,
3866 ] + diffopts,
3867 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3867 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3868 def export(ui, repo, *changesets, **opts):
3868 def export(ui, repo, *changesets, **opts):
3869 """dump the header and diffs for one or more changesets
3869 """dump the header and diffs for one or more changesets
3870
3870
3871 Print the changeset header and diffs for one or more revisions.
3871 Print the changeset header and diffs for one or more revisions.
3872 If no revision is given, the parent of the working directory is used.
3872 If no revision is given, the parent of the working directory is used.
3873
3873
3874 The information shown in the changeset header is: author, date,
3874 The information shown in the changeset header is: author, date,
3875 branch name (if non-default), changeset hash, parent(s) and commit
3875 branch name (if non-default), changeset hash, parent(s) and commit
3876 comment.
3876 comment.
3877
3877
3878 .. note::
3878 .. note::
3879
3879
3880 :hg:`export` may generate unexpected diff output for merge
3880 :hg:`export` may generate unexpected diff output for merge
3881 changesets, as it will compare the merge changeset against its
3881 changesets, as it will compare the merge changeset against its
3882 first parent only.
3882 first parent only.
3883
3883
3884 Output may be to a file, in which case the name of the file is
3884 Output may be to a file, in which case the name of the file is
3885 given using a format string. The formatting rules are as follows:
3885 given using a format string. The formatting rules are as follows:
3886
3886
3887 :``%%``: literal "%" character
3887 :``%%``: literal "%" character
3888 :``%H``: changeset hash (40 hexadecimal digits)
3888 :``%H``: changeset hash (40 hexadecimal digits)
3889 :``%N``: number of patches being generated
3889 :``%N``: number of patches being generated
3890 :``%R``: changeset revision number
3890 :``%R``: changeset revision number
3891 :``%b``: basename of the exporting repository
3891 :``%b``: basename of the exporting repository
3892 :``%h``: short-form changeset hash (12 hexadecimal digits)
3892 :``%h``: short-form changeset hash (12 hexadecimal digits)
3893 :``%m``: first line of the commit message (only alphanumeric characters)
3893 :``%m``: first line of the commit message (only alphanumeric characters)
3894 :``%n``: zero-padded sequence number, starting at 1
3894 :``%n``: zero-padded sequence number, starting at 1
3895 :``%r``: zero-padded changeset revision number
3895 :``%r``: zero-padded changeset revision number
3896
3896
3897 Without the -a/--text option, export will avoid generating diffs
3897 Without the -a/--text option, export will avoid generating diffs
3898 of files it detects as binary. With -a, export will generate a
3898 of files it detects as binary. With -a, export will generate a
3899 diff anyway, probably with undesirable results.
3899 diff anyway, probably with undesirable results.
3900
3900
3901 Use the -g/--git option to generate diffs in the git extended diff
3901 Use the -g/--git option to generate diffs in the git extended diff
3902 format. See :hg:`help diffs` for more information.
3902 format. See :hg:`help diffs` for more information.
3903
3903
3904 With the --switch-parent option, the diff will be against the
3904 With the --switch-parent option, the diff will be against the
3905 second parent. It can be useful to review a merge.
3905 second parent. It can be useful to review a merge.
3906
3906
3907 .. container:: verbose
3907 .. container:: verbose
3908
3908
3909 Examples:
3909 Examples:
3910
3910
3911 - use export and import to transplant a bugfix to the current
3911 - use export and import to transplant a bugfix to the current
3912 branch::
3912 branch::
3913
3913
3914 hg export -r 9353 | hg import -
3914 hg export -r 9353 | hg import -
3915
3915
3916 - export all the changesets between two revisions to a file with
3916 - export all the changesets between two revisions to a file with
3917 rename information::
3917 rename information::
3918
3918
3919 hg export --git -r 123:150 > changes.txt
3919 hg export --git -r 123:150 > changes.txt
3920
3920
3921 - split outgoing changes into a series of patches with
3921 - split outgoing changes into a series of patches with
3922 descriptive names::
3922 descriptive names::
3923
3923
3924 hg export -r "outgoing()" -o "%n-%m.patch"
3924 hg export -r "outgoing()" -o "%n-%m.patch"
3925
3925
3926 Returns 0 on success.
3926 Returns 0 on success.
3927 """
3927 """
3928 changesets += tuple(opts.get('rev', []))
3928 changesets += tuple(opts.get('rev', []))
3929 if not changesets:
3929 if not changesets:
3930 changesets = ['.']
3930 changesets = ['.']
3931 revs = scmutil.revrange(repo, changesets)
3931 revs = scmutil.revrange(repo, changesets)
3932 if not revs:
3932 if not revs:
3933 raise error.Abort(_("export requires at least one changeset"))
3933 raise error.Abort(_("export requires at least one changeset"))
3934 if len(revs) > 1:
3934 if len(revs) > 1:
3935 ui.note(_('exporting patches:\n'))
3935 ui.note(_('exporting patches:\n'))
3936 else:
3936 else:
3937 ui.note(_('exporting patch:\n'))
3937 ui.note(_('exporting patch:\n'))
3938 cmdutil.export(repo, revs, template=opts.get('output'),
3938 cmdutil.export(repo, revs, template=opts.get('output'),
3939 switch_parent=opts.get('switch_parent'),
3939 switch_parent=opts.get('switch_parent'),
3940 opts=patch.diffallopts(ui, opts))
3940 opts=patch.diffallopts(ui, opts))
3941
3941
3942 @command('files',
3942 @command('files',
3943 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3943 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3944 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3944 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3945 ] + walkopts + formatteropts + subrepoopts,
3945 ] + walkopts + formatteropts + subrepoopts,
3946 _('[OPTION]... [FILE]...'))
3946 _('[OPTION]... [FILE]...'))
3947 def files(ui, repo, *pats, **opts):
3947 def files(ui, repo, *pats, **opts):
3948 """list tracked files
3948 """list tracked files
3949
3949
3950 Print files under Mercurial control in the working directory or
3950 Print files under Mercurial control in the working directory or
3951 specified revision for given files (excluding removed files).
3951 specified revision for given files (excluding removed files).
3952 Files can be specified as filenames or filesets.
3952 Files can be specified as filenames or filesets.
3953
3953
3954 If no files are given to match, this command prints the names
3954 If no files are given to match, this command prints the names
3955 of all files under Mercurial control.
3955 of all files under Mercurial control.
3956
3956
3957 .. container:: verbose
3957 .. container:: verbose
3958
3958
3959 Examples:
3959 Examples:
3960
3960
3961 - list all files under the current directory::
3961 - list all files under the current directory::
3962
3962
3963 hg files .
3963 hg files .
3964
3964
3965 - shows sizes and flags for current revision::
3965 - shows sizes and flags for current revision::
3966
3966
3967 hg files -vr .
3967 hg files -vr .
3968
3968
3969 - list all files named README::
3969 - list all files named README::
3970
3970
3971 hg files -I "**/README"
3971 hg files -I "**/README"
3972
3972
3973 - list all binary files::
3973 - list all binary files::
3974
3974
3975 hg files "set:binary()"
3975 hg files "set:binary()"
3976
3976
3977 - find files containing a regular expression::
3977 - find files containing a regular expression::
3978
3978
3979 hg files "set:grep('bob')"
3979 hg files "set:grep('bob')"
3980
3980
3981 - search tracked file contents with xargs and grep::
3981 - search tracked file contents with xargs and grep::
3982
3982
3983 hg files -0 | xargs -0 grep foo
3983 hg files -0 | xargs -0 grep foo
3984
3984
3985 See :hg:`help patterns` and :hg:`help filesets` for more information
3985 See :hg:`help patterns` and :hg:`help filesets` for more information
3986 on specifying file patterns.
3986 on specifying file patterns.
3987
3987
3988 Returns 0 if a match is found, 1 otherwise.
3988 Returns 0 if a match is found, 1 otherwise.
3989
3989
3990 """
3990 """
3991 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3991 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3992
3992
3993 end = '\n'
3993 end = '\n'
3994 if opts.get('print0'):
3994 if opts.get('print0'):
3995 end = '\0'
3995 end = '\0'
3996 fmt = '%s' + end
3996 fmt = '%s' + end
3997
3997
3998 m = scmutil.match(ctx, pats, opts)
3998 m = scmutil.match(ctx, pats, opts)
3999 with ui.formatter('files', opts) as fm:
3999 with ui.formatter('files', opts) as fm:
4000 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
4000 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
4001
4001
4002 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
4002 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
4003 def forget(ui, repo, *pats, **opts):
4003 def forget(ui, repo, *pats, **opts):
4004 """forget the specified files on the next commit
4004 """forget the specified files on the next commit
4005
4005
4006 Mark the specified files so they will no longer be tracked
4006 Mark the specified files so they will no longer be tracked
4007 after the next commit.
4007 after the next commit.
4008
4008
4009 This only removes files from the current branch, not from the
4009 This only removes files from the current branch, not from the
4010 entire project history, and it does not delete them from the
4010 entire project history, and it does not delete them from the
4011 working directory.
4011 working directory.
4012
4012
4013 To delete the file from the working directory, see :hg:`remove`.
4013 To delete the file from the working directory, see :hg:`remove`.
4014
4014
4015 To undo a forget before the next commit, see :hg:`add`.
4015 To undo a forget before the next commit, see :hg:`add`.
4016
4016
4017 .. container:: verbose
4017 .. container:: verbose
4018
4018
4019 Examples:
4019 Examples:
4020
4020
4021 - forget newly-added binary files::
4021 - forget newly-added binary files::
4022
4022
4023 hg forget "set:added() and binary()"
4023 hg forget "set:added() and binary()"
4024
4024
4025 - forget files that would be excluded by .hgignore::
4025 - forget files that would be excluded by .hgignore::
4026
4026
4027 hg forget "set:hgignore()"
4027 hg forget "set:hgignore()"
4028
4028
4029 Returns 0 on success.
4029 Returns 0 on success.
4030 """
4030 """
4031
4031
4032 if not pats:
4032 if not pats:
4033 raise error.Abort(_('no files specified'))
4033 raise error.Abort(_('no files specified'))
4034
4034
4035 m = scmutil.match(repo[None], pats, opts)
4035 m = scmutil.match(repo[None], pats, opts)
4036 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4036 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4037 return rejected and 1 or 0
4037 return rejected and 1 or 0
4038
4038
4039 @command(
4039 @command(
4040 'graft',
4040 'graft',
4041 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4041 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4042 ('c', 'continue', False, _('resume interrupted graft')),
4042 ('c', 'continue', False, _('resume interrupted graft')),
4043 ('e', 'edit', False, _('invoke editor on commit messages')),
4043 ('e', 'edit', False, _('invoke editor on commit messages')),
4044 ('', 'log', None, _('append graft info to log message')),
4044 ('', 'log', None, _('append graft info to log message')),
4045 ('f', 'force', False, _('force graft')),
4045 ('f', 'force', False, _('force graft')),
4046 ('D', 'currentdate', False,
4046 ('D', 'currentdate', False,
4047 _('record the current date as commit date')),
4047 _('record the current date as commit date')),
4048 ('U', 'currentuser', False,
4048 ('U', 'currentuser', False,
4049 _('record the current user as committer'), _('DATE'))]
4049 _('record the current user as committer'), _('DATE'))]
4050 + commitopts2 + mergetoolopts + dryrunopts,
4050 + commitopts2 + mergetoolopts + dryrunopts,
4051 _('[OPTION]... [-r REV]... REV...'))
4051 _('[OPTION]... [-r REV]... REV...'))
4052 def graft(ui, repo, *revs, **opts):
4052 def graft(ui, repo, *revs, **opts):
4053 '''copy changes from other branches onto the current branch
4053 '''copy changes from other branches onto the current branch
4054
4054
4055 This command uses Mercurial's merge logic to copy individual
4055 This command uses Mercurial's merge logic to copy individual
4056 changes from other branches without merging branches in the
4056 changes from other branches without merging branches in the
4057 history graph. This is sometimes known as 'backporting' or
4057 history graph. This is sometimes known as 'backporting' or
4058 'cherry-picking'. By default, graft will copy user, date, and
4058 'cherry-picking'. By default, graft will copy user, date, and
4059 description from the source changesets.
4059 description from the source changesets.
4060
4060
4061 Changesets that are ancestors of the current revision, that have
4061 Changesets that are ancestors of the current revision, that have
4062 already been grafted, or that are merges will be skipped.
4062 already been grafted, or that are merges will be skipped.
4063
4063
4064 If --log is specified, log messages will have a comment appended
4064 If --log is specified, log messages will have a comment appended
4065 of the form::
4065 of the form::
4066
4066
4067 (grafted from CHANGESETHASH)
4067 (grafted from CHANGESETHASH)
4068
4068
4069 If --force is specified, revisions will be grafted even if they
4069 If --force is specified, revisions will be grafted even if they
4070 are already ancestors of or have been grafted to the destination.
4070 are already ancestors of or have been grafted to the destination.
4071 This is useful when the revisions have since been backed out.
4071 This is useful when the revisions have since been backed out.
4072
4072
4073 If a graft merge results in conflicts, the graft process is
4073 If a graft merge results in conflicts, the graft process is
4074 interrupted so that the current merge can be manually resolved.
4074 interrupted so that the current merge can be manually resolved.
4075 Once all conflicts are addressed, the graft process can be
4075 Once all conflicts are addressed, the graft process can be
4076 continued with the -c/--continue option.
4076 continued with the -c/--continue option.
4077
4077
4078 .. note::
4078 .. note::
4079
4079
4080 The -c/--continue option does not reapply earlier options, except
4080 The -c/--continue option does not reapply earlier options, except
4081 for --force.
4081 for --force.
4082
4082
4083 .. container:: verbose
4083 .. container:: verbose
4084
4084
4085 Examples:
4085 Examples:
4086
4086
4087 - copy a single change to the stable branch and edit its description::
4087 - copy a single change to the stable branch and edit its description::
4088
4088
4089 hg update stable
4089 hg update stable
4090 hg graft --edit 9393
4090 hg graft --edit 9393
4091
4091
4092 - graft a range of changesets with one exception, updating dates::
4092 - graft a range of changesets with one exception, updating dates::
4093
4093
4094 hg graft -D "2085::2093 and not 2091"
4094 hg graft -D "2085::2093 and not 2091"
4095
4095
4096 - continue a graft after resolving conflicts::
4096 - continue a graft after resolving conflicts::
4097
4097
4098 hg graft -c
4098 hg graft -c
4099
4099
4100 - show the source of a grafted changeset::
4100 - show the source of a grafted changeset::
4101
4101
4102 hg log --debug -r .
4102 hg log --debug -r .
4103
4103
4104 - show revisions sorted by date::
4104 - show revisions sorted by date::
4105
4105
4106 hg log -r "sort(all(), date)"
4106 hg log -r "sort(all(), date)"
4107
4107
4108 See :hg:`help revisions` and :hg:`help revsets` for more about
4108 See :hg:`help revisions` and :hg:`help revsets` for more about
4109 specifying revisions.
4109 specifying revisions.
4110
4110
4111 Returns 0 on successful completion.
4111 Returns 0 on successful completion.
4112 '''
4112 '''
4113 with repo.wlock():
4113 with repo.wlock():
4114 return _dograft(ui, repo, *revs, **opts)
4114 return _dograft(ui, repo, *revs, **opts)
4115
4115
4116 def _dograft(ui, repo, *revs, **opts):
4116 def _dograft(ui, repo, *revs, **opts):
4117 if revs and opts.get('rev'):
4117 if revs and opts.get('rev'):
4118 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4118 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4119 'revision ordering!\n'))
4119 'revision ordering!\n'))
4120
4120
4121 revs = list(revs)
4121 revs = list(revs)
4122 revs.extend(opts.get('rev'))
4122 revs.extend(opts.get('rev'))
4123
4123
4124 if not opts.get('user') and opts.get('currentuser'):
4124 if not opts.get('user') and opts.get('currentuser'):
4125 opts['user'] = ui.username()
4125 opts['user'] = ui.username()
4126 if not opts.get('date') and opts.get('currentdate'):
4126 if not opts.get('date') and opts.get('currentdate'):
4127 opts['date'] = "%d %d" % util.makedate()
4127 opts['date'] = "%d %d" % util.makedate()
4128
4128
4129 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4129 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4130
4130
4131 cont = False
4131 cont = False
4132 if opts.get('continue'):
4132 if opts.get('continue'):
4133 cont = True
4133 cont = True
4134 if revs:
4134 if revs:
4135 raise error.Abort(_("can't specify --continue and revisions"))
4135 raise error.Abort(_("can't specify --continue and revisions"))
4136 # read in unfinished revisions
4136 # read in unfinished revisions
4137 try:
4137 try:
4138 nodes = repo.vfs.read('graftstate').splitlines()
4138 nodes = repo.vfs.read('graftstate').splitlines()
4139 revs = [repo[node].rev() for node in nodes]
4139 revs = [repo[node].rev() for node in nodes]
4140 except IOError as inst:
4140 except IOError as inst:
4141 if inst.errno != errno.ENOENT:
4141 if inst.errno != errno.ENOENT:
4142 raise
4142 raise
4143 cmdutil.wrongtooltocontinue(repo, _('graft'))
4143 cmdutil.wrongtooltocontinue(repo, _('graft'))
4144 else:
4144 else:
4145 cmdutil.checkunfinished(repo)
4145 cmdutil.checkunfinished(repo)
4146 cmdutil.bailifchanged(repo)
4146 cmdutil.bailifchanged(repo)
4147 if not revs:
4147 if not revs:
4148 raise error.Abort(_('no revisions specified'))
4148 raise error.Abort(_('no revisions specified'))
4149 revs = scmutil.revrange(repo, revs)
4149 revs = scmutil.revrange(repo, revs)
4150
4150
4151 skipped = set()
4151 skipped = set()
4152 # check for merges
4152 # check for merges
4153 for rev in repo.revs('%ld and merge()', revs):
4153 for rev in repo.revs('%ld and merge()', revs):
4154 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4154 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4155 skipped.add(rev)
4155 skipped.add(rev)
4156 revs = [r for r in revs if r not in skipped]
4156 revs = [r for r in revs if r not in skipped]
4157 if not revs:
4157 if not revs:
4158 return -1
4158 return -1
4159
4159
4160 # Don't check in the --continue case, in effect retaining --force across
4160 # Don't check in the --continue case, in effect retaining --force across
4161 # --continues. That's because without --force, any revisions we decided to
4161 # --continues. That's because without --force, any revisions we decided to
4162 # skip would have been filtered out here, so they wouldn't have made their
4162 # skip would have been filtered out here, so they wouldn't have made their
4163 # way to the graftstate. With --force, any revisions we would have otherwise
4163 # way to the graftstate. With --force, any revisions we would have otherwise
4164 # skipped would not have been filtered out, and if they hadn't been applied
4164 # skipped would not have been filtered out, and if they hadn't been applied
4165 # already, they'd have been in the graftstate.
4165 # already, they'd have been in the graftstate.
4166 if not (cont or opts.get('force')):
4166 if not (cont or opts.get('force')):
4167 # check for ancestors of dest branch
4167 # check for ancestors of dest branch
4168 crev = repo['.'].rev()
4168 crev = repo['.'].rev()
4169 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4169 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4170 # XXX make this lazy in the future
4170 # XXX make this lazy in the future
4171 # don't mutate while iterating, create a copy
4171 # don't mutate while iterating, create a copy
4172 for rev in list(revs):
4172 for rev in list(revs):
4173 if rev in ancestors:
4173 if rev in ancestors:
4174 ui.warn(_('skipping ancestor revision %d:%s\n') %
4174 ui.warn(_('skipping ancestor revision %d:%s\n') %
4175 (rev, repo[rev]))
4175 (rev, repo[rev]))
4176 # XXX remove on list is slow
4176 # XXX remove on list is slow
4177 revs.remove(rev)
4177 revs.remove(rev)
4178 if not revs:
4178 if not revs:
4179 return -1
4179 return -1
4180
4180
4181 # analyze revs for earlier grafts
4181 # analyze revs for earlier grafts
4182 ids = {}
4182 ids = {}
4183 for ctx in repo.set("%ld", revs):
4183 for ctx in repo.set("%ld", revs):
4184 ids[ctx.hex()] = ctx.rev()
4184 ids[ctx.hex()] = ctx.rev()
4185 n = ctx.extra().get('source')
4185 n = ctx.extra().get('source')
4186 if n:
4186 if n:
4187 ids[n] = ctx.rev()
4187 ids[n] = ctx.rev()
4188
4188
4189 # check ancestors for earlier grafts
4189 # check ancestors for earlier grafts
4190 ui.debug('scanning for duplicate grafts\n')
4190 ui.debug('scanning for duplicate grafts\n')
4191
4191
4192 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4192 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4193 ctx = repo[rev]
4193 ctx = repo[rev]
4194 n = ctx.extra().get('source')
4194 n = ctx.extra().get('source')
4195 if n in ids:
4195 if n in ids:
4196 try:
4196 try:
4197 r = repo[n].rev()
4197 r = repo[n].rev()
4198 except error.RepoLookupError:
4198 except error.RepoLookupError:
4199 r = None
4199 r = None
4200 if r in revs:
4200 if r in revs:
4201 ui.warn(_('skipping revision %d:%s '
4201 ui.warn(_('skipping revision %d:%s '
4202 '(already grafted to %d:%s)\n')
4202 '(already grafted to %d:%s)\n')
4203 % (r, repo[r], rev, ctx))
4203 % (r, repo[r], rev, ctx))
4204 revs.remove(r)
4204 revs.remove(r)
4205 elif ids[n] in revs:
4205 elif ids[n] in revs:
4206 if r is None:
4206 if r is None:
4207 ui.warn(_('skipping already grafted revision %d:%s '
4207 ui.warn(_('skipping already grafted revision %d:%s '
4208 '(%d:%s also has unknown origin %s)\n')
4208 '(%d:%s also has unknown origin %s)\n')
4209 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4209 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4210 else:
4210 else:
4211 ui.warn(_('skipping already grafted revision %d:%s '
4211 ui.warn(_('skipping already grafted revision %d:%s '
4212 '(%d:%s also has origin %d:%s)\n')
4212 '(%d:%s also has origin %d:%s)\n')
4213 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4213 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4214 revs.remove(ids[n])
4214 revs.remove(ids[n])
4215 elif ctx.hex() in ids:
4215 elif ctx.hex() in ids:
4216 r = ids[ctx.hex()]
4216 r = ids[ctx.hex()]
4217 ui.warn(_('skipping already grafted revision %d:%s '
4217 ui.warn(_('skipping already grafted revision %d:%s '
4218 '(was grafted from %d:%s)\n') %
4218 '(was grafted from %d:%s)\n') %
4219 (r, repo[r], rev, ctx))
4219 (r, repo[r], rev, ctx))
4220 revs.remove(r)
4220 revs.remove(r)
4221 if not revs:
4221 if not revs:
4222 return -1
4222 return -1
4223
4223
4224 for pos, ctx in enumerate(repo.set("%ld", revs)):
4224 for pos, ctx in enumerate(repo.set("%ld", revs)):
4225 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4225 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4226 ctx.description().split('\n', 1)[0])
4226 ctx.description().split('\n', 1)[0])
4227 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4227 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4228 if names:
4228 if names:
4229 desc += ' (%s)' % ' '.join(names)
4229 desc += ' (%s)' % ' '.join(names)
4230 ui.status(_('grafting %s\n') % desc)
4230 ui.status(_('grafting %s\n') % desc)
4231 if opts.get('dry_run'):
4231 if opts.get('dry_run'):
4232 continue
4232 continue
4233
4233
4234 source = ctx.extra().get('source')
4234 source = ctx.extra().get('source')
4235 extra = {}
4235 extra = {}
4236 if source:
4236 if source:
4237 extra['source'] = source
4237 extra['source'] = source
4238 extra['intermediate-source'] = ctx.hex()
4238 extra['intermediate-source'] = ctx.hex()
4239 else:
4239 else:
4240 extra['source'] = ctx.hex()
4240 extra['source'] = ctx.hex()
4241 user = ctx.user()
4241 user = ctx.user()
4242 if opts.get('user'):
4242 if opts.get('user'):
4243 user = opts['user']
4243 user = opts['user']
4244 date = ctx.date()
4244 date = ctx.date()
4245 if opts.get('date'):
4245 if opts.get('date'):
4246 date = opts['date']
4246 date = opts['date']
4247 message = ctx.description()
4247 message = ctx.description()
4248 if opts.get('log'):
4248 if opts.get('log'):
4249 message += '\n(grafted from %s)' % ctx.hex()
4249 message += '\n(grafted from %s)' % ctx.hex()
4250
4250
4251 # we don't merge the first commit when continuing
4251 # we don't merge the first commit when continuing
4252 if not cont:
4252 if not cont:
4253 # perform the graft merge with p1(rev) as 'ancestor'
4253 # perform the graft merge with p1(rev) as 'ancestor'
4254 try:
4254 try:
4255 # ui.forcemerge is an internal variable, do not document
4255 # ui.forcemerge is an internal variable, do not document
4256 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4256 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4257 'graft')
4257 'graft')
4258 stats = mergemod.graft(repo, ctx, ctx.p1(),
4258 stats = mergemod.graft(repo, ctx, ctx.p1(),
4259 ['local', 'graft'])
4259 ['local', 'graft'])
4260 finally:
4260 finally:
4261 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4261 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4262 # report any conflicts
4262 # report any conflicts
4263 if stats and stats[3] > 0:
4263 if stats and stats[3] > 0:
4264 # write out state for --continue
4264 # write out state for --continue
4265 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4265 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4266 repo.vfs.write('graftstate', ''.join(nodelines))
4266 repo.vfs.write('graftstate', ''.join(nodelines))
4267 extra = ''
4267 extra = ''
4268 if opts.get('user'):
4268 if opts.get('user'):
4269 extra += ' --user %s' % util.shellquote(opts['user'])
4269 extra += ' --user %s' % util.shellquote(opts['user'])
4270 if opts.get('date'):
4270 if opts.get('date'):
4271 extra += ' --date %s' % util.shellquote(opts['date'])
4271 extra += ' --date %s' % util.shellquote(opts['date'])
4272 if opts.get('log'):
4272 if opts.get('log'):
4273 extra += ' --log'
4273 extra += ' --log'
4274 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4274 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4275 raise error.Abort(
4275 raise error.Abort(
4276 _("unresolved conflicts, can't continue"),
4276 _("unresolved conflicts, can't continue"),
4277 hint=hint)
4277 hint=hint)
4278 else:
4278 else:
4279 cont = False
4279 cont = False
4280
4280
4281 # commit
4281 # commit
4282 node = repo.commit(text=message, user=user,
4282 node = repo.commit(text=message, user=user,
4283 date=date, extra=extra, editor=editor)
4283 date=date, extra=extra, editor=editor)
4284 if node is None:
4284 if node is None:
4285 ui.warn(
4285 ui.warn(
4286 _('note: graft of %d:%s created no changes to commit\n') %
4286 _('note: graft of %d:%s created no changes to commit\n') %
4287 (ctx.rev(), ctx))
4287 (ctx.rev(), ctx))
4288
4288
4289 # remove state when we complete successfully
4289 # remove state when we complete successfully
4290 if not opts.get('dry_run'):
4290 if not opts.get('dry_run'):
4291 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4291 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4292
4292
4293 return 0
4293 return 0
4294
4294
4295 @command('grep',
4295 @command('grep',
4296 [('0', 'print0', None, _('end fields with NUL')),
4296 [('0', 'print0', None, _('end fields with NUL')),
4297 ('', 'all', None, _('print all revisions that match')),
4297 ('', 'all', None, _('print all revisions that match')),
4298 ('a', 'text', None, _('treat all files as text')),
4298 ('a', 'text', None, _('treat all files as text')),
4299 ('f', 'follow', None,
4299 ('f', 'follow', None,
4300 _('follow changeset history,'
4300 _('follow changeset history,'
4301 ' or file history across copies and renames')),
4301 ' or file history across copies and renames')),
4302 ('i', 'ignore-case', None, _('ignore case when matching')),
4302 ('i', 'ignore-case', None, _('ignore case when matching')),
4303 ('l', 'files-with-matches', None,
4303 ('l', 'files-with-matches', None,
4304 _('print only filenames and revisions that match')),
4304 _('print only filenames and revisions that match')),
4305 ('n', 'line-number', None, _('print matching line numbers')),
4305 ('n', 'line-number', None, _('print matching line numbers')),
4306 ('r', 'rev', [],
4306 ('r', 'rev', [],
4307 _('only search files changed within revision range'), _('REV')),
4307 _('only search files changed within revision range'), _('REV')),
4308 ('u', 'user', None, _('list the author (long with -v)')),
4308 ('u', 'user', None, _('list the author (long with -v)')),
4309 ('d', 'date', None, _('list the date (short with -q)')),
4309 ('d', 'date', None, _('list the date (short with -q)')),
4310 ] + formatteropts + walkopts,
4310 ] + formatteropts + walkopts,
4311 _('[OPTION]... PATTERN [FILE]...'),
4311 _('[OPTION]... PATTERN [FILE]...'),
4312 inferrepo=True)
4312 inferrepo=True)
4313 def grep(ui, repo, pattern, *pats, **opts):
4313 def grep(ui, repo, pattern, *pats, **opts):
4314 """search revision history for a pattern in specified files
4314 """search revision history for a pattern in specified files
4315
4315
4316 Search revision history for a regular expression in the specified
4316 Search revision history for a regular expression in the specified
4317 files or the entire project.
4317 files or the entire project.
4318
4318
4319 By default, grep prints the most recent revision number for each
4319 By default, grep prints the most recent revision number for each
4320 file in which it finds a match. To get it to print every revision
4320 file in which it finds a match. To get it to print every revision
4321 that contains a change in match status ("-" for a match that becomes
4321 that contains a change in match status ("-" for a match that becomes
4322 a non-match, or "+" for a non-match that becomes a match), use the
4322 a non-match, or "+" for a non-match that becomes a match), use the
4323 --all flag.
4323 --all flag.
4324
4324
4325 PATTERN can be any Python (roughly Perl-compatible) regular
4325 PATTERN can be any Python (roughly Perl-compatible) regular
4326 expression.
4326 expression.
4327
4327
4328 If no FILEs are specified (and -f/--follow isn't set), all files in
4328 If no FILEs are specified (and -f/--follow isn't set), all files in
4329 the repository are searched, including those that don't exist in the
4329 the repository are searched, including those that don't exist in the
4330 current branch or have been deleted in a prior changeset.
4330 current branch or have been deleted in a prior changeset.
4331
4331
4332 Returns 0 if a match is found, 1 otherwise.
4332 Returns 0 if a match is found, 1 otherwise.
4333 """
4333 """
4334 reflags = re.M
4334 reflags = re.M
4335 if opts.get('ignore_case'):
4335 if opts.get('ignore_case'):
4336 reflags |= re.I
4336 reflags |= re.I
4337 try:
4337 try:
4338 regexp = util.re.compile(pattern, reflags)
4338 regexp = util.re.compile(pattern, reflags)
4339 except re.error as inst:
4339 except re.error as inst:
4340 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4340 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4341 return 1
4341 return 1
4342 sep, eol = ':', '\n'
4342 sep, eol = ':', '\n'
4343 if opts.get('print0'):
4343 if opts.get('print0'):
4344 sep = eol = '\0'
4344 sep = eol = '\0'
4345
4345
4346 getfile = util.lrucachefunc(repo.file)
4346 getfile = util.lrucachefunc(repo.file)
4347
4347
4348 def matchlines(body):
4348 def matchlines(body):
4349 begin = 0
4349 begin = 0
4350 linenum = 0
4350 linenum = 0
4351 while begin < len(body):
4351 while begin < len(body):
4352 match = regexp.search(body, begin)
4352 match = regexp.search(body, begin)
4353 if not match:
4353 if not match:
4354 break
4354 break
4355 mstart, mend = match.span()
4355 mstart, mend = match.span()
4356 linenum += body.count('\n', begin, mstart) + 1
4356 linenum += body.count('\n', begin, mstart) + 1
4357 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4357 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4358 begin = body.find('\n', mend) + 1 or len(body) + 1
4358 begin = body.find('\n', mend) + 1 or len(body) + 1
4359 lend = begin - 1
4359 lend = begin - 1
4360 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4360 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4361
4361
4362 class linestate(object):
4362 class linestate(object):
4363 def __init__(self, line, linenum, colstart, colend):
4363 def __init__(self, line, linenum, colstart, colend):
4364 self.line = line
4364 self.line = line
4365 self.linenum = linenum
4365 self.linenum = linenum
4366 self.colstart = colstart
4366 self.colstart = colstart
4367 self.colend = colend
4367 self.colend = colend
4368
4368
4369 def __hash__(self):
4369 def __hash__(self):
4370 return hash((self.linenum, self.line))
4370 return hash((self.linenum, self.line))
4371
4371
4372 def __eq__(self, other):
4372 def __eq__(self, other):
4373 return self.line == other.line
4373 return self.line == other.line
4374
4374
4375 def findpos(self):
4375 def findpos(self):
4376 """Iterate all (start, end) indices of matches"""
4376 """Iterate all (start, end) indices of matches"""
4377 yield self.colstart, self.colend
4377 yield self.colstart, self.colend
4378 p = self.colend
4378 p = self.colend
4379 while p < len(self.line):
4379 while p < len(self.line):
4380 m = regexp.search(self.line, p)
4380 m = regexp.search(self.line, p)
4381 if not m:
4381 if not m:
4382 break
4382 break
4383 yield m.span()
4383 yield m.span()
4384 p = m.end()
4384 p = m.end()
4385
4385
4386 matches = {}
4386 matches = {}
4387 copies = {}
4387 copies = {}
4388 def grepbody(fn, rev, body):
4388 def grepbody(fn, rev, body):
4389 matches[rev].setdefault(fn, [])
4389 matches[rev].setdefault(fn, [])
4390 m = matches[rev][fn]
4390 m = matches[rev][fn]
4391 for lnum, cstart, cend, line in matchlines(body):
4391 for lnum, cstart, cend, line in matchlines(body):
4392 s = linestate(line, lnum, cstart, cend)
4392 s = linestate(line, lnum, cstart, cend)
4393 m.append(s)
4393 m.append(s)
4394
4394
4395 def difflinestates(a, b):
4395 def difflinestates(a, b):
4396 sm = difflib.SequenceMatcher(None, a, b)
4396 sm = difflib.SequenceMatcher(None, a, b)
4397 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4397 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4398 if tag == 'insert':
4398 if tag == 'insert':
4399 for i in xrange(blo, bhi):
4399 for i in xrange(blo, bhi):
4400 yield ('+', b[i])
4400 yield ('+', b[i])
4401 elif tag == 'delete':
4401 elif tag == 'delete':
4402 for i in xrange(alo, ahi):
4402 for i in xrange(alo, ahi):
4403 yield ('-', a[i])
4403 yield ('-', a[i])
4404 elif tag == 'replace':
4404 elif tag == 'replace':
4405 for i in xrange(alo, ahi):
4405 for i in xrange(alo, ahi):
4406 yield ('-', a[i])
4406 yield ('-', a[i])
4407 for i in xrange(blo, bhi):
4407 for i in xrange(blo, bhi):
4408 yield ('+', b[i])
4408 yield ('+', b[i])
4409
4409
4410 def display(fm, fn, ctx, pstates, states):
4410 def display(fm, fn, ctx, pstates, states):
4411 rev = ctx.rev()
4411 rev = ctx.rev()
4412 if fm.isplain():
4412 if fm.isplain():
4413 formatuser = ui.shortuser
4413 formatuser = ui.shortuser
4414 else:
4414 else:
4415 formatuser = str
4415 formatuser = str
4416 if ui.quiet:
4416 if ui.quiet:
4417 datefmt = '%Y-%m-%d'
4417 datefmt = '%Y-%m-%d'
4418 else:
4418 else:
4419 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4419 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4420 found = False
4420 found = False
4421 @util.cachefunc
4421 @util.cachefunc
4422 def binary():
4422 def binary():
4423 flog = getfile(fn)
4423 flog = getfile(fn)
4424 return util.binary(flog.read(ctx.filenode(fn)))
4424 return util.binary(flog.read(ctx.filenode(fn)))
4425
4425
4426 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4426 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4427 if opts.get('all'):
4427 if opts.get('all'):
4428 iter = difflinestates(pstates, states)
4428 iter = difflinestates(pstates, states)
4429 else:
4429 else:
4430 iter = [('', l) for l in states]
4430 iter = [('', l) for l in states]
4431 for change, l in iter:
4431 for change, l in iter:
4432 fm.startitem()
4432 fm.startitem()
4433 fm.data(node=fm.hexfunc(ctx.node()))
4433 fm.data(node=fm.hexfunc(ctx.node()))
4434 cols = [
4434 cols = [
4435 ('filename', fn, True),
4435 ('filename', fn, True),
4436 ('rev', rev, True),
4436 ('rev', rev, True),
4437 ('linenumber', l.linenum, opts.get('line_number')),
4437 ('linenumber', l.linenum, opts.get('line_number')),
4438 ]
4438 ]
4439 if opts.get('all'):
4439 if opts.get('all'):
4440 cols.append(('change', change, True))
4440 cols.append(('change', change, True))
4441 cols.extend([
4441 cols.extend([
4442 ('user', formatuser(ctx.user()), opts.get('user')),
4442 ('user', formatuser(ctx.user()), opts.get('user')),
4443 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4443 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4444 ])
4444 ])
4445 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4445 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4446 for name, data, cond in cols:
4446 for name, data, cond in cols:
4447 field = fieldnamemap.get(name, name)
4447 field = fieldnamemap.get(name, name)
4448 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4448 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4449 if cond and name != lastcol:
4449 if cond and name != lastcol:
4450 fm.plain(sep, label='grep.sep')
4450 fm.plain(sep, label='grep.sep')
4451 if not opts.get('files_with_matches'):
4451 if not opts.get('files_with_matches'):
4452 fm.plain(sep, label='grep.sep')
4452 fm.plain(sep, label='grep.sep')
4453 if not opts.get('text') and binary():
4453 if not opts.get('text') and binary():
4454 fm.plain(_(" Binary file matches"))
4454 fm.plain(_(" Binary file matches"))
4455 else:
4455 else:
4456 displaymatches(fm.nested('texts'), l)
4456 displaymatches(fm.nested('texts'), l)
4457 fm.plain(eol)
4457 fm.plain(eol)
4458 found = True
4458 found = True
4459 if opts.get('files_with_matches'):
4459 if opts.get('files_with_matches'):
4460 break
4460 break
4461 return found
4461 return found
4462
4462
4463 def displaymatches(fm, l):
4463 def displaymatches(fm, l):
4464 p = 0
4464 p = 0
4465 for s, e in l.findpos():
4465 for s, e in l.findpos():
4466 if p < s:
4466 if p < s:
4467 fm.startitem()
4467 fm.startitem()
4468 fm.write('text', '%s', l.line[p:s])
4468 fm.write('text', '%s', l.line[p:s])
4469 fm.data(matched=False)
4469 fm.data(matched=False)
4470 fm.startitem()
4470 fm.startitem()
4471 fm.write('text', '%s', l.line[s:e], label='grep.match')
4471 fm.write('text', '%s', l.line[s:e], label='grep.match')
4472 fm.data(matched=True)
4472 fm.data(matched=True)
4473 p = e
4473 p = e
4474 if p < len(l.line):
4474 if p < len(l.line):
4475 fm.startitem()
4475 fm.startitem()
4476 fm.write('text', '%s', l.line[p:])
4476 fm.write('text', '%s', l.line[p:])
4477 fm.data(matched=False)
4477 fm.data(matched=False)
4478 fm.end()
4478 fm.end()
4479
4479
4480 skip = {}
4480 skip = {}
4481 revfiles = {}
4481 revfiles = {}
4482 matchfn = scmutil.match(repo[None], pats, opts)
4482 matchfn = scmutil.match(repo[None], pats, opts)
4483 found = False
4483 found = False
4484 follow = opts.get('follow')
4484 follow = opts.get('follow')
4485
4485
4486 def prep(ctx, fns):
4486 def prep(ctx, fns):
4487 rev = ctx.rev()
4487 rev = ctx.rev()
4488 pctx = ctx.p1()
4488 pctx = ctx.p1()
4489 parent = pctx.rev()
4489 parent = pctx.rev()
4490 matches.setdefault(rev, {})
4490 matches.setdefault(rev, {})
4491 matches.setdefault(parent, {})
4491 matches.setdefault(parent, {})
4492 files = revfiles.setdefault(rev, [])
4492 files = revfiles.setdefault(rev, [])
4493 for fn in fns:
4493 for fn in fns:
4494 flog = getfile(fn)
4494 flog = getfile(fn)
4495 try:
4495 try:
4496 fnode = ctx.filenode(fn)
4496 fnode = ctx.filenode(fn)
4497 except error.LookupError:
4497 except error.LookupError:
4498 continue
4498 continue
4499
4499
4500 copied = flog.renamed(fnode)
4500 copied = flog.renamed(fnode)
4501 copy = follow and copied and copied[0]
4501 copy = follow and copied and copied[0]
4502 if copy:
4502 if copy:
4503 copies.setdefault(rev, {})[fn] = copy
4503 copies.setdefault(rev, {})[fn] = copy
4504 if fn in skip:
4504 if fn in skip:
4505 if copy:
4505 if copy:
4506 skip[copy] = True
4506 skip[copy] = True
4507 continue
4507 continue
4508 files.append(fn)
4508 files.append(fn)
4509
4509
4510 if fn not in matches[rev]:
4510 if fn not in matches[rev]:
4511 grepbody(fn, rev, flog.read(fnode))
4511 grepbody(fn, rev, flog.read(fnode))
4512
4512
4513 pfn = copy or fn
4513 pfn = copy or fn
4514 if pfn not in matches[parent]:
4514 if pfn not in matches[parent]:
4515 try:
4515 try:
4516 fnode = pctx.filenode(pfn)
4516 fnode = pctx.filenode(pfn)
4517 grepbody(pfn, parent, flog.read(fnode))
4517 grepbody(pfn, parent, flog.read(fnode))
4518 except error.LookupError:
4518 except error.LookupError:
4519 pass
4519 pass
4520
4520
4521 fm = ui.formatter('grep', opts)
4521 fm = ui.formatter('grep', opts)
4522 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4522 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4523 rev = ctx.rev()
4523 rev = ctx.rev()
4524 parent = ctx.p1().rev()
4524 parent = ctx.p1().rev()
4525 for fn in sorted(revfiles.get(rev, [])):
4525 for fn in sorted(revfiles.get(rev, [])):
4526 states = matches[rev][fn]
4526 states = matches[rev][fn]
4527 copy = copies.get(rev, {}).get(fn)
4527 copy = copies.get(rev, {}).get(fn)
4528 if fn in skip:
4528 if fn in skip:
4529 if copy:
4529 if copy:
4530 skip[copy] = True
4530 skip[copy] = True
4531 continue
4531 continue
4532 pstates = matches.get(parent, {}).get(copy or fn, [])
4532 pstates = matches.get(parent, {}).get(copy or fn, [])
4533 if pstates or states:
4533 if pstates or states:
4534 r = display(fm, fn, ctx, pstates, states)
4534 r = display(fm, fn, ctx, pstates, states)
4535 found = found or r
4535 found = found or r
4536 if r and not opts.get('all'):
4536 if r and not opts.get('all'):
4537 skip[fn] = True
4537 skip[fn] = True
4538 if copy:
4538 if copy:
4539 skip[copy] = True
4539 skip[copy] = True
4540 del matches[rev]
4540 del matches[rev]
4541 del revfiles[rev]
4541 del revfiles[rev]
4542 fm.end()
4542 fm.end()
4543
4543
4544 return not found
4544 return not found
4545
4545
4546 @command('heads',
4546 @command('heads',
4547 [('r', 'rev', '',
4547 [('r', 'rev', '',
4548 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4548 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4549 ('t', 'topo', False, _('show topological heads only')),
4549 ('t', 'topo', False, _('show topological heads only')),
4550 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4550 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4551 ('c', 'closed', False, _('show normal and closed branch heads')),
4551 ('c', 'closed', False, _('show normal and closed branch heads')),
4552 ] + templateopts,
4552 ] + templateopts,
4553 _('[-ct] [-r STARTREV] [REV]...'))
4553 _('[-ct] [-r STARTREV] [REV]...'))
4554 def heads(ui, repo, *branchrevs, **opts):
4554 def heads(ui, repo, *branchrevs, **opts):
4555 """show branch heads
4555 """show branch heads
4556
4556
4557 With no arguments, show all open branch heads in the repository.
4557 With no arguments, show all open branch heads in the repository.
4558 Branch heads are changesets that have no descendants on the
4558 Branch heads are changesets that have no descendants on the
4559 same branch. They are where development generally takes place and
4559 same branch. They are where development generally takes place and
4560 are the usual targets for update and merge operations.
4560 are the usual targets for update and merge operations.
4561
4561
4562 If one or more REVs are given, only open branch heads on the
4562 If one or more REVs are given, only open branch heads on the
4563 branches associated with the specified changesets are shown. This
4563 branches associated with the specified changesets are shown. This
4564 means that you can use :hg:`heads .` to see the heads on the
4564 means that you can use :hg:`heads .` to see the heads on the
4565 currently checked-out branch.
4565 currently checked-out branch.
4566
4566
4567 If -c/--closed is specified, also show branch heads marked closed
4567 If -c/--closed is specified, also show branch heads marked closed
4568 (see :hg:`commit --close-branch`).
4568 (see :hg:`commit --close-branch`).
4569
4569
4570 If STARTREV is specified, only those heads that are descendants of
4570 If STARTREV is specified, only those heads that are descendants of
4571 STARTREV will be displayed.
4571 STARTREV will be displayed.
4572
4572
4573 If -t/--topo is specified, named branch mechanics will be ignored and only
4573 If -t/--topo is specified, named branch mechanics will be ignored and only
4574 topological heads (changesets with no children) will be shown.
4574 topological heads (changesets with no children) will be shown.
4575
4575
4576 Returns 0 if matching heads are found, 1 if not.
4576 Returns 0 if matching heads are found, 1 if not.
4577 """
4577 """
4578
4578
4579 start = None
4579 start = None
4580 if 'rev' in opts:
4580 if 'rev' in opts:
4581 start = scmutil.revsingle(repo, opts['rev'], None).node()
4581 start = scmutil.revsingle(repo, opts['rev'], None).node()
4582
4582
4583 if opts.get('topo'):
4583 if opts.get('topo'):
4584 heads = [repo[h] for h in repo.heads(start)]
4584 heads = [repo[h] for h in repo.heads(start)]
4585 else:
4585 else:
4586 heads = []
4586 heads = []
4587 for branch in repo.branchmap():
4587 for branch in repo.branchmap():
4588 heads += repo.branchheads(branch, start, opts.get('closed'))
4588 heads += repo.branchheads(branch, start, opts.get('closed'))
4589 heads = [repo[h] for h in heads]
4589 heads = [repo[h] for h in heads]
4590
4590
4591 if branchrevs:
4591 if branchrevs:
4592 branches = set(repo[br].branch() for br in branchrevs)
4592 branches = set(repo[br].branch() for br in branchrevs)
4593 heads = [h for h in heads if h.branch() in branches]
4593 heads = [h for h in heads if h.branch() in branches]
4594
4594
4595 if opts.get('active') and branchrevs:
4595 if opts.get('active') and branchrevs:
4596 dagheads = repo.heads(start)
4596 dagheads = repo.heads(start)
4597 heads = [h for h in heads if h.node() in dagheads]
4597 heads = [h for h in heads if h.node() in dagheads]
4598
4598
4599 if branchrevs:
4599 if branchrevs:
4600 haveheads = set(h.branch() for h in heads)
4600 haveheads = set(h.branch() for h in heads)
4601 if branches - haveheads:
4601 if branches - haveheads:
4602 headless = ', '.join(b for b in branches - haveheads)
4602 headless = ', '.join(b for b in branches - haveheads)
4603 msg = _('no open branch heads found on branches %s')
4603 msg = _('no open branch heads found on branches %s')
4604 if opts.get('rev'):
4604 if opts.get('rev'):
4605 msg += _(' (started at %s)') % opts['rev']
4605 msg += _(' (started at %s)') % opts['rev']
4606 ui.warn((msg + '\n') % headless)
4606 ui.warn((msg + '\n') % headless)
4607
4607
4608 if not heads:
4608 if not heads:
4609 return 1
4609 return 1
4610
4610
4611 heads = sorted(heads, key=lambda x: -x.rev())
4611 heads = sorted(heads, key=lambda x: -x.rev())
4612 displayer = cmdutil.show_changeset(ui, repo, opts)
4612 displayer = cmdutil.show_changeset(ui, repo, opts)
4613 for ctx in heads:
4613 for ctx in heads:
4614 displayer.show(ctx)
4614 displayer.show(ctx)
4615 displayer.close()
4615 displayer.close()
4616
4616
4617 @command('help',
4617 @command('help',
4618 [('e', 'extension', None, _('show only help for extensions')),
4618 [('e', 'extension', None, _('show only help for extensions')),
4619 ('c', 'command', None, _('show only help for commands')),
4619 ('c', 'command', None, _('show only help for commands')),
4620 ('k', 'keyword', None, _('show topics matching keyword')),
4620 ('k', 'keyword', None, _('show topics matching keyword')),
4621 ('s', 'system', [], _('show help for specific platform(s)')),
4621 ('s', 'system', [], _('show help for specific platform(s)')),
4622 ],
4622 ],
4623 _('[-ecks] [TOPIC]'),
4623 _('[-ecks] [TOPIC]'),
4624 norepo=True)
4624 norepo=True)
4625 def help_(ui, name=None, **opts):
4625 def help_(ui, name=None, **opts):
4626 """show help for a given topic or a help overview
4626 """show help for a given topic or a help overview
4627
4627
4628 With no arguments, print a list of commands with short help messages.
4628 With no arguments, print a list of commands with short help messages.
4629
4629
4630 Given a topic, extension, or command name, print help for that
4630 Given a topic, extension, or command name, print help for that
4631 topic.
4631 topic.
4632
4632
4633 Returns 0 if successful.
4633 Returns 0 if successful.
4634 """
4634 """
4635
4635
4636 textwidth = ui.configint('ui', 'textwidth', 78)
4636 textwidth = ui.configint('ui', 'textwidth', 78)
4637 termwidth = ui.termwidth() - 2
4637 termwidth = ui.termwidth() - 2
4638 if textwidth <= 0 or termwidth < textwidth:
4638 if textwidth <= 0 or termwidth < textwidth:
4639 textwidth = termwidth
4639 textwidth = termwidth
4640
4640
4641 keep = opts.get('system') or []
4641 keep = opts.get('system') or []
4642 if len(keep) == 0:
4642 if len(keep) == 0:
4643 if sys.platform.startswith('win'):
4643 if sys.platform.startswith('win'):
4644 keep.append('windows')
4644 keep.append('windows')
4645 elif sys.platform == 'OpenVMS':
4645 elif sys.platform == 'OpenVMS':
4646 keep.append('vms')
4646 keep.append('vms')
4647 elif sys.platform == 'plan9':
4647 elif sys.platform == 'plan9':
4648 keep.append('plan9')
4648 keep.append('plan9')
4649 else:
4649 else:
4650 keep.append('unix')
4650 keep.append('unix')
4651 keep.append(sys.platform.lower())
4651 keep.append(sys.platform.lower())
4652 if ui.verbose:
4652 if ui.verbose:
4653 keep.append('verbose')
4653 keep.append('verbose')
4654
4654
4655 section = None
4655 section = None
4656 subtopic = None
4656 subtopic = None
4657 if name and '.' in name:
4657 if name and '.' in name:
4658 name, remaining = name.split('.', 1)
4658 name, remaining = name.split('.', 1)
4659 remaining = encoding.lower(remaining)
4659 remaining = encoding.lower(remaining)
4660 if '.' in remaining:
4660 if '.' in remaining:
4661 subtopic, section = remaining.split('.', 1)
4661 subtopic, section = remaining.split('.', 1)
4662 else:
4662 else:
4663 if name in help.subtopics:
4663 if name in help.subtopics:
4664 subtopic = remaining
4664 subtopic = remaining
4665 else:
4665 else:
4666 section = remaining
4666 section = remaining
4667
4667
4668 text = help.help_(ui, name, subtopic=subtopic, **opts)
4668 text = help.help_(ui, name, subtopic=subtopic, **opts)
4669
4669
4670 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4670 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4671 section=section)
4671 section=section)
4672
4672
4673 # We could have been given a weird ".foo" section without a name
4673 # We could have been given a weird ".foo" section without a name
4674 # to look for, or we could have simply failed to found "foo.bar"
4674 # to look for, or we could have simply failed to found "foo.bar"
4675 # because bar isn't a section of foo
4675 # because bar isn't a section of foo
4676 if section and not (formatted and name):
4676 if section and not (formatted and name):
4677 raise error.Abort(_("help section not found"))
4677 raise error.Abort(_("help section not found"))
4678
4678
4679 if 'verbose' in pruned:
4679 if 'verbose' in pruned:
4680 keep.append('omitted')
4680 keep.append('omitted')
4681 else:
4681 else:
4682 keep.append('notomitted')
4682 keep.append('notomitted')
4683 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4683 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4684 section=section)
4684 section=section)
4685 ui.write(formatted)
4685 ui.write(formatted)
4686
4686
4687
4687
4688 @command('identify|id',
4688 @command('identify|id',
4689 [('r', 'rev', '',
4689 [('r', 'rev', '',
4690 _('identify the specified revision'), _('REV')),
4690 _('identify the specified revision'), _('REV')),
4691 ('n', 'num', None, _('show local revision number')),
4691 ('n', 'num', None, _('show local revision number')),
4692 ('i', 'id', None, _('show global revision id')),
4692 ('i', 'id', None, _('show global revision id')),
4693 ('b', 'branch', None, _('show branch')),
4693 ('b', 'branch', None, _('show branch')),
4694 ('t', 'tags', None, _('show tags')),
4694 ('t', 'tags', None, _('show tags')),
4695 ('B', 'bookmarks', None, _('show bookmarks')),
4695 ('B', 'bookmarks', None, _('show bookmarks')),
4696 ] + remoteopts,
4696 ] + remoteopts,
4697 _('[-nibtB] [-r REV] [SOURCE]'),
4697 _('[-nibtB] [-r REV] [SOURCE]'),
4698 optionalrepo=True)
4698 optionalrepo=True)
4699 def identify(ui, repo, source=None, rev=None,
4699 def identify(ui, repo, source=None, rev=None,
4700 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4700 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4701 """identify the working directory or specified revision
4701 """identify the working directory or specified revision
4702
4702
4703 Print a summary identifying the repository state at REV using one or
4703 Print a summary identifying the repository state at REV using one or
4704 two parent hash identifiers, followed by a "+" if the working
4704 two parent hash identifiers, followed by a "+" if the working
4705 directory has uncommitted changes, the branch name (if not default),
4705 directory has uncommitted changes, the branch name (if not default),
4706 a list of tags, and a list of bookmarks.
4706 a list of tags, and a list of bookmarks.
4707
4707
4708 When REV is not given, print a summary of the current state of the
4708 When REV is not given, print a summary of the current state of the
4709 repository.
4709 repository.
4710
4710
4711 Specifying a path to a repository root or Mercurial bundle will
4711 Specifying a path to a repository root or Mercurial bundle will
4712 cause lookup to operate on that repository/bundle.
4712 cause lookup to operate on that repository/bundle.
4713
4713
4714 .. container:: verbose
4714 .. container:: verbose
4715
4715
4716 Examples:
4716 Examples:
4717
4717
4718 - generate a build identifier for the working directory::
4718 - generate a build identifier for the working directory::
4719
4719
4720 hg id --id > build-id.dat
4720 hg id --id > build-id.dat
4721
4721
4722 - find the revision corresponding to a tag::
4722 - find the revision corresponding to a tag::
4723
4723
4724 hg id -n -r 1.3
4724 hg id -n -r 1.3
4725
4725
4726 - check the most recent revision of a remote repository::
4726 - check the most recent revision of a remote repository::
4727
4727
4728 hg id -r tip http://selenic.com/hg/
4728 hg id -r tip http://selenic.com/hg/
4729
4729
4730 See :hg:`log` for generating more information about specific revisions,
4730 See :hg:`log` for generating more information about specific revisions,
4731 including full hash identifiers.
4731 including full hash identifiers.
4732
4732
4733 Returns 0 if successful.
4733 Returns 0 if successful.
4734 """
4734 """
4735
4735
4736 if not repo and not source:
4736 if not repo and not source:
4737 raise error.Abort(_("there is no Mercurial repository here "
4737 raise error.Abort(_("there is no Mercurial repository here "
4738 "(.hg not found)"))
4738 "(.hg not found)"))
4739
4739
4740 if ui.debugflag:
4740 if ui.debugflag:
4741 hexfunc = hex
4741 hexfunc = hex
4742 else:
4742 else:
4743 hexfunc = short
4743 hexfunc = short
4744 default = not (num or id or branch or tags or bookmarks)
4744 default = not (num or id or branch or tags or bookmarks)
4745 output = []
4745 output = []
4746 revs = []
4746 revs = []
4747
4747
4748 if source:
4748 if source:
4749 source, branches = hg.parseurl(ui.expandpath(source))
4749 source, branches = hg.parseurl(ui.expandpath(source))
4750 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4750 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4751 repo = peer.local()
4751 repo = peer.local()
4752 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4752 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4753
4753
4754 if not repo:
4754 if not repo:
4755 if num or branch or tags:
4755 if num or branch or tags:
4756 raise error.Abort(
4756 raise error.Abort(
4757 _("can't query remote revision number, branch, or tags"))
4757 _("can't query remote revision number, branch, or tags"))
4758 if not rev and revs:
4758 if not rev and revs:
4759 rev = revs[0]
4759 rev = revs[0]
4760 if not rev:
4760 if not rev:
4761 rev = "tip"
4761 rev = "tip"
4762
4762
4763 remoterev = peer.lookup(rev)
4763 remoterev = peer.lookup(rev)
4764 if default or id:
4764 if default or id:
4765 output = [hexfunc(remoterev)]
4765 output = [hexfunc(remoterev)]
4766
4766
4767 def getbms():
4767 def getbms():
4768 bms = []
4768 bms = []
4769
4769
4770 if 'bookmarks' in peer.listkeys('namespaces'):
4770 if 'bookmarks' in peer.listkeys('namespaces'):
4771 hexremoterev = hex(remoterev)
4771 hexremoterev = hex(remoterev)
4772 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4772 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4773 if bmr == hexremoterev]
4773 if bmr == hexremoterev]
4774
4774
4775 return sorted(bms)
4775 return sorted(bms)
4776
4776
4777 if bookmarks:
4777 if bookmarks:
4778 output.extend(getbms())
4778 output.extend(getbms())
4779 elif default and not ui.quiet:
4779 elif default and not ui.quiet:
4780 # multiple bookmarks for a single parent separated by '/'
4780 # multiple bookmarks for a single parent separated by '/'
4781 bm = '/'.join(getbms())
4781 bm = '/'.join(getbms())
4782 if bm:
4782 if bm:
4783 output.append(bm)
4783 output.append(bm)
4784 else:
4784 else:
4785 ctx = scmutil.revsingle(repo, rev, None)
4785 ctx = scmutil.revsingle(repo, rev, None)
4786
4786
4787 if ctx.rev() is None:
4787 if ctx.rev() is None:
4788 ctx = repo[None]
4788 ctx = repo[None]
4789 parents = ctx.parents()
4789 parents = ctx.parents()
4790 taglist = []
4790 taglist = []
4791 for p in parents:
4791 for p in parents:
4792 taglist.extend(p.tags())
4792 taglist.extend(p.tags())
4793
4793
4794 changed = ""
4794 changed = ""
4795 if default or id or num:
4795 if default or id or num:
4796 if (any(repo.status())
4796 if (any(repo.status())
4797 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4797 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4798 changed = '+'
4798 changed = '+'
4799 if default or id:
4799 if default or id:
4800 output = ["%s%s" %
4800 output = ["%s%s" %
4801 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4801 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4802 if num:
4802 if num:
4803 output.append("%s%s" %
4803 output.append("%s%s" %
4804 ('+'.join([str(p.rev()) for p in parents]), changed))
4804 ('+'.join([str(p.rev()) for p in parents]), changed))
4805 else:
4805 else:
4806 if default or id:
4806 if default or id:
4807 output = [hexfunc(ctx.node())]
4807 output = [hexfunc(ctx.node())]
4808 if num:
4808 if num:
4809 output.append(str(ctx.rev()))
4809 output.append(str(ctx.rev()))
4810 taglist = ctx.tags()
4810 taglist = ctx.tags()
4811
4811
4812 if default and not ui.quiet:
4812 if default and not ui.quiet:
4813 b = ctx.branch()
4813 b = ctx.branch()
4814 if b != 'default':
4814 if b != 'default':
4815 output.append("(%s)" % b)
4815 output.append("(%s)" % b)
4816
4816
4817 # multiple tags for a single parent separated by '/'
4817 # multiple tags for a single parent separated by '/'
4818 t = '/'.join(taglist)
4818 t = '/'.join(taglist)
4819 if t:
4819 if t:
4820 output.append(t)
4820 output.append(t)
4821
4821
4822 # multiple bookmarks for a single parent separated by '/'
4822 # multiple bookmarks for a single parent separated by '/'
4823 bm = '/'.join(ctx.bookmarks())
4823 bm = '/'.join(ctx.bookmarks())
4824 if bm:
4824 if bm:
4825 output.append(bm)
4825 output.append(bm)
4826 else:
4826 else:
4827 if branch:
4827 if branch:
4828 output.append(ctx.branch())
4828 output.append(ctx.branch())
4829
4829
4830 if tags:
4830 if tags:
4831 output.extend(taglist)
4831 output.extend(taglist)
4832
4832
4833 if bookmarks:
4833 if bookmarks:
4834 output.extend(ctx.bookmarks())
4834 output.extend(ctx.bookmarks())
4835
4835
4836 ui.write("%s\n" % ' '.join(output))
4836 ui.write("%s\n" % ' '.join(output))
4837
4837
4838 @command('import|patch',
4838 @command('import|patch',
4839 [('p', 'strip', 1,
4839 [('p', 'strip', 1,
4840 _('directory strip option for patch. This has the same '
4840 _('directory strip option for patch. This has the same '
4841 'meaning as the corresponding patch option'), _('NUM')),
4841 'meaning as the corresponding patch option'), _('NUM')),
4842 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4842 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4843 ('e', 'edit', False, _('invoke editor on commit messages')),
4843 ('e', 'edit', False, _('invoke editor on commit messages')),
4844 ('f', 'force', None,
4844 ('f', 'force', None,
4845 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4845 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4846 ('', 'no-commit', None,
4846 ('', 'no-commit', None,
4847 _("don't commit, just update the working directory")),
4847 _("don't commit, just update the working directory")),
4848 ('', 'bypass', None,
4848 ('', 'bypass', None,
4849 _("apply patch without touching the working directory")),
4849 _("apply patch without touching the working directory")),
4850 ('', 'partial', None,
4850 ('', 'partial', None,
4851 _('commit even if some hunks fail')),
4851 _('commit even if some hunks fail')),
4852 ('', 'exact', None,
4852 ('', 'exact', None,
4853 _('abort if patch would apply lossily')),
4853 _('abort if patch would apply lossily')),
4854 ('', 'prefix', '',
4854 ('', 'prefix', '',
4855 _('apply patch to subdirectory'), _('DIR')),
4855 _('apply patch to subdirectory'), _('DIR')),
4856 ('', 'import-branch', None,
4856 ('', 'import-branch', None,
4857 _('use any branch information in patch (implied by --exact)'))] +
4857 _('use any branch information in patch (implied by --exact)'))] +
4858 commitopts + commitopts2 + similarityopts,
4858 commitopts + commitopts2 + similarityopts,
4859 _('[OPTION]... PATCH...'))
4859 _('[OPTION]... PATCH...'))
4860 def import_(ui, repo, patch1=None, *patches, **opts):
4860 def import_(ui, repo, patch1=None, *patches, **opts):
4861 """import an ordered set of patches
4861 """import an ordered set of patches
4862
4862
4863 Import a list of patches and commit them individually (unless
4863 Import a list of patches and commit them individually (unless
4864 --no-commit is specified).
4864 --no-commit is specified).
4865
4865
4866 To read a patch from standard input, use "-" as the patch name. If
4866 To read a patch from standard input, use "-" as the patch name. If
4867 a URL is specified, the patch will be downloaded from there.
4867 a URL is specified, the patch will be downloaded from there.
4868
4868
4869 Import first applies changes to the working directory (unless
4869 Import first applies changes to the working directory (unless
4870 --bypass is specified), import will abort if there are outstanding
4870 --bypass is specified), import will abort if there are outstanding
4871 changes.
4871 changes.
4872
4872
4873 Use --bypass to apply and commit patches directly to the
4873 Use --bypass to apply and commit patches directly to the
4874 repository, without affecting the working directory. Without
4874 repository, without affecting the working directory. Without
4875 --exact, patches will be applied on top of the working directory
4875 --exact, patches will be applied on top of the working directory
4876 parent revision.
4876 parent revision.
4877
4877
4878 You can import a patch straight from a mail message. Even patches
4878 You can import a patch straight from a mail message. Even patches
4879 as attachments work (to use the body part, it must have type
4879 as attachments work (to use the body part, it must have type
4880 text/plain or text/x-patch). From and Subject headers of email
4880 text/plain or text/x-patch). From and Subject headers of email
4881 message are used as default committer and commit message. All
4881 message are used as default committer and commit message. All
4882 text/plain body parts before first diff are added to the commit
4882 text/plain body parts before first diff are added to the commit
4883 message.
4883 message.
4884
4884
4885 If the imported patch was generated by :hg:`export`, user and
4885 If the imported patch was generated by :hg:`export`, user and
4886 description from patch override values from message headers and
4886 description from patch override values from message headers and
4887 body. Values given on command line with -m/--message and -u/--user
4887 body. Values given on command line with -m/--message and -u/--user
4888 override these.
4888 override these.
4889
4889
4890 If --exact is specified, import will set the working directory to
4890 If --exact is specified, import will set the working directory to
4891 the parent of each patch before applying it, and will abort if the
4891 the parent of each patch before applying it, and will abort if the
4892 resulting changeset has a different ID than the one recorded in
4892 resulting changeset has a different ID than the one recorded in
4893 the patch. This will guard against various ways that portable
4893 the patch. This will guard against various ways that portable
4894 patch formats and mail systems might fail to transfer Mercurial
4894 patch formats and mail systems might fail to transfer Mercurial
4895 data or metadata. See :hg:`bundle` for lossless transmission.
4895 data or metadata. See :hg:`bundle` for lossless transmission.
4896
4896
4897 Use --partial to ensure a changeset will be created from the patch
4897 Use --partial to ensure a changeset will be created from the patch
4898 even if some hunks fail to apply. Hunks that fail to apply will be
4898 even if some hunks fail to apply. Hunks that fail to apply will be
4899 written to a <target-file>.rej file. Conflicts can then be resolved
4899 written to a <target-file>.rej file. Conflicts can then be resolved
4900 by hand before :hg:`commit --amend` is run to update the created
4900 by hand before :hg:`commit --amend` is run to update the created
4901 changeset. This flag exists to let people import patches that
4901 changeset. This flag exists to let people import patches that
4902 partially apply without losing the associated metadata (author,
4902 partially apply without losing the associated metadata (author,
4903 date, description, ...).
4903 date, description, ...).
4904
4904
4905 .. note::
4905 .. note::
4906
4906
4907 When no hunks apply cleanly, :hg:`import --partial` will create
4907 When no hunks apply cleanly, :hg:`import --partial` will create
4908 an empty changeset, importing only the patch metadata.
4908 an empty changeset, importing only the patch metadata.
4909
4909
4910 With -s/--similarity, hg will attempt to discover renames and
4910 With -s/--similarity, hg will attempt to discover renames and
4911 copies in the patch in the same way as :hg:`addremove`.
4911 copies in the patch in the same way as :hg:`addremove`.
4912
4912
4913 It is possible to use external patch programs to perform the patch
4913 It is possible to use external patch programs to perform the patch
4914 by setting the ``ui.patch`` configuration option. For the default
4914 by setting the ``ui.patch`` configuration option. For the default
4915 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4915 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4916 See :hg:`help config` for more information about configuration
4916 See :hg:`help config` for more information about configuration
4917 files and how to use these options.
4917 files and how to use these options.
4918
4918
4919 See :hg:`help dates` for a list of formats valid for -d/--date.
4919 See :hg:`help dates` for a list of formats valid for -d/--date.
4920
4920
4921 .. container:: verbose
4921 .. container:: verbose
4922
4922
4923 Examples:
4923 Examples:
4924
4924
4925 - import a traditional patch from a website and detect renames::
4925 - import a traditional patch from a website and detect renames::
4926
4926
4927 hg import -s 80 http://example.com/bugfix.patch
4927 hg import -s 80 http://example.com/bugfix.patch
4928
4928
4929 - import a changeset from an hgweb server::
4929 - import a changeset from an hgweb server::
4930
4930
4931 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4931 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4932
4932
4933 - import all the patches in an Unix-style mbox::
4933 - import all the patches in an Unix-style mbox::
4934
4934
4935 hg import incoming-patches.mbox
4935 hg import incoming-patches.mbox
4936
4936
4937 - attempt to exactly restore an exported changeset (not always
4937 - attempt to exactly restore an exported changeset (not always
4938 possible)::
4938 possible)::
4939
4939
4940 hg import --exact proposed-fix.patch
4940 hg import --exact proposed-fix.patch
4941
4941
4942 - use an external tool to apply a patch which is too fuzzy for
4942 - use an external tool to apply a patch which is too fuzzy for
4943 the default internal tool.
4943 the default internal tool.
4944
4944
4945 hg import --config ui.patch="patch --merge" fuzzy.patch
4945 hg import --config ui.patch="patch --merge" fuzzy.patch
4946
4946
4947 - change the default fuzzing from 2 to a less strict 7
4947 - change the default fuzzing from 2 to a less strict 7
4948
4948
4949 hg import --config ui.fuzz=7 fuzz.patch
4949 hg import --config ui.fuzz=7 fuzz.patch
4950
4950
4951 Returns 0 on success, 1 on partial success (see --partial).
4951 Returns 0 on success, 1 on partial success (see --partial).
4952 """
4952 """
4953
4953
4954 if not patch1:
4954 if not patch1:
4955 raise error.Abort(_('need at least one patch to import'))
4955 raise error.Abort(_('need at least one patch to import'))
4956
4956
4957 patches = (patch1,) + patches
4957 patches = (patch1,) + patches
4958
4958
4959 date = opts.get('date')
4959 date = opts.get('date')
4960 if date:
4960 if date:
4961 opts['date'] = util.parsedate(date)
4961 opts['date'] = util.parsedate(date)
4962
4962
4963 exact = opts.get('exact')
4963 exact = opts.get('exact')
4964 update = not opts.get('bypass')
4964 update = not opts.get('bypass')
4965 if not update and opts.get('no_commit'):
4965 if not update and opts.get('no_commit'):
4966 raise error.Abort(_('cannot use --no-commit with --bypass'))
4966 raise error.Abort(_('cannot use --no-commit with --bypass'))
4967 try:
4967 try:
4968 sim = float(opts.get('similarity') or 0)
4968 sim = float(opts.get('similarity') or 0)
4969 except ValueError:
4969 except ValueError:
4970 raise error.Abort(_('similarity must be a number'))
4970 raise error.Abort(_('similarity must be a number'))
4971 if sim < 0 or sim > 100:
4971 if sim < 0 or sim > 100:
4972 raise error.Abort(_('similarity must be between 0 and 100'))
4972 raise error.Abort(_('similarity must be between 0 and 100'))
4973 if sim and not update:
4973 if sim and not update:
4974 raise error.Abort(_('cannot use --similarity with --bypass'))
4974 raise error.Abort(_('cannot use --similarity with --bypass'))
4975 if exact:
4975 if exact:
4976 if opts.get('edit'):
4976 if opts.get('edit'):
4977 raise error.Abort(_('cannot use --exact with --edit'))
4977 raise error.Abort(_('cannot use --exact with --edit'))
4978 if opts.get('prefix'):
4978 if opts.get('prefix'):
4979 raise error.Abort(_('cannot use --exact with --prefix'))
4979 raise error.Abort(_('cannot use --exact with --prefix'))
4980
4980
4981 base = opts["base"]
4981 base = opts["base"]
4982 wlock = dsguard = lock = tr = None
4982 wlock = dsguard = lock = tr = None
4983 msgs = []
4983 msgs = []
4984 ret = 0
4984 ret = 0
4985
4985
4986
4986
4987 try:
4987 try:
4988 wlock = repo.wlock()
4988 wlock = repo.wlock()
4989
4989
4990 if update:
4990 if update:
4991 cmdutil.checkunfinished(repo)
4991 cmdutil.checkunfinished(repo)
4992 if (exact or not opts.get('force')):
4992 if (exact or not opts.get('force')):
4993 cmdutil.bailifchanged(repo)
4993 cmdutil.bailifchanged(repo)
4994
4994
4995 if not opts.get('no_commit'):
4995 if not opts.get('no_commit'):
4996 lock = repo.lock()
4996 lock = repo.lock()
4997 tr = repo.transaction('import')
4997 tr = repo.transaction('import')
4998 else:
4998 else:
4999 dsguard = cmdutil.dirstateguard(repo, 'import')
4999 dsguard = cmdutil.dirstateguard(repo, 'import')
5000 parents = repo[None].parents()
5000 parents = repo[None].parents()
5001 for patchurl in patches:
5001 for patchurl in patches:
5002 if patchurl == '-':
5002 if patchurl == '-':
5003 ui.status(_('applying patch from stdin\n'))
5003 ui.status(_('applying patch from stdin\n'))
5004 patchfile = ui.fin
5004 patchfile = ui.fin
5005 patchurl = 'stdin' # for error message
5005 patchurl = 'stdin' # for error message
5006 else:
5006 else:
5007 patchurl = os.path.join(base, patchurl)
5007 patchurl = os.path.join(base, patchurl)
5008 ui.status(_('applying %s\n') % patchurl)
5008 ui.status(_('applying %s\n') % patchurl)
5009 patchfile = hg.openpath(ui, patchurl)
5009 patchfile = hg.openpath(ui, patchurl)
5010
5010
5011 haspatch = False
5011 haspatch = False
5012 for hunk in patch.split(patchfile):
5012 for hunk in patch.split(patchfile):
5013 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5013 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5014 parents, opts,
5014 parents, opts,
5015 msgs, hg.clean)
5015 msgs, hg.clean)
5016 if msg:
5016 if msg:
5017 haspatch = True
5017 haspatch = True
5018 ui.note(msg + '\n')
5018 ui.note(msg + '\n')
5019 if update or exact:
5019 if update or exact:
5020 parents = repo[None].parents()
5020 parents = repo[None].parents()
5021 else:
5021 else:
5022 parents = [repo[node]]
5022 parents = [repo[node]]
5023 if rej:
5023 if rej:
5024 ui.write_err(_("patch applied partially\n"))
5024 ui.write_err(_("patch applied partially\n"))
5025 ui.write_err(_("(fix the .rej files and run "
5025 ui.write_err(_("(fix the .rej files and run "
5026 "`hg commit --amend`)\n"))
5026 "`hg commit --amend`)\n"))
5027 ret = 1
5027 ret = 1
5028 break
5028 break
5029
5029
5030 if not haspatch:
5030 if not haspatch:
5031 raise error.Abort(_('%s: no diffs found') % patchurl)
5031 raise error.Abort(_('%s: no diffs found') % patchurl)
5032
5032
5033 if tr:
5033 if tr:
5034 tr.close()
5034 tr.close()
5035 if msgs:
5035 if msgs:
5036 repo.savecommitmessage('\n* * *\n'.join(msgs))
5036 repo.savecommitmessage('\n* * *\n'.join(msgs))
5037 if dsguard:
5037 if dsguard:
5038 dsguard.close()
5038 dsguard.close()
5039 return ret
5039 return ret
5040 finally:
5040 finally:
5041 if tr:
5041 if tr:
5042 tr.release()
5042 tr.release()
5043 release(lock, dsguard, wlock)
5043 release(lock, dsguard, wlock)
5044
5044
5045 @command('incoming|in',
5045 @command('incoming|in',
5046 [('f', 'force', None,
5046 [('f', 'force', None,
5047 _('run even if remote repository is unrelated')),
5047 _('run even if remote repository is unrelated')),
5048 ('n', 'newest-first', None, _('show newest record first')),
5048 ('n', 'newest-first', None, _('show newest record first')),
5049 ('', 'bundle', '',
5049 ('', 'bundle', '',
5050 _('file to store the bundles into'), _('FILE')),
5050 _('file to store the bundles into'), _('FILE')),
5051 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5051 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5052 ('B', 'bookmarks', False, _("compare bookmarks")),
5052 ('B', 'bookmarks', False, _("compare bookmarks")),
5053 ('b', 'branch', [],
5053 ('b', 'branch', [],
5054 _('a specific branch you would like to pull'), _('BRANCH')),
5054 _('a specific branch you would like to pull'), _('BRANCH')),
5055 ] + logopts + remoteopts + subrepoopts,
5055 ] + logopts + remoteopts + subrepoopts,
5056 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5056 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5057 def incoming(ui, repo, source="default", **opts):
5057 def incoming(ui, repo, source="default", **opts):
5058 """show new changesets found in source
5058 """show new changesets found in source
5059
5059
5060 Show new changesets found in the specified path/URL or the default
5060 Show new changesets found in the specified path/URL or the default
5061 pull location. These are the changesets that would have been pulled
5061 pull location. These are the changesets that would have been pulled
5062 if a pull at the time you issued this command.
5062 if a pull at the time you issued this command.
5063
5063
5064 See pull for valid source format details.
5064 See pull for valid source format details.
5065
5065
5066 .. container:: verbose
5066 .. container:: verbose
5067
5067
5068 With -B/--bookmarks, the result of bookmark comparison between
5068 With -B/--bookmarks, the result of bookmark comparison between
5069 local and remote repositories is displayed. With -v/--verbose,
5069 local and remote repositories is displayed. With -v/--verbose,
5070 status is also displayed for each bookmark like below::
5070 status is also displayed for each bookmark like below::
5071
5071
5072 BM1 01234567890a added
5072 BM1 01234567890a added
5073 BM2 1234567890ab advanced
5073 BM2 1234567890ab advanced
5074 BM3 234567890abc diverged
5074 BM3 234567890abc diverged
5075 BM4 34567890abcd changed
5075 BM4 34567890abcd changed
5076
5076
5077 The action taken locally when pulling depends on the
5077 The action taken locally when pulling depends on the
5078 status of each bookmark:
5078 status of each bookmark:
5079
5079
5080 :``added``: pull will create it
5080 :``added``: pull will create it
5081 :``advanced``: pull will update it
5081 :``advanced``: pull will update it
5082 :``diverged``: pull will create a divergent bookmark
5082 :``diverged``: pull will create a divergent bookmark
5083 :``changed``: result depends on remote changesets
5083 :``changed``: result depends on remote changesets
5084
5084
5085 From the point of view of pulling behavior, bookmark
5085 From the point of view of pulling behavior, bookmark
5086 existing only in the remote repository are treated as ``added``,
5086 existing only in the remote repository are treated as ``added``,
5087 even if it is in fact locally deleted.
5087 even if it is in fact locally deleted.
5088
5088
5089 .. container:: verbose
5089 .. container:: verbose
5090
5090
5091 For remote repository, using --bundle avoids downloading the
5091 For remote repository, using --bundle avoids downloading the
5092 changesets twice if the incoming is followed by a pull.
5092 changesets twice if the incoming is followed by a pull.
5093
5093
5094 Examples:
5094 Examples:
5095
5095
5096 - show incoming changes with patches and full description::
5096 - show incoming changes with patches and full description::
5097
5097
5098 hg incoming -vp
5098 hg incoming -vp
5099
5099
5100 - show incoming changes excluding merges, store a bundle::
5100 - show incoming changes excluding merges, store a bundle::
5101
5101
5102 hg in -vpM --bundle incoming.hg
5102 hg in -vpM --bundle incoming.hg
5103 hg pull incoming.hg
5103 hg pull incoming.hg
5104
5104
5105 - briefly list changes inside a bundle::
5105 - briefly list changes inside a bundle::
5106
5106
5107 hg in changes.hg -T "{desc|firstline}\\n"
5107 hg in changes.hg -T "{desc|firstline}\\n"
5108
5108
5109 Returns 0 if there are incoming changes, 1 otherwise.
5109 Returns 0 if there are incoming changes, 1 otherwise.
5110 """
5110 """
5111 if opts.get('graph'):
5111 if opts.get('graph'):
5112 cmdutil.checkunsupportedgraphflags([], opts)
5112 cmdutil.checkunsupportedgraphflags([], opts)
5113 def display(other, chlist, displayer):
5113 def display(other, chlist, displayer):
5114 revdag = cmdutil.graphrevs(other, chlist, opts)
5114 revdag = cmdutil.graphrevs(other, chlist, opts)
5115 cmdutil.displaygraph(ui, repo, revdag, displayer,
5115 cmdutil.displaygraph(ui, repo, revdag, displayer,
5116 graphmod.asciiedges)
5116 graphmod.asciiedges)
5117
5117
5118 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5118 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5119 return 0
5119 return 0
5120
5120
5121 if opts.get('bundle') and opts.get('subrepos'):
5121 if opts.get('bundle') and opts.get('subrepos'):
5122 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5122 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5123
5123
5124 if opts.get('bookmarks'):
5124 if opts.get('bookmarks'):
5125 source, branches = hg.parseurl(ui.expandpath(source),
5125 source, branches = hg.parseurl(ui.expandpath(source),
5126 opts.get('branch'))
5126 opts.get('branch'))
5127 other = hg.peer(repo, opts, source)
5127 other = hg.peer(repo, opts, source)
5128 if 'bookmarks' not in other.listkeys('namespaces'):
5128 if 'bookmarks' not in other.listkeys('namespaces'):
5129 ui.warn(_("remote doesn't support bookmarks\n"))
5129 ui.warn(_("remote doesn't support bookmarks\n"))
5130 return 0
5130 return 0
5131 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5131 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5132 return bookmarks.incoming(ui, repo, other)
5132 return bookmarks.incoming(ui, repo, other)
5133
5133
5134 repo._subtoppath = ui.expandpath(source)
5134 repo._subtoppath = ui.expandpath(source)
5135 try:
5135 try:
5136 return hg.incoming(ui, repo, source, opts)
5136 return hg.incoming(ui, repo, source, opts)
5137 finally:
5137 finally:
5138 del repo._subtoppath
5138 del repo._subtoppath
5139
5139
5140
5140
5141 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5141 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5142 norepo=True)
5142 norepo=True)
5143 def init(ui, dest=".", **opts):
5143 def init(ui, dest=".", **opts):
5144 """create a new repository in the given directory
5144 """create a new repository in the given directory
5145
5145
5146 Initialize a new repository in the given directory. If the given
5146 Initialize a new repository in the given directory. If the given
5147 directory does not exist, it will be created.
5147 directory does not exist, it will be created.
5148
5148
5149 If no directory is given, the current directory is used.
5149 If no directory is given, the current directory is used.
5150
5150
5151 It is possible to specify an ``ssh://`` URL as the destination.
5151 It is possible to specify an ``ssh://`` URL as the destination.
5152 See :hg:`help urls` for more information.
5152 See :hg:`help urls` for more information.
5153
5153
5154 Returns 0 on success.
5154 Returns 0 on success.
5155 """
5155 """
5156 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5156 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5157
5157
5158 @command('locate',
5158 @command('locate',
5159 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5159 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5160 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5160 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5161 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5161 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5162 ] + walkopts,
5162 ] + walkopts,
5163 _('[OPTION]... [PATTERN]...'))
5163 _('[OPTION]... [PATTERN]...'))
5164 def locate(ui, repo, *pats, **opts):
5164 def locate(ui, repo, *pats, **opts):
5165 """locate files matching specific patterns (DEPRECATED)
5165 """locate files matching specific patterns (DEPRECATED)
5166
5166
5167 Print files under Mercurial control in the working directory whose
5167 Print files under Mercurial control in the working directory whose
5168 names match the given patterns.
5168 names match the given patterns.
5169
5169
5170 By default, this command searches all directories in the working
5170 By default, this command searches all directories in the working
5171 directory. To search just the current directory and its
5171 directory. To search just the current directory and its
5172 subdirectories, use "--include .".
5172 subdirectories, use "--include .".
5173
5173
5174 If no patterns are given to match, this command prints the names
5174 If no patterns are given to match, this command prints the names
5175 of all files under Mercurial control in the working directory.
5175 of all files under Mercurial control in the working directory.
5176
5176
5177 If you want to feed the output of this command into the "xargs"
5177 If you want to feed the output of this command into the "xargs"
5178 command, use the -0 option to both this command and "xargs". This
5178 command, use the -0 option to both this command and "xargs". This
5179 will avoid the problem of "xargs" treating single filenames that
5179 will avoid the problem of "xargs" treating single filenames that
5180 contain whitespace as multiple filenames.
5180 contain whitespace as multiple filenames.
5181
5181
5182 See :hg:`help files` for a more versatile command.
5182 See :hg:`help files` for a more versatile command.
5183
5183
5184 Returns 0 if a match is found, 1 otherwise.
5184 Returns 0 if a match is found, 1 otherwise.
5185 """
5185 """
5186 if opts.get('print0'):
5186 if opts.get('print0'):
5187 end = '\0'
5187 end = '\0'
5188 else:
5188 else:
5189 end = '\n'
5189 end = '\n'
5190 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5190 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5191
5191
5192 ret = 1
5192 ret = 1
5193 ctx = repo[rev]
5193 ctx = repo[rev]
5194 m = scmutil.match(ctx, pats, opts, default='relglob',
5194 m = scmutil.match(ctx, pats, opts, default='relglob',
5195 badfn=lambda x, y: False)
5195 badfn=lambda x, y: False)
5196
5196
5197 for abs in ctx.matches(m):
5197 for abs in ctx.matches(m):
5198 if opts.get('fullpath'):
5198 if opts.get('fullpath'):
5199 ui.write(repo.wjoin(abs), end)
5199 ui.write(repo.wjoin(abs), end)
5200 else:
5200 else:
5201 ui.write(((pats and m.rel(abs)) or abs), end)
5201 ui.write(((pats and m.rel(abs)) or abs), end)
5202 ret = 0
5202 ret = 0
5203
5203
5204 return ret
5204 return ret
5205
5205
5206 @command('^log|history',
5206 @command('^log|history',
5207 [('f', 'follow', None,
5207 [('f', 'follow', None,
5208 _('follow changeset history, or file history across copies and renames')),
5208 _('follow changeset history, or file history across copies and renames')),
5209 ('', 'follow-first', None,
5209 ('', 'follow-first', None,
5210 _('only follow the first parent of merge changesets (DEPRECATED)')),
5210 _('only follow the first parent of merge changesets (DEPRECATED)')),
5211 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5211 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5212 ('C', 'copies', None, _('show copied files')),
5212 ('C', 'copies', None, _('show copied files')),
5213 ('k', 'keyword', [],
5213 ('k', 'keyword', [],
5214 _('do case-insensitive search for a given text'), _('TEXT')),
5214 _('do case-insensitive search for a given text'), _('TEXT')),
5215 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5215 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5216 ('', 'removed', None, _('include revisions where files were removed')),
5216 ('', 'removed', None, _('include revisions where files were removed')),
5217 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5217 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5218 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5218 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5219 ('', 'only-branch', [],
5219 ('', 'only-branch', [],
5220 _('show only changesets within the given named branch (DEPRECATED)'),
5220 _('show only changesets within the given named branch (DEPRECATED)'),
5221 _('BRANCH')),
5221 _('BRANCH')),
5222 ('b', 'branch', [],
5222 ('b', 'branch', [],
5223 _('show changesets within the given named branch'), _('BRANCH')),
5223 _('show changesets within the given named branch'), _('BRANCH')),
5224 ('P', 'prune', [],
5224 ('P', 'prune', [],
5225 _('do not display revision or any of its ancestors'), _('REV')),
5225 _('do not display revision or any of its ancestors'), _('REV')),
5226 ] + logopts + walkopts,
5226 ] + logopts + walkopts,
5227 _('[OPTION]... [FILE]'),
5227 _('[OPTION]... [FILE]'),
5228 inferrepo=True)
5228 inferrepo=True)
5229 def log(ui, repo, *pats, **opts):
5229 def log(ui, repo, *pats, **opts):
5230 """show revision history of entire repository or files
5230 """show revision history of entire repository or files
5231
5231
5232 Print the revision history of the specified files or the entire
5232 Print the revision history of the specified files or the entire
5233 project.
5233 project.
5234
5234
5235 If no revision range is specified, the default is ``tip:0`` unless
5235 If no revision range is specified, the default is ``tip:0`` unless
5236 --follow is set, in which case the working directory parent is
5236 --follow is set, in which case the working directory parent is
5237 used as the starting revision.
5237 used as the starting revision.
5238
5238
5239 File history is shown without following rename or copy history of
5239 File history is shown without following rename or copy history of
5240 files. Use -f/--follow with a filename to follow history across
5240 files. Use -f/--follow with a filename to follow history across
5241 renames and copies. --follow without a filename will only show
5241 renames and copies. --follow without a filename will only show
5242 ancestors or descendants of the starting revision.
5242 ancestors or descendants of the starting revision.
5243
5243
5244 By default this command prints revision number and changeset id,
5244 By default this command prints revision number and changeset id,
5245 tags, non-trivial parents, user, date and time, and a summary for
5245 tags, non-trivial parents, user, date and time, and a summary for
5246 each commit. When the -v/--verbose switch is used, the list of
5246 each commit. When the -v/--verbose switch is used, the list of
5247 changed files and full commit message are shown.
5247 changed files and full commit message are shown.
5248
5248
5249 With --graph the revisions are shown as an ASCII art DAG with the most
5249 With --graph the revisions are shown as an ASCII art DAG with the most
5250 recent changeset at the top.
5250 recent changeset at the top.
5251 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5251 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5252 and '+' represents a fork where the changeset from the lines below is a
5252 and '+' represents a fork where the changeset from the lines below is a
5253 parent of the 'o' merge on the same line.
5253 parent of the 'o' merge on the same line.
5254
5254
5255 .. note::
5255 .. note::
5256
5256
5257 :hg:`log --patch` may generate unexpected diff output for merge
5257 :hg:`log --patch` may generate unexpected diff output for merge
5258 changesets, as it will only compare the merge changeset against
5258 changesets, as it will only compare the merge changeset against
5259 its first parent. Also, only files different from BOTH parents
5259 its first parent. Also, only files different from BOTH parents
5260 will appear in files:.
5260 will appear in files:.
5261
5261
5262 .. note::
5262 .. note::
5263
5263
5264 For performance reasons, :hg:`log FILE` may omit duplicate changes
5264 For performance reasons, :hg:`log FILE` may omit duplicate changes
5265 made on branches and will not show removals or mode changes. To
5265 made on branches and will not show removals or mode changes. To
5266 see all such changes, use the --removed switch.
5266 see all such changes, use the --removed switch.
5267
5267
5268 .. container:: verbose
5268 .. container:: verbose
5269
5269
5270 Some examples:
5270 Some examples:
5271
5271
5272 - changesets with full descriptions and file lists::
5272 - changesets with full descriptions and file lists::
5273
5273
5274 hg log -v
5274 hg log -v
5275
5275
5276 - changesets ancestral to the working directory::
5276 - changesets ancestral to the working directory::
5277
5277
5278 hg log -f
5278 hg log -f
5279
5279
5280 - last 10 commits on the current branch::
5280 - last 10 commits on the current branch::
5281
5281
5282 hg log -l 10 -b .
5282 hg log -l 10 -b .
5283
5283
5284 - changesets showing all modifications of a file, including removals::
5284 - changesets showing all modifications of a file, including removals::
5285
5285
5286 hg log --removed file.c
5286 hg log --removed file.c
5287
5287
5288 - all changesets that touch a directory, with diffs, excluding merges::
5288 - all changesets that touch a directory, with diffs, excluding merges::
5289
5289
5290 hg log -Mp lib/
5290 hg log -Mp lib/
5291
5291
5292 - all revision numbers that match a keyword::
5292 - all revision numbers that match a keyword::
5293
5293
5294 hg log -k bug --template "{rev}\\n"
5294 hg log -k bug --template "{rev}\\n"
5295
5295
5296 - the full hash identifier of the working directory parent::
5296 - the full hash identifier of the working directory parent::
5297
5297
5298 hg log -r . --template "{node}\\n"
5298 hg log -r . --template "{node}\\n"
5299
5299
5300 - list available log templates::
5300 - list available log templates::
5301
5301
5302 hg log -T list
5302 hg log -T list
5303
5303
5304 - check if a given changeset is included in a tagged release::
5304 - check if a given changeset is included in a tagged release::
5305
5305
5306 hg log -r "a21ccf and ancestor(1.9)"
5306 hg log -r "a21ccf and ancestor(1.9)"
5307
5307
5308 - find all changesets by some user in a date range::
5308 - find all changesets by some user in a date range::
5309
5309
5310 hg log -k alice -d "may 2008 to jul 2008"
5310 hg log -k alice -d "may 2008 to jul 2008"
5311
5311
5312 - summary of all changesets after the last tag::
5312 - summary of all changesets after the last tag::
5313
5313
5314 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5314 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5315
5315
5316 See :hg:`help dates` for a list of formats valid for -d/--date.
5316 See :hg:`help dates` for a list of formats valid for -d/--date.
5317
5317
5318 See :hg:`help revisions` and :hg:`help revsets` for more about
5318 See :hg:`help revisions` and :hg:`help revsets` for more about
5319 specifying and ordering revisions.
5319 specifying and ordering revisions.
5320
5320
5321 See :hg:`help templates` for more about pre-packaged styles and
5321 See :hg:`help templates` for more about pre-packaged styles and
5322 specifying custom templates.
5322 specifying custom templates.
5323
5323
5324 Returns 0 on success.
5324 Returns 0 on success.
5325
5325
5326 """
5326 """
5327 if opts.get('follow') and opts.get('rev'):
5327 if opts.get('follow') and opts.get('rev'):
5328 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5328 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5329 del opts['follow']
5329 del opts['follow']
5330
5330
5331 if opts.get('graph'):
5331 if opts.get('graph'):
5332 return cmdutil.graphlog(ui, repo, *pats, **opts)
5332 return cmdutil.graphlog(ui, repo, *pats, **opts)
5333
5333
5334 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5334 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5335 limit = cmdutil.loglimit(opts)
5335 limit = cmdutil.loglimit(opts)
5336 count = 0
5336 count = 0
5337
5337
5338 getrenamed = None
5338 getrenamed = None
5339 if opts.get('copies'):
5339 if opts.get('copies'):
5340 endrev = None
5340 endrev = None
5341 if opts.get('rev'):
5341 if opts.get('rev'):
5342 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5342 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5343 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5343 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5344
5344
5345 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5345 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5346 for rev in revs:
5346 for rev in revs:
5347 if count == limit:
5347 if count == limit:
5348 break
5348 break
5349 ctx = repo[rev]
5349 ctx = repo[rev]
5350 copies = None
5350 copies = None
5351 if getrenamed is not None and rev:
5351 if getrenamed is not None and rev:
5352 copies = []
5352 copies = []
5353 for fn in ctx.files():
5353 for fn in ctx.files():
5354 rename = getrenamed(fn, rev)
5354 rename = getrenamed(fn, rev)
5355 if rename:
5355 if rename:
5356 copies.append((fn, rename[0]))
5356 copies.append((fn, rename[0]))
5357 if filematcher:
5357 if filematcher:
5358 revmatchfn = filematcher(ctx.rev())
5358 revmatchfn = filematcher(ctx.rev())
5359 else:
5359 else:
5360 revmatchfn = None
5360 revmatchfn = None
5361 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5361 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5362 if displayer.flush(ctx):
5362 if displayer.flush(ctx):
5363 count += 1
5363 count += 1
5364
5364
5365 displayer.close()
5365 displayer.close()
5366
5366
5367 @command('manifest',
5367 @command('manifest',
5368 [('r', 'rev', '', _('revision to display'), _('REV')),
5368 [('r', 'rev', '', _('revision to display'), _('REV')),
5369 ('', 'all', False, _("list files from all revisions"))]
5369 ('', 'all', False, _("list files from all revisions"))]
5370 + formatteropts,
5370 + formatteropts,
5371 _('[-r REV]'))
5371 _('[-r REV]'))
5372 def manifest(ui, repo, node=None, rev=None, **opts):
5372 def manifest(ui, repo, node=None, rev=None, **opts):
5373 """output the current or given revision of the project manifest
5373 """output the current or given revision of the project manifest
5374
5374
5375 Print a list of version controlled files for the given revision.
5375 Print a list of version controlled files for the given revision.
5376 If no revision is given, the first parent of the working directory
5376 If no revision is given, the first parent of the working directory
5377 is used, or the null revision if no revision is checked out.
5377 is used, or the null revision if no revision is checked out.
5378
5378
5379 With -v, print file permissions, symlink and executable bits.
5379 With -v, print file permissions, symlink and executable bits.
5380 With --debug, print file revision hashes.
5380 With --debug, print file revision hashes.
5381
5381
5382 If option --all is specified, the list of all files from all revisions
5382 If option --all is specified, the list of all files from all revisions
5383 is printed. This includes deleted and renamed files.
5383 is printed. This includes deleted and renamed files.
5384
5384
5385 Returns 0 on success.
5385 Returns 0 on success.
5386 """
5386 """
5387
5387
5388 fm = ui.formatter('manifest', opts)
5388 fm = ui.formatter('manifest', opts)
5389
5389
5390 if opts.get('all'):
5390 if opts.get('all'):
5391 if rev or node:
5391 if rev or node:
5392 raise error.Abort(_("can't specify a revision with --all"))
5392 raise error.Abort(_("can't specify a revision with --all"))
5393
5393
5394 res = []
5394 res = []
5395 prefix = "data/"
5395 prefix = "data/"
5396 suffix = ".i"
5396 suffix = ".i"
5397 plen = len(prefix)
5397 plen = len(prefix)
5398 slen = len(suffix)
5398 slen = len(suffix)
5399 with repo.lock():
5399 with repo.lock():
5400 for fn, b, size in repo.store.datafiles():
5400 for fn, b, size in repo.store.datafiles():
5401 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5401 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5402 res.append(fn[plen:-slen])
5402 res.append(fn[plen:-slen])
5403 for f in res:
5403 for f in res:
5404 fm.startitem()
5404 fm.startitem()
5405 fm.write("path", '%s\n', f)
5405 fm.write("path", '%s\n', f)
5406 fm.end()
5406 fm.end()
5407 return
5407 return
5408
5408
5409 if rev and node:
5409 if rev and node:
5410 raise error.Abort(_("please specify just one revision"))
5410 raise error.Abort(_("please specify just one revision"))
5411
5411
5412 if not node:
5412 if not node:
5413 node = rev
5413 node = rev
5414
5414
5415 char = {'l': '@', 'x': '*', '': ''}
5415 char = {'l': '@', 'x': '*', '': ''}
5416 mode = {'l': '644', 'x': '755', '': '644'}
5416 mode = {'l': '644', 'x': '755', '': '644'}
5417 ctx = scmutil.revsingle(repo, node)
5417 ctx = scmutil.revsingle(repo, node)
5418 mf = ctx.manifest()
5418 mf = ctx.manifest()
5419 for f in ctx:
5419 for f in ctx:
5420 fm.startitem()
5420 fm.startitem()
5421 fl = ctx[f].flags()
5421 fl = ctx[f].flags()
5422 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5422 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5423 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5423 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5424 fm.write('path', '%s\n', f)
5424 fm.write('path', '%s\n', f)
5425 fm.end()
5425 fm.end()
5426
5426
5427 @command('^merge',
5427 @command('^merge',
5428 [('f', 'force', None,
5428 [('f', 'force', None,
5429 _('force a merge including outstanding changes (DEPRECATED)')),
5429 _('force a merge including outstanding changes (DEPRECATED)')),
5430 ('r', 'rev', '', _('revision to merge'), _('REV')),
5430 ('r', 'rev', '', _('revision to merge'), _('REV')),
5431 ('P', 'preview', None,
5431 ('P', 'preview', None,
5432 _('review revisions to merge (no merge is performed)'))
5432 _('review revisions to merge (no merge is performed)'))
5433 ] + mergetoolopts,
5433 ] + mergetoolopts,
5434 _('[-P] [[-r] REV]'))
5434 _('[-P] [[-r] REV]'))
5435 def merge(ui, repo, node=None, **opts):
5435 def merge(ui, repo, node=None, **opts):
5436 """merge another revision into working directory
5436 """merge another revision into working directory
5437
5437
5438 The current working directory is updated with all changes made in
5438 The current working directory is updated with all changes made in
5439 the requested revision since the last common predecessor revision.
5439 the requested revision since the last common predecessor revision.
5440
5440
5441 Files that changed between either parent are marked as changed for
5441 Files that changed between either parent are marked as changed for
5442 the next commit and a commit must be performed before any further
5442 the next commit and a commit must be performed before any further
5443 updates to the repository are allowed. The next commit will have
5443 updates to the repository are allowed. The next commit will have
5444 two parents.
5444 two parents.
5445
5445
5446 ``--tool`` can be used to specify the merge tool used for file
5446 ``--tool`` can be used to specify the merge tool used for file
5447 merges. It overrides the HGMERGE environment variable and your
5447 merges. It overrides the HGMERGE environment variable and your
5448 configuration files. See :hg:`help merge-tools` for options.
5448 configuration files. See :hg:`help merge-tools` for options.
5449
5449
5450 If no revision is specified, the working directory's parent is a
5450 If no revision is specified, the working directory's parent is a
5451 head revision, and the current branch contains exactly one other
5451 head revision, and the current branch contains exactly one other
5452 head, the other head is merged with by default. Otherwise, an
5452 head, the other head is merged with by default. Otherwise, an
5453 explicit revision with which to merge with must be provided.
5453 explicit revision with which to merge with must be provided.
5454
5454
5455 See :hg:`help resolve` for information on handling file conflicts.
5455 See :hg:`help resolve` for information on handling file conflicts.
5456
5456
5457 To undo an uncommitted merge, use :hg:`update --clean .` which
5457 To undo an uncommitted merge, use :hg:`update --clean .` which
5458 will check out a clean copy of the original merge parent, losing
5458 will check out a clean copy of the original merge parent, losing
5459 all changes.
5459 all changes.
5460
5460
5461 Returns 0 on success, 1 if there are unresolved files.
5461 Returns 0 on success, 1 if there are unresolved files.
5462 """
5462 """
5463
5463
5464 if opts.get('rev') and node:
5464 if opts.get('rev') and node:
5465 raise error.Abort(_("please specify just one revision"))
5465 raise error.Abort(_("please specify just one revision"))
5466 if not node:
5466 if not node:
5467 node = opts.get('rev')
5467 node = opts.get('rev')
5468
5468
5469 if node:
5469 if node:
5470 node = scmutil.revsingle(repo, node).node()
5470 node = scmutil.revsingle(repo, node).node()
5471
5471
5472 if not node:
5472 if not node:
5473 node = repo[destutil.destmerge(repo)].node()
5473 node = repo[destutil.destmerge(repo)].node()
5474
5474
5475 if opts.get('preview'):
5475 if opts.get('preview'):
5476 # find nodes that are ancestors of p2 but not of p1
5476 # find nodes that are ancestors of p2 but not of p1
5477 p1 = repo.lookup('.')
5477 p1 = repo.lookup('.')
5478 p2 = repo.lookup(node)
5478 p2 = repo.lookup(node)
5479 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5479 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5480
5480
5481 displayer = cmdutil.show_changeset(ui, repo, opts)
5481 displayer = cmdutil.show_changeset(ui, repo, opts)
5482 for node in nodes:
5482 for node in nodes:
5483 displayer.show(repo[node])
5483 displayer.show(repo[node])
5484 displayer.close()
5484 displayer.close()
5485 return 0
5485 return 0
5486
5486
5487 try:
5487 try:
5488 # ui.forcemerge is an internal variable, do not document
5488 # ui.forcemerge is an internal variable, do not document
5489 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5489 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5490 force = opts.get('force')
5490 force = opts.get('force')
5491 labels = ['working copy', 'merge rev']
5491 labels = ['working copy', 'merge rev']
5492 return hg.merge(repo, node, force=force, mergeforce=force,
5492 return hg.merge(repo, node, force=force, mergeforce=force,
5493 labels=labels)
5493 labels=labels)
5494 finally:
5494 finally:
5495 ui.setconfig('ui', 'forcemerge', '', 'merge')
5495 ui.setconfig('ui', 'forcemerge', '', 'merge')
5496
5496
5497 @command('outgoing|out',
5497 @command('outgoing|out',
5498 [('f', 'force', None, _('run even when the destination is unrelated')),
5498 [('f', 'force', None, _('run even when the destination is unrelated')),
5499 ('r', 'rev', [],
5499 ('r', 'rev', [],
5500 _('a changeset intended to be included in the destination'), _('REV')),
5500 _('a changeset intended to be included in the destination'), _('REV')),
5501 ('n', 'newest-first', None, _('show newest record first')),
5501 ('n', 'newest-first', None, _('show newest record first')),
5502 ('B', 'bookmarks', False, _('compare bookmarks')),
5502 ('B', 'bookmarks', False, _('compare bookmarks')),
5503 ('b', 'branch', [], _('a specific branch you would like to push'),
5503 ('b', 'branch', [], _('a specific branch you would like to push'),
5504 _('BRANCH')),
5504 _('BRANCH')),
5505 ] + logopts + remoteopts + subrepoopts,
5505 ] + logopts + remoteopts + subrepoopts,
5506 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5506 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5507 def outgoing(ui, repo, dest=None, **opts):
5507 def outgoing(ui, repo, dest=None, **opts):
5508 """show changesets not found in the destination
5508 """show changesets not found in the destination
5509
5509
5510 Show changesets not found in the specified destination repository
5510 Show changesets not found in the specified destination repository
5511 or the default push location. These are the changesets that would
5511 or the default push location. These are the changesets that would
5512 be pushed if a push was requested.
5512 be pushed if a push was requested.
5513
5513
5514 See pull for details of valid destination formats.
5514 See pull for details of valid destination formats.
5515
5515
5516 .. container:: verbose
5516 .. container:: verbose
5517
5517
5518 With -B/--bookmarks, the result of bookmark comparison between
5518 With -B/--bookmarks, the result of bookmark comparison between
5519 local and remote repositories is displayed. With -v/--verbose,
5519 local and remote repositories is displayed. With -v/--verbose,
5520 status is also displayed for each bookmark like below::
5520 status is also displayed for each bookmark like below::
5521
5521
5522 BM1 01234567890a added
5522 BM1 01234567890a added
5523 BM2 deleted
5523 BM2 deleted
5524 BM3 234567890abc advanced
5524 BM3 234567890abc advanced
5525 BM4 34567890abcd diverged
5525 BM4 34567890abcd diverged
5526 BM5 4567890abcde changed
5526 BM5 4567890abcde changed
5527
5527
5528 The action taken when pushing depends on the
5528 The action taken when pushing depends on the
5529 status of each bookmark:
5529 status of each bookmark:
5530
5530
5531 :``added``: push with ``-B`` will create it
5531 :``added``: push with ``-B`` will create it
5532 :``deleted``: push with ``-B`` will delete it
5532 :``deleted``: push with ``-B`` will delete it
5533 :``advanced``: push will update it
5533 :``advanced``: push will update it
5534 :``diverged``: push with ``-B`` will update it
5534 :``diverged``: push with ``-B`` will update it
5535 :``changed``: push with ``-B`` will update it
5535 :``changed``: push with ``-B`` will update it
5536
5536
5537 From the point of view of pushing behavior, bookmarks
5537 From the point of view of pushing behavior, bookmarks
5538 existing only in the remote repository are treated as
5538 existing only in the remote repository are treated as
5539 ``deleted``, even if it is in fact added remotely.
5539 ``deleted``, even if it is in fact added remotely.
5540
5540
5541 Returns 0 if there are outgoing changes, 1 otherwise.
5541 Returns 0 if there are outgoing changes, 1 otherwise.
5542 """
5542 """
5543 if opts.get('graph'):
5543 if opts.get('graph'):
5544 cmdutil.checkunsupportedgraphflags([], opts)
5544 cmdutil.checkunsupportedgraphflags([], opts)
5545 o, other = hg._outgoing(ui, repo, dest, opts)
5545 o, other = hg._outgoing(ui, repo, dest, opts)
5546 if not o:
5546 if not o:
5547 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5547 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5548 return
5548 return
5549
5549
5550 revdag = cmdutil.graphrevs(repo, o, opts)
5550 revdag = cmdutil.graphrevs(repo, o, opts)
5551 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5551 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5552 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5552 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5553 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5553 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5554 return 0
5554 return 0
5555
5555
5556 if opts.get('bookmarks'):
5556 if opts.get('bookmarks'):
5557 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5557 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5558 dest, branches = hg.parseurl(dest, opts.get('branch'))
5558 dest, branches = hg.parseurl(dest, opts.get('branch'))
5559 other = hg.peer(repo, opts, dest)
5559 other = hg.peer(repo, opts, dest)
5560 if 'bookmarks' not in other.listkeys('namespaces'):
5560 if 'bookmarks' not in other.listkeys('namespaces'):
5561 ui.warn(_("remote doesn't support bookmarks\n"))
5561 ui.warn(_("remote doesn't support bookmarks\n"))
5562 return 0
5562 return 0
5563 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5563 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5564 return bookmarks.outgoing(ui, repo, other)
5564 return bookmarks.outgoing(ui, repo, other)
5565
5565
5566 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5566 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5567 try:
5567 try:
5568 return hg.outgoing(ui, repo, dest, opts)
5568 return hg.outgoing(ui, repo, dest, opts)
5569 finally:
5569 finally:
5570 del repo._subtoppath
5570 del repo._subtoppath
5571
5571
5572 @command('parents',
5572 @command('parents',
5573 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5573 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5574 ] + templateopts,
5574 ] + templateopts,
5575 _('[-r REV] [FILE]'),
5575 _('[-r REV] [FILE]'),
5576 inferrepo=True)
5576 inferrepo=True)
5577 def parents(ui, repo, file_=None, **opts):
5577 def parents(ui, repo, file_=None, **opts):
5578 """show the parents of the working directory or revision (DEPRECATED)
5578 """show the parents of the working directory or revision (DEPRECATED)
5579
5579
5580 Print the working directory's parent revisions. If a revision is
5580 Print the working directory's parent revisions. If a revision is
5581 given via -r/--rev, the parent of that revision will be printed.
5581 given via -r/--rev, the parent of that revision will be printed.
5582 If a file argument is given, the revision in which the file was
5582 If a file argument is given, the revision in which the file was
5583 last changed (before the working directory revision or the
5583 last changed (before the working directory revision or the
5584 argument to --rev if given) is printed.
5584 argument to --rev if given) is printed.
5585
5585
5586 This command is equivalent to::
5586 This command is equivalent to::
5587
5587
5588 hg log -r "p1()+p2()" or
5588 hg log -r "p1()+p2()" or
5589 hg log -r "p1(REV)+p2(REV)" or
5589 hg log -r "p1(REV)+p2(REV)" or
5590 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5590 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5591 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5591 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5592
5592
5593 See :hg:`summary` and :hg:`help revsets` for related information.
5593 See :hg:`summary` and :hg:`help revsets` for related information.
5594
5594
5595 Returns 0 on success.
5595 Returns 0 on success.
5596 """
5596 """
5597
5597
5598 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5598 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5599
5599
5600 if file_:
5600 if file_:
5601 m = scmutil.match(ctx, (file_,), opts)
5601 m = scmutil.match(ctx, (file_,), opts)
5602 if m.anypats() or len(m.files()) != 1:
5602 if m.anypats() or len(m.files()) != 1:
5603 raise error.Abort(_('can only specify an explicit filename'))
5603 raise error.Abort(_('can only specify an explicit filename'))
5604 file_ = m.files()[0]
5604 file_ = m.files()[0]
5605 filenodes = []
5605 filenodes = []
5606 for cp in ctx.parents():
5606 for cp in ctx.parents():
5607 if not cp:
5607 if not cp:
5608 continue
5608 continue
5609 try:
5609 try:
5610 filenodes.append(cp.filenode(file_))
5610 filenodes.append(cp.filenode(file_))
5611 except error.LookupError:
5611 except error.LookupError:
5612 pass
5612 pass
5613 if not filenodes:
5613 if not filenodes:
5614 raise error.Abort(_("'%s' not found in manifest!") % file_)
5614 raise error.Abort(_("'%s' not found in manifest!") % file_)
5615 p = []
5615 p = []
5616 for fn in filenodes:
5616 for fn in filenodes:
5617 fctx = repo.filectx(file_, fileid=fn)
5617 fctx = repo.filectx(file_, fileid=fn)
5618 p.append(fctx.node())
5618 p.append(fctx.node())
5619 else:
5619 else:
5620 p = [cp.node() for cp in ctx.parents()]
5620 p = [cp.node() for cp in ctx.parents()]
5621
5621
5622 displayer = cmdutil.show_changeset(ui, repo, opts)
5622 displayer = cmdutil.show_changeset(ui, repo, opts)
5623 for n in p:
5623 for n in p:
5624 if n != nullid:
5624 if n != nullid:
5625 displayer.show(repo[n])
5625 displayer.show(repo[n])
5626 displayer.close()
5626 displayer.close()
5627
5627
5628 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5628 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5629 def paths(ui, repo, search=None, **opts):
5629 def paths(ui, repo, search=None, **opts):
5630 """show aliases for remote repositories
5630 """show aliases for remote repositories
5631
5631
5632 Show definition of symbolic path name NAME. If no name is given,
5632 Show definition of symbolic path name NAME. If no name is given,
5633 show definition of all available names.
5633 show definition of all available names.
5634
5634
5635 Option -q/--quiet suppresses all output when searching for NAME
5635 Option -q/--quiet suppresses all output when searching for NAME
5636 and shows only the path names when listing all definitions.
5636 and shows only the path names when listing all definitions.
5637
5637
5638 Path names are defined in the [paths] section of your
5638 Path names are defined in the [paths] section of your
5639 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5639 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5640 repository, ``.hg/hgrc`` is used, too.
5640 repository, ``.hg/hgrc`` is used, too.
5641
5641
5642 The path names ``default`` and ``default-push`` have a special
5642 The path names ``default`` and ``default-push`` have a special
5643 meaning. When performing a push or pull operation, they are used
5643 meaning. When performing a push or pull operation, they are used
5644 as fallbacks if no location is specified on the command-line.
5644 as fallbacks if no location is specified on the command-line.
5645 When ``default-push`` is set, it will be used for push and
5645 When ``default-push`` is set, it will be used for push and
5646 ``default`` will be used for pull; otherwise ``default`` is used
5646 ``default`` will be used for pull; otherwise ``default`` is used
5647 as the fallback for both. When cloning a repository, the clone
5647 as the fallback for both. When cloning a repository, the clone
5648 source is written as ``default`` in ``.hg/hgrc``.
5648 source is written as ``default`` in ``.hg/hgrc``.
5649
5649
5650 .. note::
5650 .. note::
5651
5651
5652 ``default`` and ``default-push`` apply to all inbound (e.g.
5652 ``default`` and ``default-push`` apply to all inbound (e.g.
5653 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5653 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5654 and :hg:`bundle`) operations.
5654 and :hg:`bundle`) operations.
5655
5655
5656 See :hg:`help urls` for more information.
5656 See :hg:`help urls` for more information.
5657
5657
5658 Returns 0 on success.
5658 Returns 0 on success.
5659 """
5659 """
5660 if search:
5660 if search:
5661 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5661 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5662 if name == search]
5662 if name == search]
5663 else:
5663 else:
5664 pathitems = sorted(ui.paths.iteritems())
5664 pathitems = sorted(ui.paths.iteritems())
5665
5665
5666 fm = ui.formatter('paths', opts)
5666 fm = ui.formatter('paths', opts)
5667 if fm.isplain():
5667 if fm.isplain():
5668 hidepassword = util.hidepassword
5668 hidepassword = util.hidepassword
5669 else:
5669 else:
5670 hidepassword = str
5670 hidepassword = str
5671 if ui.quiet:
5671 if ui.quiet:
5672 namefmt = '%s\n'
5672 namefmt = '%s\n'
5673 else:
5673 else:
5674 namefmt = '%s = '
5674 namefmt = '%s = '
5675 showsubopts = not search and not ui.quiet
5675 showsubopts = not search and not ui.quiet
5676
5676
5677 for name, path in pathitems:
5677 for name, path in pathitems:
5678 fm.startitem()
5678 fm.startitem()
5679 fm.condwrite(not search, 'name', namefmt, name)
5679 fm.condwrite(not search, 'name', namefmt, name)
5680 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5680 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5681 for subopt, value in sorted(path.suboptions.items()):
5681 for subopt, value in sorted(path.suboptions.items()):
5682 assert subopt not in ('name', 'url')
5682 assert subopt not in ('name', 'url')
5683 if showsubopts:
5683 if showsubopts:
5684 fm.plain('%s:%s = ' % (name, subopt))
5684 fm.plain('%s:%s = ' % (name, subopt))
5685 fm.condwrite(showsubopts, subopt, '%s\n', value)
5685 fm.condwrite(showsubopts, subopt, '%s\n', value)
5686
5686
5687 fm.end()
5687 fm.end()
5688
5688
5689 if search and not pathitems:
5689 if search and not pathitems:
5690 if not ui.quiet:
5690 if not ui.quiet:
5691 ui.warn(_("not found!\n"))
5691 ui.warn(_("not found!\n"))
5692 return 1
5692 return 1
5693 else:
5693 else:
5694 return 0
5694 return 0
5695
5695
5696 @command('phase',
5696 @command('phase',
5697 [('p', 'public', False, _('set changeset phase to public')),
5697 [('p', 'public', False, _('set changeset phase to public')),
5698 ('d', 'draft', False, _('set changeset phase to draft')),
5698 ('d', 'draft', False, _('set changeset phase to draft')),
5699 ('s', 'secret', False, _('set changeset phase to secret')),
5699 ('s', 'secret', False, _('set changeset phase to secret')),
5700 ('f', 'force', False, _('allow to move boundary backward')),
5700 ('f', 'force', False, _('allow to move boundary backward')),
5701 ('r', 'rev', [], _('target revision'), _('REV')),
5701 ('r', 'rev', [], _('target revision'), _('REV')),
5702 ],
5702 ],
5703 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5703 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5704 def phase(ui, repo, *revs, **opts):
5704 def phase(ui, repo, *revs, **opts):
5705 """set or show the current phase name
5705 """set or show the current phase name
5706
5706
5707 With no argument, show the phase name of the current revision(s).
5707 With no argument, show the phase name of the current revision(s).
5708
5708
5709 With one of -p/--public, -d/--draft or -s/--secret, change the
5709 With one of -p/--public, -d/--draft or -s/--secret, change the
5710 phase value of the specified revisions.
5710 phase value of the specified revisions.
5711
5711
5712 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5712 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5713 lower phase to an higher phase. Phases are ordered as follows::
5713 lower phase to an higher phase. Phases are ordered as follows::
5714
5714
5715 public < draft < secret
5715 public < draft < secret
5716
5716
5717 Returns 0 on success, 1 if some phases could not be changed.
5717 Returns 0 on success, 1 if some phases could not be changed.
5718
5718
5719 (For more information about the phases concept, see :hg:`help phases`.)
5719 (For more information about the phases concept, see :hg:`help phases`.)
5720 """
5720 """
5721 # search for a unique phase argument
5721 # search for a unique phase argument
5722 targetphase = None
5722 targetphase = None
5723 for idx, name in enumerate(phases.phasenames):
5723 for idx, name in enumerate(phases.phasenames):
5724 if opts[name]:
5724 if opts[name]:
5725 if targetphase is not None:
5725 if targetphase is not None:
5726 raise error.Abort(_('only one phase can be specified'))
5726 raise error.Abort(_('only one phase can be specified'))
5727 targetphase = idx
5727 targetphase = idx
5728
5728
5729 # look for specified revision
5729 # look for specified revision
5730 revs = list(revs)
5730 revs = list(revs)
5731 revs.extend(opts['rev'])
5731 revs.extend(opts['rev'])
5732 if not revs:
5732 if not revs:
5733 # display both parents as the second parent phase can influence
5733 # display both parents as the second parent phase can influence
5734 # the phase of a merge commit
5734 # the phase of a merge commit
5735 revs = [c.rev() for c in repo[None].parents()]
5735 revs = [c.rev() for c in repo[None].parents()]
5736
5736
5737 revs = scmutil.revrange(repo, revs)
5737 revs = scmutil.revrange(repo, revs)
5738
5738
5739 lock = None
5739 lock = None
5740 ret = 0
5740 ret = 0
5741 if targetphase is None:
5741 if targetphase is None:
5742 # display
5742 # display
5743 for r in revs:
5743 for r in revs:
5744 ctx = repo[r]
5744 ctx = repo[r]
5745 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5745 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5746 else:
5746 else:
5747 tr = None
5747 tr = None
5748 lock = repo.lock()
5748 lock = repo.lock()
5749 try:
5749 try:
5750 tr = repo.transaction("phase")
5750 tr = repo.transaction("phase")
5751 # set phase
5751 # set phase
5752 if not revs:
5752 if not revs:
5753 raise error.Abort(_('empty revision set'))
5753 raise error.Abort(_('empty revision set'))
5754 nodes = [repo[r].node() for r in revs]
5754 nodes = [repo[r].node() for r in revs]
5755 # moving revision from public to draft may hide them
5755 # moving revision from public to draft may hide them
5756 # We have to check result on an unfiltered repository
5756 # We have to check result on an unfiltered repository
5757 unfi = repo.unfiltered()
5757 unfi = repo.unfiltered()
5758 getphase = unfi._phasecache.phase
5758 getphase = unfi._phasecache.phase
5759 olddata = [getphase(unfi, r) for r in unfi]
5759 olddata = [getphase(unfi, r) for r in unfi]
5760 phases.advanceboundary(repo, tr, targetphase, nodes)
5760 phases.advanceboundary(repo, tr, targetphase, nodes)
5761 if opts['force']:
5761 if opts['force']:
5762 phases.retractboundary(repo, tr, targetphase, nodes)
5762 phases.retractboundary(repo, tr, targetphase, nodes)
5763 tr.close()
5763 tr.close()
5764 finally:
5764 finally:
5765 if tr is not None:
5765 if tr is not None:
5766 tr.release()
5766 tr.release()
5767 lock.release()
5767 lock.release()
5768 getphase = unfi._phasecache.phase
5768 getphase = unfi._phasecache.phase
5769 newdata = [getphase(unfi, r) for r in unfi]
5769 newdata = [getphase(unfi, r) for r in unfi]
5770 changes = sum(newdata[r] != olddata[r] for r in unfi)
5770 changes = sum(newdata[r] != olddata[r] for r in unfi)
5771 cl = unfi.changelog
5771 cl = unfi.changelog
5772 rejected = [n for n in nodes
5772 rejected = [n for n in nodes
5773 if newdata[cl.rev(n)] < targetphase]
5773 if newdata[cl.rev(n)] < targetphase]
5774 if rejected:
5774 if rejected:
5775 ui.warn(_('cannot move %i changesets to a higher '
5775 ui.warn(_('cannot move %i changesets to a higher '
5776 'phase, use --force\n') % len(rejected))
5776 'phase, use --force\n') % len(rejected))
5777 ret = 1
5777 ret = 1
5778 if changes:
5778 if changes:
5779 msg = _('phase changed for %i changesets\n') % changes
5779 msg = _('phase changed for %i changesets\n') % changes
5780 if ret:
5780 if ret:
5781 ui.status(msg)
5781 ui.status(msg)
5782 else:
5782 else:
5783 ui.note(msg)
5783 ui.note(msg)
5784 else:
5784 else:
5785 ui.warn(_('no phases changed\n'))
5785 ui.warn(_('no phases changed\n'))
5786 return ret
5786 return ret
5787
5787
5788 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5788 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5789 """Run after a changegroup has been added via pull/unbundle
5789 """Run after a changegroup has been added via pull/unbundle
5790
5790
5791 This takes arguments below:
5791 This takes arguments below:
5792
5792
5793 :modheads: change of heads by pull/unbundle
5793 :modheads: change of heads by pull/unbundle
5794 :optupdate: updating working directory is needed or not
5794 :optupdate: updating working directory is needed or not
5795 :checkout: update destination revision (or None to default destination)
5795 :checkout: update destination revision (or None to default destination)
5796 :brev: a name, which might be a bookmark to be activated after updating
5796 :brev: a name, which might be a bookmark to be activated after updating
5797 """
5797 """
5798 if modheads == 0:
5798 if modheads == 0:
5799 return
5799 return
5800 if optupdate:
5800 if optupdate:
5801 try:
5801 try:
5802 return hg.updatetotally(ui, repo, checkout, brev)
5802 return hg.updatetotally(ui, repo, checkout, brev)
5803 except error.UpdateAbort as inst:
5803 except error.UpdateAbort as inst:
5804 msg = _("not updating: %s") % str(inst)
5804 msg = _("not updating: %s") % str(inst)
5805 hint = inst.hint
5805 hint = inst.hint
5806 raise error.UpdateAbort(msg, hint=hint)
5806 raise error.UpdateAbort(msg, hint=hint)
5807 if modheads > 1:
5807 if modheads > 1:
5808 currentbranchheads = len(repo.branchheads())
5808 currentbranchheads = len(repo.branchheads())
5809 if currentbranchheads == modheads:
5809 if currentbranchheads == modheads:
5810 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5810 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5811 elif currentbranchheads > 1:
5811 elif currentbranchheads > 1:
5812 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5812 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5813 "merge)\n"))
5813 "merge)\n"))
5814 else:
5814 else:
5815 ui.status(_("(run 'hg heads' to see heads)\n"))
5815 ui.status(_("(run 'hg heads' to see heads)\n"))
5816 else:
5816 else:
5817 ui.status(_("(run 'hg update' to get a working copy)\n"))
5817 ui.status(_("(run 'hg update' to get a working copy)\n"))
5818
5818
5819 @command('^pull',
5819 @command('^pull',
5820 [('u', 'update', None,
5820 [('u', 'update', None,
5821 _('update to new branch head if changesets were pulled')),
5821 _('update to new branch head if changesets were pulled')),
5822 ('f', 'force', None, _('run even when remote repository is unrelated')),
5822 ('f', 'force', None, _('run even when remote repository is unrelated')),
5823 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5823 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5824 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5824 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5825 ('b', 'branch', [], _('a specific branch you would like to pull'),
5825 ('b', 'branch', [], _('a specific branch you would like to pull'),
5826 _('BRANCH')),
5826 _('BRANCH')),
5827 ] + remoteopts,
5827 ] + remoteopts,
5828 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5828 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5829 def pull(ui, repo, source="default", **opts):
5829 def pull(ui, repo, source="default", **opts):
5830 """pull changes from the specified source
5830 """pull changes from the specified source
5831
5831
5832 Pull changes from a remote repository to a local one.
5832 Pull changes from a remote repository to a local one.
5833
5833
5834 This finds all changes from the repository at the specified path
5834 This finds all changes from the repository at the specified path
5835 or URL and adds them to a local repository (the current one unless
5835 or URL and adds them to a local repository (the current one unless
5836 -R is specified). By default, this does not update the copy of the
5836 -R is specified). By default, this does not update the copy of the
5837 project in the working directory.
5837 project in the working directory.
5838
5838
5839 Use :hg:`incoming` if you want to see what would have been added
5839 Use :hg:`incoming` if you want to see what would have been added
5840 by a pull at the time you issued this command. If you then decide
5840 by a pull at the time you issued this command. If you then decide
5841 to add those changes to the repository, you should use :hg:`pull
5841 to add those changes to the repository, you should use :hg:`pull
5842 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5842 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5843
5843
5844 If SOURCE is omitted, the 'default' path will be used.
5844 If SOURCE is omitted, the 'default' path will be used.
5845 See :hg:`help urls` for more information.
5845 See :hg:`help urls` for more information.
5846
5846
5847 Specifying bookmark as ``.`` is equivalent to specifying the active
5847 Specifying bookmark as ``.`` is equivalent to specifying the active
5848 bookmark's name.
5848 bookmark's name.
5849
5849
5850 Returns 0 on success, 1 if an update had unresolved files.
5850 Returns 0 on success, 1 if an update had unresolved files.
5851 """
5851 """
5852 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5852 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5853 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5853 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5854 other = hg.peer(repo, opts, source)
5854 other = hg.peer(repo, opts, source)
5855 try:
5855 try:
5856 revs, checkout = hg.addbranchrevs(repo, other, branches,
5856 revs, checkout = hg.addbranchrevs(repo, other, branches,
5857 opts.get('rev'))
5857 opts.get('rev'))
5858
5858
5859
5859
5860 pullopargs = {}
5860 pullopargs = {}
5861 if opts.get('bookmark'):
5861 if opts.get('bookmark'):
5862 if not revs:
5862 if not revs:
5863 revs = []
5863 revs = []
5864 # The list of bookmark used here is not the one used to actually
5864 # The list of bookmark used here is not the one used to actually
5865 # update the bookmark name. This can result in the revision pulled
5865 # update the bookmark name. This can result in the revision pulled
5866 # not ending up with the name of the bookmark because of a race
5866 # not ending up with the name of the bookmark because of a race
5867 # condition on the server. (See issue 4689 for details)
5867 # condition on the server. (See issue 4689 for details)
5868 remotebookmarks = other.listkeys('bookmarks')
5868 remotebookmarks = other.listkeys('bookmarks')
5869 pullopargs['remotebookmarks'] = remotebookmarks
5869 pullopargs['remotebookmarks'] = remotebookmarks
5870 for b in opts['bookmark']:
5870 for b in opts['bookmark']:
5871 b = repo._bookmarks.expandname(b)
5871 b = repo._bookmarks.expandname(b)
5872 if b not in remotebookmarks:
5872 if b not in remotebookmarks:
5873 raise error.Abort(_('remote bookmark %s not found!') % b)
5873 raise error.Abort(_('remote bookmark %s not found!') % b)
5874 revs.append(remotebookmarks[b])
5874 revs.append(remotebookmarks[b])
5875
5875
5876 if revs:
5876 if revs:
5877 try:
5877 try:
5878 # When 'rev' is a bookmark name, we cannot guarantee that it
5878 # When 'rev' is a bookmark name, we cannot guarantee that it
5879 # will be updated with that name because of a race condition
5879 # will be updated with that name because of a race condition
5880 # server side. (See issue 4689 for details)
5880 # server side. (See issue 4689 for details)
5881 oldrevs = revs
5881 oldrevs = revs
5882 revs = [] # actually, nodes
5882 revs = [] # actually, nodes
5883 for r in oldrevs:
5883 for r in oldrevs:
5884 node = other.lookup(r)
5884 node = other.lookup(r)
5885 revs.append(node)
5885 revs.append(node)
5886 if r == checkout:
5886 if r == checkout:
5887 checkout = node
5887 checkout = node
5888 except error.CapabilityError:
5888 except error.CapabilityError:
5889 err = _("other repository doesn't support revision lookup, "
5889 err = _("other repository doesn't support revision lookup, "
5890 "so a rev cannot be specified.")
5890 "so a rev cannot be specified.")
5891 raise error.Abort(err)
5891 raise error.Abort(err)
5892
5892
5893 pullopargs.update(opts.get('opargs', {}))
5893 pullopargs.update(opts.get('opargs', {}))
5894 modheads = exchange.pull(repo, other, heads=revs,
5894 modheads = exchange.pull(repo, other, heads=revs,
5895 force=opts.get('force'),
5895 force=opts.get('force'),
5896 bookmarks=opts.get('bookmark', ()),
5896 bookmarks=opts.get('bookmark', ()),
5897 opargs=pullopargs).cgresult
5897 opargs=pullopargs).cgresult
5898
5898
5899 # brev is a name, which might be a bookmark to be activated at
5899 # brev is a name, which might be a bookmark to be activated at
5900 # the end of the update. In other words, it is an explicit
5900 # the end of the update. In other words, it is an explicit
5901 # destination of the update
5901 # destination of the update
5902 brev = None
5902 brev = None
5903
5903
5904 if checkout:
5904 if checkout:
5905 checkout = str(repo.changelog.rev(checkout))
5905 checkout = str(repo.changelog.rev(checkout))
5906
5906
5907 # order below depends on implementation of
5907 # order below depends on implementation of
5908 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5908 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5909 # because 'checkout' is determined without it.
5909 # because 'checkout' is determined without it.
5910 if opts.get('rev'):
5910 if opts.get('rev'):
5911 brev = opts['rev'][0]
5911 brev = opts['rev'][0]
5912 elif opts.get('branch'):
5912 elif opts.get('branch'):
5913 brev = opts['branch'][0]
5913 brev = opts['branch'][0]
5914 else:
5914 else:
5915 brev = branches[0]
5915 brev = branches[0]
5916 repo._subtoppath = source
5916 repo._subtoppath = source
5917 try:
5917 try:
5918 ret = postincoming(ui, repo, modheads, opts.get('update'),
5918 ret = postincoming(ui, repo, modheads, opts.get('update'),
5919 checkout, brev)
5919 checkout, brev)
5920
5920
5921 finally:
5921 finally:
5922 del repo._subtoppath
5922 del repo._subtoppath
5923
5923
5924 finally:
5924 finally:
5925 other.close()
5925 other.close()
5926 return ret
5926 return ret
5927
5927
5928 @command('^push',
5928 @command('^push',
5929 [('f', 'force', None, _('force push')),
5929 [('f', 'force', None, _('force push')),
5930 ('r', 'rev', [],
5930 ('r', 'rev', [],
5931 _('a changeset intended to be included in the destination'),
5931 _('a changeset intended to be included in the destination'),
5932 _('REV')),
5932 _('REV')),
5933 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5933 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5934 ('b', 'branch', [],
5934 ('b', 'branch', [],
5935 _('a specific branch you would like to push'), _('BRANCH')),
5935 _('a specific branch you would like to push'), _('BRANCH')),
5936 ('', 'new-branch', False, _('allow pushing a new branch')),
5936 ('', 'new-branch', False, _('allow pushing a new branch')),
5937 ] + remoteopts,
5937 ] + remoteopts,
5938 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5938 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5939 def push(ui, repo, dest=None, **opts):
5939 def push(ui, repo, dest=None, **opts):
5940 """push changes to the specified destination
5940 """push changes to the specified destination
5941
5941
5942 Push changesets from the local repository to the specified
5942 Push changesets from the local repository to the specified
5943 destination.
5943 destination.
5944
5944
5945 This operation is symmetrical to pull: it is identical to a pull
5945 This operation is symmetrical to pull: it is identical to a pull
5946 in the destination repository from the current one.
5946 in the destination repository from the current one.
5947
5947
5948 By default, push will not allow creation of new heads at the
5948 By default, push will not allow creation of new heads at the
5949 destination, since multiple heads would make it unclear which head
5949 destination, since multiple heads would make it unclear which head
5950 to use. In this situation, it is recommended to pull and merge
5950 to use. In this situation, it is recommended to pull and merge
5951 before pushing.
5951 before pushing.
5952
5952
5953 Use --new-branch if you want to allow push to create a new named
5953 Use --new-branch if you want to allow push to create a new named
5954 branch that is not present at the destination. This allows you to
5954 branch that is not present at the destination. This allows you to
5955 only create a new branch without forcing other changes.
5955 only create a new branch without forcing other changes.
5956
5956
5957 .. note::
5957 .. note::
5958
5958
5959 Extra care should be taken with the -f/--force option,
5959 Extra care should be taken with the -f/--force option,
5960 which will push all new heads on all branches, an action which will
5960 which will push all new heads on all branches, an action which will
5961 almost always cause confusion for collaborators.
5961 almost always cause confusion for collaborators.
5962
5962
5963 If -r/--rev is used, the specified revision and all its ancestors
5963 If -r/--rev is used, the specified revision and all its ancestors
5964 will be pushed to the remote repository.
5964 will be pushed to the remote repository.
5965
5965
5966 If -B/--bookmark is used, the specified bookmarked revision, its
5966 If -B/--bookmark is used, the specified bookmarked revision, its
5967 ancestors, and the bookmark will be pushed to the remote
5967 ancestors, and the bookmark will be pushed to the remote
5968 repository. Specifying ``.`` is equivalent to specifying the active
5968 repository. Specifying ``.`` is equivalent to specifying the active
5969 bookmark's name.
5969 bookmark's name.
5970
5970
5971 Please see :hg:`help urls` for important details about ``ssh://``
5971 Please see :hg:`help urls` for important details about ``ssh://``
5972 URLs. If DESTINATION is omitted, a default path will be used.
5972 URLs. If DESTINATION is omitted, a default path will be used.
5973
5973
5974 Returns 0 if push was successful, 1 if nothing to push.
5974 Returns 0 if push was successful, 1 if nothing to push.
5975 """
5975 """
5976
5976
5977 if opts.get('bookmark'):
5977 if opts.get('bookmark'):
5978 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5978 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5979 for b in opts['bookmark']:
5979 for b in opts['bookmark']:
5980 # translate -B options to -r so changesets get pushed
5980 # translate -B options to -r so changesets get pushed
5981 b = repo._bookmarks.expandname(b)
5981 b = repo._bookmarks.expandname(b)
5982 if b in repo._bookmarks:
5982 if b in repo._bookmarks:
5983 opts.setdefault('rev', []).append(b)
5983 opts.setdefault('rev', []).append(b)
5984 else:
5984 else:
5985 # if we try to push a deleted bookmark, translate it to null
5985 # if we try to push a deleted bookmark, translate it to null
5986 # this lets simultaneous -r, -b options continue working
5986 # this lets simultaneous -r, -b options continue working
5987 opts.setdefault('rev', []).append("null")
5987 opts.setdefault('rev', []).append("null")
5988
5988
5989 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5989 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5990 if not path:
5990 if not path:
5991 raise error.Abort(_('default repository not configured!'),
5991 raise error.Abort(_('default repository not configured!'),
5992 hint=_("see 'hg help config.paths'"))
5992 hint=_("see 'hg help config.paths'"))
5993 dest = path.pushloc or path.loc
5993 dest = path.pushloc or path.loc
5994 branches = (path.branch, opts.get('branch') or [])
5994 branches = (path.branch, opts.get('branch') or [])
5995 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5995 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5996 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5996 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5997 other = hg.peer(repo, opts, dest)
5997 other = hg.peer(repo, opts, dest)
5998
5998
5999 if revs:
5999 if revs:
6000 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
6000 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
6001 if not revs:
6001 if not revs:
6002 raise error.Abort(_("specified revisions evaluate to an empty set"),
6002 raise error.Abort(_("specified revisions evaluate to an empty set"),
6003 hint=_("use different revision arguments"))
6003 hint=_("use different revision arguments"))
6004 elif path.pushrev:
6004 elif path.pushrev:
6005 # It doesn't make any sense to specify ancestor revisions. So limit
6005 # It doesn't make any sense to specify ancestor revisions. So limit
6006 # to DAG heads to make discovery simpler.
6006 # to DAG heads to make discovery simpler.
6007 expr = revset.formatspec('heads(%r)', path.pushrev)
6007 expr = revset.formatspec('heads(%r)', path.pushrev)
6008 revs = scmutil.revrange(repo, [expr])
6008 revs = scmutil.revrange(repo, [expr])
6009 revs = [repo[rev].node() for rev in revs]
6009 revs = [repo[rev].node() for rev in revs]
6010 if not revs:
6010 if not revs:
6011 raise error.Abort(_('default push revset for path evaluates to an '
6011 raise error.Abort(_('default push revset for path evaluates to an '
6012 'empty set'))
6012 'empty set'))
6013
6013
6014 repo._subtoppath = dest
6014 repo._subtoppath = dest
6015 try:
6015 try:
6016 # push subrepos depth-first for coherent ordering
6016 # push subrepos depth-first for coherent ordering
6017 c = repo['']
6017 c = repo['']
6018 subs = c.substate # only repos that are committed
6018 subs = c.substate # only repos that are committed
6019 for s in sorted(subs):
6019 for s in sorted(subs):
6020 result = c.sub(s).push(opts)
6020 result = c.sub(s).push(opts)
6021 if result == 0:
6021 if result == 0:
6022 return not result
6022 return not result
6023 finally:
6023 finally:
6024 del repo._subtoppath
6024 del repo._subtoppath
6025 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6025 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6026 newbranch=opts.get('new_branch'),
6026 newbranch=opts.get('new_branch'),
6027 bookmarks=opts.get('bookmark', ()),
6027 bookmarks=opts.get('bookmark', ()),
6028 opargs=opts.get('opargs'))
6028 opargs=opts.get('opargs'))
6029
6029
6030 result = not pushop.cgresult
6030 result = not pushop.cgresult
6031
6031
6032 if pushop.bkresult is not None:
6032 if pushop.bkresult is not None:
6033 if pushop.bkresult == 2:
6033 if pushop.bkresult == 2:
6034 result = 2
6034 result = 2
6035 elif not result and pushop.bkresult:
6035 elif not result and pushop.bkresult:
6036 result = 2
6036 result = 2
6037
6037
6038 return result
6038 return result
6039
6039
6040 @command('recover', [])
6040 @command('recover', [])
6041 def recover(ui, repo):
6041 def recover(ui, repo):
6042 """roll back an interrupted transaction
6042 """roll back an interrupted transaction
6043
6043
6044 Recover from an interrupted commit or pull.
6044 Recover from an interrupted commit or pull.
6045
6045
6046 This command tries to fix the repository status after an
6046 This command tries to fix the repository status after an
6047 interrupted operation. It should only be necessary when Mercurial
6047 interrupted operation. It should only be necessary when Mercurial
6048 suggests it.
6048 suggests it.
6049
6049
6050 Returns 0 if successful, 1 if nothing to recover or verify fails.
6050 Returns 0 if successful, 1 if nothing to recover or verify fails.
6051 """
6051 """
6052 if repo.recover():
6052 if repo.recover():
6053 return hg.verify(repo)
6053 return hg.verify(repo)
6054 return 1
6054 return 1
6055
6055
6056 @command('^remove|rm',
6056 @command('^remove|rm',
6057 [('A', 'after', None, _('record delete for missing files')),
6057 [('A', 'after', None, _('record delete for missing files')),
6058 ('f', 'force', None,
6058 ('f', 'force', None,
6059 _('forget added files, delete modified files')),
6059 _('forget added files, delete modified files')),
6060 ] + subrepoopts + walkopts,
6060 ] + subrepoopts + walkopts,
6061 _('[OPTION]... FILE...'),
6061 _('[OPTION]... FILE...'),
6062 inferrepo=True)
6062 inferrepo=True)
6063 def remove(ui, repo, *pats, **opts):
6063 def remove(ui, repo, *pats, **opts):
6064 """remove the specified files on the next commit
6064 """remove the specified files on the next commit
6065
6065
6066 Schedule the indicated files for removal from the current branch.
6066 Schedule the indicated files for removal from the current branch.
6067
6067
6068 This command schedules the files to be removed at the next commit.
6068 This command schedules the files to be removed at the next commit.
6069 To undo a remove before that, see :hg:`revert`. To undo added
6069 To undo a remove before that, see :hg:`revert`. To undo added
6070 files, see :hg:`forget`.
6070 files, see :hg:`forget`.
6071
6071
6072 .. container:: verbose
6072 .. container:: verbose
6073
6073
6074 -A/--after can be used to remove only files that have already
6074 -A/--after can be used to remove only files that have already
6075 been deleted, -f/--force can be used to force deletion, and -Af
6075 been deleted, -f/--force can be used to force deletion, and -Af
6076 can be used to remove files from the next revision without
6076 can be used to remove files from the next revision without
6077 deleting them from the working directory.
6077 deleting them from the working directory.
6078
6078
6079 The following table details the behavior of remove for different
6079 The following table details the behavior of remove for different
6080 file states (columns) and option combinations (rows). The file
6080 file states (columns) and option combinations (rows). The file
6081 states are Added [A], Clean [C], Modified [M] and Missing [!]
6081 states are Added [A], Clean [C], Modified [M] and Missing [!]
6082 (as reported by :hg:`status`). The actions are Warn, Remove
6082 (as reported by :hg:`status`). The actions are Warn, Remove
6083 (from branch) and Delete (from disk):
6083 (from branch) and Delete (from disk):
6084
6084
6085 ========= == == == ==
6085 ========= == == == ==
6086 opt/state A C M !
6086 opt/state A C M !
6087 ========= == == == ==
6087 ========= == == == ==
6088 none W RD W R
6088 none W RD W R
6089 -f R RD RD R
6089 -f R RD RD R
6090 -A W W W R
6090 -A W W W R
6091 -Af R R R R
6091 -Af R R R R
6092 ========= == == == ==
6092 ========= == == == ==
6093
6093
6094 .. note::
6094 .. note::
6095
6095
6096 :hg:`remove` never deletes files in Added [A] state from the
6096 :hg:`remove` never deletes files in Added [A] state from the
6097 working directory, not even if ``--force`` is specified.
6097 working directory, not even if ``--force`` is specified.
6098
6098
6099 Returns 0 on success, 1 if any warnings encountered.
6099 Returns 0 on success, 1 if any warnings encountered.
6100 """
6100 """
6101
6101
6102 after, force = opts.get('after'), opts.get('force')
6102 after, force = opts.get('after'), opts.get('force')
6103 if not pats and not after:
6103 if not pats and not after:
6104 raise error.Abort(_('no files specified'))
6104 raise error.Abort(_('no files specified'))
6105
6105
6106 m = scmutil.match(repo[None], pats, opts)
6106 m = scmutil.match(repo[None], pats, opts)
6107 subrepos = opts.get('subrepos')
6107 subrepos = opts.get('subrepos')
6108 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6108 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6109
6109
6110 @command('rename|move|mv',
6110 @command('rename|move|mv',
6111 [('A', 'after', None, _('record a rename that has already occurred')),
6111 [('A', 'after', None, _('record a rename that has already occurred')),
6112 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6112 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6113 ] + walkopts + dryrunopts,
6113 ] + walkopts + dryrunopts,
6114 _('[OPTION]... SOURCE... DEST'))
6114 _('[OPTION]... SOURCE... DEST'))
6115 def rename(ui, repo, *pats, **opts):
6115 def rename(ui, repo, *pats, **opts):
6116 """rename files; equivalent of copy + remove
6116 """rename files; equivalent of copy + remove
6117
6117
6118 Mark dest as copies of sources; mark sources for deletion. If dest
6118 Mark dest as copies of sources; mark sources for deletion. If dest
6119 is a directory, copies are put in that directory. If dest is a
6119 is a directory, copies are put in that directory. If dest is a
6120 file, there can only be one source.
6120 file, there can only be one source.
6121
6121
6122 By default, this command copies the contents of files as they
6122 By default, this command copies the contents of files as they
6123 exist in the working directory. If invoked with -A/--after, the
6123 exist in the working directory. If invoked with -A/--after, the
6124 operation is recorded, but no copying is performed.
6124 operation is recorded, but no copying is performed.
6125
6125
6126 This command takes effect at the next commit. To undo a rename
6126 This command takes effect at the next commit. To undo a rename
6127 before that, see :hg:`revert`.
6127 before that, see :hg:`revert`.
6128
6128
6129 Returns 0 on success, 1 if errors are encountered.
6129 Returns 0 on success, 1 if errors are encountered.
6130 """
6130 """
6131 with repo.wlock(False):
6131 with repo.wlock(False):
6132 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6132 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6133
6133
6134 @command('resolve',
6134 @command('resolve',
6135 [('a', 'all', None, _('select all unresolved files')),
6135 [('a', 'all', None, _('select all unresolved files')),
6136 ('l', 'list', None, _('list state of files needing merge')),
6136 ('l', 'list', None, _('list state of files needing merge')),
6137 ('m', 'mark', None, _('mark files as resolved')),
6137 ('m', 'mark', None, _('mark files as resolved')),
6138 ('u', 'unmark', None, _('mark files as unresolved')),
6138 ('u', 'unmark', None, _('mark files as unresolved')),
6139 ('n', 'no-status', None, _('hide status prefix'))]
6139 ('n', 'no-status', None, _('hide status prefix'))]
6140 + mergetoolopts + walkopts + formatteropts,
6140 + mergetoolopts + walkopts + formatteropts,
6141 _('[OPTION]... [FILE]...'),
6141 _('[OPTION]... [FILE]...'),
6142 inferrepo=True)
6142 inferrepo=True)
6143 def resolve(ui, repo, *pats, **opts):
6143 def resolve(ui, repo, *pats, **opts):
6144 """redo merges or set/view the merge status of files
6144 """redo merges or set/view the merge status of files
6145
6145
6146 Merges with unresolved conflicts are often the result of
6146 Merges with unresolved conflicts are often the result of
6147 non-interactive merging using the ``internal:merge`` configuration
6147 non-interactive merging using the ``internal:merge`` configuration
6148 setting, or a command-line merge tool like ``diff3``. The resolve
6148 setting, or a command-line merge tool like ``diff3``. The resolve
6149 command is used to manage the files involved in a merge, after
6149 command is used to manage the files involved in a merge, after
6150 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6150 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6151 working directory must have two parents). See :hg:`help
6151 working directory must have two parents). See :hg:`help
6152 merge-tools` for information on configuring merge tools.
6152 merge-tools` for information on configuring merge tools.
6153
6153
6154 The resolve command can be used in the following ways:
6154 The resolve command can be used in the following ways:
6155
6155
6156 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6156 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6157 files, discarding any previous merge attempts. Re-merging is not
6157 files, discarding any previous merge attempts. Re-merging is not
6158 performed for files already marked as resolved. Use ``--all/-a``
6158 performed for files already marked as resolved. Use ``--all/-a``
6159 to select all unresolved files. ``--tool`` can be used to specify
6159 to select all unresolved files. ``--tool`` can be used to specify
6160 the merge tool used for the given files. It overrides the HGMERGE
6160 the merge tool used for the given files. It overrides the HGMERGE
6161 environment variable and your configuration files. Previous file
6161 environment variable and your configuration files. Previous file
6162 contents are saved with a ``.orig`` suffix.
6162 contents are saved with a ``.orig`` suffix.
6163
6163
6164 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6164 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6165 (e.g. after having manually fixed-up the files). The default is
6165 (e.g. after having manually fixed-up the files). The default is
6166 to mark all unresolved files.
6166 to mark all unresolved files.
6167
6167
6168 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6168 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6169 default is to mark all resolved files.
6169 default is to mark all resolved files.
6170
6170
6171 - :hg:`resolve -l`: list files which had or still have conflicts.
6171 - :hg:`resolve -l`: list files which had or still have conflicts.
6172 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6172 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6173
6173
6174 .. note::
6174 .. note::
6175
6175
6176 Mercurial will not let you commit files with unresolved merge
6176 Mercurial will not let you commit files with unresolved merge
6177 conflicts. You must use :hg:`resolve -m ...` before you can
6177 conflicts. You must use :hg:`resolve -m ...` before you can
6178 commit after a conflicting merge.
6178 commit after a conflicting merge.
6179
6179
6180 Returns 0 on success, 1 if any files fail a resolve attempt.
6180 Returns 0 on success, 1 if any files fail a resolve attempt.
6181 """
6181 """
6182
6182
6183 flaglist = 'all mark unmark list no_status'.split()
6183 flaglist = 'all mark unmark list no_status'.split()
6184 all, mark, unmark, show, nostatus = \
6184 all, mark, unmark, show, nostatus = \
6185 [opts.get(o) for o in flaglist]
6185 [opts.get(o) for o in flaglist]
6186
6186
6187 if (show and (mark or unmark)) or (mark and unmark):
6187 if (show and (mark or unmark)) or (mark and unmark):
6188 raise error.Abort(_("too many options specified"))
6188 raise error.Abort(_("too many options specified"))
6189 if pats and all:
6189 if pats and all:
6190 raise error.Abort(_("can't specify --all and patterns"))
6190 raise error.Abort(_("can't specify --all and patterns"))
6191 if not (all or pats or show or mark or unmark):
6191 if not (all or pats or show or mark or unmark):
6192 raise error.Abort(_('no files or directories specified'),
6192 raise error.Abort(_('no files or directories specified'),
6193 hint=('use --all to re-merge all unresolved files'))
6193 hint=('use --all to re-merge all unresolved files'))
6194
6194
6195 if show:
6195 if show:
6196 fm = ui.formatter('resolve', opts)
6196 fm = ui.formatter('resolve', opts)
6197 ms = mergemod.mergestate.read(repo)
6197 ms = mergemod.mergestate.read(repo)
6198 m = scmutil.match(repo[None], pats, opts)
6198 m = scmutil.match(repo[None], pats, opts)
6199 for f in ms:
6199 for f in ms:
6200 if not m(f):
6200 if not m(f):
6201 continue
6201 continue
6202 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6202 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6203 'd': 'driverresolved'}[ms[f]]
6203 'd': 'driverresolved'}[ms[f]]
6204 fm.startitem()
6204 fm.startitem()
6205 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6205 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6206 fm.write('path', '%s\n', f, label=l)
6206 fm.write('path', '%s\n', f, label=l)
6207 fm.end()
6207 fm.end()
6208 return 0
6208 return 0
6209
6209
6210 with repo.wlock():
6210 with repo.wlock():
6211 ms = mergemod.mergestate.read(repo)
6211 ms = mergemod.mergestate.read(repo)
6212
6212
6213 if not (ms.active() or repo.dirstate.p2() != nullid):
6213 if not (ms.active() or repo.dirstate.p2() != nullid):
6214 raise error.Abort(
6214 raise error.Abort(
6215 _('resolve command not applicable when not merging'))
6215 _('resolve command not applicable when not merging'))
6216
6216
6217 wctx = repo[None]
6217 wctx = repo[None]
6218
6218
6219 if ms.mergedriver and ms.mdstate() == 'u':
6219 if ms.mergedriver and ms.mdstate() == 'u':
6220 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6220 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6221 ms.commit()
6221 ms.commit()
6222 # allow mark and unmark to go through
6222 # allow mark and unmark to go through
6223 if not mark and not unmark and not proceed:
6223 if not mark and not unmark and not proceed:
6224 return 1
6224 return 1
6225
6225
6226 m = scmutil.match(wctx, pats, opts)
6226 m = scmutil.match(wctx, pats, opts)
6227 ret = 0
6227 ret = 0
6228 didwork = False
6228 didwork = False
6229 runconclude = False
6229 runconclude = False
6230
6230
6231 tocomplete = []
6231 tocomplete = []
6232 for f in ms:
6232 for f in ms:
6233 if not m(f):
6233 if not m(f):
6234 continue
6234 continue
6235
6235
6236 didwork = True
6236 didwork = True
6237
6237
6238 # don't let driver-resolved files be marked, and run the conclude
6238 # don't let driver-resolved files be marked, and run the conclude
6239 # step if asked to resolve
6239 # step if asked to resolve
6240 if ms[f] == "d":
6240 if ms[f] == "d":
6241 exact = m.exact(f)
6241 exact = m.exact(f)
6242 if mark:
6242 if mark:
6243 if exact:
6243 if exact:
6244 ui.warn(_('not marking %s as it is driver-resolved\n')
6244 ui.warn(_('not marking %s as it is driver-resolved\n')
6245 % f)
6245 % f)
6246 elif unmark:
6246 elif unmark:
6247 if exact:
6247 if exact:
6248 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6248 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6249 % f)
6249 % f)
6250 else:
6250 else:
6251 runconclude = True
6251 runconclude = True
6252 continue
6252 continue
6253
6253
6254 if mark:
6254 if mark:
6255 ms.mark(f, "r")
6255 ms.mark(f, "r")
6256 elif unmark:
6256 elif unmark:
6257 ms.mark(f, "u")
6257 ms.mark(f, "u")
6258 else:
6258 else:
6259 # backup pre-resolve (merge uses .orig for its own purposes)
6259 # backup pre-resolve (merge uses .orig for its own purposes)
6260 a = repo.wjoin(f)
6260 a = repo.wjoin(f)
6261 try:
6261 try:
6262 util.copyfile(a, a + ".resolve")
6262 util.copyfile(a, a + ".resolve")
6263 except (IOError, OSError) as inst:
6263 except (IOError, OSError) as inst:
6264 if inst.errno != errno.ENOENT:
6264 if inst.errno != errno.ENOENT:
6265 raise
6265 raise
6266
6266
6267 try:
6267 try:
6268 # preresolve file
6268 # preresolve file
6269 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6269 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6270 'resolve')
6270 'resolve')
6271 complete, r = ms.preresolve(f, wctx)
6271 complete, r = ms.preresolve(f, wctx)
6272 if not complete:
6272 if not complete:
6273 tocomplete.append(f)
6273 tocomplete.append(f)
6274 elif r:
6274 elif r:
6275 ret = 1
6275 ret = 1
6276 finally:
6276 finally:
6277 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6277 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6278 ms.commit()
6278 ms.commit()
6279
6279
6280 # replace filemerge's .orig file with our resolve file, but only
6280 # replace filemerge's .orig file with our resolve file, but only
6281 # for merges that are complete
6281 # for merges that are complete
6282 if complete:
6282 if complete:
6283 try:
6283 try:
6284 util.rename(a + ".resolve",
6284 util.rename(a + ".resolve",
6285 scmutil.origpath(ui, repo, a))
6285 scmutil.origpath(ui, repo, a))
6286 except OSError as inst:
6286 except OSError as inst:
6287 if inst.errno != errno.ENOENT:
6287 if inst.errno != errno.ENOENT:
6288 raise
6288 raise
6289
6289
6290 for f in tocomplete:
6290 for f in tocomplete:
6291 try:
6291 try:
6292 # resolve file
6292 # resolve file
6293 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6293 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6294 'resolve')
6294 'resolve')
6295 r = ms.resolve(f, wctx)
6295 r = ms.resolve(f, wctx)
6296 if r:
6296 if r:
6297 ret = 1
6297 ret = 1
6298 finally:
6298 finally:
6299 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6299 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6300 ms.commit()
6300 ms.commit()
6301
6301
6302 # replace filemerge's .orig file with our resolve file
6302 # replace filemerge's .orig file with our resolve file
6303 a = repo.wjoin(f)
6303 a = repo.wjoin(f)
6304 try:
6304 try:
6305 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6305 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6306 except OSError as inst:
6306 except OSError as inst:
6307 if inst.errno != errno.ENOENT:
6307 if inst.errno != errno.ENOENT:
6308 raise
6308 raise
6309
6309
6310 ms.commit()
6310 ms.commit()
6311 ms.recordactions()
6311 ms.recordactions()
6312
6312
6313 if not didwork and pats:
6313 if not didwork and pats:
6314 hint = None
6314 hint = None
6315 if not any([p for p in pats if p.find(':') >= 0]):
6315 if not any([p for p in pats if p.find(':') >= 0]):
6316 pats = ['path:%s' % p for p in pats]
6316 pats = ['path:%s' % p for p in pats]
6317 m = scmutil.match(wctx, pats, opts)
6317 m = scmutil.match(wctx, pats, opts)
6318 for f in ms:
6318 for f in ms:
6319 if not m(f):
6319 if not m(f):
6320 continue
6320 continue
6321 flags = ''.join(['-%s ' % o[0] for o in flaglist
6321 flags = ''.join(['-%s ' % o[0] for o in flaglist
6322 if opts.get(o)])
6322 if opts.get(o)])
6323 hint = _("(try: hg resolve %s%s)\n") % (
6323 hint = _("(try: hg resolve %s%s)\n") % (
6324 flags,
6324 flags,
6325 ' '.join(pats))
6325 ' '.join(pats))
6326 break
6326 break
6327 ui.warn(_("arguments do not match paths that need resolving\n"))
6327 ui.warn(_("arguments do not match paths that need resolving\n"))
6328 if hint:
6328 if hint:
6329 ui.warn(hint)
6329 ui.warn(hint)
6330 elif ms.mergedriver and ms.mdstate() != 's':
6330 elif ms.mergedriver and ms.mdstate() != 's':
6331 # run conclude step when either a driver-resolved file is requested
6331 # run conclude step when either a driver-resolved file is requested
6332 # or there are no driver-resolved files
6332 # or there are no driver-resolved files
6333 # we can't use 'ret' to determine whether any files are unresolved
6333 # we can't use 'ret' to determine whether any files are unresolved
6334 # because we might not have tried to resolve some
6334 # because we might not have tried to resolve some
6335 if ((runconclude or not list(ms.driverresolved()))
6335 if ((runconclude or not list(ms.driverresolved()))
6336 and not list(ms.unresolved())):
6336 and not list(ms.unresolved())):
6337 proceed = mergemod.driverconclude(repo, ms, wctx)
6337 proceed = mergemod.driverconclude(repo, ms, wctx)
6338 ms.commit()
6338 ms.commit()
6339 if not proceed:
6339 if not proceed:
6340 return 1
6340 return 1
6341
6341
6342 # Nudge users into finishing an unfinished operation
6342 # Nudge users into finishing an unfinished operation
6343 unresolvedf = list(ms.unresolved())
6343 unresolvedf = list(ms.unresolved())
6344 driverresolvedf = list(ms.driverresolved())
6344 driverresolvedf = list(ms.driverresolved())
6345 if not unresolvedf and not driverresolvedf:
6345 if not unresolvedf and not driverresolvedf:
6346 ui.status(_('(no more unresolved files)\n'))
6346 ui.status(_('(no more unresolved files)\n'))
6347 cmdutil.checkafterresolved(repo)
6347 cmdutil.checkafterresolved(repo)
6348 elif not unresolvedf:
6348 elif not unresolvedf:
6349 ui.status(_('(no more unresolved files -- '
6349 ui.status(_('(no more unresolved files -- '
6350 'run "hg resolve --all" to conclude)\n'))
6350 'run "hg resolve --all" to conclude)\n'))
6351
6351
6352 return ret
6352 return ret
6353
6353
6354 @command('revert',
6354 @command('revert',
6355 [('a', 'all', None, _('revert all changes when no arguments given')),
6355 [('a', 'all', None, _('revert all changes when no arguments given')),
6356 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6356 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6357 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6357 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6358 ('C', 'no-backup', None, _('do not save backup copies of files')),
6358 ('C', 'no-backup', None, _('do not save backup copies of files')),
6359 ('i', 'interactive', None,
6359 ('i', 'interactive', None,
6360 _('interactively select the changes (EXPERIMENTAL)')),
6360 _('interactively select the changes (EXPERIMENTAL)')),
6361 ] + walkopts + dryrunopts,
6361 ] + walkopts + dryrunopts,
6362 _('[OPTION]... [-r REV] [NAME]...'))
6362 _('[OPTION]... [-r REV] [NAME]...'))
6363 def revert(ui, repo, *pats, **opts):
6363 def revert(ui, repo, *pats, **opts):
6364 """restore files to their checkout state
6364 """restore files to their checkout state
6365
6365
6366 .. note::
6366 .. note::
6367
6367
6368 To check out earlier revisions, you should use :hg:`update REV`.
6368 To check out earlier revisions, you should use :hg:`update REV`.
6369 To cancel an uncommitted merge (and lose your changes),
6369 To cancel an uncommitted merge (and lose your changes),
6370 use :hg:`update --clean .`.
6370 use :hg:`update --clean .`.
6371
6371
6372 With no revision specified, revert the specified files or directories
6372 With no revision specified, revert the specified files or directories
6373 to the contents they had in the parent of the working directory.
6373 to the contents they had in the parent of the working directory.
6374 This restores the contents of files to an unmodified
6374 This restores the contents of files to an unmodified
6375 state and unschedules adds, removes, copies, and renames. If the
6375 state and unschedules adds, removes, copies, and renames. If the
6376 working directory has two parents, you must explicitly specify a
6376 working directory has two parents, you must explicitly specify a
6377 revision.
6377 revision.
6378
6378
6379 Using the -r/--rev or -d/--date options, revert the given files or
6379 Using the -r/--rev or -d/--date options, revert the given files or
6380 directories to their states as of a specific revision. Because
6380 directories to their states as of a specific revision. Because
6381 revert does not change the working directory parents, this will
6381 revert does not change the working directory parents, this will
6382 cause these files to appear modified. This can be helpful to "back
6382 cause these files to appear modified. This can be helpful to "back
6383 out" some or all of an earlier change. See :hg:`backout` for a
6383 out" some or all of an earlier change. See :hg:`backout` for a
6384 related method.
6384 related method.
6385
6385
6386 Modified files are saved with a .orig suffix before reverting.
6386 Modified files are saved with a .orig suffix before reverting.
6387 To disable these backups, use --no-backup. It is possible to store
6387 To disable these backups, use --no-backup. It is possible to store
6388 the backup files in a custom directory relative to the root of the
6388 the backup files in a custom directory relative to the root of the
6389 repository by setting the ``ui.origbackuppath`` configuration
6389 repository by setting the ``ui.origbackuppath`` configuration
6390 option.
6390 option.
6391
6391
6392 See :hg:`help dates` for a list of formats valid for -d/--date.
6392 See :hg:`help dates` for a list of formats valid for -d/--date.
6393
6393
6394 See :hg:`help backout` for a way to reverse the effect of an
6394 See :hg:`help backout` for a way to reverse the effect of an
6395 earlier changeset.
6395 earlier changeset.
6396
6396
6397 Returns 0 on success.
6397 Returns 0 on success.
6398 """
6398 """
6399
6399
6400 if opts.get("date"):
6400 if opts.get("date"):
6401 if opts.get("rev"):
6401 if opts.get("rev"):
6402 raise error.Abort(_("you can't specify a revision and a date"))
6402 raise error.Abort(_("you can't specify a revision and a date"))
6403 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6403 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6404
6404
6405 parent, p2 = repo.dirstate.parents()
6405 parent, p2 = repo.dirstate.parents()
6406 if not opts.get('rev') and p2 != nullid:
6406 if not opts.get('rev') and p2 != nullid:
6407 # revert after merge is a trap for new users (issue2915)
6407 # revert after merge is a trap for new users (issue2915)
6408 raise error.Abort(_('uncommitted merge with no revision specified'),
6408 raise error.Abort(_('uncommitted merge with no revision specified'),
6409 hint=_("use 'hg update' or see 'hg help revert'"))
6409 hint=_("use 'hg update' or see 'hg help revert'"))
6410
6410
6411 ctx = scmutil.revsingle(repo, opts.get('rev'))
6411 ctx = scmutil.revsingle(repo, opts.get('rev'))
6412
6412
6413 if (not (pats or opts.get('include') or opts.get('exclude') or
6413 if (not (pats or opts.get('include') or opts.get('exclude') or
6414 opts.get('all') or opts.get('interactive'))):
6414 opts.get('all') or opts.get('interactive'))):
6415 msg = _("no files or directories specified")
6415 msg = _("no files or directories specified")
6416 if p2 != nullid:
6416 if p2 != nullid:
6417 hint = _("uncommitted merge, use --all to discard all changes,"
6417 hint = _("uncommitted merge, use --all to discard all changes,"
6418 " or 'hg update -C .' to abort the merge")
6418 " or 'hg update -C .' to abort the merge")
6419 raise error.Abort(msg, hint=hint)
6419 raise error.Abort(msg, hint=hint)
6420 dirty = any(repo.status())
6420 dirty = any(repo.status())
6421 node = ctx.node()
6421 node = ctx.node()
6422 if node != parent:
6422 if node != parent:
6423 if dirty:
6423 if dirty:
6424 hint = _("uncommitted changes, use --all to discard all"
6424 hint = _("uncommitted changes, use --all to discard all"
6425 " changes, or 'hg update %s' to update") % ctx.rev()
6425 " changes, or 'hg update %s' to update") % ctx.rev()
6426 else:
6426 else:
6427 hint = _("use --all to revert all files,"
6427 hint = _("use --all to revert all files,"
6428 " or 'hg update %s' to update") % ctx.rev()
6428 " or 'hg update %s' to update") % ctx.rev()
6429 elif dirty:
6429 elif dirty:
6430 hint = _("uncommitted changes, use --all to discard all changes")
6430 hint = _("uncommitted changes, use --all to discard all changes")
6431 else:
6431 else:
6432 hint = _("use --all to revert all files")
6432 hint = _("use --all to revert all files")
6433 raise error.Abort(msg, hint=hint)
6433 raise error.Abort(msg, hint=hint)
6434
6434
6435 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6435 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6436
6436
6437 @command('rollback', dryrunopts +
6437 @command('rollback', dryrunopts +
6438 [('f', 'force', False, _('ignore safety measures'))])
6438 [('f', 'force', False, _('ignore safety measures'))])
6439 def rollback(ui, repo, **opts):
6439 def rollback(ui, repo, **opts):
6440 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6440 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6441
6441
6442 Please use :hg:`commit --amend` instead of rollback to correct
6442 Please use :hg:`commit --amend` instead of rollback to correct
6443 mistakes in the last commit.
6443 mistakes in the last commit.
6444
6444
6445 This command should be used with care. There is only one level of
6445 This command should be used with care. There is only one level of
6446 rollback, and there is no way to undo a rollback. It will also
6446 rollback, and there is no way to undo a rollback. It will also
6447 restore the dirstate at the time of the last transaction, losing
6447 restore the dirstate at the time of the last transaction, losing
6448 any dirstate changes since that time. This command does not alter
6448 any dirstate changes since that time. This command does not alter
6449 the working directory.
6449 the working directory.
6450
6450
6451 Transactions are used to encapsulate the effects of all commands
6451 Transactions are used to encapsulate the effects of all commands
6452 that create new changesets or propagate existing changesets into a
6452 that create new changesets or propagate existing changesets into a
6453 repository.
6453 repository.
6454
6454
6455 .. container:: verbose
6455 .. container:: verbose
6456
6456
6457 For example, the following commands are transactional, and their
6457 For example, the following commands are transactional, and their
6458 effects can be rolled back:
6458 effects can be rolled back:
6459
6459
6460 - commit
6460 - commit
6461 - import
6461 - import
6462 - pull
6462 - pull
6463 - push (with this repository as the destination)
6463 - push (with this repository as the destination)
6464 - unbundle
6464 - unbundle
6465
6465
6466 To avoid permanent data loss, rollback will refuse to rollback a
6466 To avoid permanent data loss, rollback will refuse to rollback a
6467 commit transaction if it isn't checked out. Use --force to
6467 commit transaction if it isn't checked out. Use --force to
6468 override this protection.
6468 override this protection.
6469
6469
6470 The rollback command can be entirely disabled by setting the
6470 The rollback command can be entirely disabled by setting the
6471 ``ui.rollback`` configuration setting to false. If you're here
6471 ``ui.rollback`` configuration setting to false. If you're here
6472 because you want to use rollback and it's disabled, you can
6472 because you want to use rollback and it's disabled, you can
6473 re-enable the command by setting ``ui.rollback`` to true.
6473 re-enable the command by setting ``ui.rollback`` to true.
6474
6474
6475 This command is not intended for use on public repositories. Once
6475 This command is not intended for use on public repositories. Once
6476 changes are visible for pull by other users, rolling a transaction
6476 changes are visible for pull by other users, rolling a transaction
6477 back locally is ineffective (someone else may already have pulled
6477 back locally is ineffective (someone else may already have pulled
6478 the changes). Furthermore, a race is possible with readers of the
6478 the changes). Furthermore, a race is possible with readers of the
6479 repository; for example an in-progress pull from the repository
6479 repository; for example an in-progress pull from the repository
6480 may fail if a rollback is performed.
6480 may fail if a rollback is performed.
6481
6481
6482 Returns 0 on success, 1 if no rollback data is available.
6482 Returns 0 on success, 1 if no rollback data is available.
6483 """
6483 """
6484 if not ui.configbool('ui', 'rollback', True):
6484 if not ui.configbool('ui', 'rollback', True):
6485 raise error.Abort(_('rollback is disabled because it is unsafe'),
6485 raise error.Abort(_('rollback is disabled because it is unsafe'),
6486 hint=('see `hg help -v rollback` for information'))
6486 hint=('see `hg help -v rollback` for information'))
6487 return repo.rollback(dryrun=opts.get('dry_run'),
6487 return repo.rollback(dryrun=opts.get('dry_run'),
6488 force=opts.get('force'))
6488 force=opts.get('force'))
6489
6489
6490 @command('root', [])
6490 @command('root', [])
6491 def root(ui, repo):
6491 def root(ui, repo):
6492 """print the root (top) of the current working directory
6492 """print the root (top) of the current working directory
6493
6493
6494 Print the root directory of the current repository.
6494 Print the root directory of the current repository.
6495
6495
6496 Returns 0 on success.
6496 Returns 0 on success.
6497 """
6497 """
6498 ui.write(repo.root + "\n")
6498 ui.write(repo.root + "\n")
6499
6499
6500 @command('^serve',
6500 @command('^serve',
6501 [('A', 'accesslog', '', _('name of access log file to write to'),
6501 [('A', 'accesslog', '', _('name of access log file to write to'),
6502 _('FILE')),
6502 _('FILE')),
6503 ('d', 'daemon', None, _('run server in background')),
6503 ('d', 'daemon', None, _('run server in background')),
6504 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6504 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6505 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6505 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6506 # use string type, then we can check if something was passed
6506 # use string type, then we can check if something was passed
6507 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6507 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6508 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6508 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6509 _('ADDR')),
6509 _('ADDR')),
6510 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6510 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6511 _('PREFIX')),
6511 _('PREFIX')),
6512 ('n', 'name', '',
6512 ('n', 'name', '',
6513 _('name to show in web pages (default: working directory)'), _('NAME')),
6513 _('name to show in web pages (default: working directory)'), _('NAME')),
6514 ('', 'web-conf', '',
6514 ('', 'web-conf', '',
6515 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6515 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6516 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6516 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6517 _('FILE')),
6517 _('FILE')),
6518 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6518 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6519 ('', 'stdio', None, _('for remote clients')),
6519 ('', 'stdio', None, _('for remote clients')),
6520 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6520 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6521 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6521 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6522 ('', 'style', '', _('template style to use'), _('STYLE')),
6522 ('', 'style', '', _('template style to use'), _('STYLE')),
6523 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6523 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6524 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6524 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6525 _('[OPTION]...'),
6525 _('[OPTION]...'),
6526 optionalrepo=True)
6526 optionalrepo=True)
6527 def serve(ui, repo, **opts):
6527 def serve(ui, repo, **opts):
6528 """start stand-alone webserver
6528 """start stand-alone webserver
6529
6529
6530 Start a local HTTP repository browser and pull server. You can use
6530 Start a local HTTP repository browser and pull server. You can use
6531 this for ad-hoc sharing and browsing of repositories. It is
6531 this for ad-hoc sharing and browsing of repositories. It is
6532 recommended to use a real web server to serve a repository for
6532 recommended to use a real web server to serve a repository for
6533 longer periods of time.
6533 longer periods of time.
6534
6534
6535 Please note that the server does not implement access control.
6535 Please note that the server does not implement access control.
6536 This means that, by default, anybody can read from the server and
6536 This means that, by default, anybody can read from the server and
6537 nobody can write to it by default. Set the ``web.allow_push``
6537 nobody can write to it by default. Set the ``web.allow_push``
6538 option to ``*`` to allow everybody to push to the server. You
6538 option to ``*`` to allow everybody to push to the server. You
6539 should use a real web server if you need to authenticate users.
6539 should use a real web server if you need to authenticate users.
6540
6540
6541 By default, the server logs accesses to stdout and errors to
6541 By default, the server logs accesses to stdout and errors to
6542 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6542 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6543 files.
6543 files.
6544
6544
6545 To have the server choose a free port number to listen on, specify
6545 To have the server choose a free port number to listen on, specify
6546 a port number of 0; in this case, the server will print the port
6546 a port number of 0; in this case, the server will print the port
6547 number it uses.
6547 number it uses.
6548
6548
6549 Returns 0 on success.
6549 Returns 0 on success.
6550 """
6550 """
6551
6551
6552 if opts["stdio"] and opts["cmdserver"]:
6552 if opts["stdio"] and opts["cmdserver"]:
6553 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6553 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6554
6554
6555 if opts["stdio"]:
6555 if opts["stdio"]:
6556 if repo is None:
6556 if repo is None:
6557 raise error.RepoError(_("there is no Mercurial repository here"
6557 raise error.RepoError(_("there is no Mercurial repository here"
6558 " (.hg not found)"))
6558 " (.hg not found)"))
6559 s = sshserver.sshserver(ui, repo)
6559 s = sshserver.sshserver(ui, repo)
6560 s.serve_forever()
6560 s.serve_forever()
6561
6561
6562 if opts["cmdserver"]:
6562 if opts["cmdserver"]:
6563 service = commandserver.createservice(ui, repo, opts)
6563 service = commandserver.createservice(ui, repo, opts)
6564 else:
6564 else:
6565 service = hgweb.createservice(ui, repo, opts)
6565 service = hgweb.createservice(ui, repo, opts)
6566 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6566 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6567
6567
6568 @command('^status|st',
6568 @command('^status|st',
6569 [('A', 'all', None, _('show status of all files')),
6569 [('A', 'all', None, _('show status of all files')),
6570 ('m', 'modified', None, _('show only modified files')),
6570 ('m', 'modified', None, _('show only modified files')),
6571 ('a', 'added', None, _('show only added files')),
6571 ('a', 'added', None, _('show only added files')),
6572 ('r', 'removed', None, _('show only removed files')),
6572 ('r', 'removed', None, _('show only removed files')),
6573 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6573 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6574 ('c', 'clean', None, _('show only files without changes')),
6574 ('c', 'clean', None, _('show only files without changes')),
6575 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6575 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6576 ('i', 'ignored', None, _('show only ignored files')),
6576 ('i', 'ignored', None, _('show only ignored files')),
6577 ('n', 'no-status', None, _('hide status prefix')),
6577 ('n', 'no-status', None, _('hide status prefix')),
6578 ('C', 'copies', None, _('show source of copied files')),
6578 ('C', 'copies', None, _('show source of copied files')),
6579 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6579 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6580 ('', 'rev', [], _('show difference from revision'), _('REV')),
6580 ('', 'rev', [], _('show difference from revision'), _('REV')),
6581 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6581 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6582 ] + walkopts + subrepoopts + formatteropts,
6582 ] + walkopts + subrepoopts + formatteropts,
6583 _('[OPTION]... [FILE]...'),
6583 _('[OPTION]... [FILE]...'),
6584 inferrepo=True)
6584 inferrepo=True)
6585 def status(ui, repo, *pats, **opts):
6585 def status(ui, repo, *pats, **opts):
6586 """show changed files in the working directory
6586 """show changed files in the working directory
6587
6587
6588 Show status of files in the repository. If names are given, only
6588 Show status of files in the repository. If names are given, only
6589 files that match are shown. Files that are clean or ignored or
6589 files that match are shown. Files that are clean or ignored or
6590 the source of a copy/move operation, are not listed unless
6590 the source of a copy/move operation, are not listed unless
6591 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6591 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6592 Unless options described with "show only ..." are given, the
6592 Unless options described with "show only ..." are given, the
6593 options -mardu are used.
6593 options -mardu are used.
6594
6594
6595 Option -q/--quiet hides untracked (unknown and ignored) files
6595 Option -q/--quiet hides untracked (unknown and ignored) files
6596 unless explicitly requested with -u/--unknown or -i/--ignored.
6596 unless explicitly requested with -u/--unknown or -i/--ignored.
6597
6597
6598 .. note::
6598 .. note::
6599
6599
6600 :hg:`status` may appear to disagree with diff if permissions have
6600 :hg:`status` may appear to disagree with diff if permissions have
6601 changed or a merge has occurred. The standard diff format does
6601 changed or a merge has occurred. The standard diff format does
6602 not report permission changes and diff only reports changes
6602 not report permission changes and diff only reports changes
6603 relative to one merge parent.
6603 relative to one merge parent.
6604
6604
6605 If one revision is given, it is used as the base revision.
6605 If one revision is given, it is used as the base revision.
6606 If two revisions are given, the differences between them are
6606 If two revisions are given, the differences between them are
6607 shown. The --change option can also be used as a shortcut to list
6607 shown. The --change option can also be used as a shortcut to list
6608 the changed files of a revision from its first parent.
6608 the changed files of a revision from its first parent.
6609
6609
6610 The codes used to show the status of files are::
6610 The codes used to show the status of files are::
6611
6611
6612 M = modified
6612 M = modified
6613 A = added
6613 A = added
6614 R = removed
6614 R = removed
6615 C = clean
6615 C = clean
6616 ! = missing (deleted by non-hg command, but still tracked)
6616 ! = missing (deleted by non-hg command, but still tracked)
6617 ? = not tracked
6617 ? = not tracked
6618 I = ignored
6618 I = ignored
6619 = origin of the previous file (with --copies)
6619 = origin of the previous file (with --copies)
6620
6620
6621 .. container:: verbose
6621 .. container:: verbose
6622
6622
6623 Examples:
6623 Examples:
6624
6624
6625 - show changes in the working directory relative to a
6625 - show changes in the working directory relative to a
6626 changeset::
6626 changeset::
6627
6627
6628 hg status --rev 9353
6628 hg status --rev 9353
6629
6629
6630 - show changes in the working directory relative to the
6630 - show changes in the working directory relative to the
6631 current directory (see :hg:`help patterns` for more information)::
6631 current directory (see :hg:`help patterns` for more information)::
6632
6632
6633 hg status re:
6633 hg status re:
6634
6634
6635 - show all changes including copies in an existing changeset::
6635 - show all changes including copies in an existing changeset::
6636
6636
6637 hg status --copies --change 9353
6637 hg status --copies --change 9353
6638
6638
6639 - get a NUL separated list of added files, suitable for xargs::
6639 - get a NUL separated list of added files, suitable for xargs::
6640
6640
6641 hg status -an0
6641 hg status -an0
6642
6642
6643 Returns 0 on success.
6643 Returns 0 on success.
6644 """
6644 """
6645
6645
6646 revs = opts.get('rev')
6646 revs = opts.get('rev')
6647 change = opts.get('change')
6647 change = opts.get('change')
6648
6648
6649 if revs and change:
6649 if revs and change:
6650 msg = _('cannot specify --rev and --change at the same time')
6650 msg = _('cannot specify --rev and --change at the same time')
6651 raise error.Abort(msg)
6651 raise error.Abort(msg)
6652 elif change:
6652 elif change:
6653 node2 = scmutil.revsingle(repo, change, None).node()
6653 node2 = scmutil.revsingle(repo, change, None).node()
6654 node1 = repo[node2].p1().node()
6654 node1 = repo[node2].p1().node()
6655 else:
6655 else:
6656 node1, node2 = scmutil.revpair(repo, revs)
6656 node1, node2 = scmutil.revpair(repo, revs)
6657
6657
6658 if pats:
6658 if pats:
6659 cwd = repo.getcwd()
6659 cwd = repo.getcwd()
6660 else:
6660 else:
6661 cwd = ''
6661 cwd = ''
6662
6662
6663 if opts.get('print0'):
6663 if opts.get('print0'):
6664 end = '\0'
6664 end = '\0'
6665 else:
6665 else:
6666 end = '\n'
6666 end = '\n'
6667 copy = {}
6667 copy = {}
6668 states = 'modified added removed deleted unknown ignored clean'.split()
6668 states = 'modified added removed deleted unknown ignored clean'.split()
6669 show = [k for k in states if opts.get(k)]
6669 show = [k for k in states if opts.get(k)]
6670 if opts.get('all'):
6670 if opts.get('all'):
6671 show += ui.quiet and (states[:4] + ['clean']) or states
6671 show += ui.quiet and (states[:4] + ['clean']) or states
6672 if not show:
6672 if not show:
6673 if ui.quiet:
6673 if ui.quiet:
6674 show = states[:4]
6674 show = states[:4]
6675 else:
6675 else:
6676 show = states[:5]
6676 show = states[:5]
6677
6677
6678 m = scmutil.match(repo[node2], pats, opts)
6678 m = scmutil.match(repo[node2], pats, opts)
6679 stat = repo.status(node1, node2, m,
6679 stat = repo.status(node1, node2, m,
6680 'ignored' in show, 'clean' in show, 'unknown' in show,
6680 'ignored' in show, 'clean' in show, 'unknown' in show,
6681 opts.get('subrepos'))
6681 opts.get('subrepos'))
6682 changestates = zip(states, 'MAR!?IC', stat)
6682 changestates = zip(states, 'MAR!?IC', stat)
6683
6683
6684 if (opts.get('all') or opts.get('copies')
6684 if (opts.get('all') or opts.get('copies')
6685 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6685 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6686 copy = copies.pathcopies(repo[node1], repo[node2], m)
6686 copy = copies.pathcopies(repo[node1], repo[node2], m)
6687
6687
6688 fm = ui.formatter('status', opts)
6688 fm = ui.formatter('status', opts)
6689 fmt = '%s' + end
6689 fmt = '%s' + end
6690 showchar = not opts.get('no_status')
6690 showchar = not opts.get('no_status')
6691
6691
6692 for state, char, files in changestates:
6692 for state, char, files in changestates:
6693 if state in show:
6693 if state in show:
6694 label = 'status.' + state
6694 label = 'status.' + state
6695 for f in files:
6695 for f in files:
6696 fm.startitem()
6696 fm.startitem()
6697 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6697 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6698 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6698 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6699 if f in copy:
6699 if f in copy:
6700 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6700 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6701 label='status.copied')
6701 label='status.copied')
6702 fm.end()
6702 fm.end()
6703
6703
6704 @command('^summary|sum',
6704 @command('^summary|sum',
6705 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6705 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6706 def summary(ui, repo, **opts):
6706 def summary(ui, repo, **opts):
6707 """summarize working directory state
6707 """summarize working directory state
6708
6708
6709 This generates a brief summary of the working directory state,
6709 This generates a brief summary of the working directory state,
6710 including parents, branch, commit status, phase and available updates.
6710 including parents, branch, commit status, phase and available updates.
6711
6711
6712 With the --remote option, this will check the default paths for
6712 With the --remote option, this will check the default paths for
6713 incoming and outgoing changes. This can be time-consuming.
6713 incoming and outgoing changes. This can be time-consuming.
6714
6714
6715 Returns 0 on success.
6715 Returns 0 on success.
6716 """
6716 """
6717
6717
6718 ctx = repo[None]
6718 ctx = repo[None]
6719 parents = ctx.parents()
6719 parents = ctx.parents()
6720 pnode = parents[0].node()
6720 pnode = parents[0].node()
6721 marks = []
6721 marks = []
6722
6722
6723 ms = None
6723 ms = None
6724 try:
6724 try:
6725 ms = mergemod.mergestate.read(repo)
6725 ms = mergemod.mergestate.read(repo)
6726 except error.UnsupportedMergeRecords as e:
6726 except error.UnsupportedMergeRecords as e:
6727 s = ' '.join(e.recordtypes)
6727 s = ' '.join(e.recordtypes)
6728 ui.warn(
6728 ui.warn(
6729 _('warning: merge state has unsupported record types: %s\n') % s)
6729 _('warning: merge state has unsupported record types: %s\n') % s)
6730 unresolved = 0
6730 unresolved = 0
6731 else:
6731 else:
6732 unresolved = [f for f in ms if ms[f] == 'u']
6732 unresolved = [f for f in ms if ms[f] == 'u']
6733
6733
6734 for p in parents:
6734 for p in parents:
6735 # label with log.changeset (instead of log.parent) since this
6735 # label with log.changeset (instead of log.parent) since this
6736 # shows a working directory parent *changeset*:
6736 # shows a working directory parent *changeset*:
6737 # i18n: column positioning for "hg summary"
6737 # i18n: column positioning for "hg summary"
6738 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6738 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6739 label='log.changeset changeset.%s' % p.phasestr())
6739 label='log.changeset changeset.%s' % p.phasestr())
6740 ui.write(' '.join(p.tags()), label='log.tag')
6740 ui.write(' '.join(p.tags()), label='log.tag')
6741 if p.bookmarks():
6741 if p.bookmarks():
6742 marks.extend(p.bookmarks())
6742 marks.extend(p.bookmarks())
6743 if p.rev() == -1:
6743 if p.rev() == -1:
6744 if not len(repo):
6744 if not len(repo):
6745 ui.write(_(' (empty repository)'))
6745 ui.write(_(' (empty repository)'))
6746 else:
6746 else:
6747 ui.write(_(' (no revision checked out)'))
6747 ui.write(_(' (no revision checked out)'))
6748 ui.write('\n')
6748 ui.write('\n')
6749 if p.description():
6749 if p.description():
6750 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6750 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6751 label='log.summary')
6751 label='log.summary')
6752
6752
6753 branch = ctx.branch()
6753 branch = ctx.branch()
6754 bheads = repo.branchheads(branch)
6754 bheads = repo.branchheads(branch)
6755 # i18n: column positioning for "hg summary"
6755 # i18n: column positioning for "hg summary"
6756 m = _('branch: %s\n') % branch
6756 m = _('branch: %s\n') % branch
6757 if branch != 'default':
6757 if branch != 'default':
6758 ui.write(m, label='log.branch')
6758 ui.write(m, label='log.branch')
6759 else:
6759 else:
6760 ui.status(m, label='log.branch')
6760 ui.status(m, label='log.branch')
6761
6761
6762 if marks:
6762 if marks:
6763 active = repo._activebookmark
6763 active = repo._activebookmark
6764 # i18n: column positioning for "hg summary"
6764 # i18n: column positioning for "hg summary"
6765 ui.write(_('bookmarks:'), label='log.bookmark')
6765 ui.write(_('bookmarks:'), label='log.bookmark')
6766 if active is not None:
6766 if active is not None:
6767 if active in marks:
6767 if active in marks:
6768 ui.write(' *' + active, label=activebookmarklabel)
6768 ui.write(' *' + active, label=activebookmarklabel)
6769 marks.remove(active)
6769 marks.remove(active)
6770 else:
6770 else:
6771 ui.write(' [%s]' % active, label=activebookmarklabel)
6771 ui.write(' [%s]' % active, label=activebookmarklabel)
6772 for m in marks:
6772 for m in marks:
6773 ui.write(' ' + m, label='log.bookmark')
6773 ui.write(' ' + m, label='log.bookmark')
6774 ui.write('\n', label='log.bookmark')
6774 ui.write('\n', label='log.bookmark')
6775
6775
6776 status = repo.status(unknown=True)
6776 status = repo.status(unknown=True)
6777
6777
6778 c = repo.dirstate.copies()
6778 c = repo.dirstate.copies()
6779 copied, renamed = [], []
6779 copied, renamed = [], []
6780 for d, s in c.iteritems():
6780 for d, s in c.iteritems():
6781 if s in status.removed:
6781 if s in status.removed:
6782 status.removed.remove(s)
6782 status.removed.remove(s)
6783 renamed.append(d)
6783 renamed.append(d)
6784 else:
6784 else:
6785 copied.append(d)
6785 copied.append(d)
6786 if d in status.added:
6786 if d in status.added:
6787 status.added.remove(d)
6787 status.added.remove(d)
6788
6788
6789 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6789 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6790
6790
6791 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6791 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6792 (ui.label(_('%d added'), 'status.added'), status.added),
6792 (ui.label(_('%d added'), 'status.added'), status.added),
6793 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6793 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6794 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6794 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6795 (ui.label(_('%d copied'), 'status.copied'), copied),
6795 (ui.label(_('%d copied'), 'status.copied'), copied),
6796 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6796 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6797 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6797 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6798 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6798 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6799 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6799 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6800 t = []
6800 t = []
6801 for l, s in labels:
6801 for l, s in labels:
6802 if s:
6802 if s:
6803 t.append(l % len(s))
6803 t.append(l % len(s))
6804
6804
6805 t = ', '.join(t)
6805 t = ', '.join(t)
6806 cleanworkdir = False
6806 cleanworkdir = False
6807
6807
6808 if repo.vfs.exists('graftstate'):
6808 if repo.vfs.exists('graftstate'):
6809 t += _(' (graft in progress)')
6809 t += _(' (graft in progress)')
6810 if repo.vfs.exists('updatestate'):
6810 if repo.vfs.exists('updatestate'):
6811 t += _(' (interrupted update)')
6811 t += _(' (interrupted update)')
6812 elif len(parents) > 1:
6812 elif len(parents) > 1:
6813 t += _(' (merge)')
6813 t += _(' (merge)')
6814 elif branch != parents[0].branch():
6814 elif branch != parents[0].branch():
6815 t += _(' (new branch)')
6815 t += _(' (new branch)')
6816 elif (parents[0].closesbranch() and
6816 elif (parents[0].closesbranch() and
6817 pnode in repo.branchheads(branch, closed=True)):
6817 pnode in repo.branchheads(branch, closed=True)):
6818 t += _(' (head closed)')
6818 t += _(' (head closed)')
6819 elif not (status.modified or status.added or status.removed or renamed or
6819 elif not (status.modified or status.added or status.removed or renamed or
6820 copied or subs):
6820 copied or subs):
6821 t += _(' (clean)')
6821 t += _(' (clean)')
6822 cleanworkdir = True
6822 cleanworkdir = True
6823 elif pnode not in bheads:
6823 elif pnode not in bheads:
6824 t += _(' (new branch head)')
6824 t += _(' (new branch head)')
6825
6825
6826 if parents:
6826 if parents:
6827 pendingphase = max(p.phase() for p in parents)
6827 pendingphase = max(p.phase() for p in parents)
6828 else:
6828 else:
6829 pendingphase = phases.public
6829 pendingphase = phases.public
6830
6830
6831 if pendingphase > phases.newcommitphase(ui):
6831 if pendingphase > phases.newcommitphase(ui):
6832 t += ' (%s)' % phases.phasenames[pendingphase]
6832 t += ' (%s)' % phases.phasenames[pendingphase]
6833
6833
6834 if cleanworkdir:
6834 if cleanworkdir:
6835 # i18n: column positioning for "hg summary"
6835 # i18n: column positioning for "hg summary"
6836 ui.status(_('commit: %s\n') % t.strip())
6836 ui.status(_('commit: %s\n') % t.strip())
6837 else:
6837 else:
6838 # i18n: column positioning for "hg summary"
6838 # i18n: column positioning for "hg summary"
6839 ui.write(_('commit: %s\n') % t.strip())
6839 ui.write(_('commit: %s\n') % t.strip())
6840
6840
6841 # all ancestors of branch heads - all ancestors of parent = new csets
6841 # all ancestors of branch heads - all ancestors of parent = new csets
6842 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6842 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6843 bheads))
6843 bheads))
6844
6844
6845 if new == 0:
6845 if new == 0:
6846 # i18n: column positioning for "hg summary"
6846 # i18n: column positioning for "hg summary"
6847 ui.status(_('update: (current)\n'))
6847 ui.status(_('update: (current)\n'))
6848 elif pnode not in bheads:
6848 elif pnode not in bheads:
6849 # i18n: column positioning for "hg summary"
6849 # i18n: column positioning for "hg summary"
6850 ui.write(_('update: %d new changesets (update)\n') % new)
6850 ui.write(_('update: %d new changesets (update)\n') % new)
6851 else:
6851 else:
6852 # i18n: column positioning for "hg summary"
6852 # i18n: column positioning for "hg summary"
6853 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6853 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6854 (new, len(bheads)))
6854 (new, len(bheads)))
6855
6855
6856 t = []
6856 t = []
6857 draft = len(repo.revs('draft()'))
6857 draft = len(repo.revs('draft()'))
6858 if draft:
6858 if draft:
6859 t.append(_('%d draft') % draft)
6859 t.append(_('%d draft') % draft)
6860 secret = len(repo.revs('secret()'))
6860 secret = len(repo.revs('secret()'))
6861 if secret:
6861 if secret:
6862 t.append(_('%d secret') % secret)
6862 t.append(_('%d secret') % secret)
6863
6863
6864 if draft or secret:
6864 if draft or secret:
6865 ui.status(_('phases: %s\n') % ', '.join(t))
6865 ui.status(_('phases: %s\n') % ', '.join(t))
6866
6866
6867 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6867 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6868 for trouble in ("unstable", "divergent", "bumped"):
6868 for trouble in ("unstable", "divergent", "bumped"):
6869 numtrouble = len(repo.revs(trouble + "()"))
6869 numtrouble = len(repo.revs(trouble + "()"))
6870 # We write all the possibilities to ease translation
6870 # We write all the possibilities to ease translation
6871 troublemsg = {
6871 troublemsg = {
6872 "unstable": _("unstable: %d changesets"),
6872 "unstable": _("unstable: %d changesets"),
6873 "divergent": _("divergent: %d changesets"),
6873 "divergent": _("divergent: %d changesets"),
6874 "bumped": _("bumped: %d changesets"),
6874 "bumped": _("bumped: %d changesets"),
6875 }
6875 }
6876 if numtrouble > 0:
6876 if numtrouble > 0:
6877 ui.status(troublemsg[trouble] % numtrouble + "\n")
6877 ui.status(troublemsg[trouble] % numtrouble + "\n")
6878
6878
6879 cmdutil.summaryhooks(ui, repo)
6879 cmdutil.summaryhooks(ui, repo)
6880
6880
6881 if opts.get('remote'):
6881 if opts.get('remote'):
6882 needsincoming, needsoutgoing = True, True
6882 needsincoming, needsoutgoing = True, True
6883 else:
6883 else:
6884 needsincoming, needsoutgoing = False, False
6884 needsincoming, needsoutgoing = False, False
6885 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6885 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6886 if i:
6886 if i:
6887 needsincoming = True
6887 needsincoming = True
6888 if o:
6888 if o:
6889 needsoutgoing = True
6889 needsoutgoing = True
6890 if not needsincoming and not needsoutgoing:
6890 if not needsincoming and not needsoutgoing:
6891 return
6891 return
6892
6892
6893 def getincoming():
6893 def getincoming():
6894 source, branches = hg.parseurl(ui.expandpath('default'))
6894 source, branches = hg.parseurl(ui.expandpath('default'))
6895 sbranch = branches[0]
6895 sbranch = branches[0]
6896 try:
6896 try:
6897 other = hg.peer(repo, {}, source)
6897 other = hg.peer(repo, {}, source)
6898 except error.RepoError:
6898 except error.RepoError:
6899 if opts.get('remote'):
6899 if opts.get('remote'):
6900 raise
6900 raise
6901 return source, sbranch, None, None, None
6901 return source, sbranch, None, None, None
6902 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6902 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6903 if revs:
6903 if revs:
6904 revs = [other.lookup(rev) for rev in revs]
6904 revs = [other.lookup(rev) for rev in revs]
6905 ui.debug('comparing with %s\n' % util.hidepassword(source))
6905 ui.debug('comparing with %s\n' % util.hidepassword(source))
6906 repo.ui.pushbuffer()
6906 repo.ui.pushbuffer()
6907 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6907 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6908 repo.ui.popbuffer()
6908 repo.ui.popbuffer()
6909 return source, sbranch, other, commoninc, commoninc[1]
6909 return source, sbranch, other, commoninc, commoninc[1]
6910
6910
6911 if needsincoming:
6911 if needsincoming:
6912 source, sbranch, sother, commoninc, incoming = getincoming()
6912 source, sbranch, sother, commoninc, incoming = getincoming()
6913 else:
6913 else:
6914 source = sbranch = sother = commoninc = incoming = None
6914 source = sbranch = sother = commoninc = incoming = None
6915
6915
6916 def getoutgoing():
6916 def getoutgoing():
6917 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6917 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6918 dbranch = branches[0]
6918 dbranch = branches[0]
6919 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6919 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6920 if source != dest:
6920 if source != dest:
6921 try:
6921 try:
6922 dother = hg.peer(repo, {}, dest)
6922 dother = hg.peer(repo, {}, dest)
6923 except error.RepoError:
6923 except error.RepoError:
6924 if opts.get('remote'):
6924 if opts.get('remote'):
6925 raise
6925 raise
6926 return dest, dbranch, None, None
6926 return dest, dbranch, None, None
6927 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6927 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6928 elif sother is None:
6928 elif sother is None:
6929 # there is no explicit destination peer, but source one is invalid
6929 # there is no explicit destination peer, but source one is invalid
6930 return dest, dbranch, None, None
6930 return dest, dbranch, None, None
6931 else:
6931 else:
6932 dother = sother
6932 dother = sother
6933 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6933 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6934 common = None
6934 common = None
6935 else:
6935 else:
6936 common = commoninc
6936 common = commoninc
6937 if revs:
6937 if revs:
6938 revs = [repo.lookup(rev) for rev in revs]
6938 revs = [repo.lookup(rev) for rev in revs]
6939 repo.ui.pushbuffer()
6939 repo.ui.pushbuffer()
6940 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6940 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6941 commoninc=common)
6941 commoninc=common)
6942 repo.ui.popbuffer()
6942 repo.ui.popbuffer()
6943 return dest, dbranch, dother, outgoing
6943 return dest, dbranch, dother, outgoing
6944
6944
6945 if needsoutgoing:
6945 if needsoutgoing:
6946 dest, dbranch, dother, outgoing = getoutgoing()
6946 dest, dbranch, dother, outgoing = getoutgoing()
6947 else:
6947 else:
6948 dest = dbranch = dother = outgoing = None
6948 dest = dbranch = dother = outgoing = None
6949
6949
6950 if opts.get('remote'):
6950 if opts.get('remote'):
6951 t = []
6951 t = []
6952 if incoming:
6952 if incoming:
6953 t.append(_('1 or more incoming'))
6953 t.append(_('1 or more incoming'))
6954 o = outgoing.missing
6954 o = outgoing.missing
6955 if o:
6955 if o:
6956 t.append(_('%d outgoing') % len(o))
6956 t.append(_('%d outgoing') % len(o))
6957 other = dother or sother
6957 other = dother or sother
6958 if 'bookmarks' in other.listkeys('namespaces'):
6958 if 'bookmarks' in other.listkeys('namespaces'):
6959 counts = bookmarks.summary(repo, other)
6959 counts = bookmarks.summary(repo, other)
6960 if counts[0] > 0:
6960 if counts[0] > 0:
6961 t.append(_('%d incoming bookmarks') % counts[0])
6961 t.append(_('%d incoming bookmarks') % counts[0])
6962 if counts[1] > 0:
6962 if counts[1] > 0:
6963 t.append(_('%d outgoing bookmarks') % counts[1])
6963 t.append(_('%d outgoing bookmarks') % counts[1])
6964
6964
6965 if t:
6965 if t:
6966 # i18n: column positioning for "hg summary"
6966 # i18n: column positioning for "hg summary"
6967 ui.write(_('remote: %s\n') % (', '.join(t)))
6967 ui.write(_('remote: %s\n') % (', '.join(t)))
6968 else:
6968 else:
6969 # i18n: column positioning for "hg summary"
6969 # i18n: column positioning for "hg summary"
6970 ui.status(_('remote: (synced)\n'))
6970 ui.status(_('remote: (synced)\n'))
6971
6971
6972 cmdutil.summaryremotehooks(ui, repo, opts,
6972 cmdutil.summaryremotehooks(ui, repo, opts,
6973 ((source, sbranch, sother, commoninc),
6973 ((source, sbranch, sother, commoninc),
6974 (dest, dbranch, dother, outgoing)))
6974 (dest, dbranch, dother, outgoing)))
6975
6975
6976 @command('tag',
6976 @command('tag',
6977 [('f', 'force', None, _('force tag')),
6977 [('f', 'force', None, _('force tag')),
6978 ('l', 'local', None, _('make the tag local')),
6978 ('l', 'local', None, _('make the tag local')),
6979 ('r', 'rev', '', _('revision to tag'), _('REV')),
6979 ('r', 'rev', '', _('revision to tag'), _('REV')),
6980 ('', 'remove', None, _('remove a tag')),
6980 ('', 'remove', None, _('remove a tag')),
6981 # -l/--local is already there, commitopts cannot be used
6981 # -l/--local is already there, commitopts cannot be used
6982 ('e', 'edit', None, _('invoke editor on commit messages')),
6982 ('e', 'edit', None, _('invoke editor on commit messages')),
6983 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6983 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6984 ] + commitopts2,
6984 ] + commitopts2,
6985 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6985 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6986 def tag(ui, repo, name1, *names, **opts):
6986 def tag(ui, repo, name1, *names, **opts):
6987 """add one or more tags for the current or given revision
6987 """add one or more tags for the current or given revision
6988
6988
6989 Name a particular revision using <name>.
6989 Name a particular revision using <name>.
6990
6990
6991 Tags are used to name particular revisions of the repository and are
6991 Tags are used to name particular revisions of the repository and are
6992 very useful to compare different revisions, to go back to significant
6992 very useful to compare different revisions, to go back to significant
6993 earlier versions or to mark branch points as releases, etc. Changing
6993 earlier versions or to mark branch points as releases, etc. Changing
6994 an existing tag is normally disallowed; use -f/--force to override.
6994 an existing tag is normally disallowed; use -f/--force to override.
6995
6995
6996 If no revision is given, the parent of the working directory is
6996 If no revision is given, the parent of the working directory is
6997 used.
6997 used.
6998
6998
6999 To facilitate version control, distribution, and merging of tags,
6999 To facilitate version control, distribution, and merging of tags,
7000 they are stored as a file named ".hgtags" which is managed similarly
7000 they are stored as a file named ".hgtags" which is managed similarly
7001 to other project files and can be hand-edited if necessary. This
7001 to other project files and can be hand-edited if necessary. This
7002 also means that tagging creates a new commit. The file
7002 also means that tagging creates a new commit. The file
7003 ".hg/localtags" is used for local tags (not shared among
7003 ".hg/localtags" is used for local tags (not shared among
7004 repositories).
7004 repositories).
7005
7005
7006 Tag commits are usually made at the head of a branch. If the parent
7006 Tag commits are usually made at the head of a branch. If the parent
7007 of the working directory is not a branch head, :hg:`tag` aborts; use
7007 of the working directory is not a branch head, :hg:`tag` aborts; use
7008 -f/--force to force the tag commit to be based on a non-head
7008 -f/--force to force the tag commit to be based on a non-head
7009 changeset.
7009 changeset.
7010
7010
7011 See :hg:`help dates` for a list of formats valid for -d/--date.
7011 See :hg:`help dates` for a list of formats valid for -d/--date.
7012
7012
7013 Since tag names have priority over branch names during revision
7013 Since tag names have priority over branch names during revision
7014 lookup, using an existing branch name as a tag name is discouraged.
7014 lookup, using an existing branch name as a tag name is discouraged.
7015
7015
7016 Returns 0 on success.
7016 Returns 0 on success.
7017 """
7017 """
7018 wlock = lock = None
7018 wlock = lock = None
7019 try:
7019 try:
7020 wlock = repo.wlock()
7020 wlock = repo.wlock()
7021 lock = repo.lock()
7021 lock = repo.lock()
7022 rev_ = "."
7022 rev_ = "."
7023 names = [t.strip() for t in (name1,) + names]
7023 names = [t.strip() for t in (name1,) + names]
7024 if len(names) != len(set(names)):
7024 if len(names) != len(set(names)):
7025 raise error.Abort(_('tag names must be unique'))
7025 raise error.Abort(_('tag names must be unique'))
7026 for n in names:
7026 for n in names:
7027 scmutil.checknewlabel(repo, n, 'tag')
7027 scmutil.checknewlabel(repo, n, 'tag')
7028 if not n:
7028 if not n:
7029 raise error.Abort(_('tag names cannot consist entirely of '
7029 raise error.Abort(_('tag names cannot consist entirely of '
7030 'whitespace'))
7030 'whitespace'))
7031 if opts.get('rev') and opts.get('remove'):
7031 if opts.get('rev') and opts.get('remove'):
7032 raise error.Abort(_("--rev and --remove are incompatible"))
7032 raise error.Abort(_("--rev and --remove are incompatible"))
7033 if opts.get('rev'):
7033 if opts.get('rev'):
7034 rev_ = opts['rev']
7034 rev_ = opts['rev']
7035 message = opts.get('message')
7035 message = opts.get('message')
7036 if opts.get('remove'):
7036 if opts.get('remove'):
7037 if opts.get('local'):
7037 if opts.get('local'):
7038 expectedtype = 'local'
7038 expectedtype = 'local'
7039 else:
7039 else:
7040 expectedtype = 'global'
7040 expectedtype = 'global'
7041
7041
7042 for n in names:
7042 for n in names:
7043 if not repo.tagtype(n):
7043 if not repo.tagtype(n):
7044 raise error.Abort(_("tag '%s' does not exist") % n)
7044 raise error.Abort(_("tag '%s' does not exist") % n)
7045 if repo.tagtype(n) != expectedtype:
7045 if repo.tagtype(n) != expectedtype:
7046 if expectedtype == 'global':
7046 if expectedtype == 'global':
7047 raise error.Abort(_("tag '%s' is not a global tag") % n)
7047 raise error.Abort(_("tag '%s' is not a global tag") % n)
7048 else:
7048 else:
7049 raise error.Abort(_("tag '%s' is not a local tag") % n)
7049 raise error.Abort(_("tag '%s' is not a local tag") % n)
7050 rev_ = 'null'
7050 rev_ = 'null'
7051 if not message:
7051 if not message:
7052 # we don't translate commit messages
7052 # we don't translate commit messages
7053 message = 'Removed tag %s' % ', '.join(names)
7053 message = 'Removed tag %s' % ', '.join(names)
7054 elif not opts.get('force'):
7054 elif not opts.get('force'):
7055 for n in names:
7055 for n in names:
7056 if n in repo.tags():
7056 if n in repo.tags():
7057 raise error.Abort(_("tag '%s' already exists "
7057 raise error.Abort(_("tag '%s' already exists "
7058 "(use -f to force)") % n)
7058 "(use -f to force)") % n)
7059 if not opts.get('local'):
7059 if not opts.get('local'):
7060 p1, p2 = repo.dirstate.parents()
7060 p1, p2 = repo.dirstate.parents()
7061 if p2 != nullid:
7061 if p2 != nullid:
7062 raise error.Abort(_('uncommitted merge'))
7062 raise error.Abort(_('uncommitted merge'))
7063 bheads = repo.branchheads()
7063 bheads = repo.branchheads()
7064 if not opts.get('force') and bheads and p1 not in bheads:
7064 if not opts.get('force') and bheads and p1 not in bheads:
7065 raise error.Abort(_('not at a branch head (use -f to force)'))
7065 raise error.Abort(_('not at a branch head (use -f to force)'))
7066 r = scmutil.revsingle(repo, rev_).node()
7066 r = scmutil.revsingle(repo, rev_).node()
7067
7067
7068 if not message:
7068 if not message:
7069 # we don't translate commit messages
7069 # we don't translate commit messages
7070 message = ('Added tag %s for changeset %s' %
7070 message = ('Added tag %s for changeset %s' %
7071 (', '.join(names), short(r)))
7071 (', '.join(names), short(r)))
7072
7072
7073 date = opts.get('date')
7073 date = opts.get('date')
7074 if date:
7074 if date:
7075 date = util.parsedate(date)
7075 date = util.parsedate(date)
7076
7076
7077 if opts.get('remove'):
7077 if opts.get('remove'):
7078 editform = 'tag.remove'
7078 editform = 'tag.remove'
7079 else:
7079 else:
7080 editform = 'tag.add'
7080 editform = 'tag.add'
7081 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7081 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7082
7082
7083 # don't allow tagging the null rev
7083 # don't allow tagging the null rev
7084 if (not opts.get('remove') and
7084 if (not opts.get('remove') and
7085 scmutil.revsingle(repo, rev_).rev() == nullrev):
7085 scmutil.revsingle(repo, rev_).rev() == nullrev):
7086 raise error.Abort(_("cannot tag null revision"))
7086 raise error.Abort(_("cannot tag null revision"))
7087
7087
7088 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7088 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7089 editor=editor)
7089 editor=editor)
7090 finally:
7090 finally:
7091 release(lock, wlock)
7091 release(lock, wlock)
7092
7092
7093 @command('tags', formatteropts, '')
7093 @command('tags', formatteropts, '')
7094 def tags(ui, repo, **opts):
7094 def tags(ui, repo, **opts):
7095 """list repository tags
7095 """list repository tags
7096
7096
7097 This lists both regular and local tags. When the -v/--verbose
7097 This lists both regular and local tags. When the -v/--verbose
7098 switch is used, a third column "local" is printed for local tags.
7098 switch is used, a third column "local" is printed for local tags.
7099 When the -q/--quiet switch is used, only the tag name is printed.
7099 When the -q/--quiet switch is used, only the tag name is printed.
7100
7100
7101 Returns 0 on success.
7101 Returns 0 on success.
7102 """
7102 """
7103
7103
7104 fm = ui.formatter('tags', opts)
7104 fm = ui.formatter('tags', opts)
7105 hexfunc = fm.hexfunc
7105 hexfunc = fm.hexfunc
7106 tagtype = ""
7106 tagtype = ""
7107
7107
7108 for t, n in reversed(repo.tagslist()):
7108 for t, n in reversed(repo.tagslist()):
7109 hn = hexfunc(n)
7109 hn = hexfunc(n)
7110 label = 'tags.normal'
7110 label = 'tags.normal'
7111 tagtype = ''
7111 tagtype = ''
7112 if repo.tagtype(t) == 'local':
7112 if repo.tagtype(t) == 'local':
7113 label = 'tags.local'
7113 label = 'tags.local'
7114 tagtype = 'local'
7114 tagtype = 'local'
7115
7115
7116 fm.startitem()
7116 fm.startitem()
7117 fm.write('tag', '%s', t, label=label)
7117 fm.write('tag', '%s', t, label=label)
7118 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7118 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7119 fm.condwrite(not ui.quiet, 'rev node', fmt,
7119 fm.condwrite(not ui.quiet, 'rev node', fmt,
7120 repo.changelog.rev(n), hn, label=label)
7120 repo.changelog.rev(n), hn, label=label)
7121 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7121 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7122 tagtype, label=label)
7122 tagtype, label=label)
7123 fm.plain('\n')
7123 fm.plain('\n')
7124 fm.end()
7124 fm.end()
7125
7125
7126 @command('tip',
7126 @command('tip',
7127 [('p', 'patch', None, _('show patch')),
7127 [('p', 'patch', None, _('show patch')),
7128 ('g', 'git', None, _('use git extended diff format')),
7128 ('g', 'git', None, _('use git extended diff format')),
7129 ] + templateopts,
7129 ] + templateopts,
7130 _('[-p] [-g]'))
7130 _('[-p] [-g]'))
7131 def tip(ui, repo, **opts):
7131 def tip(ui, repo, **opts):
7132 """show the tip revision (DEPRECATED)
7132 """show the tip revision (DEPRECATED)
7133
7133
7134 The tip revision (usually just called the tip) is the changeset
7134 The tip revision (usually just called the tip) is the changeset
7135 most recently added to the repository (and therefore the most
7135 most recently added to the repository (and therefore the most
7136 recently changed head).
7136 recently changed head).
7137
7137
7138 If you have just made a commit, that commit will be the tip. If
7138 If you have just made a commit, that commit will be the tip. If
7139 you have just pulled changes from another repository, the tip of
7139 you have just pulled changes from another repository, the tip of
7140 that repository becomes the current tip. The "tip" tag is special
7140 that repository becomes the current tip. The "tip" tag is special
7141 and cannot be renamed or assigned to a different changeset.
7141 and cannot be renamed or assigned to a different changeset.
7142
7142
7143 This command is deprecated, please use :hg:`heads` instead.
7143 This command is deprecated, please use :hg:`heads` instead.
7144
7144
7145 Returns 0 on success.
7145 Returns 0 on success.
7146 """
7146 """
7147 displayer = cmdutil.show_changeset(ui, repo, opts)
7147 displayer = cmdutil.show_changeset(ui, repo, opts)
7148 displayer.show(repo['tip'])
7148 displayer.show(repo['tip'])
7149 displayer.close()
7149 displayer.close()
7150
7150
7151 @command('unbundle',
7151 @command('unbundle',
7152 [('u', 'update', None,
7152 [('u', 'update', None,
7153 _('update to new branch head if changesets were unbundled'))],
7153 _('update to new branch head if changesets were unbundled'))],
7154 _('[-u] FILE...'))
7154 _('[-u] FILE...'))
7155 def unbundle(ui, repo, fname1, *fnames, **opts):
7155 def unbundle(ui, repo, fname1, *fnames, **opts):
7156 """apply one or more changegroup files
7156 """apply one or more changegroup files
7157
7157
7158 Apply one or more compressed changegroup files generated by the
7158 Apply one or more compressed changegroup files generated by the
7159 bundle command.
7159 bundle command.
7160
7160
7161 Returns 0 on success, 1 if an update has unresolved files.
7161 Returns 0 on success, 1 if an update has unresolved files.
7162 """
7162 """
7163 fnames = (fname1,) + fnames
7163 fnames = (fname1,) + fnames
7164
7164
7165 with repo.lock():
7165 with repo.lock():
7166 for fname in fnames:
7166 for fname in fnames:
7167 f = hg.openpath(ui, fname)
7167 f = hg.openpath(ui, fname)
7168 gen = exchange.readbundle(ui, f, fname)
7168 gen = exchange.readbundle(ui, f, fname)
7169 if isinstance(gen, bundle2.unbundle20):
7169 if isinstance(gen, bundle2.unbundle20):
7170 tr = repo.transaction('unbundle')
7170 tr = repo.transaction('unbundle')
7171 try:
7171 try:
7172 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7172 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7173 url='bundle:' + fname)
7173 url='bundle:' + fname)
7174 tr.close()
7174 tr.close()
7175 except error.BundleUnknownFeatureError as exc:
7175 except error.BundleUnknownFeatureError as exc:
7176 raise error.Abort(_('%s: unknown bundle feature, %s')
7176 raise error.Abort(_('%s: unknown bundle feature, %s')
7177 % (fname, exc),
7177 % (fname, exc),
7178 hint=_("see https://mercurial-scm.org/"
7178 hint=_("see https://mercurial-scm.org/"
7179 "wiki/BundleFeature for more "
7179 "wiki/BundleFeature for more "
7180 "information"))
7180 "information"))
7181 finally:
7181 finally:
7182 if tr:
7182 if tr:
7183 tr.release()
7183 tr.release()
7184 changes = [r.get('return', 0)
7184 changes = [r.get('return', 0)
7185 for r in op.records['changegroup']]
7185 for r in op.records['changegroup']]
7186 modheads = changegroup.combineresults(changes)
7186 modheads = changegroup.combineresults(changes)
7187 elif isinstance(gen, streamclone.streamcloneapplier):
7187 elif isinstance(gen, streamclone.streamcloneapplier):
7188 raise error.Abort(
7188 raise error.Abort(
7189 _('packed bundles cannot be applied with '
7189 _('packed bundles cannot be applied with '
7190 '"hg unbundle"'),
7190 '"hg unbundle"'),
7191 hint=_('use "hg debugapplystreamclonebundle"'))
7191 hint=_('use "hg debugapplystreamclonebundle"'))
7192 else:
7192 else:
7193 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7193 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7194
7194
7195 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7195 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7196
7196
7197 @command('^update|up|checkout|co',
7197 @command('^update|up|checkout|co',
7198 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7198 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7199 ('c', 'check', None, _('require clean working directory')),
7199 ('c', 'check', None, _('require clean working directory')),
7200 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7200 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7201 ('r', 'rev', '', _('revision'), _('REV'))
7201 ('r', 'rev', '', _('revision'), _('REV'))
7202 ] + mergetoolopts,
7202 ] + mergetoolopts,
7203 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7203 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7204 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7204 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7205 tool=None):
7205 tool=None):
7206 """update working directory (or switch revisions)
7206 """update working directory (or switch revisions)
7207
7207
7208 Update the repository's working directory to the specified
7208 Update the repository's working directory to the specified
7209 changeset. If no changeset is specified, update to the tip of the
7209 changeset. If no changeset is specified, update to the tip of the
7210 current named branch and move the active bookmark (see :hg:`help
7210 current named branch and move the active bookmark (see :hg:`help
7211 bookmarks`).
7211 bookmarks`).
7212
7212
7213 Update sets the working directory's parent revision to the specified
7213 Update sets the working directory's parent revision to the specified
7214 changeset (see :hg:`help parents`).
7214 changeset (see :hg:`help parents`).
7215
7215
7216 If the changeset is not a descendant or ancestor of the working
7216 If the changeset is not a descendant or ancestor of the working
7217 directory's parent, the update is aborted. With the -c/--check
7217 directory's parent, the update is aborted. With the -c/--check
7218 option, the working directory is checked for uncommitted changes; if
7218 option, the working directory is checked for uncommitted changes; if
7219 none are found, the working directory is updated to the specified
7219 none are found, the working directory is updated to the specified
7220 changeset.
7220 changeset.
7221
7221
7222 .. container:: verbose
7222 .. container:: verbose
7223
7223
7224 The following rules apply when the working directory contains
7224 The following rules apply when the working directory contains
7225 uncommitted changes:
7225 uncommitted changes:
7226
7226
7227 1. If neither -c/--check nor -C/--clean is specified, and if
7227 1. If neither -c/--check nor -C/--clean is specified, and if
7228 the requested changeset is an ancestor or descendant of
7228 the requested changeset is an ancestor or descendant of
7229 the working directory's parent, the uncommitted changes
7229 the working directory's parent, the uncommitted changes
7230 are merged into the requested changeset and the merged
7230 are merged into the requested changeset and the merged
7231 result is left uncommitted. If the requested changeset is
7231 result is left uncommitted. If the requested changeset is
7232 not an ancestor or descendant (that is, it is on another
7232 not an ancestor or descendant (that is, it is on another
7233 branch), the update is aborted and the uncommitted changes
7233 branch), the update is aborted and the uncommitted changes
7234 are preserved.
7234 are preserved.
7235
7235
7236 2. With the -c/--check option, the update is aborted and the
7236 2. With the -c/--check option, the update is aborted and the
7237 uncommitted changes are preserved.
7237 uncommitted changes are preserved.
7238
7238
7239 3. With the -C/--clean option, uncommitted changes are discarded and
7239 3. With the -C/--clean option, uncommitted changes are discarded and
7240 the working directory is updated to the requested changeset.
7240 the working directory is updated to the requested changeset.
7241
7241
7242 To cancel an uncommitted merge (and lose your changes), use
7242 To cancel an uncommitted merge (and lose your changes), use
7243 :hg:`update --clean .`.
7243 :hg:`update --clean .`.
7244
7244
7245 Use null as the changeset to remove the working directory (like
7245 Use null as the changeset to remove the working directory (like
7246 :hg:`clone -U`).
7246 :hg:`clone -U`).
7247
7247
7248 If you want to revert just one file to an older revision, use
7248 If you want to revert just one file to an older revision, use
7249 :hg:`revert [-r REV] NAME`.
7249 :hg:`revert [-r REV] NAME`.
7250
7250
7251 See :hg:`help dates` for a list of formats valid for -d/--date.
7251 See :hg:`help dates` for a list of formats valid for -d/--date.
7252
7252
7253 Returns 0 on success, 1 if there are unresolved files.
7253 Returns 0 on success, 1 if there are unresolved files.
7254 """
7254 """
7255 if rev and node:
7255 if rev and node:
7256 raise error.Abort(_("please specify just one revision"))
7256 raise error.Abort(_("please specify just one revision"))
7257
7257
7258 if rev is None or rev == '':
7258 if rev is None or rev == '':
7259 rev = node
7259 rev = node
7260
7260
7261 if date and rev is not None:
7261 if date and rev is not None:
7262 raise error.Abort(_("you can't specify a revision and a date"))
7262 raise error.Abort(_("you can't specify a revision and a date"))
7263
7263
7264 if check and clean:
7264 if check and clean:
7265 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7265 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7266
7266
7267 with repo.wlock():
7267 with repo.wlock():
7268 cmdutil.clearunfinished(repo)
7268 cmdutil.clearunfinished(repo)
7269
7269
7270 if date:
7270 if date:
7271 rev = cmdutil.finddate(ui, repo, date)
7271 rev = cmdutil.finddate(ui, repo, date)
7272
7272
7273 # if we defined a bookmark, we have to remember the original name
7273 # if we defined a bookmark, we have to remember the original name
7274 brev = rev
7274 brev = rev
7275 rev = scmutil.revsingle(repo, rev, rev).rev()
7275 rev = scmutil.revsingle(repo, rev, rev).rev()
7276
7276
7277 if check:
7277 if check:
7278 cmdutil.bailifchanged(repo, merge=False)
7278 cmdutil.bailifchanged(repo, merge=False)
7279
7279
7280 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7280 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7281
7281
7282 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7282 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7283
7283
7284 @command('verify', [])
7284 @command('verify', [])
7285 def verify(ui, repo):
7285 def verify(ui, repo):
7286 """verify the integrity of the repository
7286 """verify the integrity of the repository
7287
7287
7288 Verify the integrity of the current repository.
7288 Verify the integrity of the current repository.
7289
7289
7290 This will perform an extensive check of the repository's
7290 This will perform an extensive check of the repository's
7291 integrity, validating the hashes and checksums of each entry in
7291 integrity, validating the hashes and checksums of each entry in
7292 the changelog, manifest, and tracked files, as well as the
7292 the changelog, manifest, and tracked files, as well as the
7293 integrity of their crosslinks and indices.
7293 integrity of their crosslinks and indices.
7294
7294
7295 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7295 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7296 for more information about recovery from corruption of the
7296 for more information about recovery from corruption of the
7297 repository.
7297 repository.
7298
7298
7299 Returns 0 on success, 1 if errors are encountered.
7299 Returns 0 on success, 1 if errors are encountered.
7300 """
7300 """
7301 return hg.verify(repo)
7301 return hg.verify(repo)
7302
7302
7303 @command('version', [] + formatteropts, norepo=True)
7303 @command('version', [] + formatteropts, norepo=True)
7304 def version_(ui, **opts):
7304 def version_(ui, **opts):
7305 """output version and copyright information"""
7305 """output version and copyright information"""
7306 fm = ui.formatter("version", opts)
7306 fm = ui.formatter("version", opts)
7307 fm.startitem()
7307 fm.startitem()
7308 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7308 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7309 util.version())
7309 util.version())
7310 license = _(
7310 license = _(
7311 "(see https://mercurial-scm.org for more information)\n"
7311 "(see https://mercurial-scm.org for more information)\n"
7312 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7312 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7313 "This is free software; see the source for copying conditions. "
7313 "This is free software; see the source for copying conditions. "
7314 "There is NO\nwarranty; "
7314 "There is NO\nwarranty; "
7315 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7315 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7316 )
7316 )
7317 if not ui.quiet:
7317 if not ui.quiet:
7318 fm.plain(license)
7318 fm.plain(license)
7319
7319
7320 if ui.verbose:
7320 if ui.verbose:
7321 fm.plain(_("\nEnabled extensions:\n\n"))
7321 fm.plain(_("\nEnabled extensions:\n\n"))
7322 # format names and versions into columns
7322 # format names and versions into columns
7323 names = []
7323 names = []
7324 vers = []
7324 vers = []
7325 isinternals = []
7325 isinternals = []
7326 for name, module in extensions.extensions():
7326 for name, module in extensions.extensions():
7327 names.append(name)
7327 names.append(name)
7328 vers.append(extensions.moduleversion(module) or None)
7328 vers.append(extensions.moduleversion(module) or None)
7329 isinternals.append(extensions.ismoduleinternal(module))
7329 isinternals.append(extensions.ismoduleinternal(module))
7330 fn = fm.nested("extensions")
7330 fn = fm.nested("extensions")
7331 if names:
7331 if names:
7332 namefmt = " %%-%ds " % max(len(n) for n in names)
7332 namefmt = " %%-%ds " % max(len(n) for n in names)
7333 places = [_("external"), _("internal")]
7333 places = [_("external"), _("internal")]
7334 for n, v, p in zip(names, vers, isinternals):
7334 for n, v, p in zip(names, vers, isinternals):
7335 fn.startitem()
7335 fn.startitem()
7336 fn.condwrite(ui.verbose, "name", namefmt, n)
7336 fn.condwrite(ui.verbose, "name", namefmt, n)
7337 if ui.verbose:
7337 if ui.verbose:
7338 fn.plain("%s " % places[p])
7338 fn.plain("%s " % places[p])
7339 fn.data(bundled=p)
7339 fn.data(bundled=p)
7340 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7340 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7341 if ui.verbose:
7341 if ui.verbose:
7342 fn.plain("\n")
7342 fn.plain("\n")
7343 fn.end()
7343 fn.end()
7344 fm.end()
7344 fm.end()
7345
7345
7346 def loadcmdtable(ui, name, cmdtable):
7346 def loadcmdtable(ui, name, cmdtable):
7347 """Load command functions from specified cmdtable
7347 """Load command functions from specified cmdtable
7348 """
7348 """
7349 overrides = [cmd for cmd in cmdtable if cmd in table]
7349 overrides = [cmd for cmd in cmdtable if cmd in table]
7350 if overrides:
7350 if overrides:
7351 ui.warn(_("extension '%s' overrides commands: %s\n")
7351 ui.warn(_("extension '%s' overrides commands: %s\n")
7352 % (name, " ".join(overrides)))
7352 % (name, " ".join(overrides)))
7353 table.update(cmdtable)
7353 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now