##// END OF EJS Templates
bisect: move check_state into the bisect module...
Pierre-Yves David -
r30126:755730fc default
parent child Browse files
Show More
@@ -1,7353 +1,7345 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):
839 if state['good'] and state['bad']:
840 return True
841 if not state['good']:
842 raise error.Abort(_('cannot bisect (no known good revisions)'))
843 else:
844 raise error.Abort(_('cannot bisect (no known bad revisions)'))
845
846 # backward compatibility
838 # backward compatibility
847 if rev in "good bad reset init".split():
839 if rev in "good bad reset init".split():
848 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
840 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
849 cmd, rev, extra = rev, extra, None
841 cmd, rev, extra = rev, extra, None
850 if cmd == "good":
842 if cmd == "good":
851 good = True
843 good = True
852 elif cmd == "bad":
844 elif cmd == "bad":
853 bad = True
845 bad = True
854 else:
846 else:
855 reset = True
847 reset = True
856 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
848 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
857 raise error.Abort(_('incompatible arguments'))
849 raise error.Abort(_('incompatible arguments'))
858
850
859 cmdutil.checkunfinished(repo)
851 cmdutil.checkunfinished(repo)
860
852
861 if reset:
853 if reset:
862 hbisect.resetstate(repo)
854 hbisect.resetstate(repo)
863 return
855 return
864
856
865 state = hbisect.load_state(repo)
857 state = hbisect.load_state(repo)
866
858
867 # update state
859 # update state
868 if good or bad or skip:
860 if good or bad or skip:
869 if rev:
861 if rev:
870 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
862 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
871 else:
863 else:
872 nodes = [repo.lookup('.')]
864 nodes = [repo.lookup('.')]
873 if good:
865 if good:
874 state['good'] += nodes
866 state['good'] += nodes
875 elif bad:
867 elif bad:
876 state['bad'] += nodes
868 state['bad'] += nodes
877 elif skip:
869 elif skip:
878 state['skip'] += nodes
870 state['skip'] += nodes
879 hbisect.save_state(repo, state)
871 hbisect.save_state(repo, state)
880 if not (state['good'] and state['bad']):
872 if not (state['good'] and state['bad']):
881 return
873 return
882
874
883 if command:
875 if command:
884 changesets = 1
876 changesets = 1
885 if noupdate:
877 if noupdate:
886 try:
878 try:
887 node = state['current'][0]
879 node = state['current'][0]
888 except LookupError:
880 except LookupError:
889 raise error.Abort(_('current bisect revision is unknown - '
881 raise error.Abort(_('current bisect revision is unknown - '
890 'start a new bisect to fix'))
882 'start a new bisect to fix'))
891 else:
883 else:
892 node, p2 = repo.dirstate.parents()
884 node, p2 = repo.dirstate.parents()
893 if p2 != nullid:
885 if p2 != nullid:
894 raise error.Abort(_('current bisect revision is a merge'))
886 raise error.Abort(_('current bisect revision is a merge'))
895 try:
887 try:
896 while changesets:
888 while changesets:
897 # update state
889 # update state
898 state['current'] = [node]
890 state['current'] = [node]
899 hbisect.save_state(repo, state)
891 hbisect.save_state(repo, state)
900 status = ui.system(command, environ={'HG_NODE': hex(node)})
892 status = ui.system(command, environ={'HG_NODE': hex(node)})
901 if status == 125:
893 if status == 125:
902 transition = "skip"
894 transition = "skip"
903 elif status == 0:
895 elif status == 0:
904 transition = "good"
896 transition = "good"
905 # status < 0 means process was killed
897 # status < 0 means process was killed
906 elif status == 127:
898 elif status == 127:
907 raise error.Abort(_("failed to execute %s") % command)
899 raise error.Abort(_("failed to execute %s") % command)
908 elif status < 0:
900 elif status < 0:
909 raise error.Abort(_("%s killed") % command)
901 raise error.Abort(_("%s killed") % command)
910 else:
902 else:
911 transition = "bad"
903 transition = "bad"
912 ctx = scmutil.revsingle(repo, rev, node)
904 ctx = scmutil.revsingle(repo, rev, node)
913 rev = None # clear for future iterations
905 rev = None # clear for future iterations
914 state[transition].append(ctx.node())
906 state[transition].append(ctx.node())
915 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
907 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
916 checkstate(state)
908 hbisect.checkstate(state)
917 # bisect
909 # bisect
918 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
910 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
919 # update to next check
911 # update to next check
920 node = nodes[0]
912 node = nodes[0]
921 if not noupdate:
913 if not noupdate:
922 cmdutil.bailifchanged(repo)
914 cmdutil.bailifchanged(repo)
923 hg.clean(repo, node, show_stats=False)
915 hg.clean(repo, node, show_stats=False)
924 finally:
916 finally:
925 state['current'] = [node]
917 state['current'] = [node]
926 hbisect.save_state(repo, state)
918 hbisect.save_state(repo, state)
927 displayer = cmdutil.show_changeset(ui, repo, {})
919 displayer = cmdutil.show_changeset(ui, repo, {})
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
920 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
929 return
921 return
930
922
931 checkstate(state)
923 hbisect.checkstate(state)
932
924
933 # actually bisect
925 # actually bisect
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
926 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 if extend:
927 if extend:
936 if not changesets:
928 if not changesets:
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
929 extendnode = hbisect.extendrange(repo, state, nodes, good)
938 if extendnode is not None:
930 if extendnode is not None:
939 ui.write(_("Extending search to changeset %d:%s\n")
931 ui.write(_("Extending search to changeset %d:%s\n")
940 % (extendnode.rev(), extendnode))
932 % (extendnode.rev(), extendnode))
941 state['current'] = [extendnode.node()]
933 state['current'] = [extendnode.node()]
942 hbisect.save_state(repo, state)
934 hbisect.save_state(repo, state)
943 if noupdate:
935 if noupdate:
944 return
936 return
945 cmdutil.bailifchanged(repo)
937 cmdutil.bailifchanged(repo)
946 return hg.clean(repo, extendnode.node())
938 return hg.clean(repo, extendnode.node())
947 raise error.Abort(_("nothing to extend"))
939 raise error.Abort(_("nothing to extend"))
948
940
949 if changesets == 0:
941 if changesets == 0:
950 displayer = cmdutil.show_changeset(ui, repo, {})
942 displayer = cmdutil.show_changeset(ui, repo, {})
951 hbisect.printresult(ui, repo, state, displayer, nodes, good)
943 hbisect.printresult(ui, repo, state, displayer, nodes, good)
952 else:
944 else:
953 assert len(nodes) == 1 # only a single node can be tested next
945 assert len(nodes) == 1 # only a single node can be tested next
954 node = nodes[0]
946 node = nodes[0]
955 # compute the approximate number of remaining tests
947 # compute the approximate number of remaining tests
956 tests, size = 0, 2
948 tests, size = 0, 2
957 while size <= changesets:
949 while size <= changesets:
958 tests, size = tests + 1, size * 2
950 tests, size = tests + 1, size * 2
959 rev = repo.changelog.rev(node)
951 rev = repo.changelog.rev(node)
960 ui.write(_("Testing changeset %d:%s "
952 ui.write(_("Testing changeset %d:%s "
961 "(%d changesets remaining, ~%d tests)\n")
953 "(%d changesets remaining, ~%d tests)\n")
962 % (rev, short(node), changesets, tests))
954 % (rev, short(node), changesets, tests))
963 state['current'] = [node]
955 state['current'] = [node]
964 hbisect.save_state(repo, state)
956 hbisect.save_state(repo, state)
965 if not noupdate:
957 if not noupdate:
966 cmdutil.bailifchanged(repo)
958 cmdutil.bailifchanged(repo)
967 return hg.clean(repo, node)
959 return hg.clean(repo, node)
968
960
969 @command('bookmarks|bookmark',
961 @command('bookmarks|bookmark',
970 [('f', 'force', False, _('force')),
962 [('f', 'force', False, _('force')),
971 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
963 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
972 ('d', 'delete', False, _('delete a given bookmark')),
964 ('d', 'delete', False, _('delete a given bookmark')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
965 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
966 ('i', 'inactive', False, _('mark a bookmark inactive')),
975 ] + formatteropts,
967 ] + formatteropts,
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
968 _('hg bookmarks [OPTIONS]... [NAME]...'))
977 def bookmark(ui, repo, *names, **opts):
969 def bookmark(ui, repo, *names, **opts):
978 '''create a new bookmark or list existing bookmarks
970 '''create a new bookmark or list existing bookmarks
979
971
980 Bookmarks are labels on changesets to help track lines of development.
972 Bookmarks are labels on changesets to help track lines of development.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
973 Bookmarks are unversioned and can be moved, renamed and deleted.
982 Deleting or moving a bookmark has no effect on the associated changesets.
974 Deleting or moving a bookmark has no effect on the associated changesets.
983
975
984 Creating or updating to a bookmark causes it to be marked as 'active'.
976 Creating or updating to a bookmark causes it to be marked as 'active'.
985 The active bookmark is indicated with a '*'.
977 The active bookmark is indicated with a '*'.
986 When a commit is made, the active bookmark will advance to the new commit.
978 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.
979 A plain :hg:`update` will also advance an active bookmark, if possible.
988 Updating away from a bookmark will cause it to be deactivated.
980 Updating away from a bookmark will cause it to be deactivated.
989
981
990 Bookmarks can be pushed and pulled between repositories (see
982 Bookmarks can be pushed and pulled between repositories (see
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
983 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
984 diverged, a new 'divergent bookmark' of the form 'name@path' will
993 be created. Using :hg:`merge` will resolve the divergence.
985 be created. Using :hg:`merge` will resolve the divergence.
994
986
995 A bookmark named '@' has the special property that :hg:`clone` will
987 A bookmark named '@' has the special property that :hg:`clone` will
996 check it out by default if it exists.
988 check it out by default if it exists.
997
989
998 .. container:: verbose
990 .. container:: verbose
999
991
1000 Examples:
992 Examples:
1001
993
1002 - create an active bookmark for a new line of development::
994 - create an active bookmark for a new line of development::
1003
995
1004 hg book new-feature
996 hg book new-feature
1005
997
1006 - create an inactive bookmark as a place marker::
998 - create an inactive bookmark as a place marker::
1007
999
1008 hg book -i reviewed
1000 hg book -i reviewed
1009
1001
1010 - create an inactive bookmark on another changeset::
1002 - create an inactive bookmark on another changeset::
1011
1003
1012 hg book -r .^ tested
1004 hg book -r .^ tested
1013
1005
1014 - rename bookmark turkey to dinner::
1006 - rename bookmark turkey to dinner::
1015
1007
1016 hg book -m turkey dinner
1008 hg book -m turkey dinner
1017
1009
1018 - move the '@' bookmark from another branch::
1010 - move the '@' bookmark from another branch::
1019
1011
1020 hg book -f @
1012 hg book -f @
1021 '''
1013 '''
1022 force = opts.get('force')
1014 force = opts.get('force')
1023 rev = opts.get('rev')
1015 rev = opts.get('rev')
1024 delete = opts.get('delete')
1016 delete = opts.get('delete')
1025 rename = opts.get('rename')
1017 rename = opts.get('rename')
1026 inactive = opts.get('inactive')
1018 inactive = opts.get('inactive')
1027
1019
1028 def checkformat(mark):
1020 def checkformat(mark):
1029 mark = mark.strip()
1021 mark = mark.strip()
1030 if not mark:
1022 if not mark:
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1023 raise error.Abort(_("bookmark names cannot consist entirely of "
1032 "whitespace"))
1024 "whitespace"))
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1025 scmutil.checknewlabel(repo, mark, 'bookmark')
1034 return mark
1026 return mark
1035
1027
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1028 def checkconflict(repo, mark, cur, force=False, target=None):
1037 if mark in marks and not force:
1029 if mark in marks and not force:
1038 if target:
1030 if target:
1039 if marks[mark] == target and target == cur:
1031 if marks[mark] == target and target == cur:
1040 # re-activating a bookmark
1032 # re-activating a bookmark
1041 return
1033 return
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1034 anc = repo.changelog.ancestors([repo[target].rev()])
1043 bmctx = repo[marks[mark]]
1035 bmctx = repo[marks[mark]]
1044 divs = [repo[b].node() for b in marks
1036 divs = [repo[b].node() for b in marks
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1037 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1046
1038
1047 # allow resolving a single divergent bookmark even if moving
1039 # allow resolving a single divergent bookmark even if moving
1048 # the bookmark across branches when a revision is specified
1040 # the bookmark across branches when a revision is specified
1049 # that contains a divergent bookmark
1041 # that contains a divergent bookmark
1050 if bmctx.rev() not in anc and target in divs:
1042 if bmctx.rev() not in anc and target in divs:
1051 bookmarks.deletedivergent(repo, [target], mark)
1043 bookmarks.deletedivergent(repo, [target], mark)
1052 return
1044 return
1053
1045
1054 deletefrom = [b for b in divs
1046 deletefrom = [b for b in divs
1055 if repo[b].rev() in anc or b == target]
1047 if repo[b].rev() in anc or b == target]
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1048 bookmarks.deletedivergent(repo, deletefrom, mark)
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1049 if bookmarks.validdest(repo, bmctx, repo[target]):
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1050 ui.status(_("moving bookmark '%s' forward from %s\n") %
1059 (mark, short(bmctx.node())))
1051 (mark, short(bmctx.node())))
1060 return
1052 return
1061 raise error.Abort(_("bookmark '%s' already exists "
1053 raise error.Abort(_("bookmark '%s' already exists "
1062 "(use -f to force)") % mark)
1054 "(use -f to force)") % mark)
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1055 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1064 and not force):
1056 and not force):
1065 raise error.Abort(
1057 raise error.Abort(
1066 _("a bookmark cannot have the name of an existing branch"))
1058 _("a bookmark cannot have the name of an existing branch"))
1067
1059
1068 if delete and rename:
1060 if delete and rename:
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1061 raise error.Abort(_("--delete and --rename are incompatible"))
1070 if delete and rev:
1062 if delete and rev:
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1063 raise error.Abort(_("--rev is incompatible with --delete"))
1072 if rename and rev:
1064 if rename and rev:
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1065 raise error.Abort(_("--rev is incompatible with --rename"))
1074 if not names and (delete or rev):
1066 if not names and (delete or rev):
1075 raise error.Abort(_("bookmark name required"))
1067 raise error.Abort(_("bookmark name required"))
1076
1068
1077 if delete or rename or names or inactive:
1069 if delete or rename or names or inactive:
1078 wlock = lock = tr = None
1070 wlock = lock = tr = None
1079 try:
1071 try:
1080 wlock = repo.wlock()
1072 wlock = repo.wlock()
1081 lock = repo.lock()
1073 lock = repo.lock()
1082 cur = repo.changectx('.').node()
1074 cur = repo.changectx('.').node()
1083 marks = repo._bookmarks
1075 marks = repo._bookmarks
1084 if delete:
1076 if delete:
1085 tr = repo.transaction('bookmark')
1077 tr = repo.transaction('bookmark')
1086 for mark in names:
1078 for mark in names:
1087 if mark not in marks:
1079 if mark not in marks:
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1080 raise error.Abort(_("bookmark '%s' does not exist") %
1089 mark)
1081 mark)
1090 if mark == repo._activebookmark:
1082 if mark == repo._activebookmark:
1091 bookmarks.deactivate(repo)
1083 bookmarks.deactivate(repo)
1092 del marks[mark]
1084 del marks[mark]
1093
1085
1094 elif rename:
1086 elif rename:
1095 tr = repo.transaction('bookmark')
1087 tr = repo.transaction('bookmark')
1096 if not names:
1088 if not names:
1097 raise error.Abort(_("new bookmark name required"))
1089 raise error.Abort(_("new bookmark name required"))
1098 elif len(names) > 1:
1090 elif len(names) > 1:
1099 raise error.Abort(_("only one new bookmark name allowed"))
1091 raise error.Abort(_("only one new bookmark name allowed"))
1100 mark = checkformat(names[0])
1092 mark = checkformat(names[0])
1101 if rename not in marks:
1093 if rename not in marks:
1102 raise error.Abort(_("bookmark '%s' does not exist")
1094 raise error.Abort(_("bookmark '%s' does not exist")
1103 % rename)
1095 % rename)
1104 checkconflict(repo, mark, cur, force)
1096 checkconflict(repo, mark, cur, force)
1105 marks[mark] = marks[rename]
1097 marks[mark] = marks[rename]
1106 if repo._activebookmark == rename and not inactive:
1098 if repo._activebookmark == rename and not inactive:
1107 bookmarks.activate(repo, mark)
1099 bookmarks.activate(repo, mark)
1108 del marks[rename]
1100 del marks[rename]
1109 elif names:
1101 elif names:
1110 tr = repo.transaction('bookmark')
1102 tr = repo.transaction('bookmark')
1111 newact = None
1103 newact = None
1112 for mark in names:
1104 for mark in names:
1113 mark = checkformat(mark)
1105 mark = checkformat(mark)
1114 if newact is None:
1106 if newact is None:
1115 newact = mark
1107 newact = mark
1116 if inactive and mark == repo._activebookmark:
1108 if inactive and mark == repo._activebookmark:
1117 bookmarks.deactivate(repo)
1109 bookmarks.deactivate(repo)
1118 return
1110 return
1119 tgt = cur
1111 tgt = cur
1120 if rev:
1112 if rev:
1121 tgt = scmutil.revsingle(repo, rev).node()
1113 tgt = scmutil.revsingle(repo, rev).node()
1122 checkconflict(repo, mark, cur, force, tgt)
1114 checkconflict(repo, mark, cur, force, tgt)
1123 marks[mark] = tgt
1115 marks[mark] = tgt
1124 if not inactive and cur == marks[newact] and not rev:
1116 if not inactive and cur == marks[newact] and not rev:
1125 bookmarks.activate(repo, newact)
1117 bookmarks.activate(repo, newact)
1126 elif cur != tgt and newact == repo._activebookmark:
1118 elif cur != tgt and newact == repo._activebookmark:
1127 bookmarks.deactivate(repo)
1119 bookmarks.deactivate(repo)
1128 elif inactive:
1120 elif inactive:
1129 if len(marks) == 0:
1121 if len(marks) == 0:
1130 ui.status(_("no bookmarks set\n"))
1122 ui.status(_("no bookmarks set\n"))
1131 elif not repo._activebookmark:
1123 elif not repo._activebookmark:
1132 ui.status(_("no active bookmark\n"))
1124 ui.status(_("no active bookmark\n"))
1133 else:
1125 else:
1134 bookmarks.deactivate(repo)
1126 bookmarks.deactivate(repo)
1135 if tr is not None:
1127 if tr is not None:
1136 marks.recordchange(tr)
1128 marks.recordchange(tr)
1137 tr.close()
1129 tr.close()
1138 finally:
1130 finally:
1139 lockmod.release(tr, lock, wlock)
1131 lockmod.release(tr, lock, wlock)
1140 else: # show bookmarks
1132 else: # show bookmarks
1141 fm = ui.formatter('bookmarks', opts)
1133 fm = ui.formatter('bookmarks', opts)
1142 hexfn = fm.hexfunc
1134 hexfn = fm.hexfunc
1143 marks = repo._bookmarks
1135 marks = repo._bookmarks
1144 if len(marks) == 0 and fm.isplain():
1136 if len(marks) == 0 and fm.isplain():
1145 ui.status(_("no bookmarks set\n"))
1137 ui.status(_("no bookmarks set\n"))
1146 for bmark, n in sorted(marks.iteritems()):
1138 for bmark, n in sorted(marks.iteritems()):
1147 active = repo._activebookmark
1139 active = repo._activebookmark
1148 if bmark == active:
1140 if bmark == active:
1149 prefix, label = '*', activebookmarklabel
1141 prefix, label = '*', activebookmarklabel
1150 else:
1142 else:
1151 prefix, label = ' ', ''
1143 prefix, label = ' ', ''
1152
1144
1153 fm.startitem()
1145 fm.startitem()
1154 if not ui.quiet:
1146 if not ui.quiet:
1155 fm.plain(' %s ' % prefix, label=label)
1147 fm.plain(' %s ' % prefix, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1148 fm.write('bookmark', '%s', bmark, label=label)
1157 pad = " " * (25 - encoding.colwidth(bmark))
1149 pad = " " * (25 - encoding.colwidth(bmark))
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1150 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1159 repo.changelog.rev(n), hexfn(n), label=label)
1151 repo.changelog.rev(n), hexfn(n), label=label)
1160 fm.data(active=(bmark == active))
1152 fm.data(active=(bmark == active))
1161 fm.plain('\n')
1153 fm.plain('\n')
1162 fm.end()
1154 fm.end()
1163
1155
1164 @command('branch',
1156 @command('branch',
1165 [('f', 'force', None,
1157 [('f', 'force', None,
1166 _('set branch name even if it shadows an existing branch')),
1158 _('set branch name even if it shadows an existing branch')),
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1159 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1168 _('[-fC] [NAME]'))
1160 _('[-fC] [NAME]'))
1169 def branch(ui, repo, label=None, **opts):
1161 def branch(ui, repo, label=None, **opts):
1170 """set or show the current branch name
1162 """set or show the current branch name
1171
1163
1172 .. note::
1164 .. note::
1173
1165
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1166 Branch names are permanent and global. Use :hg:`bookmark` to create a
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1167 light-weight bookmark instead. See :hg:`help glossary` for more
1176 information about named branches and bookmarks.
1168 information about named branches and bookmarks.
1177
1169
1178 With no argument, show the current branch name. With one argument,
1170 With no argument, show the current branch name. With one argument,
1179 set the working directory branch name (the branch will not exist
1171 set the working directory branch name (the branch will not exist
1180 in the repository until the next commit). Standard practice
1172 in the repository until the next commit). Standard practice
1181 recommends that primary development take place on the 'default'
1173 recommends that primary development take place on the 'default'
1182 branch.
1174 branch.
1183
1175
1184 Unless -f/--force is specified, branch will not let you set a
1176 Unless -f/--force is specified, branch will not let you set a
1185 branch name that already exists.
1177 branch name that already exists.
1186
1178
1187 Use -C/--clean to reset the working directory branch to that of
1179 Use -C/--clean to reset the working directory branch to that of
1188 the parent of the working directory, negating a previous branch
1180 the parent of the working directory, negating a previous branch
1189 change.
1181 change.
1190
1182
1191 Use the command :hg:`update` to switch to an existing branch. Use
1183 Use the command :hg:`update` to switch to an existing branch. Use
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1184 :hg:`commit --close-branch` to mark this branch head as closed.
1193 When all heads of a branch are closed, the branch will be
1185 When all heads of a branch are closed, the branch will be
1194 considered closed.
1186 considered closed.
1195
1187
1196 Returns 0 on success.
1188 Returns 0 on success.
1197 """
1189 """
1198 if label:
1190 if label:
1199 label = label.strip()
1191 label = label.strip()
1200
1192
1201 if not opts.get('clean') and not label:
1193 if not opts.get('clean') and not label:
1202 ui.write("%s\n" % repo.dirstate.branch())
1194 ui.write("%s\n" % repo.dirstate.branch())
1203 return
1195 return
1204
1196
1205 with repo.wlock():
1197 with repo.wlock():
1206 if opts.get('clean'):
1198 if opts.get('clean'):
1207 label = repo[None].p1().branch()
1199 label = repo[None].p1().branch()
1208 repo.dirstate.setbranch(label)
1200 repo.dirstate.setbranch(label)
1209 ui.status(_('reset working directory to branch %s\n') % label)
1201 ui.status(_('reset working directory to branch %s\n') % label)
1210 elif label:
1202 elif label:
1211 if not opts.get('force') and label in repo.branchmap():
1203 if not opts.get('force') and label in repo.branchmap():
1212 if label not in [p.branch() for p in repo[None].parents()]:
1204 if label not in [p.branch() for p in repo[None].parents()]:
1213 raise error.Abort(_('a branch of the same name already'
1205 raise error.Abort(_('a branch of the same name already'
1214 ' exists'),
1206 ' exists'),
1215 # i18n: "it" refers to an existing branch
1207 # i18n: "it" refers to an existing branch
1216 hint=_("use 'hg update' to switch to it"))
1208 hint=_("use 'hg update' to switch to it"))
1217 scmutil.checknewlabel(repo, label, 'branch')
1209 scmutil.checknewlabel(repo, label, 'branch')
1218 repo.dirstate.setbranch(label)
1210 repo.dirstate.setbranch(label)
1219 ui.status(_('marked working directory as branch %s\n') % label)
1211 ui.status(_('marked working directory as branch %s\n') % label)
1220
1212
1221 # find any open named branches aside from default
1213 # find any open named branches aside from default
1222 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1214 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1223 if n != "default" and not c]
1215 if n != "default" and not c]
1224 if not others:
1216 if not others:
1225 ui.status(_('(branches are permanent and global, '
1217 ui.status(_('(branches are permanent and global, '
1226 'did you want a bookmark?)\n'))
1218 'did you want a bookmark?)\n'))
1227
1219
1228 @command('branches',
1220 @command('branches',
1229 [('a', 'active', False,
1221 [('a', 'active', False,
1230 _('show only branches that have unmerged heads (DEPRECATED)')),
1222 _('show only branches that have unmerged heads (DEPRECATED)')),
1231 ('c', 'closed', False, _('show normal and closed branches')),
1223 ('c', 'closed', False, _('show normal and closed branches')),
1232 ] + formatteropts,
1224 ] + formatteropts,
1233 _('[-c]'))
1225 _('[-c]'))
1234 def branches(ui, repo, active=False, closed=False, **opts):
1226 def branches(ui, repo, active=False, closed=False, **opts):
1235 """list repository named branches
1227 """list repository named branches
1236
1228
1237 List the repository's named branches, indicating which ones are
1229 List the repository's named branches, indicating which ones are
1238 inactive. If -c/--closed is specified, also list branches which have
1230 inactive. If -c/--closed is specified, also list branches which have
1239 been marked closed (see :hg:`commit --close-branch`).
1231 been marked closed (see :hg:`commit --close-branch`).
1240
1232
1241 Use the command :hg:`update` to switch to an existing branch.
1233 Use the command :hg:`update` to switch to an existing branch.
1242
1234
1243 Returns 0.
1235 Returns 0.
1244 """
1236 """
1245
1237
1246 fm = ui.formatter('branches', opts)
1238 fm = ui.formatter('branches', opts)
1247 hexfunc = fm.hexfunc
1239 hexfunc = fm.hexfunc
1248
1240
1249 allheads = set(repo.heads())
1241 allheads = set(repo.heads())
1250 branches = []
1242 branches = []
1251 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1243 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1252 isactive = not isclosed and bool(set(heads) & allheads)
1244 isactive = not isclosed and bool(set(heads) & allheads)
1253 branches.append((tag, repo[tip], isactive, not isclosed))
1245 branches.append((tag, repo[tip], isactive, not isclosed))
1254 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1246 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1255 reverse=True)
1247 reverse=True)
1256
1248
1257 for tag, ctx, isactive, isopen in branches:
1249 for tag, ctx, isactive, isopen in branches:
1258 if active and not isactive:
1250 if active and not isactive:
1259 continue
1251 continue
1260 if isactive:
1252 if isactive:
1261 label = 'branches.active'
1253 label = 'branches.active'
1262 notice = ''
1254 notice = ''
1263 elif not isopen:
1255 elif not isopen:
1264 if not closed:
1256 if not closed:
1265 continue
1257 continue
1266 label = 'branches.closed'
1258 label = 'branches.closed'
1267 notice = _(' (closed)')
1259 notice = _(' (closed)')
1268 else:
1260 else:
1269 label = 'branches.inactive'
1261 label = 'branches.inactive'
1270 notice = _(' (inactive)')
1262 notice = _(' (inactive)')
1271 current = (tag == repo.dirstate.branch())
1263 current = (tag == repo.dirstate.branch())
1272 if current:
1264 if current:
1273 label = 'branches.current'
1265 label = 'branches.current'
1274
1266
1275 fm.startitem()
1267 fm.startitem()
1276 fm.write('branch', '%s', tag, label=label)
1268 fm.write('branch', '%s', tag, label=label)
1277 rev = ctx.rev()
1269 rev = ctx.rev()
1278 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1270 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1279 fmt = ' ' * padsize + ' %d:%s'
1271 fmt = ' ' * padsize + ' %d:%s'
1280 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1272 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1281 label='log.changeset changeset.%s' % ctx.phasestr())
1273 label='log.changeset changeset.%s' % ctx.phasestr())
1282 fm.data(active=isactive, closed=not isopen, current=current)
1274 fm.data(active=isactive, closed=not isopen, current=current)
1283 if not ui.quiet:
1275 if not ui.quiet:
1284 fm.plain(notice)
1276 fm.plain(notice)
1285 fm.plain('\n')
1277 fm.plain('\n')
1286 fm.end()
1278 fm.end()
1287
1279
1288 @command('bundle',
1280 @command('bundle',
1289 [('f', 'force', None, _('run even when the destination is unrelated')),
1281 [('f', 'force', None, _('run even when the destination is unrelated')),
1290 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1282 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1291 _('REV')),
1283 _('REV')),
1292 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1284 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1293 _('BRANCH')),
1285 _('BRANCH')),
1294 ('', 'base', [],
1286 ('', 'base', [],
1295 _('a base changeset assumed to be available at the destination'),
1287 _('a base changeset assumed to be available at the destination'),
1296 _('REV')),
1288 _('REV')),
1297 ('a', 'all', None, _('bundle all changesets in the repository')),
1289 ('a', 'all', None, _('bundle all changesets in the repository')),
1298 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1290 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1299 ] + remoteopts,
1291 ] + remoteopts,
1300 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1292 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1301 def bundle(ui, repo, fname, dest=None, **opts):
1293 def bundle(ui, repo, fname, dest=None, **opts):
1302 """create a changegroup file
1294 """create a changegroup file
1303
1295
1304 Generate a changegroup file collecting changesets to be added
1296 Generate a changegroup file collecting changesets to be added
1305 to a repository.
1297 to a repository.
1306
1298
1307 To create a bundle containing all changesets, use -a/--all
1299 To create a bundle containing all changesets, use -a/--all
1308 (or --base null). Otherwise, hg assumes the destination will have
1300 (or --base null). Otherwise, hg assumes the destination will have
1309 all the nodes you specify with --base parameters. Otherwise, hg
1301 all the nodes you specify with --base parameters. Otherwise, hg
1310 will assume the repository has all the nodes in destination, or
1302 will assume the repository has all the nodes in destination, or
1311 default-push/default if no destination is specified.
1303 default-push/default if no destination is specified.
1312
1304
1313 You can change bundle format with the -t/--type option. You can
1305 You can change bundle format with the -t/--type option. You can
1314 specify a compression, a bundle version or both using a dash
1306 specify a compression, a bundle version or both using a dash
1315 (comp-version). The available compression methods are: none, bzip2,
1307 (comp-version). The available compression methods are: none, bzip2,
1316 and gzip (by default, bundles are compressed using bzip2). The
1308 and gzip (by default, bundles are compressed using bzip2). The
1317 available formats are: v1, v2 (default to most suitable).
1309 available formats are: v1, v2 (default to most suitable).
1318
1310
1319 The bundle file can then be transferred using conventional means
1311 The bundle file can then be transferred using conventional means
1320 and applied to another repository with the unbundle or pull
1312 and applied to another repository with the unbundle or pull
1321 command. This is useful when direct push and pull are not
1313 command. This is useful when direct push and pull are not
1322 available or when exporting an entire repository is undesirable.
1314 available or when exporting an entire repository is undesirable.
1323
1315
1324 Applying bundles preserves all changeset contents including
1316 Applying bundles preserves all changeset contents including
1325 permissions, copy/rename information, and revision history.
1317 permissions, copy/rename information, and revision history.
1326
1318
1327 Returns 0 on success, 1 if no changes found.
1319 Returns 0 on success, 1 if no changes found.
1328 """
1320 """
1329 revs = None
1321 revs = None
1330 if 'rev' in opts:
1322 if 'rev' in opts:
1331 revstrings = opts['rev']
1323 revstrings = opts['rev']
1332 revs = scmutil.revrange(repo, revstrings)
1324 revs = scmutil.revrange(repo, revstrings)
1333 if revstrings and not revs:
1325 if revstrings and not revs:
1334 raise error.Abort(_('no commits to bundle'))
1326 raise error.Abort(_('no commits to bundle'))
1335
1327
1336 bundletype = opts.get('type', 'bzip2').lower()
1328 bundletype = opts.get('type', 'bzip2').lower()
1337 try:
1329 try:
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1330 bcompression, cgversion, params = exchange.parsebundlespec(
1339 repo, bundletype, strict=False)
1331 repo, bundletype, strict=False)
1340 except error.UnsupportedBundleSpecification as e:
1332 except error.UnsupportedBundleSpecification as e:
1341 raise error.Abort(str(e),
1333 raise error.Abort(str(e),
1342 hint=_("see 'hg help bundle' for supported "
1334 hint=_("see 'hg help bundle' for supported "
1343 "values for --type"))
1335 "values for --type"))
1344
1336
1345 # Packed bundles are a pseudo bundle format for now.
1337 # Packed bundles are a pseudo bundle format for now.
1346 if cgversion == 's1':
1338 if cgversion == 's1':
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1339 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1348 hint=_("use 'hg debugcreatestreamclonebundle'"))
1340 hint=_("use 'hg debugcreatestreamclonebundle'"))
1349
1341
1350 if opts.get('all'):
1342 if opts.get('all'):
1351 if dest:
1343 if dest:
1352 raise error.Abort(_("--all is incompatible with specifying "
1344 raise error.Abort(_("--all is incompatible with specifying "
1353 "a destination"))
1345 "a destination"))
1354 if opts.get('base'):
1346 if opts.get('base'):
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1347 ui.warn(_("ignoring --base because --all was specified\n"))
1356 base = ['null']
1348 base = ['null']
1357 else:
1349 else:
1358 base = scmutil.revrange(repo, opts.get('base'))
1350 base = scmutil.revrange(repo, opts.get('base'))
1359 # TODO: get desired bundlecaps from command line.
1351 # TODO: get desired bundlecaps from command line.
1360 bundlecaps = None
1352 bundlecaps = None
1361 if cgversion not in changegroup.supportedoutgoingversions(repo):
1353 if cgversion not in changegroup.supportedoutgoingversions(repo):
1362 raise error.Abort(_("repository does not support bundle version %s") %
1354 raise error.Abort(_("repository does not support bundle version %s") %
1363 cgversion)
1355 cgversion)
1364
1356
1365 if base:
1357 if base:
1366 if dest:
1358 if dest:
1367 raise error.Abort(_("--base is incompatible with specifying "
1359 raise error.Abort(_("--base is incompatible with specifying "
1368 "a destination"))
1360 "a destination"))
1369 common = [repo.lookup(rev) for rev in base]
1361 common = [repo.lookup(rev) for rev in base]
1370 heads = revs and map(repo.lookup, revs) or None
1362 heads = revs and map(repo.lookup, revs) or None
1371 outgoing = discovery.outgoing(repo, common, heads)
1363 outgoing = discovery.outgoing(repo, common, heads)
1372 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1364 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1373 bundlecaps=bundlecaps,
1365 bundlecaps=bundlecaps,
1374 version=cgversion)
1366 version=cgversion)
1375 outgoing = None
1367 outgoing = None
1376 else:
1368 else:
1377 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1369 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1378 dest, branches = hg.parseurl(dest, opts.get('branch'))
1370 dest, branches = hg.parseurl(dest, opts.get('branch'))
1379 other = hg.peer(repo, opts, dest)
1371 other = hg.peer(repo, opts, dest)
1380 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1372 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1381 heads = revs and map(repo.lookup, revs) or revs
1373 heads = revs and map(repo.lookup, revs) or revs
1382 outgoing = discovery.findcommonoutgoing(repo, other,
1374 outgoing = discovery.findcommonoutgoing(repo, other,
1383 onlyheads=heads,
1375 onlyheads=heads,
1384 force=opts.get('force'),
1376 force=opts.get('force'),
1385 portable=True)
1377 portable=True)
1386 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1378 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1387 bundlecaps, version=cgversion)
1379 bundlecaps, version=cgversion)
1388 if not cg:
1380 if not cg:
1389 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1381 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1390 return 1
1382 return 1
1391
1383
1392 if cgversion == '01': #bundle1
1384 if cgversion == '01': #bundle1
1393 if bcompression is None:
1385 if bcompression is None:
1394 bcompression = 'UN'
1386 bcompression = 'UN'
1395 bversion = 'HG10' + bcompression
1387 bversion = 'HG10' + bcompression
1396 bcompression = None
1388 bcompression = None
1397 else:
1389 else:
1398 assert cgversion == '02'
1390 assert cgversion == '02'
1399 bversion = 'HG20'
1391 bversion = 'HG20'
1400
1392
1401 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1393 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1402
1394
1403 @command('cat',
1395 @command('cat',
1404 [('o', 'output', '',
1396 [('o', 'output', '',
1405 _('print output to file with formatted name'), _('FORMAT')),
1397 _('print output to file with formatted name'), _('FORMAT')),
1406 ('r', 'rev', '', _('print the given revision'), _('REV')),
1398 ('r', 'rev', '', _('print the given revision'), _('REV')),
1407 ('', 'decode', None, _('apply any matching decode filter')),
1399 ('', 'decode', None, _('apply any matching decode filter')),
1408 ] + walkopts,
1400 ] + walkopts,
1409 _('[OPTION]... FILE...'),
1401 _('[OPTION]... FILE...'),
1410 inferrepo=True)
1402 inferrepo=True)
1411 def cat(ui, repo, file1, *pats, **opts):
1403 def cat(ui, repo, file1, *pats, **opts):
1412 """output the current or given revision of files
1404 """output the current or given revision of files
1413
1405
1414 Print the specified files as they were at the given revision. If
1406 Print the specified files as they were at the given revision. If
1415 no revision is given, the parent of the working directory is used.
1407 no revision is given, the parent of the working directory is used.
1416
1408
1417 Output may be to a file, in which case the name of the file is
1409 Output may be to a file, in which case the name of the file is
1418 given using a format string. The formatting rules as follows:
1410 given using a format string. The formatting rules as follows:
1419
1411
1420 :``%%``: literal "%" character
1412 :``%%``: literal "%" character
1421 :``%s``: basename of file being printed
1413 :``%s``: basename of file being printed
1422 :``%d``: dirname of file being printed, or '.' if in repository root
1414 :``%d``: dirname of file being printed, or '.' if in repository root
1423 :``%p``: root-relative path name of file being printed
1415 :``%p``: root-relative path name of file being printed
1424 :``%H``: changeset hash (40 hexadecimal digits)
1416 :``%H``: changeset hash (40 hexadecimal digits)
1425 :``%R``: changeset revision number
1417 :``%R``: changeset revision number
1426 :``%h``: short-form changeset hash (12 hexadecimal digits)
1418 :``%h``: short-form changeset hash (12 hexadecimal digits)
1427 :``%r``: zero-padded changeset revision number
1419 :``%r``: zero-padded changeset revision number
1428 :``%b``: basename of the exporting repository
1420 :``%b``: basename of the exporting repository
1429
1421
1430 Returns 0 on success.
1422 Returns 0 on success.
1431 """
1423 """
1432 ctx = scmutil.revsingle(repo, opts.get('rev'))
1424 ctx = scmutil.revsingle(repo, opts.get('rev'))
1433 m = scmutil.match(ctx, (file1,) + pats, opts)
1425 m = scmutil.match(ctx, (file1,) + pats, opts)
1434
1426
1435 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1427 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1436
1428
1437 @command('^clone',
1429 @command('^clone',
1438 [('U', 'noupdate', None, _('the clone will include an empty working '
1430 [('U', 'noupdate', None, _('the clone will include an empty working '
1439 'directory (only a repository)')),
1431 'directory (only a repository)')),
1440 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1432 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1441 _('REV')),
1433 _('REV')),
1442 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1434 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1443 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1435 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1444 ('', 'pull', None, _('use pull protocol to copy metadata')),
1436 ('', 'pull', None, _('use pull protocol to copy metadata')),
1445 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1437 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1446 ] + remoteopts,
1438 ] + remoteopts,
1447 _('[OPTION]... SOURCE [DEST]'),
1439 _('[OPTION]... SOURCE [DEST]'),
1448 norepo=True)
1440 norepo=True)
1449 def clone(ui, source, dest=None, **opts):
1441 def clone(ui, source, dest=None, **opts):
1450 """make a copy of an existing repository
1442 """make a copy of an existing repository
1451
1443
1452 Create a copy of an existing repository in a new directory.
1444 Create a copy of an existing repository in a new directory.
1453
1445
1454 If no destination directory name is specified, it defaults to the
1446 If no destination directory name is specified, it defaults to the
1455 basename of the source.
1447 basename of the source.
1456
1448
1457 The location of the source is added to the new repository's
1449 The location of the source is added to the new repository's
1458 ``.hg/hgrc`` file, as the default to be used for future pulls.
1450 ``.hg/hgrc`` file, as the default to be used for future pulls.
1459
1451
1460 Only local paths and ``ssh://`` URLs are supported as
1452 Only local paths and ``ssh://`` URLs are supported as
1461 destinations. For ``ssh://`` destinations, no working directory or
1453 destinations. For ``ssh://`` destinations, no working directory or
1462 ``.hg/hgrc`` will be created on the remote side.
1454 ``.hg/hgrc`` will be created on the remote side.
1463
1455
1464 If the source repository has a bookmark called '@' set, that
1456 If the source repository has a bookmark called '@' set, that
1465 revision will be checked out in the new repository by default.
1457 revision will be checked out in the new repository by default.
1466
1458
1467 To check out a particular version, use -u/--update, or
1459 To check out a particular version, use -u/--update, or
1468 -U/--noupdate to create a clone with no working directory.
1460 -U/--noupdate to create a clone with no working directory.
1469
1461
1470 To pull only a subset of changesets, specify one or more revisions
1462 To pull only a subset of changesets, specify one or more revisions
1471 identifiers with -r/--rev or branches with -b/--branch. The
1463 identifiers with -r/--rev or branches with -b/--branch. The
1472 resulting clone will contain only the specified changesets and
1464 resulting clone will contain only the specified changesets and
1473 their ancestors. These options (or 'clone src#rev dest') imply
1465 their ancestors. These options (or 'clone src#rev dest') imply
1474 --pull, even for local source repositories.
1466 --pull, even for local source repositories.
1475
1467
1476 .. note::
1468 .. note::
1477
1469
1478 Specifying a tag will include the tagged changeset but not the
1470 Specifying a tag will include the tagged changeset but not the
1479 changeset containing the tag.
1471 changeset containing the tag.
1480
1472
1481 .. container:: verbose
1473 .. container:: verbose
1482
1474
1483 For efficiency, hardlinks are used for cloning whenever the
1475 For efficiency, hardlinks are used for cloning whenever the
1484 source and destination are on the same filesystem (note this
1476 source and destination are on the same filesystem (note this
1485 applies only to the repository data, not to the working
1477 applies only to the repository data, not to the working
1486 directory). Some filesystems, such as AFS, implement hardlinking
1478 directory). Some filesystems, such as AFS, implement hardlinking
1487 incorrectly, but do not report errors. In these cases, use the
1479 incorrectly, but do not report errors. In these cases, use the
1488 --pull option to avoid hardlinking.
1480 --pull option to avoid hardlinking.
1489
1481
1490 In some cases, you can clone repositories and the working
1482 In some cases, you can clone repositories and the working
1491 directory using full hardlinks with ::
1483 directory using full hardlinks with ::
1492
1484
1493 $ cp -al REPO REPOCLONE
1485 $ cp -al REPO REPOCLONE
1494
1486
1495 This is the fastest way to clone, but it is not always safe. The
1487 This is the fastest way to clone, but it is not always safe. The
1496 operation is not atomic (making sure REPO is not modified during
1488 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
1489 the operation is up to you) and you have to make sure your
1498 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1490 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1499 so). Also, this is not compatible with certain extensions that
1491 so). Also, this is not compatible with certain extensions that
1500 place their metadata under the .hg directory, such as mq.
1492 place their metadata under the .hg directory, such as mq.
1501
1493
1502 Mercurial will update the working directory to the first applicable
1494 Mercurial will update the working directory to the first applicable
1503 revision from this list:
1495 revision from this list:
1504
1496
1505 a) null if -U or the source repository has no changesets
1497 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
1498 b) if -u . and the source repository is local, the first parent of
1507 the source repository's working directory
1499 the source repository's working directory
1508 c) the changeset specified with -u (if a branch name, this means the
1500 c) the changeset specified with -u (if a branch name, this means the
1509 latest head of that branch)
1501 latest head of that branch)
1510 d) the changeset specified with -r
1502 d) the changeset specified with -r
1511 e) the tipmost head specified with -b
1503 e) the tipmost head specified with -b
1512 f) the tipmost head specified with the url#branch source syntax
1504 f) the tipmost head specified with the url#branch source syntax
1513 g) the revision marked with the '@' bookmark, if present
1505 g) the revision marked with the '@' bookmark, if present
1514 h) the tipmost head of the default branch
1506 h) the tipmost head of the default branch
1515 i) tip
1507 i) tip
1516
1508
1517 When cloning from servers that support it, Mercurial may fetch
1509 When cloning from servers that support it, Mercurial may fetch
1518 pre-generated data from a server-advertised URL. When this is done,
1510 pre-generated data from a server-advertised URL. When this is done,
1519 hooks operating on incoming changesets and changegroups may fire twice,
1511 hooks operating on incoming changesets and changegroups may fire twice,
1520 once for the bundle fetched from the URL and another for any additional
1512 once for the bundle fetched from the URL and another for any additional
1521 data not fetched from this URL. In addition, if an error occurs, the
1513 data not fetched from this URL. In addition, if an error occurs, the
1522 repository may be rolled back to a partial clone. This behavior may
1514 repository may be rolled back to a partial clone. This behavior may
1523 change in future releases. See :hg:`help -e clonebundles` for more.
1515 change in future releases. See :hg:`help -e clonebundles` for more.
1524
1516
1525 Examples:
1517 Examples:
1526
1518
1527 - clone a remote repository to a new directory named hg/::
1519 - clone a remote repository to a new directory named hg/::
1528
1520
1529 hg clone http://selenic.com/hg
1521 hg clone http://selenic.com/hg
1530
1522
1531 - create a lightweight local clone::
1523 - create a lightweight local clone::
1532
1524
1533 hg clone project/ project-feature/
1525 hg clone project/ project-feature/
1534
1526
1535 - clone from an absolute path on an ssh server (note double-slash)::
1527 - clone from an absolute path on an ssh server (note double-slash)::
1536
1528
1537 hg clone ssh://user@server//home/projects/alpha/
1529 hg clone ssh://user@server//home/projects/alpha/
1538
1530
1539 - do a high-speed clone over a LAN while checking out a
1531 - do a high-speed clone over a LAN while checking out a
1540 specified version::
1532 specified version::
1541
1533
1542 hg clone --uncompressed http://server/repo -u 1.5
1534 hg clone --uncompressed http://server/repo -u 1.5
1543
1535
1544 - create a repository without changesets after a particular revision::
1536 - create a repository without changesets after a particular revision::
1545
1537
1546 hg clone -r 04e544 experimental/ good/
1538 hg clone -r 04e544 experimental/ good/
1547
1539
1548 - clone (and track) a particular named branch::
1540 - clone (and track) a particular named branch::
1549
1541
1550 hg clone http://selenic.com/hg#stable
1542 hg clone http://selenic.com/hg#stable
1551
1543
1552 See :hg:`help urls` for details on specifying URLs.
1544 See :hg:`help urls` for details on specifying URLs.
1553
1545
1554 Returns 0 on success.
1546 Returns 0 on success.
1555 """
1547 """
1556 if opts.get('noupdate') and opts.get('updaterev'):
1548 if opts.get('noupdate') and opts.get('updaterev'):
1557 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1558
1550
1559 r = hg.clone(ui, opts, source, dest,
1551 r = hg.clone(ui, opts, source, dest,
1560 pull=opts.get('pull'),
1552 pull=opts.get('pull'),
1561 stream=opts.get('uncompressed'),
1553 stream=opts.get('uncompressed'),
1562 rev=opts.get('rev'),
1554 rev=opts.get('rev'),
1563 update=opts.get('updaterev') or not opts.get('noupdate'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1564 branch=opts.get('branch'),
1556 branch=opts.get('branch'),
1565 shareopts=opts.get('shareopts'))
1557 shareopts=opts.get('shareopts'))
1566
1558
1567 return r is None
1559 return r is None
1568
1560
1569 @command('^commit|ci',
1561 @command('^commit|ci',
1570 [('A', 'addremove', None,
1562 [('A', 'addremove', None,
1571 _('mark new/missing files as added/removed before committing')),
1563 _('mark new/missing files as added/removed before committing')),
1572 ('', 'close-branch', None,
1564 ('', 'close-branch', None,
1573 _('mark a branch head as closed')),
1565 _('mark a branch head as closed')),
1574 ('', 'amend', None, _('amend the parent of the working directory')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1575 ('s', 'secret', None, _('use the secret phase for committing')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1576 ('e', 'edit', None, _('invoke editor on commit messages')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1577 ('i', 'interactive', None, _('use interactive mode')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1578 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1579 _('[OPTION]... [FILE]...'),
1571 _('[OPTION]... [FILE]...'),
1580 inferrepo=True)
1572 inferrepo=True)
1581 def commit(ui, repo, *pats, **opts):
1573 def commit(ui, repo, *pats, **opts):
1582 """commit the specified files or all outstanding changes
1574 """commit the specified files or all outstanding changes
1583
1575
1584 Commit changes to the given files into the repository. Unlike a
1576 Commit changes to the given files into the repository. Unlike a
1585 centralized SCM, this operation is a local operation. See
1577 centralized SCM, this operation is a local operation. See
1586 :hg:`push` for a way to actively distribute your changes.
1578 :hg:`push` for a way to actively distribute your changes.
1587
1579
1588 If a list of files is omitted, all changes reported by :hg:`status`
1580 If a list of files is omitted, all changes reported by :hg:`status`
1589 will be committed.
1581 will be committed.
1590
1582
1591 If you are committing the result of a merge, do not provide any
1583 If you are committing the result of a merge, do not provide any
1592 filenames or -I/-X filters.
1584 filenames or -I/-X filters.
1593
1585
1594 If no commit message is specified, Mercurial starts your
1586 If no commit message is specified, Mercurial starts your
1595 configured editor where you can enter a message. In case your
1587 configured editor where you can enter a message. In case your
1596 commit fails, you will find a backup of your message in
1588 commit fails, you will find a backup of your message in
1597 ``.hg/last-message.txt``.
1589 ``.hg/last-message.txt``.
1598
1590
1599 The --close-branch flag can be used to mark the current branch
1591 The --close-branch flag can be used to mark the current branch
1600 head closed. When all heads of a branch are closed, the branch
1592 head closed. When all heads of a branch are closed, the branch
1601 will be considered closed and no longer listed.
1593 will be considered closed and no longer listed.
1602
1594
1603 The --amend flag can be used to amend the parent of the
1595 The --amend flag can be used to amend the parent of the
1604 working directory with a new commit that contains the changes
1596 working directory with a new commit that contains the changes
1605 in the parent in addition to those currently reported by :hg:`status`,
1597 in the parent in addition to those currently reported by :hg:`status`,
1606 if there are any. The old commit is stored in a backup bundle in
1598 if there are any. The old commit is stored in a backup bundle in
1607 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1599 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1608 on how to restore it).
1600 on how to restore it).
1609
1601
1610 Message, user and date are taken from the amended commit unless
1602 Message, user and date are taken from the amended commit unless
1611 specified. When a message isn't specified on the command line,
1603 specified. When a message isn't specified on the command line,
1612 the editor will open with the message of the amended commit.
1604 the editor will open with the message of the amended commit.
1613
1605
1614 It is not possible to amend public changesets (see :hg:`help phases`)
1606 It is not possible to amend public changesets (see :hg:`help phases`)
1615 or changesets that have children.
1607 or changesets that have children.
1616
1608
1617 See :hg:`help dates` for a list of formats valid for -d/--date.
1609 See :hg:`help dates` for a list of formats valid for -d/--date.
1618
1610
1619 Returns 0 on success, 1 if nothing changed.
1611 Returns 0 on success, 1 if nothing changed.
1620
1612
1621 .. container:: verbose
1613 .. container:: verbose
1622
1614
1623 Examples:
1615 Examples:
1624
1616
1625 - commit all files ending in .py::
1617 - commit all files ending in .py::
1626
1618
1627 hg commit --include "set:**.py"
1619 hg commit --include "set:**.py"
1628
1620
1629 - commit all non-binary files::
1621 - commit all non-binary files::
1630
1622
1631 hg commit --exclude "set:binary()"
1623 hg commit --exclude "set:binary()"
1632
1624
1633 - amend the current commit and set the date to now::
1625 - amend the current commit and set the date to now::
1634
1626
1635 hg commit --amend --date now
1627 hg commit --amend --date now
1636 """
1628 """
1637 wlock = lock = None
1629 wlock = lock = None
1638 try:
1630 try:
1639 wlock = repo.wlock()
1631 wlock = repo.wlock()
1640 lock = repo.lock()
1632 lock = repo.lock()
1641 return _docommit(ui, repo, *pats, **opts)
1633 return _docommit(ui, repo, *pats, **opts)
1642 finally:
1634 finally:
1643 release(lock, wlock)
1635 release(lock, wlock)
1644
1636
1645 def _docommit(ui, repo, *pats, **opts):
1637 def _docommit(ui, repo, *pats, **opts):
1646 if opts.get('interactive'):
1638 if opts.get('interactive'):
1647 opts.pop('interactive')
1639 opts.pop('interactive')
1648 cmdutil.dorecord(ui, repo, commit, None, False,
1640 cmdutil.dorecord(ui, repo, commit, None, False,
1649 cmdutil.recordfilter, *pats, **opts)
1641 cmdutil.recordfilter, *pats, **opts)
1650 return
1642 return
1651
1643
1652 if opts.get('subrepos'):
1644 if opts.get('subrepos'):
1653 if opts.get('amend'):
1645 if opts.get('amend'):
1654 raise error.Abort(_('cannot amend with --subrepos'))
1646 raise error.Abort(_('cannot amend with --subrepos'))
1655 # Let --subrepos on the command line override config setting.
1647 # Let --subrepos on the command line override config setting.
1656 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1657
1649
1658 cmdutil.checkunfinished(repo, commit=True)
1650 cmdutil.checkunfinished(repo, commit=True)
1659
1651
1660 branch = repo[None].branch()
1652 branch = repo[None].branch()
1661 bheads = repo.branchheads(branch)
1653 bheads = repo.branchheads(branch)
1662
1654
1663 extra = {}
1655 extra = {}
1664 if opts.get('close_branch'):
1656 if opts.get('close_branch'):
1665 extra['close'] = 1
1657 extra['close'] = 1
1666
1658
1667 if not bheads:
1659 if not bheads:
1668 raise error.Abort(_('can only close branch heads'))
1660 raise error.Abort(_('can only close branch heads'))
1669 elif opts.get('amend'):
1661 elif opts.get('amend'):
1670 if repo[None].parents()[0].p1().branch() != branch and \
1662 if repo[None].parents()[0].p1().branch() != branch and \
1671 repo[None].parents()[0].p2().branch() != branch:
1663 repo[None].parents()[0].p2().branch() != branch:
1672 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1673
1665
1674 if opts.get('amend'):
1666 if opts.get('amend'):
1675 if ui.configbool('ui', 'commitsubrepos'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1676 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1677
1669
1678 old = repo['.']
1670 old = repo['.']
1679 if not old.mutable():
1671 if not old.mutable():
1680 raise error.Abort(_('cannot amend public changesets'))
1672 raise error.Abort(_('cannot amend public changesets'))
1681 if len(repo[None].parents()) > 1:
1673 if len(repo[None].parents()) > 1:
1682 raise error.Abort(_('cannot amend while merging'))
1674 raise error.Abort(_('cannot amend while merging'))
1683 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1675 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1684 if not allowunstable and old.children():
1676 if not allowunstable and old.children():
1685 raise error.Abort(_('cannot amend changeset with children'))
1677 raise error.Abort(_('cannot amend changeset with children'))
1686
1678
1687 # Currently histedit gets confused if an amend happens while histedit
1679 # Currently histedit gets confused if an amend happens while histedit
1688 # is in progress. Since we have a checkunfinished command, we are
1680 # is in progress. Since we have a checkunfinished command, we are
1689 # temporarily honoring it.
1681 # temporarily honoring it.
1690 #
1682 #
1691 # Note: eventually this guard will be removed. Please do not expect
1683 # Note: eventually this guard will be removed. Please do not expect
1692 # this behavior to remain.
1684 # this behavior to remain.
1693 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1685 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1694 cmdutil.checkunfinished(repo)
1686 cmdutil.checkunfinished(repo)
1695
1687
1696 # commitfunc is used only for temporary amend commit by cmdutil.amend
1688 # commitfunc is used only for temporary amend commit by cmdutil.amend
1697 def commitfunc(ui, repo, message, match, opts):
1689 def commitfunc(ui, repo, message, match, opts):
1698 return repo.commit(message,
1690 return repo.commit(message,
1699 opts.get('user') or old.user(),
1691 opts.get('user') or old.user(),
1700 opts.get('date') or old.date(),
1692 opts.get('date') or old.date(),
1701 match,
1693 match,
1702 extra=extra)
1694 extra=extra)
1703
1695
1704 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1696 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1705 if node == old.node():
1697 if node == old.node():
1706 ui.status(_("nothing changed\n"))
1698 ui.status(_("nothing changed\n"))
1707 return 1
1699 return 1
1708 else:
1700 else:
1709 def commitfunc(ui, repo, message, match, opts):
1701 def commitfunc(ui, repo, message, match, opts):
1710 backup = ui.backupconfig('phases', 'new-commit')
1702 backup = ui.backupconfig('phases', 'new-commit')
1711 baseui = repo.baseui
1703 baseui = repo.baseui
1712 basebackup = baseui.backupconfig('phases', 'new-commit')
1704 basebackup = baseui.backupconfig('phases', 'new-commit')
1713 try:
1705 try:
1714 if opts.get('secret'):
1706 if opts.get('secret'):
1715 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1707 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1716 # Propagate to subrepos
1708 # Propagate to subrepos
1717 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1709 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1718
1710
1719 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1711 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1720 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1712 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1721 return repo.commit(message, opts.get('user'), opts.get('date'),
1713 return repo.commit(message, opts.get('user'), opts.get('date'),
1722 match,
1714 match,
1723 editor=editor,
1715 editor=editor,
1724 extra=extra)
1716 extra=extra)
1725 finally:
1717 finally:
1726 ui.restoreconfig(backup)
1718 ui.restoreconfig(backup)
1727 repo.baseui.restoreconfig(basebackup)
1719 repo.baseui.restoreconfig(basebackup)
1728
1720
1729
1721
1730 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1722 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1731
1723
1732 if not node:
1724 if not node:
1733 stat = cmdutil.postcommitstatus(repo, pats, opts)
1725 stat = cmdutil.postcommitstatus(repo, pats, opts)
1734 if stat[3]:
1726 if stat[3]:
1735 ui.status(_("nothing changed (%d missing files, see "
1727 ui.status(_("nothing changed (%d missing files, see "
1736 "'hg status')\n") % len(stat[3]))
1728 "'hg status')\n") % len(stat[3]))
1737 else:
1729 else:
1738 ui.status(_("nothing changed\n"))
1730 ui.status(_("nothing changed\n"))
1739 return 1
1731 return 1
1740
1732
1741 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1733 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1742
1734
1743 @command('config|showconfig|debugconfig',
1735 @command('config|showconfig|debugconfig',
1744 [('u', 'untrusted', None, _('show untrusted configuration options')),
1736 [('u', 'untrusted', None, _('show untrusted configuration options')),
1745 ('e', 'edit', None, _('edit user config')),
1737 ('e', 'edit', None, _('edit user config')),
1746 ('l', 'local', None, _('edit repository config')),
1738 ('l', 'local', None, _('edit repository config')),
1747 ('g', 'global', None, _('edit global config'))] + formatteropts,
1739 ('g', 'global', None, _('edit global config'))] + formatteropts,
1748 _('[-u] [NAME]...'),
1740 _('[-u] [NAME]...'),
1749 optionalrepo=True)
1741 optionalrepo=True)
1750 def config(ui, repo, *values, **opts):
1742 def config(ui, repo, *values, **opts):
1751 """show combined config settings from all hgrc files
1743 """show combined config settings from all hgrc files
1752
1744
1753 With no arguments, print names and values of all config items.
1745 With no arguments, print names and values of all config items.
1754
1746
1755 With one argument of the form section.name, print just the value
1747 With one argument of the form section.name, print just the value
1756 of that config item.
1748 of that config item.
1757
1749
1758 With multiple arguments, print names and values of all config
1750 With multiple arguments, print names and values of all config
1759 items with matching section names.
1751 items with matching section names.
1760
1752
1761 With --edit, start an editor on the user-level config file. With
1753 With --edit, start an editor on the user-level config file. With
1762 --global, edit the system-wide config file. With --local, edit the
1754 --global, edit the system-wide config file. With --local, edit the
1763 repository-level config file.
1755 repository-level config file.
1764
1756
1765 With --debug, the source (filename and line number) is printed
1757 With --debug, the source (filename and line number) is printed
1766 for each config item.
1758 for each config item.
1767
1759
1768 See :hg:`help config` for more information about config files.
1760 See :hg:`help config` for more information about config files.
1769
1761
1770 Returns 0 on success, 1 if NAME does not exist.
1762 Returns 0 on success, 1 if NAME does not exist.
1771
1763
1772 """
1764 """
1773
1765
1774 if opts.get('edit') or opts.get('local') or opts.get('global'):
1766 if opts.get('edit') or opts.get('local') or opts.get('global'):
1775 if opts.get('local') and opts.get('global'):
1767 if opts.get('local') and opts.get('global'):
1776 raise error.Abort(_("can't use --local and --global together"))
1768 raise error.Abort(_("can't use --local and --global together"))
1777
1769
1778 if opts.get('local'):
1770 if opts.get('local'):
1779 if not repo:
1771 if not repo:
1780 raise error.Abort(_("can't use --local outside a repository"))
1772 raise error.Abort(_("can't use --local outside a repository"))
1781 paths = [repo.join('hgrc')]
1773 paths = [repo.join('hgrc')]
1782 elif opts.get('global'):
1774 elif opts.get('global'):
1783 paths = scmutil.systemrcpath()
1775 paths = scmutil.systemrcpath()
1784 else:
1776 else:
1785 paths = scmutil.userrcpath()
1777 paths = scmutil.userrcpath()
1786
1778
1787 for f in paths:
1779 for f in paths:
1788 if os.path.exists(f):
1780 if os.path.exists(f):
1789 break
1781 break
1790 else:
1782 else:
1791 if opts.get('global'):
1783 if opts.get('global'):
1792 samplehgrc = uimod.samplehgrcs['global']
1784 samplehgrc = uimod.samplehgrcs['global']
1793 elif opts.get('local'):
1785 elif opts.get('local'):
1794 samplehgrc = uimod.samplehgrcs['local']
1786 samplehgrc = uimod.samplehgrcs['local']
1795 else:
1787 else:
1796 samplehgrc = uimod.samplehgrcs['user']
1788 samplehgrc = uimod.samplehgrcs['user']
1797
1789
1798 f = paths[0]
1790 f = paths[0]
1799 fp = open(f, "w")
1791 fp = open(f, "w")
1800 fp.write(samplehgrc)
1792 fp.write(samplehgrc)
1801 fp.close()
1793 fp.close()
1802
1794
1803 editor = ui.geteditor()
1795 editor = ui.geteditor()
1804 ui.system("%s \"%s\"" % (editor, f),
1796 ui.system("%s \"%s\"" % (editor, f),
1805 onerr=error.Abort, errprefix=_("edit failed"))
1797 onerr=error.Abort, errprefix=_("edit failed"))
1806 return
1798 return
1807
1799
1808 fm = ui.formatter('config', opts)
1800 fm = ui.formatter('config', opts)
1809 for f in scmutil.rcpath():
1801 for f in scmutil.rcpath():
1810 ui.debug('read config from: %s\n' % f)
1802 ui.debug('read config from: %s\n' % f)
1811 untrusted = bool(opts.get('untrusted'))
1803 untrusted = bool(opts.get('untrusted'))
1812 if values:
1804 if values:
1813 sections = [v for v in values if '.' not in v]
1805 sections = [v for v in values if '.' not in v]
1814 items = [v for v in values if '.' in v]
1806 items = [v for v in values if '.' in v]
1815 if len(items) > 1 or items and sections:
1807 if len(items) > 1 or items and sections:
1816 raise error.Abort(_('only one config item permitted'))
1808 raise error.Abort(_('only one config item permitted'))
1817 matched = False
1809 matched = False
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1810 for section, name, value in ui.walkconfig(untrusted=untrusted):
1819 value = str(value)
1811 value = str(value)
1820 if fm.isplain():
1812 if fm.isplain():
1821 value = value.replace('\n', '\\n')
1813 value = value.replace('\n', '\\n')
1822 entryname = section + '.' + name
1814 entryname = section + '.' + name
1823 if values:
1815 if values:
1824 for v in values:
1816 for v in values:
1825 if v == section:
1817 if v == section:
1826 fm.startitem()
1818 fm.startitem()
1827 fm.condwrite(ui.debugflag, 'source', '%s: ',
1819 fm.condwrite(ui.debugflag, 'source', '%s: ',
1828 ui.configsource(section, name, untrusted))
1820 ui.configsource(section, name, untrusted))
1829 fm.write('name value', '%s=%s\n', entryname, value)
1821 fm.write('name value', '%s=%s\n', entryname, value)
1830 matched = True
1822 matched = True
1831 elif v == entryname:
1823 elif v == entryname:
1832 fm.startitem()
1824 fm.startitem()
1833 fm.condwrite(ui.debugflag, 'source', '%s: ',
1825 fm.condwrite(ui.debugflag, 'source', '%s: ',
1834 ui.configsource(section, name, untrusted))
1826 ui.configsource(section, name, untrusted))
1835 fm.write('value', '%s\n', value)
1827 fm.write('value', '%s\n', value)
1836 fm.data(name=entryname)
1828 fm.data(name=entryname)
1837 matched = True
1829 matched = True
1838 else:
1830 else:
1839 fm.startitem()
1831 fm.startitem()
1840 fm.condwrite(ui.debugflag, 'source', '%s: ',
1832 fm.condwrite(ui.debugflag, 'source', '%s: ',
1841 ui.configsource(section, name, untrusted))
1833 ui.configsource(section, name, untrusted))
1842 fm.write('name value', '%s=%s\n', entryname, value)
1834 fm.write('name value', '%s=%s\n', entryname, value)
1843 matched = True
1835 matched = True
1844 fm.end()
1836 fm.end()
1845 if matched:
1837 if matched:
1846 return 0
1838 return 0
1847 return 1
1839 return 1
1848
1840
1849 @command('copy|cp',
1841 @command('copy|cp',
1850 [('A', 'after', None, _('record a copy that has already occurred')),
1842 [('A', 'after', None, _('record a copy that has already occurred')),
1851 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1843 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1852 ] + walkopts + dryrunopts,
1844 ] + walkopts + dryrunopts,
1853 _('[OPTION]... [SOURCE]... DEST'))
1845 _('[OPTION]... [SOURCE]... DEST'))
1854 def copy(ui, repo, *pats, **opts):
1846 def copy(ui, repo, *pats, **opts):
1855 """mark files as copied for the next commit
1847 """mark files as copied for the next commit
1856
1848
1857 Mark dest as having copies of source files. If dest is a
1849 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,
1850 directory, copies are put in that directory. If dest is a file,
1859 the source must be a single file.
1851 the source must be a single file.
1860
1852
1861 By default, this command copies the contents of files as they
1853 By default, this command copies the contents of files as they
1862 exist in the working directory. If invoked with -A/--after, the
1854 exist in the working directory. If invoked with -A/--after, the
1863 operation is recorded, but no copying is performed.
1855 operation is recorded, but no copying is performed.
1864
1856
1865 This command takes effect with the next commit. To undo a copy
1857 This command takes effect with the next commit. To undo a copy
1866 before that, see :hg:`revert`.
1858 before that, see :hg:`revert`.
1867
1859
1868 Returns 0 on success, 1 if errors are encountered.
1860 Returns 0 on success, 1 if errors are encountered.
1869 """
1861 """
1870 with repo.wlock(False):
1862 with repo.wlock(False):
1871 return cmdutil.copy(ui, repo, pats, opts)
1863 return cmdutil.copy(ui, repo, pats, opts)
1872
1864
1873 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1865 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1874 def debugancestor(ui, repo, *args):
1866 def debugancestor(ui, repo, *args):
1875 """find the ancestor revision of two revisions in a given index"""
1867 """find the ancestor revision of two revisions in a given index"""
1876 if len(args) == 3:
1868 if len(args) == 3:
1877 index, rev1, rev2 = args
1869 index, rev1, rev2 = args
1878 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1870 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1879 lookup = r.lookup
1871 lookup = r.lookup
1880 elif len(args) == 2:
1872 elif len(args) == 2:
1881 if not repo:
1873 if not repo:
1882 raise error.Abort(_("there is no Mercurial repository here "
1874 raise error.Abort(_("there is no Mercurial repository here "
1883 "(.hg not found)"))
1875 "(.hg not found)"))
1884 rev1, rev2 = args
1876 rev1, rev2 = args
1885 r = repo.changelog
1877 r = repo.changelog
1886 lookup = repo.lookup
1878 lookup = repo.lookup
1887 else:
1879 else:
1888 raise error.Abort(_('either two or three arguments required'))
1880 raise error.Abort(_('either two or three arguments required'))
1889 a = r.ancestor(lookup(rev1), lookup(rev2))
1881 a = r.ancestor(lookup(rev1), lookup(rev2))
1890 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1882 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1891
1883
1892 @command('debugbuilddag',
1884 @command('debugbuilddag',
1893 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1885 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1894 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1886 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1895 ('n', 'new-file', None, _('add new file at each rev'))],
1887 ('n', 'new-file', None, _('add new file at each rev'))],
1896 _('[OPTION]... [TEXT]'))
1888 _('[OPTION]... [TEXT]'))
1897 def debugbuilddag(ui, repo, text=None,
1889 def debugbuilddag(ui, repo, text=None,
1898 mergeable_file=False,
1890 mergeable_file=False,
1899 overwritten_file=False,
1891 overwritten_file=False,
1900 new_file=False):
1892 new_file=False):
1901 """builds a repo with a given DAG from scratch in the current empty repo
1893 """builds a repo with a given DAG from scratch in the current empty repo
1902
1894
1903 The description of the DAG is read from stdin if not given on the
1895 The description of the DAG is read from stdin if not given on the
1904 command line.
1896 command line.
1905
1897
1906 Elements:
1898 Elements:
1907
1899
1908 - "+n" is a linear run of n nodes based on the current default parent
1900 - "+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
1901 - "." is a single node based on the current default parent
1910 - "$" resets the default parent to null (implied at the start);
1902 - "$" resets the default parent to null (implied at the start);
1911 otherwise the default parent is always the last node created
1903 otherwise the default parent is always the last node created
1912 - "<p" sets the default parent to the backref p
1904 - "<p" sets the default parent to the backref p
1913 - "*p" is a fork at parent p, which is a backref
1905 - "*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
1906 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1915 - "/p2" is a merge of the preceding node and p2
1907 - "/p2" is a merge of the preceding node and p2
1916 - ":tag" defines a local tag for the preceding node
1908 - ":tag" defines a local tag for the preceding node
1917 - "@branch" sets the named branch for subsequent nodes
1909 - "@branch" sets the named branch for subsequent nodes
1918 - "#...\\n" is a comment up to the end of the line
1910 - "#...\\n" is a comment up to the end of the line
1919
1911
1920 Whitespace between the above elements is ignored.
1912 Whitespace between the above elements is ignored.
1921
1913
1922 A backref is either
1914 A backref is either
1923
1915
1924 - a number n, which references the node curr-n, where curr is the current
1916 - a number n, which references the node curr-n, where curr is the current
1925 node, or
1917 node, or
1926 - the name of a local tag you placed earlier using ":tag", or
1918 - the name of a local tag you placed earlier using ":tag", or
1927 - empty to denote the default parent.
1919 - empty to denote the default parent.
1928
1920
1929 All string valued-elements are either strictly alphanumeric, or must
1921 All string valued-elements are either strictly alphanumeric, or must
1930 be enclosed in double quotes ("..."), with "\\" as escape character.
1922 be enclosed in double quotes ("..."), with "\\" as escape character.
1931 """
1923 """
1932
1924
1933 if text is None:
1925 if text is None:
1934 ui.status(_("reading DAG from stdin\n"))
1926 ui.status(_("reading DAG from stdin\n"))
1935 text = ui.fin.read()
1927 text = ui.fin.read()
1936
1928
1937 cl = repo.changelog
1929 cl = repo.changelog
1938 if len(cl) > 0:
1930 if len(cl) > 0:
1939 raise error.Abort(_('repository is not empty'))
1931 raise error.Abort(_('repository is not empty'))
1940
1932
1941 # determine number of revs in DAG
1933 # determine number of revs in DAG
1942 total = 0
1934 total = 0
1943 for type, data in dagparser.parsedag(text):
1935 for type, data in dagparser.parsedag(text):
1944 if type == 'n':
1936 if type == 'n':
1945 total += 1
1937 total += 1
1946
1938
1947 if mergeable_file:
1939 if mergeable_file:
1948 linesperrev = 2
1940 linesperrev = 2
1949 # make a file with k lines per rev
1941 # make a file with k lines per rev
1950 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1942 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1951 initialmergedlines.append("")
1943 initialmergedlines.append("")
1952
1944
1953 tags = []
1945 tags = []
1954
1946
1955 wlock = lock = tr = None
1947 wlock = lock = tr = None
1956 try:
1948 try:
1957 wlock = repo.wlock()
1949 wlock = repo.wlock()
1958 lock = repo.lock()
1950 lock = repo.lock()
1959 tr = repo.transaction("builddag")
1951 tr = repo.transaction("builddag")
1960
1952
1961 at = -1
1953 at = -1
1962 atbranch = 'default'
1954 atbranch = 'default'
1963 nodeids = []
1955 nodeids = []
1964 id = 0
1956 id = 0
1965 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1957 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1966 for type, data in dagparser.parsedag(text):
1958 for type, data in dagparser.parsedag(text):
1967 if type == 'n':
1959 if type == 'n':
1968 ui.note(('node %s\n' % str(data)))
1960 ui.note(('node %s\n' % str(data)))
1969 id, ps = data
1961 id, ps = data
1970
1962
1971 files = []
1963 files = []
1972 fctxs = {}
1964 fctxs = {}
1973
1965
1974 p2 = None
1966 p2 = None
1975 if mergeable_file:
1967 if mergeable_file:
1976 fn = "mf"
1968 fn = "mf"
1977 p1 = repo[ps[0]]
1969 p1 = repo[ps[0]]
1978 if len(ps) > 1:
1970 if len(ps) > 1:
1979 p2 = repo[ps[1]]
1971 p2 = repo[ps[1]]
1980 pa = p1.ancestor(p2)
1972 pa = p1.ancestor(p2)
1981 base, local, other = [x[fn].data() for x in (pa, p1,
1973 base, local, other = [x[fn].data() for x in (pa, p1,
1982 p2)]
1974 p2)]
1983 m3 = simplemerge.Merge3Text(base, local, other)
1975 m3 = simplemerge.Merge3Text(base, local, other)
1984 ml = [l.strip() for l in m3.merge_lines()]
1976 ml = [l.strip() for l in m3.merge_lines()]
1985 ml.append("")
1977 ml.append("")
1986 elif at > 0:
1978 elif at > 0:
1987 ml = p1[fn].data().split("\n")
1979 ml = p1[fn].data().split("\n")
1988 else:
1980 else:
1989 ml = initialmergedlines
1981 ml = initialmergedlines
1990 ml[id * linesperrev] += " r%i" % id
1982 ml[id * linesperrev] += " r%i" % id
1991 mergedtext = "\n".join(ml)
1983 mergedtext = "\n".join(ml)
1992 files.append(fn)
1984 files.append(fn)
1993 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1985 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1994
1986
1995 if overwritten_file:
1987 if overwritten_file:
1996 fn = "of"
1988 fn = "of"
1997 files.append(fn)
1989 files.append(fn)
1998 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1990 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1999
1991
2000 if new_file:
1992 if new_file:
2001 fn = "nf%i" % id
1993 fn = "nf%i" % id
2002 files.append(fn)
1994 files.append(fn)
2003 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1995 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2004 if len(ps) > 1:
1996 if len(ps) > 1:
2005 if not p2:
1997 if not p2:
2006 p2 = repo[ps[1]]
1998 p2 = repo[ps[1]]
2007 for fn in p2:
1999 for fn in p2:
2008 if fn.startswith("nf"):
2000 if fn.startswith("nf"):
2009 files.append(fn)
2001 files.append(fn)
2010 fctxs[fn] = p2[fn]
2002 fctxs[fn] = p2[fn]
2011
2003
2012 def fctxfn(repo, cx, path):
2004 def fctxfn(repo, cx, path):
2013 return fctxs.get(path)
2005 return fctxs.get(path)
2014
2006
2015 if len(ps) == 0 or ps[0] < 0:
2007 if len(ps) == 0 or ps[0] < 0:
2016 pars = [None, None]
2008 pars = [None, None]
2017 elif len(ps) == 1:
2009 elif len(ps) == 1:
2018 pars = [nodeids[ps[0]], None]
2010 pars = [nodeids[ps[0]], None]
2019 else:
2011 else:
2020 pars = [nodeids[p] for p in ps]
2012 pars = [nodeids[p] for p in ps]
2021 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2013 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2022 date=(id, 0),
2014 date=(id, 0),
2023 user="debugbuilddag",
2015 user="debugbuilddag",
2024 extra={'branch': atbranch})
2016 extra={'branch': atbranch})
2025 nodeid = repo.commitctx(cx)
2017 nodeid = repo.commitctx(cx)
2026 nodeids.append(nodeid)
2018 nodeids.append(nodeid)
2027 at = id
2019 at = id
2028 elif type == 'l':
2020 elif type == 'l':
2029 id, name = data
2021 id, name = data
2030 ui.note(('tag %s\n' % name))
2022 ui.note(('tag %s\n' % name))
2031 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2023 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2032 elif type == 'a':
2024 elif type == 'a':
2033 ui.note(('branch %s\n' % data))
2025 ui.note(('branch %s\n' % data))
2034 atbranch = data
2026 atbranch = data
2035 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2027 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2036 tr.close()
2028 tr.close()
2037
2029
2038 if tags:
2030 if tags:
2039 repo.vfs.write("localtags", "".join(tags))
2031 repo.vfs.write("localtags", "".join(tags))
2040 finally:
2032 finally:
2041 ui.progress(_('building'), None)
2033 ui.progress(_('building'), None)
2042 release(tr, lock, wlock)
2034 release(tr, lock, wlock)
2043
2035
2044 @command('debugbundle',
2036 @command('debugbundle',
2045 [('a', 'all', None, _('show all details')),
2037 [('a', 'all', None, _('show all details')),
2046 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2038 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2047 _('FILE'),
2039 _('FILE'),
2048 norepo=True)
2040 norepo=True)
2049 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2041 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2050 """lists the contents of a bundle"""
2042 """lists the contents of a bundle"""
2051 with hg.openpath(ui, bundlepath) as f:
2043 with hg.openpath(ui, bundlepath) as f:
2052 if spec:
2044 if spec:
2053 spec = exchange.getbundlespec(ui, f)
2045 spec = exchange.getbundlespec(ui, f)
2054 ui.write('%s\n' % spec)
2046 ui.write('%s\n' % spec)
2055 return
2047 return
2056
2048
2057 gen = exchange.readbundle(ui, f, bundlepath)
2049 gen = exchange.readbundle(ui, f, bundlepath)
2058 if isinstance(gen, bundle2.unbundle20):
2050 if isinstance(gen, bundle2.unbundle20):
2059 return _debugbundle2(ui, gen, all=all, **opts)
2051 return _debugbundle2(ui, gen, all=all, **opts)
2060 _debugchangegroup(ui, gen, all=all, **opts)
2052 _debugchangegroup(ui, gen, all=all, **opts)
2061
2053
2062 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2054 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2063 indent_string = ' ' * indent
2055 indent_string = ' ' * indent
2064 if all:
2056 if all:
2065 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2057 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2066 % indent_string)
2058 % indent_string)
2067
2059
2068 def showchunks(named):
2060 def showchunks(named):
2069 ui.write("\n%s%s\n" % (indent_string, named))
2061 ui.write("\n%s%s\n" % (indent_string, named))
2070 chain = None
2062 chain = None
2071 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2063 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2072 node = chunkdata['node']
2064 node = chunkdata['node']
2073 p1 = chunkdata['p1']
2065 p1 = chunkdata['p1']
2074 p2 = chunkdata['p2']
2066 p2 = chunkdata['p2']
2075 cs = chunkdata['cs']
2067 cs = chunkdata['cs']
2076 deltabase = chunkdata['deltabase']
2068 deltabase = chunkdata['deltabase']
2077 delta = chunkdata['delta']
2069 delta = chunkdata['delta']
2078 ui.write("%s%s %s %s %s %s %s\n" %
2070 ui.write("%s%s %s %s %s %s %s\n" %
2079 (indent_string, hex(node), hex(p1), hex(p2),
2071 (indent_string, hex(node), hex(p1), hex(p2),
2080 hex(cs), hex(deltabase), len(delta)))
2072 hex(cs), hex(deltabase), len(delta)))
2081 chain = node
2073 chain = node
2082
2074
2083 chunkdata = gen.changelogheader()
2075 chunkdata = gen.changelogheader()
2084 showchunks("changelog")
2076 showchunks("changelog")
2085 chunkdata = gen.manifestheader()
2077 chunkdata = gen.manifestheader()
2086 showchunks("manifest")
2078 showchunks("manifest")
2087 for chunkdata in iter(gen.filelogheader, {}):
2079 for chunkdata in iter(gen.filelogheader, {}):
2088 fname = chunkdata['filename']
2080 fname = chunkdata['filename']
2089 showchunks(fname)
2081 showchunks(fname)
2090 else:
2082 else:
2091 if isinstance(gen, bundle2.unbundle20):
2083 if isinstance(gen, bundle2.unbundle20):
2092 raise error.Abort(_('use debugbundle2 for this file'))
2084 raise error.Abort(_('use debugbundle2 for this file'))
2093 chunkdata = gen.changelogheader()
2085 chunkdata = gen.changelogheader()
2094 chain = None
2086 chain = None
2095 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2087 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2096 node = chunkdata['node']
2088 node = chunkdata['node']
2097 ui.write("%s%s\n" % (indent_string, hex(node)))
2089 ui.write("%s%s\n" % (indent_string, hex(node)))
2098 chain = node
2090 chain = node
2099
2091
2100 def _debugbundle2(ui, gen, all=None, **opts):
2092 def _debugbundle2(ui, gen, all=None, **opts):
2101 """lists the contents of a bundle2"""
2093 """lists the contents of a bundle2"""
2102 if not isinstance(gen, bundle2.unbundle20):
2094 if not isinstance(gen, bundle2.unbundle20):
2103 raise error.Abort(_('not a bundle2 file'))
2095 raise error.Abort(_('not a bundle2 file'))
2104 ui.write(('Stream params: %s\n' % repr(gen.params)))
2096 ui.write(('Stream params: %s\n' % repr(gen.params)))
2105 for part in gen.iterparts():
2097 for part in gen.iterparts():
2106 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2098 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2107 if part.type == 'changegroup':
2099 if part.type == 'changegroup':
2108 version = part.params.get('version', '01')
2100 version = part.params.get('version', '01')
2109 cg = changegroup.getunbundler(version, part, 'UN')
2101 cg = changegroup.getunbundler(version, part, 'UN')
2110 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2102 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2111
2103
2112 @command('debugcreatestreamclonebundle', [], 'FILE')
2104 @command('debugcreatestreamclonebundle', [], 'FILE')
2113 def debugcreatestreamclonebundle(ui, repo, fname):
2105 def debugcreatestreamclonebundle(ui, repo, fname):
2114 """create a stream clone bundle file
2106 """create a stream clone bundle file
2115
2107
2116 Stream bundles are special bundles that are essentially archives of
2108 Stream bundles are special bundles that are essentially archives of
2117 revlog files. They are commonly used for cloning very quickly.
2109 revlog files. They are commonly used for cloning very quickly.
2118 """
2110 """
2119 requirements, gen = streamclone.generatebundlev1(repo)
2111 requirements, gen = streamclone.generatebundlev1(repo)
2120 changegroup.writechunks(ui, gen, fname)
2112 changegroup.writechunks(ui, gen, fname)
2121
2113
2122 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2114 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2123
2115
2124 @command('debugapplystreamclonebundle', [], 'FILE')
2116 @command('debugapplystreamclonebundle', [], 'FILE')
2125 def debugapplystreamclonebundle(ui, repo, fname):
2117 def debugapplystreamclonebundle(ui, repo, fname):
2126 """apply a stream clone bundle file"""
2118 """apply a stream clone bundle file"""
2127 f = hg.openpath(ui, fname)
2119 f = hg.openpath(ui, fname)
2128 gen = exchange.readbundle(ui, f, fname)
2120 gen = exchange.readbundle(ui, f, fname)
2129 gen.apply(repo)
2121 gen.apply(repo)
2130
2122
2131 @command('debugcheckstate', [], '')
2123 @command('debugcheckstate', [], '')
2132 def debugcheckstate(ui, repo):
2124 def debugcheckstate(ui, repo):
2133 """validate the correctness of the current dirstate"""
2125 """validate the correctness of the current dirstate"""
2134 parent1, parent2 = repo.dirstate.parents()
2126 parent1, parent2 = repo.dirstate.parents()
2135 m1 = repo[parent1].manifest()
2127 m1 = repo[parent1].manifest()
2136 m2 = repo[parent2].manifest()
2128 m2 = repo[parent2].manifest()
2137 errors = 0
2129 errors = 0
2138 for f in repo.dirstate:
2130 for f in repo.dirstate:
2139 state = repo.dirstate[f]
2131 state = repo.dirstate[f]
2140 if state in "nr" and f not in m1:
2132 if state in "nr" and f not in m1:
2141 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2133 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2142 errors += 1
2134 errors += 1
2143 if state in "a" and f in m1:
2135 if state in "a" and f in m1:
2144 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2136 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2145 errors += 1
2137 errors += 1
2146 if state in "m" and f not in m1 and f not in m2:
2138 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") %
2139 ui.warn(_("%s in state %s, but not in either manifest\n") %
2148 (f, state))
2140 (f, state))
2149 errors += 1
2141 errors += 1
2150 for f in m1:
2142 for f in m1:
2151 state = repo.dirstate[f]
2143 state = repo.dirstate[f]
2152 if state not in "nrm":
2144 if state not in "nrm":
2153 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2145 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2154 errors += 1
2146 errors += 1
2155 if errors:
2147 if errors:
2156 error = _(".hg/dirstate inconsistent with current parent's manifest")
2148 error = _(".hg/dirstate inconsistent with current parent's manifest")
2157 raise error.Abort(error)
2149 raise error.Abort(error)
2158
2150
2159 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2151 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2160 def debugcommands(ui, cmd='', *args):
2152 def debugcommands(ui, cmd='', *args):
2161 """list all available commands and options"""
2153 """list all available commands and options"""
2162 for cmd, vals in sorted(table.iteritems()):
2154 for cmd, vals in sorted(table.iteritems()):
2163 cmd = cmd.split('|')[0].strip('^')
2155 cmd = cmd.split('|')[0].strip('^')
2164 opts = ', '.join([i[1] for i in vals[1]])
2156 opts = ', '.join([i[1] for i in vals[1]])
2165 ui.write('%s: %s\n' % (cmd, opts))
2157 ui.write('%s: %s\n' % (cmd, opts))
2166
2158
2167 @command('debugcomplete',
2159 @command('debugcomplete',
2168 [('o', 'options', None, _('show the command options'))],
2160 [('o', 'options', None, _('show the command options'))],
2169 _('[-o] CMD'),
2161 _('[-o] CMD'),
2170 norepo=True)
2162 norepo=True)
2171 def debugcomplete(ui, cmd='', **opts):
2163 def debugcomplete(ui, cmd='', **opts):
2172 """returns the completion list associated with the given command"""
2164 """returns the completion list associated with the given command"""
2173
2165
2174 if opts.get('options'):
2166 if opts.get('options'):
2175 options = []
2167 options = []
2176 otables = [globalopts]
2168 otables = [globalopts]
2177 if cmd:
2169 if cmd:
2178 aliases, entry = cmdutil.findcmd(cmd, table, False)
2170 aliases, entry = cmdutil.findcmd(cmd, table, False)
2179 otables.append(entry[1])
2171 otables.append(entry[1])
2180 for t in otables:
2172 for t in otables:
2181 for o in t:
2173 for o in t:
2182 if "(DEPRECATED)" in o[3]:
2174 if "(DEPRECATED)" in o[3]:
2183 continue
2175 continue
2184 if o[0]:
2176 if o[0]:
2185 options.append('-%s' % o[0])
2177 options.append('-%s' % o[0])
2186 options.append('--%s' % o[1])
2178 options.append('--%s' % o[1])
2187 ui.write("%s\n" % "\n".join(options))
2179 ui.write("%s\n" % "\n".join(options))
2188 return
2180 return
2189
2181
2190 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2182 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2191 if ui.verbose:
2183 if ui.verbose:
2192 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2184 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2193 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2185 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2194
2186
2195 @command('debugdag',
2187 @command('debugdag',
2196 [('t', 'tags', None, _('use tags as labels')),
2188 [('t', 'tags', None, _('use tags as labels')),
2197 ('b', 'branches', None, _('annotate with branch names')),
2189 ('b', 'branches', None, _('annotate with branch names')),
2198 ('', 'dots', None, _('use dots for runs')),
2190 ('', 'dots', None, _('use dots for runs')),
2199 ('s', 'spaces', None, _('separate elements by spaces'))],
2191 ('s', 'spaces', None, _('separate elements by spaces'))],
2200 _('[OPTION]... [FILE [REV]...]'),
2192 _('[OPTION]... [FILE [REV]...]'),
2201 optionalrepo=True)
2193 optionalrepo=True)
2202 def debugdag(ui, repo, file_=None, *revs, **opts):
2194 def debugdag(ui, repo, file_=None, *revs, **opts):
2203 """format the changelog or an index DAG as a concise textual description
2195 """format the changelog or an index DAG as a concise textual description
2204
2196
2205 If you pass a revlog index, the revlog's DAG is emitted. If you list
2197 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.
2198 revision numbers, they get labeled in the output as rN.
2207
2199
2208 Otherwise, the changelog DAG of the current repo is emitted.
2200 Otherwise, the changelog DAG of the current repo is emitted.
2209 """
2201 """
2210 spaces = opts.get('spaces')
2202 spaces = opts.get('spaces')
2211 dots = opts.get('dots')
2203 dots = opts.get('dots')
2212 if file_:
2204 if file_:
2213 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2205 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2214 revs = set((int(r) for r in revs))
2206 revs = set((int(r) for r in revs))
2215 def events():
2207 def events():
2216 for r in rlog:
2208 for r in rlog:
2217 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2209 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2218 if p != -1))
2210 if p != -1))
2219 if r in revs:
2211 if r in revs:
2220 yield 'l', (r, "r%i" % r)
2212 yield 'l', (r, "r%i" % r)
2221 elif repo:
2213 elif repo:
2222 cl = repo.changelog
2214 cl = repo.changelog
2223 tags = opts.get('tags')
2215 tags = opts.get('tags')
2224 branches = opts.get('branches')
2216 branches = opts.get('branches')
2225 if tags:
2217 if tags:
2226 labels = {}
2218 labels = {}
2227 for l, n in repo.tags().items():
2219 for l, n in repo.tags().items():
2228 labels.setdefault(cl.rev(n), []).append(l)
2220 labels.setdefault(cl.rev(n), []).append(l)
2229 def events():
2221 def events():
2230 b = "default"
2222 b = "default"
2231 for r in cl:
2223 for r in cl:
2232 if branches:
2224 if branches:
2233 newb = cl.read(cl.node(r))[5]['branch']
2225 newb = cl.read(cl.node(r))[5]['branch']
2234 if newb != b:
2226 if newb != b:
2235 yield 'a', newb
2227 yield 'a', newb
2236 b = newb
2228 b = newb
2237 yield 'n', (r, list(p for p in cl.parentrevs(r)
2229 yield 'n', (r, list(p for p in cl.parentrevs(r)
2238 if p != -1))
2230 if p != -1))
2239 if tags:
2231 if tags:
2240 ls = labels.get(r)
2232 ls = labels.get(r)
2241 if ls:
2233 if ls:
2242 for l in ls:
2234 for l in ls:
2243 yield 'l', (r, l)
2235 yield 'l', (r, l)
2244 else:
2236 else:
2245 raise error.Abort(_('need repo for changelog dag'))
2237 raise error.Abort(_('need repo for changelog dag'))
2246
2238
2247 for line in dagparser.dagtextlines(events(),
2239 for line in dagparser.dagtextlines(events(),
2248 addspaces=spaces,
2240 addspaces=spaces,
2249 wraplabels=True,
2241 wraplabels=True,
2250 wrapannotations=True,
2242 wrapannotations=True,
2251 wrapnonlinear=dots,
2243 wrapnonlinear=dots,
2252 usedots=dots,
2244 usedots=dots,
2253 maxlinewidth=70):
2245 maxlinewidth=70):
2254 ui.write(line)
2246 ui.write(line)
2255 ui.write("\n")
2247 ui.write("\n")
2256
2248
2257 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2249 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2258 def debugdata(ui, repo, file_, rev=None, **opts):
2250 def debugdata(ui, repo, file_, rev=None, **opts):
2259 """dump the contents of a data file revision"""
2251 """dump the contents of a data file revision"""
2260 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2252 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2261 if rev is not None:
2253 if rev is not None:
2262 raise error.CommandError('debugdata', _('invalid arguments'))
2254 raise error.CommandError('debugdata', _('invalid arguments'))
2263 file_, rev = None, file_
2255 file_, rev = None, file_
2264 elif rev is None:
2256 elif rev is None:
2265 raise error.CommandError('debugdata', _('invalid arguments'))
2257 raise error.CommandError('debugdata', _('invalid arguments'))
2266 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2258 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2267 try:
2259 try:
2268 ui.write(r.revision(r.lookup(rev)))
2260 ui.write(r.revision(r.lookup(rev)))
2269 except KeyError:
2261 except KeyError:
2270 raise error.Abort(_('invalid revision identifier %s') % rev)
2262 raise error.Abort(_('invalid revision identifier %s') % rev)
2271
2263
2272 @command('debugdate',
2264 @command('debugdate',
2273 [('e', 'extended', None, _('try extended date formats'))],
2265 [('e', 'extended', None, _('try extended date formats'))],
2274 _('[-e] DATE [RANGE]'),
2266 _('[-e] DATE [RANGE]'),
2275 norepo=True, optionalrepo=True)
2267 norepo=True, optionalrepo=True)
2276 def debugdate(ui, date, range=None, **opts):
2268 def debugdate(ui, date, range=None, **opts):
2277 """parse and display a date"""
2269 """parse and display a date"""
2278 if opts["extended"]:
2270 if opts["extended"]:
2279 d = util.parsedate(date, util.extendeddateformats)
2271 d = util.parsedate(date, util.extendeddateformats)
2280 else:
2272 else:
2281 d = util.parsedate(date)
2273 d = util.parsedate(date)
2282 ui.write(("internal: %s %s\n") % d)
2274 ui.write(("internal: %s %s\n") % d)
2283 ui.write(("standard: %s\n") % util.datestr(d))
2275 ui.write(("standard: %s\n") % util.datestr(d))
2284 if range:
2276 if range:
2285 m = util.matchdate(range)
2277 m = util.matchdate(range)
2286 ui.write(("match: %s\n") % m(d[0]))
2278 ui.write(("match: %s\n") % m(d[0]))
2287
2279
2288 @command('debugdiscovery',
2280 @command('debugdiscovery',
2289 [('', 'old', None, _('use old-style discovery')),
2281 [('', 'old', None, _('use old-style discovery')),
2290 ('', 'nonheads', None,
2282 ('', 'nonheads', None,
2291 _('use old-style discovery with non-heads included')),
2283 _('use old-style discovery with non-heads included')),
2292 ] + remoteopts,
2284 ] + remoteopts,
2293 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2285 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2294 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2286 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2295 """runs the changeset discovery protocol in isolation"""
2287 """runs the changeset discovery protocol in isolation"""
2296 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2288 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2297 opts.get('branch'))
2289 opts.get('branch'))
2298 remote = hg.peer(repo, opts, remoteurl)
2290 remote = hg.peer(repo, opts, remoteurl)
2299 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2291 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2300
2292
2301 # make sure tests are repeatable
2293 # make sure tests are repeatable
2302 random.seed(12323)
2294 random.seed(12323)
2303
2295
2304 def doit(localheads, remoteheads, remote=remote):
2296 def doit(localheads, remoteheads, remote=remote):
2305 if opts.get('old'):
2297 if opts.get('old'):
2306 if localheads:
2298 if localheads:
2307 raise error.Abort('cannot use localheads with old style '
2299 raise error.Abort('cannot use localheads with old style '
2308 'discovery')
2300 'discovery')
2309 if not util.safehasattr(remote, 'branches'):
2301 if not util.safehasattr(remote, 'branches'):
2310 # enable in-client legacy support
2302 # enable in-client legacy support
2311 remote = localrepo.locallegacypeer(remote.local())
2303 remote = localrepo.locallegacypeer(remote.local())
2312 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2304 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2313 force=True)
2305 force=True)
2314 common = set(common)
2306 common = set(common)
2315 if not opts.get('nonheads'):
2307 if not opts.get('nonheads'):
2316 ui.write(("unpruned common: %s\n") %
2308 ui.write(("unpruned common: %s\n") %
2317 " ".join(sorted(short(n) for n in common)))
2309 " ".join(sorted(short(n) for n in common)))
2318 dag = dagutil.revlogdag(repo.changelog)
2310 dag = dagutil.revlogdag(repo.changelog)
2319 all = dag.ancestorset(dag.internalizeall(common))
2311 all = dag.ancestorset(dag.internalizeall(common))
2320 common = dag.externalizeall(dag.headsetofconnecteds(all))
2312 common = dag.externalizeall(dag.headsetofconnecteds(all))
2321 else:
2313 else:
2322 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2314 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2323 common = set(common)
2315 common = set(common)
2324 rheads = set(hds)
2316 rheads = set(hds)
2325 lheads = set(repo.heads())
2317 lheads = set(repo.heads())
2326 ui.write(("common heads: %s\n") %
2318 ui.write(("common heads: %s\n") %
2327 " ".join(sorted(short(n) for n in common)))
2319 " ".join(sorted(short(n) for n in common)))
2328 if lheads <= common:
2320 if lheads <= common:
2329 ui.write(("local is subset\n"))
2321 ui.write(("local is subset\n"))
2330 elif rheads <= common:
2322 elif rheads <= common:
2331 ui.write(("remote is subset\n"))
2323 ui.write(("remote is subset\n"))
2332
2324
2333 serverlogs = opts.get('serverlog')
2325 serverlogs = opts.get('serverlog')
2334 if serverlogs:
2326 if serverlogs:
2335 for filename in serverlogs:
2327 for filename in serverlogs:
2336 with open(filename, 'r') as logfile:
2328 with open(filename, 'r') as logfile:
2337 line = logfile.readline()
2329 line = logfile.readline()
2338 while line:
2330 while line:
2339 parts = line.strip().split(';')
2331 parts = line.strip().split(';')
2340 op = parts[1]
2332 op = parts[1]
2341 if op == 'cg':
2333 if op == 'cg':
2342 pass
2334 pass
2343 elif op == 'cgss':
2335 elif op == 'cgss':
2344 doit(parts[2].split(' '), parts[3].split(' '))
2336 doit(parts[2].split(' '), parts[3].split(' '))
2345 elif op == 'unb':
2337 elif op == 'unb':
2346 doit(parts[3].split(' '), parts[2].split(' '))
2338 doit(parts[3].split(' '), parts[2].split(' '))
2347 line = logfile.readline()
2339 line = logfile.readline()
2348 else:
2340 else:
2349 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2341 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2350 opts.get('remote_head'))
2342 opts.get('remote_head'))
2351 localrevs = opts.get('local_head')
2343 localrevs = opts.get('local_head')
2352 doit(localrevs, remoterevs)
2344 doit(localrevs, remoterevs)
2353
2345
2354 @command('debugextensions', formatteropts, [], norepo=True)
2346 @command('debugextensions', formatteropts, [], norepo=True)
2355 def debugextensions(ui, **opts):
2347 def debugextensions(ui, **opts):
2356 '''show information about active extensions'''
2348 '''show information about active extensions'''
2357 exts = extensions.extensions(ui)
2349 exts = extensions.extensions(ui)
2358 hgver = util.version()
2350 hgver = util.version()
2359 fm = ui.formatter('debugextensions', opts)
2351 fm = ui.formatter('debugextensions', opts)
2360 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2352 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2361 isinternal = extensions.ismoduleinternal(extmod)
2353 isinternal = extensions.ismoduleinternal(extmod)
2362 extsource = extmod.__file__
2354 extsource = extmod.__file__
2363 if isinternal:
2355 if isinternal:
2364 exttestedwith = [] # never expose magic string to users
2356 exttestedwith = [] # never expose magic string to users
2365 else:
2357 else:
2366 exttestedwith = getattr(extmod, 'testedwith', '').split()
2358 exttestedwith = getattr(extmod, 'testedwith', '').split()
2367 extbuglink = getattr(extmod, 'buglink', None)
2359 extbuglink = getattr(extmod, 'buglink', None)
2368
2360
2369 fm.startitem()
2361 fm.startitem()
2370
2362
2371 if ui.quiet or ui.verbose:
2363 if ui.quiet or ui.verbose:
2372 fm.write('name', '%s\n', extname)
2364 fm.write('name', '%s\n', extname)
2373 else:
2365 else:
2374 fm.write('name', '%s', extname)
2366 fm.write('name', '%s', extname)
2375 if isinternal or hgver in exttestedwith:
2367 if isinternal or hgver in exttestedwith:
2376 fm.plain('\n')
2368 fm.plain('\n')
2377 elif not exttestedwith:
2369 elif not exttestedwith:
2378 fm.plain(_(' (untested!)\n'))
2370 fm.plain(_(' (untested!)\n'))
2379 else:
2371 else:
2380 lasttestedversion = exttestedwith[-1]
2372 lasttestedversion = exttestedwith[-1]
2381 fm.plain(' (%s!)\n' % lasttestedversion)
2373 fm.plain(' (%s!)\n' % lasttestedversion)
2382
2374
2383 fm.condwrite(ui.verbose and extsource, 'source',
2375 fm.condwrite(ui.verbose and extsource, 'source',
2384 _(' location: %s\n'), extsource or "")
2376 _(' location: %s\n'), extsource or "")
2385
2377
2386 if ui.verbose:
2378 if ui.verbose:
2387 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2379 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2388 fm.data(bundled=isinternal)
2380 fm.data(bundled=isinternal)
2389
2381
2390 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2382 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2391 _(' tested with: %s\n'),
2383 _(' tested with: %s\n'),
2392 fm.formatlist(exttestedwith, name='ver'))
2384 fm.formatlist(exttestedwith, name='ver'))
2393
2385
2394 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2386 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2395 _(' bug reporting: %s\n'), extbuglink or "")
2387 _(' bug reporting: %s\n'), extbuglink or "")
2396
2388
2397 fm.end()
2389 fm.end()
2398
2390
2399 @command('debugfileset',
2391 @command('debugfileset',
2400 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2392 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2401 _('[-r REV] FILESPEC'))
2393 _('[-r REV] FILESPEC'))
2402 def debugfileset(ui, repo, expr, **opts):
2394 def debugfileset(ui, repo, expr, **opts):
2403 '''parse and apply a fileset specification'''
2395 '''parse and apply a fileset specification'''
2404 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2396 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2405 if ui.verbose:
2397 if ui.verbose:
2406 tree = fileset.parse(expr)
2398 tree = fileset.parse(expr)
2407 ui.note(fileset.prettyformat(tree), "\n")
2399 ui.note(fileset.prettyformat(tree), "\n")
2408
2400
2409 for f in ctx.getfileset(expr):
2401 for f in ctx.getfileset(expr):
2410 ui.write("%s\n" % f)
2402 ui.write("%s\n" % f)
2411
2403
2412 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2404 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2413 def debugfsinfo(ui, path="."):
2405 def debugfsinfo(ui, path="."):
2414 """show information detected about current filesystem"""
2406 """show information detected about current filesystem"""
2415 util.writefile('.debugfsinfo', '')
2407 util.writefile('.debugfsinfo', '')
2416 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2408 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'))
2409 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'))
2410 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2419 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2411 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2420 and 'yes' or 'no'))
2412 and 'yes' or 'no'))
2421 os.unlink('.debugfsinfo')
2413 os.unlink('.debugfsinfo')
2422
2414
2423 @command('debuggetbundle',
2415 @command('debuggetbundle',
2424 [('H', 'head', [], _('id of head node'), _('ID')),
2416 [('H', 'head', [], _('id of head node'), _('ID')),
2425 ('C', 'common', [], _('id of common node'), _('ID')),
2417 ('C', 'common', [], _('id of common node'), _('ID')),
2426 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2418 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2427 _('REPO FILE [-H|-C ID]...'),
2419 _('REPO FILE [-H|-C ID]...'),
2428 norepo=True)
2420 norepo=True)
2429 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2421 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2430 """retrieves a bundle from a repo
2422 """retrieves a bundle from a repo
2431
2423
2432 Every ID must be a full-length hex node id string. Saves the bundle to the
2424 Every ID must be a full-length hex node id string. Saves the bundle to the
2433 given file.
2425 given file.
2434 """
2426 """
2435 repo = hg.peer(ui, opts, repopath)
2427 repo = hg.peer(ui, opts, repopath)
2436 if not repo.capable('getbundle'):
2428 if not repo.capable('getbundle'):
2437 raise error.Abort("getbundle() not supported by target repository")
2429 raise error.Abort("getbundle() not supported by target repository")
2438 args = {}
2430 args = {}
2439 if common:
2431 if common:
2440 args['common'] = [bin(s) for s in common]
2432 args['common'] = [bin(s) for s in common]
2441 if head:
2433 if head:
2442 args['heads'] = [bin(s) for s in head]
2434 args['heads'] = [bin(s) for s in head]
2443 # TODO: get desired bundlecaps from command line.
2435 # TODO: get desired bundlecaps from command line.
2444 args['bundlecaps'] = None
2436 args['bundlecaps'] = None
2445 bundle = repo.getbundle('debug', **args)
2437 bundle = repo.getbundle('debug', **args)
2446
2438
2447 bundletype = opts.get('type', 'bzip2').lower()
2439 bundletype = opts.get('type', 'bzip2').lower()
2448 btypes = {'none': 'HG10UN',
2440 btypes = {'none': 'HG10UN',
2449 'bzip2': 'HG10BZ',
2441 'bzip2': 'HG10BZ',
2450 'gzip': 'HG10GZ',
2442 'gzip': 'HG10GZ',
2451 'bundle2': 'HG20'}
2443 'bundle2': 'HG20'}
2452 bundletype = btypes.get(bundletype)
2444 bundletype = btypes.get(bundletype)
2453 if bundletype not in bundle2.bundletypes:
2445 if bundletype not in bundle2.bundletypes:
2454 raise error.Abort(_('unknown bundle type specified with --type'))
2446 raise error.Abort(_('unknown bundle type specified with --type'))
2455 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2447 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2456
2448
2457 @command('debugignore', [], '[FILE]')
2449 @command('debugignore', [], '[FILE]')
2458 def debugignore(ui, repo, *files, **opts):
2450 def debugignore(ui, repo, *files, **opts):
2459 """display the combined ignore pattern and information about ignored files
2451 """display the combined ignore pattern and information about ignored files
2460
2452
2461 With no argument display the combined ignore pattern.
2453 With no argument display the combined ignore pattern.
2462
2454
2463 Given space separated file names, shows if the given file is ignored and
2455 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.
2456 if so, show the ignore rule (file and line number) that matched it.
2465 """
2457 """
2466 ignore = repo.dirstate._ignore
2458 ignore = repo.dirstate._ignore
2467 if not files:
2459 if not files:
2468 # Show all the patterns
2460 # Show all the patterns
2469 includepat = getattr(ignore, 'includepat', None)
2461 includepat = getattr(ignore, 'includepat', None)
2470 if includepat is not None:
2462 if includepat is not None:
2471 ui.write("%s\n" % includepat)
2463 ui.write("%s\n" % includepat)
2472 else:
2464 else:
2473 raise error.Abort(_("no ignore patterns found"))
2465 raise error.Abort(_("no ignore patterns found"))
2474 else:
2466 else:
2475 for f in files:
2467 for f in files:
2476 nf = util.normpath(f)
2468 nf = util.normpath(f)
2477 ignored = None
2469 ignored = None
2478 ignoredata = None
2470 ignoredata = None
2479 if nf != '.':
2471 if nf != '.':
2480 if ignore(nf):
2472 if ignore(nf):
2481 ignored = nf
2473 ignored = nf
2482 ignoredata = repo.dirstate._ignorefileandline(nf)
2474 ignoredata = repo.dirstate._ignorefileandline(nf)
2483 else:
2475 else:
2484 for p in util.finddirs(nf):
2476 for p in util.finddirs(nf):
2485 if ignore(p):
2477 if ignore(p):
2486 ignored = p
2478 ignored = p
2487 ignoredata = repo.dirstate._ignorefileandline(p)
2479 ignoredata = repo.dirstate._ignorefileandline(p)
2488 break
2480 break
2489 if ignored:
2481 if ignored:
2490 if ignored == nf:
2482 if ignored == nf:
2491 ui.write(_("%s is ignored\n") % f)
2483 ui.write(_("%s is ignored\n") % f)
2492 else:
2484 else:
2493 ui.write(_("%s is ignored because of "
2485 ui.write(_("%s is ignored because of "
2494 "containing folder %s\n")
2486 "containing folder %s\n")
2495 % (f, ignored))
2487 % (f, ignored))
2496 ignorefile, lineno, line = ignoredata
2488 ignorefile, lineno, line = ignoredata
2497 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2489 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2498 % (ignorefile, lineno, line))
2490 % (ignorefile, lineno, line))
2499 else:
2491 else:
2500 ui.write(_("%s is not ignored\n") % f)
2492 ui.write(_("%s is not ignored\n") % f)
2501
2493
2502 @command('debugindex', debugrevlogopts +
2494 @command('debugindex', debugrevlogopts +
2503 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2495 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2504 _('[-f FORMAT] -c|-m|FILE'),
2496 _('[-f FORMAT] -c|-m|FILE'),
2505 optionalrepo=True)
2497 optionalrepo=True)
2506 def debugindex(ui, repo, file_=None, **opts):
2498 def debugindex(ui, repo, file_=None, **opts):
2507 """dump the contents of an index file"""
2499 """dump the contents of an index file"""
2508 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2500 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2509 format = opts.get('format', 0)
2501 format = opts.get('format', 0)
2510 if format not in (0, 1):
2502 if format not in (0, 1):
2511 raise error.Abort(_("unknown format %d") % format)
2503 raise error.Abort(_("unknown format %d") % format)
2512
2504
2513 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2505 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2514 if generaldelta:
2506 if generaldelta:
2515 basehdr = ' delta'
2507 basehdr = ' delta'
2516 else:
2508 else:
2517 basehdr = ' base'
2509 basehdr = ' base'
2518
2510
2519 if ui.debugflag:
2511 if ui.debugflag:
2520 shortfn = hex
2512 shortfn = hex
2521 else:
2513 else:
2522 shortfn = short
2514 shortfn = short
2523
2515
2524 # There might not be anything in r, so have a sane default
2516 # There might not be anything in r, so have a sane default
2525 idlen = 12
2517 idlen = 12
2526 for i in r:
2518 for i in r:
2527 idlen = len(shortfn(r.node(i)))
2519 idlen = len(shortfn(r.node(i)))
2528 break
2520 break
2529
2521
2530 if format == 0:
2522 if format == 0:
2531 ui.write((" rev offset length " + basehdr + " linkrev"
2523 ui.write((" rev offset length " + basehdr + " linkrev"
2532 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2524 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2533 elif format == 1:
2525 elif format == 1:
2534 ui.write((" rev flag offset length"
2526 ui.write((" rev flag offset length"
2535 " size " + basehdr + " link p1 p2"
2527 " size " + basehdr + " link p1 p2"
2536 " %s\n") % "nodeid".rjust(idlen))
2528 " %s\n") % "nodeid".rjust(idlen))
2537
2529
2538 for i in r:
2530 for i in r:
2539 node = r.node(i)
2531 node = r.node(i)
2540 if generaldelta:
2532 if generaldelta:
2541 base = r.deltaparent(i)
2533 base = r.deltaparent(i)
2542 else:
2534 else:
2543 base = r.chainbase(i)
2535 base = r.chainbase(i)
2544 if format == 0:
2536 if format == 0:
2545 try:
2537 try:
2546 pp = r.parents(node)
2538 pp = r.parents(node)
2547 except Exception:
2539 except Exception:
2548 pp = [nullid, nullid]
2540 pp = [nullid, nullid]
2549 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2541 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2550 i, r.start(i), r.length(i), base, r.linkrev(i),
2542 i, r.start(i), r.length(i), base, r.linkrev(i),
2551 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2543 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2552 elif format == 1:
2544 elif format == 1:
2553 pr = r.parentrevs(i)
2545 pr = r.parentrevs(i)
2554 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2546 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),
2547 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2556 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2548 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2557
2549
2558 @command('debugindexdot', debugrevlogopts,
2550 @command('debugindexdot', debugrevlogopts,
2559 _('-c|-m|FILE'), optionalrepo=True)
2551 _('-c|-m|FILE'), optionalrepo=True)
2560 def debugindexdot(ui, repo, file_=None, **opts):
2552 def debugindexdot(ui, repo, file_=None, **opts):
2561 """dump an index DAG as a graphviz dot file"""
2553 """dump an index DAG as a graphviz dot file"""
2562 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2554 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2563 ui.write(("digraph G {\n"))
2555 ui.write(("digraph G {\n"))
2564 for i in r:
2556 for i in r:
2565 node = r.node(i)
2557 node = r.node(i)
2566 pp = r.parents(node)
2558 pp = r.parents(node)
2567 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2559 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2568 if pp[1] != nullid:
2560 if pp[1] != nullid:
2569 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2561 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2570 ui.write("}\n")
2562 ui.write("}\n")
2571
2563
2572 @command('debugdeltachain',
2564 @command('debugdeltachain',
2573 debugrevlogopts + formatteropts,
2565 debugrevlogopts + formatteropts,
2574 _('-c|-m|FILE'),
2566 _('-c|-m|FILE'),
2575 optionalrepo=True)
2567 optionalrepo=True)
2576 def debugdeltachain(ui, repo, file_=None, **opts):
2568 def debugdeltachain(ui, repo, file_=None, **opts):
2577 """dump information about delta chains in a revlog
2569 """dump information about delta chains in a revlog
2578
2570
2579 Output can be templatized. Available template keywords are:
2571 Output can be templatized. Available template keywords are:
2580
2572
2581 :``rev``: revision number
2573 :``rev``: revision number
2582 :``chainid``: delta chain identifier (numbered by unique base)
2574 :``chainid``: delta chain identifier (numbered by unique base)
2583 :``chainlen``: delta chain length to this revision
2575 :``chainlen``: delta chain length to this revision
2584 :``prevrev``: previous revision in delta chain
2576 :``prevrev``: previous revision in delta chain
2585 :``deltatype``: role of delta / how it was computed
2577 :``deltatype``: role of delta / how it was computed
2586 :``compsize``: compressed size of revision
2578 :``compsize``: compressed size of revision
2587 :``uncompsize``: uncompressed size of revision
2579 :``uncompsize``: uncompressed size of revision
2588 :``chainsize``: total size of compressed revisions in chain
2580 :``chainsize``: total size of compressed revisions in chain
2589 :``chainratio``: total chain size divided by uncompressed revision size
2581 :``chainratio``: total chain size divided by uncompressed revision size
2590 (new delta chains typically start at ratio 2.00)
2582 (new delta chains typically start at ratio 2.00)
2591 :``lindist``: linear distance from base revision in delta chain to end
2583 :``lindist``: linear distance from base revision in delta chain to end
2592 of this revision
2584 of this revision
2593 :``extradist``: total size of revisions not part of this delta chain from
2585 :``extradist``: total size of revisions not part of this delta chain from
2594 base of delta chain to end of this revision; a measurement
2586 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
2587 of how much extra data we need to read/seek across to read
2596 the delta chain for this revision
2588 the delta chain for this revision
2597 :``extraratio``: extradist divided by chainsize; another representation of
2589 :``extraratio``: extradist divided by chainsize; another representation of
2598 how much unrelated data is needed to load this delta chain
2590 how much unrelated data is needed to load this delta chain
2599 """
2591 """
2600 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2592 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2601 index = r.index
2593 index = r.index
2602 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2594 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2603
2595
2604 def revinfo(rev):
2596 def revinfo(rev):
2605 e = index[rev]
2597 e = index[rev]
2606 compsize = e[1]
2598 compsize = e[1]
2607 uncompsize = e[2]
2599 uncompsize = e[2]
2608 chainsize = 0
2600 chainsize = 0
2609
2601
2610 if generaldelta:
2602 if generaldelta:
2611 if e[3] == e[5]:
2603 if e[3] == e[5]:
2612 deltatype = 'p1'
2604 deltatype = 'p1'
2613 elif e[3] == e[6]:
2605 elif e[3] == e[6]:
2614 deltatype = 'p2'
2606 deltatype = 'p2'
2615 elif e[3] == rev - 1:
2607 elif e[3] == rev - 1:
2616 deltatype = 'prev'
2608 deltatype = 'prev'
2617 elif e[3] == rev:
2609 elif e[3] == rev:
2618 deltatype = 'base'
2610 deltatype = 'base'
2619 else:
2611 else:
2620 deltatype = 'other'
2612 deltatype = 'other'
2621 else:
2613 else:
2622 if e[3] == rev:
2614 if e[3] == rev:
2623 deltatype = 'base'
2615 deltatype = 'base'
2624 else:
2616 else:
2625 deltatype = 'prev'
2617 deltatype = 'prev'
2626
2618
2627 chain = r._deltachain(rev)[0]
2619 chain = r._deltachain(rev)[0]
2628 for iterrev in chain:
2620 for iterrev in chain:
2629 e = index[iterrev]
2621 e = index[iterrev]
2630 chainsize += e[1]
2622 chainsize += e[1]
2631
2623
2632 return compsize, uncompsize, deltatype, chain, chainsize
2624 return compsize, uncompsize, deltatype, chain, chainsize
2633
2625
2634 fm = ui.formatter('debugdeltachain', opts)
2626 fm = ui.formatter('debugdeltachain', opts)
2635
2627
2636 fm.plain(' rev chain# chainlen prev delta '
2628 fm.plain(' rev chain# chainlen prev delta '
2637 'size rawsize chainsize ratio lindist extradist '
2629 'size rawsize chainsize ratio lindist extradist '
2638 'extraratio\n')
2630 'extraratio\n')
2639
2631
2640 chainbases = {}
2632 chainbases = {}
2641 for rev in r:
2633 for rev in r:
2642 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2634 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2643 chainbase = chain[0]
2635 chainbase = chain[0]
2644 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2636 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2645 basestart = r.start(chainbase)
2637 basestart = r.start(chainbase)
2646 revstart = r.start(rev)
2638 revstart = r.start(rev)
2647 lineardist = revstart + comp - basestart
2639 lineardist = revstart + comp - basestart
2648 extradist = lineardist - chainsize
2640 extradist = lineardist - chainsize
2649 try:
2641 try:
2650 prevrev = chain[-2]
2642 prevrev = chain[-2]
2651 except IndexError:
2643 except IndexError:
2652 prevrev = -1
2644 prevrev = -1
2653
2645
2654 chainratio = float(chainsize) / float(uncomp)
2646 chainratio = float(chainsize) / float(uncomp)
2655 extraratio = float(extradist) / float(chainsize)
2647 extraratio = float(extradist) / float(chainsize)
2656
2648
2657 fm.startitem()
2649 fm.startitem()
2658 fm.write('rev chainid chainlen prevrev deltatype compsize '
2650 fm.write('rev chainid chainlen prevrev deltatype compsize '
2659 'uncompsize chainsize chainratio lindist extradist '
2651 'uncompsize chainsize chainratio lindist extradist '
2660 'extraratio',
2652 'extraratio',
2661 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2653 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2662 rev, chainid, len(chain), prevrev, deltatype, comp,
2654 rev, chainid, len(chain), prevrev, deltatype, comp,
2663 uncomp, chainsize, chainratio, lineardist, extradist,
2655 uncomp, chainsize, chainratio, lineardist, extradist,
2664 extraratio,
2656 extraratio,
2665 rev=rev, chainid=chainid, chainlen=len(chain),
2657 rev=rev, chainid=chainid, chainlen=len(chain),
2666 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2658 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2667 uncompsize=uncomp, chainsize=chainsize,
2659 uncompsize=uncomp, chainsize=chainsize,
2668 chainratio=chainratio, lindist=lineardist,
2660 chainratio=chainratio, lindist=lineardist,
2669 extradist=extradist, extraratio=extraratio)
2661 extradist=extradist, extraratio=extraratio)
2670
2662
2671 fm.end()
2663 fm.end()
2672
2664
2673 @command('debuginstall', [] + formatteropts, '', norepo=True)
2665 @command('debuginstall', [] + formatteropts, '', norepo=True)
2674 def debuginstall(ui, **opts):
2666 def debuginstall(ui, **opts):
2675 '''test Mercurial installation
2667 '''test Mercurial installation
2676
2668
2677 Returns 0 on success.
2669 Returns 0 on success.
2678 '''
2670 '''
2679
2671
2680 def writetemp(contents):
2672 def writetemp(contents):
2681 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2673 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2682 f = os.fdopen(fd, "wb")
2674 f = os.fdopen(fd, "wb")
2683 f.write(contents)
2675 f.write(contents)
2684 f.close()
2676 f.close()
2685 return name
2677 return name
2686
2678
2687 problems = 0
2679 problems = 0
2688
2680
2689 fm = ui.formatter('debuginstall', opts)
2681 fm = ui.formatter('debuginstall', opts)
2690 fm.startitem()
2682 fm.startitem()
2691
2683
2692 # encoding
2684 # encoding
2693 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2685 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2694 err = None
2686 err = None
2695 try:
2687 try:
2696 encoding.fromlocal("test")
2688 encoding.fromlocal("test")
2697 except error.Abort as inst:
2689 except error.Abort as inst:
2698 err = inst
2690 err = inst
2699 problems += 1
2691 problems += 1
2700 fm.condwrite(err, 'encodingerror', _(" %s\n"
2692 fm.condwrite(err, 'encodingerror', _(" %s\n"
2701 " (check that your locale is properly set)\n"), err)
2693 " (check that your locale is properly set)\n"), err)
2702
2694
2703 # Python
2695 # Python
2704 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2696 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2705 sys.executable)
2697 sys.executable)
2706 fm.write('pythonver', _("checking Python version (%s)\n"),
2698 fm.write('pythonver', _("checking Python version (%s)\n"),
2707 ("%s.%s.%s" % sys.version_info[:3]))
2699 ("%s.%s.%s" % sys.version_info[:3]))
2708 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2700 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2709 os.path.dirname(os.__file__))
2701 os.path.dirname(os.__file__))
2710
2702
2711 # hg version
2703 # hg version
2712 hgver = util.version()
2704 hgver = util.version()
2713 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2705 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2714 hgver.split('+')[0])
2706 hgver.split('+')[0])
2715 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2707 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2716 '+'.join(hgver.split('+')[1:]))
2708 '+'.join(hgver.split('+')[1:]))
2717
2709
2718 # compiled modules
2710 # compiled modules
2719 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2711 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2720 policy.policy)
2712 policy.policy)
2721 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2713 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2722 os.path.dirname(__file__))
2714 os.path.dirname(__file__))
2723
2715
2724 err = None
2716 err = None
2725 try:
2717 try:
2726 from . import (
2718 from . import (
2727 base85,
2719 base85,
2728 bdiff,
2720 bdiff,
2729 mpatch,
2721 mpatch,
2730 osutil,
2722 osutil,
2731 )
2723 )
2732 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2724 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2733 except Exception as inst:
2725 except Exception as inst:
2734 err = inst
2726 err = inst
2735 problems += 1
2727 problems += 1
2736 fm.condwrite(err, 'extensionserror', " %s\n", err)
2728 fm.condwrite(err, 'extensionserror', " %s\n", err)
2737
2729
2738 # templates
2730 # templates
2739 p = templater.templatepaths()
2731 p = templater.templatepaths()
2740 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2732 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2741 fm.condwrite(not p, '', _(" no template directories found\n"))
2733 fm.condwrite(not p, '', _(" no template directories found\n"))
2742 if p:
2734 if p:
2743 m = templater.templatepath("map-cmdline.default")
2735 m = templater.templatepath("map-cmdline.default")
2744 if m:
2736 if m:
2745 # template found, check if it is working
2737 # template found, check if it is working
2746 err = None
2738 err = None
2747 try:
2739 try:
2748 templater.templater.frommapfile(m)
2740 templater.templater.frommapfile(m)
2749 except Exception as inst:
2741 except Exception as inst:
2750 err = inst
2742 err = inst
2751 p = None
2743 p = None
2752 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2744 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2753 else:
2745 else:
2754 p = None
2746 p = None
2755 fm.condwrite(p, 'defaulttemplate',
2747 fm.condwrite(p, 'defaulttemplate',
2756 _("checking default template (%s)\n"), m)
2748 _("checking default template (%s)\n"), m)
2757 fm.condwrite(not m, 'defaulttemplatenotfound',
2749 fm.condwrite(not m, 'defaulttemplatenotfound',
2758 _(" template '%s' not found\n"), "default")
2750 _(" template '%s' not found\n"), "default")
2759 if not p:
2751 if not p:
2760 problems += 1
2752 problems += 1
2761 fm.condwrite(not p, '',
2753 fm.condwrite(not p, '',
2762 _(" (templates seem to have been installed incorrectly)\n"))
2754 _(" (templates seem to have been installed incorrectly)\n"))
2763
2755
2764 # editor
2756 # editor
2765 editor = ui.geteditor()
2757 editor = ui.geteditor()
2766 editor = util.expandpath(editor)
2758 editor = util.expandpath(editor)
2767 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2759 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2768 cmdpath = util.findexe(shlex.split(editor)[0])
2760 cmdpath = util.findexe(shlex.split(editor)[0])
2769 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2761 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2770 _(" No commit editor set and can't find %s in PATH\n"
2762 _(" No commit editor set and can't find %s in PATH\n"
2771 " (specify a commit editor in your configuration"
2763 " (specify a commit editor in your configuration"
2772 " file)\n"), not cmdpath and editor == 'vi' and editor)
2764 " file)\n"), not cmdpath and editor == 'vi' and editor)
2773 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2765 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2774 _(" Can't find editor '%s' in PATH\n"
2766 _(" Can't find editor '%s' in PATH\n"
2775 " (specify a commit editor in your configuration"
2767 " (specify a commit editor in your configuration"
2776 " file)\n"), not cmdpath and editor)
2768 " file)\n"), not cmdpath and editor)
2777 if not cmdpath and editor != 'vi':
2769 if not cmdpath and editor != 'vi':
2778 problems += 1
2770 problems += 1
2779
2771
2780 # check username
2772 # check username
2781 username = None
2773 username = None
2782 err = None
2774 err = None
2783 try:
2775 try:
2784 username = ui.username()
2776 username = ui.username()
2785 except error.Abort as e:
2777 except error.Abort as e:
2786 err = e
2778 err = e
2787 problems += 1
2779 problems += 1
2788
2780
2789 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2781 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2790 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2782 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2791 " (specify a username in your configuration file)\n"), err)
2783 " (specify a username in your configuration file)\n"), err)
2792
2784
2793 fm.condwrite(not problems, '',
2785 fm.condwrite(not problems, '',
2794 _("no problems detected\n"))
2786 _("no problems detected\n"))
2795 if not problems:
2787 if not problems:
2796 fm.data(problems=problems)
2788 fm.data(problems=problems)
2797 fm.condwrite(problems, 'problems',
2789 fm.condwrite(problems, 'problems',
2798 _("%s problems detected,"
2790 _("%s problems detected,"
2799 " please check your install!\n"), problems)
2791 " please check your install!\n"), problems)
2800 fm.end()
2792 fm.end()
2801
2793
2802 return problems
2794 return problems
2803
2795
2804 @command('debugknown', [], _('REPO ID...'), norepo=True)
2796 @command('debugknown', [], _('REPO ID...'), norepo=True)
2805 def debugknown(ui, repopath, *ids, **opts):
2797 def debugknown(ui, repopath, *ids, **opts):
2806 """test whether node ids are known to a repo
2798 """test whether node ids are known to a repo
2807
2799
2808 Every ID must be a full-length hex node id string. Returns a list of 0s
2800 Every ID must be a full-length hex node id string. Returns a list of 0s
2809 and 1s indicating unknown/known.
2801 and 1s indicating unknown/known.
2810 """
2802 """
2811 repo = hg.peer(ui, opts, repopath)
2803 repo = hg.peer(ui, opts, repopath)
2812 if not repo.capable('known'):
2804 if not repo.capable('known'):
2813 raise error.Abort("known() not supported by target repository")
2805 raise error.Abort("known() not supported by target repository")
2814 flags = repo.known([bin(s) for s in ids])
2806 flags = repo.known([bin(s) for s in ids])
2815 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2807 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2816
2808
2817 @command('debuglabelcomplete', [], _('LABEL...'))
2809 @command('debuglabelcomplete', [], _('LABEL...'))
2818 def debuglabelcomplete(ui, repo, *args):
2810 def debuglabelcomplete(ui, repo, *args):
2819 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2811 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2820 debugnamecomplete(ui, repo, *args)
2812 debugnamecomplete(ui, repo, *args)
2821
2813
2822 @command('debugmergestate', [], '')
2814 @command('debugmergestate', [], '')
2823 def debugmergestate(ui, repo, *args):
2815 def debugmergestate(ui, repo, *args):
2824 """print merge state
2816 """print merge state
2825
2817
2826 Use --verbose to print out information about whether v1 or v2 merge state
2818 Use --verbose to print out information about whether v1 or v2 merge state
2827 was chosen."""
2819 was chosen."""
2828 def _hashornull(h):
2820 def _hashornull(h):
2829 if h == nullhex:
2821 if h == nullhex:
2830 return 'null'
2822 return 'null'
2831 else:
2823 else:
2832 return h
2824 return h
2833
2825
2834 def printrecords(version):
2826 def printrecords(version):
2835 ui.write(('* version %s records\n') % version)
2827 ui.write(('* version %s records\n') % version)
2836 if version == 1:
2828 if version == 1:
2837 records = v1records
2829 records = v1records
2838 else:
2830 else:
2839 records = v2records
2831 records = v2records
2840
2832
2841 for rtype, record in records:
2833 for rtype, record in records:
2842 # pretty print some record types
2834 # pretty print some record types
2843 if rtype == 'L':
2835 if rtype == 'L':
2844 ui.write(('local: %s\n') % record)
2836 ui.write(('local: %s\n') % record)
2845 elif rtype == 'O':
2837 elif rtype == 'O':
2846 ui.write(('other: %s\n') % record)
2838 ui.write(('other: %s\n') % record)
2847 elif rtype == 'm':
2839 elif rtype == 'm':
2848 driver, mdstate = record.split('\0', 1)
2840 driver, mdstate = record.split('\0', 1)
2849 ui.write(('merge driver: %s (state "%s")\n')
2841 ui.write(('merge driver: %s (state "%s")\n')
2850 % (driver, mdstate))
2842 % (driver, mdstate))
2851 elif rtype in 'FDC':
2843 elif rtype in 'FDC':
2852 r = record.split('\0')
2844 r = record.split('\0')
2853 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2845 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2854 if version == 1:
2846 if version == 1:
2855 onode = 'not stored in v1 format'
2847 onode = 'not stored in v1 format'
2856 flags = r[7]
2848 flags = r[7]
2857 else:
2849 else:
2858 onode, flags = r[7:9]
2850 onode, flags = r[7:9]
2859 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2851 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2860 % (f, rtype, state, _hashornull(hash)))
2852 % (f, rtype, state, _hashornull(hash)))
2861 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2853 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2862 ui.write((' ancestor path: %s (node %s)\n')
2854 ui.write((' ancestor path: %s (node %s)\n')
2863 % (afile, _hashornull(anode)))
2855 % (afile, _hashornull(anode)))
2864 ui.write((' other path: %s (node %s)\n')
2856 ui.write((' other path: %s (node %s)\n')
2865 % (ofile, _hashornull(onode)))
2857 % (ofile, _hashornull(onode)))
2866 elif rtype == 'f':
2858 elif rtype == 'f':
2867 filename, rawextras = record.split('\0', 1)
2859 filename, rawextras = record.split('\0', 1)
2868 extras = rawextras.split('\0')
2860 extras = rawextras.split('\0')
2869 i = 0
2861 i = 0
2870 extrastrings = []
2862 extrastrings = []
2871 while i < len(extras):
2863 while i < len(extras):
2872 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2864 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2873 i += 2
2865 i += 2
2874
2866
2875 ui.write(('file extras: %s (%s)\n')
2867 ui.write(('file extras: %s (%s)\n')
2876 % (filename, ', '.join(extrastrings)))
2868 % (filename, ', '.join(extrastrings)))
2877 elif rtype == 'l':
2869 elif rtype == 'l':
2878 labels = record.split('\0', 2)
2870 labels = record.split('\0', 2)
2879 labels = [l for l in labels if len(l) > 0]
2871 labels = [l for l in labels if len(l) > 0]
2880 ui.write(('labels:\n'))
2872 ui.write(('labels:\n'))
2881 ui.write((' local: %s\n' % labels[0]))
2873 ui.write((' local: %s\n' % labels[0]))
2882 ui.write((' other: %s\n' % labels[1]))
2874 ui.write((' other: %s\n' % labels[1]))
2883 if len(labels) > 2:
2875 if len(labels) > 2:
2884 ui.write((' base: %s\n' % labels[2]))
2876 ui.write((' base: %s\n' % labels[2]))
2885 else:
2877 else:
2886 ui.write(('unrecognized entry: %s\t%s\n')
2878 ui.write(('unrecognized entry: %s\t%s\n')
2887 % (rtype, record.replace('\0', '\t')))
2879 % (rtype, record.replace('\0', '\t')))
2888
2880
2889 # Avoid mergestate.read() since it may raise an exception for unsupported
2881 # 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
2882 # merge state records. We shouldn't be doing this, but this is OK since this
2891 # command is pretty low-level.
2883 # command is pretty low-level.
2892 ms = mergemod.mergestate(repo)
2884 ms = mergemod.mergestate(repo)
2893
2885
2894 # sort so that reasonable information is on top
2886 # sort so that reasonable information is on top
2895 v1records = ms._readrecordsv1()
2887 v1records = ms._readrecordsv1()
2896 v2records = ms._readrecordsv2()
2888 v2records = ms._readrecordsv2()
2897 order = 'LOml'
2889 order = 'LOml'
2898 def key(r):
2890 def key(r):
2899 idx = order.find(r[0])
2891 idx = order.find(r[0])
2900 if idx == -1:
2892 if idx == -1:
2901 return (1, r[1])
2893 return (1, r[1])
2902 else:
2894 else:
2903 return (0, idx)
2895 return (0, idx)
2904 v1records.sort(key=key)
2896 v1records.sort(key=key)
2905 v2records.sort(key=key)
2897 v2records.sort(key=key)
2906
2898
2907 if not v1records and not v2records:
2899 if not v1records and not v2records:
2908 ui.write(('no merge state found\n'))
2900 ui.write(('no merge state found\n'))
2909 elif not v2records:
2901 elif not v2records:
2910 ui.note(('no version 2 merge state\n'))
2902 ui.note(('no version 2 merge state\n'))
2911 printrecords(1)
2903 printrecords(1)
2912 elif ms._v1v2match(v1records, v2records):
2904 elif ms._v1v2match(v1records, v2records):
2913 ui.note(('v1 and v2 states match: using v2\n'))
2905 ui.note(('v1 and v2 states match: using v2\n'))
2914 printrecords(2)
2906 printrecords(2)
2915 else:
2907 else:
2916 ui.note(('v1 and v2 states mismatch: using v1\n'))
2908 ui.note(('v1 and v2 states mismatch: using v1\n'))
2917 printrecords(1)
2909 printrecords(1)
2918 if ui.verbose:
2910 if ui.verbose:
2919 printrecords(2)
2911 printrecords(2)
2920
2912
2921 @command('debugnamecomplete', [], _('NAME...'))
2913 @command('debugnamecomplete', [], _('NAME...'))
2922 def debugnamecomplete(ui, repo, *args):
2914 def debugnamecomplete(ui, repo, *args):
2923 '''complete "names" - tags, open branch names, bookmark names'''
2915 '''complete "names" - tags, open branch names, bookmark names'''
2924
2916
2925 names = set()
2917 names = set()
2926 # since we previously only listed open branches, we will handle that
2918 # since we previously only listed open branches, we will handle that
2927 # specially (after this for loop)
2919 # specially (after this for loop)
2928 for name, ns in repo.names.iteritems():
2920 for name, ns in repo.names.iteritems():
2929 if name != 'branches':
2921 if name != 'branches':
2930 names.update(ns.listnames(repo))
2922 names.update(ns.listnames(repo))
2931 names.update(tag for (tag, heads, tip, closed)
2923 names.update(tag for (tag, heads, tip, closed)
2932 in repo.branchmap().iterbranches() if not closed)
2924 in repo.branchmap().iterbranches() if not closed)
2933 completions = set()
2925 completions = set()
2934 if not args:
2926 if not args:
2935 args = ['']
2927 args = ['']
2936 for a in args:
2928 for a in args:
2937 completions.update(n for n in names if n.startswith(a))
2929 completions.update(n for n in names if n.startswith(a))
2938 ui.write('\n'.join(sorted(completions)))
2930 ui.write('\n'.join(sorted(completions)))
2939 ui.write('\n')
2931 ui.write('\n')
2940
2932
2941 @command('debuglocks',
2933 @command('debuglocks',
2942 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2934 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2943 ('W', 'force-wlock', None,
2935 ('W', 'force-wlock', None,
2944 _('free the working state lock (DANGEROUS)'))],
2936 _('free the working state lock (DANGEROUS)'))],
2945 _('[OPTION]...'))
2937 _('[OPTION]...'))
2946 def debuglocks(ui, repo, **opts):
2938 def debuglocks(ui, repo, **opts):
2947 """show or modify state of locks
2939 """show or modify state of locks
2948
2940
2949 By default, this command will show which locks are held. This
2941 By default, this command will show which locks are held. This
2950 includes the user and process holding the lock, the amount of time
2942 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
2943 the lock has been held, and the machine name where the process is
2952 running if it's not local.
2944 running if it's not local.
2953
2945
2954 Locks protect the integrity of Mercurial's data, so should be
2946 Locks protect the integrity of Mercurial's data, so should be
2955 treated with care. System crashes or other interruptions may cause
2947 treated with care. System crashes or other interruptions may cause
2956 locks to not be properly released, though Mercurial will usually
2948 locks to not be properly released, though Mercurial will usually
2957 detect and remove such stale locks automatically.
2949 detect and remove such stale locks automatically.
2958
2950
2959 However, detecting stale locks may not always be possible (for
2951 However, detecting stale locks may not always be possible (for
2960 instance, on a shared filesystem). Removing locks may also be
2952 instance, on a shared filesystem). Removing locks may also be
2961 blocked by filesystem permissions.
2953 blocked by filesystem permissions.
2962
2954
2963 Returns 0 if no locks are held.
2955 Returns 0 if no locks are held.
2964
2956
2965 """
2957 """
2966
2958
2967 if opts.get('force_lock'):
2959 if opts.get('force_lock'):
2968 repo.svfs.unlink('lock')
2960 repo.svfs.unlink('lock')
2969 if opts.get('force_wlock'):
2961 if opts.get('force_wlock'):
2970 repo.vfs.unlink('wlock')
2962 repo.vfs.unlink('wlock')
2971 if opts.get('force_lock') or opts.get('force_lock'):
2963 if opts.get('force_lock') or opts.get('force_lock'):
2972 return 0
2964 return 0
2973
2965
2974 now = time.time()
2966 now = time.time()
2975 held = 0
2967 held = 0
2976
2968
2977 def report(vfs, name, method):
2969 def report(vfs, name, method):
2978 # this causes stale locks to get reaped for more accurate reporting
2970 # this causes stale locks to get reaped for more accurate reporting
2979 try:
2971 try:
2980 l = method(False)
2972 l = method(False)
2981 except error.LockHeld:
2973 except error.LockHeld:
2982 l = None
2974 l = None
2983
2975
2984 if l:
2976 if l:
2985 l.release()
2977 l.release()
2986 else:
2978 else:
2987 try:
2979 try:
2988 stat = vfs.lstat(name)
2980 stat = vfs.lstat(name)
2989 age = now - stat.st_mtime
2981 age = now - stat.st_mtime
2990 user = util.username(stat.st_uid)
2982 user = util.username(stat.st_uid)
2991 locker = vfs.readlock(name)
2983 locker = vfs.readlock(name)
2992 if ":" in locker:
2984 if ":" in locker:
2993 host, pid = locker.split(':')
2985 host, pid = locker.split(':')
2994 if host == socket.gethostname():
2986 if host == socket.gethostname():
2995 locker = 'user %s, process %s' % (user, pid)
2987 locker = 'user %s, process %s' % (user, pid)
2996 else:
2988 else:
2997 locker = 'user %s, process %s, host %s' \
2989 locker = 'user %s, process %s, host %s' \
2998 % (user, pid, host)
2990 % (user, pid, host)
2999 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2991 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3000 return 1
2992 return 1
3001 except OSError as e:
2993 except OSError as e:
3002 if e.errno != errno.ENOENT:
2994 if e.errno != errno.ENOENT:
3003 raise
2995 raise
3004
2996
3005 ui.write(("%-6s free\n") % (name + ":"))
2997 ui.write(("%-6s free\n") % (name + ":"))
3006 return 0
2998 return 0
3007
2999
3008 held += report(repo.svfs, "lock", repo.lock)
3000 held += report(repo.svfs, "lock", repo.lock)
3009 held += report(repo.vfs, "wlock", repo.wlock)
3001 held += report(repo.vfs, "wlock", repo.wlock)
3010
3002
3011 return held
3003 return held
3012
3004
3013 @command('debugobsolete',
3005 @command('debugobsolete',
3014 [('', 'flags', 0, _('markers flag')),
3006 [('', 'flags', 0, _('markers flag')),
3015 ('', 'record-parents', False,
3007 ('', 'record-parents', False,
3016 _('record parent information for the precursor')),
3008 _('record parent information for the precursor')),
3017 ('r', 'rev', [], _('display markers relevant to REV')),
3009 ('r', 'rev', [], _('display markers relevant to REV')),
3018 ('', 'index', False, _('display index of the marker')),
3010 ('', 'index', False, _('display index of the marker')),
3019 ('', 'delete', [], _('delete markers specified by indices')),
3011 ('', 'delete', [], _('delete markers specified by indices')),
3020 ] + commitopts2 + formatteropts,
3012 ] + commitopts2 + formatteropts,
3021 _('[OBSOLETED [REPLACEMENT ...]]'))
3013 _('[OBSOLETED [REPLACEMENT ...]]'))
3022 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3014 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3023 """create arbitrary obsolete marker
3015 """create arbitrary obsolete marker
3024
3016
3025 With no arguments, displays the list of obsolescence markers."""
3017 With no arguments, displays the list of obsolescence markers."""
3026
3018
3027 def parsenodeid(s):
3019 def parsenodeid(s):
3028 try:
3020 try:
3029 # We do not use revsingle/revrange functions here to accept
3021 # We do not use revsingle/revrange functions here to accept
3030 # arbitrary node identifiers, possibly not present in the
3022 # arbitrary node identifiers, possibly not present in the
3031 # local repository.
3023 # local repository.
3032 n = bin(s)
3024 n = bin(s)
3033 if len(n) != len(nullid):
3025 if len(n) != len(nullid):
3034 raise TypeError()
3026 raise TypeError()
3035 return n
3027 return n
3036 except TypeError:
3028 except TypeError:
3037 raise error.Abort('changeset references must be full hexadecimal '
3029 raise error.Abort('changeset references must be full hexadecimal '
3038 'node identifiers')
3030 'node identifiers')
3039
3031
3040 if opts.get('delete'):
3032 if opts.get('delete'):
3041 indices = []
3033 indices = []
3042 for v in opts.get('delete'):
3034 for v in opts.get('delete'):
3043 try:
3035 try:
3044 indices.append(int(v))
3036 indices.append(int(v))
3045 except ValueError:
3037 except ValueError:
3046 raise error.Abort(_('invalid index value: %r') % v,
3038 raise error.Abort(_('invalid index value: %r') % v,
3047 hint=_('use integers for indices'))
3039 hint=_('use integers for indices'))
3048
3040
3049 if repo.currenttransaction():
3041 if repo.currenttransaction():
3050 raise error.Abort(_('cannot delete obsmarkers in the middle '
3042 raise error.Abort(_('cannot delete obsmarkers in the middle '
3051 'of transaction.'))
3043 'of transaction.'))
3052
3044
3053 with repo.lock():
3045 with repo.lock():
3054 n = repair.deleteobsmarkers(repo.obsstore, indices)
3046 n = repair.deleteobsmarkers(repo.obsstore, indices)
3055 ui.write(_('deleted %i obsolescense markers\n') % n)
3047 ui.write(_('deleted %i obsolescense markers\n') % n)
3056
3048
3057 return
3049 return
3058
3050
3059 if precursor is not None:
3051 if precursor is not None:
3060 if opts['rev']:
3052 if opts['rev']:
3061 raise error.Abort('cannot select revision when creating marker')
3053 raise error.Abort('cannot select revision when creating marker')
3062 metadata = {}
3054 metadata = {}
3063 metadata['user'] = opts['user'] or ui.username()
3055 metadata['user'] = opts['user'] or ui.username()
3064 succs = tuple(parsenodeid(succ) for succ in successors)
3056 succs = tuple(parsenodeid(succ) for succ in successors)
3065 l = repo.lock()
3057 l = repo.lock()
3066 try:
3058 try:
3067 tr = repo.transaction('debugobsolete')
3059 tr = repo.transaction('debugobsolete')
3068 try:
3060 try:
3069 date = opts.get('date')
3061 date = opts.get('date')
3070 if date:
3062 if date:
3071 date = util.parsedate(date)
3063 date = util.parsedate(date)
3072 else:
3064 else:
3073 date = None
3065 date = None
3074 prec = parsenodeid(precursor)
3066 prec = parsenodeid(precursor)
3075 parents = None
3067 parents = None
3076 if opts['record_parents']:
3068 if opts['record_parents']:
3077 if prec not in repo.unfiltered():
3069 if prec not in repo.unfiltered():
3078 raise error.Abort('cannot used --record-parents on '
3070 raise error.Abort('cannot used --record-parents on '
3079 'unknown changesets')
3071 'unknown changesets')
3080 parents = repo.unfiltered()[prec].parents()
3072 parents = repo.unfiltered()[prec].parents()
3081 parents = tuple(p.node() for p in parents)
3073 parents = tuple(p.node() for p in parents)
3082 repo.obsstore.create(tr, prec, succs, opts['flags'],
3074 repo.obsstore.create(tr, prec, succs, opts['flags'],
3083 parents=parents, date=date,
3075 parents=parents, date=date,
3084 metadata=metadata)
3076 metadata=metadata)
3085 tr.close()
3077 tr.close()
3086 except ValueError as exc:
3078 except ValueError as exc:
3087 raise error.Abort(_('bad obsmarker input: %s') % exc)
3079 raise error.Abort(_('bad obsmarker input: %s') % exc)
3088 finally:
3080 finally:
3089 tr.release()
3081 tr.release()
3090 finally:
3082 finally:
3091 l.release()
3083 l.release()
3092 else:
3084 else:
3093 if opts['rev']:
3085 if opts['rev']:
3094 revs = scmutil.revrange(repo, opts['rev'])
3086 revs = scmutil.revrange(repo, opts['rev'])
3095 nodes = [repo[r].node() for r in revs]
3087 nodes = [repo[r].node() for r in revs]
3096 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3088 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3097 markers.sort(key=lambda x: x._data)
3089 markers.sort(key=lambda x: x._data)
3098 else:
3090 else:
3099 markers = obsolete.getmarkers(repo)
3091 markers = obsolete.getmarkers(repo)
3100
3092
3101 markerstoiter = markers
3093 markerstoiter = markers
3102 isrelevant = lambda m: True
3094 isrelevant = lambda m: True
3103 if opts.get('rev') and opts.get('index'):
3095 if opts.get('rev') and opts.get('index'):
3104 markerstoiter = obsolete.getmarkers(repo)
3096 markerstoiter = obsolete.getmarkers(repo)
3105 markerset = set(markers)
3097 markerset = set(markers)
3106 isrelevant = lambda m: m in markerset
3098 isrelevant = lambda m: m in markerset
3107
3099
3108 fm = ui.formatter('debugobsolete', opts)
3100 fm = ui.formatter('debugobsolete', opts)
3109 for i, m in enumerate(markerstoiter):
3101 for i, m in enumerate(markerstoiter):
3110 if not isrelevant(m):
3102 if not isrelevant(m):
3111 # marker can be irrelevant when we're iterating over a set
3103 # marker can be irrelevant when we're iterating over a set
3112 # of markers (markerstoiter) which is bigger than the set
3104 # of markers (markerstoiter) which is bigger than the set
3113 # of markers we want to display (markers)
3105 # of markers we want to display (markers)
3114 # this can happen if both --index and --rev options are
3106 # this can happen if both --index and --rev options are
3115 # provided and thus we need to iterate over all of the markers
3107 # provided and thus we need to iterate over all of the markers
3116 # to get the correct indices, but only display the ones that
3108 # to get the correct indices, but only display the ones that
3117 # are relevant to --rev value
3109 # are relevant to --rev value
3118 continue
3110 continue
3119 fm.startitem()
3111 fm.startitem()
3120 ind = i if opts.get('index') else None
3112 ind = i if opts.get('index') else None
3121 cmdutil.showmarker(fm, m, index=ind)
3113 cmdutil.showmarker(fm, m, index=ind)
3122 fm.end()
3114 fm.end()
3123
3115
3124 @command('debugpathcomplete',
3116 @command('debugpathcomplete',
3125 [('f', 'full', None, _('complete an entire path')),
3117 [('f', 'full', None, _('complete an entire path')),
3126 ('n', 'normal', None, _('show only normal files')),
3118 ('n', 'normal', None, _('show only normal files')),
3127 ('a', 'added', None, _('show only added files')),
3119 ('a', 'added', None, _('show only added files')),
3128 ('r', 'removed', None, _('show only removed files'))],
3120 ('r', 'removed', None, _('show only removed files'))],
3129 _('FILESPEC...'))
3121 _('FILESPEC...'))
3130 def debugpathcomplete(ui, repo, *specs, **opts):
3122 def debugpathcomplete(ui, repo, *specs, **opts):
3131 '''complete part or all of a tracked path
3123 '''complete part or all of a tracked path
3132
3124
3133 This command supports shells that offer path name completion. It
3125 This command supports shells that offer path name completion. It
3134 currently completes only files already known to the dirstate.
3126 currently completes only files already known to the dirstate.
3135
3127
3136 Completion extends only to the next path segment unless
3128 Completion extends only to the next path segment unless
3137 --full is specified, in which case entire paths are used.'''
3129 --full is specified, in which case entire paths are used.'''
3138
3130
3139 def complete(path, acceptable):
3131 def complete(path, acceptable):
3140 dirstate = repo.dirstate
3132 dirstate = repo.dirstate
3141 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3133 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3142 rootdir = repo.root + os.sep
3134 rootdir = repo.root + os.sep
3143 if spec != repo.root and not spec.startswith(rootdir):
3135 if spec != repo.root and not spec.startswith(rootdir):
3144 return [], []
3136 return [], []
3145 if os.path.isdir(spec):
3137 if os.path.isdir(spec):
3146 spec += '/'
3138 spec += '/'
3147 spec = spec[len(rootdir):]
3139 spec = spec[len(rootdir):]
3148 fixpaths = os.sep != '/'
3140 fixpaths = os.sep != '/'
3149 if fixpaths:
3141 if fixpaths:
3150 spec = spec.replace(os.sep, '/')
3142 spec = spec.replace(os.sep, '/')
3151 speclen = len(spec)
3143 speclen = len(spec)
3152 fullpaths = opts['full']
3144 fullpaths = opts['full']
3153 files, dirs = set(), set()
3145 files, dirs = set(), set()
3154 adddir, addfile = dirs.add, files.add
3146 adddir, addfile = dirs.add, files.add
3155 for f, st in dirstate.iteritems():
3147 for f, st in dirstate.iteritems():
3156 if f.startswith(spec) and st[0] in acceptable:
3148 if f.startswith(spec) and st[0] in acceptable:
3157 if fixpaths:
3149 if fixpaths:
3158 f = f.replace('/', os.sep)
3150 f = f.replace('/', os.sep)
3159 if fullpaths:
3151 if fullpaths:
3160 addfile(f)
3152 addfile(f)
3161 continue
3153 continue
3162 s = f.find(os.sep, speclen)
3154 s = f.find(os.sep, speclen)
3163 if s >= 0:
3155 if s >= 0:
3164 adddir(f[:s])
3156 adddir(f[:s])
3165 else:
3157 else:
3166 addfile(f)
3158 addfile(f)
3167 return files, dirs
3159 return files, dirs
3168
3160
3169 acceptable = ''
3161 acceptable = ''
3170 if opts['normal']:
3162 if opts['normal']:
3171 acceptable += 'nm'
3163 acceptable += 'nm'
3172 if opts['added']:
3164 if opts['added']:
3173 acceptable += 'a'
3165 acceptable += 'a'
3174 if opts['removed']:
3166 if opts['removed']:
3175 acceptable += 'r'
3167 acceptable += 'r'
3176 cwd = repo.getcwd()
3168 cwd = repo.getcwd()
3177 if not specs:
3169 if not specs:
3178 specs = ['.']
3170 specs = ['.']
3179
3171
3180 files, dirs = set(), set()
3172 files, dirs = set(), set()
3181 for spec in specs:
3173 for spec in specs:
3182 f, d = complete(spec, acceptable or 'nmar')
3174 f, d = complete(spec, acceptable or 'nmar')
3183 files.update(f)
3175 files.update(f)
3184 dirs.update(d)
3176 dirs.update(d)
3185 files.update(dirs)
3177 files.update(dirs)
3186 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3178 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3187 ui.write('\n')
3179 ui.write('\n')
3188
3180
3189 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3181 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3190 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3182 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3191 '''access the pushkey key/value protocol
3183 '''access the pushkey key/value protocol
3192
3184
3193 With two args, list the keys in the given namespace.
3185 With two args, list the keys in the given namespace.
3194
3186
3195 With five args, set a key to new if it currently is set to old.
3187 With five args, set a key to new if it currently is set to old.
3196 Reports success or failure.
3188 Reports success or failure.
3197 '''
3189 '''
3198
3190
3199 target = hg.peer(ui, {}, repopath)
3191 target = hg.peer(ui, {}, repopath)
3200 if keyinfo:
3192 if keyinfo:
3201 key, old, new = keyinfo
3193 key, old, new = keyinfo
3202 r = target.pushkey(namespace, key, old, new)
3194 r = target.pushkey(namespace, key, old, new)
3203 ui.status(str(r) + '\n')
3195 ui.status(str(r) + '\n')
3204 return not r
3196 return not r
3205 else:
3197 else:
3206 for k, v in sorted(target.listkeys(namespace).iteritems()):
3198 for k, v in sorted(target.listkeys(namespace).iteritems()):
3207 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3199 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3208 v.encode('string-escape')))
3200 v.encode('string-escape')))
3209
3201
3210 @command('debugpvec', [], _('A B'))
3202 @command('debugpvec', [], _('A B'))
3211 def debugpvec(ui, repo, a, b=None):
3203 def debugpvec(ui, repo, a, b=None):
3212 ca = scmutil.revsingle(repo, a)
3204 ca = scmutil.revsingle(repo, a)
3213 cb = scmutil.revsingle(repo, b)
3205 cb = scmutil.revsingle(repo, b)
3214 pa = pvec.ctxpvec(ca)
3206 pa = pvec.ctxpvec(ca)
3215 pb = pvec.ctxpvec(cb)
3207 pb = pvec.ctxpvec(cb)
3216 if pa == pb:
3208 if pa == pb:
3217 rel = "="
3209 rel = "="
3218 elif pa > pb:
3210 elif pa > pb:
3219 rel = ">"
3211 rel = ">"
3220 elif pa < pb:
3212 elif pa < pb:
3221 rel = "<"
3213 rel = "<"
3222 elif pa | pb:
3214 elif pa | pb:
3223 rel = "|"
3215 rel = "|"
3224 ui.write(_("a: %s\n") % pa)
3216 ui.write(_("a: %s\n") % pa)
3225 ui.write(_("b: %s\n") % pb)
3217 ui.write(_("b: %s\n") % pb)
3226 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3218 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") %
3219 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3228 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3220 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3229 pa.distance(pb), rel))
3221 pa.distance(pb), rel))
3230
3222
3231 @command('debugrebuilddirstate|debugrebuildstate',
3223 @command('debugrebuilddirstate|debugrebuildstate',
3232 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3224 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3233 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3225 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3234 'the working copy parent')),
3226 'the working copy parent')),
3235 ],
3227 ],
3236 _('[-r REV]'))
3228 _('[-r REV]'))
3237 def debugrebuilddirstate(ui, repo, rev, **opts):
3229 def debugrebuilddirstate(ui, repo, rev, **opts):
3238 """rebuild the dirstate as it would look like for the given revision
3230 """rebuild the dirstate as it would look like for the given revision
3239
3231
3240 If no revision is specified the first current parent will be used.
3232 If no revision is specified the first current parent will be used.
3241
3233
3242 The dirstate will be set to the files of the given revision.
3234 The dirstate will be set to the files of the given revision.
3243 The actual working directory content or existing dirstate
3235 The actual working directory content or existing dirstate
3244 information such as adds or removes is not considered.
3236 information such as adds or removes is not considered.
3245
3237
3246 ``minimal`` will only rebuild the dirstate status for files that claim to be
3238 ``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
3239 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
3240 manifest but are not in the dirstate. It will not change adds, removes, or
3249 modified files that are in the working copy parent.
3241 modified files that are in the working copy parent.
3250
3242
3251 One use of this command is to make the next :hg:`status` invocation
3243 One use of this command is to make the next :hg:`status` invocation
3252 check the actual file content.
3244 check the actual file content.
3253 """
3245 """
3254 ctx = scmutil.revsingle(repo, rev)
3246 ctx = scmutil.revsingle(repo, rev)
3255 with repo.wlock():
3247 with repo.wlock():
3256 dirstate = repo.dirstate
3248 dirstate = repo.dirstate
3257 changedfiles = None
3249 changedfiles = None
3258 # See command doc for what minimal does.
3250 # See command doc for what minimal does.
3259 if opts.get('minimal'):
3251 if opts.get('minimal'):
3260 manifestfiles = set(ctx.manifest().keys())
3252 manifestfiles = set(ctx.manifest().keys())
3261 dirstatefiles = set(dirstate)
3253 dirstatefiles = set(dirstate)
3262 manifestonly = manifestfiles - dirstatefiles
3254 manifestonly = manifestfiles - dirstatefiles
3263 dsonly = dirstatefiles - manifestfiles
3255 dsonly = dirstatefiles - manifestfiles
3264 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3256 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3265 changedfiles = manifestonly | dsnotadded
3257 changedfiles = manifestonly | dsnotadded
3266
3258
3267 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3259 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3268
3260
3269 @command('debugrebuildfncache', [], '')
3261 @command('debugrebuildfncache', [], '')
3270 def debugrebuildfncache(ui, repo):
3262 def debugrebuildfncache(ui, repo):
3271 """rebuild the fncache file"""
3263 """rebuild the fncache file"""
3272 repair.rebuildfncache(ui, repo)
3264 repair.rebuildfncache(ui, repo)
3273
3265
3274 @command('debugrename',
3266 @command('debugrename',
3275 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3267 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3276 _('[-r REV] FILE'))
3268 _('[-r REV] FILE'))
3277 def debugrename(ui, repo, file1, *pats, **opts):
3269 def debugrename(ui, repo, file1, *pats, **opts):
3278 """dump rename information"""
3270 """dump rename information"""
3279
3271
3280 ctx = scmutil.revsingle(repo, opts.get('rev'))
3272 ctx = scmutil.revsingle(repo, opts.get('rev'))
3281 m = scmutil.match(ctx, (file1,) + pats, opts)
3273 m = scmutil.match(ctx, (file1,) + pats, opts)
3282 for abs in ctx.walk(m):
3274 for abs in ctx.walk(m):
3283 fctx = ctx[abs]
3275 fctx = ctx[abs]
3284 o = fctx.filelog().renamed(fctx.filenode())
3276 o = fctx.filelog().renamed(fctx.filenode())
3285 rel = m.rel(abs)
3277 rel = m.rel(abs)
3286 if o:
3278 if o:
3287 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3279 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3288 else:
3280 else:
3289 ui.write(_("%s not renamed\n") % rel)
3281 ui.write(_("%s not renamed\n") % rel)
3290
3282
3291 @command('debugrevlog', debugrevlogopts +
3283 @command('debugrevlog', debugrevlogopts +
3292 [('d', 'dump', False, _('dump index data'))],
3284 [('d', 'dump', False, _('dump index data'))],
3293 _('-c|-m|FILE'),
3285 _('-c|-m|FILE'),
3294 optionalrepo=True)
3286 optionalrepo=True)
3295 def debugrevlog(ui, repo, file_=None, **opts):
3287 def debugrevlog(ui, repo, file_=None, **opts):
3296 """show data and statistics about a revlog"""
3288 """show data and statistics about a revlog"""
3297 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3289 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3298
3290
3299 if opts.get("dump"):
3291 if opts.get("dump"):
3300 numrevs = len(r)
3292 numrevs = len(r)
3301 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3293 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3302 " rawsize totalsize compression heads chainlen\n"))
3294 " rawsize totalsize compression heads chainlen\n"))
3303 ts = 0
3295 ts = 0
3304 heads = set()
3296 heads = set()
3305
3297
3306 for rev in xrange(numrevs):
3298 for rev in xrange(numrevs):
3307 dbase = r.deltaparent(rev)
3299 dbase = r.deltaparent(rev)
3308 if dbase == -1:
3300 if dbase == -1:
3309 dbase = rev
3301 dbase = rev
3310 cbase = r.chainbase(rev)
3302 cbase = r.chainbase(rev)
3311 clen = r.chainlen(rev)
3303 clen = r.chainlen(rev)
3312 p1, p2 = r.parentrevs(rev)
3304 p1, p2 = r.parentrevs(rev)
3313 rs = r.rawsize(rev)
3305 rs = r.rawsize(rev)
3314 ts = ts + rs
3306 ts = ts + rs
3315 heads -= set(r.parentrevs(rev))
3307 heads -= set(r.parentrevs(rev))
3316 heads.add(rev)
3308 heads.add(rev)
3317 try:
3309 try:
3318 compression = ts / r.end(rev)
3310 compression = ts / r.end(rev)
3319 except ZeroDivisionError:
3311 except ZeroDivisionError:
3320 compression = 0
3312 compression = 0
3321 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3313 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3322 "%11d %5d %8d\n" %
3314 "%11d %5d %8d\n" %
3323 (rev, p1, p2, r.start(rev), r.end(rev),
3315 (rev, p1, p2, r.start(rev), r.end(rev),
3324 r.start(dbase), r.start(cbase),
3316 r.start(dbase), r.start(cbase),
3325 r.start(p1), r.start(p2),
3317 r.start(p1), r.start(p2),
3326 rs, ts, compression, len(heads), clen))
3318 rs, ts, compression, len(heads), clen))
3327 return 0
3319 return 0
3328
3320
3329 v = r.version
3321 v = r.version
3330 format = v & 0xFFFF
3322 format = v & 0xFFFF
3331 flags = []
3323 flags = []
3332 gdelta = False
3324 gdelta = False
3333 if v & revlog.REVLOGNGINLINEDATA:
3325 if v & revlog.REVLOGNGINLINEDATA:
3334 flags.append('inline')
3326 flags.append('inline')
3335 if v & revlog.REVLOGGENERALDELTA:
3327 if v & revlog.REVLOGGENERALDELTA:
3336 gdelta = True
3328 gdelta = True
3337 flags.append('generaldelta')
3329 flags.append('generaldelta')
3338 if not flags:
3330 if not flags:
3339 flags = ['(none)']
3331 flags = ['(none)']
3340
3332
3341 nummerges = 0
3333 nummerges = 0
3342 numfull = 0
3334 numfull = 0
3343 numprev = 0
3335 numprev = 0
3344 nump1 = 0
3336 nump1 = 0
3345 nump2 = 0
3337 nump2 = 0
3346 numother = 0
3338 numother = 0
3347 nump1prev = 0
3339 nump1prev = 0
3348 nump2prev = 0
3340 nump2prev = 0
3349 chainlengths = []
3341 chainlengths = []
3350
3342
3351 datasize = [None, 0, 0]
3343 datasize = [None, 0, 0]
3352 fullsize = [None, 0, 0]
3344 fullsize = [None, 0, 0]
3353 deltasize = [None, 0, 0]
3345 deltasize = [None, 0, 0]
3354
3346
3355 def addsize(size, l):
3347 def addsize(size, l):
3356 if l[0] is None or size < l[0]:
3348 if l[0] is None or size < l[0]:
3357 l[0] = size
3349 l[0] = size
3358 if size > l[1]:
3350 if size > l[1]:
3359 l[1] = size
3351 l[1] = size
3360 l[2] += size
3352 l[2] += size
3361
3353
3362 numrevs = len(r)
3354 numrevs = len(r)
3363 for rev in xrange(numrevs):
3355 for rev in xrange(numrevs):
3364 p1, p2 = r.parentrevs(rev)
3356 p1, p2 = r.parentrevs(rev)
3365 delta = r.deltaparent(rev)
3357 delta = r.deltaparent(rev)
3366 if format > 0:
3358 if format > 0:
3367 addsize(r.rawsize(rev), datasize)
3359 addsize(r.rawsize(rev), datasize)
3368 if p2 != nullrev:
3360 if p2 != nullrev:
3369 nummerges += 1
3361 nummerges += 1
3370 size = r.length(rev)
3362 size = r.length(rev)
3371 if delta == nullrev:
3363 if delta == nullrev:
3372 chainlengths.append(0)
3364 chainlengths.append(0)
3373 numfull += 1
3365 numfull += 1
3374 addsize(size, fullsize)
3366 addsize(size, fullsize)
3375 else:
3367 else:
3376 chainlengths.append(chainlengths[delta] + 1)
3368 chainlengths.append(chainlengths[delta] + 1)
3377 addsize(size, deltasize)
3369 addsize(size, deltasize)
3378 if delta == rev - 1:
3370 if delta == rev - 1:
3379 numprev += 1
3371 numprev += 1
3380 if delta == p1:
3372 if delta == p1:
3381 nump1prev += 1
3373 nump1prev += 1
3382 elif delta == p2:
3374 elif delta == p2:
3383 nump2prev += 1
3375 nump2prev += 1
3384 elif delta == p1:
3376 elif delta == p1:
3385 nump1 += 1
3377 nump1 += 1
3386 elif delta == p2:
3378 elif delta == p2:
3387 nump2 += 1
3379 nump2 += 1
3388 elif delta != nullrev:
3380 elif delta != nullrev:
3389 numother += 1
3381 numother += 1
3390
3382
3391 # Adjust size min value for empty cases
3383 # Adjust size min value for empty cases
3392 for size in (datasize, fullsize, deltasize):
3384 for size in (datasize, fullsize, deltasize):
3393 if size[0] is None:
3385 if size[0] is None:
3394 size[0] = 0
3386 size[0] = 0
3395
3387
3396 numdeltas = numrevs - numfull
3388 numdeltas = numrevs - numfull
3397 numoprev = numprev - nump1prev - nump2prev
3389 numoprev = numprev - nump1prev - nump2prev
3398 totalrawsize = datasize[2]
3390 totalrawsize = datasize[2]
3399 datasize[2] /= numrevs
3391 datasize[2] /= numrevs
3400 fulltotal = fullsize[2]
3392 fulltotal = fullsize[2]
3401 fullsize[2] /= numfull
3393 fullsize[2] /= numfull
3402 deltatotal = deltasize[2]
3394 deltatotal = deltasize[2]
3403 if numrevs - numfull > 0:
3395 if numrevs - numfull > 0:
3404 deltasize[2] /= numrevs - numfull
3396 deltasize[2] /= numrevs - numfull
3405 totalsize = fulltotal + deltatotal
3397 totalsize = fulltotal + deltatotal
3406 avgchainlen = sum(chainlengths) / numrevs
3398 avgchainlen = sum(chainlengths) / numrevs
3407 maxchainlen = max(chainlengths)
3399 maxchainlen = max(chainlengths)
3408 compratio = 1
3400 compratio = 1
3409 if totalsize:
3401 if totalsize:
3410 compratio = totalrawsize / totalsize
3402 compratio = totalrawsize / totalsize
3411
3403
3412 basedfmtstr = '%%%dd\n'
3404 basedfmtstr = '%%%dd\n'
3413 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3405 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3414
3406
3415 def dfmtstr(max):
3407 def dfmtstr(max):
3416 return basedfmtstr % len(str(max))
3408 return basedfmtstr % len(str(max))
3417 def pcfmtstr(max, padding=0):
3409 def pcfmtstr(max, padding=0):
3418 return basepcfmtstr % (len(str(max)), ' ' * padding)
3410 return basepcfmtstr % (len(str(max)), ' ' * padding)
3419
3411
3420 def pcfmt(value, total):
3412 def pcfmt(value, total):
3421 if total:
3413 if total:
3422 return (value, 100 * float(value) / total)
3414 return (value, 100 * float(value) / total)
3423 else:
3415 else:
3424 return value, 100.0
3416 return value, 100.0
3425
3417
3426 ui.write(('format : %d\n') % format)
3418 ui.write(('format : %d\n') % format)
3427 ui.write(('flags : %s\n') % ', '.join(flags))
3419 ui.write(('flags : %s\n') % ', '.join(flags))
3428
3420
3429 ui.write('\n')
3421 ui.write('\n')
3430 fmt = pcfmtstr(totalsize)
3422 fmt = pcfmtstr(totalsize)
3431 fmt2 = dfmtstr(totalsize)
3423 fmt2 = dfmtstr(totalsize)
3432 ui.write(('revisions : ') + fmt2 % numrevs)
3424 ui.write(('revisions : ') + fmt2 % numrevs)
3433 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3425 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3434 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3426 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3435 ui.write(('revisions : ') + fmt2 % numrevs)
3427 ui.write(('revisions : ') + fmt2 % numrevs)
3436 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3428 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3437 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3429 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3438 ui.write(('revision size : ') + fmt2 % totalsize)
3430 ui.write(('revision size : ') + fmt2 % totalsize)
3439 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3431 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3440 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3432 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3441
3433
3442 ui.write('\n')
3434 ui.write('\n')
3443 fmt = dfmtstr(max(avgchainlen, compratio))
3435 fmt = dfmtstr(max(avgchainlen, compratio))
3444 ui.write(('avg chain length : ') + fmt % avgchainlen)
3436 ui.write(('avg chain length : ') + fmt % avgchainlen)
3445 ui.write(('max chain length : ') + fmt % maxchainlen)
3437 ui.write(('max chain length : ') + fmt % maxchainlen)
3446 ui.write(('compression ratio : ') + fmt % compratio)
3438 ui.write(('compression ratio : ') + fmt % compratio)
3447
3439
3448 if format > 0:
3440 if format > 0:
3449 ui.write('\n')
3441 ui.write('\n')
3450 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3442 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3451 % tuple(datasize))
3443 % tuple(datasize))
3452 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3444 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3453 % tuple(fullsize))
3445 % tuple(fullsize))
3454 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3446 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3455 % tuple(deltasize))
3447 % tuple(deltasize))
3456
3448
3457 if numdeltas > 0:
3449 if numdeltas > 0:
3458 ui.write('\n')
3450 ui.write('\n')
3459 fmt = pcfmtstr(numdeltas)
3451 fmt = pcfmtstr(numdeltas)
3460 fmt2 = pcfmtstr(numdeltas, 4)
3452 fmt2 = pcfmtstr(numdeltas, 4)
3461 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3453 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3462 if numprev > 0:
3454 if numprev > 0:
3463 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3455 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3464 numprev))
3456 numprev))
3465 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3457 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3466 numprev))
3458 numprev))
3467 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3459 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3468 numprev))
3460 numprev))
3469 if gdelta:
3461 if gdelta:
3470 ui.write(('deltas against p1 : ')
3462 ui.write(('deltas against p1 : ')
3471 + fmt % pcfmt(nump1, numdeltas))
3463 + fmt % pcfmt(nump1, numdeltas))
3472 ui.write(('deltas against p2 : ')
3464 ui.write(('deltas against p2 : ')
3473 + fmt % pcfmt(nump2, numdeltas))
3465 + fmt % pcfmt(nump2, numdeltas))
3474 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3466 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3475 numdeltas))
3467 numdeltas))
3476
3468
3477 @command('debugrevspec',
3469 @command('debugrevspec',
3478 [('', 'optimize', None,
3470 [('', 'optimize', None,
3479 _('print parsed tree after optimizing (DEPRECATED)')),
3471 _('print parsed tree after optimizing (DEPRECATED)')),
3480 ('p', 'show-stage', [],
3472 ('p', 'show-stage', [],
3481 _('print parsed tree at the given stage'), _('NAME')),
3473 _('print parsed tree at the given stage'), _('NAME')),
3482 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3474 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3483 ('', 'verify-optimized', False, _('verify optimized result')),
3475 ('', 'verify-optimized', False, _('verify optimized result')),
3484 ],
3476 ],
3485 ('REVSPEC'))
3477 ('REVSPEC'))
3486 def debugrevspec(ui, repo, expr, **opts):
3478 def debugrevspec(ui, repo, expr, **opts):
3487 """parse and apply a revision specification
3479 """parse and apply a revision specification
3488
3480
3489 Use -p/--show-stage option to print the parsed tree at the given stages.
3481 Use -p/--show-stage option to print the parsed tree at the given stages.
3490 Use -p all to print tree at every stage.
3482 Use -p all to print tree at every stage.
3491
3483
3492 Use --verify-optimized to compare the optimized result with the unoptimized
3484 Use --verify-optimized to compare the optimized result with the unoptimized
3493 one. Returns 1 if the optimized result differs.
3485 one. Returns 1 if the optimized result differs.
3494 """
3486 """
3495 stages = [
3487 stages = [
3496 ('parsed', lambda tree: tree),
3488 ('parsed', lambda tree: tree),
3497 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3489 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3498 ('concatenated', revset.foldconcat),
3490 ('concatenated', revset.foldconcat),
3499 ('analyzed', revset.analyze),
3491 ('analyzed', revset.analyze),
3500 ('optimized', revset.optimize),
3492 ('optimized', revset.optimize),
3501 ]
3493 ]
3502 if opts['no_optimized']:
3494 if opts['no_optimized']:
3503 stages = stages[:-1]
3495 stages = stages[:-1]
3504 if opts['verify_optimized'] and opts['no_optimized']:
3496 if opts['verify_optimized'] and opts['no_optimized']:
3505 raise error.Abort(_('cannot use --verify-optimized with '
3497 raise error.Abort(_('cannot use --verify-optimized with '
3506 '--no-optimized'))
3498 '--no-optimized'))
3507 stagenames = set(n for n, f in stages)
3499 stagenames = set(n for n, f in stages)
3508
3500
3509 showalways = set()
3501 showalways = set()
3510 showchanged = set()
3502 showchanged = set()
3511 if ui.verbose and not opts['show_stage']:
3503 if ui.verbose and not opts['show_stage']:
3512 # show parsed tree by --verbose (deprecated)
3504 # show parsed tree by --verbose (deprecated)
3513 showalways.add('parsed')
3505 showalways.add('parsed')
3514 showchanged.update(['expanded', 'concatenated'])
3506 showchanged.update(['expanded', 'concatenated'])
3515 if opts['optimize']:
3507 if opts['optimize']:
3516 showalways.add('optimized')
3508 showalways.add('optimized')
3517 if opts['show_stage'] and opts['optimize']:
3509 if opts['show_stage'] and opts['optimize']:
3518 raise error.Abort(_('cannot use --optimize with --show-stage'))
3510 raise error.Abort(_('cannot use --optimize with --show-stage'))
3519 if opts['show_stage'] == ['all']:
3511 if opts['show_stage'] == ['all']:
3520 showalways.update(stagenames)
3512 showalways.update(stagenames)
3521 else:
3513 else:
3522 for n in opts['show_stage']:
3514 for n in opts['show_stage']:
3523 if n not in stagenames:
3515 if n not in stagenames:
3524 raise error.Abort(_('invalid stage name: %s') % n)
3516 raise error.Abort(_('invalid stage name: %s') % n)
3525 showalways.update(opts['show_stage'])
3517 showalways.update(opts['show_stage'])
3526
3518
3527 treebystage = {}
3519 treebystage = {}
3528 printedtree = None
3520 printedtree = None
3529 tree = revset.parse(expr, lookup=repo.__contains__)
3521 tree = revset.parse(expr, lookup=repo.__contains__)
3530 for n, f in stages:
3522 for n, f in stages:
3531 treebystage[n] = tree = f(tree)
3523 treebystage[n] = tree = f(tree)
3532 if n in showalways or (n in showchanged and tree != printedtree):
3524 if n in showalways or (n in showchanged and tree != printedtree):
3533 if opts['show_stage'] or n != 'parsed':
3525 if opts['show_stage'] or n != 'parsed':
3534 ui.write(("* %s:\n") % n)
3526 ui.write(("* %s:\n") % n)
3535 ui.write(revset.prettyformat(tree), "\n")
3527 ui.write(revset.prettyformat(tree), "\n")
3536 printedtree = tree
3528 printedtree = tree
3537
3529
3538 if opts['verify_optimized']:
3530 if opts['verify_optimized']:
3539 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3531 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3540 brevs = revset.makematcher(treebystage['optimized'])(repo)
3532 brevs = revset.makematcher(treebystage['optimized'])(repo)
3541 if ui.verbose:
3533 if ui.verbose:
3542 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3534 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3543 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3535 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3544 arevs = list(arevs)
3536 arevs = list(arevs)
3545 brevs = list(brevs)
3537 brevs = list(brevs)
3546 if arevs == brevs:
3538 if arevs == brevs:
3547 return 0
3539 return 0
3548 ui.write(('--- analyzed\n'), label='diff.file_a')
3540 ui.write(('--- analyzed\n'), label='diff.file_a')
3549 ui.write(('+++ optimized\n'), label='diff.file_b')
3541 ui.write(('+++ optimized\n'), label='diff.file_b')
3550 sm = difflib.SequenceMatcher(None, arevs, brevs)
3542 sm = difflib.SequenceMatcher(None, arevs, brevs)
3551 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3543 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3552 if tag in ('delete', 'replace'):
3544 if tag in ('delete', 'replace'):
3553 for c in arevs[alo:ahi]:
3545 for c in arevs[alo:ahi]:
3554 ui.write('-%s\n' % c, label='diff.deleted')
3546 ui.write('-%s\n' % c, label='diff.deleted')
3555 if tag in ('insert', 'replace'):
3547 if tag in ('insert', 'replace'):
3556 for c in brevs[blo:bhi]:
3548 for c in brevs[blo:bhi]:
3557 ui.write('+%s\n' % c, label='diff.inserted')
3549 ui.write('+%s\n' % c, label='diff.inserted')
3558 if tag == 'equal':
3550 if tag == 'equal':
3559 for c in arevs[alo:ahi]:
3551 for c in arevs[alo:ahi]:
3560 ui.write(' %s\n' % c)
3552 ui.write(' %s\n' % c)
3561 return 1
3553 return 1
3562
3554
3563 func = revset.makematcher(tree)
3555 func = revset.makematcher(tree)
3564 revs = func(repo)
3556 revs = func(repo)
3565 if ui.verbose:
3557 if ui.verbose:
3566 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3558 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3567 for c in revs:
3559 for c in revs:
3568 ui.write("%s\n" % c)
3560 ui.write("%s\n" % c)
3569
3561
3570 @command('debugsetparents', [], _('REV1 [REV2]'))
3562 @command('debugsetparents', [], _('REV1 [REV2]'))
3571 def debugsetparents(ui, repo, rev1, rev2=None):
3563 def debugsetparents(ui, repo, rev1, rev2=None):
3572 """manually set the parents of the current working directory
3564 """manually set the parents of the current working directory
3573
3565
3574 This is useful for writing repository conversion tools, but should
3566 This is useful for writing repository conversion tools, but should
3575 be used with care. For example, neither the working directory nor the
3567 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
3568 dirstate is updated, so file status may be incorrect after running this
3577 command.
3569 command.
3578
3570
3579 Returns 0 on success.
3571 Returns 0 on success.
3580 """
3572 """
3581
3573
3582 r1 = scmutil.revsingle(repo, rev1).node()
3574 r1 = scmutil.revsingle(repo, rev1).node()
3583 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3575 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3584
3576
3585 with repo.wlock():
3577 with repo.wlock():
3586 repo.setparents(r1, r2)
3578 repo.setparents(r1, r2)
3587
3579
3588 @command('debugdirstate|debugstate',
3580 @command('debugdirstate|debugstate',
3589 [('', 'nodates', None, _('do not display the saved mtime')),
3581 [('', 'nodates', None, _('do not display the saved mtime')),
3590 ('', 'datesort', None, _('sort by saved mtime'))],
3582 ('', 'datesort', None, _('sort by saved mtime'))],
3591 _('[OPTION]...'))
3583 _('[OPTION]...'))
3592 def debugstate(ui, repo, **opts):
3584 def debugstate(ui, repo, **opts):
3593 """show the contents of the current dirstate"""
3585 """show the contents of the current dirstate"""
3594
3586
3595 nodates = opts.get('nodates')
3587 nodates = opts.get('nodates')
3596 datesort = opts.get('datesort')
3588 datesort = opts.get('datesort')
3597
3589
3598 timestr = ""
3590 timestr = ""
3599 if datesort:
3591 if datesort:
3600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3592 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3601 else:
3593 else:
3602 keyfunc = None # sort by filename
3594 keyfunc = None # sort by filename
3603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3595 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3604 if ent[3] == -1:
3596 if ent[3] == -1:
3605 timestr = 'unset '
3597 timestr = 'unset '
3606 elif nodates:
3598 elif nodates:
3607 timestr = 'set '
3599 timestr = 'set '
3608 else:
3600 else:
3609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3601 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3610 time.localtime(ent[3]))
3602 time.localtime(ent[3]))
3611 if ent[1] & 0o20000:
3603 if ent[1] & 0o20000:
3612 mode = 'lnk'
3604 mode = 'lnk'
3613 else:
3605 else:
3614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3606 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3607 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3616 for f in repo.dirstate.copies():
3608 for f in repo.dirstate.copies():
3617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3609 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3618
3610
3619 @command('debugsub',
3611 @command('debugsub',
3620 [('r', 'rev', '',
3612 [('r', 'rev', '',
3621 _('revision to check'), _('REV'))],
3613 _('revision to check'), _('REV'))],
3622 _('[-r REV] [REV]'))
3614 _('[-r REV] [REV]'))
3623 def debugsub(ui, repo, rev=None):
3615 def debugsub(ui, repo, rev=None):
3624 ctx = scmutil.revsingle(repo, rev, None)
3616 ctx = scmutil.revsingle(repo, rev, None)
3625 for k, v in sorted(ctx.substate.items()):
3617 for k, v in sorted(ctx.substate.items()):
3626 ui.write(('path %s\n') % k)
3618 ui.write(('path %s\n') % k)
3627 ui.write((' source %s\n') % v[0])
3619 ui.write((' source %s\n') % v[0])
3628 ui.write((' revision %s\n') % v[1])
3620 ui.write((' revision %s\n') % v[1])
3629
3621
3630 @command('debugsuccessorssets',
3622 @command('debugsuccessorssets',
3631 [],
3623 [],
3632 _('[REV]'))
3624 _('[REV]'))
3633 def debugsuccessorssets(ui, repo, *revs):
3625 def debugsuccessorssets(ui, repo, *revs):
3634 """show set of successors for revision
3626 """show set of successors for revision
3635
3627
3636 A successors set of changeset A is a consistent group of revisions that
3628 A successors set of changeset A is a consistent group of revisions that
3637 succeed A. It contains non-obsolete changesets only.
3629 succeed A. It contains non-obsolete changesets only.
3638
3630
3639 In most cases a changeset A has a single successors set containing a single
3631 In most cases a changeset A has a single successors set containing a single
3640 successor (changeset A replaced by A').
3632 successor (changeset A replaced by A').
3641
3633
3642 A changeset that is made obsolete with no successors are called "pruned".
3634 A changeset that is made obsolete with no successors are called "pruned".
3643 Such changesets have no successors sets at all.
3635 Such changesets have no successors sets at all.
3644
3636
3645 A changeset that has been "split" will have a successors set containing
3637 A changeset that has been "split" will have a successors set containing
3646 more than one successor.
3638 more than one successor.
3647
3639
3648 A changeset that has been rewritten in multiple different ways is called
3640 A changeset that has been rewritten in multiple different ways is called
3649 "divergent". Such changesets have multiple successor sets (each of which
3641 "divergent". Such changesets have multiple successor sets (each of which
3650 may also be split, i.e. have multiple successors).
3642 may also be split, i.e. have multiple successors).
3651
3643
3652 Results are displayed as follows::
3644 Results are displayed as follows::
3653
3645
3654 <rev1>
3646 <rev1>
3655 <successors-1A>
3647 <successors-1A>
3656 <rev2>
3648 <rev2>
3657 <successors-2A>
3649 <successors-2A>
3658 <successors-2B1> <successors-2B2> <successors-2B3>
3650 <successors-2B1> <successors-2B2> <successors-2B3>
3659
3651
3660 Here rev2 has two possible (i.e. divergent) successors sets. The first
3652 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
3653 holds one element, whereas the second holds three (i.e. the changeset has
3662 been split).
3654 been split).
3663 """
3655 """
3664 # passed to successorssets caching computation from one call to another
3656 # passed to successorssets caching computation from one call to another
3665 cache = {}
3657 cache = {}
3666 ctx2str = str
3658 ctx2str = str
3667 node2str = short
3659 node2str = short
3668 if ui.debug():
3660 if ui.debug():
3669 def ctx2str(ctx):
3661 def ctx2str(ctx):
3670 return ctx.hex()
3662 return ctx.hex()
3671 node2str = hex
3663 node2str = hex
3672 for rev in scmutil.revrange(repo, revs):
3664 for rev in scmutil.revrange(repo, revs):
3673 ctx = repo[rev]
3665 ctx = repo[rev]
3674 ui.write('%s\n'% ctx2str(ctx))
3666 ui.write('%s\n'% ctx2str(ctx))
3675 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3667 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3676 if succsset:
3668 if succsset:
3677 ui.write(' ')
3669 ui.write(' ')
3678 ui.write(node2str(succsset[0]))
3670 ui.write(node2str(succsset[0]))
3679 for node in succsset[1:]:
3671 for node in succsset[1:]:
3680 ui.write(' ')
3672 ui.write(' ')
3681 ui.write(node2str(node))
3673 ui.write(node2str(node))
3682 ui.write('\n')
3674 ui.write('\n')
3683
3675
3684 @command('debugtemplate',
3676 @command('debugtemplate',
3685 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3677 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3686 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3678 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3687 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3679 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3688 optionalrepo=True)
3680 optionalrepo=True)
3689 def debugtemplate(ui, repo, tmpl, **opts):
3681 def debugtemplate(ui, repo, tmpl, **opts):
3690 """parse and apply a template
3682 """parse and apply a template
3691
3683
3692 If -r/--rev is given, the template is processed as a log template and
3684 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
3685 applied to the given changesets. Otherwise, it is processed as a generic
3694 template.
3686 template.
3695
3687
3696 Use --verbose to print the parsed tree.
3688 Use --verbose to print the parsed tree.
3697 """
3689 """
3698 revs = None
3690 revs = None
3699 if opts['rev']:
3691 if opts['rev']:
3700 if repo is None:
3692 if repo is None:
3701 raise error.RepoError(_('there is no Mercurial repository here '
3693 raise error.RepoError(_('there is no Mercurial repository here '
3702 '(.hg not found)'))
3694 '(.hg not found)'))
3703 revs = scmutil.revrange(repo, opts['rev'])
3695 revs = scmutil.revrange(repo, opts['rev'])
3704
3696
3705 props = {}
3697 props = {}
3706 for d in opts['define']:
3698 for d in opts['define']:
3707 try:
3699 try:
3708 k, v = (e.strip() for e in d.split('=', 1))
3700 k, v = (e.strip() for e in d.split('=', 1))
3709 if not k:
3701 if not k:
3710 raise ValueError
3702 raise ValueError
3711 props[k] = v
3703 props[k] = v
3712 except ValueError:
3704 except ValueError:
3713 raise error.Abort(_('malformed keyword definition: %s') % d)
3705 raise error.Abort(_('malformed keyword definition: %s') % d)
3714
3706
3715 if ui.verbose:
3707 if ui.verbose:
3716 aliases = ui.configitems('templatealias')
3708 aliases = ui.configitems('templatealias')
3717 tree = templater.parse(tmpl)
3709 tree = templater.parse(tmpl)
3718 ui.note(templater.prettyformat(tree), '\n')
3710 ui.note(templater.prettyformat(tree), '\n')
3719 newtree = templater.expandaliases(tree, aliases)
3711 newtree = templater.expandaliases(tree, aliases)
3720 if newtree != tree:
3712 if newtree != tree:
3721 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3713 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3722
3714
3723 mapfile = None
3715 mapfile = None
3724 if revs is None:
3716 if revs is None:
3725 k = 'debugtemplate'
3717 k = 'debugtemplate'
3726 t = formatter.maketemplater(ui, k, tmpl)
3718 t = formatter.maketemplater(ui, k, tmpl)
3727 ui.write(templater.stringify(t(k, **props)))
3719 ui.write(templater.stringify(t(k, **props)))
3728 else:
3720 else:
3729 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3721 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3730 mapfile, buffered=False)
3722 mapfile, buffered=False)
3731 for r in revs:
3723 for r in revs:
3732 displayer.show(repo[r], **props)
3724 displayer.show(repo[r], **props)
3733 displayer.close()
3725 displayer.close()
3734
3726
3735 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3727 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3736 def debugwalk(ui, repo, *pats, **opts):
3728 def debugwalk(ui, repo, *pats, **opts):
3737 """show how files match on given patterns"""
3729 """show how files match on given patterns"""
3738 m = scmutil.match(repo[None], pats, opts)
3730 m = scmutil.match(repo[None], pats, opts)
3739 items = list(repo.walk(m))
3731 items = list(repo.walk(m))
3740 if not items:
3732 if not items:
3741 return
3733 return
3742 f = lambda fn: fn
3734 f = lambda fn: fn
3743 if ui.configbool('ui', 'slash') and os.sep != '/':
3735 if ui.configbool('ui', 'slash') and os.sep != '/':
3744 f = lambda fn: util.normpath(fn)
3736 f = lambda fn: util.normpath(fn)
3745 fmt = 'f %%-%ds %%-%ds %%s' % (
3737 fmt = 'f %%-%ds %%-%ds %%s' % (
3746 max([len(abs) for abs in items]),
3738 max([len(abs) for abs in items]),
3747 max([len(m.rel(abs)) for abs in items]))
3739 max([len(m.rel(abs)) for abs in items]))
3748 for abs in items:
3740 for abs in items:
3749 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3741 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3750 ui.write("%s\n" % line.rstrip())
3742 ui.write("%s\n" % line.rstrip())
3751
3743
3752 @command('debugwireargs',
3744 @command('debugwireargs',
3753 [('', 'three', '', 'three'),
3745 [('', 'three', '', 'three'),
3754 ('', 'four', '', 'four'),
3746 ('', 'four', '', 'four'),
3755 ('', 'five', '', 'five'),
3747 ('', 'five', '', 'five'),
3756 ] + remoteopts,
3748 ] + remoteopts,
3757 _('REPO [OPTIONS]... [ONE [TWO]]'),
3749 _('REPO [OPTIONS]... [ONE [TWO]]'),
3758 norepo=True)
3750 norepo=True)
3759 def debugwireargs(ui, repopath, *vals, **opts):
3751 def debugwireargs(ui, repopath, *vals, **opts):
3760 repo = hg.peer(ui, opts, repopath)
3752 repo = hg.peer(ui, opts, repopath)
3761 for opt in remoteopts:
3753 for opt in remoteopts:
3762 del opts[opt[1]]
3754 del opts[opt[1]]
3763 args = {}
3755 args = {}
3764 for k, v in opts.iteritems():
3756 for k, v in opts.iteritems():
3765 if v:
3757 if v:
3766 args[k] = v
3758 args[k] = v
3767 # run twice to check that we don't mess up the stream for the next command
3759 # run twice to check that we don't mess up the stream for the next command
3768 res1 = repo.debugwireargs(*vals, **args)
3760 res1 = repo.debugwireargs(*vals, **args)
3769 res2 = repo.debugwireargs(*vals, **args)
3761 res2 = repo.debugwireargs(*vals, **args)
3770 ui.write("%s\n" % res1)
3762 ui.write("%s\n" % res1)
3771 if res1 != res2:
3763 if res1 != res2:
3772 ui.warn("%s\n" % res2)
3764 ui.warn("%s\n" % res2)
3773
3765
3774 @command('^diff',
3766 @command('^diff',
3775 [('r', 'rev', [], _('revision'), _('REV')),
3767 [('r', 'rev', [], _('revision'), _('REV')),
3776 ('c', 'change', '', _('change made by revision'), _('REV'))
3768 ('c', 'change', '', _('change made by revision'), _('REV'))
3777 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3769 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3778 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3770 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3779 inferrepo=True)
3771 inferrepo=True)
3780 def diff(ui, repo, *pats, **opts):
3772 def diff(ui, repo, *pats, **opts):
3781 """diff repository (or selected files)
3773 """diff repository (or selected files)
3782
3774
3783 Show differences between revisions for the specified files.
3775 Show differences between revisions for the specified files.
3784
3776
3785 Differences between files are shown using the unified diff format.
3777 Differences between files are shown using the unified diff format.
3786
3778
3787 .. note::
3779 .. note::
3788
3780
3789 :hg:`diff` may generate unexpected results for merges, as it will
3781 :hg:`diff` may generate unexpected results for merges, as it will
3790 default to comparing against the working directory's first
3782 default to comparing against the working directory's first
3791 parent changeset if no revisions are specified.
3783 parent changeset if no revisions are specified.
3792
3784
3793 When two revision arguments are given, then changes are shown
3785 When two revision arguments are given, then changes are shown
3794 between those revisions. If only one revision is specified then
3786 between those revisions. If only one revision is specified then
3795 that revision is compared to the working directory, and, when no
3787 that revision is compared to the working directory, and, when no
3796 revisions are specified, the working directory files are compared
3788 revisions are specified, the working directory files are compared
3797 to its first parent.
3789 to its first parent.
3798
3790
3799 Alternatively you can specify -c/--change with a revision to see
3791 Alternatively you can specify -c/--change with a revision to see
3800 the changes in that changeset relative to its first parent.
3792 the changes in that changeset relative to its first parent.
3801
3793
3802 Without the -a/--text option, diff will avoid generating diffs of
3794 Without the -a/--text option, diff will avoid generating diffs of
3803 files it detects as binary. With -a, diff will generate a diff
3795 files it detects as binary. With -a, diff will generate a diff
3804 anyway, probably with undesirable results.
3796 anyway, probably with undesirable results.
3805
3797
3806 Use the -g/--git option to generate diffs in the git extended diff
3798 Use the -g/--git option to generate diffs in the git extended diff
3807 format. For more information, read :hg:`help diffs`.
3799 format. For more information, read :hg:`help diffs`.
3808
3800
3809 .. container:: verbose
3801 .. container:: verbose
3810
3802
3811 Examples:
3803 Examples:
3812
3804
3813 - compare a file in the current working directory to its parent::
3805 - compare a file in the current working directory to its parent::
3814
3806
3815 hg diff foo.c
3807 hg diff foo.c
3816
3808
3817 - compare two historical versions of a directory, with rename info::
3809 - compare two historical versions of a directory, with rename info::
3818
3810
3819 hg diff --git -r 1.0:1.2 lib/
3811 hg diff --git -r 1.0:1.2 lib/
3820
3812
3821 - get change stats relative to the last change on some date::
3813 - get change stats relative to the last change on some date::
3822
3814
3823 hg diff --stat -r "date('may 2')"
3815 hg diff --stat -r "date('may 2')"
3824
3816
3825 - diff all newly-added files that contain a keyword::
3817 - diff all newly-added files that contain a keyword::
3826
3818
3827 hg diff "set:added() and grep(GNU)"
3819 hg diff "set:added() and grep(GNU)"
3828
3820
3829 - compare a revision and its parents::
3821 - compare a revision and its parents::
3830
3822
3831 hg diff -c 9353 # compare against first parent
3823 hg diff -c 9353 # compare against first parent
3832 hg diff -r 9353^:9353 # same using revset syntax
3824 hg diff -r 9353^:9353 # same using revset syntax
3833 hg diff -r 9353^2:9353 # compare against the second parent
3825 hg diff -r 9353^2:9353 # compare against the second parent
3834
3826
3835 Returns 0 on success.
3827 Returns 0 on success.
3836 """
3828 """
3837
3829
3838 revs = opts.get('rev')
3830 revs = opts.get('rev')
3839 change = opts.get('change')
3831 change = opts.get('change')
3840 stat = opts.get('stat')
3832 stat = opts.get('stat')
3841 reverse = opts.get('reverse')
3833 reverse = opts.get('reverse')
3842
3834
3843 if revs and change:
3835 if revs and change:
3844 msg = _('cannot specify --rev and --change at the same time')
3836 msg = _('cannot specify --rev and --change at the same time')
3845 raise error.Abort(msg)
3837 raise error.Abort(msg)
3846 elif change:
3838 elif change:
3847 node2 = scmutil.revsingle(repo, change, None).node()
3839 node2 = scmutil.revsingle(repo, change, None).node()
3848 node1 = repo[node2].p1().node()
3840 node1 = repo[node2].p1().node()
3849 else:
3841 else:
3850 node1, node2 = scmutil.revpair(repo, revs)
3842 node1, node2 = scmutil.revpair(repo, revs)
3851
3843
3852 if reverse:
3844 if reverse:
3853 node1, node2 = node2, node1
3845 node1, node2 = node2, node1
3854
3846
3855 diffopts = patch.diffallopts(ui, opts)
3847 diffopts = patch.diffallopts(ui, opts)
3856 m = scmutil.match(repo[node2], pats, opts)
3848 m = scmutil.match(repo[node2], pats, opts)
3857 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3849 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3858 listsubrepos=opts.get('subrepos'),
3850 listsubrepos=opts.get('subrepos'),
3859 root=opts.get('root'))
3851 root=opts.get('root'))
3860
3852
3861 @command('^export',
3853 @command('^export',
3862 [('o', 'output', '',
3854 [('o', 'output', '',
3863 _('print output to file with formatted name'), _('FORMAT')),
3855 _('print output to file with formatted name'), _('FORMAT')),
3864 ('', 'switch-parent', None, _('diff against the second parent')),
3856 ('', 'switch-parent', None, _('diff against the second parent')),
3865 ('r', 'rev', [], _('revisions to export'), _('REV')),
3857 ('r', 'rev', [], _('revisions to export'), _('REV')),
3866 ] + diffopts,
3858 ] + diffopts,
3867 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3859 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3868 def export(ui, repo, *changesets, **opts):
3860 def export(ui, repo, *changesets, **opts):
3869 """dump the header and diffs for one or more changesets
3861 """dump the header and diffs for one or more changesets
3870
3862
3871 Print the changeset header and diffs for one or more revisions.
3863 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.
3864 If no revision is given, the parent of the working directory is used.
3873
3865
3874 The information shown in the changeset header is: author, date,
3866 The information shown in the changeset header is: author, date,
3875 branch name (if non-default), changeset hash, parent(s) and commit
3867 branch name (if non-default), changeset hash, parent(s) and commit
3876 comment.
3868 comment.
3877
3869
3878 .. note::
3870 .. note::
3879
3871
3880 :hg:`export` may generate unexpected diff output for merge
3872 :hg:`export` may generate unexpected diff output for merge
3881 changesets, as it will compare the merge changeset against its
3873 changesets, as it will compare the merge changeset against its
3882 first parent only.
3874 first parent only.
3883
3875
3884 Output may be to a file, in which case the name of the file is
3876 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:
3877 given using a format string. The formatting rules are as follows:
3886
3878
3887 :``%%``: literal "%" character
3879 :``%%``: literal "%" character
3888 :``%H``: changeset hash (40 hexadecimal digits)
3880 :``%H``: changeset hash (40 hexadecimal digits)
3889 :``%N``: number of patches being generated
3881 :``%N``: number of patches being generated
3890 :``%R``: changeset revision number
3882 :``%R``: changeset revision number
3891 :``%b``: basename of the exporting repository
3883 :``%b``: basename of the exporting repository
3892 :``%h``: short-form changeset hash (12 hexadecimal digits)
3884 :``%h``: short-form changeset hash (12 hexadecimal digits)
3893 :``%m``: first line of the commit message (only alphanumeric characters)
3885 :``%m``: first line of the commit message (only alphanumeric characters)
3894 :``%n``: zero-padded sequence number, starting at 1
3886 :``%n``: zero-padded sequence number, starting at 1
3895 :``%r``: zero-padded changeset revision number
3887 :``%r``: zero-padded changeset revision number
3896
3888
3897 Without the -a/--text option, export will avoid generating diffs
3889 Without the -a/--text option, export will avoid generating diffs
3898 of files it detects as binary. With -a, export will generate a
3890 of files it detects as binary. With -a, export will generate a
3899 diff anyway, probably with undesirable results.
3891 diff anyway, probably with undesirable results.
3900
3892
3901 Use the -g/--git option to generate diffs in the git extended diff
3893 Use the -g/--git option to generate diffs in the git extended diff
3902 format. See :hg:`help diffs` for more information.
3894 format. See :hg:`help diffs` for more information.
3903
3895
3904 With the --switch-parent option, the diff will be against the
3896 With the --switch-parent option, the diff will be against the
3905 second parent. It can be useful to review a merge.
3897 second parent. It can be useful to review a merge.
3906
3898
3907 .. container:: verbose
3899 .. container:: verbose
3908
3900
3909 Examples:
3901 Examples:
3910
3902
3911 - use export and import to transplant a bugfix to the current
3903 - use export and import to transplant a bugfix to the current
3912 branch::
3904 branch::
3913
3905
3914 hg export -r 9353 | hg import -
3906 hg export -r 9353 | hg import -
3915
3907
3916 - export all the changesets between two revisions to a file with
3908 - export all the changesets between two revisions to a file with
3917 rename information::
3909 rename information::
3918
3910
3919 hg export --git -r 123:150 > changes.txt
3911 hg export --git -r 123:150 > changes.txt
3920
3912
3921 - split outgoing changes into a series of patches with
3913 - split outgoing changes into a series of patches with
3922 descriptive names::
3914 descriptive names::
3923
3915
3924 hg export -r "outgoing()" -o "%n-%m.patch"
3916 hg export -r "outgoing()" -o "%n-%m.patch"
3925
3917
3926 Returns 0 on success.
3918 Returns 0 on success.
3927 """
3919 """
3928 changesets += tuple(opts.get('rev', []))
3920 changesets += tuple(opts.get('rev', []))
3929 if not changesets:
3921 if not changesets:
3930 changesets = ['.']
3922 changesets = ['.']
3931 revs = scmutil.revrange(repo, changesets)
3923 revs = scmutil.revrange(repo, changesets)
3932 if not revs:
3924 if not revs:
3933 raise error.Abort(_("export requires at least one changeset"))
3925 raise error.Abort(_("export requires at least one changeset"))
3934 if len(revs) > 1:
3926 if len(revs) > 1:
3935 ui.note(_('exporting patches:\n'))
3927 ui.note(_('exporting patches:\n'))
3936 else:
3928 else:
3937 ui.note(_('exporting patch:\n'))
3929 ui.note(_('exporting patch:\n'))
3938 cmdutil.export(repo, revs, template=opts.get('output'),
3930 cmdutil.export(repo, revs, template=opts.get('output'),
3939 switch_parent=opts.get('switch_parent'),
3931 switch_parent=opts.get('switch_parent'),
3940 opts=patch.diffallopts(ui, opts))
3932 opts=patch.diffallopts(ui, opts))
3941
3933
3942 @command('files',
3934 @command('files',
3943 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3935 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3944 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3936 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3945 ] + walkopts + formatteropts + subrepoopts,
3937 ] + walkopts + formatteropts + subrepoopts,
3946 _('[OPTION]... [FILE]...'))
3938 _('[OPTION]... [FILE]...'))
3947 def files(ui, repo, *pats, **opts):
3939 def files(ui, repo, *pats, **opts):
3948 """list tracked files
3940 """list tracked files
3949
3941
3950 Print files under Mercurial control in the working directory or
3942 Print files under Mercurial control in the working directory or
3951 specified revision for given files (excluding removed files).
3943 specified revision for given files (excluding removed files).
3952 Files can be specified as filenames or filesets.
3944 Files can be specified as filenames or filesets.
3953
3945
3954 If no files are given to match, this command prints the names
3946 If no files are given to match, this command prints the names
3955 of all files under Mercurial control.
3947 of all files under Mercurial control.
3956
3948
3957 .. container:: verbose
3949 .. container:: verbose
3958
3950
3959 Examples:
3951 Examples:
3960
3952
3961 - list all files under the current directory::
3953 - list all files under the current directory::
3962
3954
3963 hg files .
3955 hg files .
3964
3956
3965 - shows sizes and flags for current revision::
3957 - shows sizes and flags for current revision::
3966
3958
3967 hg files -vr .
3959 hg files -vr .
3968
3960
3969 - list all files named README::
3961 - list all files named README::
3970
3962
3971 hg files -I "**/README"
3963 hg files -I "**/README"
3972
3964
3973 - list all binary files::
3965 - list all binary files::
3974
3966
3975 hg files "set:binary()"
3967 hg files "set:binary()"
3976
3968
3977 - find files containing a regular expression::
3969 - find files containing a regular expression::
3978
3970
3979 hg files "set:grep('bob')"
3971 hg files "set:grep('bob')"
3980
3972
3981 - search tracked file contents with xargs and grep::
3973 - search tracked file contents with xargs and grep::
3982
3974
3983 hg files -0 | xargs -0 grep foo
3975 hg files -0 | xargs -0 grep foo
3984
3976
3985 See :hg:`help patterns` and :hg:`help filesets` for more information
3977 See :hg:`help patterns` and :hg:`help filesets` for more information
3986 on specifying file patterns.
3978 on specifying file patterns.
3987
3979
3988 Returns 0 if a match is found, 1 otherwise.
3980 Returns 0 if a match is found, 1 otherwise.
3989
3981
3990 """
3982 """
3991 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3983 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3992
3984
3993 end = '\n'
3985 end = '\n'
3994 if opts.get('print0'):
3986 if opts.get('print0'):
3995 end = '\0'
3987 end = '\0'
3996 fmt = '%s' + end
3988 fmt = '%s' + end
3997
3989
3998 m = scmutil.match(ctx, pats, opts)
3990 m = scmutil.match(ctx, pats, opts)
3999 with ui.formatter('files', opts) as fm:
3991 with ui.formatter('files', opts) as fm:
4000 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3992 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
4001
3993
4002 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3994 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
4003 def forget(ui, repo, *pats, **opts):
3995 def forget(ui, repo, *pats, **opts):
4004 """forget the specified files on the next commit
3996 """forget the specified files on the next commit
4005
3997
4006 Mark the specified files so they will no longer be tracked
3998 Mark the specified files so they will no longer be tracked
4007 after the next commit.
3999 after the next commit.
4008
4000
4009 This only removes files from the current branch, not from the
4001 This only removes files from the current branch, not from the
4010 entire project history, and it does not delete them from the
4002 entire project history, and it does not delete them from the
4011 working directory.
4003 working directory.
4012
4004
4013 To delete the file from the working directory, see :hg:`remove`.
4005 To delete the file from the working directory, see :hg:`remove`.
4014
4006
4015 To undo a forget before the next commit, see :hg:`add`.
4007 To undo a forget before the next commit, see :hg:`add`.
4016
4008
4017 .. container:: verbose
4009 .. container:: verbose
4018
4010
4019 Examples:
4011 Examples:
4020
4012
4021 - forget newly-added binary files::
4013 - forget newly-added binary files::
4022
4014
4023 hg forget "set:added() and binary()"
4015 hg forget "set:added() and binary()"
4024
4016
4025 - forget files that would be excluded by .hgignore::
4017 - forget files that would be excluded by .hgignore::
4026
4018
4027 hg forget "set:hgignore()"
4019 hg forget "set:hgignore()"
4028
4020
4029 Returns 0 on success.
4021 Returns 0 on success.
4030 """
4022 """
4031
4023
4032 if not pats:
4024 if not pats:
4033 raise error.Abort(_('no files specified'))
4025 raise error.Abort(_('no files specified'))
4034
4026
4035 m = scmutil.match(repo[None], pats, opts)
4027 m = scmutil.match(repo[None], pats, opts)
4036 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4028 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4037 return rejected and 1 or 0
4029 return rejected and 1 or 0
4038
4030
4039 @command(
4031 @command(
4040 'graft',
4032 'graft',
4041 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4033 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4042 ('c', 'continue', False, _('resume interrupted graft')),
4034 ('c', 'continue', False, _('resume interrupted graft')),
4043 ('e', 'edit', False, _('invoke editor on commit messages')),
4035 ('e', 'edit', False, _('invoke editor on commit messages')),
4044 ('', 'log', None, _('append graft info to log message')),
4036 ('', 'log', None, _('append graft info to log message')),
4045 ('f', 'force', False, _('force graft')),
4037 ('f', 'force', False, _('force graft')),
4046 ('D', 'currentdate', False,
4038 ('D', 'currentdate', False,
4047 _('record the current date as commit date')),
4039 _('record the current date as commit date')),
4048 ('U', 'currentuser', False,
4040 ('U', 'currentuser', False,
4049 _('record the current user as committer'), _('DATE'))]
4041 _('record the current user as committer'), _('DATE'))]
4050 + commitopts2 + mergetoolopts + dryrunopts,
4042 + commitopts2 + mergetoolopts + dryrunopts,
4051 _('[OPTION]... [-r REV]... REV...'))
4043 _('[OPTION]... [-r REV]... REV...'))
4052 def graft(ui, repo, *revs, **opts):
4044 def graft(ui, repo, *revs, **opts):
4053 '''copy changes from other branches onto the current branch
4045 '''copy changes from other branches onto the current branch
4054
4046
4055 This command uses Mercurial's merge logic to copy individual
4047 This command uses Mercurial's merge logic to copy individual
4056 changes from other branches without merging branches in the
4048 changes from other branches without merging branches in the
4057 history graph. This is sometimes known as 'backporting' or
4049 history graph. This is sometimes known as 'backporting' or
4058 'cherry-picking'. By default, graft will copy user, date, and
4050 'cherry-picking'. By default, graft will copy user, date, and
4059 description from the source changesets.
4051 description from the source changesets.
4060
4052
4061 Changesets that are ancestors of the current revision, that have
4053 Changesets that are ancestors of the current revision, that have
4062 already been grafted, or that are merges will be skipped.
4054 already been grafted, or that are merges will be skipped.
4063
4055
4064 If --log is specified, log messages will have a comment appended
4056 If --log is specified, log messages will have a comment appended
4065 of the form::
4057 of the form::
4066
4058
4067 (grafted from CHANGESETHASH)
4059 (grafted from CHANGESETHASH)
4068
4060
4069 If --force is specified, revisions will be grafted even if they
4061 If --force is specified, revisions will be grafted even if they
4070 are already ancestors of or have been grafted to the destination.
4062 are already ancestors of or have been grafted to the destination.
4071 This is useful when the revisions have since been backed out.
4063 This is useful when the revisions have since been backed out.
4072
4064
4073 If a graft merge results in conflicts, the graft process is
4065 If a graft merge results in conflicts, the graft process is
4074 interrupted so that the current merge can be manually resolved.
4066 interrupted so that the current merge can be manually resolved.
4075 Once all conflicts are addressed, the graft process can be
4067 Once all conflicts are addressed, the graft process can be
4076 continued with the -c/--continue option.
4068 continued with the -c/--continue option.
4077
4069
4078 .. note::
4070 .. note::
4079
4071
4080 The -c/--continue option does not reapply earlier options, except
4072 The -c/--continue option does not reapply earlier options, except
4081 for --force.
4073 for --force.
4082
4074
4083 .. container:: verbose
4075 .. container:: verbose
4084
4076
4085 Examples:
4077 Examples:
4086
4078
4087 - copy a single change to the stable branch and edit its description::
4079 - copy a single change to the stable branch and edit its description::
4088
4080
4089 hg update stable
4081 hg update stable
4090 hg graft --edit 9393
4082 hg graft --edit 9393
4091
4083
4092 - graft a range of changesets with one exception, updating dates::
4084 - graft a range of changesets with one exception, updating dates::
4093
4085
4094 hg graft -D "2085::2093 and not 2091"
4086 hg graft -D "2085::2093 and not 2091"
4095
4087
4096 - continue a graft after resolving conflicts::
4088 - continue a graft after resolving conflicts::
4097
4089
4098 hg graft -c
4090 hg graft -c
4099
4091
4100 - show the source of a grafted changeset::
4092 - show the source of a grafted changeset::
4101
4093
4102 hg log --debug -r .
4094 hg log --debug -r .
4103
4095
4104 - show revisions sorted by date::
4096 - show revisions sorted by date::
4105
4097
4106 hg log -r "sort(all(), date)"
4098 hg log -r "sort(all(), date)"
4107
4099
4108 See :hg:`help revisions` and :hg:`help revsets` for more about
4100 See :hg:`help revisions` and :hg:`help revsets` for more about
4109 specifying revisions.
4101 specifying revisions.
4110
4102
4111 Returns 0 on successful completion.
4103 Returns 0 on successful completion.
4112 '''
4104 '''
4113 with repo.wlock():
4105 with repo.wlock():
4114 return _dograft(ui, repo, *revs, **opts)
4106 return _dograft(ui, repo, *revs, **opts)
4115
4107
4116 def _dograft(ui, repo, *revs, **opts):
4108 def _dograft(ui, repo, *revs, **opts):
4117 if revs and opts.get('rev'):
4109 if revs and opts.get('rev'):
4118 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4110 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4119 'revision ordering!\n'))
4111 'revision ordering!\n'))
4120
4112
4121 revs = list(revs)
4113 revs = list(revs)
4122 revs.extend(opts.get('rev'))
4114 revs.extend(opts.get('rev'))
4123
4115
4124 if not opts.get('user') and opts.get('currentuser'):
4116 if not opts.get('user') and opts.get('currentuser'):
4125 opts['user'] = ui.username()
4117 opts['user'] = ui.username()
4126 if not opts.get('date') and opts.get('currentdate'):
4118 if not opts.get('date') and opts.get('currentdate'):
4127 opts['date'] = "%d %d" % util.makedate()
4119 opts['date'] = "%d %d" % util.makedate()
4128
4120
4129 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4121 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4130
4122
4131 cont = False
4123 cont = False
4132 if opts.get('continue'):
4124 if opts.get('continue'):
4133 cont = True
4125 cont = True
4134 if revs:
4126 if revs:
4135 raise error.Abort(_("can't specify --continue and revisions"))
4127 raise error.Abort(_("can't specify --continue and revisions"))
4136 # read in unfinished revisions
4128 # read in unfinished revisions
4137 try:
4129 try:
4138 nodes = repo.vfs.read('graftstate').splitlines()
4130 nodes = repo.vfs.read('graftstate').splitlines()
4139 revs = [repo[node].rev() for node in nodes]
4131 revs = [repo[node].rev() for node in nodes]
4140 except IOError as inst:
4132 except IOError as inst:
4141 if inst.errno != errno.ENOENT:
4133 if inst.errno != errno.ENOENT:
4142 raise
4134 raise
4143 cmdutil.wrongtooltocontinue(repo, _('graft'))
4135 cmdutil.wrongtooltocontinue(repo, _('graft'))
4144 else:
4136 else:
4145 cmdutil.checkunfinished(repo)
4137 cmdutil.checkunfinished(repo)
4146 cmdutil.bailifchanged(repo)
4138 cmdutil.bailifchanged(repo)
4147 if not revs:
4139 if not revs:
4148 raise error.Abort(_('no revisions specified'))
4140 raise error.Abort(_('no revisions specified'))
4149 revs = scmutil.revrange(repo, revs)
4141 revs = scmutil.revrange(repo, revs)
4150
4142
4151 skipped = set()
4143 skipped = set()
4152 # check for merges
4144 # check for merges
4153 for rev in repo.revs('%ld and merge()', revs):
4145 for rev in repo.revs('%ld and merge()', revs):
4154 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4146 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4155 skipped.add(rev)
4147 skipped.add(rev)
4156 revs = [r for r in revs if r not in skipped]
4148 revs = [r for r in revs if r not in skipped]
4157 if not revs:
4149 if not revs:
4158 return -1
4150 return -1
4159
4151
4160 # Don't check in the --continue case, in effect retaining --force across
4152 # Don't check in the --continue case, in effect retaining --force across
4161 # --continues. That's because without --force, any revisions we decided to
4153 # --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
4154 # 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
4155 # 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
4156 # skipped would not have been filtered out, and if they hadn't been applied
4165 # already, they'd have been in the graftstate.
4157 # already, they'd have been in the graftstate.
4166 if not (cont or opts.get('force')):
4158 if not (cont or opts.get('force')):
4167 # check for ancestors of dest branch
4159 # check for ancestors of dest branch
4168 crev = repo['.'].rev()
4160 crev = repo['.'].rev()
4169 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4161 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4170 # XXX make this lazy in the future
4162 # XXX make this lazy in the future
4171 # don't mutate while iterating, create a copy
4163 # don't mutate while iterating, create a copy
4172 for rev in list(revs):
4164 for rev in list(revs):
4173 if rev in ancestors:
4165 if rev in ancestors:
4174 ui.warn(_('skipping ancestor revision %d:%s\n') %
4166 ui.warn(_('skipping ancestor revision %d:%s\n') %
4175 (rev, repo[rev]))
4167 (rev, repo[rev]))
4176 # XXX remove on list is slow
4168 # XXX remove on list is slow
4177 revs.remove(rev)
4169 revs.remove(rev)
4178 if not revs:
4170 if not revs:
4179 return -1
4171 return -1
4180
4172
4181 # analyze revs for earlier grafts
4173 # analyze revs for earlier grafts
4182 ids = {}
4174 ids = {}
4183 for ctx in repo.set("%ld", revs):
4175 for ctx in repo.set("%ld", revs):
4184 ids[ctx.hex()] = ctx.rev()
4176 ids[ctx.hex()] = ctx.rev()
4185 n = ctx.extra().get('source')
4177 n = ctx.extra().get('source')
4186 if n:
4178 if n:
4187 ids[n] = ctx.rev()
4179 ids[n] = ctx.rev()
4188
4180
4189 # check ancestors for earlier grafts
4181 # check ancestors for earlier grafts
4190 ui.debug('scanning for duplicate grafts\n')
4182 ui.debug('scanning for duplicate grafts\n')
4191
4183
4192 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4184 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4193 ctx = repo[rev]
4185 ctx = repo[rev]
4194 n = ctx.extra().get('source')
4186 n = ctx.extra().get('source')
4195 if n in ids:
4187 if n in ids:
4196 try:
4188 try:
4197 r = repo[n].rev()
4189 r = repo[n].rev()
4198 except error.RepoLookupError:
4190 except error.RepoLookupError:
4199 r = None
4191 r = None
4200 if r in revs:
4192 if r in revs:
4201 ui.warn(_('skipping revision %d:%s '
4193 ui.warn(_('skipping revision %d:%s '
4202 '(already grafted to %d:%s)\n')
4194 '(already grafted to %d:%s)\n')
4203 % (r, repo[r], rev, ctx))
4195 % (r, repo[r], rev, ctx))
4204 revs.remove(r)
4196 revs.remove(r)
4205 elif ids[n] in revs:
4197 elif ids[n] in revs:
4206 if r is None:
4198 if r is None:
4207 ui.warn(_('skipping already grafted revision %d:%s '
4199 ui.warn(_('skipping already grafted revision %d:%s '
4208 '(%d:%s also has unknown origin %s)\n')
4200 '(%d:%s also has unknown origin %s)\n')
4209 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4201 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4210 else:
4202 else:
4211 ui.warn(_('skipping already grafted revision %d:%s '
4203 ui.warn(_('skipping already grafted revision %d:%s '
4212 '(%d:%s also has origin %d:%s)\n')
4204 '(%d:%s also has origin %d:%s)\n')
4213 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4205 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4214 revs.remove(ids[n])
4206 revs.remove(ids[n])
4215 elif ctx.hex() in ids:
4207 elif ctx.hex() in ids:
4216 r = ids[ctx.hex()]
4208 r = ids[ctx.hex()]
4217 ui.warn(_('skipping already grafted revision %d:%s '
4209 ui.warn(_('skipping already grafted revision %d:%s '
4218 '(was grafted from %d:%s)\n') %
4210 '(was grafted from %d:%s)\n') %
4219 (r, repo[r], rev, ctx))
4211 (r, repo[r], rev, ctx))
4220 revs.remove(r)
4212 revs.remove(r)
4221 if not revs:
4213 if not revs:
4222 return -1
4214 return -1
4223
4215
4224 for pos, ctx in enumerate(repo.set("%ld", revs)):
4216 for pos, ctx in enumerate(repo.set("%ld", revs)):
4225 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4217 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4226 ctx.description().split('\n', 1)[0])
4218 ctx.description().split('\n', 1)[0])
4227 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4219 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4228 if names:
4220 if names:
4229 desc += ' (%s)' % ' '.join(names)
4221 desc += ' (%s)' % ' '.join(names)
4230 ui.status(_('grafting %s\n') % desc)
4222 ui.status(_('grafting %s\n') % desc)
4231 if opts.get('dry_run'):
4223 if opts.get('dry_run'):
4232 continue
4224 continue
4233
4225
4234 source = ctx.extra().get('source')
4226 source = ctx.extra().get('source')
4235 extra = {}
4227 extra = {}
4236 if source:
4228 if source:
4237 extra['source'] = source
4229 extra['source'] = source
4238 extra['intermediate-source'] = ctx.hex()
4230 extra['intermediate-source'] = ctx.hex()
4239 else:
4231 else:
4240 extra['source'] = ctx.hex()
4232 extra['source'] = ctx.hex()
4241 user = ctx.user()
4233 user = ctx.user()
4242 if opts.get('user'):
4234 if opts.get('user'):
4243 user = opts['user']
4235 user = opts['user']
4244 date = ctx.date()
4236 date = ctx.date()
4245 if opts.get('date'):
4237 if opts.get('date'):
4246 date = opts['date']
4238 date = opts['date']
4247 message = ctx.description()
4239 message = ctx.description()
4248 if opts.get('log'):
4240 if opts.get('log'):
4249 message += '\n(grafted from %s)' % ctx.hex()
4241 message += '\n(grafted from %s)' % ctx.hex()
4250
4242
4251 # we don't merge the first commit when continuing
4243 # we don't merge the first commit when continuing
4252 if not cont:
4244 if not cont:
4253 # perform the graft merge with p1(rev) as 'ancestor'
4245 # perform the graft merge with p1(rev) as 'ancestor'
4254 try:
4246 try:
4255 # ui.forcemerge is an internal variable, do not document
4247 # ui.forcemerge is an internal variable, do not document
4256 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4248 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4257 'graft')
4249 'graft')
4258 stats = mergemod.graft(repo, ctx, ctx.p1(),
4250 stats = mergemod.graft(repo, ctx, ctx.p1(),
4259 ['local', 'graft'])
4251 ['local', 'graft'])
4260 finally:
4252 finally:
4261 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4253 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4262 # report any conflicts
4254 # report any conflicts
4263 if stats and stats[3] > 0:
4255 if stats and stats[3] > 0:
4264 # write out state for --continue
4256 # write out state for --continue
4265 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4257 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4266 repo.vfs.write('graftstate', ''.join(nodelines))
4258 repo.vfs.write('graftstate', ''.join(nodelines))
4267 extra = ''
4259 extra = ''
4268 if opts.get('user'):
4260 if opts.get('user'):
4269 extra += ' --user %s' % util.shellquote(opts['user'])
4261 extra += ' --user %s' % util.shellquote(opts['user'])
4270 if opts.get('date'):
4262 if opts.get('date'):
4271 extra += ' --date %s' % util.shellquote(opts['date'])
4263 extra += ' --date %s' % util.shellquote(opts['date'])
4272 if opts.get('log'):
4264 if opts.get('log'):
4273 extra += ' --log'
4265 extra += ' --log'
4274 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4266 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4275 raise error.Abort(
4267 raise error.Abort(
4276 _("unresolved conflicts, can't continue"),
4268 _("unresolved conflicts, can't continue"),
4277 hint=hint)
4269 hint=hint)
4278 else:
4270 else:
4279 cont = False
4271 cont = False
4280
4272
4281 # commit
4273 # commit
4282 node = repo.commit(text=message, user=user,
4274 node = repo.commit(text=message, user=user,
4283 date=date, extra=extra, editor=editor)
4275 date=date, extra=extra, editor=editor)
4284 if node is None:
4276 if node is None:
4285 ui.warn(
4277 ui.warn(
4286 _('note: graft of %d:%s created no changes to commit\n') %
4278 _('note: graft of %d:%s created no changes to commit\n') %
4287 (ctx.rev(), ctx))
4279 (ctx.rev(), ctx))
4288
4280
4289 # remove state when we complete successfully
4281 # remove state when we complete successfully
4290 if not opts.get('dry_run'):
4282 if not opts.get('dry_run'):
4291 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4283 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4292
4284
4293 return 0
4285 return 0
4294
4286
4295 @command('grep',
4287 @command('grep',
4296 [('0', 'print0', None, _('end fields with NUL')),
4288 [('0', 'print0', None, _('end fields with NUL')),
4297 ('', 'all', None, _('print all revisions that match')),
4289 ('', 'all', None, _('print all revisions that match')),
4298 ('a', 'text', None, _('treat all files as text')),
4290 ('a', 'text', None, _('treat all files as text')),
4299 ('f', 'follow', None,
4291 ('f', 'follow', None,
4300 _('follow changeset history,'
4292 _('follow changeset history,'
4301 ' or file history across copies and renames')),
4293 ' or file history across copies and renames')),
4302 ('i', 'ignore-case', None, _('ignore case when matching')),
4294 ('i', 'ignore-case', None, _('ignore case when matching')),
4303 ('l', 'files-with-matches', None,
4295 ('l', 'files-with-matches', None,
4304 _('print only filenames and revisions that match')),
4296 _('print only filenames and revisions that match')),
4305 ('n', 'line-number', None, _('print matching line numbers')),
4297 ('n', 'line-number', None, _('print matching line numbers')),
4306 ('r', 'rev', [],
4298 ('r', 'rev', [],
4307 _('only search files changed within revision range'), _('REV')),
4299 _('only search files changed within revision range'), _('REV')),
4308 ('u', 'user', None, _('list the author (long with -v)')),
4300 ('u', 'user', None, _('list the author (long with -v)')),
4309 ('d', 'date', None, _('list the date (short with -q)')),
4301 ('d', 'date', None, _('list the date (short with -q)')),
4310 ] + formatteropts + walkopts,
4302 ] + formatteropts + walkopts,
4311 _('[OPTION]... PATTERN [FILE]...'),
4303 _('[OPTION]... PATTERN [FILE]...'),
4312 inferrepo=True)
4304 inferrepo=True)
4313 def grep(ui, repo, pattern, *pats, **opts):
4305 def grep(ui, repo, pattern, *pats, **opts):
4314 """search revision history for a pattern in specified files
4306 """search revision history for a pattern in specified files
4315
4307
4316 Search revision history for a regular expression in the specified
4308 Search revision history for a regular expression in the specified
4317 files or the entire project.
4309 files or the entire project.
4318
4310
4319 By default, grep prints the most recent revision number for each
4311 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
4312 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
4313 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
4314 a non-match, or "+" for a non-match that becomes a match), use the
4323 --all flag.
4315 --all flag.
4324
4316
4325 PATTERN can be any Python (roughly Perl-compatible) regular
4317 PATTERN can be any Python (roughly Perl-compatible) regular
4326 expression.
4318 expression.
4327
4319
4328 If no FILEs are specified (and -f/--follow isn't set), all files in
4320 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
4321 the repository are searched, including those that don't exist in the
4330 current branch or have been deleted in a prior changeset.
4322 current branch or have been deleted in a prior changeset.
4331
4323
4332 Returns 0 if a match is found, 1 otherwise.
4324 Returns 0 if a match is found, 1 otherwise.
4333 """
4325 """
4334 reflags = re.M
4326 reflags = re.M
4335 if opts.get('ignore_case'):
4327 if opts.get('ignore_case'):
4336 reflags |= re.I
4328 reflags |= re.I
4337 try:
4329 try:
4338 regexp = util.re.compile(pattern, reflags)
4330 regexp = util.re.compile(pattern, reflags)
4339 except re.error as inst:
4331 except re.error as inst:
4340 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4332 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4341 return 1
4333 return 1
4342 sep, eol = ':', '\n'
4334 sep, eol = ':', '\n'
4343 if opts.get('print0'):
4335 if opts.get('print0'):
4344 sep = eol = '\0'
4336 sep = eol = '\0'
4345
4337
4346 getfile = util.lrucachefunc(repo.file)
4338 getfile = util.lrucachefunc(repo.file)
4347
4339
4348 def matchlines(body):
4340 def matchlines(body):
4349 begin = 0
4341 begin = 0
4350 linenum = 0
4342 linenum = 0
4351 while begin < len(body):
4343 while begin < len(body):
4352 match = regexp.search(body, begin)
4344 match = regexp.search(body, begin)
4353 if not match:
4345 if not match:
4354 break
4346 break
4355 mstart, mend = match.span()
4347 mstart, mend = match.span()
4356 linenum += body.count('\n', begin, mstart) + 1
4348 linenum += body.count('\n', begin, mstart) + 1
4357 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4349 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4358 begin = body.find('\n', mend) + 1 or len(body) + 1
4350 begin = body.find('\n', mend) + 1 or len(body) + 1
4359 lend = begin - 1
4351 lend = begin - 1
4360 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4352 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4361
4353
4362 class linestate(object):
4354 class linestate(object):
4363 def __init__(self, line, linenum, colstart, colend):
4355 def __init__(self, line, linenum, colstart, colend):
4364 self.line = line
4356 self.line = line
4365 self.linenum = linenum
4357 self.linenum = linenum
4366 self.colstart = colstart
4358 self.colstart = colstart
4367 self.colend = colend
4359 self.colend = colend
4368
4360
4369 def __hash__(self):
4361 def __hash__(self):
4370 return hash((self.linenum, self.line))
4362 return hash((self.linenum, self.line))
4371
4363
4372 def __eq__(self, other):
4364 def __eq__(self, other):
4373 return self.line == other.line
4365 return self.line == other.line
4374
4366
4375 def findpos(self):
4367 def findpos(self):
4376 """Iterate all (start, end) indices of matches"""
4368 """Iterate all (start, end) indices of matches"""
4377 yield self.colstart, self.colend
4369 yield self.colstart, self.colend
4378 p = self.colend
4370 p = self.colend
4379 while p < len(self.line):
4371 while p < len(self.line):
4380 m = regexp.search(self.line, p)
4372 m = regexp.search(self.line, p)
4381 if not m:
4373 if not m:
4382 break
4374 break
4383 yield m.span()
4375 yield m.span()
4384 p = m.end()
4376 p = m.end()
4385
4377
4386 matches = {}
4378 matches = {}
4387 copies = {}
4379 copies = {}
4388 def grepbody(fn, rev, body):
4380 def grepbody(fn, rev, body):
4389 matches[rev].setdefault(fn, [])
4381 matches[rev].setdefault(fn, [])
4390 m = matches[rev][fn]
4382 m = matches[rev][fn]
4391 for lnum, cstart, cend, line in matchlines(body):
4383 for lnum, cstart, cend, line in matchlines(body):
4392 s = linestate(line, lnum, cstart, cend)
4384 s = linestate(line, lnum, cstart, cend)
4393 m.append(s)
4385 m.append(s)
4394
4386
4395 def difflinestates(a, b):
4387 def difflinestates(a, b):
4396 sm = difflib.SequenceMatcher(None, a, b)
4388 sm = difflib.SequenceMatcher(None, a, b)
4397 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4389 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4398 if tag == 'insert':
4390 if tag == 'insert':
4399 for i in xrange(blo, bhi):
4391 for i in xrange(blo, bhi):
4400 yield ('+', b[i])
4392 yield ('+', b[i])
4401 elif tag == 'delete':
4393 elif tag == 'delete':
4402 for i in xrange(alo, ahi):
4394 for i in xrange(alo, ahi):
4403 yield ('-', a[i])
4395 yield ('-', a[i])
4404 elif tag == 'replace':
4396 elif tag == 'replace':
4405 for i in xrange(alo, ahi):
4397 for i in xrange(alo, ahi):
4406 yield ('-', a[i])
4398 yield ('-', a[i])
4407 for i in xrange(blo, bhi):
4399 for i in xrange(blo, bhi):
4408 yield ('+', b[i])
4400 yield ('+', b[i])
4409
4401
4410 def display(fm, fn, ctx, pstates, states):
4402 def display(fm, fn, ctx, pstates, states):
4411 rev = ctx.rev()
4403 rev = ctx.rev()
4412 if fm.isplain():
4404 if fm.isplain():
4413 formatuser = ui.shortuser
4405 formatuser = ui.shortuser
4414 else:
4406 else:
4415 formatuser = str
4407 formatuser = str
4416 if ui.quiet:
4408 if ui.quiet:
4417 datefmt = '%Y-%m-%d'
4409 datefmt = '%Y-%m-%d'
4418 else:
4410 else:
4419 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4411 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4420 found = False
4412 found = False
4421 @util.cachefunc
4413 @util.cachefunc
4422 def binary():
4414 def binary():
4423 flog = getfile(fn)
4415 flog = getfile(fn)
4424 return util.binary(flog.read(ctx.filenode(fn)))
4416 return util.binary(flog.read(ctx.filenode(fn)))
4425
4417
4426 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4418 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4427 if opts.get('all'):
4419 if opts.get('all'):
4428 iter = difflinestates(pstates, states)
4420 iter = difflinestates(pstates, states)
4429 else:
4421 else:
4430 iter = [('', l) for l in states]
4422 iter = [('', l) for l in states]
4431 for change, l in iter:
4423 for change, l in iter:
4432 fm.startitem()
4424 fm.startitem()
4433 fm.data(node=fm.hexfunc(ctx.node()))
4425 fm.data(node=fm.hexfunc(ctx.node()))
4434 cols = [
4426 cols = [
4435 ('filename', fn, True),
4427 ('filename', fn, True),
4436 ('rev', rev, True),
4428 ('rev', rev, True),
4437 ('linenumber', l.linenum, opts.get('line_number')),
4429 ('linenumber', l.linenum, opts.get('line_number')),
4438 ]
4430 ]
4439 if opts.get('all'):
4431 if opts.get('all'):
4440 cols.append(('change', change, True))
4432 cols.append(('change', change, True))
4441 cols.extend([
4433 cols.extend([
4442 ('user', formatuser(ctx.user()), opts.get('user')),
4434 ('user', formatuser(ctx.user()), opts.get('user')),
4443 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4435 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4444 ])
4436 ])
4445 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4437 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4446 for name, data, cond in cols:
4438 for name, data, cond in cols:
4447 field = fieldnamemap.get(name, name)
4439 field = fieldnamemap.get(name, name)
4448 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4440 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4449 if cond and name != lastcol:
4441 if cond and name != lastcol:
4450 fm.plain(sep, label='grep.sep')
4442 fm.plain(sep, label='grep.sep')
4451 if not opts.get('files_with_matches'):
4443 if not opts.get('files_with_matches'):
4452 fm.plain(sep, label='grep.sep')
4444 fm.plain(sep, label='grep.sep')
4453 if not opts.get('text') and binary():
4445 if not opts.get('text') and binary():
4454 fm.plain(_(" Binary file matches"))
4446 fm.plain(_(" Binary file matches"))
4455 else:
4447 else:
4456 displaymatches(fm.nested('texts'), l)
4448 displaymatches(fm.nested('texts'), l)
4457 fm.plain(eol)
4449 fm.plain(eol)
4458 found = True
4450 found = True
4459 if opts.get('files_with_matches'):
4451 if opts.get('files_with_matches'):
4460 break
4452 break
4461 return found
4453 return found
4462
4454
4463 def displaymatches(fm, l):
4455 def displaymatches(fm, l):
4464 p = 0
4456 p = 0
4465 for s, e in l.findpos():
4457 for s, e in l.findpos():
4466 if p < s:
4458 if p < s:
4467 fm.startitem()
4459 fm.startitem()
4468 fm.write('text', '%s', l.line[p:s])
4460 fm.write('text', '%s', l.line[p:s])
4469 fm.data(matched=False)
4461 fm.data(matched=False)
4470 fm.startitem()
4462 fm.startitem()
4471 fm.write('text', '%s', l.line[s:e], label='grep.match')
4463 fm.write('text', '%s', l.line[s:e], label='grep.match')
4472 fm.data(matched=True)
4464 fm.data(matched=True)
4473 p = e
4465 p = e
4474 if p < len(l.line):
4466 if p < len(l.line):
4475 fm.startitem()
4467 fm.startitem()
4476 fm.write('text', '%s', l.line[p:])
4468 fm.write('text', '%s', l.line[p:])
4477 fm.data(matched=False)
4469 fm.data(matched=False)
4478 fm.end()
4470 fm.end()
4479
4471
4480 skip = {}
4472 skip = {}
4481 revfiles = {}
4473 revfiles = {}
4482 matchfn = scmutil.match(repo[None], pats, opts)
4474 matchfn = scmutil.match(repo[None], pats, opts)
4483 found = False
4475 found = False
4484 follow = opts.get('follow')
4476 follow = opts.get('follow')
4485
4477
4486 def prep(ctx, fns):
4478 def prep(ctx, fns):
4487 rev = ctx.rev()
4479 rev = ctx.rev()
4488 pctx = ctx.p1()
4480 pctx = ctx.p1()
4489 parent = pctx.rev()
4481 parent = pctx.rev()
4490 matches.setdefault(rev, {})
4482 matches.setdefault(rev, {})
4491 matches.setdefault(parent, {})
4483 matches.setdefault(parent, {})
4492 files = revfiles.setdefault(rev, [])
4484 files = revfiles.setdefault(rev, [])
4493 for fn in fns:
4485 for fn in fns:
4494 flog = getfile(fn)
4486 flog = getfile(fn)
4495 try:
4487 try:
4496 fnode = ctx.filenode(fn)
4488 fnode = ctx.filenode(fn)
4497 except error.LookupError:
4489 except error.LookupError:
4498 continue
4490 continue
4499
4491
4500 copied = flog.renamed(fnode)
4492 copied = flog.renamed(fnode)
4501 copy = follow and copied and copied[0]
4493 copy = follow and copied and copied[0]
4502 if copy:
4494 if copy:
4503 copies.setdefault(rev, {})[fn] = copy
4495 copies.setdefault(rev, {})[fn] = copy
4504 if fn in skip:
4496 if fn in skip:
4505 if copy:
4497 if copy:
4506 skip[copy] = True
4498 skip[copy] = True
4507 continue
4499 continue
4508 files.append(fn)
4500 files.append(fn)
4509
4501
4510 if fn not in matches[rev]:
4502 if fn not in matches[rev]:
4511 grepbody(fn, rev, flog.read(fnode))
4503 grepbody(fn, rev, flog.read(fnode))
4512
4504
4513 pfn = copy or fn
4505 pfn = copy or fn
4514 if pfn not in matches[parent]:
4506 if pfn not in matches[parent]:
4515 try:
4507 try:
4516 fnode = pctx.filenode(pfn)
4508 fnode = pctx.filenode(pfn)
4517 grepbody(pfn, parent, flog.read(fnode))
4509 grepbody(pfn, parent, flog.read(fnode))
4518 except error.LookupError:
4510 except error.LookupError:
4519 pass
4511 pass
4520
4512
4521 fm = ui.formatter('grep', opts)
4513 fm = ui.formatter('grep', opts)
4522 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4514 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4523 rev = ctx.rev()
4515 rev = ctx.rev()
4524 parent = ctx.p1().rev()
4516 parent = ctx.p1().rev()
4525 for fn in sorted(revfiles.get(rev, [])):
4517 for fn in sorted(revfiles.get(rev, [])):
4526 states = matches[rev][fn]
4518 states = matches[rev][fn]
4527 copy = copies.get(rev, {}).get(fn)
4519 copy = copies.get(rev, {}).get(fn)
4528 if fn in skip:
4520 if fn in skip:
4529 if copy:
4521 if copy:
4530 skip[copy] = True
4522 skip[copy] = True
4531 continue
4523 continue
4532 pstates = matches.get(parent, {}).get(copy or fn, [])
4524 pstates = matches.get(parent, {}).get(copy or fn, [])
4533 if pstates or states:
4525 if pstates or states:
4534 r = display(fm, fn, ctx, pstates, states)
4526 r = display(fm, fn, ctx, pstates, states)
4535 found = found or r
4527 found = found or r
4536 if r and not opts.get('all'):
4528 if r and not opts.get('all'):
4537 skip[fn] = True
4529 skip[fn] = True
4538 if copy:
4530 if copy:
4539 skip[copy] = True
4531 skip[copy] = True
4540 del matches[rev]
4532 del matches[rev]
4541 del revfiles[rev]
4533 del revfiles[rev]
4542 fm.end()
4534 fm.end()
4543
4535
4544 return not found
4536 return not found
4545
4537
4546 @command('heads',
4538 @command('heads',
4547 [('r', 'rev', '',
4539 [('r', 'rev', '',
4548 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4540 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4549 ('t', 'topo', False, _('show topological heads only')),
4541 ('t', 'topo', False, _('show topological heads only')),
4550 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4542 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4551 ('c', 'closed', False, _('show normal and closed branch heads')),
4543 ('c', 'closed', False, _('show normal and closed branch heads')),
4552 ] + templateopts,
4544 ] + templateopts,
4553 _('[-ct] [-r STARTREV] [REV]...'))
4545 _('[-ct] [-r STARTREV] [REV]...'))
4554 def heads(ui, repo, *branchrevs, **opts):
4546 def heads(ui, repo, *branchrevs, **opts):
4555 """show branch heads
4547 """show branch heads
4556
4548
4557 With no arguments, show all open branch heads in the repository.
4549 With no arguments, show all open branch heads in the repository.
4558 Branch heads are changesets that have no descendants on the
4550 Branch heads are changesets that have no descendants on the
4559 same branch. They are where development generally takes place and
4551 same branch. They are where development generally takes place and
4560 are the usual targets for update and merge operations.
4552 are the usual targets for update and merge operations.
4561
4553
4562 If one or more REVs are given, only open branch heads on the
4554 If one or more REVs are given, only open branch heads on the
4563 branches associated with the specified changesets are shown. This
4555 branches associated with the specified changesets are shown. This
4564 means that you can use :hg:`heads .` to see the heads on the
4556 means that you can use :hg:`heads .` to see the heads on the
4565 currently checked-out branch.
4557 currently checked-out branch.
4566
4558
4567 If -c/--closed is specified, also show branch heads marked closed
4559 If -c/--closed is specified, also show branch heads marked closed
4568 (see :hg:`commit --close-branch`).
4560 (see :hg:`commit --close-branch`).
4569
4561
4570 If STARTREV is specified, only those heads that are descendants of
4562 If STARTREV is specified, only those heads that are descendants of
4571 STARTREV will be displayed.
4563 STARTREV will be displayed.
4572
4564
4573 If -t/--topo is specified, named branch mechanics will be ignored and only
4565 If -t/--topo is specified, named branch mechanics will be ignored and only
4574 topological heads (changesets with no children) will be shown.
4566 topological heads (changesets with no children) will be shown.
4575
4567
4576 Returns 0 if matching heads are found, 1 if not.
4568 Returns 0 if matching heads are found, 1 if not.
4577 """
4569 """
4578
4570
4579 start = None
4571 start = None
4580 if 'rev' in opts:
4572 if 'rev' in opts:
4581 start = scmutil.revsingle(repo, opts['rev'], None).node()
4573 start = scmutil.revsingle(repo, opts['rev'], None).node()
4582
4574
4583 if opts.get('topo'):
4575 if opts.get('topo'):
4584 heads = [repo[h] for h in repo.heads(start)]
4576 heads = [repo[h] for h in repo.heads(start)]
4585 else:
4577 else:
4586 heads = []
4578 heads = []
4587 for branch in repo.branchmap():
4579 for branch in repo.branchmap():
4588 heads += repo.branchheads(branch, start, opts.get('closed'))
4580 heads += repo.branchheads(branch, start, opts.get('closed'))
4589 heads = [repo[h] for h in heads]
4581 heads = [repo[h] for h in heads]
4590
4582
4591 if branchrevs:
4583 if branchrevs:
4592 branches = set(repo[br].branch() for br in branchrevs)
4584 branches = set(repo[br].branch() for br in branchrevs)
4593 heads = [h for h in heads if h.branch() in branches]
4585 heads = [h for h in heads if h.branch() in branches]
4594
4586
4595 if opts.get('active') and branchrevs:
4587 if opts.get('active') and branchrevs:
4596 dagheads = repo.heads(start)
4588 dagheads = repo.heads(start)
4597 heads = [h for h in heads if h.node() in dagheads]
4589 heads = [h for h in heads if h.node() in dagheads]
4598
4590
4599 if branchrevs:
4591 if branchrevs:
4600 haveheads = set(h.branch() for h in heads)
4592 haveheads = set(h.branch() for h in heads)
4601 if branches - haveheads:
4593 if branches - haveheads:
4602 headless = ', '.join(b for b in branches - haveheads)
4594 headless = ', '.join(b for b in branches - haveheads)
4603 msg = _('no open branch heads found on branches %s')
4595 msg = _('no open branch heads found on branches %s')
4604 if opts.get('rev'):
4596 if opts.get('rev'):
4605 msg += _(' (started at %s)') % opts['rev']
4597 msg += _(' (started at %s)') % opts['rev']
4606 ui.warn((msg + '\n') % headless)
4598 ui.warn((msg + '\n') % headless)
4607
4599
4608 if not heads:
4600 if not heads:
4609 return 1
4601 return 1
4610
4602
4611 heads = sorted(heads, key=lambda x: -x.rev())
4603 heads = sorted(heads, key=lambda x: -x.rev())
4612 displayer = cmdutil.show_changeset(ui, repo, opts)
4604 displayer = cmdutil.show_changeset(ui, repo, opts)
4613 for ctx in heads:
4605 for ctx in heads:
4614 displayer.show(ctx)
4606 displayer.show(ctx)
4615 displayer.close()
4607 displayer.close()
4616
4608
4617 @command('help',
4609 @command('help',
4618 [('e', 'extension', None, _('show only help for extensions')),
4610 [('e', 'extension', None, _('show only help for extensions')),
4619 ('c', 'command', None, _('show only help for commands')),
4611 ('c', 'command', None, _('show only help for commands')),
4620 ('k', 'keyword', None, _('show topics matching keyword')),
4612 ('k', 'keyword', None, _('show topics matching keyword')),
4621 ('s', 'system', [], _('show help for specific platform(s)')),
4613 ('s', 'system', [], _('show help for specific platform(s)')),
4622 ],
4614 ],
4623 _('[-ecks] [TOPIC]'),
4615 _('[-ecks] [TOPIC]'),
4624 norepo=True)
4616 norepo=True)
4625 def help_(ui, name=None, **opts):
4617 def help_(ui, name=None, **opts):
4626 """show help for a given topic or a help overview
4618 """show help for a given topic or a help overview
4627
4619
4628 With no arguments, print a list of commands with short help messages.
4620 With no arguments, print a list of commands with short help messages.
4629
4621
4630 Given a topic, extension, or command name, print help for that
4622 Given a topic, extension, or command name, print help for that
4631 topic.
4623 topic.
4632
4624
4633 Returns 0 if successful.
4625 Returns 0 if successful.
4634 """
4626 """
4635
4627
4636 textwidth = ui.configint('ui', 'textwidth', 78)
4628 textwidth = ui.configint('ui', 'textwidth', 78)
4637 termwidth = ui.termwidth() - 2
4629 termwidth = ui.termwidth() - 2
4638 if textwidth <= 0 or termwidth < textwidth:
4630 if textwidth <= 0 or termwidth < textwidth:
4639 textwidth = termwidth
4631 textwidth = termwidth
4640
4632
4641 keep = opts.get('system') or []
4633 keep = opts.get('system') or []
4642 if len(keep) == 0:
4634 if len(keep) == 0:
4643 if sys.platform.startswith('win'):
4635 if sys.platform.startswith('win'):
4644 keep.append('windows')
4636 keep.append('windows')
4645 elif sys.platform == 'OpenVMS':
4637 elif sys.platform == 'OpenVMS':
4646 keep.append('vms')
4638 keep.append('vms')
4647 elif sys.platform == 'plan9':
4639 elif sys.platform == 'plan9':
4648 keep.append('plan9')
4640 keep.append('plan9')
4649 else:
4641 else:
4650 keep.append('unix')
4642 keep.append('unix')
4651 keep.append(sys.platform.lower())
4643 keep.append(sys.platform.lower())
4652 if ui.verbose:
4644 if ui.verbose:
4653 keep.append('verbose')
4645 keep.append('verbose')
4654
4646
4655 section = None
4647 section = None
4656 subtopic = None
4648 subtopic = None
4657 if name and '.' in name:
4649 if name and '.' in name:
4658 name, remaining = name.split('.', 1)
4650 name, remaining = name.split('.', 1)
4659 remaining = encoding.lower(remaining)
4651 remaining = encoding.lower(remaining)
4660 if '.' in remaining:
4652 if '.' in remaining:
4661 subtopic, section = remaining.split('.', 1)
4653 subtopic, section = remaining.split('.', 1)
4662 else:
4654 else:
4663 if name in help.subtopics:
4655 if name in help.subtopics:
4664 subtopic = remaining
4656 subtopic = remaining
4665 else:
4657 else:
4666 section = remaining
4658 section = remaining
4667
4659
4668 text = help.help_(ui, name, subtopic=subtopic, **opts)
4660 text = help.help_(ui, name, subtopic=subtopic, **opts)
4669
4661
4670 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4662 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4671 section=section)
4663 section=section)
4672
4664
4673 # We could have been given a weird ".foo" section without a name
4665 # 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"
4666 # to look for, or we could have simply failed to found "foo.bar"
4675 # because bar isn't a section of foo
4667 # because bar isn't a section of foo
4676 if section and not (formatted and name):
4668 if section and not (formatted and name):
4677 raise error.Abort(_("help section not found"))
4669 raise error.Abort(_("help section not found"))
4678
4670
4679 if 'verbose' in pruned:
4671 if 'verbose' in pruned:
4680 keep.append('omitted')
4672 keep.append('omitted')
4681 else:
4673 else:
4682 keep.append('notomitted')
4674 keep.append('notomitted')
4683 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4675 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4684 section=section)
4676 section=section)
4685 ui.write(formatted)
4677 ui.write(formatted)
4686
4678
4687
4679
4688 @command('identify|id',
4680 @command('identify|id',
4689 [('r', 'rev', '',
4681 [('r', 'rev', '',
4690 _('identify the specified revision'), _('REV')),
4682 _('identify the specified revision'), _('REV')),
4691 ('n', 'num', None, _('show local revision number')),
4683 ('n', 'num', None, _('show local revision number')),
4692 ('i', 'id', None, _('show global revision id')),
4684 ('i', 'id', None, _('show global revision id')),
4693 ('b', 'branch', None, _('show branch')),
4685 ('b', 'branch', None, _('show branch')),
4694 ('t', 'tags', None, _('show tags')),
4686 ('t', 'tags', None, _('show tags')),
4695 ('B', 'bookmarks', None, _('show bookmarks')),
4687 ('B', 'bookmarks', None, _('show bookmarks')),
4696 ] + remoteopts,
4688 ] + remoteopts,
4697 _('[-nibtB] [-r REV] [SOURCE]'),
4689 _('[-nibtB] [-r REV] [SOURCE]'),
4698 optionalrepo=True)
4690 optionalrepo=True)
4699 def identify(ui, repo, source=None, rev=None,
4691 def identify(ui, repo, source=None, rev=None,
4700 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4692 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4701 """identify the working directory or specified revision
4693 """identify the working directory or specified revision
4702
4694
4703 Print a summary identifying the repository state at REV using one or
4695 Print a summary identifying the repository state at REV using one or
4704 two parent hash identifiers, followed by a "+" if the working
4696 two parent hash identifiers, followed by a "+" if the working
4705 directory has uncommitted changes, the branch name (if not default),
4697 directory has uncommitted changes, the branch name (if not default),
4706 a list of tags, and a list of bookmarks.
4698 a list of tags, and a list of bookmarks.
4707
4699
4708 When REV is not given, print a summary of the current state of the
4700 When REV is not given, print a summary of the current state of the
4709 repository.
4701 repository.
4710
4702
4711 Specifying a path to a repository root or Mercurial bundle will
4703 Specifying a path to a repository root or Mercurial bundle will
4712 cause lookup to operate on that repository/bundle.
4704 cause lookup to operate on that repository/bundle.
4713
4705
4714 .. container:: verbose
4706 .. container:: verbose
4715
4707
4716 Examples:
4708 Examples:
4717
4709
4718 - generate a build identifier for the working directory::
4710 - generate a build identifier for the working directory::
4719
4711
4720 hg id --id > build-id.dat
4712 hg id --id > build-id.dat
4721
4713
4722 - find the revision corresponding to a tag::
4714 - find the revision corresponding to a tag::
4723
4715
4724 hg id -n -r 1.3
4716 hg id -n -r 1.3
4725
4717
4726 - check the most recent revision of a remote repository::
4718 - check the most recent revision of a remote repository::
4727
4719
4728 hg id -r tip http://selenic.com/hg/
4720 hg id -r tip http://selenic.com/hg/
4729
4721
4730 See :hg:`log` for generating more information about specific revisions,
4722 See :hg:`log` for generating more information about specific revisions,
4731 including full hash identifiers.
4723 including full hash identifiers.
4732
4724
4733 Returns 0 if successful.
4725 Returns 0 if successful.
4734 """
4726 """
4735
4727
4736 if not repo and not source:
4728 if not repo and not source:
4737 raise error.Abort(_("there is no Mercurial repository here "
4729 raise error.Abort(_("there is no Mercurial repository here "
4738 "(.hg not found)"))
4730 "(.hg not found)"))
4739
4731
4740 if ui.debugflag:
4732 if ui.debugflag:
4741 hexfunc = hex
4733 hexfunc = hex
4742 else:
4734 else:
4743 hexfunc = short
4735 hexfunc = short
4744 default = not (num or id or branch or tags or bookmarks)
4736 default = not (num or id or branch or tags or bookmarks)
4745 output = []
4737 output = []
4746 revs = []
4738 revs = []
4747
4739
4748 if source:
4740 if source:
4749 source, branches = hg.parseurl(ui.expandpath(source))
4741 source, branches = hg.parseurl(ui.expandpath(source))
4750 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4742 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4751 repo = peer.local()
4743 repo = peer.local()
4752 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4744 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4753
4745
4754 if not repo:
4746 if not repo:
4755 if num or branch or tags:
4747 if num or branch or tags:
4756 raise error.Abort(
4748 raise error.Abort(
4757 _("can't query remote revision number, branch, or tags"))
4749 _("can't query remote revision number, branch, or tags"))
4758 if not rev and revs:
4750 if not rev and revs:
4759 rev = revs[0]
4751 rev = revs[0]
4760 if not rev:
4752 if not rev:
4761 rev = "tip"
4753 rev = "tip"
4762
4754
4763 remoterev = peer.lookup(rev)
4755 remoterev = peer.lookup(rev)
4764 if default or id:
4756 if default or id:
4765 output = [hexfunc(remoterev)]
4757 output = [hexfunc(remoterev)]
4766
4758
4767 def getbms():
4759 def getbms():
4768 bms = []
4760 bms = []
4769
4761
4770 if 'bookmarks' in peer.listkeys('namespaces'):
4762 if 'bookmarks' in peer.listkeys('namespaces'):
4771 hexremoterev = hex(remoterev)
4763 hexremoterev = hex(remoterev)
4772 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4764 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4773 if bmr == hexremoterev]
4765 if bmr == hexremoterev]
4774
4766
4775 return sorted(bms)
4767 return sorted(bms)
4776
4768
4777 if bookmarks:
4769 if bookmarks:
4778 output.extend(getbms())
4770 output.extend(getbms())
4779 elif default and not ui.quiet:
4771 elif default and not ui.quiet:
4780 # multiple bookmarks for a single parent separated by '/'
4772 # multiple bookmarks for a single parent separated by '/'
4781 bm = '/'.join(getbms())
4773 bm = '/'.join(getbms())
4782 if bm:
4774 if bm:
4783 output.append(bm)
4775 output.append(bm)
4784 else:
4776 else:
4785 ctx = scmutil.revsingle(repo, rev, None)
4777 ctx = scmutil.revsingle(repo, rev, None)
4786
4778
4787 if ctx.rev() is None:
4779 if ctx.rev() is None:
4788 ctx = repo[None]
4780 ctx = repo[None]
4789 parents = ctx.parents()
4781 parents = ctx.parents()
4790 taglist = []
4782 taglist = []
4791 for p in parents:
4783 for p in parents:
4792 taglist.extend(p.tags())
4784 taglist.extend(p.tags())
4793
4785
4794 changed = ""
4786 changed = ""
4795 if default or id or num:
4787 if default or id or num:
4796 if (any(repo.status())
4788 if (any(repo.status())
4797 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4789 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4798 changed = '+'
4790 changed = '+'
4799 if default or id:
4791 if default or id:
4800 output = ["%s%s" %
4792 output = ["%s%s" %
4801 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4793 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4802 if num:
4794 if num:
4803 output.append("%s%s" %
4795 output.append("%s%s" %
4804 ('+'.join([str(p.rev()) for p in parents]), changed))
4796 ('+'.join([str(p.rev()) for p in parents]), changed))
4805 else:
4797 else:
4806 if default or id:
4798 if default or id:
4807 output = [hexfunc(ctx.node())]
4799 output = [hexfunc(ctx.node())]
4808 if num:
4800 if num:
4809 output.append(str(ctx.rev()))
4801 output.append(str(ctx.rev()))
4810 taglist = ctx.tags()
4802 taglist = ctx.tags()
4811
4803
4812 if default and not ui.quiet:
4804 if default and not ui.quiet:
4813 b = ctx.branch()
4805 b = ctx.branch()
4814 if b != 'default':
4806 if b != 'default':
4815 output.append("(%s)" % b)
4807 output.append("(%s)" % b)
4816
4808
4817 # multiple tags for a single parent separated by '/'
4809 # multiple tags for a single parent separated by '/'
4818 t = '/'.join(taglist)
4810 t = '/'.join(taglist)
4819 if t:
4811 if t:
4820 output.append(t)
4812 output.append(t)
4821
4813
4822 # multiple bookmarks for a single parent separated by '/'
4814 # multiple bookmarks for a single parent separated by '/'
4823 bm = '/'.join(ctx.bookmarks())
4815 bm = '/'.join(ctx.bookmarks())
4824 if bm:
4816 if bm:
4825 output.append(bm)
4817 output.append(bm)
4826 else:
4818 else:
4827 if branch:
4819 if branch:
4828 output.append(ctx.branch())
4820 output.append(ctx.branch())
4829
4821
4830 if tags:
4822 if tags:
4831 output.extend(taglist)
4823 output.extend(taglist)
4832
4824
4833 if bookmarks:
4825 if bookmarks:
4834 output.extend(ctx.bookmarks())
4826 output.extend(ctx.bookmarks())
4835
4827
4836 ui.write("%s\n" % ' '.join(output))
4828 ui.write("%s\n" % ' '.join(output))
4837
4829
4838 @command('import|patch',
4830 @command('import|patch',
4839 [('p', 'strip', 1,
4831 [('p', 'strip', 1,
4840 _('directory strip option for patch. This has the same '
4832 _('directory strip option for patch. This has the same '
4841 'meaning as the corresponding patch option'), _('NUM')),
4833 'meaning as the corresponding patch option'), _('NUM')),
4842 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4834 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4843 ('e', 'edit', False, _('invoke editor on commit messages')),
4835 ('e', 'edit', False, _('invoke editor on commit messages')),
4844 ('f', 'force', None,
4836 ('f', 'force', None,
4845 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4837 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4846 ('', 'no-commit', None,
4838 ('', 'no-commit', None,
4847 _("don't commit, just update the working directory")),
4839 _("don't commit, just update the working directory")),
4848 ('', 'bypass', None,
4840 ('', 'bypass', None,
4849 _("apply patch without touching the working directory")),
4841 _("apply patch without touching the working directory")),
4850 ('', 'partial', None,
4842 ('', 'partial', None,
4851 _('commit even if some hunks fail')),
4843 _('commit even if some hunks fail')),
4852 ('', 'exact', None,
4844 ('', 'exact', None,
4853 _('abort if patch would apply lossily')),
4845 _('abort if patch would apply lossily')),
4854 ('', 'prefix', '',
4846 ('', 'prefix', '',
4855 _('apply patch to subdirectory'), _('DIR')),
4847 _('apply patch to subdirectory'), _('DIR')),
4856 ('', 'import-branch', None,
4848 ('', 'import-branch', None,
4857 _('use any branch information in patch (implied by --exact)'))] +
4849 _('use any branch information in patch (implied by --exact)'))] +
4858 commitopts + commitopts2 + similarityopts,
4850 commitopts + commitopts2 + similarityopts,
4859 _('[OPTION]... PATCH...'))
4851 _('[OPTION]... PATCH...'))
4860 def import_(ui, repo, patch1=None, *patches, **opts):
4852 def import_(ui, repo, patch1=None, *patches, **opts):
4861 """import an ordered set of patches
4853 """import an ordered set of patches
4862
4854
4863 Import a list of patches and commit them individually (unless
4855 Import a list of patches and commit them individually (unless
4864 --no-commit is specified).
4856 --no-commit is specified).
4865
4857
4866 To read a patch from standard input, use "-" as the patch name. If
4858 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.
4859 a URL is specified, the patch will be downloaded from there.
4868
4860
4869 Import first applies changes to the working directory (unless
4861 Import first applies changes to the working directory (unless
4870 --bypass is specified), import will abort if there are outstanding
4862 --bypass is specified), import will abort if there are outstanding
4871 changes.
4863 changes.
4872
4864
4873 Use --bypass to apply and commit patches directly to the
4865 Use --bypass to apply and commit patches directly to the
4874 repository, without affecting the working directory. Without
4866 repository, without affecting the working directory. Without
4875 --exact, patches will be applied on top of the working directory
4867 --exact, patches will be applied on top of the working directory
4876 parent revision.
4868 parent revision.
4877
4869
4878 You can import a patch straight from a mail message. Even patches
4870 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
4871 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
4872 text/plain or text/x-patch). From and Subject headers of email
4881 message are used as default committer and commit message. All
4873 message are used as default committer and commit message. All
4882 text/plain body parts before first diff are added to the commit
4874 text/plain body parts before first diff are added to the commit
4883 message.
4875 message.
4884
4876
4885 If the imported patch was generated by :hg:`export`, user and
4877 If the imported patch was generated by :hg:`export`, user and
4886 description from patch override values from message headers and
4878 description from patch override values from message headers and
4887 body. Values given on command line with -m/--message and -u/--user
4879 body. Values given on command line with -m/--message and -u/--user
4888 override these.
4880 override these.
4889
4881
4890 If --exact is specified, import will set the working directory to
4882 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
4883 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
4884 resulting changeset has a different ID than the one recorded in
4893 the patch. This will guard against various ways that portable
4885 the patch. This will guard against various ways that portable
4894 patch formats and mail systems might fail to transfer Mercurial
4886 patch formats and mail systems might fail to transfer Mercurial
4895 data or metadata. See :hg:`bundle` for lossless transmission.
4887 data or metadata. See :hg:`bundle` for lossless transmission.
4896
4888
4897 Use --partial to ensure a changeset will be created from the patch
4889 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
4890 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
4891 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
4892 by hand before :hg:`commit --amend` is run to update the created
4901 changeset. This flag exists to let people import patches that
4893 changeset. This flag exists to let people import patches that
4902 partially apply without losing the associated metadata (author,
4894 partially apply without losing the associated metadata (author,
4903 date, description, ...).
4895 date, description, ...).
4904
4896
4905 .. note::
4897 .. note::
4906
4898
4907 When no hunks apply cleanly, :hg:`import --partial` will create
4899 When no hunks apply cleanly, :hg:`import --partial` will create
4908 an empty changeset, importing only the patch metadata.
4900 an empty changeset, importing only the patch metadata.
4909
4901
4910 With -s/--similarity, hg will attempt to discover renames and
4902 With -s/--similarity, hg will attempt to discover renames and
4911 copies in the patch in the same way as :hg:`addremove`.
4903 copies in the patch in the same way as :hg:`addremove`.
4912
4904
4913 It is possible to use external patch programs to perform the patch
4905 It is possible to use external patch programs to perform the patch
4914 by setting the ``ui.patch`` configuration option. For the default
4906 by setting the ``ui.patch`` configuration option. For the default
4915 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4907 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4916 See :hg:`help config` for more information about configuration
4908 See :hg:`help config` for more information about configuration
4917 files and how to use these options.
4909 files and how to use these options.
4918
4910
4919 See :hg:`help dates` for a list of formats valid for -d/--date.
4911 See :hg:`help dates` for a list of formats valid for -d/--date.
4920
4912
4921 .. container:: verbose
4913 .. container:: verbose
4922
4914
4923 Examples:
4915 Examples:
4924
4916
4925 - import a traditional patch from a website and detect renames::
4917 - import a traditional patch from a website and detect renames::
4926
4918
4927 hg import -s 80 http://example.com/bugfix.patch
4919 hg import -s 80 http://example.com/bugfix.patch
4928
4920
4929 - import a changeset from an hgweb server::
4921 - import a changeset from an hgweb server::
4930
4922
4931 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4923 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4932
4924
4933 - import all the patches in an Unix-style mbox::
4925 - import all the patches in an Unix-style mbox::
4934
4926
4935 hg import incoming-patches.mbox
4927 hg import incoming-patches.mbox
4936
4928
4937 - attempt to exactly restore an exported changeset (not always
4929 - attempt to exactly restore an exported changeset (not always
4938 possible)::
4930 possible)::
4939
4931
4940 hg import --exact proposed-fix.patch
4932 hg import --exact proposed-fix.patch
4941
4933
4942 - use an external tool to apply a patch which is too fuzzy for
4934 - use an external tool to apply a patch which is too fuzzy for
4943 the default internal tool.
4935 the default internal tool.
4944
4936
4945 hg import --config ui.patch="patch --merge" fuzzy.patch
4937 hg import --config ui.patch="patch --merge" fuzzy.patch
4946
4938
4947 - change the default fuzzing from 2 to a less strict 7
4939 - change the default fuzzing from 2 to a less strict 7
4948
4940
4949 hg import --config ui.fuzz=7 fuzz.patch
4941 hg import --config ui.fuzz=7 fuzz.patch
4950
4942
4951 Returns 0 on success, 1 on partial success (see --partial).
4943 Returns 0 on success, 1 on partial success (see --partial).
4952 """
4944 """
4953
4945
4954 if not patch1:
4946 if not patch1:
4955 raise error.Abort(_('need at least one patch to import'))
4947 raise error.Abort(_('need at least one patch to import'))
4956
4948
4957 patches = (patch1,) + patches
4949 patches = (patch1,) + patches
4958
4950
4959 date = opts.get('date')
4951 date = opts.get('date')
4960 if date:
4952 if date:
4961 opts['date'] = util.parsedate(date)
4953 opts['date'] = util.parsedate(date)
4962
4954
4963 exact = opts.get('exact')
4955 exact = opts.get('exact')
4964 update = not opts.get('bypass')
4956 update = not opts.get('bypass')
4965 if not update and opts.get('no_commit'):
4957 if not update and opts.get('no_commit'):
4966 raise error.Abort(_('cannot use --no-commit with --bypass'))
4958 raise error.Abort(_('cannot use --no-commit with --bypass'))
4967 try:
4959 try:
4968 sim = float(opts.get('similarity') or 0)
4960 sim = float(opts.get('similarity') or 0)
4969 except ValueError:
4961 except ValueError:
4970 raise error.Abort(_('similarity must be a number'))
4962 raise error.Abort(_('similarity must be a number'))
4971 if sim < 0 or sim > 100:
4963 if sim < 0 or sim > 100:
4972 raise error.Abort(_('similarity must be between 0 and 100'))
4964 raise error.Abort(_('similarity must be between 0 and 100'))
4973 if sim and not update:
4965 if sim and not update:
4974 raise error.Abort(_('cannot use --similarity with --bypass'))
4966 raise error.Abort(_('cannot use --similarity with --bypass'))
4975 if exact:
4967 if exact:
4976 if opts.get('edit'):
4968 if opts.get('edit'):
4977 raise error.Abort(_('cannot use --exact with --edit'))
4969 raise error.Abort(_('cannot use --exact with --edit'))
4978 if opts.get('prefix'):
4970 if opts.get('prefix'):
4979 raise error.Abort(_('cannot use --exact with --prefix'))
4971 raise error.Abort(_('cannot use --exact with --prefix'))
4980
4972
4981 base = opts["base"]
4973 base = opts["base"]
4982 wlock = dsguard = lock = tr = None
4974 wlock = dsguard = lock = tr = None
4983 msgs = []
4975 msgs = []
4984 ret = 0
4976 ret = 0
4985
4977
4986
4978
4987 try:
4979 try:
4988 wlock = repo.wlock()
4980 wlock = repo.wlock()
4989
4981
4990 if update:
4982 if update:
4991 cmdutil.checkunfinished(repo)
4983 cmdutil.checkunfinished(repo)
4992 if (exact or not opts.get('force')):
4984 if (exact or not opts.get('force')):
4993 cmdutil.bailifchanged(repo)
4985 cmdutil.bailifchanged(repo)
4994
4986
4995 if not opts.get('no_commit'):
4987 if not opts.get('no_commit'):
4996 lock = repo.lock()
4988 lock = repo.lock()
4997 tr = repo.transaction('import')
4989 tr = repo.transaction('import')
4998 else:
4990 else:
4999 dsguard = cmdutil.dirstateguard(repo, 'import')
4991 dsguard = cmdutil.dirstateguard(repo, 'import')
5000 parents = repo[None].parents()
4992 parents = repo[None].parents()
5001 for patchurl in patches:
4993 for patchurl in patches:
5002 if patchurl == '-':
4994 if patchurl == '-':
5003 ui.status(_('applying patch from stdin\n'))
4995 ui.status(_('applying patch from stdin\n'))
5004 patchfile = ui.fin
4996 patchfile = ui.fin
5005 patchurl = 'stdin' # for error message
4997 patchurl = 'stdin' # for error message
5006 else:
4998 else:
5007 patchurl = os.path.join(base, patchurl)
4999 patchurl = os.path.join(base, patchurl)
5008 ui.status(_('applying %s\n') % patchurl)
5000 ui.status(_('applying %s\n') % patchurl)
5009 patchfile = hg.openpath(ui, patchurl)
5001 patchfile = hg.openpath(ui, patchurl)
5010
5002
5011 haspatch = False
5003 haspatch = False
5012 for hunk in patch.split(patchfile):
5004 for hunk in patch.split(patchfile):
5013 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5005 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5014 parents, opts,
5006 parents, opts,
5015 msgs, hg.clean)
5007 msgs, hg.clean)
5016 if msg:
5008 if msg:
5017 haspatch = True
5009 haspatch = True
5018 ui.note(msg + '\n')
5010 ui.note(msg + '\n')
5019 if update or exact:
5011 if update or exact:
5020 parents = repo[None].parents()
5012 parents = repo[None].parents()
5021 else:
5013 else:
5022 parents = [repo[node]]
5014 parents = [repo[node]]
5023 if rej:
5015 if rej:
5024 ui.write_err(_("patch applied partially\n"))
5016 ui.write_err(_("patch applied partially\n"))
5025 ui.write_err(_("(fix the .rej files and run "
5017 ui.write_err(_("(fix the .rej files and run "
5026 "`hg commit --amend`)\n"))
5018 "`hg commit --amend`)\n"))
5027 ret = 1
5019 ret = 1
5028 break
5020 break
5029
5021
5030 if not haspatch:
5022 if not haspatch:
5031 raise error.Abort(_('%s: no diffs found') % patchurl)
5023 raise error.Abort(_('%s: no diffs found') % patchurl)
5032
5024
5033 if tr:
5025 if tr:
5034 tr.close()
5026 tr.close()
5035 if msgs:
5027 if msgs:
5036 repo.savecommitmessage('\n* * *\n'.join(msgs))
5028 repo.savecommitmessage('\n* * *\n'.join(msgs))
5037 if dsguard:
5029 if dsguard:
5038 dsguard.close()
5030 dsguard.close()
5039 return ret
5031 return ret
5040 finally:
5032 finally:
5041 if tr:
5033 if tr:
5042 tr.release()
5034 tr.release()
5043 release(lock, dsguard, wlock)
5035 release(lock, dsguard, wlock)
5044
5036
5045 @command('incoming|in',
5037 @command('incoming|in',
5046 [('f', 'force', None,
5038 [('f', 'force', None,
5047 _('run even if remote repository is unrelated')),
5039 _('run even if remote repository is unrelated')),
5048 ('n', 'newest-first', None, _('show newest record first')),
5040 ('n', 'newest-first', None, _('show newest record first')),
5049 ('', 'bundle', '',
5041 ('', 'bundle', '',
5050 _('file to store the bundles into'), _('FILE')),
5042 _('file to store the bundles into'), _('FILE')),
5051 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5043 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5052 ('B', 'bookmarks', False, _("compare bookmarks")),
5044 ('B', 'bookmarks', False, _("compare bookmarks")),
5053 ('b', 'branch', [],
5045 ('b', 'branch', [],
5054 _('a specific branch you would like to pull'), _('BRANCH')),
5046 _('a specific branch you would like to pull'), _('BRANCH')),
5055 ] + logopts + remoteopts + subrepoopts,
5047 ] + logopts + remoteopts + subrepoopts,
5056 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5048 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5057 def incoming(ui, repo, source="default", **opts):
5049 def incoming(ui, repo, source="default", **opts):
5058 """show new changesets found in source
5050 """show new changesets found in source
5059
5051
5060 Show new changesets found in the specified path/URL or the default
5052 Show new changesets found in the specified path/URL or the default
5061 pull location. These are the changesets that would have been pulled
5053 pull location. These are the changesets that would have been pulled
5062 if a pull at the time you issued this command.
5054 if a pull at the time you issued this command.
5063
5055
5064 See pull for valid source format details.
5056 See pull for valid source format details.
5065
5057
5066 .. container:: verbose
5058 .. container:: verbose
5067
5059
5068 With -B/--bookmarks, the result of bookmark comparison between
5060 With -B/--bookmarks, the result of bookmark comparison between
5069 local and remote repositories is displayed. With -v/--verbose,
5061 local and remote repositories is displayed. With -v/--verbose,
5070 status is also displayed for each bookmark like below::
5062 status is also displayed for each bookmark like below::
5071
5063
5072 BM1 01234567890a added
5064 BM1 01234567890a added
5073 BM2 1234567890ab advanced
5065 BM2 1234567890ab advanced
5074 BM3 234567890abc diverged
5066 BM3 234567890abc diverged
5075 BM4 34567890abcd changed
5067 BM4 34567890abcd changed
5076
5068
5077 The action taken locally when pulling depends on the
5069 The action taken locally when pulling depends on the
5078 status of each bookmark:
5070 status of each bookmark:
5079
5071
5080 :``added``: pull will create it
5072 :``added``: pull will create it
5081 :``advanced``: pull will update it
5073 :``advanced``: pull will update it
5082 :``diverged``: pull will create a divergent bookmark
5074 :``diverged``: pull will create a divergent bookmark
5083 :``changed``: result depends on remote changesets
5075 :``changed``: result depends on remote changesets
5084
5076
5085 From the point of view of pulling behavior, bookmark
5077 From the point of view of pulling behavior, bookmark
5086 existing only in the remote repository are treated as ``added``,
5078 existing only in the remote repository are treated as ``added``,
5087 even if it is in fact locally deleted.
5079 even if it is in fact locally deleted.
5088
5080
5089 .. container:: verbose
5081 .. container:: verbose
5090
5082
5091 For remote repository, using --bundle avoids downloading the
5083 For remote repository, using --bundle avoids downloading the
5092 changesets twice if the incoming is followed by a pull.
5084 changesets twice if the incoming is followed by a pull.
5093
5085
5094 Examples:
5086 Examples:
5095
5087
5096 - show incoming changes with patches and full description::
5088 - show incoming changes with patches and full description::
5097
5089
5098 hg incoming -vp
5090 hg incoming -vp
5099
5091
5100 - show incoming changes excluding merges, store a bundle::
5092 - show incoming changes excluding merges, store a bundle::
5101
5093
5102 hg in -vpM --bundle incoming.hg
5094 hg in -vpM --bundle incoming.hg
5103 hg pull incoming.hg
5095 hg pull incoming.hg
5104
5096
5105 - briefly list changes inside a bundle::
5097 - briefly list changes inside a bundle::
5106
5098
5107 hg in changes.hg -T "{desc|firstline}\\n"
5099 hg in changes.hg -T "{desc|firstline}\\n"
5108
5100
5109 Returns 0 if there are incoming changes, 1 otherwise.
5101 Returns 0 if there are incoming changes, 1 otherwise.
5110 """
5102 """
5111 if opts.get('graph'):
5103 if opts.get('graph'):
5112 cmdutil.checkunsupportedgraphflags([], opts)
5104 cmdutil.checkunsupportedgraphflags([], opts)
5113 def display(other, chlist, displayer):
5105 def display(other, chlist, displayer):
5114 revdag = cmdutil.graphrevs(other, chlist, opts)
5106 revdag = cmdutil.graphrevs(other, chlist, opts)
5115 cmdutil.displaygraph(ui, repo, revdag, displayer,
5107 cmdutil.displaygraph(ui, repo, revdag, displayer,
5116 graphmod.asciiedges)
5108 graphmod.asciiedges)
5117
5109
5118 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5110 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5119 return 0
5111 return 0
5120
5112
5121 if opts.get('bundle') and opts.get('subrepos'):
5113 if opts.get('bundle') and opts.get('subrepos'):
5122 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5114 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5123
5115
5124 if opts.get('bookmarks'):
5116 if opts.get('bookmarks'):
5125 source, branches = hg.parseurl(ui.expandpath(source),
5117 source, branches = hg.parseurl(ui.expandpath(source),
5126 opts.get('branch'))
5118 opts.get('branch'))
5127 other = hg.peer(repo, opts, source)
5119 other = hg.peer(repo, opts, source)
5128 if 'bookmarks' not in other.listkeys('namespaces'):
5120 if 'bookmarks' not in other.listkeys('namespaces'):
5129 ui.warn(_("remote doesn't support bookmarks\n"))
5121 ui.warn(_("remote doesn't support bookmarks\n"))
5130 return 0
5122 return 0
5131 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5123 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5132 return bookmarks.incoming(ui, repo, other)
5124 return bookmarks.incoming(ui, repo, other)
5133
5125
5134 repo._subtoppath = ui.expandpath(source)
5126 repo._subtoppath = ui.expandpath(source)
5135 try:
5127 try:
5136 return hg.incoming(ui, repo, source, opts)
5128 return hg.incoming(ui, repo, source, opts)
5137 finally:
5129 finally:
5138 del repo._subtoppath
5130 del repo._subtoppath
5139
5131
5140
5132
5141 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5133 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5142 norepo=True)
5134 norepo=True)
5143 def init(ui, dest=".", **opts):
5135 def init(ui, dest=".", **opts):
5144 """create a new repository in the given directory
5136 """create a new repository in the given directory
5145
5137
5146 Initialize a new repository in the given directory. If the given
5138 Initialize a new repository in the given directory. If the given
5147 directory does not exist, it will be created.
5139 directory does not exist, it will be created.
5148
5140
5149 If no directory is given, the current directory is used.
5141 If no directory is given, the current directory is used.
5150
5142
5151 It is possible to specify an ``ssh://`` URL as the destination.
5143 It is possible to specify an ``ssh://`` URL as the destination.
5152 See :hg:`help urls` for more information.
5144 See :hg:`help urls` for more information.
5153
5145
5154 Returns 0 on success.
5146 Returns 0 on success.
5155 """
5147 """
5156 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5148 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5157
5149
5158 @command('locate',
5150 @command('locate',
5159 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5151 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5160 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5152 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5161 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5153 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5162 ] + walkopts,
5154 ] + walkopts,
5163 _('[OPTION]... [PATTERN]...'))
5155 _('[OPTION]... [PATTERN]...'))
5164 def locate(ui, repo, *pats, **opts):
5156 def locate(ui, repo, *pats, **opts):
5165 """locate files matching specific patterns (DEPRECATED)
5157 """locate files matching specific patterns (DEPRECATED)
5166
5158
5167 Print files under Mercurial control in the working directory whose
5159 Print files under Mercurial control in the working directory whose
5168 names match the given patterns.
5160 names match the given patterns.
5169
5161
5170 By default, this command searches all directories in the working
5162 By default, this command searches all directories in the working
5171 directory. To search just the current directory and its
5163 directory. To search just the current directory and its
5172 subdirectories, use "--include .".
5164 subdirectories, use "--include .".
5173
5165
5174 If no patterns are given to match, this command prints the names
5166 If no patterns are given to match, this command prints the names
5175 of all files under Mercurial control in the working directory.
5167 of all files under Mercurial control in the working directory.
5176
5168
5177 If you want to feed the output of this command into the "xargs"
5169 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
5170 command, use the -0 option to both this command and "xargs". This
5179 will avoid the problem of "xargs" treating single filenames that
5171 will avoid the problem of "xargs" treating single filenames that
5180 contain whitespace as multiple filenames.
5172 contain whitespace as multiple filenames.
5181
5173
5182 See :hg:`help files` for a more versatile command.
5174 See :hg:`help files` for a more versatile command.
5183
5175
5184 Returns 0 if a match is found, 1 otherwise.
5176 Returns 0 if a match is found, 1 otherwise.
5185 """
5177 """
5186 if opts.get('print0'):
5178 if opts.get('print0'):
5187 end = '\0'
5179 end = '\0'
5188 else:
5180 else:
5189 end = '\n'
5181 end = '\n'
5190 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5182 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5191
5183
5192 ret = 1
5184 ret = 1
5193 ctx = repo[rev]
5185 ctx = repo[rev]
5194 m = scmutil.match(ctx, pats, opts, default='relglob',
5186 m = scmutil.match(ctx, pats, opts, default='relglob',
5195 badfn=lambda x, y: False)
5187 badfn=lambda x, y: False)
5196
5188
5197 for abs in ctx.matches(m):
5189 for abs in ctx.matches(m):
5198 if opts.get('fullpath'):
5190 if opts.get('fullpath'):
5199 ui.write(repo.wjoin(abs), end)
5191 ui.write(repo.wjoin(abs), end)
5200 else:
5192 else:
5201 ui.write(((pats and m.rel(abs)) or abs), end)
5193 ui.write(((pats and m.rel(abs)) or abs), end)
5202 ret = 0
5194 ret = 0
5203
5195
5204 return ret
5196 return ret
5205
5197
5206 @command('^log|history',
5198 @command('^log|history',
5207 [('f', 'follow', None,
5199 [('f', 'follow', None,
5208 _('follow changeset history, or file history across copies and renames')),
5200 _('follow changeset history, or file history across copies and renames')),
5209 ('', 'follow-first', None,
5201 ('', 'follow-first', None,
5210 _('only follow the first parent of merge changesets (DEPRECATED)')),
5202 _('only follow the first parent of merge changesets (DEPRECATED)')),
5211 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5203 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5212 ('C', 'copies', None, _('show copied files')),
5204 ('C', 'copies', None, _('show copied files')),
5213 ('k', 'keyword', [],
5205 ('k', 'keyword', [],
5214 _('do case-insensitive search for a given text'), _('TEXT')),
5206 _('do case-insensitive search for a given text'), _('TEXT')),
5215 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5207 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5216 ('', 'removed', None, _('include revisions where files were removed')),
5208 ('', 'removed', None, _('include revisions where files were removed')),
5217 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5209 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5218 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5210 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5219 ('', 'only-branch', [],
5211 ('', 'only-branch', [],
5220 _('show only changesets within the given named branch (DEPRECATED)'),
5212 _('show only changesets within the given named branch (DEPRECATED)'),
5221 _('BRANCH')),
5213 _('BRANCH')),
5222 ('b', 'branch', [],
5214 ('b', 'branch', [],
5223 _('show changesets within the given named branch'), _('BRANCH')),
5215 _('show changesets within the given named branch'), _('BRANCH')),
5224 ('P', 'prune', [],
5216 ('P', 'prune', [],
5225 _('do not display revision or any of its ancestors'), _('REV')),
5217 _('do not display revision or any of its ancestors'), _('REV')),
5226 ] + logopts + walkopts,
5218 ] + logopts + walkopts,
5227 _('[OPTION]... [FILE]'),
5219 _('[OPTION]... [FILE]'),
5228 inferrepo=True)
5220 inferrepo=True)
5229 def log(ui, repo, *pats, **opts):
5221 def log(ui, repo, *pats, **opts):
5230 """show revision history of entire repository or files
5222 """show revision history of entire repository or files
5231
5223
5232 Print the revision history of the specified files or the entire
5224 Print the revision history of the specified files or the entire
5233 project.
5225 project.
5234
5226
5235 If no revision range is specified, the default is ``tip:0`` unless
5227 If no revision range is specified, the default is ``tip:0`` unless
5236 --follow is set, in which case the working directory parent is
5228 --follow is set, in which case the working directory parent is
5237 used as the starting revision.
5229 used as the starting revision.
5238
5230
5239 File history is shown without following rename or copy history of
5231 File history is shown without following rename or copy history of
5240 files. Use -f/--follow with a filename to follow history across
5232 files. Use -f/--follow with a filename to follow history across
5241 renames and copies. --follow without a filename will only show
5233 renames and copies. --follow without a filename will only show
5242 ancestors or descendants of the starting revision.
5234 ancestors or descendants of the starting revision.
5243
5235
5244 By default this command prints revision number and changeset id,
5236 By default this command prints revision number and changeset id,
5245 tags, non-trivial parents, user, date and time, and a summary for
5237 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
5238 each commit. When the -v/--verbose switch is used, the list of
5247 changed files and full commit message are shown.
5239 changed files and full commit message are shown.
5248
5240
5249 With --graph the revisions are shown as an ASCII art DAG with the most
5241 With --graph the revisions are shown as an ASCII art DAG with the most
5250 recent changeset at the top.
5242 recent changeset at the top.
5251 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5243 '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
5244 and '+' represents a fork where the changeset from the lines below is a
5253 parent of the 'o' merge on the same line.
5245 parent of the 'o' merge on the same line.
5254
5246
5255 .. note::
5247 .. note::
5256
5248
5257 :hg:`log --patch` may generate unexpected diff output for merge
5249 :hg:`log --patch` may generate unexpected diff output for merge
5258 changesets, as it will only compare the merge changeset against
5250 changesets, as it will only compare the merge changeset against
5259 its first parent. Also, only files different from BOTH parents
5251 its first parent. Also, only files different from BOTH parents
5260 will appear in files:.
5252 will appear in files:.
5261
5253
5262 .. note::
5254 .. note::
5263
5255
5264 For performance reasons, :hg:`log FILE` may omit duplicate changes
5256 For performance reasons, :hg:`log FILE` may omit duplicate changes
5265 made on branches and will not show removals or mode changes. To
5257 made on branches and will not show removals or mode changes. To
5266 see all such changes, use the --removed switch.
5258 see all such changes, use the --removed switch.
5267
5259
5268 .. container:: verbose
5260 .. container:: verbose
5269
5261
5270 Some examples:
5262 Some examples:
5271
5263
5272 - changesets with full descriptions and file lists::
5264 - changesets with full descriptions and file lists::
5273
5265
5274 hg log -v
5266 hg log -v
5275
5267
5276 - changesets ancestral to the working directory::
5268 - changesets ancestral to the working directory::
5277
5269
5278 hg log -f
5270 hg log -f
5279
5271
5280 - last 10 commits on the current branch::
5272 - last 10 commits on the current branch::
5281
5273
5282 hg log -l 10 -b .
5274 hg log -l 10 -b .
5283
5275
5284 - changesets showing all modifications of a file, including removals::
5276 - changesets showing all modifications of a file, including removals::
5285
5277
5286 hg log --removed file.c
5278 hg log --removed file.c
5287
5279
5288 - all changesets that touch a directory, with diffs, excluding merges::
5280 - all changesets that touch a directory, with diffs, excluding merges::
5289
5281
5290 hg log -Mp lib/
5282 hg log -Mp lib/
5291
5283
5292 - all revision numbers that match a keyword::
5284 - all revision numbers that match a keyword::
5293
5285
5294 hg log -k bug --template "{rev}\\n"
5286 hg log -k bug --template "{rev}\\n"
5295
5287
5296 - the full hash identifier of the working directory parent::
5288 - the full hash identifier of the working directory parent::
5297
5289
5298 hg log -r . --template "{node}\\n"
5290 hg log -r . --template "{node}\\n"
5299
5291
5300 - list available log templates::
5292 - list available log templates::
5301
5293
5302 hg log -T list
5294 hg log -T list
5303
5295
5304 - check if a given changeset is included in a tagged release::
5296 - check if a given changeset is included in a tagged release::
5305
5297
5306 hg log -r "a21ccf and ancestor(1.9)"
5298 hg log -r "a21ccf and ancestor(1.9)"
5307
5299
5308 - find all changesets by some user in a date range::
5300 - find all changesets by some user in a date range::
5309
5301
5310 hg log -k alice -d "may 2008 to jul 2008"
5302 hg log -k alice -d "may 2008 to jul 2008"
5311
5303
5312 - summary of all changesets after the last tag::
5304 - summary of all changesets after the last tag::
5313
5305
5314 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5306 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5315
5307
5316 See :hg:`help dates` for a list of formats valid for -d/--date.
5308 See :hg:`help dates` for a list of formats valid for -d/--date.
5317
5309
5318 See :hg:`help revisions` and :hg:`help revsets` for more about
5310 See :hg:`help revisions` and :hg:`help revsets` for more about
5319 specifying and ordering revisions.
5311 specifying and ordering revisions.
5320
5312
5321 See :hg:`help templates` for more about pre-packaged styles and
5313 See :hg:`help templates` for more about pre-packaged styles and
5322 specifying custom templates.
5314 specifying custom templates.
5323
5315
5324 Returns 0 on success.
5316 Returns 0 on success.
5325
5317
5326 """
5318 """
5327 if opts.get('follow') and opts.get('rev'):
5319 if opts.get('follow') and opts.get('rev'):
5328 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5320 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5329 del opts['follow']
5321 del opts['follow']
5330
5322
5331 if opts.get('graph'):
5323 if opts.get('graph'):
5332 return cmdutil.graphlog(ui, repo, *pats, **opts)
5324 return cmdutil.graphlog(ui, repo, *pats, **opts)
5333
5325
5334 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5326 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5335 limit = cmdutil.loglimit(opts)
5327 limit = cmdutil.loglimit(opts)
5336 count = 0
5328 count = 0
5337
5329
5338 getrenamed = None
5330 getrenamed = None
5339 if opts.get('copies'):
5331 if opts.get('copies'):
5340 endrev = None
5332 endrev = None
5341 if opts.get('rev'):
5333 if opts.get('rev'):
5342 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5334 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5343 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5335 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5344
5336
5345 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5337 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5346 for rev in revs:
5338 for rev in revs:
5347 if count == limit:
5339 if count == limit:
5348 break
5340 break
5349 ctx = repo[rev]
5341 ctx = repo[rev]
5350 copies = None
5342 copies = None
5351 if getrenamed is not None and rev:
5343 if getrenamed is not None and rev:
5352 copies = []
5344 copies = []
5353 for fn in ctx.files():
5345 for fn in ctx.files():
5354 rename = getrenamed(fn, rev)
5346 rename = getrenamed(fn, rev)
5355 if rename:
5347 if rename:
5356 copies.append((fn, rename[0]))
5348 copies.append((fn, rename[0]))
5357 if filematcher:
5349 if filematcher:
5358 revmatchfn = filematcher(ctx.rev())
5350 revmatchfn = filematcher(ctx.rev())
5359 else:
5351 else:
5360 revmatchfn = None
5352 revmatchfn = None
5361 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5353 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5362 if displayer.flush(ctx):
5354 if displayer.flush(ctx):
5363 count += 1
5355 count += 1
5364
5356
5365 displayer.close()
5357 displayer.close()
5366
5358
5367 @command('manifest',
5359 @command('manifest',
5368 [('r', 'rev', '', _('revision to display'), _('REV')),
5360 [('r', 'rev', '', _('revision to display'), _('REV')),
5369 ('', 'all', False, _("list files from all revisions"))]
5361 ('', 'all', False, _("list files from all revisions"))]
5370 + formatteropts,
5362 + formatteropts,
5371 _('[-r REV]'))
5363 _('[-r REV]'))
5372 def manifest(ui, repo, node=None, rev=None, **opts):
5364 def manifest(ui, repo, node=None, rev=None, **opts):
5373 """output the current or given revision of the project manifest
5365 """output the current or given revision of the project manifest
5374
5366
5375 Print a list of version controlled files for the given revision.
5367 Print a list of version controlled files for the given revision.
5376 If no revision is given, the first parent of the working directory
5368 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.
5369 is used, or the null revision if no revision is checked out.
5378
5370
5379 With -v, print file permissions, symlink and executable bits.
5371 With -v, print file permissions, symlink and executable bits.
5380 With --debug, print file revision hashes.
5372 With --debug, print file revision hashes.
5381
5373
5382 If option --all is specified, the list of all files from all revisions
5374 If option --all is specified, the list of all files from all revisions
5383 is printed. This includes deleted and renamed files.
5375 is printed. This includes deleted and renamed files.
5384
5376
5385 Returns 0 on success.
5377 Returns 0 on success.
5386 """
5378 """
5387
5379
5388 fm = ui.formatter('manifest', opts)
5380 fm = ui.formatter('manifest', opts)
5389
5381
5390 if opts.get('all'):
5382 if opts.get('all'):
5391 if rev or node:
5383 if rev or node:
5392 raise error.Abort(_("can't specify a revision with --all"))
5384 raise error.Abort(_("can't specify a revision with --all"))
5393
5385
5394 res = []
5386 res = []
5395 prefix = "data/"
5387 prefix = "data/"
5396 suffix = ".i"
5388 suffix = ".i"
5397 plen = len(prefix)
5389 plen = len(prefix)
5398 slen = len(suffix)
5390 slen = len(suffix)
5399 with repo.lock():
5391 with repo.lock():
5400 for fn, b, size in repo.store.datafiles():
5392 for fn, b, size in repo.store.datafiles():
5401 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5393 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5402 res.append(fn[plen:-slen])
5394 res.append(fn[plen:-slen])
5403 for f in res:
5395 for f in res:
5404 fm.startitem()
5396 fm.startitem()
5405 fm.write("path", '%s\n', f)
5397 fm.write("path", '%s\n', f)
5406 fm.end()
5398 fm.end()
5407 return
5399 return
5408
5400
5409 if rev and node:
5401 if rev and node:
5410 raise error.Abort(_("please specify just one revision"))
5402 raise error.Abort(_("please specify just one revision"))
5411
5403
5412 if not node:
5404 if not node:
5413 node = rev
5405 node = rev
5414
5406
5415 char = {'l': '@', 'x': '*', '': ''}
5407 char = {'l': '@', 'x': '*', '': ''}
5416 mode = {'l': '644', 'x': '755', '': '644'}
5408 mode = {'l': '644', 'x': '755', '': '644'}
5417 ctx = scmutil.revsingle(repo, node)
5409 ctx = scmutil.revsingle(repo, node)
5418 mf = ctx.manifest()
5410 mf = ctx.manifest()
5419 for f in ctx:
5411 for f in ctx:
5420 fm.startitem()
5412 fm.startitem()
5421 fl = ctx[f].flags()
5413 fl = ctx[f].flags()
5422 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5414 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5423 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5415 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5424 fm.write('path', '%s\n', f)
5416 fm.write('path', '%s\n', f)
5425 fm.end()
5417 fm.end()
5426
5418
5427 @command('^merge',
5419 @command('^merge',
5428 [('f', 'force', None,
5420 [('f', 'force', None,
5429 _('force a merge including outstanding changes (DEPRECATED)')),
5421 _('force a merge including outstanding changes (DEPRECATED)')),
5430 ('r', 'rev', '', _('revision to merge'), _('REV')),
5422 ('r', 'rev', '', _('revision to merge'), _('REV')),
5431 ('P', 'preview', None,
5423 ('P', 'preview', None,
5432 _('review revisions to merge (no merge is performed)'))
5424 _('review revisions to merge (no merge is performed)'))
5433 ] + mergetoolopts,
5425 ] + mergetoolopts,
5434 _('[-P] [[-r] REV]'))
5426 _('[-P] [[-r] REV]'))
5435 def merge(ui, repo, node=None, **opts):
5427 def merge(ui, repo, node=None, **opts):
5436 """merge another revision into working directory
5428 """merge another revision into working directory
5437
5429
5438 The current working directory is updated with all changes made in
5430 The current working directory is updated with all changes made in
5439 the requested revision since the last common predecessor revision.
5431 the requested revision since the last common predecessor revision.
5440
5432
5441 Files that changed between either parent are marked as changed for
5433 Files that changed between either parent are marked as changed for
5442 the next commit and a commit must be performed before any further
5434 the next commit and a commit must be performed before any further
5443 updates to the repository are allowed. The next commit will have
5435 updates to the repository are allowed. The next commit will have
5444 two parents.
5436 two parents.
5445
5437
5446 ``--tool`` can be used to specify the merge tool used for file
5438 ``--tool`` can be used to specify the merge tool used for file
5447 merges. It overrides the HGMERGE environment variable and your
5439 merges. It overrides the HGMERGE environment variable and your
5448 configuration files. See :hg:`help merge-tools` for options.
5440 configuration files. See :hg:`help merge-tools` for options.
5449
5441
5450 If no revision is specified, the working directory's parent is a
5442 If no revision is specified, the working directory's parent is a
5451 head revision, and the current branch contains exactly one other
5443 head revision, and the current branch contains exactly one other
5452 head, the other head is merged with by default. Otherwise, an
5444 head, the other head is merged with by default. Otherwise, an
5453 explicit revision with which to merge with must be provided.
5445 explicit revision with which to merge with must be provided.
5454
5446
5455 See :hg:`help resolve` for information on handling file conflicts.
5447 See :hg:`help resolve` for information on handling file conflicts.
5456
5448
5457 To undo an uncommitted merge, use :hg:`update --clean .` which
5449 To undo an uncommitted merge, use :hg:`update --clean .` which
5458 will check out a clean copy of the original merge parent, losing
5450 will check out a clean copy of the original merge parent, losing
5459 all changes.
5451 all changes.
5460
5452
5461 Returns 0 on success, 1 if there are unresolved files.
5453 Returns 0 on success, 1 if there are unresolved files.
5462 """
5454 """
5463
5455
5464 if opts.get('rev') and node:
5456 if opts.get('rev') and node:
5465 raise error.Abort(_("please specify just one revision"))
5457 raise error.Abort(_("please specify just one revision"))
5466 if not node:
5458 if not node:
5467 node = opts.get('rev')
5459 node = opts.get('rev')
5468
5460
5469 if node:
5461 if node:
5470 node = scmutil.revsingle(repo, node).node()
5462 node = scmutil.revsingle(repo, node).node()
5471
5463
5472 if not node:
5464 if not node:
5473 node = repo[destutil.destmerge(repo)].node()
5465 node = repo[destutil.destmerge(repo)].node()
5474
5466
5475 if opts.get('preview'):
5467 if opts.get('preview'):
5476 # find nodes that are ancestors of p2 but not of p1
5468 # find nodes that are ancestors of p2 but not of p1
5477 p1 = repo.lookup('.')
5469 p1 = repo.lookup('.')
5478 p2 = repo.lookup(node)
5470 p2 = repo.lookup(node)
5479 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5471 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5480
5472
5481 displayer = cmdutil.show_changeset(ui, repo, opts)
5473 displayer = cmdutil.show_changeset(ui, repo, opts)
5482 for node in nodes:
5474 for node in nodes:
5483 displayer.show(repo[node])
5475 displayer.show(repo[node])
5484 displayer.close()
5476 displayer.close()
5485 return 0
5477 return 0
5486
5478
5487 try:
5479 try:
5488 # ui.forcemerge is an internal variable, do not document
5480 # ui.forcemerge is an internal variable, do not document
5489 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5481 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5490 force = opts.get('force')
5482 force = opts.get('force')
5491 labels = ['working copy', 'merge rev']
5483 labels = ['working copy', 'merge rev']
5492 return hg.merge(repo, node, force=force, mergeforce=force,
5484 return hg.merge(repo, node, force=force, mergeforce=force,
5493 labels=labels)
5485 labels=labels)
5494 finally:
5486 finally:
5495 ui.setconfig('ui', 'forcemerge', '', 'merge')
5487 ui.setconfig('ui', 'forcemerge', '', 'merge')
5496
5488
5497 @command('outgoing|out',
5489 @command('outgoing|out',
5498 [('f', 'force', None, _('run even when the destination is unrelated')),
5490 [('f', 'force', None, _('run even when the destination is unrelated')),
5499 ('r', 'rev', [],
5491 ('r', 'rev', [],
5500 _('a changeset intended to be included in the destination'), _('REV')),
5492 _('a changeset intended to be included in the destination'), _('REV')),
5501 ('n', 'newest-first', None, _('show newest record first')),
5493 ('n', 'newest-first', None, _('show newest record first')),
5502 ('B', 'bookmarks', False, _('compare bookmarks')),
5494 ('B', 'bookmarks', False, _('compare bookmarks')),
5503 ('b', 'branch', [], _('a specific branch you would like to push'),
5495 ('b', 'branch', [], _('a specific branch you would like to push'),
5504 _('BRANCH')),
5496 _('BRANCH')),
5505 ] + logopts + remoteopts + subrepoopts,
5497 ] + logopts + remoteopts + subrepoopts,
5506 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5498 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5507 def outgoing(ui, repo, dest=None, **opts):
5499 def outgoing(ui, repo, dest=None, **opts):
5508 """show changesets not found in the destination
5500 """show changesets not found in the destination
5509
5501
5510 Show changesets not found in the specified destination repository
5502 Show changesets not found in the specified destination repository
5511 or the default push location. These are the changesets that would
5503 or the default push location. These are the changesets that would
5512 be pushed if a push was requested.
5504 be pushed if a push was requested.
5513
5505
5514 See pull for details of valid destination formats.
5506 See pull for details of valid destination formats.
5515
5507
5516 .. container:: verbose
5508 .. container:: verbose
5517
5509
5518 With -B/--bookmarks, the result of bookmark comparison between
5510 With -B/--bookmarks, the result of bookmark comparison between
5519 local and remote repositories is displayed. With -v/--verbose,
5511 local and remote repositories is displayed. With -v/--verbose,
5520 status is also displayed for each bookmark like below::
5512 status is also displayed for each bookmark like below::
5521
5513
5522 BM1 01234567890a added
5514 BM1 01234567890a added
5523 BM2 deleted
5515 BM2 deleted
5524 BM3 234567890abc advanced
5516 BM3 234567890abc advanced
5525 BM4 34567890abcd diverged
5517 BM4 34567890abcd diverged
5526 BM5 4567890abcde changed
5518 BM5 4567890abcde changed
5527
5519
5528 The action taken when pushing depends on the
5520 The action taken when pushing depends on the
5529 status of each bookmark:
5521 status of each bookmark:
5530
5522
5531 :``added``: push with ``-B`` will create it
5523 :``added``: push with ``-B`` will create it
5532 :``deleted``: push with ``-B`` will delete it
5524 :``deleted``: push with ``-B`` will delete it
5533 :``advanced``: push will update it
5525 :``advanced``: push will update it
5534 :``diverged``: push with ``-B`` will update it
5526 :``diverged``: push with ``-B`` will update it
5535 :``changed``: push with ``-B`` will update it
5527 :``changed``: push with ``-B`` will update it
5536
5528
5537 From the point of view of pushing behavior, bookmarks
5529 From the point of view of pushing behavior, bookmarks
5538 existing only in the remote repository are treated as
5530 existing only in the remote repository are treated as
5539 ``deleted``, even if it is in fact added remotely.
5531 ``deleted``, even if it is in fact added remotely.
5540
5532
5541 Returns 0 if there are outgoing changes, 1 otherwise.
5533 Returns 0 if there are outgoing changes, 1 otherwise.
5542 """
5534 """
5543 if opts.get('graph'):
5535 if opts.get('graph'):
5544 cmdutil.checkunsupportedgraphflags([], opts)
5536 cmdutil.checkunsupportedgraphflags([], opts)
5545 o, other = hg._outgoing(ui, repo, dest, opts)
5537 o, other = hg._outgoing(ui, repo, dest, opts)
5546 if not o:
5538 if not o:
5547 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5539 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5548 return
5540 return
5549
5541
5550 revdag = cmdutil.graphrevs(repo, o, opts)
5542 revdag = cmdutil.graphrevs(repo, o, opts)
5551 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5543 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5552 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5544 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5553 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5545 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5554 return 0
5546 return 0
5555
5547
5556 if opts.get('bookmarks'):
5548 if opts.get('bookmarks'):
5557 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5549 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5558 dest, branches = hg.parseurl(dest, opts.get('branch'))
5550 dest, branches = hg.parseurl(dest, opts.get('branch'))
5559 other = hg.peer(repo, opts, dest)
5551 other = hg.peer(repo, opts, dest)
5560 if 'bookmarks' not in other.listkeys('namespaces'):
5552 if 'bookmarks' not in other.listkeys('namespaces'):
5561 ui.warn(_("remote doesn't support bookmarks\n"))
5553 ui.warn(_("remote doesn't support bookmarks\n"))
5562 return 0
5554 return 0
5563 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5555 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5564 return bookmarks.outgoing(ui, repo, other)
5556 return bookmarks.outgoing(ui, repo, other)
5565
5557
5566 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5558 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5567 try:
5559 try:
5568 return hg.outgoing(ui, repo, dest, opts)
5560 return hg.outgoing(ui, repo, dest, opts)
5569 finally:
5561 finally:
5570 del repo._subtoppath
5562 del repo._subtoppath
5571
5563
5572 @command('parents',
5564 @command('parents',
5573 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5565 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5574 ] + templateopts,
5566 ] + templateopts,
5575 _('[-r REV] [FILE]'),
5567 _('[-r REV] [FILE]'),
5576 inferrepo=True)
5568 inferrepo=True)
5577 def parents(ui, repo, file_=None, **opts):
5569 def parents(ui, repo, file_=None, **opts):
5578 """show the parents of the working directory or revision (DEPRECATED)
5570 """show the parents of the working directory or revision (DEPRECATED)
5579
5571
5580 Print the working directory's parent revisions. If a revision is
5572 Print the working directory's parent revisions. If a revision is
5581 given via -r/--rev, the parent of that revision will be printed.
5573 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
5574 If a file argument is given, the revision in which the file was
5583 last changed (before the working directory revision or the
5575 last changed (before the working directory revision or the
5584 argument to --rev if given) is printed.
5576 argument to --rev if given) is printed.
5585
5577
5586 This command is equivalent to::
5578 This command is equivalent to::
5587
5579
5588 hg log -r "p1()+p2()" or
5580 hg log -r "p1()+p2()" or
5589 hg log -r "p1(REV)+p2(REV)" or
5581 hg log -r "p1(REV)+p2(REV)" or
5590 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5582 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))"
5583 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5592
5584
5593 See :hg:`summary` and :hg:`help revsets` for related information.
5585 See :hg:`summary` and :hg:`help revsets` for related information.
5594
5586
5595 Returns 0 on success.
5587 Returns 0 on success.
5596 """
5588 """
5597
5589
5598 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5590 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5599
5591
5600 if file_:
5592 if file_:
5601 m = scmutil.match(ctx, (file_,), opts)
5593 m = scmutil.match(ctx, (file_,), opts)
5602 if m.anypats() or len(m.files()) != 1:
5594 if m.anypats() or len(m.files()) != 1:
5603 raise error.Abort(_('can only specify an explicit filename'))
5595 raise error.Abort(_('can only specify an explicit filename'))
5604 file_ = m.files()[0]
5596 file_ = m.files()[0]
5605 filenodes = []
5597 filenodes = []
5606 for cp in ctx.parents():
5598 for cp in ctx.parents():
5607 if not cp:
5599 if not cp:
5608 continue
5600 continue
5609 try:
5601 try:
5610 filenodes.append(cp.filenode(file_))
5602 filenodes.append(cp.filenode(file_))
5611 except error.LookupError:
5603 except error.LookupError:
5612 pass
5604 pass
5613 if not filenodes:
5605 if not filenodes:
5614 raise error.Abort(_("'%s' not found in manifest!") % file_)
5606 raise error.Abort(_("'%s' not found in manifest!") % file_)
5615 p = []
5607 p = []
5616 for fn in filenodes:
5608 for fn in filenodes:
5617 fctx = repo.filectx(file_, fileid=fn)
5609 fctx = repo.filectx(file_, fileid=fn)
5618 p.append(fctx.node())
5610 p.append(fctx.node())
5619 else:
5611 else:
5620 p = [cp.node() for cp in ctx.parents()]
5612 p = [cp.node() for cp in ctx.parents()]
5621
5613
5622 displayer = cmdutil.show_changeset(ui, repo, opts)
5614 displayer = cmdutil.show_changeset(ui, repo, opts)
5623 for n in p:
5615 for n in p:
5624 if n != nullid:
5616 if n != nullid:
5625 displayer.show(repo[n])
5617 displayer.show(repo[n])
5626 displayer.close()
5618 displayer.close()
5627
5619
5628 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5620 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5629 def paths(ui, repo, search=None, **opts):
5621 def paths(ui, repo, search=None, **opts):
5630 """show aliases for remote repositories
5622 """show aliases for remote repositories
5631
5623
5632 Show definition of symbolic path name NAME. If no name is given,
5624 Show definition of symbolic path name NAME. If no name is given,
5633 show definition of all available names.
5625 show definition of all available names.
5634
5626
5635 Option -q/--quiet suppresses all output when searching for NAME
5627 Option -q/--quiet suppresses all output when searching for NAME
5636 and shows only the path names when listing all definitions.
5628 and shows only the path names when listing all definitions.
5637
5629
5638 Path names are defined in the [paths] section of your
5630 Path names are defined in the [paths] section of your
5639 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5631 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5640 repository, ``.hg/hgrc`` is used, too.
5632 repository, ``.hg/hgrc`` is used, too.
5641
5633
5642 The path names ``default`` and ``default-push`` have a special
5634 The path names ``default`` and ``default-push`` have a special
5643 meaning. When performing a push or pull operation, they are used
5635 meaning. When performing a push or pull operation, they are used
5644 as fallbacks if no location is specified on the command-line.
5636 as fallbacks if no location is specified on the command-line.
5645 When ``default-push`` is set, it will be used for push and
5637 When ``default-push`` is set, it will be used for push and
5646 ``default`` will be used for pull; otherwise ``default`` is used
5638 ``default`` will be used for pull; otherwise ``default`` is used
5647 as the fallback for both. When cloning a repository, the clone
5639 as the fallback for both. When cloning a repository, the clone
5648 source is written as ``default`` in ``.hg/hgrc``.
5640 source is written as ``default`` in ``.hg/hgrc``.
5649
5641
5650 .. note::
5642 .. note::
5651
5643
5652 ``default`` and ``default-push`` apply to all inbound (e.g.
5644 ``default`` and ``default-push`` apply to all inbound (e.g.
5653 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5645 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5654 and :hg:`bundle`) operations.
5646 and :hg:`bundle`) operations.
5655
5647
5656 See :hg:`help urls` for more information.
5648 See :hg:`help urls` for more information.
5657
5649
5658 Returns 0 on success.
5650 Returns 0 on success.
5659 """
5651 """
5660 if search:
5652 if search:
5661 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5653 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5662 if name == search]
5654 if name == search]
5663 else:
5655 else:
5664 pathitems = sorted(ui.paths.iteritems())
5656 pathitems = sorted(ui.paths.iteritems())
5665
5657
5666 fm = ui.formatter('paths', opts)
5658 fm = ui.formatter('paths', opts)
5667 if fm.isplain():
5659 if fm.isplain():
5668 hidepassword = util.hidepassword
5660 hidepassword = util.hidepassword
5669 else:
5661 else:
5670 hidepassword = str
5662 hidepassword = str
5671 if ui.quiet:
5663 if ui.quiet:
5672 namefmt = '%s\n'
5664 namefmt = '%s\n'
5673 else:
5665 else:
5674 namefmt = '%s = '
5666 namefmt = '%s = '
5675 showsubopts = not search and not ui.quiet
5667 showsubopts = not search and not ui.quiet
5676
5668
5677 for name, path in pathitems:
5669 for name, path in pathitems:
5678 fm.startitem()
5670 fm.startitem()
5679 fm.condwrite(not search, 'name', namefmt, name)
5671 fm.condwrite(not search, 'name', namefmt, name)
5680 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5672 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5681 for subopt, value in sorted(path.suboptions.items()):
5673 for subopt, value in sorted(path.suboptions.items()):
5682 assert subopt not in ('name', 'url')
5674 assert subopt not in ('name', 'url')
5683 if showsubopts:
5675 if showsubopts:
5684 fm.plain('%s:%s = ' % (name, subopt))
5676 fm.plain('%s:%s = ' % (name, subopt))
5685 fm.condwrite(showsubopts, subopt, '%s\n', value)
5677 fm.condwrite(showsubopts, subopt, '%s\n', value)
5686
5678
5687 fm.end()
5679 fm.end()
5688
5680
5689 if search and not pathitems:
5681 if search and not pathitems:
5690 if not ui.quiet:
5682 if not ui.quiet:
5691 ui.warn(_("not found!\n"))
5683 ui.warn(_("not found!\n"))
5692 return 1
5684 return 1
5693 else:
5685 else:
5694 return 0
5686 return 0
5695
5687
5696 @command('phase',
5688 @command('phase',
5697 [('p', 'public', False, _('set changeset phase to public')),
5689 [('p', 'public', False, _('set changeset phase to public')),
5698 ('d', 'draft', False, _('set changeset phase to draft')),
5690 ('d', 'draft', False, _('set changeset phase to draft')),
5699 ('s', 'secret', False, _('set changeset phase to secret')),
5691 ('s', 'secret', False, _('set changeset phase to secret')),
5700 ('f', 'force', False, _('allow to move boundary backward')),
5692 ('f', 'force', False, _('allow to move boundary backward')),
5701 ('r', 'rev', [], _('target revision'), _('REV')),
5693 ('r', 'rev', [], _('target revision'), _('REV')),
5702 ],
5694 ],
5703 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5695 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5704 def phase(ui, repo, *revs, **opts):
5696 def phase(ui, repo, *revs, **opts):
5705 """set or show the current phase name
5697 """set or show the current phase name
5706
5698
5707 With no argument, show the phase name of the current revision(s).
5699 With no argument, show the phase name of the current revision(s).
5708
5700
5709 With one of -p/--public, -d/--draft or -s/--secret, change the
5701 With one of -p/--public, -d/--draft or -s/--secret, change the
5710 phase value of the specified revisions.
5702 phase value of the specified revisions.
5711
5703
5712 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5704 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::
5705 lower phase to an higher phase. Phases are ordered as follows::
5714
5706
5715 public < draft < secret
5707 public < draft < secret
5716
5708
5717 Returns 0 on success, 1 if some phases could not be changed.
5709 Returns 0 on success, 1 if some phases could not be changed.
5718
5710
5719 (For more information about the phases concept, see :hg:`help phases`.)
5711 (For more information about the phases concept, see :hg:`help phases`.)
5720 """
5712 """
5721 # search for a unique phase argument
5713 # search for a unique phase argument
5722 targetphase = None
5714 targetphase = None
5723 for idx, name in enumerate(phases.phasenames):
5715 for idx, name in enumerate(phases.phasenames):
5724 if opts[name]:
5716 if opts[name]:
5725 if targetphase is not None:
5717 if targetphase is not None:
5726 raise error.Abort(_('only one phase can be specified'))
5718 raise error.Abort(_('only one phase can be specified'))
5727 targetphase = idx
5719 targetphase = idx
5728
5720
5729 # look for specified revision
5721 # look for specified revision
5730 revs = list(revs)
5722 revs = list(revs)
5731 revs.extend(opts['rev'])
5723 revs.extend(opts['rev'])
5732 if not revs:
5724 if not revs:
5733 # display both parents as the second parent phase can influence
5725 # display both parents as the second parent phase can influence
5734 # the phase of a merge commit
5726 # the phase of a merge commit
5735 revs = [c.rev() for c in repo[None].parents()]
5727 revs = [c.rev() for c in repo[None].parents()]
5736
5728
5737 revs = scmutil.revrange(repo, revs)
5729 revs = scmutil.revrange(repo, revs)
5738
5730
5739 lock = None
5731 lock = None
5740 ret = 0
5732 ret = 0
5741 if targetphase is None:
5733 if targetphase is None:
5742 # display
5734 # display
5743 for r in revs:
5735 for r in revs:
5744 ctx = repo[r]
5736 ctx = repo[r]
5745 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5737 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5746 else:
5738 else:
5747 tr = None
5739 tr = None
5748 lock = repo.lock()
5740 lock = repo.lock()
5749 try:
5741 try:
5750 tr = repo.transaction("phase")
5742 tr = repo.transaction("phase")
5751 # set phase
5743 # set phase
5752 if not revs:
5744 if not revs:
5753 raise error.Abort(_('empty revision set'))
5745 raise error.Abort(_('empty revision set'))
5754 nodes = [repo[r].node() for r in revs]
5746 nodes = [repo[r].node() for r in revs]
5755 # moving revision from public to draft may hide them
5747 # moving revision from public to draft may hide them
5756 # We have to check result on an unfiltered repository
5748 # We have to check result on an unfiltered repository
5757 unfi = repo.unfiltered()
5749 unfi = repo.unfiltered()
5758 getphase = unfi._phasecache.phase
5750 getphase = unfi._phasecache.phase
5759 olddata = [getphase(unfi, r) for r in unfi]
5751 olddata = [getphase(unfi, r) for r in unfi]
5760 phases.advanceboundary(repo, tr, targetphase, nodes)
5752 phases.advanceboundary(repo, tr, targetphase, nodes)
5761 if opts['force']:
5753 if opts['force']:
5762 phases.retractboundary(repo, tr, targetphase, nodes)
5754 phases.retractboundary(repo, tr, targetphase, nodes)
5763 tr.close()
5755 tr.close()
5764 finally:
5756 finally:
5765 if tr is not None:
5757 if tr is not None:
5766 tr.release()
5758 tr.release()
5767 lock.release()
5759 lock.release()
5768 getphase = unfi._phasecache.phase
5760 getphase = unfi._phasecache.phase
5769 newdata = [getphase(unfi, r) for r in unfi]
5761 newdata = [getphase(unfi, r) for r in unfi]
5770 changes = sum(newdata[r] != olddata[r] for r in unfi)
5762 changes = sum(newdata[r] != olddata[r] for r in unfi)
5771 cl = unfi.changelog
5763 cl = unfi.changelog
5772 rejected = [n for n in nodes
5764 rejected = [n for n in nodes
5773 if newdata[cl.rev(n)] < targetphase]
5765 if newdata[cl.rev(n)] < targetphase]
5774 if rejected:
5766 if rejected:
5775 ui.warn(_('cannot move %i changesets to a higher '
5767 ui.warn(_('cannot move %i changesets to a higher '
5776 'phase, use --force\n') % len(rejected))
5768 'phase, use --force\n') % len(rejected))
5777 ret = 1
5769 ret = 1
5778 if changes:
5770 if changes:
5779 msg = _('phase changed for %i changesets\n') % changes
5771 msg = _('phase changed for %i changesets\n') % changes
5780 if ret:
5772 if ret:
5781 ui.status(msg)
5773 ui.status(msg)
5782 else:
5774 else:
5783 ui.note(msg)
5775 ui.note(msg)
5784 else:
5776 else:
5785 ui.warn(_('no phases changed\n'))
5777 ui.warn(_('no phases changed\n'))
5786 return ret
5778 return ret
5787
5779
5788 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5780 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5789 """Run after a changegroup has been added via pull/unbundle
5781 """Run after a changegroup has been added via pull/unbundle
5790
5782
5791 This takes arguments below:
5783 This takes arguments below:
5792
5784
5793 :modheads: change of heads by pull/unbundle
5785 :modheads: change of heads by pull/unbundle
5794 :optupdate: updating working directory is needed or not
5786 :optupdate: updating working directory is needed or not
5795 :checkout: update destination revision (or None to default destination)
5787 :checkout: update destination revision (or None to default destination)
5796 :brev: a name, which might be a bookmark to be activated after updating
5788 :brev: a name, which might be a bookmark to be activated after updating
5797 """
5789 """
5798 if modheads == 0:
5790 if modheads == 0:
5799 return
5791 return
5800 if optupdate:
5792 if optupdate:
5801 try:
5793 try:
5802 return hg.updatetotally(ui, repo, checkout, brev)
5794 return hg.updatetotally(ui, repo, checkout, brev)
5803 except error.UpdateAbort as inst:
5795 except error.UpdateAbort as inst:
5804 msg = _("not updating: %s") % str(inst)
5796 msg = _("not updating: %s") % str(inst)
5805 hint = inst.hint
5797 hint = inst.hint
5806 raise error.UpdateAbort(msg, hint=hint)
5798 raise error.UpdateAbort(msg, hint=hint)
5807 if modheads > 1:
5799 if modheads > 1:
5808 currentbranchheads = len(repo.branchheads())
5800 currentbranchheads = len(repo.branchheads())
5809 if currentbranchheads == modheads:
5801 if currentbranchheads == modheads:
5810 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5802 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5811 elif currentbranchheads > 1:
5803 elif currentbranchheads > 1:
5812 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5804 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5813 "merge)\n"))
5805 "merge)\n"))
5814 else:
5806 else:
5815 ui.status(_("(run 'hg heads' to see heads)\n"))
5807 ui.status(_("(run 'hg heads' to see heads)\n"))
5816 else:
5808 else:
5817 ui.status(_("(run 'hg update' to get a working copy)\n"))
5809 ui.status(_("(run 'hg update' to get a working copy)\n"))
5818
5810
5819 @command('^pull',
5811 @command('^pull',
5820 [('u', 'update', None,
5812 [('u', 'update', None,
5821 _('update to new branch head if changesets were pulled')),
5813 _('update to new branch head if changesets were pulled')),
5822 ('f', 'force', None, _('run even when remote repository is unrelated')),
5814 ('f', 'force', None, _('run even when remote repository is unrelated')),
5823 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5815 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5824 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5816 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5825 ('b', 'branch', [], _('a specific branch you would like to pull'),
5817 ('b', 'branch', [], _('a specific branch you would like to pull'),
5826 _('BRANCH')),
5818 _('BRANCH')),
5827 ] + remoteopts,
5819 ] + remoteopts,
5828 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5820 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5829 def pull(ui, repo, source="default", **opts):
5821 def pull(ui, repo, source="default", **opts):
5830 """pull changes from the specified source
5822 """pull changes from the specified source
5831
5823
5832 Pull changes from a remote repository to a local one.
5824 Pull changes from a remote repository to a local one.
5833
5825
5834 This finds all changes from the repository at the specified path
5826 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
5827 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
5828 -R is specified). By default, this does not update the copy of the
5837 project in the working directory.
5829 project in the working directory.
5838
5830
5839 Use :hg:`incoming` if you want to see what would have been added
5831 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
5832 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
5833 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`.
5834 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5843
5835
5844 If SOURCE is omitted, the 'default' path will be used.
5836 If SOURCE is omitted, the 'default' path will be used.
5845 See :hg:`help urls` for more information.
5837 See :hg:`help urls` for more information.
5846
5838
5847 Specifying bookmark as ``.`` is equivalent to specifying the active
5839 Specifying bookmark as ``.`` is equivalent to specifying the active
5848 bookmark's name.
5840 bookmark's name.
5849
5841
5850 Returns 0 on success, 1 if an update had unresolved files.
5842 Returns 0 on success, 1 if an update had unresolved files.
5851 """
5843 """
5852 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5844 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5853 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5845 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5854 other = hg.peer(repo, opts, source)
5846 other = hg.peer(repo, opts, source)
5855 try:
5847 try:
5856 revs, checkout = hg.addbranchrevs(repo, other, branches,
5848 revs, checkout = hg.addbranchrevs(repo, other, branches,
5857 opts.get('rev'))
5849 opts.get('rev'))
5858
5850
5859
5851
5860 pullopargs = {}
5852 pullopargs = {}
5861 if opts.get('bookmark'):
5853 if opts.get('bookmark'):
5862 if not revs:
5854 if not revs:
5863 revs = []
5855 revs = []
5864 # The list of bookmark used here is not the one used to actually
5856 # 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
5857 # 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
5858 # not ending up with the name of the bookmark because of a race
5867 # condition on the server. (See issue 4689 for details)
5859 # condition on the server. (See issue 4689 for details)
5868 remotebookmarks = other.listkeys('bookmarks')
5860 remotebookmarks = other.listkeys('bookmarks')
5869 pullopargs['remotebookmarks'] = remotebookmarks
5861 pullopargs['remotebookmarks'] = remotebookmarks
5870 for b in opts['bookmark']:
5862 for b in opts['bookmark']:
5871 b = repo._bookmarks.expandname(b)
5863 b = repo._bookmarks.expandname(b)
5872 if b not in remotebookmarks:
5864 if b not in remotebookmarks:
5873 raise error.Abort(_('remote bookmark %s not found!') % b)
5865 raise error.Abort(_('remote bookmark %s not found!') % b)
5874 revs.append(remotebookmarks[b])
5866 revs.append(remotebookmarks[b])
5875
5867
5876 if revs:
5868 if revs:
5877 try:
5869 try:
5878 # When 'rev' is a bookmark name, we cannot guarantee that it
5870 # When 'rev' is a bookmark name, we cannot guarantee that it
5879 # will be updated with that name because of a race condition
5871 # will be updated with that name because of a race condition
5880 # server side. (See issue 4689 for details)
5872 # server side. (See issue 4689 for details)
5881 oldrevs = revs
5873 oldrevs = revs
5882 revs = [] # actually, nodes
5874 revs = [] # actually, nodes
5883 for r in oldrevs:
5875 for r in oldrevs:
5884 node = other.lookup(r)
5876 node = other.lookup(r)
5885 revs.append(node)
5877 revs.append(node)
5886 if r == checkout:
5878 if r == checkout:
5887 checkout = node
5879 checkout = node
5888 except error.CapabilityError:
5880 except error.CapabilityError:
5889 err = _("other repository doesn't support revision lookup, "
5881 err = _("other repository doesn't support revision lookup, "
5890 "so a rev cannot be specified.")
5882 "so a rev cannot be specified.")
5891 raise error.Abort(err)
5883 raise error.Abort(err)
5892
5884
5893 pullopargs.update(opts.get('opargs', {}))
5885 pullopargs.update(opts.get('opargs', {}))
5894 modheads = exchange.pull(repo, other, heads=revs,
5886 modheads = exchange.pull(repo, other, heads=revs,
5895 force=opts.get('force'),
5887 force=opts.get('force'),
5896 bookmarks=opts.get('bookmark', ()),
5888 bookmarks=opts.get('bookmark', ()),
5897 opargs=pullopargs).cgresult
5889 opargs=pullopargs).cgresult
5898
5890
5899 # brev is a name, which might be a bookmark to be activated at
5891 # 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
5892 # the end of the update. In other words, it is an explicit
5901 # destination of the update
5893 # destination of the update
5902 brev = None
5894 brev = None
5903
5895
5904 if checkout:
5896 if checkout:
5905 checkout = str(repo.changelog.rev(checkout))
5897 checkout = str(repo.changelog.rev(checkout))
5906
5898
5907 # order below depends on implementation of
5899 # order below depends on implementation of
5908 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5900 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5909 # because 'checkout' is determined without it.
5901 # because 'checkout' is determined without it.
5910 if opts.get('rev'):
5902 if opts.get('rev'):
5911 brev = opts['rev'][0]
5903 brev = opts['rev'][0]
5912 elif opts.get('branch'):
5904 elif opts.get('branch'):
5913 brev = opts['branch'][0]
5905 brev = opts['branch'][0]
5914 else:
5906 else:
5915 brev = branches[0]
5907 brev = branches[0]
5916 repo._subtoppath = source
5908 repo._subtoppath = source
5917 try:
5909 try:
5918 ret = postincoming(ui, repo, modheads, opts.get('update'),
5910 ret = postincoming(ui, repo, modheads, opts.get('update'),
5919 checkout, brev)
5911 checkout, brev)
5920
5912
5921 finally:
5913 finally:
5922 del repo._subtoppath
5914 del repo._subtoppath
5923
5915
5924 finally:
5916 finally:
5925 other.close()
5917 other.close()
5926 return ret
5918 return ret
5927
5919
5928 @command('^push',
5920 @command('^push',
5929 [('f', 'force', None, _('force push')),
5921 [('f', 'force', None, _('force push')),
5930 ('r', 'rev', [],
5922 ('r', 'rev', [],
5931 _('a changeset intended to be included in the destination'),
5923 _('a changeset intended to be included in the destination'),
5932 _('REV')),
5924 _('REV')),
5933 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5925 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5934 ('b', 'branch', [],
5926 ('b', 'branch', [],
5935 _('a specific branch you would like to push'), _('BRANCH')),
5927 _('a specific branch you would like to push'), _('BRANCH')),
5936 ('', 'new-branch', False, _('allow pushing a new branch')),
5928 ('', 'new-branch', False, _('allow pushing a new branch')),
5937 ] + remoteopts,
5929 ] + remoteopts,
5938 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5930 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5939 def push(ui, repo, dest=None, **opts):
5931 def push(ui, repo, dest=None, **opts):
5940 """push changes to the specified destination
5932 """push changes to the specified destination
5941
5933
5942 Push changesets from the local repository to the specified
5934 Push changesets from the local repository to the specified
5943 destination.
5935 destination.
5944
5936
5945 This operation is symmetrical to pull: it is identical to a pull
5937 This operation is symmetrical to pull: it is identical to a pull
5946 in the destination repository from the current one.
5938 in the destination repository from the current one.
5947
5939
5948 By default, push will not allow creation of new heads at the
5940 By default, push will not allow creation of new heads at the
5949 destination, since multiple heads would make it unclear which head
5941 destination, since multiple heads would make it unclear which head
5950 to use. In this situation, it is recommended to pull and merge
5942 to use. In this situation, it is recommended to pull and merge
5951 before pushing.
5943 before pushing.
5952
5944
5953 Use --new-branch if you want to allow push to create a new named
5945 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
5946 branch that is not present at the destination. This allows you to
5955 only create a new branch without forcing other changes.
5947 only create a new branch without forcing other changes.
5956
5948
5957 .. note::
5949 .. note::
5958
5950
5959 Extra care should be taken with the -f/--force option,
5951 Extra care should be taken with the -f/--force option,
5960 which will push all new heads on all branches, an action which will
5952 which will push all new heads on all branches, an action which will
5961 almost always cause confusion for collaborators.
5953 almost always cause confusion for collaborators.
5962
5954
5963 If -r/--rev is used, the specified revision and all its ancestors
5955 If -r/--rev is used, the specified revision and all its ancestors
5964 will be pushed to the remote repository.
5956 will be pushed to the remote repository.
5965
5957
5966 If -B/--bookmark is used, the specified bookmarked revision, its
5958 If -B/--bookmark is used, the specified bookmarked revision, its
5967 ancestors, and the bookmark will be pushed to the remote
5959 ancestors, and the bookmark will be pushed to the remote
5968 repository. Specifying ``.`` is equivalent to specifying the active
5960 repository. Specifying ``.`` is equivalent to specifying the active
5969 bookmark's name.
5961 bookmark's name.
5970
5962
5971 Please see :hg:`help urls` for important details about ``ssh://``
5963 Please see :hg:`help urls` for important details about ``ssh://``
5972 URLs. If DESTINATION is omitted, a default path will be used.
5964 URLs. If DESTINATION is omitted, a default path will be used.
5973
5965
5974 Returns 0 if push was successful, 1 if nothing to push.
5966 Returns 0 if push was successful, 1 if nothing to push.
5975 """
5967 """
5976
5968
5977 if opts.get('bookmark'):
5969 if opts.get('bookmark'):
5978 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5970 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5979 for b in opts['bookmark']:
5971 for b in opts['bookmark']:
5980 # translate -B options to -r so changesets get pushed
5972 # translate -B options to -r so changesets get pushed
5981 b = repo._bookmarks.expandname(b)
5973 b = repo._bookmarks.expandname(b)
5982 if b in repo._bookmarks:
5974 if b in repo._bookmarks:
5983 opts.setdefault('rev', []).append(b)
5975 opts.setdefault('rev', []).append(b)
5984 else:
5976 else:
5985 # if we try to push a deleted bookmark, translate it to null
5977 # if we try to push a deleted bookmark, translate it to null
5986 # this lets simultaneous -r, -b options continue working
5978 # this lets simultaneous -r, -b options continue working
5987 opts.setdefault('rev', []).append("null")
5979 opts.setdefault('rev', []).append("null")
5988
5980
5989 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5981 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5990 if not path:
5982 if not path:
5991 raise error.Abort(_('default repository not configured!'),
5983 raise error.Abort(_('default repository not configured!'),
5992 hint=_("see 'hg help config.paths'"))
5984 hint=_("see 'hg help config.paths'"))
5993 dest = path.pushloc or path.loc
5985 dest = path.pushloc or path.loc
5994 branches = (path.branch, opts.get('branch') or [])
5986 branches = (path.branch, opts.get('branch') or [])
5995 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5987 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5996 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5988 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5997 other = hg.peer(repo, opts, dest)
5989 other = hg.peer(repo, opts, dest)
5998
5990
5999 if revs:
5991 if revs:
6000 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5992 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
6001 if not revs:
5993 if not revs:
6002 raise error.Abort(_("specified revisions evaluate to an empty set"),
5994 raise error.Abort(_("specified revisions evaluate to an empty set"),
6003 hint=_("use different revision arguments"))
5995 hint=_("use different revision arguments"))
6004 elif path.pushrev:
5996 elif path.pushrev:
6005 # It doesn't make any sense to specify ancestor revisions. So limit
5997 # It doesn't make any sense to specify ancestor revisions. So limit
6006 # to DAG heads to make discovery simpler.
5998 # to DAG heads to make discovery simpler.
6007 expr = revset.formatspec('heads(%r)', path.pushrev)
5999 expr = revset.formatspec('heads(%r)', path.pushrev)
6008 revs = scmutil.revrange(repo, [expr])
6000 revs = scmutil.revrange(repo, [expr])
6009 revs = [repo[rev].node() for rev in revs]
6001 revs = [repo[rev].node() for rev in revs]
6010 if not revs:
6002 if not revs:
6011 raise error.Abort(_('default push revset for path evaluates to an '
6003 raise error.Abort(_('default push revset for path evaluates to an '
6012 'empty set'))
6004 'empty set'))
6013
6005
6014 repo._subtoppath = dest
6006 repo._subtoppath = dest
6015 try:
6007 try:
6016 # push subrepos depth-first for coherent ordering
6008 # push subrepos depth-first for coherent ordering
6017 c = repo['']
6009 c = repo['']
6018 subs = c.substate # only repos that are committed
6010 subs = c.substate # only repos that are committed
6019 for s in sorted(subs):
6011 for s in sorted(subs):
6020 result = c.sub(s).push(opts)
6012 result = c.sub(s).push(opts)
6021 if result == 0:
6013 if result == 0:
6022 return not result
6014 return not result
6023 finally:
6015 finally:
6024 del repo._subtoppath
6016 del repo._subtoppath
6025 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6017 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6026 newbranch=opts.get('new_branch'),
6018 newbranch=opts.get('new_branch'),
6027 bookmarks=opts.get('bookmark', ()),
6019 bookmarks=opts.get('bookmark', ()),
6028 opargs=opts.get('opargs'))
6020 opargs=opts.get('opargs'))
6029
6021
6030 result = not pushop.cgresult
6022 result = not pushop.cgresult
6031
6023
6032 if pushop.bkresult is not None:
6024 if pushop.bkresult is not None:
6033 if pushop.bkresult == 2:
6025 if pushop.bkresult == 2:
6034 result = 2
6026 result = 2
6035 elif not result and pushop.bkresult:
6027 elif not result and pushop.bkresult:
6036 result = 2
6028 result = 2
6037
6029
6038 return result
6030 return result
6039
6031
6040 @command('recover', [])
6032 @command('recover', [])
6041 def recover(ui, repo):
6033 def recover(ui, repo):
6042 """roll back an interrupted transaction
6034 """roll back an interrupted transaction
6043
6035
6044 Recover from an interrupted commit or pull.
6036 Recover from an interrupted commit or pull.
6045
6037
6046 This command tries to fix the repository status after an
6038 This command tries to fix the repository status after an
6047 interrupted operation. It should only be necessary when Mercurial
6039 interrupted operation. It should only be necessary when Mercurial
6048 suggests it.
6040 suggests it.
6049
6041
6050 Returns 0 if successful, 1 if nothing to recover or verify fails.
6042 Returns 0 if successful, 1 if nothing to recover or verify fails.
6051 """
6043 """
6052 if repo.recover():
6044 if repo.recover():
6053 return hg.verify(repo)
6045 return hg.verify(repo)
6054 return 1
6046 return 1
6055
6047
6056 @command('^remove|rm',
6048 @command('^remove|rm',
6057 [('A', 'after', None, _('record delete for missing files')),
6049 [('A', 'after', None, _('record delete for missing files')),
6058 ('f', 'force', None,
6050 ('f', 'force', None,
6059 _('forget added files, delete modified files')),
6051 _('forget added files, delete modified files')),
6060 ] + subrepoopts + walkopts,
6052 ] + subrepoopts + walkopts,
6061 _('[OPTION]... FILE...'),
6053 _('[OPTION]... FILE...'),
6062 inferrepo=True)
6054 inferrepo=True)
6063 def remove(ui, repo, *pats, **opts):
6055 def remove(ui, repo, *pats, **opts):
6064 """remove the specified files on the next commit
6056 """remove the specified files on the next commit
6065
6057
6066 Schedule the indicated files for removal from the current branch.
6058 Schedule the indicated files for removal from the current branch.
6067
6059
6068 This command schedules the files to be removed at the next commit.
6060 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
6061 To undo a remove before that, see :hg:`revert`. To undo added
6070 files, see :hg:`forget`.
6062 files, see :hg:`forget`.
6071
6063
6072 .. container:: verbose
6064 .. container:: verbose
6073
6065
6074 -A/--after can be used to remove only files that have already
6066 -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
6067 been deleted, -f/--force can be used to force deletion, and -Af
6076 can be used to remove files from the next revision without
6068 can be used to remove files from the next revision without
6077 deleting them from the working directory.
6069 deleting them from the working directory.
6078
6070
6079 The following table details the behavior of remove for different
6071 The following table details the behavior of remove for different
6080 file states (columns) and option combinations (rows). The file
6072 file states (columns) and option combinations (rows). The file
6081 states are Added [A], Clean [C], Modified [M] and Missing [!]
6073 states are Added [A], Clean [C], Modified [M] and Missing [!]
6082 (as reported by :hg:`status`). The actions are Warn, Remove
6074 (as reported by :hg:`status`). The actions are Warn, Remove
6083 (from branch) and Delete (from disk):
6075 (from branch) and Delete (from disk):
6084
6076
6085 ========= == == == ==
6077 ========= == == == ==
6086 opt/state A C M !
6078 opt/state A C M !
6087 ========= == == == ==
6079 ========= == == == ==
6088 none W RD W R
6080 none W RD W R
6089 -f R RD RD R
6081 -f R RD RD R
6090 -A W W W R
6082 -A W W W R
6091 -Af R R R R
6083 -Af R R R R
6092 ========= == == == ==
6084 ========= == == == ==
6093
6085
6094 .. note::
6086 .. note::
6095
6087
6096 :hg:`remove` never deletes files in Added [A] state from the
6088 :hg:`remove` never deletes files in Added [A] state from the
6097 working directory, not even if ``--force`` is specified.
6089 working directory, not even if ``--force`` is specified.
6098
6090
6099 Returns 0 on success, 1 if any warnings encountered.
6091 Returns 0 on success, 1 if any warnings encountered.
6100 """
6092 """
6101
6093
6102 after, force = opts.get('after'), opts.get('force')
6094 after, force = opts.get('after'), opts.get('force')
6103 if not pats and not after:
6095 if not pats and not after:
6104 raise error.Abort(_('no files specified'))
6096 raise error.Abort(_('no files specified'))
6105
6097
6106 m = scmutil.match(repo[None], pats, opts)
6098 m = scmutil.match(repo[None], pats, opts)
6107 subrepos = opts.get('subrepos')
6099 subrepos = opts.get('subrepos')
6108 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6100 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6109
6101
6110 @command('rename|move|mv',
6102 @command('rename|move|mv',
6111 [('A', 'after', None, _('record a rename that has already occurred')),
6103 [('A', 'after', None, _('record a rename that has already occurred')),
6112 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6104 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6113 ] + walkopts + dryrunopts,
6105 ] + walkopts + dryrunopts,
6114 _('[OPTION]... SOURCE... DEST'))
6106 _('[OPTION]... SOURCE... DEST'))
6115 def rename(ui, repo, *pats, **opts):
6107 def rename(ui, repo, *pats, **opts):
6116 """rename files; equivalent of copy + remove
6108 """rename files; equivalent of copy + remove
6117
6109
6118 Mark dest as copies of sources; mark sources for deletion. If dest
6110 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
6111 is a directory, copies are put in that directory. If dest is a
6120 file, there can only be one source.
6112 file, there can only be one source.
6121
6113
6122 By default, this command copies the contents of files as they
6114 By default, this command copies the contents of files as they
6123 exist in the working directory. If invoked with -A/--after, the
6115 exist in the working directory. If invoked with -A/--after, the
6124 operation is recorded, but no copying is performed.
6116 operation is recorded, but no copying is performed.
6125
6117
6126 This command takes effect at the next commit. To undo a rename
6118 This command takes effect at the next commit. To undo a rename
6127 before that, see :hg:`revert`.
6119 before that, see :hg:`revert`.
6128
6120
6129 Returns 0 on success, 1 if errors are encountered.
6121 Returns 0 on success, 1 if errors are encountered.
6130 """
6122 """
6131 with repo.wlock(False):
6123 with repo.wlock(False):
6132 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6124 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6133
6125
6134 @command('resolve',
6126 @command('resolve',
6135 [('a', 'all', None, _('select all unresolved files')),
6127 [('a', 'all', None, _('select all unresolved files')),
6136 ('l', 'list', None, _('list state of files needing merge')),
6128 ('l', 'list', None, _('list state of files needing merge')),
6137 ('m', 'mark', None, _('mark files as resolved')),
6129 ('m', 'mark', None, _('mark files as resolved')),
6138 ('u', 'unmark', None, _('mark files as unresolved')),
6130 ('u', 'unmark', None, _('mark files as unresolved')),
6139 ('n', 'no-status', None, _('hide status prefix'))]
6131 ('n', 'no-status', None, _('hide status prefix'))]
6140 + mergetoolopts + walkopts + formatteropts,
6132 + mergetoolopts + walkopts + formatteropts,
6141 _('[OPTION]... [FILE]...'),
6133 _('[OPTION]... [FILE]...'),
6142 inferrepo=True)
6134 inferrepo=True)
6143 def resolve(ui, repo, *pats, **opts):
6135 def resolve(ui, repo, *pats, **opts):
6144 """redo merges or set/view the merge status of files
6136 """redo merges or set/view the merge status of files
6145
6137
6146 Merges with unresolved conflicts are often the result of
6138 Merges with unresolved conflicts are often the result of
6147 non-interactive merging using the ``internal:merge`` configuration
6139 non-interactive merging using the ``internal:merge`` configuration
6148 setting, or a command-line merge tool like ``diff3``. The resolve
6140 setting, or a command-line merge tool like ``diff3``. The resolve
6149 command is used to manage the files involved in a merge, after
6141 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
6142 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6151 working directory must have two parents). See :hg:`help
6143 working directory must have two parents). See :hg:`help
6152 merge-tools` for information on configuring merge tools.
6144 merge-tools` for information on configuring merge tools.
6153
6145
6154 The resolve command can be used in the following ways:
6146 The resolve command can be used in the following ways:
6155
6147
6156 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6148 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6157 files, discarding any previous merge attempts. Re-merging is not
6149 files, discarding any previous merge attempts. Re-merging is not
6158 performed for files already marked as resolved. Use ``--all/-a``
6150 performed for files already marked as resolved. Use ``--all/-a``
6159 to select all unresolved files. ``--tool`` can be used to specify
6151 to select all unresolved files. ``--tool`` can be used to specify
6160 the merge tool used for the given files. It overrides the HGMERGE
6152 the merge tool used for the given files. It overrides the HGMERGE
6161 environment variable and your configuration files. Previous file
6153 environment variable and your configuration files. Previous file
6162 contents are saved with a ``.orig`` suffix.
6154 contents are saved with a ``.orig`` suffix.
6163
6155
6164 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6156 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6165 (e.g. after having manually fixed-up the files). The default is
6157 (e.g. after having manually fixed-up the files). The default is
6166 to mark all unresolved files.
6158 to mark all unresolved files.
6167
6159
6168 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6160 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6169 default is to mark all resolved files.
6161 default is to mark all resolved files.
6170
6162
6171 - :hg:`resolve -l`: list files which had or still have conflicts.
6163 - :hg:`resolve -l`: list files which had or still have conflicts.
6172 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6164 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6173
6165
6174 .. note::
6166 .. note::
6175
6167
6176 Mercurial will not let you commit files with unresolved merge
6168 Mercurial will not let you commit files with unresolved merge
6177 conflicts. You must use :hg:`resolve -m ...` before you can
6169 conflicts. You must use :hg:`resolve -m ...` before you can
6178 commit after a conflicting merge.
6170 commit after a conflicting merge.
6179
6171
6180 Returns 0 on success, 1 if any files fail a resolve attempt.
6172 Returns 0 on success, 1 if any files fail a resolve attempt.
6181 """
6173 """
6182
6174
6183 flaglist = 'all mark unmark list no_status'.split()
6175 flaglist = 'all mark unmark list no_status'.split()
6184 all, mark, unmark, show, nostatus = \
6176 all, mark, unmark, show, nostatus = \
6185 [opts.get(o) for o in flaglist]
6177 [opts.get(o) for o in flaglist]
6186
6178
6187 if (show and (mark or unmark)) or (mark and unmark):
6179 if (show and (mark or unmark)) or (mark and unmark):
6188 raise error.Abort(_("too many options specified"))
6180 raise error.Abort(_("too many options specified"))
6189 if pats and all:
6181 if pats and all:
6190 raise error.Abort(_("can't specify --all and patterns"))
6182 raise error.Abort(_("can't specify --all and patterns"))
6191 if not (all or pats or show or mark or unmark):
6183 if not (all or pats or show or mark or unmark):
6192 raise error.Abort(_('no files or directories specified'),
6184 raise error.Abort(_('no files or directories specified'),
6193 hint=('use --all to re-merge all unresolved files'))
6185 hint=('use --all to re-merge all unresolved files'))
6194
6186
6195 if show:
6187 if show:
6196 fm = ui.formatter('resolve', opts)
6188 fm = ui.formatter('resolve', opts)
6197 ms = mergemod.mergestate.read(repo)
6189 ms = mergemod.mergestate.read(repo)
6198 m = scmutil.match(repo[None], pats, opts)
6190 m = scmutil.match(repo[None], pats, opts)
6199 for f in ms:
6191 for f in ms:
6200 if not m(f):
6192 if not m(f):
6201 continue
6193 continue
6202 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6194 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6203 'd': 'driverresolved'}[ms[f]]
6195 'd': 'driverresolved'}[ms[f]]
6204 fm.startitem()
6196 fm.startitem()
6205 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6197 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6206 fm.write('path', '%s\n', f, label=l)
6198 fm.write('path', '%s\n', f, label=l)
6207 fm.end()
6199 fm.end()
6208 return 0
6200 return 0
6209
6201
6210 with repo.wlock():
6202 with repo.wlock():
6211 ms = mergemod.mergestate.read(repo)
6203 ms = mergemod.mergestate.read(repo)
6212
6204
6213 if not (ms.active() or repo.dirstate.p2() != nullid):
6205 if not (ms.active() or repo.dirstate.p2() != nullid):
6214 raise error.Abort(
6206 raise error.Abort(
6215 _('resolve command not applicable when not merging'))
6207 _('resolve command not applicable when not merging'))
6216
6208
6217 wctx = repo[None]
6209 wctx = repo[None]
6218
6210
6219 if ms.mergedriver and ms.mdstate() == 'u':
6211 if ms.mergedriver and ms.mdstate() == 'u':
6220 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6212 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6221 ms.commit()
6213 ms.commit()
6222 # allow mark and unmark to go through
6214 # allow mark and unmark to go through
6223 if not mark and not unmark and not proceed:
6215 if not mark and not unmark and not proceed:
6224 return 1
6216 return 1
6225
6217
6226 m = scmutil.match(wctx, pats, opts)
6218 m = scmutil.match(wctx, pats, opts)
6227 ret = 0
6219 ret = 0
6228 didwork = False
6220 didwork = False
6229 runconclude = False
6221 runconclude = False
6230
6222
6231 tocomplete = []
6223 tocomplete = []
6232 for f in ms:
6224 for f in ms:
6233 if not m(f):
6225 if not m(f):
6234 continue
6226 continue
6235
6227
6236 didwork = True
6228 didwork = True
6237
6229
6238 # don't let driver-resolved files be marked, and run the conclude
6230 # don't let driver-resolved files be marked, and run the conclude
6239 # step if asked to resolve
6231 # step if asked to resolve
6240 if ms[f] == "d":
6232 if ms[f] == "d":
6241 exact = m.exact(f)
6233 exact = m.exact(f)
6242 if mark:
6234 if mark:
6243 if exact:
6235 if exact:
6244 ui.warn(_('not marking %s as it is driver-resolved\n')
6236 ui.warn(_('not marking %s as it is driver-resolved\n')
6245 % f)
6237 % f)
6246 elif unmark:
6238 elif unmark:
6247 if exact:
6239 if exact:
6248 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6240 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6249 % f)
6241 % f)
6250 else:
6242 else:
6251 runconclude = True
6243 runconclude = True
6252 continue
6244 continue
6253
6245
6254 if mark:
6246 if mark:
6255 ms.mark(f, "r")
6247 ms.mark(f, "r")
6256 elif unmark:
6248 elif unmark:
6257 ms.mark(f, "u")
6249 ms.mark(f, "u")
6258 else:
6250 else:
6259 # backup pre-resolve (merge uses .orig for its own purposes)
6251 # backup pre-resolve (merge uses .orig for its own purposes)
6260 a = repo.wjoin(f)
6252 a = repo.wjoin(f)
6261 try:
6253 try:
6262 util.copyfile(a, a + ".resolve")
6254 util.copyfile(a, a + ".resolve")
6263 except (IOError, OSError) as inst:
6255 except (IOError, OSError) as inst:
6264 if inst.errno != errno.ENOENT:
6256 if inst.errno != errno.ENOENT:
6265 raise
6257 raise
6266
6258
6267 try:
6259 try:
6268 # preresolve file
6260 # preresolve file
6269 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6261 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6270 'resolve')
6262 'resolve')
6271 complete, r = ms.preresolve(f, wctx)
6263 complete, r = ms.preresolve(f, wctx)
6272 if not complete:
6264 if not complete:
6273 tocomplete.append(f)
6265 tocomplete.append(f)
6274 elif r:
6266 elif r:
6275 ret = 1
6267 ret = 1
6276 finally:
6268 finally:
6277 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6269 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6278 ms.commit()
6270 ms.commit()
6279
6271
6280 # replace filemerge's .orig file with our resolve file, but only
6272 # replace filemerge's .orig file with our resolve file, but only
6281 # for merges that are complete
6273 # for merges that are complete
6282 if complete:
6274 if complete:
6283 try:
6275 try:
6284 util.rename(a + ".resolve",
6276 util.rename(a + ".resolve",
6285 scmutil.origpath(ui, repo, a))
6277 scmutil.origpath(ui, repo, a))
6286 except OSError as inst:
6278 except OSError as inst:
6287 if inst.errno != errno.ENOENT:
6279 if inst.errno != errno.ENOENT:
6288 raise
6280 raise
6289
6281
6290 for f in tocomplete:
6282 for f in tocomplete:
6291 try:
6283 try:
6292 # resolve file
6284 # resolve file
6293 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6285 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6294 'resolve')
6286 'resolve')
6295 r = ms.resolve(f, wctx)
6287 r = ms.resolve(f, wctx)
6296 if r:
6288 if r:
6297 ret = 1
6289 ret = 1
6298 finally:
6290 finally:
6299 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6291 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6300 ms.commit()
6292 ms.commit()
6301
6293
6302 # replace filemerge's .orig file with our resolve file
6294 # replace filemerge's .orig file with our resolve file
6303 a = repo.wjoin(f)
6295 a = repo.wjoin(f)
6304 try:
6296 try:
6305 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6297 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6306 except OSError as inst:
6298 except OSError as inst:
6307 if inst.errno != errno.ENOENT:
6299 if inst.errno != errno.ENOENT:
6308 raise
6300 raise
6309
6301
6310 ms.commit()
6302 ms.commit()
6311 ms.recordactions()
6303 ms.recordactions()
6312
6304
6313 if not didwork and pats:
6305 if not didwork and pats:
6314 hint = None
6306 hint = None
6315 if not any([p for p in pats if p.find(':') >= 0]):
6307 if not any([p for p in pats if p.find(':') >= 0]):
6316 pats = ['path:%s' % p for p in pats]
6308 pats = ['path:%s' % p for p in pats]
6317 m = scmutil.match(wctx, pats, opts)
6309 m = scmutil.match(wctx, pats, opts)
6318 for f in ms:
6310 for f in ms:
6319 if not m(f):
6311 if not m(f):
6320 continue
6312 continue
6321 flags = ''.join(['-%s ' % o[0] for o in flaglist
6313 flags = ''.join(['-%s ' % o[0] for o in flaglist
6322 if opts.get(o)])
6314 if opts.get(o)])
6323 hint = _("(try: hg resolve %s%s)\n") % (
6315 hint = _("(try: hg resolve %s%s)\n") % (
6324 flags,
6316 flags,
6325 ' '.join(pats))
6317 ' '.join(pats))
6326 break
6318 break
6327 ui.warn(_("arguments do not match paths that need resolving\n"))
6319 ui.warn(_("arguments do not match paths that need resolving\n"))
6328 if hint:
6320 if hint:
6329 ui.warn(hint)
6321 ui.warn(hint)
6330 elif ms.mergedriver and ms.mdstate() != 's':
6322 elif ms.mergedriver and ms.mdstate() != 's':
6331 # run conclude step when either a driver-resolved file is requested
6323 # run conclude step when either a driver-resolved file is requested
6332 # or there are no driver-resolved files
6324 # or there are no driver-resolved files
6333 # we can't use 'ret' to determine whether any files are unresolved
6325 # we can't use 'ret' to determine whether any files are unresolved
6334 # because we might not have tried to resolve some
6326 # because we might not have tried to resolve some
6335 if ((runconclude or not list(ms.driverresolved()))
6327 if ((runconclude or not list(ms.driverresolved()))
6336 and not list(ms.unresolved())):
6328 and not list(ms.unresolved())):
6337 proceed = mergemod.driverconclude(repo, ms, wctx)
6329 proceed = mergemod.driverconclude(repo, ms, wctx)
6338 ms.commit()
6330 ms.commit()
6339 if not proceed:
6331 if not proceed:
6340 return 1
6332 return 1
6341
6333
6342 # Nudge users into finishing an unfinished operation
6334 # Nudge users into finishing an unfinished operation
6343 unresolvedf = list(ms.unresolved())
6335 unresolvedf = list(ms.unresolved())
6344 driverresolvedf = list(ms.driverresolved())
6336 driverresolvedf = list(ms.driverresolved())
6345 if not unresolvedf and not driverresolvedf:
6337 if not unresolvedf and not driverresolvedf:
6346 ui.status(_('(no more unresolved files)\n'))
6338 ui.status(_('(no more unresolved files)\n'))
6347 cmdutil.checkafterresolved(repo)
6339 cmdutil.checkafterresolved(repo)
6348 elif not unresolvedf:
6340 elif not unresolvedf:
6349 ui.status(_('(no more unresolved files -- '
6341 ui.status(_('(no more unresolved files -- '
6350 'run "hg resolve --all" to conclude)\n'))
6342 'run "hg resolve --all" to conclude)\n'))
6351
6343
6352 return ret
6344 return ret
6353
6345
6354 @command('revert',
6346 @command('revert',
6355 [('a', 'all', None, _('revert all changes when no arguments given')),
6347 [('a', 'all', None, _('revert all changes when no arguments given')),
6356 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6348 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6357 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6349 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6358 ('C', 'no-backup', None, _('do not save backup copies of files')),
6350 ('C', 'no-backup', None, _('do not save backup copies of files')),
6359 ('i', 'interactive', None,
6351 ('i', 'interactive', None,
6360 _('interactively select the changes (EXPERIMENTAL)')),
6352 _('interactively select the changes (EXPERIMENTAL)')),
6361 ] + walkopts + dryrunopts,
6353 ] + walkopts + dryrunopts,
6362 _('[OPTION]... [-r REV] [NAME]...'))
6354 _('[OPTION]... [-r REV] [NAME]...'))
6363 def revert(ui, repo, *pats, **opts):
6355 def revert(ui, repo, *pats, **opts):
6364 """restore files to their checkout state
6356 """restore files to their checkout state
6365
6357
6366 .. note::
6358 .. note::
6367
6359
6368 To check out earlier revisions, you should use :hg:`update REV`.
6360 To check out earlier revisions, you should use :hg:`update REV`.
6369 To cancel an uncommitted merge (and lose your changes),
6361 To cancel an uncommitted merge (and lose your changes),
6370 use :hg:`update --clean .`.
6362 use :hg:`update --clean .`.
6371
6363
6372 With no revision specified, revert the specified files or directories
6364 With no revision specified, revert the specified files or directories
6373 to the contents they had in the parent of the working directory.
6365 to the contents they had in the parent of the working directory.
6374 This restores the contents of files to an unmodified
6366 This restores the contents of files to an unmodified
6375 state and unschedules adds, removes, copies, and renames. If the
6367 state and unschedules adds, removes, copies, and renames. If the
6376 working directory has two parents, you must explicitly specify a
6368 working directory has two parents, you must explicitly specify a
6377 revision.
6369 revision.
6378
6370
6379 Using the -r/--rev or -d/--date options, revert the given files or
6371 Using the -r/--rev or -d/--date options, revert the given files or
6380 directories to their states as of a specific revision. Because
6372 directories to their states as of a specific revision. Because
6381 revert does not change the working directory parents, this will
6373 revert does not change the working directory parents, this will
6382 cause these files to appear modified. This can be helpful to "back
6374 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
6375 out" some or all of an earlier change. See :hg:`backout` for a
6384 related method.
6376 related method.
6385
6377
6386 Modified files are saved with a .orig suffix before reverting.
6378 Modified files are saved with a .orig suffix before reverting.
6387 To disable these backups, use --no-backup. It is possible to store
6379 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
6380 the backup files in a custom directory relative to the root of the
6389 repository by setting the ``ui.origbackuppath`` configuration
6381 repository by setting the ``ui.origbackuppath`` configuration
6390 option.
6382 option.
6391
6383
6392 See :hg:`help dates` for a list of formats valid for -d/--date.
6384 See :hg:`help dates` for a list of formats valid for -d/--date.
6393
6385
6394 See :hg:`help backout` for a way to reverse the effect of an
6386 See :hg:`help backout` for a way to reverse the effect of an
6395 earlier changeset.
6387 earlier changeset.
6396
6388
6397 Returns 0 on success.
6389 Returns 0 on success.
6398 """
6390 """
6399
6391
6400 if opts.get("date"):
6392 if opts.get("date"):
6401 if opts.get("rev"):
6393 if opts.get("rev"):
6402 raise error.Abort(_("you can't specify a revision and a date"))
6394 raise error.Abort(_("you can't specify a revision and a date"))
6403 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6395 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6404
6396
6405 parent, p2 = repo.dirstate.parents()
6397 parent, p2 = repo.dirstate.parents()
6406 if not opts.get('rev') and p2 != nullid:
6398 if not opts.get('rev') and p2 != nullid:
6407 # revert after merge is a trap for new users (issue2915)
6399 # revert after merge is a trap for new users (issue2915)
6408 raise error.Abort(_('uncommitted merge with no revision specified'),
6400 raise error.Abort(_('uncommitted merge with no revision specified'),
6409 hint=_("use 'hg update' or see 'hg help revert'"))
6401 hint=_("use 'hg update' or see 'hg help revert'"))
6410
6402
6411 ctx = scmutil.revsingle(repo, opts.get('rev'))
6403 ctx = scmutil.revsingle(repo, opts.get('rev'))
6412
6404
6413 if (not (pats or opts.get('include') or opts.get('exclude') or
6405 if (not (pats or opts.get('include') or opts.get('exclude') or
6414 opts.get('all') or opts.get('interactive'))):
6406 opts.get('all') or opts.get('interactive'))):
6415 msg = _("no files or directories specified")
6407 msg = _("no files or directories specified")
6416 if p2 != nullid:
6408 if p2 != nullid:
6417 hint = _("uncommitted merge, use --all to discard all changes,"
6409 hint = _("uncommitted merge, use --all to discard all changes,"
6418 " or 'hg update -C .' to abort the merge")
6410 " or 'hg update -C .' to abort the merge")
6419 raise error.Abort(msg, hint=hint)
6411 raise error.Abort(msg, hint=hint)
6420 dirty = any(repo.status())
6412 dirty = any(repo.status())
6421 node = ctx.node()
6413 node = ctx.node()
6422 if node != parent:
6414 if node != parent:
6423 if dirty:
6415 if dirty:
6424 hint = _("uncommitted changes, use --all to discard all"
6416 hint = _("uncommitted changes, use --all to discard all"
6425 " changes, or 'hg update %s' to update") % ctx.rev()
6417 " changes, or 'hg update %s' to update") % ctx.rev()
6426 else:
6418 else:
6427 hint = _("use --all to revert all files,"
6419 hint = _("use --all to revert all files,"
6428 " or 'hg update %s' to update") % ctx.rev()
6420 " or 'hg update %s' to update") % ctx.rev()
6429 elif dirty:
6421 elif dirty:
6430 hint = _("uncommitted changes, use --all to discard all changes")
6422 hint = _("uncommitted changes, use --all to discard all changes")
6431 else:
6423 else:
6432 hint = _("use --all to revert all files")
6424 hint = _("use --all to revert all files")
6433 raise error.Abort(msg, hint=hint)
6425 raise error.Abort(msg, hint=hint)
6434
6426
6435 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6427 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6436
6428
6437 @command('rollback', dryrunopts +
6429 @command('rollback', dryrunopts +
6438 [('f', 'force', False, _('ignore safety measures'))])
6430 [('f', 'force', False, _('ignore safety measures'))])
6439 def rollback(ui, repo, **opts):
6431 def rollback(ui, repo, **opts):
6440 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6432 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6441
6433
6442 Please use :hg:`commit --amend` instead of rollback to correct
6434 Please use :hg:`commit --amend` instead of rollback to correct
6443 mistakes in the last commit.
6435 mistakes in the last commit.
6444
6436
6445 This command should be used with care. There is only one level of
6437 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
6438 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
6439 restore the dirstate at the time of the last transaction, losing
6448 any dirstate changes since that time. This command does not alter
6440 any dirstate changes since that time. This command does not alter
6449 the working directory.
6441 the working directory.
6450
6442
6451 Transactions are used to encapsulate the effects of all commands
6443 Transactions are used to encapsulate the effects of all commands
6452 that create new changesets or propagate existing changesets into a
6444 that create new changesets or propagate existing changesets into a
6453 repository.
6445 repository.
6454
6446
6455 .. container:: verbose
6447 .. container:: verbose
6456
6448
6457 For example, the following commands are transactional, and their
6449 For example, the following commands are transactional, and their
6458 effects can be rolled back:
6450 effects can be rolled back:
6459
6451
6460 - commit
6452 - commit
6461 - import
6453 - import
6462 - pull
6454 - pull
6463 - push (with this repository as the destination)
6455 - push (with this repository as the destination)
6464 - unbundle
6456 - unbundle
6465
6457
6466 To avoid permanent data loss, rollback will refuse to rollback a
6458 To avoid permanent data loss, rollback will refuse to rollback a
6467 commit transaction if it isn't checked out. Use --force to
6459 commit transaction if it isn't checked out. Use --force to
6468 override this protection.
6460 override this protection.
6469
6461
6470 The rollback command can be entirely disabled by setting the
6462 The rollback command can be entirely disabled by setting the
6471 ``ui.rollback`` configuration setting to false. If you're here
6463 ``ui.rollback`` configuration setting to false. If you're here
6472 because you want to use rollback and it's disabled, you can
6464 because you want to use rollback and it's disabled, you can
6473 re-enable the command by setting ``ui.rollback`` to true.
6465 re-enable the command by setting ``ui.rollback`` to true.
6474
6466
6475 This command is not intended for use on public repositories. Once
6467 This command is not intended for use on public repositories. Once
6476 changes are visible for pull by other users, rolling a transaction
6468 changes are visible for pull by other users, rolling a transaction
6477 back locally is ineffective (someone else may already have pulled
6469 back locally is ineffective (someone else may already have pulled
6478 the changes). Furthermore, a race is possible with readers of the
6470 the changes). Furthermore, a race is possible with readers of the
6479 repository; for example an in-progress pull from the repository
6471 repository; for example an in-progress pull from the repository
6480 may fail if a rollback is performed.
6472 may fail if a rollback is performed.
6481
6473
6482 Returns 0 on success, 1 if no rollback data is available.
6474 Returns 0 on success, 1 if no rollback data is available.
6483 """
6475 """
6484 if not ui.configbool('ui', 'rollback', True):
6476 if not ui.configbool('ui', 'rollback', True):
6485 raise error.Abort(_('rollback is disabled because it is unsafe'),
6477 raise error.Abort(_('rollback is disabled because it is unsafe'),
6486 hint=('see `hg help -v rollback` for information'))
6478 hint=('see `hg help -v rollback` for information'))
6487 return repo.rollback(dryrun=opts.get('dry_run'),
6479 return repo.rollback(dryrun=opts.get('dry_run'),
6488 force=opts.get('force'))
6480 force=opts.get('force'))
6489
6481
6490 @command('root', [])
6482 @command('root', [])
6491 def root(ui, repo):
6483 def root(ui, repo):
6492 """print the root (top) of the current working directory
6484 """print the root (top) of the current working directory
6493
6485
6494 Print the root directory of the current repository.
6486 Print the root directory of the current repository.
6495
6487
6496 Returns 0 on success.
6488 Returns 0 on success.
6497 """
6489 """
6498 ui.write(repo.root + "\n")
6490 ui.write(repo.root + "\n")
6499
6491
6500 @command('^serve',
6492 @command('^serve',
6501 [('A', 'accesslog', '', _('name of access log file to write to'),
6493 [('A', 'accesslog', '', _('name of access log file to write to'),
6502 _('FILE')),
6494 _('FILE')),
6503 ('d', 'daemon', None, _('run server in background')),
6495 ('d', 'daemon', None, _('run server in background')),
6504 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6496 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6505 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6497 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6506 # use string type, then we can check if something was passed
6498 # use string type, then we can check if something was passed
6507 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6499 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6508 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6500 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6509 _('ADDR')),
6501 _('ADDR')),
6510 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6502 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6511 _('PREFIX')),
6503 _('PREFIX')),
6512 ('n', 'name', '',
6504 ('n', 'name', '',
6513 _('name to show in web pages (default: working directory)'), _('NAME')),
6505 _('name to show in web pages (default: working directory)'), _('NAME')),
6514 ('', 'web-conf', '',
6506 ('', 'web-conf', '',
6515 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6507 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6516 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6508 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6517 _('FILE')),
6509 _('FILE')),
6518 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6510 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6519 ('', 'stdio', None, _('for remote clients')),
6511 ('', 'stdio', None, _('for remote clients')),
6520 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6512 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6521 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6513 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6522 ('', 'style', '', _('template style to use'), _('STYLE')),
6514 ('', 'style', '', _('template style to use'), _('STYLE')),
6523 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6515 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6524 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6516 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6525 _('[OPTION]...'),
6517 _('[OPTION]...'),
6526 optionalrepo=True)
6518 optionalrepo=True)
6527 def serve(ui, repo, **opts):
6519 def serve(ui, repo, **opts):
6528 """start stand-alone webserver
6520 """start stand-alone webserver
6529
6521
6530 Start a local HTTP repository browser and pull server. You can use
6522 Start a local HTTP repository browser and pull server. You can use
6531 this for ad-hoc sharing and browsing of repositories. It is
6523 this for ad-hoc sharing and browsing of repositories. It is
6532 recommended to use a real web server to serve a repository for
6524 recommended to use a real web server to serve a repository for
6533 longer periods of time.
6525 longer periods of time.
6534
6526
6535 Please note that the server does not implement access control.
6527 Please note that the server does not implement access control.
6536 This means that, by default, anybody can read from the server and
6528 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``
6529 nobody can write to it by default. Set the ``web.allow_push``
6538 option to ``*`` to allow everybody to push to the server. You
6530 option to ``*`` to allow everybody to push to the server. You
6539 should use a real web server if you need to authenticate users.
6531 should use a real web server if you need to authenticate users.
6540
6532
6541 By default, the server logs accesses to stdout and errors to
6533 By default, the server logs accesses to stdout and errors to
6542 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6534 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6543 files.
6535 files.
6544
6536
6545 To have the server choose a free port number to listen on, specify
6537 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
6538 a port number of 0; in this case, the server will print the port
6547 number it uses.
6539 number it uses.
6548
6540
6549 Returns 0 on success.
6541 Returns 0 on success.
6550 """
6542 """
6551
6543
6552 if opts["stdio"] and opts["cmdserver"]:
6544 if opts["stdio"] and opts["cmdserver"]:
6553 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6545 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6554
6546
6555 if opts["stdio"]:
6547 if opts["stdio"]:
6556 if repo is None:
6548 if repo is None:
6557 raise error.RepoError(_("there is no Mercurial repository here"
6549 raise error.RepoError(_("there is no Mercurial repository here"
6558 " (.hg not found)"))
6550 " (.hg not found)"))
6559 s = sshserver.sshserver(ui, repo)
6551 s = sshserver.sshserver(ui, repo)
6560 s.serve_forever()
6552 s.serve_forever()
6561
6553
6562 if opts["cmdserver"]:
6554 if opts["cmdserver"]:
6563 service = commandserver.createservice(ui, repo, opts)
6555 service = commandserver.createservice(ui, repo, opts)
6564 else:
6556 else:
6565 service = hgweb.createservice(ui, repo, opts)
6557 service = hgweb.createservice(ui, repo, opts)
6566 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6558 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6567
6559
6568 @command('^status|st',
6560 @command('^status|st',
6569 [('A', 'all', None, _('show status of all files')),
6561 [('A', 'all', None, _('show status of all files')),
6570 ('m', 'modified', None, _('show only modified files')),
6562 ('m', 'modified', None, _('show only modified files')),
6571 ('a', 'added', None, _('show only added files')),
6563 ('a', 'added', None, _('show only added files')),
6572 ('r', 'removed', None, _('show only removed files')),
6564 ('r', 'removed', None, _('show only removed files')),
6573 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6565 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6574 ('c', 'clean', None, _('show only files without changes')),
6566 ('c', 'clean', None, _('show only files without changes')),
6575 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6567 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6576 ('i', 'ignored', None, _('show only ignored files')),
6568 ('i', 'ignored', None, _('show only ignored files')),
6577 ('n', 'no-status', None, _('hide status prefix')),
6569 ('n', 'no-status', None, _('hide status prefix')),
6578 ('C', 'copies', None, _('show source of copied files')),
6570 ('C', 'copies', None, _('show source of copied files')),
6579 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6571 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6580 ('', 'rev', [], _('show difference from revision'), _('REV')),
6572 ('', 'rev', [], _('show difference from revision'), _('REV')),
6581 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6573 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6582 ] + walkopts + subrepoopts + formatteropts,
6574 ] + walkopts + subrepoopts + formatteropts,
6583 _('[OPTION]... [FILE]...'),
6575 _('[OPTION]... [FILE]...'),
6584 inferrepo=True)
6576 inferrepo=True)
6585 def status(ui, repo, *pats, **opts):
6577 def status(ui, repo, *pats, **opts):
6586 """show changed files in the working directory
6578 """show changed files in the working directory
6587
6579
6588 Show status of files in the repository. If names are given, only
6580 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
6581 files that match are shown. Files that are clean or ignored or
6590 the source of a copy/move operation, are not listed unless
6582 the source of a copy/move operation, are not listed unless
6591 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6583 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6592 Unless options described with "show only ..." are given, the
6584 Unless options described with "show only ..." are given, the
6593 options -mardu are used.
6585 options -mardu are used.
6594
6586
6595 Option -q/--quiet hides untracked (unknown and ignored) files
6587 Option -q/--quiet hides untracked (unknown and ignored) files
6596 unless explicitly requested with -u/--unknown or -i/--ignored.
6588 unless explicitly requested with -u/--unknown or -i/--ignored.
6597
6589
6598 .. note::
6590 .. note::
6599
6591
6600 :hg:`status` may appear to disagree with diff if permissions have
6592 :hg:`status` may appear to disagree with diff if permissions have
6601 changed or a merge has occurred. The standard diff format does
6593 changed or a merge has occurred. The standard diff format does
6602 not report permission changes and diff only reports changes
6594 not report permission changes and diff only reports changes
6603 relative to one merge parent.
6595 relative to one merge parent.
6604
6596
6605 If one revision is given, it is used as the base revision.
6597 If one revision is given, it is used as the base revision.
6606 If two revisions are given, the differences between them are
6598 If two revisions are given, the differences between them are
6607 shown. The --change option can also be used as a shortcut to list
6599 shown. The --change option can also be used as a shortcut to list
6608 the changed files of a revision from its first parent.
6600 the changed files of a revision from its first parent.
6609
6601
6610 The codes used to show the status of files are::
6602 The codes used to show the status of files are::
6611
6603
6612 M = modified
6604 M = modified
6613 A = added
6605 A = added
6614 R = removed
6606 R = removed
6615 C = clean
6607 C = clean
6616 ! = missing (deleted by non-hg command, but still tracked)
6608 ! = missing (deleted by non-hg command, but still tracked)
6617 ? = not tracked
6609 ? = not tracked
6618 I = ignored
6610 I = ignored
6619 = origin of the previous file (with --copies)
6611 = origin of the previous file (with --copies)
6620
6612
6621 .. container:: verbose
6613 .. container:: verbose
6622
6614
6623 Examples:
6615 Examples:
6624
6616
6625 - show changes in the working directory relative to a
6617 - show changes in the working directory relative to a
6626 changeset::
6618 changeset::
6627
6619
6628 hg status --rev 9353
6620 hg status --rev 9353
6629
6621
6630 - show changes in the working directory relative to the
6622 - show changes in the working directory relative to the
6631 current directory (see :hg:`help patterns` for more information)::
6623 current directory (see :hg:`help patterns` for more information)::
6632
6624
6633 hg status re:
6625 hg status re:
6634
6626
6635 - show all changes including copies in an existing changeset::
6627 - show all changes including copies in an existing changeset::
6636
6628
6637 hg status --copies --change 9353
6629 hg status --copies --change 9353
6638
6630
6639 - get a NUL separated list of added files, suitable for xargs::
6631 - get a NUL separated list of added files, suitable for xargs::
6640
6632
6641 hg status -an0
6633 hg status -an0
6642
6634
6643 Returns 0 on success.
6635 Returns 0 on success.
6644 """
6636 """
6645
6637
6646 revs = opts.get('rev')
6638 revs = opts.get('rev')
6647 change = opts.get('change')
6639 change = opts.get('change')
6648
6640
6649 if revs and change:
6641 if revs and change:
6650 msg = _('cannot specify --rev and --change at the same time')
6642 msg = _('cannot specify --rev and --change at the same time')
6651 raise error.Abort(msg)
6643 raise error.Abort(msg)
6652 elif change:
6644 elif change:
6653 node2 = scmutil.revsingle(repo, change, None).node()
6645 node2 = scmutil.revsingle(repo, change, None).node()
6654 node1 = repo[node2].p1().node()
6646 node1 = repo[node2].p1().node()
6655 else:
6647 else:
6656 node1, node2 = scmutil.revpair(repo, revs)
6648 node1, node2 = scmutil.revpair(repo, revs)
6657
6649
6658 if pats:
6650 if pats:
6659 cwd = repo.getcwd()
6651 cwd = repo.getcwd()
6660 else:
6652 else:
6661 cwd = ''
6653 cwd = ''
6662
6654
6663 if opts.get('print0'):
6655 if opts.get('print0'):
6664 end = '\0'
6656 end = '\0'
6665 else:
6657 else:
6666 end = '\n'
6658 end = '\n'
6667 copy = {}
6659 copy = {}
6668 states = 'modified added removed deleted unknown ignored clean'.split()
6660 states = 'modified added removed deleted unknown ignored clean'.split()
6669 show = [k for k in states if opts.get(k)]
6661 show = [k for k in states if opts.get(k)]
6670 if opts.get('all'):
6662 if opts.get('all'):
6671 show += ui.quiet and (states[:4] + ['clean']) or states
6663 show += ui.quiet and (states[:4] + ['clean']) or states
6672 if not show:
6664 if not show:
6673 if ui.quiet:
6665 if ui.quiet:
6674 show = states[:4]
6666 show = states[:4]
6675 else:
6667 else:
6676 show = states[:5]
6668 show = states[:5]
6677
6669
6678 m = scmutil.match(repo[node2], pats, opts)
6670 m = scmutil.match(repo[node2], pats, opts)
6679 stat = repo.status(node1, node2, m,
6671 stat = repo.status(node1, node2, m,
6680 'ignored' in show, 'clean' in show, 'unknown' in show,
6672 'ignored' in show, 'clean' in show, 'unknown' in show,
6681 opts.get('subrepos'))
6673 opts.get('subrepos'))
6682 changestates = zip(states, 'MAR!?IC', stat)
6674 changestates = zip(states, 'MAR!?IC', stat)
6683
6675
6684 if (opts.get('all') or opts.get('copies')
6676 if (opts.get('all') or opts.get('copies')
6685 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6677 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6686 copy = copies.pathcopies(repo[node1], repo[node2], m)
6678 copy = copies.pathcopies(repo[node1], repo[node2], m)
6687
6679
6688 fm = ui.formatter('status', opts)
6680 fm = ui.formatter('status', opts)
6689 fmt = '%s' + end
6681 fmt = '%s' + end
6690 showchar = not opts.get('no_status')
6682 showchar = not opts.get('no_status')
6691
6683
6692 for state, char, files in changestates:
6684 for state, char, files in changestates:
6693 if state in show:
6685 if state in show:
6694 label = 'status.' + state
6686 label = 'status.' + state
6695 for f in files:
6687 for f in files:
6696 fm.startitem()
6688 fm.startitem()
6697 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6689 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6698 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6690 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6699 if f in copy:
6691 if f in copy:
6700 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6692 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6701 label='status.copied')
6693 label='status.copied')
6702 fm.end()
6694 fm.end()
6703
6695
6704 @command('^summary|sum',
6696 @command('^summary|sum',
6705 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6697 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6706 def summary(ui, repo, **opts):
6698 def summary(ui, repo, **opts):
6707 """summarize working directory state
6699 """summarize working directory state
6708
6700
6709 This generates a brief summary of the working directory state,
6701 This generates a brief summary of the working directory state,
6710 including parents, branch, commit status, phase and available updates.
6702 including parents, branch, commit status, phase and available updates.
6711
6703
6712 With the --remote option, this will check the default paths for
6704 With the --remote option, this will check the default paths for
6713 incoming and outgoing changes. This can be time-consuming.
6705 incoming and outgoing changes. This can be time-consuming.
6714
6706
6715 Returns 0 on success.
6707 Returns 0 on success.
6716 """
6708 """
6717
6709
6718 ctx = repo[None]
6710 ctx = repo[None]
6719 parents = ctx.parents()
6711 parents = ctx.parents()
6720 pnode = parents[0].node()
6712 pnode = parents[0].node()
6721 marks = []
6713 marks = []
6722
6714
6723 ms = None
6715 ms = None
6724 try:
6716 try:
6725 ms = mergemod.mergestate.read(repo)
6717 ms = mergemod.mergestate.read(repo)
6726 except error.UnsupportedMergeRecords as e:
6718 except error.UnsupportedMergeRecords as e:
6727 s = ' '.join(e.recordtypes)
6719 s = ' '.join(e.recordtypes)
6728 ui.warn(
6720 ui.warn(
6729 _('warning: merge state has unsupported record types: %s\n') % s)
6721 _('warning: merge state has unsupported record types: %s\n') % s)
6730 unresolved = 0
6722 unresolved = 0
6731 else:
6723 else:
6732 unresolved = [f for f in ms if ms[f] == 'u']
6724 unresolved = [f for f in ms if ms[f] == 'u']
6733
6725
6734 for p in parents:
6726 for p in parents:
6735 # label with log.changeset (instead of log.parent) since this
6727 # label with log.changeset (instead of log.parent) since this
6736 # shows a working directory parent *changeset*:
6728 # shows a working directory parent *changeset*:
6737 # i18n: column positioning for "hg summary"
6729 # i18n: column positioning for "hg summary"
6738 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6730 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6739 label='log.changeset changeset.%s' % p.phasestr())
6731 label='log.changeset changeset.%s' % p.phasestr())
6740 ui.write(' '.join(p.tags()), label='log.tag')
6732 ui.write(' '.join(p.tags()), label='log.tag')
6741 if p.bookmarks():
6733 if p.bookmarks():
6742 marks.extend(p.bookmarks())
6734 marks.extend(p.bookmarks())
6743 if p.rev() == -1:
6735 if p.rev() == -1:
6744 if not len(repo):
6736 if not len(repo):
6745 ui.write(_(' (empty repository)'))
6737 ui.write(_(' (empty repository)'))
6746 else:
6738 else:
6747 ui.write(_(' (no revision checked out)'))
6739 ui.write(_(' (no revision checked out)'))
6748 ui.write('\n')
6740 ui.write('\n')
6749 if p.description():
6741 if p.description():
6750 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6742 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6751 label='log.summary')
6743 label='log.summary')
6752
6744
6753 branch = ctx.branch()
6745 branch = ctx.branch()
6754 bheads = repo.branchheads(branch)
6746 bheads = repo.branchheads(branch)
6755 # i18n: column positioning for "hg summary"
6747 # i18n: column positioning for "hg summary"
6756 m = _('branch: %s\n') % branch
6748 m = _('branch: %s\n') % branch
6757 if branch != 'default':
6749 if branch != 'default':
6758 ui.write(m, label='log.branch')
6750 ui.write(m, label='log.branch')
6759 else:
6751 else:
6760 ui.status(m, label='log.branch')
6752 ui.status(m, label='log.branch')
6761
6753
6762 if marks:
6754 if marks:
6763 active = repo._activebookmark
6755 active = repo._activebookmark
6764 # i18n: column positioning for "hg summary"
6756 # i18n: column positioning for "hg summary"
6765 ui.write(_('bookmarks:'), label='log.bookmark')
6757 ui.write(_('bookmarks:'), label='log.bookmark')
6766 if active is not None:
6758 if active is not None:
6767 if active in marks:
6759 if active in marks:
6768 ui.write(' *' + active, label=activebookmarklabel)
6760 ui.write(' *' + active, label=activebookmarklabel)
6769 marks.remove(active)
6761 marks.remove(active)
6770 else:
6762 else:
6771 ui.write(' [%s]' % active, label=activebookmarklabel)
6763 ui.write(' [%s]' % active, label=activebookmarklabel)
6772 for m in marks:
6764 for m in marks:
6773 ui.write(' ' + m, label='log.bookmark')
6765 ui.write(' ' + m, label='log.bookmark')
6774 ui.write('\n', label='log.bookmark')
6766 ui.write('\n', label='log.bookmark')
6775
6767
6776 status = repo.status(unknown=True)
6768 status = repo.status(unknown=True)
6777
6769
6778 c = repo.dirstate.copies()
6770 c = repo.dirstate.copies()
6779 copied, renamed = [], []
6771 copied, renamed = [], []
6780 for d, s in c.iteritems():
6772 for d, s in c.iteritems():
6781 if s in status.removed:
6773 if s in status.removed:
6782 status.removed.remove(s)
6774 status.removed.remove(s)
6783 renamed.append(d)
6775 renamed.append(d)
6784 else:
6776 else:
6785 copied.append(d)
6777 copied.append(d)
6786 if d in status.added:
6778 if d in status.added:
6787 status.added.remove(d)
6779 status.added.remove(d)
6788
6780
6789 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6781 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6790
6782
6791 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6783 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6792 (ui.label(_('%d added'), 'status.added'), status.added),
6784 (ui.label(_('%d added'), 'status.added'), status.added),
6793 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6785 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6794 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6786 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6795 (ui.label(_('%d copied'), 'status.copied'), copied),
6787 (ui.label(_('%d copied'), 'status.copied'), copied),
6796 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6788 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6797 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6789 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6798 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6790 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6799 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6791 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6800 t = []
6792 t = []
6801 for l, s in labels:
6793 for l, s in labels:
6802 if s:
6794 if s:
6803 t.append(l % len(s))
6795 t.append(l % len(s))
6804
6796
6805 t = ', '.join(t)
6797 t = ', '.join(t)
6806 cleanworkdir = False
6798 cleanworkdir = False
6807
6799
6808 if repo.vfs.exists('graftstate'):
6800 if repo.vfs.exists('graftstate'):
6809 t += _(' (graft in progress)')
6801 t += _(' (graft in progress)')
6810 if repo.vfs.exists('updatestate'):
6802 if repo.vfs.exists('updatestate'):
6811 t += _(' (interrupted update)')
6803 t += _(' (interrupted update)')
6812 elif len(parents) > 1:
6804 elif len(parents) > 1:
6813 t += _(' (merge)')
6805 t += _(' (merge)')
6814 elif branch != parents[0].branch():
6806 elif branch != parents[0].branch():
6815 t += _(' (new branch)')
6807 t += _(' (new branch)')
6816 elif (parents[0].closesbranch() and
6808 elif (parents[0].closesbranch() and
6817 pnode in repo.branchheads(branch, closed=True)):
6809 pnode in repo.branchheads(branch, closed=True)):
6818 t += _(' (head closed)')
6810 t += _(' (head closed)')
6819 elif not (status.modified or status.added or status.removed or renamed or
6811 elif not (status.modified or status.added or status.removed or renamed or
6820 copied or subs):
6812 copied or subs):
6821 t += _(' (clean)')
6813 t += _(' (clean)')
6822 cleanworkdir = True
6814 cleanworkdir = True
6823 elif pnode not in bheads:
6815 elif pnode not in bheads:
6824 t += _(' (new branch head)')
6816 t += _(' (new branch head)')
6825
6817
6826 if parents:
6818 if parents:
6827 pendingphase = max(p.phase() for p in parents)
6819 pendingphase = max(p.phase() for p in parents)
6828 else:
6820 else:
6829 pendingphase = phases.public
6821 pendingphase = phases.public
6830
6822
6831 if pendingphase > phases.newcommitphase(ui):
6823 if pendingphase > phases.newcommitphase(ui):
6832 t += ' (%s)' % phases.phasenames[pendingphase]
6824 t += ' (%s)' % phases.phasenames[pendingphase]
6833
6825
6834 if cleanworkdir:
6826 if cleanworkdir:
6835 # i18n: column positioning for "hg summary"
6827 # i18n: column positioning for "hg summary"
6836 ui.status(_('commit: %s\n') % t.strip())
6828 ui.status(_('commit: %s\n') % t.strip())
6837 else:
6829 else:
6838 # i18n: column positioning for "hg summary"
6830 # i18n: column positioning for "hg summary"
6839 ui.write(_('commit: %s\n') % t.strip())
6831 ui.write(_('commit: %s\n') % t.strip())
6840
6832
6841 # all ancestors of branch heads - all ancestors of parent = new csets
6833 # all ancestors of branch heads - all ancestors of parent = new csets
6842 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6834 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6843 bheads))
6835 bheads))
6844
6836
6845 if new == 0:
6837 if new == 0:
6846 # i18n: column positioning for "hg summary"
6838 # i18n: column positioning for "hg summary"
6847 ui.status(_('update: (current)\n'))
6839 ui.status(_('update: (current)\n'))
6848 elif pnode not in bheads:
6840 elif pnode not in bheads:
6849 # i18n: column positioning for "hg summary"
6841 # i18n: column positioning for "hg summary"
6850 ui.write(_('update: %d new changesets (update)\n') % new)
6842 ui.write(_('update: %d new changesets (update)\n') % new)
6851 else:
6843 else:
6852 # i18n: column positioning for "hg summary"
6844 # i18n: column positioning for "hg summary"
6853 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6845 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6854 (new, len(bheads)))
6846 (new, len(bheads)))
6855
6847
6856 t = []
6848 t = []
6857 draft = len(repo.revs('draft()'))
6849 draft = len(repo.revs('draft()'))
6858 if draft:
6850 if draft:
6859 t.append(_('%d draft') % draft)
6851 t.append(_('%d draft') % draft)
6860 secret = len(repo.revs('secret()'))
6852 secret = len(repo.revs('secret()'))
6861 if secret:
6853 if secret:
6862 t.append(_('%d secret') % secret)
6854 t.append(_('%d secret') % secret)
6863
6855
6864 if draft or secret:
6856 if draft or secret:
6865 ui.status(_('phases: %s\n') % ', '.join(t))
6857 ui.status(_('phases: %s\n') % ', '.join(t))
6866
6858
6867 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6859 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6868 for trouble in ("unstable", "divergent", "bumped"):
6860 for trouble in ("unstable", "divergent", "bumped"):
6869 numtrouble = len(repo.revs(trouble + "()"))
6861 numtrouble = len(repo.revs(trouble + "()"))
6870 # We write all the possibilities to ease translation
6862 # We write all the possibilities to ease translation
6871 troublemsg = {
6863 troublemsg = {
6872 "unstable": _("unstable: %d changesets"),
6864 "unstable": _("unstable: %d changesets"),
6873 "divergent": _("divergent: %d changesets"),
6865 "divergent": _("divergent: %d changesets"),
6874 "bumped": _("bumped: %d changesets"),
6866 "bumped": _("bumped: %d changesets"),
6875 }
6867 }
6876 if numtrouble > 0:
6868 if numtrouble > 0:
6877 ui.status(troublemsg[trouble] % numtrouble + "\n")
6869 ui.status(troublemsg[trouble] % numtrouble + "\n")
6878
6870
6879 cmdutil.summaryhooks(ui, repo)
6871 cmdutil.summaryhooks(ui, repo)
6880
6872
6881 if opts.get('remote'):
6873 if opts.get('remote'):
6882 needsincoming, needsoutgoing = True, True
6874 needsincoming, needsoutgoing = True, True
6883 else:
6875 else:
6884 needsincoming, needsoutgoing = False, False
6876 needsincoming, needsoutgoing = False, False
6885 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6877 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6886 if i:
6878 if i:
6887 needsincoming = True
6879 needsincoming = True
6888 if o:
6880 if o:
6889 needsoutgoing = True
6881 needsoutgoing = True
6890 if not needsincoming and not needsoutgoing:
6882 if not needsincoming and not needsoutgoing:
6891 return
6883 return
6892
6884
6893 def getincoming():
6885 def getincoming():
6894 source, branches = hg.parseurl(ui.expandpath('default'))
6886 source, branches = hg.parseurl(ui.expandpath('default'))
6895 sbranch = branches[0]
6887 sbranch = branches[0]
6896 try:
6888 try:
6897 other = hg.peer(repo, {}, source)
6889 other = hg.peer(repo, {}, source)
6898 except error.RepoError:
6890 except error.RepoError:
6899 if opts.get('remote'):
6891 if opts.get('remote'):
6900 raise
6892 raise
6901 return source, sbranch, None, None, None
6893 return source, sbranch, None, None, None
6902 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6894 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6903 if revs:
6895 if revs:
6904 revs = [other.lookup(rev) for rev in revs]
6896 revs = [other.lookup(rev) for rev in revs]
6905 ui.debug('comparing with %s\n' % util.hidepassword(source))
6897 ui.debug('comparing with %s\n' % util.hidepassword(source))
6906 repo.ui.pushbuffer()
6898 repo.ui.pushbuffer()
6907 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6899 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6908 repo.ui.popbuffer()
6900 repo.ui.popbuffer()
6909 return source, sbranch, other, commoninc, commoninc[1]
6901 return source, sbranch, other, commoninc, commoninc[1]
6910
6902
6911 if needsincoming:
6903 if needsincoming:
6912 source, sbranch, sother, commoninc, incoming = getincoming()
6904 source, sbranch, sother, commoninc, incoming = getincoming()
6913 else:
6905 else:
6914 source = sbranch = sother = commoninc = incoming = None
6906 source = sbranch = sother = commoninc = incoming = None
6915
6907
6916 def getoutgoing():
6908 def getoutgoing():
6917 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6909 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6918 dbranch = branches[0]
6910 dbranch = branches[0]
6919 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6911 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6920 if source != dest:
6912 if source != dest:
6921 try:
6913 try:
6922 dother = hg.peer(repo, {}, dest)
6914 dother = hg.peer(repo, {}, dest)
6923 except error.RepoError:
6915 except error.RepoError:
6924 if opts.get('remote'):
6916 if opts.get('remote'):
6925 raise
6917 raise
6926 return dest, dbranch, None, None
6918 return dest, dbranch, None, None
6927 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6919 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6928 elif sother is None:
6920 elif sother is None:
6929 # there is no explicit destination peer, but source one is invalid
6921 # there is no explicit destination peer, but source one is invalid
6930 return dest, dbranch, None, None
6922 return dest, dbranch, None, None
6931 else:
6923 else:
6932 dother = sother
6924 dother = sother
6933 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6925 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6934 common = None
6926 common = None
6935 else:
6927 else:
6936 common = commoninc
6928 common = commoninc
6937 if revs:
6929 if revs:
6938 revs = [repo.lookup(rev) for rev in revs]
6930 revs = [repo.lookup(rev) for rev in revs]
6939 repo.ui.pushbuffer()
6931 repo.ui.pushbuffer()
6940 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6932 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6941 commoninc=common)
6933 commoninc=common)
6942 repo.ui.popbuffer()
6934 repo.ui.popbuffer()
6943 return dest, dbranch, dother, outgoing
6935 return dest, dbranch, dother, outgoing
6944
6936
6945 if needsoutgoing:
6937 if needsoutgoing:
6946 dest, dbranch, dother, outgoing = getoutgoing()
6938 dest, dbranch, dother, outgoing = getoutgoing()
6947 else:
6939 else:
6948 dest = dbranch = dother = outgoing = None
6940 dest = dbranch = dother = outgoing = None
6949
6941
6950 if opts.get('remote'):
6942 if opts.get('remote'):
6951 t = []
6943 t = []
6952 if incoming:
6944 if incoming:
6953 t.append(_('1 or more incoming'))
6945 t.append(_('1 or more incoming'))
6954 o = outgoing.missing
6946 o = outgoing.missing
6955 if o:
6947 if o:
6956 t.append(_('%d outgoing') % len(o))
6948 t.append(_('%d outgoing') % len(o))
6957 other = dother or sother
6949 other = dother or sother
6958 if 'bookmarks' in other.listkeys('namespaces'):
6950 if 'bookmarks' in other.listkeys('namespaces'):
6959 counts = bookmarks.summary(repo, other)
6951 counts = bookmarks.summary(repo, other)
6960 if counts[0] > 0:
6952 if counts[0] > 0:
6961 t.append(_('%d incoming bookmarks') % counts[0])
6953 t.append(_('%d incoming bookmarks') % counts[0])
6962 if counts[1] > 0:
6954 if counts[1] > 0:
6963 t.append(_('%d outgoing bookmarks') % counts[1])
6955 t.append(_('%d outgoing bookmarks') % counts[1])
6964
6956
6965 if t:
6957 if t:
6966 # i18n: column positioning for "hg summary"
6958 # i18n: column positioning for "hg summary"
6967 ui.write(_('remote: %s\n') % (', '.join(t)))
6959 ui.write(_('remote: %s\n') % (', '.join(t)))
6968 else:
6960 else:
6969 # i18n: column positioning for "hg summary"
6961 # i18n: column positioning for "hg summary"
6970 ui.status(_('remote: (synced)\n'))
6962 ui.status(_('remote: (synced)\n'))
6971
6963
6972 cmdutil.summaryremotehooks(ui, repo, opts,
6964 cmdutil.summaryremotehooks(ui, repo, opts,
6973 ((source, sbranch, sother, commoninc),
6965 ((source, sbranch, sother, commoninc),
6974 (dest, dbranch, dother, outgoing)))
6966 (dest, dbranch, dother, outgoing)))
6975
6967
6976 @command('tag',
6968 @command('tag',
6977 [('f', 'force', None, _('force tag')),
6969 [('f', 'force', None, _('force tag')),
6978 ('l', 'local', None, _('make the tag local')),
6970 ('l', 'local', None, _('make the tag local')),
6979 ('r', 'rev', '', _('revision to tag'), _('REV')),
6971 ('r', 'rev', '', _('revision to tag'), _('REV')),
6980 ('', 'remove', None, _('remove a tag')),
6972 ('', 'remove', None, _('remove a tag')),
6981 # -l/--local is already there, commitopts cannot be used
6973 # -l/--local is already there, commitopts cannot be used
6982 ('e', 'edit', None, _('invoke editor on commit messages')),
6974 ('e', 'edit', None, _('invoke editor on commit messages')),
6983 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6975 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6984 ] + commitopts2,
6976 ] + commitopts2,
6985 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6977 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6986 def tag(ui, repo, name1, *names, **opts):
6978 def tag(ui, repo, name1, *names, **opts):
6987 """add one or more tags for the current or given revision
6979 """add one or more tags for the current or given revision
6988
6980
6989 Name a particular revision using <name>.
6981 Name a particular revision using <name>.
6990
6982
6991 Tags are used to name particular revisions of the repository and are
6983 Tags are used to name particular revisions of the repository and are
6992 very useful to compare different revisions, to go back to significant
6984 very useful to compare different revisions, to go back to significant
6993 earlier versions or to mark branch points as releases, etc. Changing
6985 earlier versions or to mark branch points as releases, etc. Changing
6994 an existing tag is normally disallowed; use -f/--force to override.
6986 an existing tag is normally disallowed; use -f/--force to override.
6995
6987
6996 If no revision is given, the parent of the working directory is
6988 If no revision is given, the parent of the working directory is
6997 used.
6989 used.
6998
6990
6999 To facilitate version control, distribution, and merging of tags,
6991 To facilitate version control, distribution, and merging of tags,
7000 they are stored as a file named ".hgtags" which is managed similarly
6992 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
6993 to other project files and can be hand-edited if necessary. This
7002 also means that tagging creates a new commit. The file
6994 also means that tagging creates a new commit. The file
7003 ".hg/localtags" is used for local tags (not shared among
6995 ".hg/localtags" is used for local tags (not shared among
7004 repositories).
6996 repositories).
7005
6997
7006 Tag commits are usually made at the head of a branch. If the parent
6998 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
6999 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
7000 -f/--force to force the tag commit to be based on a non-head
7009 changeset.
7001 changeset.
7010
7002
7011 See :hg:`help dates` for a list of formats valid for -d/--date.
7003 See :hg:`help dates` for a list of formats valid for -d/--date.
7012
7004
7013 Since tag names have priority over branch names during revision
7005 Since tag names have priority over branch names during revision
7014 lookup, using an existing branch name as a tag name is discouraged.
7006 lookup, using an existing branch name as a tag name is discouraged.
7015
7007
7016 Returns 0 on success.
7008 Returns 0 on success.
7017 """
7009 """
7018 wlock = lock = None
7010 wlock = lock = None
7019 try:
7011 try:
7020 wlock = repo.wlock()
7012 wlock = repo.wlock()
7021 lock = repo.lock()
7013 lock = repo.lock()
7022 rev_ = "."
7014 rev_ = "."
7023 names = [t.strip() for t in (name1,) + names]
7015 names = [t.strip() for t in (name1,) + names]
7024 if len(names) != len(set(names)):
7016 if len(names) != len(set(names)):
7025 raise error.Abort(_('tag names must be unique'))
7017 raise error.Abort(_('tag names must be unique'))
7026 for n in names:
7018 for n in names:
7027 scmutil.checknewlabel(repo, n, 'tag')
7019 scmutil.checknewlabel(repo, n, 'tag')
7028 if not n:
7020 if not n:
7029 raise error.Abort(_('tag names cannot consist entirely of '
7021 raise error.Abort(_('tag names cannot consist entirely of '
7030 'whitespace'))
7022 'whitespace'))
7031 if opts.get('rev') and opts.get('remove'):
7023 if opts.get('rev') and opts.get('remove'):
7032 raise error.Abort(_("--rev and --remove are incompatible"))
7024 raise error.Abort(_("--rev and --remove are incompatible"))
7033 if opts.get('rev'):
7025 if opts.get('rev'):
7034 rev_ = opts['rev']
7026 rev_ = opts['rev']
7035 message = opts.get('message')
7027 message = opts.get('message')
7036 if opts.get('remove'):
7028 if opts.get('remove'):
7037 if opts.get('local'):
7029 if opts.get('local'):
7038 expectedtype = 'local'
7030 expectedtype = 'local'
7039 else:
7031 else:
7040 expectedtype = 'global'
7032 expectedtype = 'global'
7041
7033
7042 for n in names:
7034 for n in names:
7043 if not repo.tagtype(n):
7035 if not repo.tagtype(n):
7044 raise error.Abort(_("tag '%s' does not exist") % n)
7036 raise error.Abort(_("tag '%s' does not exist") % n)
7045 if repo.tagtype(n) != expectedtype:
7037 if repo.tagtype(n) != expectedtype:
7046 if expectedtype == 'global':
7038 if expectedtype == 'global':
7047 raise error.Abort(_("tag '%s' is not a global tag") % n)
7039 raise error.Abort(_("tag '%s' is not a global tag") % n)
7048 else:
7040 else:
7049 raise error.Abort(_("tag '%s' is not a local tag") % n)
7041 raise error.Abort(_("tag '%s' is not a local tag") % n)
7050 rev_ = 'null'
7042 rev_ = 'null'
7051 if not message:
7043 if not message:
7052 # we don't translate commit messages
7044 # we don't translate commit messages
7053 message = 'Removed tag %s' % ', '.join(names)
7045 message = 'Removed tag %s' % ', '.join(names)
7054 elif not opts.get('force'):
7046 elif not opts.get('force'):
7055 for n in names:
7047 for n in names:
7056 if n in repo.tags():
7048 if n in repo.tags():
7057 raise error.Abort(_("tag '%s' already exists "
7049 raise error.Abort(_("tag '%s' already exists "
7058 "(use -f to force)") % n)
7050 "(use -f to force)") % n)
7059 if not opts.get('local'):
7051 if not opts.get('local'):
7060 p1, p2 = repo.dirstate.parents()
7052 p1, p2 = repo.dirstate.parents()
7061 if p2 != nullid:
7053 if p2 != nullid:
7062 raise error.Abort(_('uncommitted merge'))
7054 raise error.Abort(_('uncommitted merge'))
7063 bheads = repo.branchheads()
7055 bheads = repo.branchheads()
7064 if not opts.get('force') and bheads and p1 not in bheads:
7056 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)'))
7057 raise error.Abort(_('not at a branch head (use -f to force)'))
7066 r = scmutil.revsingle(repo, rev_).node()
7058 r = scmutil.revsingle(repo, rev_).node()
7067
7059
7068 if not message:
7060 if not message:
7069 # we don't translate commit messages
7061 # we don't translate commit messages
7070 message = ('Added tag %s for changeset %s' %
7062 message = ('Added tag %s for changeset %s' %
7071 (', '.join(names), short(r)))
7063 (', '.join(names), short(r)))
7072
7064
7073 date = opts.get('date')
7065 date = opts.get('date')
7074 if date:
7066 if date:
7075 date = util.parsedate(date)
7067 date = util.parsedate(date)
7076
7068
7077 if opts.get('remove'):
7069 if opts.get('remove'):
7078 editform = 'tag.remove'
7070 editform = 'tag.remove'
7079 else:
7071 else:
7080 editform = 'tag.add'
7072 editform = 'tag.add'
7081 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7073 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7082
7074
7083 # don't allow tagging the null rev
7075 # don't allow tagging the null rev
7084 if (not opts.get('remove') and
7076 if (not opts.get('remove') and
7085 scmutil.revsingle(repo, rev_).rev() == nullrev):
7077 scmutil.revsingle(repo, rev_).rev() == nullrev):
7086 raise error.Abort(_("cannot tag null revision"))
7078 raise error.Abort(_("cannot tag null revision"))
7087
7079
7088 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7080 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7089 editor=editor)
7081 editor=editor)
7090 finally:
7082 finally:
7091 release(lock, wlock)
7083 release(lock, wlock)
7092
7084
7093 @command('tags', formatteropts, '')
7085 @command('tags', formatteropts, '')
7094 def tags(ui, repo, **opts):
7086 def tags(ui, repo, **opts):
7095 """list repository tags
7087 """list repository tags
7096
7088
7097 This lists both regular and local tags. When the -v/--verbose
7089 This lists both regular and local tags. When the -v/--verbose
7098 switch is used, a third column "local" is printed for local tags.
7090 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.
7091 When the -q/--quiet switch is used, only the tag name is printed.
7100
7092
7101 Returns 0 on success.
7093 Returns 0 on success.
7102 """
7094 """
7103
7095
7104 fm = ui.formatter('tags', opts)
7096 fm = ui.formatter('tags', opts)
7105 hexfunc = fm.hexfunc
7097 hexfunc = fm.hexfunc
7106 tagtype = ""
7098 tagtype = ""
7107
7099
7108 for t, n in reversed(repo.tagslist()):
7100 for t, n in reversed(repo.tagslist()):
7109 hn = hexfunc(n)
7101 hn = hexfunc(n)
7110 label = 'tags.normal'
7102 label = 'tags.normal'
7111 tagtype = ''
7103 tagtype = ''
7112 if repo.tagtype(t) == 'local':
7104 if repo.tagtype(t) == 'local':
7113 label = 'tags.local'
7105 label = 'tags.local'
7114 tagtype = 'local'
7106 tagtype = 'local'
7115
7107
7116 fm.startitem()
7108 fm.startitem()
7117 fm.write('tag', '%s', t, label=label)
7109 fm.write('tag', '%s', t, label=label)
7118 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7110 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7119 fm.condwrite(not ui.quiet, 'rev node', fmt,
7111 fm.condwrite(not ui.quiet, 'rev node', fmt,
7120 repo.changelog.rev(n), hn, label=label)
7112 repo.changelog.rev(n), hn, label=label)
7121 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7113 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7122 tagtype, label=label)
7114 tagtype, label=label)
7123 fm.plain('\n')
7115 fm.plain('\n')
7124 fm.end()
7116 fm.end()
7125
7117
7126 @command('tip',
7118 @command('tip',
7127 [('p', 'patch', None, _('show patch')),
7119 [('p', 'patch', None, _('show patch')),
7128 ('g', 'git', None, _('use git extended diff format')),
7120 ('g', 'git', None, _('use git extended diff format')),
7129 ] + templateopts,
7121 ] + templateopts,
7130 _('[-p] [-g]'))
7122 _('[-p] [-g]'))
7131 def tip(ui, repo, **opts):
7123 def tip(ui, repo, **opts):
7132 """show the tip revision (DEPRECATED)
7124 """show the tip revision (DEPRECATED)
7133
7125
7134 The tip revision (usually just called the tip) is the changeset
7126 The tip revision (usually just called the tip) is the changeset
7135 most recently added to the repository (and therefore the most
7127 most recently added to the repository (and therefore the most
7136 recently changed head).
7128 recently changed head).
7137
7129
7138 If you have just made a commit, that commit will be the tip. If
7130 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
7131 you have just pulled changes from another repository, the tip of
7140 that repository becomes the current tip. The "tip" tag is special
7132 that repository becomes the current tip. The "tip" tag is special
7141 and cannot be renamed or assigned to a different changeset.
7133 and cannot be renamed or assigned to a different changeset.
7142
7134
7143 This command is deprecated, please use :hg:`heads` instead.
7135 This command is deprecated, please use :hg:`heads` instead.
7144
7136
7145 Returns 0 on success.
7137 Returns 0 on success.
7146 """
7138 """
7147 displayer = cmdutil.show_changeset(ui, repo, opts)
7139 displayer = cmdutil.show_changeset(ui, repo, opts)
7148 displayer.show(repo['tip'])
7140 displayer.show(repo['tip'])
7149 displayer.close()
7141 displayer.close()
7150
7142
7151 @command('unbundle',
7143 @command('unbundle',
7152 [('u', 'update', None,
7144 [('u', 'update', None,
7153 _('update to new branch head if changesets were unbundled'))],
7145 _('update to new branch head if changesets were unbundled'))],
7154 _('[-u] FILE...'))
7146 _('[-u] FILE...'))
7155 def unbundle(ui, repo, fname1, *fnames, **opts):
7147 def unbundle(ui, repo, fname1, *fnames, **opts):
7156 """apply one or more changegroup files
7148 """apply one or more changegroup files
7157
7149
7158 Apply one or more compressed changegroup files generated by the
7150 Apply one or more compressed changegroup files generated by the
7159 bundle command.
7151 bundle command.
7160
7152
7161 Returns 0 on success, 1 if an update has unresolved files.
7153 Returns 0 on success, 1 if an update has unresolved files.
7162 """
7154 """
7163 fnames = (fname1,) + fnames
7155 fnames = (fname1,) + fnames
7164
7156
7165 with repo.lock():
7157 with repo.lock():
7166 for fname in fnames:
7158 for fname in fnames:
7167 f = hg.openpath(ui, fname)
7159 f = hg.openpath(ui, fname)
7168 gen = exchange.readbundle(ui, f, fname)
7160 gen = exchange.readbundle(ui, f, fname)
7169 if isinstance(gen, bundle2.unbundle20):
7161 if isinstance(gen, bundle2.unbundle20):
7170 tr = repo.transaction('unbundle')
7162 tr = repo.transaction('unbundle')
7171 try:
7163 try:
7172 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7164 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7173 url='bundle:' + fname)
7165 url='bundle:' + fname)
7174 tr.close()
7166 tr.close()
7175 except error.BundleUnknownFeatureError as exc:
7167 except error.BundleUnknownFeatureError as exc:
7176 raise error.Abort(_('%s: unknown bundle feature, %s')
7168 raise error.Abort(_('%s: unknown bundle feature, %s')
7177 % (fname, exc),
7169 % (fname, exc),
7178 hint=_("see https://mercurial-scm.org/"
7170 hint=_("see https://mercurial-scm.org/"
7179 "wiki/BundleFeature for more "
7171 "wiki/BundleFeature for more "
7180 "information"))
7172 "information"))
7181 finally:
7173 finally:
7182 if tr:
7174 if tr:
7183 tr.release()
7175 tr.release()
7184 changes = [r.get('return', 0)
7176 changes = [r.get('return', 0)
7185 for r in op.records['changegroup']]
7177 for r in op.records['changegroup']]
7186 modheads = changegroup.combineresults(changes)
7178 modheads = changegroup.combineresults(changes)
7187 elif isinstance(gen, streamclone.streamcloneapplier):
7179 elif isinstance(gen, streamclone.streamcloneapplier):
7188 raise error.Abort(
7180 raise error.Abort(
7189 _('packed bundles cannot be applied with '
7181 _('packed bundles cannot be applied with '
7190 '"hg unbundle"'),
7182 '"hg unbundle"'),
7191 hint=_('use "hg debugapplystreamclonebundle"'))
7183 hint=_('use "hg debugapplystreamclonebundle"'))
7192 else:
7184 else:
7193 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7185 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7194
7186
7195 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7187 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7196
7188
7197 @command('^update|up|checkout|co',
7189 @command('^update|up|checkout|co',
7198 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7190 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7199 ('c', 'check', None, _('require clean working directory')),
7191 ('c', 'check', None, _('require clean working directory')),
7200 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7192 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7201 ('r', 'rev', '', _('revision'), _('REV'))
7193 ('r', 'rev', '', _('revision'), _('REV'))
7202 ] + mergetoolopts,
7194 ] + mergetoolopts,
7203 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7195 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7204 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7196 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7205 tool=None):
7197 tool=None):
7206 """update working directory (or switch revisions)
7198 """update working directory (or switch revisions)
7207
7199
7208 Update the repository's working directory to the specified
7200 Update the repository's working directory to the specified
7209 changeset. If no changeset is specified, update to the tip of the
7201 changeset. If no changeset is specified, update to the tip of the
7210 current named branch and move the active bookmark (see :hg:`help
7202 current named branch and move the active bookmark (see :hg:`help
7211 bookmarks`).
7203 bookmarks`).
7212
7204
7213 Update sets the working directory's parent revision to the specified
7205 Update sets the working directory's parent revision to the specified
7214 changeset (see :hg:`help parents`).
7206 changeset (see :hg:`help parents`).
7215
7207
7216 If the changeset is not a descendant or ancestor of the working
7208 If the changeset is not a descendant or ancestor of the working
7217 directory's parent, the update is aborted. With the -c/--check
7209 directory's parent, the update is aborted. With the -c/--check
7218 option, the working directory is checked for uncommitted changes; if
7210 option, the working directory is checked for uncommitted changes; if
7219 none are found, the working directory is updated to the specified
7211 none are found, the working directory is updated to the specified
7220 changeset.
7212 changeset.
7221
7213
7222 .. container:: verbose
7214 .. container:: verbose
7223
7215
7224 The following rules apply when the working directory contains
7216 The following rules apply when the working directory contains
7225 uncommitted changes:
7217 uncommitted changes:
7226
7218
7227 1. If neither -c/--check nor -C/--clean is specified, and if
7219 1. If neither -c/--check nor -C/--clean is specified, and if
7228 the requested changeset is an ancestor or descendant of
7220 the requested changeset is an ancestor or descendant of
7229 the working directory's parent, the uncommitted changes
7221 the working directory's parent, the uncommitted changes
7230 are merged into the requested changeset and the merged
7222 are merged into the requested changeset and the merged
7231 result is left uncommitted. If the requested changeset is
7223 result is left uncommitted. If the requested changeset is
7232 not an ancestor or descendant (that is, it is on another
7224 not an ancestor or descendant (that is, it is on another
7233 branch), the update is aborted and the uncommitted changes
7225 branch), the update is aborted and the uncommitted changes
7234 are preserved.
7226 are preserved.
7235
7227
7236 2. With the -c/--check option, the update is aborted and the
7228 2. With the -c/--check option, the update is aborted and the
7237 uncommitted changes are preserved.
7229 uncommitted changes are preserved.
7238
7230
7239 3. With the -C/--clean option, uncommitted changes are discarded and
7231 3. With the -C/--clean option, uncommitted changes are discarded and
7240 the working directory is updated to the requested changeset.
7232 the working directory is updated to the requested changeset.
7241
7233
7242 To cancel an uncommitted merge (and lose your changes), use
7234 To cancel an uncommitted merge (and lose your changes), use
7243 :hg:`update --clean .`.
7235 :hg:`update --clean .`.
7244
7236
7245 Use null as the changeset to remove the working directory (like
7237 Use null as the changeset to remove the working directory (like
7246 :hg:`clone -U`).
7238 :hg:`clone -U`).
7247
7239
7248 If you want to revert just one file to an older revision, use
7240 If you want to revert just one file to an older revision, use
7249 :hg:`revert [-r REV] NAME`.
7241 :hg:`revert [-r REV] NAME`.
7250
7242
7251 See :hg:`help dates` for a list of formats valid for -d/--date.
7243 See :hg:`help dates` for a list of formats valid for -d/--date.
7252
7244
7253 Returns 0 on success, 1 if there are unresolved files.
7245 Returns 0 on success, 1 if there are unresolved files.
7254 """
7246 """
7255 if rev and node:
7247 if rev and node:
7256 raise error.Abort(_("please specify just one revision"))
7248 raise error.Abort(_("please specify just one revision"))
7257
7249
7258 if rev is None or rev == '':
7250 if rev is None or rev == '':
7259 rev = node
7251 rev = node
7260
7252
7261 if date and rev is not None:
7253 if date and rev is not None:
7262 raise error.Abort(_("you can't specify a revision and a date"))
7254 raise error.Abort(_("you can't specify a revision and a date"))
7263
7255
7264 if check and clean:
7256 if check and clean:
7265 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7257 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7266
7258
7267 with repo.wlock():
7259 with repo.wlock():
7268 cmdutil.clearunfinished(repo)
7260 cmdutil.clearunfinished(repo)
7269
7261
7270 if date:
7262 if date:
7271 rev = cmdutil.finddate(ui, repo, date)
7263 rev = cmdutil.finddate(ui, repo, date)
7272
7264
7273 # if we defined a bookmark, we have to remember the original name
7265 # if we defined a bookmark, we have to remember the original name
7274 brev = rev
7266 brev = rev
7275 rev = scmutil.revsingle(repo, rev, rev).rev()
7267 rev = scmutil.revsingle(repo, rev, rev).rev()
7276
7268
7277 if check:
7269 if check:
7278 cmdutil.bailifchanged(repo, merge=False)
7270 cmdutil.bailifchanged(repo, merge=False)
7279
7271
7280 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7272 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7281
7273
7282 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7274 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7283
7275
7284 @command('verify', [])
7276 @command('verify', [])
7285 def verify(ui, repo):
7277 def verify(ui, repo):
7286 """verify the integrity of the repository
7278 """verify the integrity of the repository
7287
7279
7288 Verify the integrity of the current repository.
7280 Verify the integrity of the current repository.
7289
7281
7290 This will perform an extensive check of the repository's
7282 This will perform an extensive check of the repository's
7291 integrity, validating the hashes and checksums of each entry in
7283 integrity, validating the hashes and checksums of each entry in
7292 the changelog, manifest, and tracked files, as well as the
7284 the changelog, manifest, and tracked files, as well as the
7293 integrity of their crosslinks and indices.
7285 integrity of their crosslinks and indices.
7294
7286
7295 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7287 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7296 for more information about recovery from corruption of the
7288 for more information about recovery from corruption of the
7297 repository.
7289 repository.
7298
7290
7299 Returns 0 on success, 1 if errors are encountered.
7291 Returns 0 on success, 1 if errors are encountered.
7300 """
7292 """
7301 return hg.verify(repo)
7293 return hg.verify(repo)
7302
7294
7303 @command('version', [] + formatteropts, norepo=True)
7295 @command('version', [] + formatteropts, norepo=True)
7304 def version_(ui, **opts):
7296 def version_(ui, **opts):
7305 """output version and copyright information"""
7297 """output version and copyright information"""
7306 fm = ui.formatter("version", opts)
7298 fm = ui.formatter("version", opts)
7307 fm.startitem()
7299 fm.startitem()
7308 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7300 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7309 util.version())
7301 util.version())
7310 license = _(
7302 license = _(
7311 "(see https://mercurial-scm.org for more information)\n"
7303 "(see https://mercurial-scm.org for more information)\n"
7312 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7304 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7313 "This is free software; see the source for copying conditions. "
7305 "This is free software; see the source for copying conditions. "
7314 "There is NO\nwarranty; "
7306 "There is NO\nwarranty; "
7315 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7307 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7316 )
7308 )
7317 if not ui.quiet:
7309 if not ui.quiet:
7318 fm.plain(license)
7310 fm.plain(license)
7319
7311
7320 if ui.verbose:
7312 if ui.verbose:
7321 fm.plain(_("\nEnabled extensions:\n\n"))
7313 fm.plain(_("\nEnabled extensions:\n\n"))
7322 # format names and versions into columns
7314 # format names and versions into columns
7323 names = []
7315 names = []
7324 vers = []
7316 vers = []
7325 isinternals = []
7317 isinternals = []
7326 for name, module in extensions.extensions():
7318 for name, module in extensions.extensions():
7327 names.append(name)
7319 names.append(name)
7328 vers.append(extensions.moduleversion(module) or None)
7320 vers.append(extensions.moduleversion(module) or None)
7329 isinternals.append(extensions.ismoduleinternal(module))
7321 isinternals.append(extensions.ismoduleinternal(module))
7330 fn = fm.nested("extensions")
7322 fn = fm.nested("extensions")
7331 if names:
7323 if names:
7332 namefmt = " %%-%ds " % max(len(n) for n in names)
7324 namefmt = " %%-%ds " % max(len(n) for n in names)
7333 places = [_("external"), _("internal")]
7325 places = [_("external"), _("internal")]
7334 for n, v, p in zip(names, vers, isinternals):
7326 for n, v, p in zip(names, vers, isinternals):
7335 fn.startitem()
7327 fn.startitem()
7336 fn.condwrite(ui.verbose, "name", namefmt, n)
7328 fn.condwrite(ui.verbose, "name", namefmt, n)
7337 if ui.verbose:
7329 if ui.verbose:
7338 fn.plain("%s " % places[p])
7330 fn.plain("%s " % places[p])
7339 fn.data(bundled=p)
7331 fn.data(bundled=p)
7340 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7332 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7341 if ui.verbose:
7333 if ui.verbose:
7342 fn.plain("\n")
7334 fn.plain("\n")
7343 fn.end()
7335 fn.end()
7344 fm.end()
7336 fm.end()
7345
7337
7346 def loadcmdtable(ui, name, cmdtable):
7338 def loadcmdtable(ui, name, cmdtable):
7347 """Load command functions from specified cmdtable
7339 """Load command functions from specified cmdtable
7348 """
7340 """
7349 overrides = [cmd for cmd in cmdtable if cmd in table]
7341 overrides = [cmd for cmd in cmdtable if cmd in table]
7350 if overrides:
7342 if overrides:
7351 ui.warn(_("extension '%s' overrides commands: %s\n")
7343 ui.warn(_("extension '%s' overrides commands: %s\n")
7352 % (name, " ".join(overrides)))
7344 % (name, " ".join(overrides)))
7353 table.update(cmdtable)
7345 table.update(cmdtable)
@@ -1,307 +1,318 b''
1 # changelog bisection for mercurial
1 # changelog bisection for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall
3 # Copyright 2007 Matt Mackall
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
4 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
5 #
5 #
6 # Inspired by git bisect, extension skeleton taken from mq.py.
6 # Inspired by git bisect, extension skeleton taken from mq.py.
7 #
7 #
8 # This software may be used and distributed according to the terms of the
8 # This software may be used and distributed according to the terms of the
9 # GNU General Public License version 2 or any later version.
9 # GNU General Public License version 2 or any later version.
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12
12
13 import collections
13 import collections
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 short,
18 short,
19 )
19 )
20 from . import (
20 from . import (
21 error,
21 error,
22 )
22 )
23
23
24 def bisect(changelog, state):
24 def bisect(changelog, state):
25 """find the next node (if any) for testing during a bisect search.
25 """find the next node (if any) for testing during a bisect search.
26 returns a (nodes, number, good) tuple.
26 returns a (nodes, number, good) tuple.
27
27
28 'nodes' is the final result of the bisect if 'number' is 0.
28 'nodes' is the final result of the bisect if 'number' is 0.
29 Otherwise 'number' indicates the remaining possible candidates for
29 Otherwise 'number' indicates the remaining possible candidates for
30 the search and 'nodes' contains the next bisect target.
30 the search and 'nodes' contains the next bisect target.
31 'good' is True if bisect is searching for a first good changeset, False
31 'good' is True if bisect is searching for a first good changeset, False
32 if searching for a first bad one.
32 if searching for a first bad one.
33 """
33 """
34
34
35 clparents = changelog.parentrevs
35 clparents = changelog.parentrevs
36 skip = set([changelog.rev(n) for n in state['skip']])
36 skip = set([changelog.rev(n) for n in state['skip']])
37
37
38 def buildancestors(bad, good):
38 def buildancestors(bad, good):
39 # only the earliest bad revision matters
39 # only the earliest bad revision matters
40 badrev = min([changelog.rev(n) for n in bad])
40 badrev = min([changelog.rev(n) for n in bad])
41 goodrevs = [changelog.rev(n) for n in good]
41 goodrevs = [changelog.rev(n) for n in good]
42 goodrev = min(goodrevs)
42 goodrev = min(goodrevs)
43 # build visit array
43 # build visit array
44 ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
44 ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
45
45
46 # set nodes descended from goodrevs
46 # set nodes descended from goodrevs
47 for rev in goodrevs:
47 for rev in goodrevs:
48 ancestors[rev] = []
48 ancestors[rev] = []
49 for rev in changelog.revs(goodrev + 1):
49 for rev in changelog.revs(goodrev + 1):
50 for prev in clparents(rev):
50 for prev in clparents(rev):
51 if ancestors[prev] == []:
51 if ancestors[prev] == []:
52 ancestors[rev] = []
52 ancestors[rev] = []
53
53
54 # clear good revs from array
54 # clear good revs from array
55 for rev in goodrevs:
55 for rev in goodrevs:
56 ancestors[rev] = None
56 ancestors[rev] = None
57 for rev in changelog.revs(len(changelog), goodrev):
57 for rev in changelog.revs(len(changelog), goodrev):
58 if ancestors[rev] is None:
58 if ancestors[rev] is None:
59 for prev in clparents(rev):
59 for prev in clparents(rev):
60 ancestors[prev] = None
60 ancestors[prev] = None
61
61
62 if ancestors[badrev] is None:
62 if ancestors[badrev] is None:
63 return badrev, None
63 return badrev, None
64 return badrev, ancestors
64 return badrev, ancestors
65
65
66 good = False
66 good = False
67 badrev, ancestors = buildancestors(state['bad'], state['good'])
67 badrev, ancestors = buildancestors(state['bad'], state['good'])
68 if not ancestors: # looking for bad to good transition?
68 if not ancestors: # looking for bad to good transition?
69 good = True
69 good = True
70 badrev, ancestors = buildancestors(state['good'], state['bad'])
70 badrev, ancestors = buildancestors(state['good'], state['bad'])
71 bad = changelog.node(badrev)
71 bad = changelog.node(badrev)
72 if not ancestors: # now we're confused
72 if not ancestors: # now we're confused
73 if (len(state['bad']) == 1 and len(state['good']) == 1 and
73 if (len(state['bad']) == 1 and len(state['good']) == 1 and
74 state['bad'] != state['good']):
74 state['bad'] != state['good']):
75 raise error.Abort(_("starting revisions are not directly related"))
75 raise error.Abort(_("starting revisions are not directly related"))
76 raise error.Abort(_("inconsistent state, %s:%s is good and bad")
76 raise error.Abort(_("inconsistent state, %s:%s is good and bad")
77 % (badrev, short(bad)))
77 % (badrev, short(bad)))
78
78
79 # build children dict
79 # build children dict
80 children = {}
80 children = {}
81 visit = collections.deque([badrev])
81 visit = collections.deque([badrev])
82 candidates = []
82 candidates = []
83 while visit:
83 while visit:
84 rev = visit.popleft()
84 rev = visit.popleft()
85 if ancestors[rev] == []:
85 if ancestors[rev] == []:
86 candidates.append(rev)
86 candidates.append(rev)
87 for prev in clparents(rev):
87 for prev in clparents(rev):
88 if prev != -1:
88 if prev != -1:
89 if prev in children:
89 if prev in children:
90 children[prev].append(rev)
90 children[prev].append(rev)
91 else:
91 else:
92 children[prev] = [rev]
92 children[prev] = [rev]
93 visit.append(prev)
93 visit.append(prev)
94
94
95 candidates.sort()
95 candidates.sort()
96 # have we narrowed it down to one entry?
96 # have we narrowed it down to one entry?
97 # or have all other possible candidates besides 'bad' have been skipped?
97 # or have all other possible candidates besides 'bad' have been skipped?
98 tot = len(candidates)
98 tot = len(candidates)
99 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
99 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
100 if tot == 1 or not unskipped:
100 if tot == 1 or not unskipped:
101 return ([changelog.node(rev) for rev in candidates], 0, good)
101 return ([changelog.node(rev) for rev in candidates], 0, good)
102 perfect = tot // 2
102 perfect = tot // 2
103
103
104 # find the best node to test
104 # find the best node to test
105 best_rev = None
105 best_rev = None
106 best_len = -1
106 best_len = -1
107 poison = set()
107 poison = set()
108 for rev in candidates:
108 for rev in candidates:
109 if rev in poison:
109 if rev in poison:
110 # poison children
110 # poison children
111 poison.update(children.get(rev, []))
111 poison.update(children.get(rev, []))
112 continue
112 continue
113
113
114 a = ancestors[rev] or [rev]
114 a = ancestors[rev] or [rev]
115 ancestors[rev] = None
115 ancestors[rev] = None
116
116
117 x = len(a) # number of ancestors
117 x = len(a) # number of ancestors
118 y = tot - x # number of non-ancestors
118 y = tot - x # number of non-ancestors
119 value = min(x, y) # how good is this test?
119 value = min(x, y) # how good is this test?
120 if value > best_len and rev not in skip:
120 if value > best_len and rev not in skip:
121 best_len = value
121 best_len = value
122 best_rev = rev
122 best_rev = rev
123 if value == perfect: # found a perfect candidate? quit early
123 if value == perfect: # found a perfect candidate? quit early
124 break
124 break
125
125
126 if y < perfect and rev not in skip: # all downhill from here?
126 if y < perfect and rev not in skip: # all downhill from here?
127 # poison children
127 # poison children
128 poison.update(children.get(rev, []))
128 poison.update(children.get(rev, []))
129 continue
129 continue
130
130
131 for c in children.get(rev, []):
131 for c in children.get(rev, []):
132 if ancestors[c]:
132 if ancestors[c]:
133 ancestors[c] = list(set(ancestors[c] + a))
133 ancestors[c] = list(set(ancestors[c] + a))
134 else:
134 else:
135 ancestors[c] = a + [c]
135 ancestors[c] = a + [c]
136
136
137 assert best_rev is not None
137 assert best_rev is not None
138 best_node = changelog.node(best_rev)
138 best_node = changelog.node(best_rev)
139
139
140 return ([best_node], tot, good)
140 return ([best_node], tot, good)
141
141
142 def extendrange(repo, state, nodes, good):
142 def extendrange(repo, state, nodes, good):
143 # bisect is incomplete when it ends on a merge node and
143 # bisect is incomplete when it ends on a merge node and
144 # one of the parent was not checked.
144 # one of the parent was not checked.
145 parents = repo[nodes[0]].parents()
145 parents = repo[nodes[0]].parents()
146 if len(parents) > 1:
146 if len(parents) > 1:
147 if good:
147 if good:
148 side = state['bad']
148 side = state['bad']
149 else:
149 else:
150 side = state['good']
150 side = state['good']
151 num = len(set(i.node() for i in parents) & set(side))
151 num = len(set(i.node() for i in parents) & set(side))
152 if num == 1:
152 if num == 1:
153 return parents[0].ancestor(parents[1])
153 return parents[0].ancestor(parents[1])
154 return None
154 return None
155
155
156 def load_state(repo):
156 def load_state(repo):
157 state = {'current': [], 'good': [], 'bad': [], 'skip': []}
157 state = {'current': [], 'good': [], 'bad': [], 'skip': []}
158 for l in repo.vfs.tryreadlines("bisect.state"):
158 for l in repo.vfs.tryreadlines("bisect.state"):
159 kind, node = l[:-1].split()
159 kind, node = l[:-1].split()
160 node = repo.lookup(node)
160 node = repo.lookup(node)
161 if kind not in state:
161 if kind not in state:
162 raise error.Abort(_("unknown bisect kind %s") % kind)
162 raise error.Abort(_("unknown bisect kind %s") % kind)
163 state[kind].append(node)
163 state[kind].append(node)
164 return state
164 return state
165
165
166
166
167 def save_state(repo, state):
167 def save_state(repo, state):
168 f = repo.vfs("bisect.state", "w", atomictemp=True)
168 f = repo.vfs("bisect.state", "w", atomictemp=True)
169 with repo.wlock():
169 with repo.wlock():
170 for kind in sorted(state):
170 for kind in sorted(state):
171 for node in state[kind]:
171 for node in state[kind]:
172 f.write("%s %s\n" % (kind, hex(node)))
172 f.write("%s %s\n" % (kind, hex(node)))
173 f.close()
173 f.close()
174
174
175 def resetstate(repo):
175 def resetstate(repo):
176 """remove any bisect state from the repository"""
176 """remove any bisect state from the repository"""
177 if repo.vfs.exists("bisect.state"):
177 if repo.vfs.exists("bisect.state"):
178 repo.vfs.unlink("bisect.state")
178 repo.vfs.unlink("bisect.state")
179
179
180 def checkstate(state):
181 """check we have both 'good' and 'bad' to define a range
182
183 Raise Abort exception otherwise."""
184 if state['good'] and state['bad']:
185 return True
186 if not state['good']:
187 raise error.Abort(_('cannot bisect (no known good revisions)'))
188 else:
189 raise error.Abort(_('cannot bisect (no known bad revisions)'))
190
180 def get(repo, status):
191 def get(repo, status):
181 """
192 """
182 Return a list of revision(s) that match the given status:
193 Return a list of revision(s) that match the given status:
183
194
184 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
195 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
185 - ``goods``, ``bads`` : csets topologically good/bad
196 - ``goods``, ``bads`` : csets topologically good/bad
186 - ``range`` : csets taking part in the bisection
197 - ``range`` : csets taking part in the bisection
187 - ``pruned`` : csets that are goods, bads or skipped
198 - ``pruned`` : csets that are goods, bads or skipped
188 - ``untested`` : csets whose fate is yet unknown
199 - ``untested`` : csets whose fate is yet unknown
189 - ``ignored`` : csets ignored due to DAG topology
200 - ``ignored`` : csets ignored due to DAG topology
190 - ``current`` : the cset currently being bisected
201 - ``current`` : the cset currently being bisected
191 """
202 """
192 state = load_state(repo)
203 state = load_state(repo)
193 if status in ('good', 'bad', 'skip', 'current'):
204 if status in ('good', 'bad', 'skip', 'current'):
194 return map(repo.changelog.rev, state[status])
205 return map(repo.changelog.rev, state[status])
195 else:
206 else:
196 # In the following sets, we do *not* call 'bisect()' with more
207 # In the following sets, we do *not* call 'bisect()' with more
197 # than one level of recursion, because that can be very, very
208 # than one level of recursion, because that can be very, very
198 # time consuming. Instead, we always develop the expression as
209 # time consuming. Instead, we always develop the expression as
199 # much as possible.
210 # much as possible.
200
211
201 # 'range' is all csets that make the bisection:
212 # 'range' is all csets that make the bisection:
202 # - have a good ancestor and a bad descendant, or conversely
213 # - have a good ancestor and a bad descendant, or conversely
203 # that's because the bisection can go either way
214 # that's because the bisection can go either way
204 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
215 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
205
216
206 _t = repo.revs('bisect(good)::bisect(bad)')
217 _t = repo.revs('bisect(good)::bisect(bad)')
207 # The sets of topologically good or bad csets
218 # The sets of topologically good or bad csets
208 if len(_t) == 0:
219 if len(_t) == 0:
209 # Goods are topologically after bads
220 # Goods are topologically after bads
210 goods = 'bisect(good)::' # Pruned good csets
221 goods = 'bisect(good)::' # Pruned good csets
211 bads = '::bisect(bad)' # Pruned bad csets
222 bads = '::bisect(bad)' # Pruned bad csets
212 else:
223 else:
213 # Goods are topologically before bads
224 # Goods are topologically before bads
214 goods = '::bisect(good)' # Pruned good csets
225 goods = '::bisect(good)' # Pruned good csets
215 bads = 'bisect(bad)::' # Pruned bad csets
226 bads = 'bisect(bad)::' # Pruned bad csets
216
227
217 # 'pruned' is all csets whose fate is already known: good, bad, skip
228 # 'pruned' is all csets whose fate is already known: good, bad, skip
218 skips = 'bisect(skip)' # Pruned skipped csets
229 skips = 'bisect(skip)' # Pruned skipped csets
219 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips)
230 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips)
220
231
221 # 'untested' is all cset that are- in 'range', but not in 'pruned'
232 # 'untested' is all cset that are- in 'range', but not in 'pruned'
222 untested = '( (%s) - (%s) )' % (range, pruned)
233 untested = '( (%s) - (%s) )' % (range, pruned)
223
234
224 # 'ignored' is all csets that were not used during the bisection
235 # 'ignored' is all csets that were not used during the bisection
225 # due to DAG topology, but may however have had an impact.
236 # due to DAG topology, but may however have had an impact.
226 # E.g., a branch merged between bads and goods, but whose branch-
237 # E.g., a branch merged between bads and goods, but whose branch-
227 # point is out-side of the range.
238 # point is out-side of the range.
228 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors
239 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors
229 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors
240 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors
230 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range)
241 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range)
231
242
232 if status == 'range':
243 if status == 'range':
233 return repo.revs(range)
244 return repo.revs(range)
234 elif status == 'pruned':
245 elif status == 'pruned':
235 return repo.revs(pruned)
246 return repo.revs(pruned)
236 elif status == 'untested':
247 elif status == 'untested':
237 return repo.revs(untested)
248 return repo.revs(untested)
238 elif status == 'ignored':
249 elif status == 'ignored':
239 return repo.revs(ignored)
250 return repo.revs(ignored)
240 elif status == "goods":
251 elif status == "goods":
241 return repo.revs(goods)
252 return repo.revs(goods)
242 elif status == "bads":
253 elif status == "bads":
243 return repo.revs(bads)
254 return repo.revs(bads)
244 else:
255 else:
245 raise error.ParseError(_('invalid bisect state'))
256 raise error.ParseError(_('invalid bisect state'))
246
257
247 def label(repo, node):
258 def label(repo, node):
248 rev = repo.changelog.rev(node)
259 rev = repo.changelog.rev(node)
249
260
250 # Try explicit sets
261 # Try explicit sets
251 if rev in get(repo, 'good'):
262 if rev in get(repo, 'good'):
252 # i18n: bisect changeset status
263 # i18n: bisect changeset status
253 return _('good')
264 return _('good')
254 if rev in get(repo, 'bad'):
265 if rev in get(repo, 'bad'):
255 # i18n: bisect changeset status
266 # i18n: bisect changeset status
256 return _('bad')
267 return _('bad')
257 if rev in get(repo, 'skip'):
268 if rev in get(repo, 'skip'):
258 # i18n: bisect changeset status
269 # i18n: bisect changeset status
259 return _('skipped')
270 return _('skipped')
260 if rev in get(repo, 'untested') or rev in get(repo, 'current'):
271 if rev in get(repo, 'untested') or rev in get(repo, 'current'):
261 # i18n: bisect changeset status
272 # i18n: bisect changeset status
262 return _('untested')
273 return _('untested')
263 if rev in get(repo, 'ignored'):
274 if rev in get(repo, 'ignored'):
264 # i18n: bisect changeset status
275 # i18n: bisect changeset status
265 return _('ignored')
276 return _('ignored')
266
277
267 # Try implicit sets
278 # Try implicit sets
268 if rev in get(repo, 'goods'):
279 if rev in get(repo, 'goods'):
269 # i18n: bisect changeset status
280 # i18n: bisect changeset status
270 return _('good (implicit)')
281 return _('good (implicit)')
271 if rev in get(repo, 'bads'):
282 if rev in get(repo, 'bads'):
272 # i18n: bisect changeset status
283 # i18n: bisect changeset status
273 return _('bad (implicit)')
284 return _('bad (implicit)')
274
285
275 return None
286 return None
276
287
277 def shortlabel(label):
288 def shortlabel(label):
278 if label:
289 if label:
279 return label[0].upper()
290 return label[0].upper()
280
291
281 return None
292 return None
282
293
283 def printresult(ui, repo, state, displayer, nodes, good):
294 def printresult(ui, repo, state, displayer, nodes, good):
284 if len(nodes) == 1:
295 if len(nodes) == 1:
285 # narrowed it down to a single revision
296 # narrowed it down to a single revision
286 if good:
297 if good:
287 ui.write(_("The first good revision is:\n"))
298 ui.write(_("The first good revision is:\n"))
288 else:
299 else:
289 ui.write(_("The first bad revision is:\n"))
300 ui.write(_("The first bad revision is:\n"))
290 displayer.show(repo[nodes[0]])
301 displayer.show(repo[nodes[0]])
291 extendnode = extendrange(repo, state, nodes, good)
302 extendnode = extendrange(repo, state, nodes, good)
292 if extendnode is not None:
303 if extendnode is not None:
293 ui.write(_('Not all ancestors of this changeset have been'
304 ui.write(_('Not all ancestors of this changeset have been'
294 ' checked.\nUse bisect --extend to continue the '
305 ' checked.\nUse bisect --extend to continue the '
295 'bisection from\nthe common ancestor, %s.\n')
306 'bisection from\nthe common ancestor, %s.\n')
296 % extendnode)
307 % extendnode)
297 else:
308 else:
298 # multiple possible revisions
309 # multiple possible revisions
299 if good:
310 if good:
300 ui.write(_("Due to skipped revisions, the first "
311 ui.write(_("Due to skipped revisions, the first "
301 "good revision could be any of:\n"))
312 "good revision could be any of:\n"))
302 else:
313 else:
303 ui.write(_("Due to skipped revisions, the first "
314 ui.write(_("Due to skipped revisions, the first "
304 "bad revision could be any of:\n"))
315 "bad revision could be any of:\n"))
305 for n in nodes:
316 for n in nodes:
306 displayer.show(repo[n])
317 displayer.show(repo[n])
307 displayer.close()
318 displayer.close()
General Comments 0
You need to be logged in to leave comments. Login now