##// END OF EJS Templates
commands: use `iter(callable, sentinel)` instead of while True...
Augie Fackler -
r29725:cbeb2cb5 default
parent child Browse files
Show More
@@ -1,7284 +1,7275 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:
444 if fm:
445 def makefunc(get, fmt):
445 def makefunc(get, fmt):
446 return get
446 return get
447 else:
447 else:
448 def makefunc(get, fmt):
448 def makefunc(get, fmt):
449 return lambda x: fmt(get(x))
449 return lambda x: fmt(get(x))
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:
479 if fm:
480 formats.append(['%s' for x in l])
480 formats.append(['%s' for x in l])
481 else:
481 else:
482 sizes = [encoding.colwidth(x) for x in l]
482 sizes = [encoding.colwidth(x) for x in l]
483 ml = max(sizes)
483 ml = max(sizes)
484 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
484 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
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 extendbisectrange(nodes, good):
838 def extendbisectrange(nodes, good):
839 # bisect is incomplete when it ends on a merge node and
839 # bisect is incomplete when it ends on a merge node and
840 # one of the parent was not checked.
840 # one of the parent was not checked.
841 parents = repo[nodes[0]].parents()
841 parents = repo[nodes[0]].parents()
842 if len(parents) > 1:
842 if len(parents) > 1:
843 if good:
843 if good:
844 side = state['bad']
844 side = state['bad']
845 else:
845 else:
846 side = state['good']
846 side = state['good']
847 num = len(set(i.node() for i in parents) & set(side))
847 num = len(set(i.node() for i in parents) & set(side))
848 if num == 1:
848 if num == 1:
849 return parents[0].ancestor(parents[1])
849 return parents[0].ancestor(parents[1])
850 return None
850 return None
851
851
852 def print_result(nodes, good):
852 def print_result(nodes, good):
853 displayer = cmdutil.show_changeset(ui, repo, {})
853 displayer = cmdutil.show_changeset(ui, repo, {})
854 if len(nodes) == 1:
854 if len(nodes) == 1:
855 # narrowed it down to a single revision
855 # narrowed it down to a single revision
856 if good:
856 if good:
857 ui.write(_("The first good revision is:\n"))
857 ui.write(_("The first good revision is:\n"))
858 else:
858 else:
859 ui.write(_("The first bad revision is:\n"))
859 ui.write(_("The first bad revision is:\n"))
860 displayer.show(repo[nodes[0]])
860 displayer.show(repo[nodes[0]])
861 extendnode = extendbisectrange(nodes, good)
861 extendnode = extendbisectrange(nodes, good)
862 if extendnode is not None:
862 if extendnode is not None:
863 ui.write(_('Not all ancestors of this changeset have been'
863 ui.write(_('Not all ancestors of this changeset have been'
864 ' checked.\nUse bisect --extend to continue the '
864 ' checked.\nUse bisect --extend to continue the '
865 'bisection from\nthe common ancestor, %s.\n')
865 'bisection from\nthe common ancestor, %s.\n')
866 % extendnode)
866 % extendnode)
867 else:
867 else:
868 # multiple possible revisions
868 # multiple possible revisions
869 if good:
869 if good:
870 ui.write(_("Due to skipped revisions, the first "
870 ui.write(_("Due to skipped revisions, the first "
871 "good revision could be any of:\n"))
871 "good revision could be any of:\n"))
872 else:
872 else:
873 ui.write(_("Due to skipped revisions, the first "
873 ui.write(_("Due to skipped revisions, the first "
874 "bad revision could be any of:\n"))
874 "bad revision could be any of:\n"))
875 for n in nodes:
875 for n in nodes:
876 displayer.show(repo[n])
876 displayer.show(repo[n])
877 displayer.close()
877 displayer.close()
878
878
879 def check_state(state, interactive=True):
879 def check_state(state, interactive=True):
880 if not state['good'] or not state['bad']:
880 if not state['good'] or not state['bad']:
881 if (good or bad or skip or reset) and interactive:
881 if (good or bad or skip or reset) and interactive:
882 return
882 return
883 if not state['good']:
883 if not state['good']:
884 raise error.Abort(_('cannot bisect (no known good revisions)'))
884 raise error.Abort(_('cannot bisect (no known good revisions)'))
885 else:
885 else:
886 raise error.Abort(_('cannot bisect (no known bad revisions)'))
886 raise error.Abort(_('cannot bisect (no known bad revisions)'))
887 return True
887 return True
888
888
889 # backward compatibility
889 # backward compatibility
890 if rev in "good bad reset init".split():
890 if rev in "good bad reset init".split():
891 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
891 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
892 cmd, rev, extra = rev, extra, None
892 cmd, rev, extra = rev, extra, None
893 if cmd == "good":
893 if cmd == "good":
894 good = True
894 good = True
895 elif cmd == "bad":
895 elif cmd == "bad":
896 bad = True
896 bad = True
897 else:
897 else:
898 reset = True
898 reset = True
899 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
899 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
900 raise error.Abort(_('incompatible arguments'))
900 raise error.Abort(_('incompatible arguments'))
901
901
902 cmdutil.checkunfinished(repo)
902 cmdutil.checkunfinished(repo)
903
903
904 if reset:
904 if reset:
905 p = repo.join("bisect.state")
905 p = repo.join("bisect.state")
906 if os.path.exists(p):
906 if os.path.exists(p):
907 os.unlink(p)
907 os.unlink(p)
908 return
908 return
909
909
910 state = hbisect.load_state(repo)
910 state = hbisect.load_state(repo)
911
911
912 if command:
912 if command:
913 changesets = 1
913 changesets = 1
914 if noupdate:
914 if noupdate:
915 try:
915 try:
916 node = state['current'][0]
916 node = state['current'][0]
917 except LookupError:
917 except LookupError:
918 raise error.Abort(_('current bisect revision is unknown - '
918 raise error.Abort(_('current bisect revision is unknown - '
919 'start a new bisect to fix'))
919 'start a new bisect to fix'))
920 else:
920 else:
921 node, p2 = repo.dirstate.parents()
921 node, p2 = repo.dirstate.parents()
922 if p2 != nullid:
922 if p2 != nullid:
923 raise error.Abort(_('current bisect revision is a merge'))
923 raise error.Abort(_('current bisect revision is a merge'))
924 try:
924 try:
925 while changesets:
925 while changesets:
926 # update state
926 # update state
927 state['current'] = [node]
927 state['current'] = [node]
928 hbisect.save_state(repo, state)
928 hbisect.save_state(repo, state)
929 status = ui.system(command, environ={'HG_NODE': hex(node)})
929 status = ui.system(command, environ={'HG_NODE': hex(node)})
930 if status == 125:
930 if status == 125:
931 transition = "skip"
931 transition = "skip"
932 elif status == 0:
932 elif status == 0:
933 transition = "good"
933 transition = "good"
934 # status < 0 means process was killed
934 # status < 0 means process was killed
935 elif status == 127:
935 elif status == 127:
936 raise error.Abort(_("failed to execute %s") % command)
936 raise error.Abort(_("failed to execute %s") % command)
937 elif status < 0:
937 elif status < 0:
938 raise error.Abort(_("%s killed") % command)
938 raise error.Abort(_("%s killed") % command)
939 else:
939 else:
940 transition = "bad"
940 transition = "bad"
941 ctx = scmutil.revsingle(repo, rev, node)
941 ctx = scmutil.revsingle(repo, rev, node)
942 rev = None # clear for future iterations
942 rev = None # clear for future iterations
943 state[transition].append(ctx.node())
943 state[transition].append(ctx.node())
944 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
944 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
945 check_state(state, interactive=False)
945 check_state(state, interactive=False)
946 # bisect
946 # bisect
947 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
947 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
948 # update to next check
948 # update to next check
949 node = nodes[0]
949 node = nodes[0]
950 if not noupdate:
950 if not noupdate:
951 cmdutil.bailifchanged(repo)
951 cmdutil.bailifchanged(repo)
952 hg.clean(repo, node, show_stats=False)
952 hg.clean(repo, node, show_stats=False)
953 finally:
953 finally:
954 state['current'] = [node]
954 state['current'] = [node]
955 hbisect.save_state(repo, state)
955 hbisect.save_state(repo, state)
956 print_result(nodes, bgood)
956 print_result(nodes, bgood)
957 return
957 return
958
958
959 # update state
959 # update state
960
960
961 if rev:
961 if rev:
962 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
962 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
963 else:
963 else:
964 nodes = [repo.lookup('.')]
964 nodes = [repo.lookup('.')]
965
965
966 if good or bad or skip:
966 if good or bad or skip:
967 if good:
967 if good:
968 state['good'] += nodes
968 state['good'] += nodes
969 elif bad:
969 elif bad:
970 state['bad'] += nodes
970 state['bad'] += nodes
971 elif skip:
971 elif skip:
972 state['skip'] += nodes
972 state['skip'] += nodes
973 hbisect.save_state(repo, state)
973 hbisect.save_state(repo, state)
974
974
975 if not check_state(state):
975 if not check_state(state):
976 return
976 return
977
977
978 # actually bisect
978 # actually bisect
979 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
979 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
980 if extend:
980 if extend:
981 if not changesets:
981 if not changesets:
982 extendnode = extendbisectrange(nodes, good)
982 extendnode = extendbisectrange(nodes, good)
983 if extendnode is not None:
983 if extendnode is not None:
984 ui.write(_("Extending search to changeset %d:%s\n")
984 ui.write(_("Extending search to changeset %d:%s\n")
985 % (extendnode.rev(), extendnode))
985 % (extendnode.rev(), extendnode))
986 state['current'] = [extendnode.node()]
986 state['current'] = [extendnode.node()]
987 hbisect.save_state(repo, state)
987 hbisect.save_state(repo, state)
988 if noupdate:
988 if noupdate:
989 return
989 return
990 cmdutil.bailifchanged(repo)
990 cmdutil.bailifchanged(repo)
991 return hg.clean(repo, extendnode.node())
991 return hg.clean(repo, extendnode.node())
992 raise error.Abort(_("nothing to extend"))
992 raise error.Abort(_("nothing to extend"))
993
993
994 if changesets == 0:
994 if changesets == 0:
995 print_result(nodes, good)
995 print_result(nodes, good)
996 else:
996 else:
997 assert len(nodes) == 1 # only a single node can be tested next
997 assert len(nodes) == 1 # only a single node can be tested next
998 node = nodes[0]
998 node = nodes[0]
999 # compute the approximate number of remaining tests
999 # compute the approximate number of remaining tests
1000 tests, size = 0, 2
1000 tests, size = 0, 2
1001 while size <= changesets:
1001 while size <= changesets:
1002 tests, size = tests + 1, size * 2
1002 tests, size = tests + 1, size * 2
1003 rev = repo.changelog.rev(node)
1003 rev = repo.changelog.rev(node)
1004 ui.write(_("Testing changeset %d:%s "
1004 ui.write(_("Testing changeset %d:%s "
1005 "(%d changesets remaining, ~%d tests)\n")
1005 "(%d changesets remaining, ~%d tests)\n")
1006 % (rev, short(node), changesets, tests))
1006 % (rev, short(node), changesets, tests))
1007 state['current'] = [node]
1007 state['current'] = [node]
1008 hbisect.save_state(repo, state)
1008 hbisect.save_state(repo, state)
1009 if not noupdate:
1009 if not noupdate:
1010 cmdutil.bailifchanged(repo)
1010 cmdutil.bailifchanged(repo)
1011 return hg.clean(repo, node)
1011 return hg.clean(repo, node)
1012
1012
1013 @command('bookmarks|bookmark',
1013 @command('bookmarks|bookmark',
1014 [('f', 'force', False, _('force')),
1014 [('f', 'force', False, _('force')),
1015 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1015 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1016 ('d', 'delete', False, _('delete a given bookmark')),
1016 ('d', 'delete', False, _('delete a given bookmark')),
1017 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1017 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1018 ('i', 'inactive', False, _('mark a bookmark inactive')),
1018 ('i', 'inactive', False, _('mark a bookmark inactive')),
1019 ] + formatteropts,
1019 ] + formatteropts,
1020 _('hg bookmarks [OPTIONS]... [NAME]...'))
1020 _('hg bookmarks [OPTIONS]... [NAME]...'))
1021 def bookmark(ui, repo, *names, **opts):
1021 def bookmark(ui, repo, *names, **opts):
1022 '''create a new bookmark or list existing bookmarks
1022 '''create a new bookmark or list existing bookmarks
1023
1023
1024 Bookmarks are labels on changesets to help track lines of development.
1024 Bookmarks are labels on changesets to help track lines of development.
1025 Bookmarks are unversioned and can be moved, renamed and deleted.
1025 Bookmarks are unversioned and can be moved, renamed and deleted.
1026 Deleting or moving a bookmark has no effect on the associated changesets.
1026 Deleting or moving a bookmark has no effect on the associated changesets.
1027
1027
1028 Creating or updating to a bookmark causes it to be marked as 'active'.
1028 Creating or updating to a bookmark causes it to be marked as 'active'.
1029 The active bookmark is indicated with a '*'.
1029 The active bookmark is indicated with a '*'.
1030 When a commit is made, the active bookmark will advance to the new commit.
1030 When a commit is made, the active bookmark will advance to the new commit.
1031 A plain :hg:`update` will also advance an active bookmark, if possible.
1031 A plain :hg:`update` will also advance an active bookmark, if possible.
1032 Updating away from a bookmark will cause it to be deactivated.
1032 Updating away from a bookmark will cause it to be deactivated.
1033
1033
1034 Bookmarks can be pushed and pulled between repositories (see
1034 Bookmarks can be pushed and pulled between repositories (see
1035 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1035 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1036 diverged, a new 'divergent bookmark' of the form 'name@path' will
1036 diverged, a new 'divergent bookmark' of the form 'name@path' will
1037 be created. Using :hg:`merge` will resolve the divergence.
1037 be created. Using :hg:`merge` will resolve the divergence.
1038
1038
1039 A bookmark named '@' has the special property that :hg:`clone` will
1039 A bookmark named '@' has the special property that :hg:`clone` will
1040 check it out by default if it exists.
1040 check it out by default if it exists.
1041
1041
1042 .. container:: verbose
1042 .. container:: verbose
1043
1043
1044 Examples:
1044 Examples:
1045
1045
1046 - create an active bookmark for a new line of development::
1046 - create an active bookmark for a new line of development::
1047
1047
1048 hg book new-feature
1048 hg book new-feature
1049
1049
1050 - create an inactive bookmark as a place marker::
1050 - create an inactive bookmark as a place marker::
1051
1051
1052 hg book -i reviewed
1052 hg book -i reviewed
1053
1053
1054 - create an inactive bookmark on another changeset::
1054 - create an inactive bookmark on another changeset::
1055
1055
1056 hg book -r .^ tested
1056 hg book -r .^ tested
1057
1057
1058 - rename bookmark turkey to dinner::
1058 - rename bookmark turkey to dinner::
1059
1059
1060 hg book -m turkey dinner
1060 hg book -m turkey dinner
1061
1061
1062 - move the '@' bookmark from another branch::
1062 - move the '@' bookmark from another branch::
1063
1063
1064 hg book -f @
1064 hg book -f @
1065 '''
1065 '''
1066 force = opts.get('force')
1066 force = opts.get('force')
1067 rev = opts.get('rev')
1067 rev = opts.get('rev')
1068 delete = opts.get('delete')
1068 delete = opts.get('delete')
1069 rename = opts.get('rename')
1069 rename = opts.get('rename')
1070 inactive = opts.get('inactive')
1070 inactive = opts.get('inactive')
1071
1071
1072 def checkformat(mark):
1072 def checkformat(mark):
1073 mark = mark.strip()
1073 mark = mark.strip()
1074 if not mark:
1074 if not mark:
1075 raise error.Abort(_("bookmark names cannot consist entirely of "
1075 raise error.Abort(_("bookmark names cannot consist entirely of "
1076 "whitespace"))
1076 "whitespace"))
1077 scmutil.checknewlabel(repo, mark, 'bookmark')
1077 scmutil.checknewlabel(repo, mark, 'bookmark')
1078 return mark
1078 return mark
1079
1079
1080 def checkconflict(repo, mark, cur, force=False, target=None):
1080 def checkconflict(repo, mark, cur, force=False, target=None):
1081 if mark in marks and not force:
1081 if mark in marks and not force:
1082 if target:
1082 if target:
1083 if marks[mark] == target and target == cur:
1083 if marks[mark] == target and target == cur:
1084 # re-activating a bookmark
1084 # re-activating a bookmark
1085 return
1085 return
1086 anc = repo.changelog.ancestors([repo[target].rev()])
1086 anc = repo.changelog.ancestors([repo[target].rev()])
1087 bmctx = repo[marks[mark]]
1087 bmctx = repo[marks[mark]]
1088 divs = [repo[b].node() for b in marks
1088 divs = [repo[b].node() for b in marks
1089 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1089 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1090
1090
1091 # allow resolving a single divergent bookmark even if moving
1091 # allow resolving a single divergent bookmark even if moving
1092 # the bookmark across branches when a revision is specified
1092 # the bookmark across branches when a revision is specified
1093 # that contains a divergent bookmark
1093 # that contains a divergent bookmark
1094 if bmctx.rev() not in anc and target in divs:
1094 if bmctx.rev() not in anc and target in divs:
1095 bookmarks.deletedivergent(repo, [target], mark)
1095 bookmarks.deletedivergent(repo, [target], mark)
1096 return
1096 return
1097
1097
1098 deletefrom = [b for b in divs
1098 deletefrom = [b for b in divs
1099 if repo[b].rev() in anc or b == target]
1099 if repo[b].rev() in anc or b == target]
1100 bookmarks.deletedivergent(repo, deletefrom, mark)
1100 bookmarks.deletedivergent(repo, deletefrom, mark)
1101 if bookmarks.validdest(repo, bmctx, repo[target]):
1101 if bookmarks.validdest(repo, bmctx, repo[target]):
1102 ui.status(_("moving bookmark '%s' forward from %s\n") %
1102 ui.status(_("moving bookmark '%s' forward from %s\n") %
1103 (mark, short(bmctx.node())))
1103 (mark, short(bmctx.node())))
1104 return
1104 return
1105 raise error.Abort(_("bookmark '%s' already exists "
1105 raise error.Abort(_("bookmark '%s' already exists "
1106 "(use -f to force)") % mark)
1106 "(use -f to force)") % mark)
1107 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1107 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1108 and not force):
1108 and not force):
1109 raise error.Abort(
1109 raise error.Abort(
1110 _("a bookmark cannot have the name of an existing branch"))
1110 _("a bookmark cannot have the name of an existing branch"))
1111
1111
1112 if delete and rename:
1112 if delete and rename:
1113 raise error.Abort(_("--delete and --rename are incompatible"))
1113 raise error.Abort(_("--delete and --rename are incompatible"))
1114 if delete and rev:
1114 if delete and rev:
1115 raise error.Abort(_("--rev is incompatible with --delete"))
1115 raise error.Abort(_("--rev is incompatible with --delete"))
1116 if rename and rev:
1116 if rename and rev:
1117 raise error.Abort(_("--rev is incompatible with --rename"))
1117 raise error.Abort(_("--rev is incompatible with --rename"))
1118 if not names and (delete or rev):
1118 if not names and (delete or rev):
1119 raise error.Abort(_("bookmark name required"))
1119 raise error.Abort(_("bookmark name required"))
1120
1120
1121 if delete or rename or names or inactive:
1121 if delete or rename or names or inactive:
1122 wlock = lock = tr = None
1122 wlock = lock = tr = None
1123 try:
1123 try:
1124 wlock = repo.wlock()
1124 wlock = repo.wlock()
1125 lock = repo.lock()
1125 lock = repo.lock()
1126 cur = repo.changectx('.').node()
1126 cur = repo.changectx('.').node()
1127 marks = repo._bookmarks
1127 marks = repo._bookmarks
1128 if delete:
1128 if delete:
1129 tr = repo.transaction('bookmark')
1129 tr = repo.transaction('bookmark')
1130 for mark in names:
1130 for mark in names:
1131 if mark not in marks:
1131 if mark not in marks:
1132 raise error.Abort(_("bookmark '%s' does not exist") %
1132 raise error.Abort(_("bookmark '%s' does not exist") %
1133 mark)
1133 mark)
1134 if mark == repo._activebookmark:
1134 if mark == repo._activebookmark:
1135 bookmarks.deactivate(repo)
1135 bookmarks.deactivate(repo)
1136 del marks[mark]
1136 del marks[mark]
1137
1137
1138 elif rename:
1138 elif rename:
1139 tr = repo.transaction('bookmark')
1139 tr = repo.transaction('bookmark')
1140 if not names:
1140 if not names:
1141 raise error.Abort(_("new bookmark name required"))
1141 raise error.Abort(_("new bookmark name required"))
1142 elif len(names) > 1:
1142 elif len(names) > 1:
1143 raise error.Abort(_("only one new bookmark name allowed"))
1143 raise error.Abort(_("only one new bookmark name allowed"))
1144 mark = checkformat(names[0])
1144 mark = checkformat(names[0])
1145 if rename not in marks:
1145 if rename not in marks:
1146 raise error.Abort(_("bookmark '%s' does not exist")
1146 raise error.Abort(_("bookmark '%s' does not exist")
1147 % rename)
1147 % rename)
1148 checkconflict(repo, mark, cur, force)
1148 checkconflict(repo, mark, cur, force)
1149 marks[mark] = marks[rename]
1149 marks[mark] = marks[rename]
1150 if repo._activebookmark == rename and not inactive:
1150 if repo._activebookmark == rename and not inactive:
1151 bookmarks.activate(repo, mark)
1151 bookmarks.activate(repo, mark)
1152 del marks[rename]
1152 del marks[rename]
1153 elif names:
1153 elif names:
1154 tr = repo.transaction('bookmark')
1154 tr = repo.transaction('bookmark')
1155 newact = None
1155 newact = None
1156 for mark in names:
1156 for mark in names:
1157 mark = checkformat(mark)
1157 mark = checkformat(mark)
1158 if newact is None:
1158 if newact is None:
1159 newact = mark
1159 newact = mark
1160 if inactive and mark == repo._activebookmark:
1160 if inactive and mark == repo._activebookmark:
1161 bookmarks.deactivate(repo)
1161 bookmarks.deactivate(repo)
1162 return
1162 return
1163 tgt = cur
1163 tgt = cur
1164 if rev:
1164 if rev:
1165 tgt = scmutil.revsingle(repo, rev).node()
1165 tgt = scmutil.revsingle(repo, rev).node()
1166 checkconflict(repo, mark, cur, force, tgt)
1166 checkconflict(repo, mark, cur, force, tgt)
1167 marks[mark] = tgt
1167 marks[mark] = tgt
1168 if not inactive and cur == marks[newact] and not rev:
1168 if not inactive and cur == marks[newact] and not rev:
1169 bookmarks.activate(repo, newact)
1169 bookmarks.activate(repo, newact)
1170 elif cur != tgt and newact == repo._activebookmark:
1170 elif cur != tgt and newact == repo._activebookmark:
1171 bookmarks.deactivate(repo)
1171 bookmarks.deactivate(repo)
1172 elif inactive:
1172 elif inactive:
1173 if len(marks) == 0:
1173 if len(marks) == 0:
1174 ui.status(_("no bookmarks set\n"))
1174 ui.status(_("no bookmarks set\n"))
1175 elif not repo._activebookmark:
1175 elif not repo._activebookmark:
1176 ui.status(_("no active bookmark\n"))
1176 ui.status(_("no active bookmark\n"))
1177 else:
1177 else:
1178 bookmarks.deactivate(repo)
1178 bookmarks.deactivate(repo)
1179 if tr is not None:
1179 if tr is not None:
1180 marks.recordchange(tr)
1180 marks.recordchange(tr)
1181 tr.close()
1181 tr.close()
1182 finally:
1182 finally:
1183 lockmod.release(tr, lock, wlock)
1183 lockmod.release(tr, lock, wlock)
1184 else: # show bookmarks
1184 else: # show bookmarks
1185 fm = ui.formatter('bookmarks', opts)
1185 fm = ui.formatter('bookmarks', opts)
1186 hexfn = fm.hexfunc
1186 hexfn = fm.hexfunc
1187 marks = repo._bookmarks
1187 marks = repo._bookmarks
1188 if len(marks) == 0 and not fm:
1188 if len(marks) == 0 and not fm:
1189 ui.status(_("no bookmarks set\n"))
1189 ui.status(_("no bookmarks set\n"))
1190 for bmark, n in sorted(marks.iteritems()):
1190 for bmark, n in sorted(marks.iteritems()):
1191 active = repo._activebookmark
1191 active = repo._activebookmark
1192 if bmark == active:
1192 if bmark == active:
1193 prefix, label = '*', activebookmarklabel
1193 prefix, label = '*', activebookmarklabel
1194 else:
1194 else:
1195 prefix, label = ' ', ''
1195 prefix, label = ' ', ''
1196
1196
1197 fm.startitem()
1197 fm.startitem()
1198 if not ui.quiet:
1198 if not ui.quiet:
1199 fm.plain(' %s ' % prefix, label=label)
1199 fm.plain(' %s ' % prefix, label=label)
1200 fm.write('bookmark', '%s', bmark, label=label)
1200 fm.write('bookmark', '%s', bmark, label=label)
1201 pad = " " * (25 - encoding.colwidth(bmark))
1201 pad = " " * (25 - encoding.colwidth(bmark))
1202 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1202 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1203 repo.changelog.rev(n), hexfn(n), label=label)
1203 repo.changelog.rev(n), hexfn(n), label=label)
1204 fm.data(active=(bmark == active))
1204 fm.data(active=(bmark == active))
1205 fm.plain('\n')
1205 fm.plain('\n')
1206 fm.end()
1206 fm.end()
1207
1207
1208 @command('branch',
1208 @command('branch',
1209 [('f', 'force', None,
1209 [('f', 'force', None,
1210 _('set branch name even if it shadows an existing branch')),
1210 _('set branch name even if it shadows an existing branch')),
1211 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1211 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1212 _('[-fC] [NAME]'))
1212 _('[-fC] [NAME]'))
1213 def branch(ui, repo, label=None, **opts):
1213 def branch(ui, repo, label=None, **opts):
1214 """set or show the current branch name
1214 """set or show the current branch name
1215
1215
1216 .. note::
1216 .. note::
1217
1217
1218 Branch names are permanent and global. Use :hg:`bookmark` to create a
1218 Branch names are permanent and global. Use :hg:`bookmark` to create a
1219 light-weight bookmark instead. See :hg:`help glossary` for more
1219 light-weight bookmark instead. See :hg:`help glossary` for more
1220 information about named branches and bookmarks.
1220 information about named branches and bookmarks.
1221
1221
1222 With no argument, show the current branch name. With one argument,
1222 With no argument, show the current branch name. With one argument,
1223 set the working directory branch name (the branch will not exist
1223 set the working directory branch name (the branch will not exist
1224 in the repository until the next commit). Standard practice
1224 in the repository until the next commit). Standard practice
1225 recommends that primary development take place on the 'default'
1225 recommends that primary development take place on the 'default'
1226 branch.
1226 branch.
1227
1227
1228 Unless -f/--force is specified, branch will not let you set a
1228 Unless -f/--force is specified, branch will not let you set a
1229 branch name that already exists.
1229 branch name that already exists.
1230
1230
1231 Use -C/--clean to reset the working directory branch to that of
1231 Use -C/--clean to reset the working directory branch to that of
1232 the parent of the working directory, negating a previous branch
1232 the parent of the working directory, negating a previous branch
1233 change.
1233 change.
1234
1234
1235 Use the command :hg:`update` to switch to an existing branch. Use
1235 Use the command :hg:`update` to switch to an existing branch. Use
1236 :hg:`commit --close-branch` to mark this branch head as closed.
1236 :hg:`commit --close-branch` to mark this branch head as closed.
1237 When all heads of a branch are closed, the branch will be
1237 When all heads of a branch are closed, the branch will be
1238 considered closed.
1238 considered closed.
1239
1239
1240 Returns 0 on success.
1240 Returns 0 on success.
1241 """
1241 """
1242 if label:
1242 if label:
1243 label = label.strip()
1243 label = label.strip()
1244
1244
1245 if not opts.get('clean') and not label:
1245 if not opts.get('clean') and not label:
1246 ui.write("%s\n" % repo.dirstate.branch())
1246 ui.write("%s\n" % repo.dirstate.branch())
1247 return
1247 return
1248
1248
1249 with repo.wlock():
1249 with repo.wlock():
1250 if opts.get('clean'):
1250 if opts.get('clean'):
1251 label = repo[None].p1().branch()
1251 label = repo[None].p1().branch()
1252 repo.dirstate.setbranch(label)
1252 repo.dirstate.setbranch(label)
1253 ui.status(_('reset working directory to branch %s\n') % label)
1253 ui.status(_('reset working directory to branch %s\n') % label)
1254 elif label:
1254 elif label:
1255 if not opts.get('force') and label in repo.branchmap():
1255 if not opts.get('force') and label in repo.branchmap():
1256 if label not in [p.branch() for p in repo[None].parents()]:
1256 if label not in [p.branch() for p in repo[None].parents()]:
1257 raise error.Abort(_('a branch of the same name already'
1257 raise error.Abort(_('a branch of the same name already'
1258 ' exists'),
1258 ' exists'),
1259 # i18n: "it" refers to an existing branch
1259 # i18n: "it" refers to an existing branch
1260 hint=_("use 'hg update' to switch to it"))
1260 hint=_("use 'hg update' to switch to it"))
1261 scmutil.checknewlabel(repo, label, 'branch')
1261 scmutil.checknewlabel(repo, label, 'branch')
1262 repo.dirstate.setbranch(label)
1262 repo.dirstate.setbranch(label)
1263 ui.status(_('marked working directory as branch %s\n') % label)
1263 ui.status(_('marked working directory as branch %s\n') % label)
1264
1264
1265 # find any open named branches aside from default
1265 # find any open named branches aside from default
1266 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1266 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1267 if n != "default" and not c]
1267 if n != "default" and not c]
1268 if not others:
1268 if not others:
1269 ui.status(_('(branches are permanent and global, '
1269 ui.status(_('(branches are permanent and global, '
1270 'did you want a bookmark?)\n'))
1270 'did you want a bookmark?)\n'))
1271
1271
1272 @command('branches',
1272 @command('branches',
1273 [('a', 'active', False,
1273 [('a', 'active', False,
1274 _('show only branches that have unmerged heads (DEPRECATED)')),
1274 _('show only branches that have unmerged heads (DEPRECATED)')),
1275 ('c', 'closed', False, _('show normal and closed branches')),
1275 ('c', 'closed', False, _('show normal and closed branches')),
1276 ] + formatteropts,
1276 ] + formatteropts,
1277 _('[-c]'))
1277 _('[-c]'))
1278 def branches(ui, repo, active=False, closed=False, **opts):
1278 def branches(ui, repo, active=False, closed=False, **opts):
1279 """list repository named branches
1279 """list repository named branches
1280
1280
1281 List the repository's named branches, indicating which ones are
1281 List the repository's named branches, indicating which ones are
1282 inactive. If -c/--closed is specified, also list branches which have
1282 inactive. If -c/--closed is specified, also list branches which have
1283 been marked closed (see :hg:`commit --close-branch`).
1283 been marked closed (see :hg:`commit --close-branch`).
1284
1284
1285 Use the command :hg:`update` to switch to an existing branch.
1285 Use the command :hg:`update` to switch to an existing branch.
1286
1286
1287 Returns 0.
1287 Returns 0.
1288 """
1288 """
1289
1289
1290 fm = ui.formatter('branches', opts)
1290 fm = ui.formatter('branches', opts)
1291 hexfunc = fm.hexfunc
1291 hexfunc = fm.hexfunc
1292
1292
1293 allheads = set(repo.heads())
1293 allheads = set(repo.heads())
1294 branches = []
1294 branches = []
1295 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1295 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1296 isactive = not isclosed and bool(set(heads) & allheads)
1296 isactive = not isclosed and bool(set(heads) & allheads)
1297 branches.append((tag, repo[tip], isactive, not isclosed))
1297 branches.append((tag, repo[tip], isactive, not isclosed))
1298 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1298 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1299 reverse=True)
1299 reverse=True)
1300
1300
1301 for tag, ctx, isactive, isopen in branches:
1301 for tag, ctx, isactive, isopen in branches:
1302 if active and not isactive:
1302 if active and not isactive:
1303 continue
1303 continue
1304 if isactive:
1304 if isactive:
1305 label = 'branches.active'
1305 label = 'branches.active'
1306 notice = ''
1306 notice = ''
1307 elif not isopen:
1307 elif not isopen:
1308 if not closed:
1308 if not closed:
1309 continue
1309 continue
1310 label = 'branches.closed'
1310 label = 'branches.closed'
1311 notice = _(' (closed)')
1311 notice = _(' (closed)')
1312 else:
1312 else:
1313 label = 'branches.inactive'
1313 label = 'branches.inactive'
1314 notice = _(' (inactive)')
1314 notice = _(' (inactive)')
1315 current = (tag == repo.dirstate.branch())
1315 current = (tag == repo.dirstate.branch())
1316 if current:
1316 if current:
1317 label = 'branches.current'
1317 label = 'branches.current'
1318
1318
1319 fm.startitem()
1319 fm.startitem()
1320 fm.write('branch', '%s', tag, label=label)
1320 fm.write('branch', '%s', tag, label=label)
1321 rev = ctx.rev()
1321 rev = ctx.rev()
1322 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1322 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1323 fmt = ' ' * padsize + ' %d:%s'
1323 fmt = ' ' * padsize + ' %d:%s'
1324 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1324 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1325 label='log.changeset changeset.%s' % ctx.phasestr())
1325 label='log.changeset changeset.%s' % ctx.phasestr())
1326 fm.data(active=isactive, closed=not isopen, current=current)
1326 fm.data(active=isactive, closed=not isopen, current=current)
1327 if not ui.quiet:
1327 if not ui.quiet:
1328 fm.plain(notice)
1328 fm.plain(notice)
1329 fm.plain('\n')
1329 fm.plain('\n')
1330 fm.end()
1330 fm.end()
1331
1331
1332 @command('bundle',
1332 @command('bundle',
1333 [('f', 'force', None, _('run even when the destination is unrelated')),
1333 [('f', 'force', None, _('run even when the destination is unrelated')),
1334 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1334 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1335 _('REV')),
1335 _('REV')),
1336 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1336 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1337 _('BRANCH')),
1337 _('BRANCH')),
1338 ('', 'base', [],
1338 ('', 'base', [],
1339 _('a base changeset assumed to be available at the destination'),
1339 _('a base changeset assumed to be available at the destination'),
1340 _('REV')),
1340 _('REV')),
1341 ('a', 'all', None, _('bundle all changesets in the repository')),
1341 ('a', 'all', None, _('bundle all changesets in the repository')),
1342 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1342 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1343 ] + remoteopts,
1343 ] + remoteopts,
1344 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1344 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1345 def bundle(ui, repo, fname, dest=None, **opts):
1345 def bundle(ui, repo, fname, dest=None, **opts):
1346 """create a changegroup file
1346 """create a changegroup file
1347
1347
1348 Generate a changegroup file collecting changesets to be added
1348 Generate a changegroup file collecting changesets to be added
1349 to a repository.
1349 to a repository.
1350
1350
1351 To create a bundle containing all changesets, use -a/--all
1351 To create a bundle containing all changesets, use -a/--all
1352 (or --base null). Otherwise, hg assumes the destination will have
1352 (or --base null). Otherwise, hg assumes the destination will have
1353 all the nodes you specify with --base parameters. Otherwise, hg
1353 all the nodes you specify with --base parameters. Otherwise, hg
1354 will assume the repository has all the nodes in destination, or
1354 will assume the repository has all the nodes in destination, or
1355 default-push/default if no destination is specified.
1355 default-push/default if no destination is specified.
1356
1356
1357 You can change bundle format with the -t/--type option. You can
1357 You can change bundle format with the -t/--type option. You can
1358 specify a compression, a bundle version or both using a dash
1358 specify a compression, a bundle version or both using a dash
1359 (comp-version). The available compression methods are: none, bzip2,
1359 (comp-version). The available compression methods are: none, bzip2,
1360 and gzip (by default, bundles are compressed using bzip2). The
1360 and gzip (by default, bundles are compressed using bzip2). The
1361 available formats are: v1, v2 (default to most suitable).
1361 available formats are: v1, v2 (default to most suitable).
1362
1362
1363 The bundle file can then be transferred using conventional means
1363 The bundle file can then be transferred using conventional means
1364 and applied to another repository with the unbundle or pull
1364 and applied to another repository with the unbundle or pull
1365 command. This is useful when direct push and pull are not
1365 command. This is useful when direct push and pull are not
1366 available or when exporting an entire repository is undesirable.
1366 available or when exporting an entire repository is undesirable.
1367
1367
1368 Applying bundles preserves all changeset contents including
1368 Applying bundles preserves all changeset contents including
1369 permissions, copy/rename information, and revision history.
1369 permissions, copy/rename information, and revision history.
1370
1370
1371 Returns 0 on success, 1 if no changes found.
1371 Returns 0 on success, 1 if no changes found.
1372 """
1372 """
1373 revs = None
1373 revs = None
1374 if 'rev' in opts:
1374 if 'rev' in opts:
1375 revstrings = opts['rev']
1375 revstrings = opts['rev']
1376 revs = scmutil.revrange(repo, revstrings)
1376 revs = scmutil.revrange(repo, revstrings)
1377 if revstrings and not revs:
1377 if revstrings and not revs:
1378 raise error.Abort(_('no commits to bundle'))
1378 raise error.Abort(_('no commits to bundle'))
1379
1379
1380 bundletype = opts.get('type', 'bzip2').lower()
1380 bundletype = opts.get('type', 'bzip2').lower()
1381 try:
1381 try:
1382 bcompression, cgversion, params = exchange.parsebundlespec(
1382 bcompression, cgversion, params = exchange.parsebundlespec(
1383 repo, bundletype, strict=False)
1383 repo, bundletype, strict=False)
1384 except error.UnsupportedBundleSpecification as e:
1384 except error.UnsupportedBundleSpecification as e:
1385 raise error.Abort(str(e),
1385 raise error.Abort(str(e),
1386 hint=_('see "hg help bundle" for supported '
1386 hint=_('see "hg help bundle" for supported '
1387 'values for --type'))
1387 'values for --type'))
1388
1388
1389 # Packed bundles are a pseudo bundle format for now.
1389 # Packed bundles are a pseudo bundle format for now.
1390 if cgversion == 's1':
1390 if cgversion == 's1':
1391 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1391 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1392 hint=_("use 'hg debugcreatestreamclonebundle'"))
1392 hint=_("use 'hg debugcreatestreamclonebundle'"))
1393
1393
1394 if opts.get('all'):
1394 if opts.get('all'):
1395 if dest:
1395 if dest:
1396 raise error.Abort(_("--all is incompatible with specifying "
1396 raise error.Abort(_("--all is incompatible with specifying "
1397 "a destination"))
1397 "a destination"))
1398 if opts.get('base'):
1398 if opts.get('base'):
1399 ui.warn(_("ignoring --base because --all was specified\n"))
1399 ui.warn(_("ignoring --base because --all was specified\n"))
1400 base = ['null']
1400 base = ['null']
1401 else:
1401 else:
1402 base = scmutil.revrange(repo, opts.get('base'))
1402 base = scmutil.revrange(repo, opts.get('base'))
1403 # TODO: get desired bundlecaps from command line.
1403 # TODO: get desired bundlecaps from command line.
1404 bundlecaps = None
1404 bundlecaps = None
1405 if cgversion not in changegroup.supportedoutgoingversions(repo):
1405 if cgversion not in changegroup.supportedoutgoingversions(repo):
1406 raise error.Abort(_("repository does not support bundle version %s") %
1406 raise error.Abort(_("repository does not support bundle version %s") %
1407 cgversion)
1407 cgversion)
1408
1408
1409 if base:
1409 if base:
1410 if dest:
1410 if dest:
1411 raise error.Abort(_("--base is incompatible with specifying "
1411 raise error.Abort(_("--base is incompatible with specifying "
1412 "a destination"))
1412 "a destination"))
1413 common = [repo.lookup(rev) for rev in base]
1413 common = [repo.lookup(rev) for rev in base]
1414 heads = revs and map(repo.lookup, revs) or revs
1414 heads = revs and map(repo.lookup, revs) or revs
1415 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1415 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1416 common=common, bundlecaps=bundlecaps,
1416 common=common, bundlecaps=bundlecaps,
1417 version=cgversion)
1417 version=cgversion)
1418 outgoing = None
1418 outgoing = None
1419 else:
1419 else:
1420 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1420 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1421 dest, branches = hg.parseurl(dest, opts.get('branch'))
1421 dest, branches = hg.parseurl(dest, opts.get('branch'))
1422 other = hg.peer(repo, opts, dest)
1422 other = hg.peer(repo, opts, dest)
1423 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1423 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1424 heads = revs and map(repo.lookup, revs) or revs
1424 heads = revs and map(repo.lookup, revs) or revs
1425 outgoing = discovery.findcommonoutgoing(repo, other,
1425 outgoing = discovery.findcommonoutgoing(repo, other,
1426 onlyheads=heads,
1426 onlyheads=heads,
1427 force=opts.get('force'),
1427 force=opts.get('force'),
1428 portable=True)
1428 portable=True)
1429 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1429 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1430 bundlecaps, version=cgversion)
1430 bundlecaps, version=cgversion)
1431 if not cg:
1431 if not cg:
1432 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1432 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1433 return 1
1433 return 1
1434
1434
1435 if cgversion == '01': #bundle1
1435 if cgversion == '01': #bundle1
1436 if bcompression is None:
1436 if bcompression is None:
1437 bcompression = 'UN'
1437 bcompression = 'UN'
1438 bversion = 'HG10' + bcompression
1438 bversion = 'HG10' + bcompression
1439 bcompression = None
1439 bcompression = None
1440 else:
1440 else:
1441 assert cgversion == '02'
1441 assert cgversion == '02'
1442 bversion = 'HG20'
1442 bversion = 'HG20'
1443
1443
1444 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1444 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1445
1445
1446 @command('cat',
1446 @command('cat',
1447 [('o', 'output', '',
1447 [('o', 'output', '',
1448 _('print output to file with formatted name'), _('FORMAT')),
1448 _('print output to file with formatted name'), _('FORMAT')),
1449 ('r', 'rev', '', _('print the given revision'), _('REV')),
1449 ('r', 'rev', '', _('print the given revision'), _('REV')),
1450 ('', 'decode', None, _('apply any matching decode filter')),
1450 ('', 'decode', None, _('apply any matching decode filter')),
1451 ] + walkopts,
1451 ] + walkopts,
1452 _('[OPTION]... FILE...'),
1452 _('[OPTION]... FILE...'),
1453 inferrepo=True)
1453 inferrepo=True)
1454 def cat(ui, repo, file1, *pats, **opts):
1454 def cat(ui, repo, file1, *pats, **opts):
1455 """output the current or given revision of files
1455 """output the current or given revision of files
1456
1456
1457 Print the specified files as they were at the given revision. If
1457 Print the specified files as they were at the given revision. If
1458 no revision is given, the parent of the working directory is used.
1458 no revision is given, the parent of the working directory is used.
1459
1459
1460 Output may be to a file, in which case the name of the file is
1460 Output may be to a file, in which case the name of the file is
1461 given using a format string. The formatting rules as follows:
1461 given using a format string. The formatting rules as follows:
1462
1462
1463 :``%%``: literal "%" character
1463 :``%%``: literal "%" character
1464 :``%s``: basename of file being printed
1464 :``%s``: basename of file being printed
1465 :``%d``: dirname of file being printed, or '.' if in repository root
1465 :``%d``: dirname of file being printed, or '.' if in repository root
1466 :``%p``: root-relative path name of file being printed
1466 :``%p``: root-relative path name of file being printed
1467 :``%H``: changeset hash (40 hexadecimal digits)
1467 :``%H``: changeset hash (40 hexadecimal digits)
1468 :``%R``: changeset revision number
1468 :``%R``: changeset revision number
1469 :``%h``: short-form changeset hash (12 hexadecimal digits)
1469 :``%h``: short-form changeset hash (12 hexadecimal digits)
1470 :``%r``: zero-padded changeset revision number
1470 :``%r``: zero-padded changeset revision number
1471 :``%b``: basename of the exporting repository
1471 :``%b``: basename of the exporting repository
1472
1472
1473 Returns 0 on success.
1473 Returns 0 on success.
1474 """
1474 """
1475 ctx = scmutil.revsingle(repo, opts.get('rev'))
1475 ctx = scmutil.revsingle(repo, opts.get('rev'))
1476 m = scmutil.match(ctx, (file1,) + pats, opts)
1476 m = scmutil.match(ctx, (file1,) + pats, opts)
1477
1477
1478 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1478 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1479
1479
1480 @command('^clone',
1480 @command('^clone',
1481 [('U', 'noupdate', None, _('the clone will include an empty working '
1481 [('U', 'noupdate', None, _('the clone will include an empty working '
1482 'directory (only a repository)')),
1482 'directory (only a repository)')),
1483 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1483 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1484 _('REV')),
1484 _('REV')),
1485 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1485 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1486 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1486 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1487 ('', 'pull', None, _('use pull protocol to copy metadata')),
1487 ('', 'pull', None, _('use pull protocol to copy metadata')),
1488 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1488 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1489 ] + remoteopts,
1489 ] + remoteopts,
1490 _('[OPTION]... SOURCE [DEST]'),
1490 _('[OPTION]... SOURCE [DEST]'),
1491 norepo=True)
1491 norepo=True)
1492 def clone(ui, source, dest=None, **opts):
1492 def clone(ui, source, dest=None, **opts):
1493 """make a copy of an existing repository
1493 """make a copy of an existing repository
1494
1494
1495 Create a copy of an existing repository in a new directory.
1495 Create a copy of an existing repository in a new directory.
1496
1496
1497 If no destination directory name is specified, it defaults to the
1497 If no destination directory name is specified, it defaults to the
1498 basename of the source.
1498 basename of the source.
1499
1499
1500 The location of the source is added to the new repository's
1500 The location of the source is added to the new repository's
1501 ``.hg/hgrc`` file, as the default to be used for future pulls.
1501 ``.hg/hgrc`` file, as the default to be used for future pulls.
1502
1502
1503 Only local paths and ``ssh://`` URLs are supported as
1503 Only local paths and ``ssh://`` URLs are supported as
1504 destinations. For ``ssh://`` destinations, no working directory or
1504 destinations. For ``ssh://`` destinations, no working directory or
1505 ``.hg/hgrc`` will be created on the remote side.
1505 ``.hg/hgrc`` will be created on the remote side.
1506
1506
1507 If the source repository has a bookmark called '@' set, that
1507 If the source repository has a bookmark called '@' set, that
1508 revision will be checked out in the new repository by default.
1508 revision will be checked out in the new repository by default.
1509
1509
1510 To check out a particular version, use -u/--update, or
1510 To check out a particular version, use -u/--update, or
1511 -U/--noupdate to create a clone with no working directory.
1511 -U/--noupdate to create a clone with no working directory.
1512
1512
1513 To pull only a subset of changesets, specify one or more revisions
1513 To pull only a subset of changesets, specify one or more revisions
1514 identifiers with -r/--rev or branches with -b/--branch. The
1514 identifiers with -r/--rev or branches with -b/--branch. The
1515 resulting clone will contain only the specified changesets and
1515 resulting clone will contain only the specified changesets and
1516 their ancestors. These options (or 'clone src#rev dest') imply
1516 their ancestors. These options (or 'clone src#rev dest') imply
1517 --pull, even for local source repositories.
1517 --pull, even for local source repositories.
1518
1518
1519 .. note::
1519 .. note::
1520
1520
1521 Specifying a tag will include the tagged changeset but not the
1521 Specifying a tag will include the tagged changeset but not the
1522 changeset containing the tag.
1522 changeset containing the tag.
1523
1523
1524 .. container:: verbose
1524 .. container:: verbose
1525
1525
1526 For efficiency, hardlinks are used for cloning whenever the
1526 For efficiency, hardlinks are used for cloning whenever the
1527 source and destination are on the same filesystem (note this
1527 source and destination are on the same filesystem (note this
1528 applies only to the repository data, not to the working
1528 applies only to the repository data, not to the working
1529 directory). Some filesystems, such as AFS, implement hardlinking
1529 directory). Some filesystems, such as AFS, implement hardlinking
1530 incorrectly, but do not report errors. In these cases, use the
1530 incorrectly, but do not report errors. In these cases, use the
1531 --pull option to avoid hardlinking.
1531 --pull option to avoid hardlinking.
1532
1532
1533 In some cases, you can clone repositories and the working
1533 In some cases, you can clone repositories and the working
1534 directory using full hardlinks with ::
1534 directory using full hardlinks with ::
1535
1535
1536 $ cp -al REPO REPOCLONE
1536 $ cp -al REPO REPOCLONE
1537
1537
1538 This is the fastest way to clone, but it is not always safe. The
1538 This is the fastest way to clone, but it is not always safe. The
1539 operation is not atomic (making sure REPO is not modified during
1539 operation is not atomic (making sure REPO is not modified during
1540 the operation is up to you) and you have to make sure your
1540 the operation is up to you) and you have to make sure your
1541 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1541 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1542 so). Also, this is not compatible with certain extensions that
1542 so). Also, this is not compatible with certain extensions that
1543 place their metadata under the .hg directory, such as mq.
1543 place their metadata under the .hg directory, such as mq.
1544
1544
1545 Mercurial will update the working directory to the first applicable
1545 Mercurial will update the working directory to the first applicable
1546 revision from this list:
1546 revision from this list:
1547
1547
1548 a) null if -U or the source repository has no changesets
1548 a) null if -U or the source repository has no changesets
1549 b) if -u . and the source repository is local, the first parent of
1549 b) if -u . and the source repository is local, the first parent of
1550 the source repository's working directory
1550 the source repository's working directory
1551 c) the changeset specified with -u (if a branch name, this means the
1551 c) the changeset specified with -u (if a branch name, this means the
1552 latest head of that branch)
1552 latest head of that branch)
1553 d) the changeset specified with -r
1553 d) the changeset specified with -r
1554 e) the tipmost head specified with -b
1554 e) the tipmost head specified with -b
1555 f) the tipmost head specified with the url#branch source syntax
1555 f) the tipmost head specified with the url#branch source syntax
1556 g) the revision marked with the '@' bookmark, if present
1556 g) the revision marked with the '@' bookmark, if present
1557 h) the tipmost head of the default branch
1557 h) the tipmost head of the default branch
1558 i) tip
1558 i) tip
1559
1559
1560 When cloning from servers that support it, Mercurial may fetch
1560 When cloning from servers that support it, Mercurial may fetch
1561 pre-generated data from a server-advertised URL. When this is done,
1561 pre-generated data from a server-advertised URL. When this is done,
1562 hooks operating on incoming changesets and changegroups may fire twice,
1562 hooks operating on incoming changesets and changegroups may fire twice,
1563 once for the bundle fetched from the URL and another for any additional
1563 once for the bundle fetched from the URL and another for any additional
1564 data not fetched from this URL. In addition, if an error occurs, the
1564 data not fetched from this URL. In addition, if an error occurs, the
1565 repository may be rolled back to a partial clone. This behavior may
1565 repository may be rolled back to a partial clone. This behavior may
1566 change in future releases. See :hg:`help -e clonebundles` for more.
1566 change in future releases. See :hg:`help -e clonebundles` for more.
1567
1567
1568 Examples:
1568 Examples:
1569
1569
1570 - clone a remote repository to a new directory named hg/::
1570 - clone a remote repository to a new directory named hg/::
1571
1571
1572 hg clone http://selenic.com/hg
1572 hg clone http://selenic.com/hg
1573
1573
1574 - create a lightweight local clone::
1574 - create a lightweight local clone::
1575
1575
1576 hg clone project/ project-feature/
1576 hg clone project/ project-feature/
1577
1577
1578 - clone from an absolute path on an ssh server (note double-slash)::
1578 - clone from an absolute path on an ssh server (note double-slash)::
1579
1579
1580 hg clone ssh://user@server//home/projects/alpha/
1580 hg clone ssh://user@server//home/projects/alpha/
1581
1581
1582 - do a high-speed clone over a LAN while checking out a
1582 - do a high-speed clone over a LAN while checking out a
1583 specified version::
1583 specified version::
1584
1584
1585 hg clone --uncompressed http://server/repo -u 1.5
1585 hg clone --uncompressed http://server/repo -u 1.5
1586
1586
1587 - create a repository without changesets after a particular revision::
1587 - create a repository without changesets after a particular revision::
1588
1588
1589 hg clone -r 04e544 experimental/ good/
1589 hg clone -r 04e544 experimental/ good/
1590
1590
1591 - clone (and track) a particular named branch::
1591 - clone (and track) a particular named branch::
1592
1592
1593 hg clone http://selenic.com/hg#stable
1593 hg clone http://selenic.com/hg#stable
1594
1594
1595 See :hg:`help urls` for details on specifying URLs.
1595 See :hg:`help urls` for details on specifying URLs.
1596
1596
1597 Returns 0 on success.
1597 Returns 0 on success.
1598 """
1598 """
1599 if opts.get('noupdate') and opts.get('updaterev'):
1599 if opts.get('noupdate') and opts.get('updaterev'):
1600 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1600 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1601
1601
1602 r = hg.clone(ui, opts, source, dest,
1602 r = hg.clone(ui, opts, source, dest,
1603 pull=opts.get('pull'),
1603 pull=opts.get('pull'),
1604 stream=opts.get('uncompressed'),
1604 stream=opts.get('uncompressed'),
1605 rev=opts.get('rev'),
1605 rev=opts.get('rev'),
1606 update=opts.get('updaterev') or not opts.get('noupdate'),
1606 update=opts.get('updaterev') or not opts.get('noupdate'),
1607 branch=opts.get('branch'),
1607 branch=opts.get('branch'),
1608 shareopts=opts.get('shareopts'))
1608 shareopts=opts.get('shareopts'))
1609
1609
1610 return r is None
1610 return r is None
1611
1611
1612 @command('^commit|ci',
1612 @command('^commit|ci',
1613 [('A', 'addremove', None,
1613 [('A', 'addremove', None,
1614 _('mark new/missing files as added/removed before committing')),
1614 _('mark new/missing files as added/removed before committing')),
1615 ('', 'close-branch', None,
1615 ('', 'close-branch', None,
1616 _('mark a branch head as closed')),
1616 _('mark a branch head as closed')),
1617 ('', 'amend', None, _('amend the parent of the working directory')),
1617 ('', 'amend', None, _('amend the parent of the working directory')),
1618 ('s', 'secret', None, _('use the secret phase for committing')),
1618 ('s', 'secret', None, _('use the secret phase for committing')),
1619 ('e', 'edit', None, _('invoke editor on commit messages')),
1619 ('e', 'edit', None, _('invoke editor on commit messages')),
1620 ('i', 'interactive', None, _('use interactive mode')),
1620 ('i', 'interactive', None, _('use interactive mode')),
1621 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1621 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1622 _('[OPTION]... [FILE]...'),
1622 _('[OPTION]... [FILE]...'),
1623 inferrepo=True)
1623 inferrepo=True)
1624 def commit(ui, repo, *pats, **opts):
1624 def commit(ui, repo, *pats, **opts):
1625 """commit the specified files or all outstanding changes
1625 """commit the specified files or all outstanding changes
1626
1626
1627 Commit changes to the given files into the repository. Unlike a
1627 Commit changes to the given files into the repository. Unlike a
1628 centralized SCM, this operation is a local operation. See
1628 centralized SCM, this operation is a local operation. See
1629 :hg:`push` for a way to actively distribute your changes.
1629 :hg:`push` for a way to actively distribute your changes.
1630
1630
1631 If a list of files is omitted, all changes reported by :hg:`status`
1631 If a list of files is omitted, all changes reported by :hg:`status`
1632 will be committed.
1632 will be committed.
1633
1633
1634 If you are committing the result of a merge, do not provide any
1634 If you are committing the result of a merge, do not provide any
1635 filenames or -I/-X filters.
1635 filenames or -I/-X filters.
1636
1636
1637 If no commit message is specified, Mercurial starts your
1637 If no commit message is specified, Mercurial starts your
1638 configured editor where you can enter a message. In case your
1638 configured editor where you can enter a message. In case your
1639 commit fails, you will find a backup of your message in
1639 commit fails, you will find a backup of your message in
1640 ``.hg/last-message.txt``.
1640 ``.hg/last-message.txt``.
1641
1641
1642 The --close-branch flag can be used to mark the current branch
1642 The --close-branch flag can be used to mark the current branch
1643 head closed. When all heads of a branch are closed, the branch
1643 head closed. When all heads of a branch are closed, the branch
1644 will be considered closed and no longer listed.
1644 will be considered closed and no longer listed.
1645
1645
1646 The --amend flag can be used to amend the parent of the
1646 The --amend flag can be used to amend the parent of the
1647 working directory with a new commit that contains the changes
1647 working directory with a new commit that contains the changes
1648 in the parent in addition to those currently reported by :hg:`status`,
1648 in the parent in addition to those currently reported by :hg:`status`,
1649 if there are any. The old commit is stored in a backup bundle in
1649 if there are any. The old commit is stored in a backup bundle in
1650 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1650 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1651 on how to restore it).
1651 on how to restore it).
1652
1652
1653 Message, user and date are taken from the amended commit unless
1653 Message, user and date are taken from the amended commit unless
1654 specified. When a message isn't specified on the command line,
1654 specified. When a message isn't specified on the command line,
1655 the editor will open with the message of the amended commit.
1655 the editor will open with the message of the amended commit.
1656
1656
1657 It is not possible to amend public changesets (see :hg:`help phases`)
1657 It is not possible to amend public changesets (see :hg:`help phases`)
1658 or changesets that have children.
1658 or changesets that have children.
1659
1659
1660 See :hg:`help dates` for a list of formats valid for -d/--date.
1660 See :hg:`help dates` for a list of formats valid for -d/--date.
1661
1661
1662 Returns 0 on success, 1 if nothing changed.
1662 Returns 0 on success, 1 if nothing changed.
1663
1663
1664 .. container:: verbose
1664 .. container:: verbose
1665
1665
1666 Examples:
1666 Examples:
1667
1667
1668 - commit all files ending in .py::
1668 - commit all files ending in .py::
1669
1669
1670 hg commit --include "set:**.py"
1670 hg commit --include "set:**.py"
1671
1671
1672 - commit all non-binary files::
1672 - commit all non-binary files::
1673
1673
1674 hg commit --exclude "set:binary()"
1674 hg commit --exclude "set:binary()"
1675
1675
1676 - amend the current commit and set the date to now::
1676 - amend the current commit and set the date to now::
1677
1677
1678 hg commit --amend --date now
1678 hg commit --amend --date now
1679 """
1679 """
1680 wlock = lock = None
1680 wlock = lock = None
1681 try:
1681 try:
1682 wlock = repo.wlock()
1682 wlock = repo.wlock()
1683 lock = repo.lock()
1683 lock = repo.lock()
1684 return _docommit(ui, repo, *pats, **opts)
1684 return _docommit(ui, repo, *pats, **opts)
1685 finally:
1685 finally:
1686 release(lock, wlock)
1686 release(lock, wlock)
1687
1687
1688 def _docommit(ui, repo, *pats, **opts):
1688 def _docommit(ui, repo, *pats, **opts):
1689 if opts.get('interactive'):
1689 if opts.get('interactive'):
1690 opts.pop('interactive')
1690 opts.pop('interactive')
1691 cmdutil.dorecord(ui, repo, commit, None, False,
1691 cmdutil.dorecord(ui, repo, commit, None, False,
1692 cmdutil.recordfilter, *pats, **opts)
1692 cmdutil.recordfilter, *pats, **opts)
1693 return
1693 return
1694
1694
1695 if opts.get('subrepos'):
1695 if opts.get('subrepos'):
1696 if opts.get('amend'):
1696 if opts.get('amend'):
1697 raise error.Abort(_('cannot amend with --subrepos'))
1697 raise error.Abort(_('cannot amend with --subrepos'))
1698 # Let --subrepos on the command line override config setting.
1698 # Let --subrepos on the command line override config setting.
1699 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1699 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1700
1700
1701 cmdutil.checkunfinished(repo, commit=True)
1701 cmdutil.checkunfinished(repo, commit=True)
1702
1702
1703 branch = repo[None].branch()
1703 branch = repo[None].branch()
1704 bheads = repo.branchheads(branch)
1704 bheads = repo.branchheads(branch)
1705
1705
1706 extra = {}
1706 extra = {}
1707 if opts.get('close_branch'):
1707 if opts.get('close_branch'):
1708 extra['close'] = 1
1708 extra['close'] = 1
1709
1709
1710 if not bheads:
1710 if not bheads:
1711 raise error.Abort(_('can only close branch heads'))
1711 raise error.Abort(_('can only close branch heads'))
1712 elif opts.get('amend'):
1712 elif opts.get('amend'):
1713 if repo[None].parents()[0].p1().branch() != branch and \
1713 if repo[None].parents()[0].p1().branch() != branch and \
1714 repo[None].parents()[0].p2().branch() != branch:
1714 repo[None].parents()[0].p2().branch() != branch:
1715 raise error.Abort(_('can only close branch heads'))
1715 raise error.Abort(_('can only close branch heads'))
1716
1716
1717 if opts.get('amend'):
1717 if opts.get('amend'):
1718 if ui.configbool('ui', 'commitsubrepos'):
1718 if ui.configbool('ui', 'commitsubrepos'):
1719 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1719 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1720
1720
1721 old = repo['.']
1721 old = repo['.']
1722 if not old.mutable():
1722 if not old.mutable():
1723 raise error.Abort(_('cannot amend public changesets'))
1723 raise error.Abort(_('cannot amend public changesets'))
1724 if len(repo[None].parents()) > 1:
1724 if len(repo[None].parents()) > 1:
1725 raise error.Abort(_('cannot amend while merging'))
1725 raise error.Abort(_('cannot amend while merging'))
1726 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1726 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1727 if not allowunstable and old.children():
1727 if not allowunstable and old.children():
1728 raise error.Abort(_('cannot amend changeset with children'))
1728 raise error.Abort(_('cannot amend changeset with children'))
1729
1729
1730 # Currently histedit gets confused if an amend happens while histedit
1730 # Currently histedit gets confused if an amend happens while histedit
1731 # is in progress. Since we have a checkunfinished command, we are
1731 # is in progress. Since we have a checkunfinished command, we are
1732 # temporarily honoring it.
1732 # temporarily honoring it.
1733 #
1733 #
1734 # Note: eventually this guard will be removed. Please do not expect
1734 # Note: eventually this guard will be removed. Please do not expect
1735 # this behavior to remain.
1735 # this behavior to remain.
1736 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1736 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1737 cmdutil.checkunfinished(repo)
1737 cmdutil.checkunfinished(repo)
1738
1738
1739 # commitfunc is used only for temporary amend commit by cmdutil.amend
1739 # commitfunc is used only for temporary amend commit by cmdutil.amend
1740 def commitfunc(ui, repo, message, match, opts):
1740 def commitfunc(ui, repo, message, match, opts):
1741 return repo.commit(message,
1741 return repo.commit(message,
1742 opts.get('user') or old.user(),
1742 opts.get('user') or old.user(),
1743 opts.get('date') or old.date(),
1743 opts.get('date') or old.date(),
1744 match,
1744 match,
1745 extra=extra)
1745 extra=extra)
1746
1746
1747 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1747 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1748 if node == old.node():
1748 if node == old.node():
1749 ui.status(_("nothing changed\n"))
1749 ui.status(_("nothing changed\n"))
1750 return 1
1750 return 1
1751 else:
1751 else:
1752 def commitfunc(ui, repo, message, match, opts):
1752 def commitfunc(ui, repo, message, match, opts):
1753 backup = ui.backupconfig('phases', 'new-commit')
1753 backup = ui.backupconfig('phases', 'new-commit')
1754 baseui = repo.baseui
1754 baseui = repo.baseui
1755 basebackup = baseui.backupconfig('phases', 'new-commit')
1755 basebackup = baseui.backupconfig('phases', 'new-commit')
1756 try:
1756 try:
1757 if opts.get('secret'):
1757 if opts.get('secret'):
1758 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1758 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1759 # Propagate to subrepos
1759 # Propagate to subrepos
1760 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1760 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1761
1761
1762 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1762 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1763 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1763 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1764 return repo.commit(message, opts.get('user'), opts.get('date'),
1764 return repo.commit(message, opts.get('user'), opts.get('date'),
1765 match,
1765 match,
1766 editor=editor,
1766 editor=editor,
1767 extra=extra)
1767 extra=extra)
1768 finally:
1768 finally:
1769 ui.restoreconfig(backup)
1769 ui.restoreconfig(backup)
1770 repo.baseui.restoreconfig(basebackup)
1770 repo.baseui.restoreconfig(basebackup)
1771
1771
1772
1772
1773 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1773 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1774
1774
1775 if not node:
1775 if not node:
1776 stat = cmdutil.postcommitstatus(repo, pats, opts)
1776 stat = cmdutil.postcommitstatus(repo, pats, opts)
1777 if stat[3]:
1777 if stat[3]:
1778 ui.status(_("nothing changed (%d missing files, see "
1778 ui.status(_("nothing changed (%d missing files, see "
1779 "'hg status')\n") % len(stat[3]))
1779 "'hg status')\n") % len(stat[3]))
1780 else:
1780 else:
1781 ui.status(_("nothing changed\n"))
1781 ui.status(_("nothing changed\n"))
1782 return 1
1782 return 1
1783
1783
1784 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1784 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1785
1785
1786 @command('config|showconfig|debugconfig',
1786 @command('config|showconfig|debugconfig',
1787 [('u', 'untrusted', None, _('show untrusted configuration options')),
1787 [('u', 'untrusted', None, _('show untrusted configuration options')),
1788 ('e', 'edit', None, _('edit user config')),
1788 ('e', 'edit', None, _('edit user config')),
1789 ('l', 'local', None, _('edit repository config')),
1789 ('l', 'local', None, _('edit repository config')),
1790 ('g', 'global', None, _('edit global config'))],
1790 ('g', 'global', None, _('edit global config'))],
1791 _('[-u] [NAME]...'),
1791 _('[-u] [NAME]...'),
1792 optionalrepo=True)
1792 optionalrepo=True)
1793 def config(ui, repo, *values, **opts):
1793 def config(ui, repo, *values, **opts):
1794 """show combined config settings from all hgrc files
1794 """show combined config settings from all hgrc files
1795
1795
1796 With no arguments, print names and values of all config items.
1796 With no arguments, print names and values of all config items.
1797
1797
1798 With one argument of the form section.name, print just the value
1798 With one argument of the form section.name, print just the value
1799 of that config item.
1799 of that config item.
1800
1800
1801 With multiple arguments, print names and values of all config
1801 With multiple arguments, print names and values of all config
1802 items with matching section names.
1802 items with matching section names.
1803
1803
1804 With --edit, start an editor on the user-level config file. With
1804 With --edit, start an editor on the user-level config file. With
1805 --global, edit the system-wide config file. With --local, edit the
1805 --global, edit the system-wide config file. With --local, edit the
1806 repository-level config file.
1806 repository-level config file.
1807
1807
1808 With --debug, the source (filename and line number) is printed
1808 With --debug, the source (filename and line number) is printed
1809 for each config item.
1809 for each config item.
1810
1810
1811 See :hg:`help config` for more information about config files.
1811 See :hg:`help config` for more information about config files.
1812
1812
1813 Returns 0 on success, 1 if NAME does not exist.
1813 Returns 0 on success, 1 if NAME does not exist.
1814
1814
1815 """
1815 """
1816
1816
1817 if opts.get('edit') or opts.get('local') or opts.get('global'):
1817 if opts.get('edit') or opts.get('local') or opts.get('global'):
1818 if opts.get('local') and opts.get('global'):
1818 if opts.get('local') and opts.get('global'):
1819 raise error.Abort(_("can't use --local and --global together"))
1819 raise error.Abort(_("can't use --local and --global together"))
1820
1820
1821 if opts.get('local'):
1821 if opts.get('local'):
1822 if not repo:
1822 if not repo:
1823 raise error.Abort(_("can't use --local outside a repository"))
1823 raise error.Abort(_("can't use --local outside a repository"))
1824 paths = [repo.join('hgrc')]
1824 paths = [repo.join('hgrc')]
1825 elif opts.get('global'):
1825 elif opts.get('global'):
1826 paths = scmutil.systemrcpath()
1826 paths = scmutil.systemrcpath()
1827 else:
1827 else:
1828 paths = scmutil.userrcpath()
1828 paths = scmutil.userrcpath()
1829
1829
1830 for f in paths:
1830 for f in paths:
1831 if os.path.exists(f):
1831 if os.path.exists(f):
1832 break
1832 break
1833 else:
1833 else:
1834 if opts.get('global'):
1834 if opts.get('global'):
1835 samplehgrc = uimod.samplehgrcs['global']
1835 samplehgrc = uimod.samplehgrcs['global']
1836 elif opts.get('local'):
1836 elif opts.get('local'):
1837 samplehgrc = uimod.samplehgrcs['local']
1837 samplehgrc = uimod.samplehgrcs['local']
1838 else:
1838 else:
1839 samplehgrc = uimod.samplehgrcs['user']
1839 samplehgrc = uimod.samplehgrcs['user']
1840
1840
1841 f = paths[0]
1841 f = paths[0]
1842 fp = open(f, "w")
1842 fp = open(f, "w")
1843 fp.write(samplehgrc)
1843 fp.write(samplehgrc)
1844 fp.close()
1844 fp.close()
1845
1845
1846 editor = ui.geteditor()
1846 editor = ui.geteditor()
1847 ui.system("%s \"%s\"" % (editor, f),
1847 ui.system("%s \"%s\"" % (editor, f),
1848 onerr=error.Abort, errprefix=_("edit failed"))
1848 onerr=error.Abort, errprefix=_("edit failed"))
1849 return
1849 return
1850
1850
1851 for f in scmutil.rcpath():
1851 for f in scmutil.rcpath():
1852 ui.debug('read config from: %s\n' % f)
1852 ui.debug('read config from: %s\n' % f)
1853 untrusted = bool(opts.get('untrusted'))
1853 untrusted = bool(opts.get('untrusted'))
1854 if values:
1854 if values:
1855 sections = [v for v in values if '.' not in v]
1855 sections = [v for v in values if '.' not in v]
1856 items = [v for v in values if '.' in v]
1856 items = [v for v in values if '.' in v]
1857 if len(items) > 1 or items and sections:
1857 if len(items) > 1 or items and sections:
1858 raise error.Abort(_('only one config item permitted'))
1858 raise error.Abort(_('only one config item permitted'))
1859 matched = False
1859 matched = False
1860 for section, name, value in ui.walkconfig(untrusted=untrusted):
1860 for section, name, value in ui.walkconfig(untrusted=untrusted):
1861 value = str(value).replace('\n', '\\n')
1861 value = str(value).replace('\n', '\\n')
1862 sectname = section + '.' + name
1862 sectname = section + '.' + name
1863 if values:
1863 if values:
1864 for v in values:
1864 for v in values:
1865 if v == section:
1865 if v == section:
1866 ui.debug('%s: ' %
1866 ui.debug('%s: ' %
1867 ui.configsource(section, name, untrusted))
1867 ui.configsource(section, name, untrusted))
1868 ui.write('%s=%s\n' % (sectname, value))
1868 ui.write('%s=%s\n' % (sectname, value))
1869 matched = True
1869 matched = True
1870 elif v == sectname:
1870 elif v == sectname:
1871 ui.debug('%s: ' %
1871 ui.debug('%s: ' %
1872 ui.configsource(section, name, untrusted))
1872 ui.configsource(section, name, untrusted))
1873 ui.write(value, '\n')
1873 ui.write(value, '\n')
1874 matched = True
1874 matched = True
1875 else:
1875 else:
1876 ui.debug('%s: ' %
1876 ui.debug('%s: ' %
1877 ui.configsource(section, name, untrusted))
1877 ui.configsource(section, name, untrusted))
1878 ui.write('%s=%s\n' % (sectname, value))
1878 ui.write('%s=%s\n' % (sectname, value))
1879 matched = True
1879 matched = True
1880 if matched:
1880 if matched:
1881 return 0
1881 return 0
1882 return 1
1882 return 1
1883
1883
1884 @command('copy|cp',
1884 @command('copy|cp',
1885 [('A', 'after', None, _('record a copy that has already occurred')),
1885 [('A', 'after', None, _('record a copy that has already occurred')),
1886 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1886 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1887 ] + walkopts + dryrunopts,
1887 ] + walkopts + dryrunopts,
1888 _('[OPTION]... [SOURCE]... DEST'))
1888 _('[OPTION]... [SOURCE]... DEST'))
1889 def copy(ui, repo, *pats, **opts):
1889 def copy(ui, repo, *pats, **opts):
1890 """mark files as copied for the next commit
1890 """mark files as copied for the next commit
1891
1891
1892 Mark dest as having copies of source files. If dest is a
1892 Mark dest as having copies of source files. If dest is a
1893 directory, copies are put in that directory. If dest is a file,
1893 directory, copies are put in that directory. If dest is a file,
1894 the source must be a single file.
1894 the source must be a single file.
1895
1895
1896 By default, this command copies the contents of files as they
1896 By default, this command copies the contents of files as they
1897 exist in the working directory. If invoked with -A/--after, the
1897 exist in the working directory. If invoked with -A/--after, the
1898 operation is recorded, but no copying is performed.
1898 operation is recorded, but no copying is performed.
1899
1899
1900 This command takes effect with the next commit. To undo a copy
1900 This command takes effect with the next commit. To undo a copy
1901 before that, see :hg:`revert`.
1901 before that, see :hg:`revert`.
1902
1902
1903 Returns 0 on success, 1 if errors are encountered.
1903 Returns 0 on success, 1 if errors are encountered.
1904 """
1904 """
1905 with repo.wlock(False):
1905 with repo.wlock(False):
1906 return cmdutil.copy(ui, repo, pats, opts)
1906 return cmdutil.copy(ui, repo, pats, opts)
1907
1907
1908 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1908 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1909 def debugancestor(ui, repo, *args):
1909 def debugancestor(ui, repo, *args):
1910 """find the ancestor revision of two revisions in a given index"""
1910 """find the ancestor revision of two revisions in a given index"""
1911 if len(args) == 3:
1911 if len(args) == 3:
1912 index, rev1, rev2 = args
1912 index, rev1, rev2 = args
1913 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1913 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1914 lookup = r.lookup
1914 lookup = r.lookup
1915 elif len(args) == 2:
1915 elif len(args) == 2:
1916 if not repo:
1916 if not repo:
1917 raise error.Abort(_("there is no Mercurial repository here "
1917 raise error.Abort(_("there is no Mercurial repository here "
1918 "(.hg not found)"))
1918 "(.hg not found)"))
1919 rev1, rev2 = args
1919 rev1, rev2 = args
1920 r = repo.changelog
1920 r = repo.changelog
1921 lookup = repo.lookup
1921 lookup = repo.lookup
1922 else:
1922 else:
1923 raise error.Abort(_('either two or three arguments required'))
1923 raise error.Abort(_('either two or three arguments required'))
1924 a = r.ancestor(lookup(rev1), lookup(rev2))
1924 a = r.ancestor(lookup(rev1), lookup(rev2))
1925 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1925 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1926
1926
1927 @command('debugbuilddag',
1927 @command('debugbuilddag',
1928 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1928 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1929 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1929 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1930 ('n', 'new-file', None, _('add new file at each rev'))],
1930 ('n', 'new-file', None, _('add new file at each rev'))],
1931 _('[OPTION]... [TEXT]'))
1931 _('[OPTION]... [TEXT]'))
1932 def debugbuilddag(ui, repo, text=None,
1932 def debugbuilddag(ui, repo, text=None,
1933 mergeable_file=False,
1933 mergeable_file=False,
1934 overwritten_file=False,
1934 overwritten_file=False,
1935 new_file=False):
1935 new_file=False):
1936 """builds a repo with a given DAG from scratch in the current empty repo
1936 """builds a repo with a given DAG from scratch in the current empty repo
1937
1937
1938 The description of the DAG is read from stdin if not given on the
1938 The description of the DAG is read from stdin if not given on the
1939 command line.
1939 command line.
1940
1940
1941 Elements:
1941 Elements:
1942
1942
1943 - "+n" is a linear run of n nodes based on the current default parent
1943 - "+n" is a linear run of n nodes based on the current default parent
1944 - "." is a single node based on the current default parent
1944 - "." is a single node based on the current default parent
1945 - "$" resets the default parent to null (implied at the start);
1945 - "$" resets the default parent to null (implied at the start);
1946 otherwise the default parent is always the last node created
1946 otherwise the default parent is always the last node created
1947 - "<p" sets the default parent to the backref p
1947 - "<p" sets the default parent to the backref p
1948 - "*p" is a fork at parent p, which is a backref
1948 - "*p" is a fork at parent p, which is a backref
1949 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1949 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1950 - "/p2" is a merge of the preceding node and p2
1950 - "/p2" is a merge of the preceding node and p2
1951 - ":tag" defines a local tag for the preceding node
1951 - ":tag" defines a local tag for the preceding node
1952 - "@branch" sets the named branch for subsequent nodes
1952 - "@branch" sets the named branch for subsequent nodes
1953 - "#...\\n" is a comment up to the end of the line
1953 - "#...\\n" is a comment up to the end of the line
1954
1954
1955 Whitespace between the above elements is ignored.
1955 Whitespace between the above elements is ignored.
1956
1956
1957 A backref is either
1957 A backref is either
1958
1958
1959 - a number n, which references the node curr-n, where curr is the current
1959 - a number n, which references the node curr-n, where curr is the current
1960 node, or
1960 node, or
1961 - the name of a local tag you placed earlier using ":tag", or
1961 - the name of a local tag you placed earlier using ":tag", or
1962 - empty to denote the default parent.
1962 - empty to denote the default parent.
1963
1963
1964 All string valued-elements are either strictly alphanumeric, or must
1964 All string valued-elements are either strictly alphanumeric, or must
1965 be enclosed in double quotes ("..."), with "\\" as escape character.
1965 be enclosed in double quotes ("..."), with "\\" as escape character.
1966 """
1966 """
1967
1967
1968 if text is None:
1968 if text is None:
1969 ui.status(_("reading DAG from stdin\n"))
1969 ui.status(_("reading DAG from stdin\n"))
1970 text = ui.fin.read()
1970 text = ui.fin.read()
1971
1971
1972 cl = repo.changelog
1972 cl = repo.changelog
1973 if len(cl) > 0:
1973 if len(cl) > 0:
1974 raise error.Abort(_('repository is not empty'))
1974 raise error.Abort(_('repository is not empty'))
1975
1975
1976 # determine number of revs in DAG
1976 # determine number of revs in DAG
1977 total = 0
1977 total = 0
1978 for type, data in dagparser.parsedag(text):
1978 for type, data in dagparser.parsedag(text):
1979 if type == 'n':
1979 if type == 'n':
1980 total += 1
1980 total += 1
1981
1981
1982 if mergeable_file:
1982 if mergeable_file:
1983 linesperrev = 2
1983 linesperrev = 2
1984 # make a file with k lines per rev
1984 # make a file with k lines per rev
1985 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1985 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1986 initialmergedlines.append("")
1986 initialmergedlines.append("")
1987
1987
1988 tags = []
1988 tags = []
1989
1989
1990 lock = tr = None
1990 lock = tr = None
1991 try:
1991 try:
1992 lock = repo.lock()
1992 lock = repo.lock()
1993 tr = repo.transaction("builddag")
1993 tr = repo.transaction("builddag")
1994
1994
1995 at = -1
1995 at = -1
1996 atbranch = 'default'
1996 atbranch = 'default'
1997 nodeids = []
1997 nodeids = []
1998 id = 0
1998 id = 0
1999 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1999 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2000 for type, data in dagparser.parsedag(text):
2000 for type, data in dagparser.parsedag(text):
2001 if type == 'n':
2001 if type == 'n':
2002 ui.note(('node %s\n' % str(data)))
2002 ui.note(('node %s\n' % str(data)))
2003 id, ps = data
2003 id, ps = data
2004
2004
2005 files = []
2005 files = []
2006 fctxs = {}
2006 fctxs = {}
2007
2007
2008 p2 = None
2008 p2 = None
2009 if mergeable_file:
2009 if mergeable_file:
2010 fn = "mf"
2010 fn = "mf"
2011 p1 = repo[ps[0]]
2011 p1 = repo[ps[0]]
2012 if len(ps) > 1:
2012 if len(ps) > 1:
2013 p2 = repo[ps[1]]
2013 p2 = repo[ps[1]]
2014 pa = p1.ancestor(p2)
2014 pa = p1.ancestor(p2)
2015 base, local, other = [x[fn].data() for x in (pa, p1,
2015 base, local, other = [x[fn].data() for x in (pa, p1,
2016 p2)]
2016 p2)]
2017 m3 = simplemerge.Merge3Text(base, local, other)
2017 m3 = simplemerge.Merge3Text(base, local, other)
2018 ml = [l.strip() for l in m3.merge_lines()]
2018 ml = [l.strip() for l in m3.merge_lines()]
2019 ml.append("")
2019 ml.append("")
2020 elif at > 0:
2020 elif at > 0:
2021 ml = p1[fn].data().split("\n")
2021 ml = p1[fn].data().split("\n")
2022 else:
2022 else:
2023 ml = initialmergedlines
2023 ml = initialmergedlines
2024 ml[id * linesperrev] += " r%i" % id
2024 ml[id * linesperrev] += " r%i" % id
2025 mergedtext = "\n".join(ml)
2025 mergedtext = "\n".join(ml)
2026 files.append(fn)
2026 files.append(fn)
2027 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2027 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2028
2028
2029 if overwritten_file:
2029 if overwritten_file:
2030 fn = "of"
2030 fn = "of"
2031 files.append(fn)
2031 files.append(fn)
2032 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2033
2033
2034 if new_file:
2034 if new_file:
2035 fn = "nf%i" % id
2035 fn = "nf%i" % id
2036 files.append(fn)
2036 files.append(fn)
2037 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2037 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2038 if len(ps) > 1:
2038 if len(ps) > 1:
2039 if not p2:
2039 if not p2:
2040 p2 = repo[ps[1]]
2040 p2 = repo[ps[1]]
2041 for fn in p2:
2041 for fn in p2:
2042 if fn.startswith("nf"):
2042 if fn.startswith("nf"):
2043 files.append(fn)
2043 files.append(fn)
2044 fctxs[fn] = p2[fn]
2044 fctxs[fn] = p2[fn]
2045
2045
2046 def fctxfn(repo, cx, path):
2046 def fctxfn(repo, cx, path):
2047 return fctxs.get(path)
2047 return fctxs.get(path)
2048
2048
2049 if len(ps) == 0 or ps[0] < 0:
2049 if len(ps) == 0 or ps[0] < 0:
2050 pars = [None, None]
2050 pars = [None, None]
2051 elif len(ps) == 1:
2051 elif len(ps) == 1:
2052 pars = [nodeids[ps[0]], None]
2052 pars = [nodeids[ps[0]], None]
2053 else:
2053 else:
2054 pars = [nodeids[p] for p in ps]
2054 pars = [nodeids[p] for p in ps]
2055 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2055 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2056 date=(id, 0),
2056 date=(id, 0),
2057 user="debugbuilddag",
2057 user="debugbuilddag",
2058 extra={'branch': atbranch})
2058 extra={'branch': atbranch})
2059 nodeid = repo.commitctx(cx)
2059 nodeid = repo.commitctx(cx)
2060 nodeids.append(nodeid)
2060 nodeids.append(nodeid)
2061 at = id
2061 at = id
2062 elif type == 'l':
2062 elif type == 'l':
2063 id, name = data
2063 id, name = data
2064 ui.note(('tag %s\n' % name))
2064 ui.note(('tag %s\n' % name))
2065 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2065 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2066 elif type == 'a':
2066 elif type == 'a':
2067 ui.note(('branch %s\n' % data))
2067 ui.note(('branch %s\n' % data))
2068 atbranch = data
2068 atbranch = data
2069 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2069 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2070 tr.close()
2070 tr.close()
2071
2071
2072 if tags:
2072 if tags:
2073 repo.vfs.write("localtags", "".join(tags))
2073 repo.vfs.write("localtags", "".join(tags))
2074 finally:
2074 finally:
2075 ui.progress(_('building'), None)
2075 ui.progress(_('building'), None)
2076 release(tr, lock)
2076 release(tr, lock)
2077
2077
2078 @command('debugbundle',
2078 @command('debugbundle',
2079 [('a', 'all', None, _('show all details')),
2079 [('a', 'all', None, _('show all details')),
2080 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2080 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2081 _('FILE'),
2081 _('FILE'),
2082 norepo=True)
2082 norepo=True)
2083 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2083 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2084 """lists the contents of a bundle"""
2084 """lists the contents of a bundle"""
2085 with hg.openpath(ui, bundlepath) as f:
2085 with hg.openpath(ui, bundlepath) as f:
2086 if spec:
2086 if spec:
2087 spec = exchange.getbundlespec(ui, f)
2087 spec = exchange.getbundlespec(ui, f)
2088 ui.write('%s\n' % spec)
2088 ui.write('%s\n' % spec)
2089 return
2089 return
2090
2090
2091 gen = exchange.readbundle(ui, f, bundlepath)
2091 gen = exchange.readbundle(ui, f, bundlepath)
2092 if isinstance(gen, bundle2.unbundle20):
2092 if isinstance(gen, bundle2.unbundle20):
2093 return _debugbundle2(ui, gen, all=all, **opts)
2093 return _debugbundle2(ui, gen, all=all, **opts)
2094 _debugchangegroup(ui, gen, all=all, **opts)
2094 _debugchangegroup(ui, gen, all=all, **opts)
2095
2095
2096 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2096 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2097 indent_string = ' ' * indent
2097 indent_string = ' ' * indent
2098 if all:
2098 if all:
2099 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2099 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2100 % indent_string)
2100 % indent_string)
2101
2101
2102 def showchunks(named):
2102 def showchunks(named):
2103 ui.write("\n%s%s\n" % (indent_string, named))
2103 ui.write("\n%s%s\n" % (indent_string, named))
2104 chain = None
2104 chain = None
2105 while True:
2105 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2106 chunkdata = gen.deltachunk(chain)
2107 if not chunkdata:
2108 break
2109 node = chunkdata['node']
2106 node = chunkdata['node']
2110 p1 = chunkdata['p1']
2107 p1 = chunkdata['p1']
2111 p2 = chunkdata['p2']
2108 p2 = chunkdata['p2']
2112 cs = chunkdata['cs']
2109 cs = chunkdata['cs']
2113 deltabase = chunkdata['deltabase']
2110 deltabase = chunkdata['deltabase']
2114 delta = chunkdata['delta']
2111 delta = chunkdata['delta']
2115 ui.write("%s%s %s %s %s %s %s\n" %
2112 ui.write("%s%s %s %s %s %s %s\n" %
2116 (indent_string, hex(node), hex(p1), hex(p2),
2113 (indent_string, hex(node), hex(p1), hex(p2),
2117 hex(cs), hex(deltabase), len(delta)))
2114 hex(cs), hex(deltabase), len(delta)))
2118 chain = node
2115 chain = node
2119
2116
2120 chunkdata = gen.changelogheader()
2117 chunkdata = gen.changelogheader()
2121 showchunks("changelog")
2118 showchunks("changelog")
2122 chunkdata = gen.manifestheader()
2119 chunkdata = gen.manifestheader()
2123 showchunks("manifest")
2120 showchunks("manifest")
2124 while True:
2121 for chunkdata in iter(gen.filelogheader, {}):
2125 chunkdata = gen.filelogheader()
2126 if not chunkdata:
2127 break
2128 fname = chunkdata['filename']
2122 fname = chunkdata['filename']
2129 showchunks(fname)
2123 showchunks(fname)
2130 else:
2124 else:
2131 if isinstance(gen, bundle2.unbundle20):
2125 if isinstance(gen, bundle2.unbundle20):
2132 raise error.Abort(_('use debugbundle2 for this file'))
2126 raise error.Abort(_('use debugbundle2 for this file'))
2133 chunkdata = gen.changelogheader()
2127 chunkdata = gen.changelogheader()
2134 chain = None
2128 chain = None
2135 while True:
2129 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2136 chunkdata = gen.deltachunk(chain)
2137 if not chunkdata:
2138 break
2139 node = chunkdata['node']
2130 node = chunkdata['node']
2140 ui.write("%s%s\n" % (indent_string, hex(node)))
2131 ui.write("%s%s\n" % (indent_string, hex(node)))
2141 chain = node
2132 chain = node
2142
2133
2143 def _debugbundle2(ui, gen, all=None, **opts):
2134 def _debugbundle2(ui, gen, all=None, **opts):
2144 """lists the contents of a bundle2"""
2135 """lists the contents of a bundle2"""
2145 if not isinstance(gen, bundle2.unbundle20):
2136 if not isinstance(gen, bundle2.unbundle20):
2146 raise error.Abort(_('not a bundle2 file'))
2137 raise error.Abort(_('not a bundle2 file'))
2147 ui.write(('Stream params: %s\n' % repr(gen.params)))
2138 ui.write(('Stream params: %s\n' % repr(gen.params)))
2148 for part in gen.iterparts():
2139 for part in gen.iterparts():
2149 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2140 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2150 if part.type == 'changegroup':
2141 if part.type == 'changegroup':
2151 version = part.params.get('version', '01')
2142 version = part.params.get('version', '01')
2152 cg = changegroup.getunbundler(version, part, 'UN')
2143 cg = changegroup.getunbundler(version, part, 'UN')
2153 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2144 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2154
2145
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2146 @command('debugcreatestreamclonebundle', [], 'FILE')
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2147 def debugcreatestreamclonebundle(ui, repo, fname):
2157 """create a stream clone bundle file
2148 """create a stream clone bundle file
2158
2149
2159 Stream bundles are special bundles that are essentially archives of
2150 Stream bundles are special bundles that are essentially archives of
2160 revlog files. They are commonly used for cloning very quickly.
2151 revlog files. They are commonly used for cloning very quickly.
2161 """
2152 """
2162 requirements, gen = streamclone.generatebundlev1(repo)
2153 requirements, gen = streamclone.generatebundlev1(repo)
2163 changegroup.writechunks(ui, gen, fname)
2154 changegroup.writechunks(ui, gen, fname)
2164
2155
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2156 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2166
2157
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2158 @command('debugapplystreamclonebundle', [], 'FILE')
2168 def debugapplystreamclonebundle(ui, repo, fname):
2159 def debugapplystreamclonebundle(ui, repo, fname):
2169 """apply a stream clone bundle file"""
2160 """apply a stream clone bundle file"""
2170 f = hg.openpath(ui, fname)
2161 f = hg.openpath(ui, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2162 gen = exchange.readbundle(ui, f, fname)
2172 gen.apply(repo)
2163 gen.apply(repo)
2173
2164
2174 @command('debugcheckstate', [], '')
2165 @command('debugcheckstate', [], '')
2175 def debugcheckstate(ui, repo):
2166 def debugcheckstate(ui, repo):
2176 """validate the correctness of the current dirstate"""
2167 """validate the correctness of the current dirstate"""
2177 parent1, parent2 = repo.dirstate.parents()
2168 parent1, parent2 = repo.dirstate.parents()
2178 m1 = repo[parent1].manifest()
2169 m1 = repo[parent1].manifest()
2179 m2 = repo[parent2].manifest()
2170 m2 = repo[parent2].manifest()
2180 errors = 0
2171 errors = 0
2181 for f in repo.dirstate:
2172 for f in repo.dirstate:
2182 state = repo.dirstate[f]
2173 state = repo.dirstate[f]
2183 if state in "nr" and f not in m1:
2174 if state in "nr" and f not in m1:
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2175 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2185 errors += 1
2176 errors += 1
2186 if state in "a" and f in m1:
2177 if state in "a" and f in m1:
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2178 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2188 errors += 1
2179 errors += 1
2189 if state in "m" and f not in m1 and f not in m2:
2180 if state in "m" and f not in m1 and f not in m2:
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2181 ui.warn(_("%s in state %s, but not in either manifest\n") %
2191 (f, state))
2182 (f, state))
2192 errors += 1
2183 errors += 1
2193 for f in m1:
2184 for f in m1:
2194 state = repo.dirstate[f]
2185 state = repo.dirstate[f]
2195 if state not in "nrm":
2186 if state not in "nrm":
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2187 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2197 errors += 1
2188 errors += 1
2198 if errors:
2189 if errors:
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2190 error = _(".hg/dirstate inconsistent with current parent's manifest")
2200 raise error.Abort(error)
2191 raise error.Abort(error)
2201
2192
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2193 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2203 def debugcommands(ui, cmd='', *args):
2194 def debugcommands(ui, cmd='', *args):
2204 """list all available commands and options"""
2195 """list all available commands and options"""
2205 for cmd, vals in sorted(table.iteritems()):
2196 for cmd, vals in sorted(table.iteritems()):
2206 cmd = cmd.split('|')[0].strip('^')
2197 cmd = cmd.split('|')[0].strip('^')
2207 opts = ', '.join([i[1] for i in vals[1]])
2198 opts = ', '.join([i[1] for i in vals[1]])
2208 ui.write('%s: %s\n' % (cmd, opts))
2199 ui.write('%s: %s\n' % (cmd, opts))
2209
2200
2210 @command('debugcomplete',
2201 @command('debugcomplete',
2211 [('o', 'options', None, _('show the command options'))],
2202 [('o', 'options', None, _('show the command options'))],
2212 _('[-o] CMD'),
2203 _('[-o] CMD'),
2213 norepo=True)
2204 norepo=True)
2214 def debugcomplete(ui, cmd='', **opts):
2205 def debugcomplete(ui, cmd='', **opts):
2215 """returns the completion list associated with the given command"""
2206 """returns the completion list associated with the given command"""
2216
2207
2217 if opts.get('options'):
2208 if opts.get('options'):
2218 options = []
2209 options = []
2219 otables = [globalopts]
2210 otables = [globalopts]
2220 if cmd:
2211 if cmd:
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2212 aliases, entry = cmdutil.findcmd(cmd, table, False)
2222 otables.append(entry[1])
2213 otables.append(entry[1])
2223 for t in otables:
2214 for t in otables:
2224 for o in t:
2215 for o in t:
2225 if "(DEPRECATED)" in o[3]:
2216 if "(DEPRECATED)" in o[3]:
2226 continue
2217 continue
2227 if o[0]:
2218 if o[0]:
2228 options.append('-%s' % o[0])
2219 options.append('-%s' % o[0])
2229 options.append('--%s' % o[1])
2220 options.append('--%s' % o[1])
2230 ui.write("%s\n" % "\n".join(options))
2221 ui.write("%s\n" % "\n".join(options))
2231 return
2222 return
2232
2223
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2224 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2234 if ui.verbose:
2225 if ui.verbose:
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2226 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2227 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2237
2228
2238 @command('debugdag',
2229 @command('debugdag',
2239 [('t', 'tags', None, _('use tags as labels')),
2230 [('t', 'tags', None, _('use tags as labels')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2231 ('b', 'branches', None, _('annotate with branch names')),
2241 ('', 'dots', None, _('use dots for runs')),
2232 ('', 'dots', None, _('use dots for runs')),
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2233 ('s', 'spaces', None, _('separate elements by spaces'))],
2243 _('[OPTION]... [FILE [REV]...]'),
2234 _('[OPTION]... [FILE [REV]...]'),
2244 optionalrepo=True)
2235 optionalrepo=True)
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2236 def debugdag(ui, repo, file_=None, *revs, **opts):
2246 """format the changelog or an index DAG as a concise textual description
2237 """format the changelog or an index DAG as a concise textual description
2247
2238
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2239 If you pass a revlog index, the revlog's DAG is emitted. If you list
2249 revision numbers, they get labeled in the output as rN.
2240 revision numbers, they get labeled in the output as rN.
2250
2241
2251 Otherwise, the changelog DAG of the current repo is emitted.
2242 Otherwise, the changelog DAG of the current repo is emitted.
2252 """
2243 """
2253 spaces = opts.get('spaces')
2244 spaces = opts.get('spaces')
2254 dots = opts.get('dots')
2245 dots = opts.get('dots')
2255 if file_:
2246 if file_:
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2247 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2257 revs = set((int(r) for r in revs))
2248 revs = set((int(r) for r in revs))
2258 def events():
2249 def events():
2259 for r in rlog:
2250 for r in rlog:
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2251 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2261 if p != -1))
2252 if p != -1))
2262 if r in revs:
2253 if r in revs:
2263 yield 'l', (r, "r%i" % r)
2254 yield 'l', (r, "r%i" % r)
2264 elif repo:
2255 elif repo:
2265 cl = repo.changelog
2256 cl = repo.changelog
2266 tags = opts.get('tags')
2257 tags = opts.get('tags')
2267 branches = opts.get('branches')
2258 branches = opts.get('branches')
2268 if tags:
2259 if tags:
2269 labels = {}
2260 labels = {}
2270 for l, n in repo.tags().items():
2261 for l, n in repo.tags().items():
2271 labels.setdefault(cl.rev(n), []).append(l)
2262 labels.setdefault(cl.rev(n), []).append(l)
2272 def events():
2263 def events():
2273 b = "default"
2264 b = "default"
2274 for r in cl:
2265 for r in cl:
2275 if branches:
2266 if branches:
2276 newb = cl.read(cl.node(r))[5]['branch']
2267 newb = cl.read(cl.node(r))[5]['branch']
2277 if newb != b:
2268 if newb != b:
2278 yield 'a', newb
2269 yield 'a', newb
2279 b = newb
2270 b = newb
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2271 yield 'n', (r, list(p for p in cl.parentrevs(r)
2281 if p != -1))
2272 if p != -1))
2282 if tags:
2273 if tags:
2283 ls = labels.get(r)
2274 ls = labels.get(r)
2284 if ls:
2275 if ls:
2285 for l in ls:
2276 for l in ls:
2286 yield 'l', (r, l)
2277 yield 'l', (r, l)
2287 else:
2278 else:
2288 raise error.Abort(_('need repo for changelog dag'))
2279 raise error.Abort(_('need repo for changelog dag'))
2289
2280
2290 for line in dagparser.dagtextlines(events(),
2281 for line in dagparser.dagtextlines(events(),
2291 addspaces=spaces,
2282 addspaces=spaces,
2292 wraplabels=True,
2283 wraplabels=True,
2293 wrapannotations=True,
2284 wrapannotations=True,
2294 wrapnonlinear=dots,
2285 wrapnonlinear=dots,
2295 usedots=dots,
2286 usedots=dots,
2296 maxlinewidth=70):
2287 maxlinewidth=70):
2297 ui.write(line)
2288 ui.write(line)
2298 ui.write("\n")
2289 ui.write("\n")
2299
2290
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2291 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2292 def debugdata(ui, repo, file_, rev=None, **opts):
2302 """dump the contents of a data file revision"""
2293 """dump the contents of a data file revision"""
2303 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2294 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2304 if rev is not None:
2295 if rev is not None:
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2296 raise error.CommandError('debugdata', _('invalid arguments'))
2306 file_, rev = None, file_
2297 file_, rev = None, file_
2307 elif rev is None:
2298 elif rev is None:
2308 raise error.CommandError('debugdata', _('invalid arguments'))
2299 raise error.CommandError('debugdata', _('invalid arguments'))
2309 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2300 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2310 try:
2301 try:
2311 ui.write(r.revision(r.lookup(rev)))
2302 ui.write(r.revision(r.lookup(rev)))
2312 except KeyError:
2303 except KeyError:
2313 raise error.Abort(_('invalid revision identifier %s') % rev)
2304 raise error.Abort(_('invalid revision identifier %s') % rev)
2314
2305
2315 @command('debugdate',
2306 @command('debugdate',
2316 [('e', 'extended', None, _('try extended date formats'))],
2307 [('e', 'extended', None, _('try extended date formats'))],
2317 _('[-e] DATE [RANGE]'),
2308 _('[-e] DATE [RANGE]'),
2318 norepo=True, optionalrepo=True)
2309 norepo=True, optionalrepo=True)
2319 def debugdate(ui, date, range=None, **opts):
2310 def debugdate(ui, date, range=None, **opts):
2320 """parse and display a date"""
2311 """parse and display a date"""
2321 if opts["extended"]:
2312 if opts["extended"]:
2322 d = util.parsedate(date, util.extendeddateformats)
2313 d = util.parsedate(date, util.extendeddateformats)
2323 else:
2314 else:
2324 d = util.parsedate(date)
2315 d = util.parsedate(date)
2325 ui.write(("internal: %s %s\n") % d)
2316 ui.write(("internal: %s %s\n") % d)
2326 ui.write(("standard: %s\n") % util.datestr(d))
2317 ui.write(("standard: %s\n") % util.datestr(d))
2327 if range:
2318 if range:
2328 m = util.matchdate(range)
2319 m = util.matchdate(range)
2329 ui.write(("match: %s\n") % m(d[0]))
2320 ui.write(("match: %s\n") % m(d[0]))
2330
2321
2331 @command('debugdiscovery',
2322 @command('debugdiscovery',
2332 [('', 'old', None, _('use old-style discovery')),
2323 [('', 'old', None, _('use old-style discovery')),
2333 ('', 'nonheads', None,
2324 ('', 'nonheads', None,
2334 _('use old-style discovery with non-heads included')),
2325 _('use old-style discovery with non-heads included')),
2335 ] + remoteopts,
2326 ] + remoteopts,
2336 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2327 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2337 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2328 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2338 """runs the changeset discovery protocol in isolation"""
2329 """runs the changeset discovery protocol in isolation"""
2339 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2330 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2340 opts.get('branch'))
2331 opts.get('branch'))
2341 remote = hg.peer(repo, opts, remoteurl)
2332 remote = hg.peer(repo, opts, remoteurl)
2342 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2333 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2343
2334
2344 # make sure tests are repeatable
2335 # make sure tests are repeatable
2345 random.seed(12323)
2336 random.seed(12323)
2346
2337
2347 def doit(localheads, remoteheads, remote=remote):
2338 def doit(localheads, remoteheads, remote=remote):
2348 if opts.get('old'):
2339 if opts.get('old'):
2349 if localheads:
2340 if localheads:
2350 raise error.Abort('cannot use localheads with old style '
2341 raise error.Abort('cannot use localheads with old style '
2351 'discovery')
2342 'discovery')
2352 if not util.safehasattr(remote, 'branches'):
2343 if not util.safehasattr(remote, 'branches'):
2353 # enable in-client legacy support
2344 # enable in-client legacy support
2354 remote = localrepo.locallegacypeer(remote.local())
2345 remote = localrepo.locallegacypeer(remote.local())
2355 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2346 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2356 force=True)
2347 force=True)
2357 common = set(common)
2348 common = set(common)
2358 if not opts.get('nonheads'):
2349 if not opts.get('nonheads'):
2359 ui.write(("unpruned common: %s\n") %
2350 ui.write(("unpruned common: %s\n") %
2360 " ".join(sorted(short(n) for n in common)))
2351 " ".join(sorted(short(n) for n in common)))
2361 dag = dagutil.revlogdag(repo.changelog)
2352 dag = dagutil.revlogdag(repo.changelog)
2362 all = dag.ancestorset(dag.internalizeall(common))
2353 all = dag.ancestorset(dag.internalizeall(common))
2363 common = dag.externalizeall(dag.headsetofconnecteds(all))
2354 common = dag.externalizeall(dag.headsetofconnecteds(all))
2364 else:
2355 else:
2365 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2356 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2366 common = set(common)
2357 common = set(common)
2367 rheads = set(hds)
2358 rheads = set(hds)
2368 lheads = set(repo.heads())
2359 lheads = set(repo.heads())
2369 ui.write(("common heads: %s\n") %
2360 ui.write(("common heads: %s\n") %
2370 " ".join(sorted(short(n) for n in common)))
2361 " ".join(sorted(short(n) for n in common)))
2371 if lheads <= common:
2362 if lheads <= common:
2372 ui.write(("local is subset\n"))
2363 ui.write(("local is subset\n"))
2373 elif rheads <= common:
2364 elif rheads <= common:
2374 ui.write(("remote is subset\n"))
2365 ui.write(("remote is subset\n"))
2375
2366
2376 serverlogs = opts.get('serverlog')
2367 serverlogs = opts.get('serverlog')
2377 if serverlogs:
2368 if serverlogs:
2378 for filename in serverlogs:
2369 for filename in serverlogs:
2379 with open(filename, 'r') as logfile:
2370 with open(filename, 'r') as logfile:
2380 line = logfile.readline()
2371 line = logfile.readline()
2381 while line:
2372 while line:
2382 parts = line.strip().split(';')
2373 parts = line.strip().split(';')
2383 op = parts[1]
2374 op = parts[1]
2384 if op == 'cg':
2375 if op == 'cg':
2385 pass
2376 pass
2386 elif op == 'cgss':
2377 elif op == 'cgss':
2387 doit(parts[2].split(' '), parts[3].split(' '))
2378 doit(parts[2].split(' '), parts[3].split(' '))
2388 elif op == 'unb':
2379 elif op == 'unb':
2389 doit(parts[3].split(' '), parts[2].split(' '))
2380 doit(parts[3].split(' '), parts[2].split(' '))
2390 line = logfile.readline()
2381 line = logfile.readline()
2391 else:
2382 else:
2392 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2383 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2393 opts.get('remote_head'))
2384 opts.get('remote_head'))
2394 localrevs = opts.get('local_head')
2385 localrevs = opts.get('local_head')
2395 doit(localrevs, remoterevs)
2386 doit(localrevs, remoterevs)
2396
2387
2397 @command('debugextensions', formatteropts, [], norepo=True)
2388 @command('debugextensions', formatteropts, [], norepo=True)
2398 def debugextensions(ui, **opts):
2389 def debugextensions(ui, **opts):
2399 '''show information about active extensions'''
2390 '''show information about active extensions'''
2400 exts = extensions.extensions(ui)
2391 exts = extensions.extensions(ui)
2401 hgver = util.version()
2392 hgver = util.version()
2402 fm = ui.formatter('debugextensions', opts)
2393 fm = ui.formatter('debugextensions', opts)
2403 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2394 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2404 extsource = extmod.__file__
2395 extsource = extmod.__file__
2405 exttestedwith = getattr(extmod, 'testedwith', '').split()
2396 exttestedwith = getattr(extmod, 'testedwith', '').split()
2406 extbuglink = getattr(extmod, 'buglink', None)
2397 extbuglink = getattr(extmod, 'buglink', None)
2407
2398
2408 fm.startitem()
2399 fm.startitem()
2409
2400
2410 if ui.quiet or ui.verbose:
2401 if ui.quiet or ui.verbose:
2411 fm.write('name', '%s\n', extname)
2402 fm.write('name', '%s\n', extname)
2412 else:
2403 else:
2413 fm.write('name', '%s', extname)
2404 fm.write('name', '%s', extname)
2414 if not exttestedwith:
2405 if not exttestedwith:
2415 fm.plain(_(' (untested!)\n'))
2406 fm.plain(_(' (untested!)\n'))
2416 elif exttestedwith == ['internal'] or hgver in exttestedwith:
2407 elif exttestedwith == ['internal'] or hgver in exttestedwith:
2417 fm.plain('\n')
2408 fm.plain('\n')
2418 else:
2409 else:
2419 lasttestedversion = exttestedwith[-1]
2410 lasttestedversion = exttestedwith[-1]
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2411 fm.plain(' (%s!)\n' % lasttestedversion)
2421
2412
2422 fm.condwrite(ui.verbose and extsource, 'source',
2413 fm.condwrite(ui.verbose and extsource, 'source',
2423 _(' location: %s\n'), extsource or "")
2414 _(' location: %s\n'), extsource or "")
2424
2415
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2416 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 _(' tested with: %s\n'),
2417 _(' tested with: %s\n'),
2427 fm.formatlist(exttestedwith, name='ver'))
2418 fm.formatlist(exttestedwith, name='ver'))
2428
2419
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2420 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2430 _(' bug reporting: %s\n'), extbuglink or "")
2421 _(' bug reporting: %s\n'), extbuglink or "")
2431
2422
2432 fm.end()
2423 fm.end()
2433
2424
2434 @command('debugfileset',
2425 @command('debugfileset',
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2426 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2436 _('[-r REV] FILESPEC'))
2427 _('[-r REV] FILESPEC'))
2437 def debugfileset(ui, repo, expr, **opts):
2428 def debugfileset(ui, repo, expr, **opts):
2438 '''parse and apply a fileset specification'''
2429 '''parse and apply a fileset specification'''
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2430 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2440 if ui.verbose:
2431 if ui.verbose:
2441 tree = fileset.parse(expr)
2432 tree = fileset.parse(expr)
2442 ui.note(fileset.prettyformat(tree), "\n")
2433 ui.note(fileset.prettyformat(tree), "\n")
2443
2434
2444 for f in ctx.getfileset(expr):
2435 for f in ctx.getfileset(expr):
2445 ui.write("%s\n" % f)
2436 ui.write("%s\n" % f)
2446
2437
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2438 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2448 def debugfsinfo(ui, path="."):
2439 def debugfsinfo(ui, path="."):
2449 """show information detected about current filesystem"""
2440 """show information detected about current filesystem"""
2450 util.writefile('.debugfsinfo', '')
2441 util.writefile('.debugfsinfo', '')
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2442 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2443 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2444 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2445 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2455 and 'yes' or 'no'))
2446 and 'yes' or 'no'))
2456 os.unlink('.debugfsinfo')
2447 os.unlink('.debugfsinfo')
2457
2448
2458 @command('debuggetbundle',
2449 @command('debuggetbundle',
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2450 [('H', 'head', [], _('id of head node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2451 ('C', 'common', [], _('id of common node'), _('ID')),
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2452 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2462 _('REPO FILE [-H|-C ID]...'),
2453 _('REPO FILE [-H|-C ID]...'),
2463 norepo=True)
2454 norepo=True)
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2455 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2465 """retrieves a bundle from a repo
2456 """retrieves a bundle from a repo
2466
2457
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2458 Every ID must be a full-length hex node id string. Saves the bundle to the
2468 given file.
2459 given file.
2469 """
2460 """
2470 repo = hg.peer(ui, opts, repopath)
2461 repo = hg.peer(ui, opts, repopath)
2471 if not repo.capable('getbundle'):
2462 if not repo.capable('getbundle'):
2472 raise error.Abort("getbundle() not supported by target repository")
2463 raise error.Abort("getbundle() not supported by target repository")
2473 args = {}
2464 args = {}
2474 if common:
2465 if common:
2475 args['common'] = [bin(s) for s in common]
2466 args['common'] = [bin(s) for s in common]
2476 if head:
2467 if head:
2477 args['heads'] = [bin(s) for s in head]
2468 args['heads'] = [bin(s) for s in head]
2478 # TODO: get desired bundlecaps from command line.
2469 # TODO: get desired bundlecaps from command line.
2479 args['bundlecaps'] = None
2470 args['bundlecaps'] = None
2480 bundle = repo.getbundle('debug', **args)
2471 bundle = repo.getbundle('debug', **args)
2481
2472
2482 bundletype = opts.get('type', 'bzip2').lower()
2473 bundletype = opts.get('type', 'bzip2').lower()
2483 btypes = {'none': 'HG10UN',
2474 btypes = {'none': 'HG10UN',
2484 'bzip2': 'HG10BZ',
2475 'bzip2': 'HG10BZ',
2485 'gzip': 'HG10GZ',
2476 'gzip': 'HG10GZ',
2486 'bundle2': 'HG20'}
2477 'bundle2': 'HG20'}
2487 bundletype = btypes.get(bundletype)
2478 bundletype = btypes.get(bundletype)
2488 if bundletype not in bundle2.bundletypes:
2479 if bundletype not in bundle2.bundletypes:
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2480 raise error.Abort(_('unknown bundle type specified with --type'))
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2481 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2491
2482
2492 @command('debugignore', [], '[FILE]')
2483 @command('debugignore', [], '[FILE]')
2493 def debugignore(ui, repo, *files, **opts):
2484 def debugignore(ui, repo, *files, **opts):
2494 """display the combined ignore pattern and information about ignored files
2485 """display the combined ignore pattern and information about ignored files
2495
2486
2496 With no argument display the combined ignore pattern.
2487 With no argument display the combined ignore pattern.
2497
2488
2498 Given space separated file names, shows if the given file is ignored and
2489 Given space separated file names, shows if the given file is ignored and
2499 if so, show the ignore rule (file and line number) that matched it.
2490 if so, show the ignore rule (file and line number) that matched it.
2500 """
2491 """
2501 ignore = repo.dirstate._ignore
2492 ignore = repo.dirstate._ignore
2502 if not files:
2493 if not files:
2503 # Show all the patterns
2494 # Show all the patterns
2504 includepat = getattr(ignore, 'includepat', None)
2495 includepat = getattr(ignore, 'includepat', None)
2505 if includepat is not None:
2496 if includepat is not None:
2506 ui.write("%s\n" % includepat)
2497 ui.write("%s\n" % includepat)
2507 else:
2498 else:
2508 raise error.Abort(_("no ignore patterns found"))
2499 raise error.Abort(_("no ignore patterns found"))
2509 else:
2500 else:
2510 for f in files:
2501 for f in files:
2511 nf = util.normpath(f)
2502 nf = util.normpath(f)
2512 ignored = None
2503 ignored = None
2513 ignoredata = None
2504 ignoredata = None
2514 if nf != '.':
2505 if nf != '.':
2515 if ignore(nf):
2506 if ignore(nf):
2516 ignored = nf
2507 ignored = nf
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2508 ignoredata = repo.dirstate._ignorefileandline(nf)
2518 else:
2509 else:
2519 for p in util.finddirs(nf):
2510 for p in util.finddirs(nf):
2520 if ignore(p):
2511 if ignore(p):
2521 ignored = p
2512 ignored = p
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2513 ignoredata = repo.dirstate._ignorefileandline(p)
2523 break
2514 break
2524 if ignored:
2515 if ignored:
2525 if ignored == nf:
2516 if ignored == nf:
2526 ui.write(_("%s is ignored\n") % f)
2517 ui.write(_("%s is ignored\n") % f)
2527 else:
2518 else:
2528 ui.write(_("%s is ignored because of "
2519 ui.write(_("%s is ignored because of "
2529 "containing folder %s\n")
2520 "containing folder %s\n")
2530 % (f, ignored))
2521 % (f, ignored))
2531 ignorefile, lineno, line = ignoredata
2522 ignorefile, lineno, line = ignoredata
2532 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2523 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2533 % (ignorefile, lineno, line))
2524 % (ignorefile, lineno, line))
2534 else:
2525 else:
2535 ui.write(_("%s is not ignored\n") % f)
2526 ui.write(_("%s is not ignored\n") % f)
2536
2527
2537 @command('debugindex', debugrevlogopts +
2528 @command('debugindex', debugrevlogopts +
2538 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2529 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2539 _('[-f FORMAT] -c|-m|FILE'),
2530 _('[-f FORMAT] -c|-m|FILE'),
2540 optionalrepo=True)
2531 optionalrepo=True)
2541 def debugindex(ui, repo, file_=None, **opts):
2532 def debugindex(ui, repo, file_=None, **opts):
2542 """dump the contents of an index file"""
2533 """dump the contents of an index file"""
2543 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2534 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2544 format = opts.get('format', 0)
2535 format = opts.get('format', 0)
2545 if format not in (0, 1):
2536 if format not in (0, 1):
2546 raise error.Abort(_("unknown format %d") % format)
2537 raise error.Abort(_("unknown format %d") % format)
2547
2538
2548 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2539 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2549 if generaldelta:
2540 if generaldelta:
2550 basehdr = ' delta'
2541 basehdr = ' delta'
2551 else:
2542 else:
2552 basehdr = ' base'
2543 basehdr = ' base'
2553
2544
2554 if ui.debugflag:
2545 if ui.debugflag:
2555 shortfn = hex
2546 shortfn = hex
2556 else:
2547 else:
2557 shortfn = short
2548 shortfn = short
2558
2549
2559 # There might not be anything in r, so have a sane default
2550 # There might not be anything in r, so have a sane default
2560 idlen = 12
2551 idlen = 12
2561 for i in r:
2552 for i in r:
2562 idlen = len(shortfn(r.node(i)))
2553 idlen = len(shortfn(r.node(i)))
2563 break
2554 break
2564
2555
2565 if format == 0:
2556 if format == 0:
2566 ui.write((" rev offset length " + basehdr + " linkrev"
2557 ui.write((" rev offset length " + basehdr + " linkrev"
2567 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2558 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2568 elif format == 1:
2559 elif format == 1:
2569 ui.write((" rev flag offset length"
2560 ui.write((" rev flag offset length"
2570 " size " + basehdr + " link p1 p2"
2561 " size " + basehdr + " link p1 p2"
2571 " %s\n") % "nodeid".rjust(idlen))
2562 " %s\n") % "nodeid".rjust(idlen))
2572
2563
2573 for i in r:
2564 for i in r:
2574 node = r.node(i)
2565 node = r.node(i)
2575 if generaldelta:
2566 if generaldelta:
2576 base = r.deltaparent(i)
2567 base = r.deltaparent(i)
2577 else:
2568 else:
2578 base = r.chainbase(i)
2569 base = r.chainbase(i)
2579 if format == 0:
2570 if format == 0:
2580 try:
2571 try:
2581 pp = r.parents(node)
2572 pp = r.parents(node)
2582 except Exception:
2573 except Exception:
2583 pp = [nullid, nullid]
2574 pp = [nullid, nullid]
2584 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2575 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2585 i, r.start(i), r.length(i), base, r.linkrev(i),
2576 i, r.start(i), r.length(i), base, r.linkrev(i),
2586 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2577 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2587 elif format == 1:
2578 elif format == 1:
2588 pr = r.parentrevs(i)
2579 pr = r.parentrevs(i)
2589 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2580 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2590 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2581 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2591 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2582 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2592
2583
2593 @command('debugindexdot', debugrevlogopts,
2584 @command('debugindexdot', debugrevlogopts,
2594 _('-c|-m|FILE'), optionalrepo=True)
2585 _('-c|-m|FILE'), optionalrepo=True)
2595 def debugindexdot(ui, repo, file_=None, **opts):
2586 def debugindexdot(ui, repo, file_=None, **opts):
2596 """dump an index DAG as a graphviz dot file"""
2587 """dump an index DAG as a graphviz dot file"""
2597 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2588 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2598 ui.write(("digraph G {\n"))
2589 ui.write(("digraph G {\n"))
2599 for i in r:
2590 for i in r:
2600 node = r.node(i)
2591 node = r.node(i)
2601 pp = r.parents(node)
2592 pp = r.parents(node)
2602 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2593 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2603 if pp[1] != nullid:
2594 if pp[1] != nullid:
2604 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2595 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2605 ui.write("}\n")
2596 ui.write("}\n")
2606
2597
2607 @command('debugdeltachain',
2598 @command('debugdeltachain',
2608 debugrevlogopts + formatteropts,
2599 debugrevlogopts + formatteropts,
2609 _('-c|-m|FILE'),
2600 _('-c|-m|FILE'),
2610 optionalrepo=True)
2601 optionalrepo=True)
2611 def debugdeltachain(ui, repo, file_=None, **opts):
2602 def debugdeltachain(ui, repo, file_=None, **opts):
2612 """dump information about delta chains in a revlog
2603 """dump information about delta chains in a revlog
2613
2604
2614 Output can be templatized. Available template keywords are:
2605 Output can be templatized. Available template keywords are:
2615
2606
2616 :``rev``: revision number
2607 :``rev``: revision number
2617 :``chainid``: delta chain identifier (numbered by unique base)
2608 :``chainid``: delta chain identifier (numbered by unique base)
2618 :``chainlen``: delta chain length to this revision
2609 :``chainlen``: delta chain length to this revision
2619 :``prevrev``: previous revision in delta chain
2610 :``prevrev``: previous revision in delta chain
2620 :``deltatype``: role of delta / how it was computed
2611 :``deltatype``: role of delta / how it was computed
2621 :``compsize``: compressed size of revision
2612 :``compsize``: compressed size of revision
2622 :``uncompsize``: uncompressed size of revision
2613 :``uncompsize``: uncompressed size of revision
2623 :``chainsize``: total size of compressed revisions in chain
2614 :``chainsize``: total size of compressed revisions in chain
2624 :``chainratio``: total chain size divided by uncompressed revision size
2615 :``chainratio``: total chain size divided by uncompressed revision size
2625 (new delta chains typically start at ratio 2.00)
2616 (new delta chains typically start at ratio 2.00)
2626 :``lindist``: linear distance from base revision in delta chain to end
2617 :``lindist``: linear distance from base revision in delta chain to end
2627 of this revision
2618 of this revision
2628 :``extradist``: total size of revisions not part of this delta chain from
2619 :``extradist``: total size of revisions not part of this delta chain from
2629 base of delta chain to end of this revision; a measurement
2620 base of delta chain to end of this revision; a measurement
2630 of how much extra data we need to read/seek across to read
2621 of how much extra data we need to read/seek across to read
2631 the delta chain for this revision
2622 the delta chain for this revision
2632 :``extraratio``: extradist divided by chainsize; another representation of
2623 :``extraratio``: extradist divided by chainsize; another representation of
2633 how much unrelated data is needed to load this delta chain
2624 how much unrelated data is needed to load this delta chain
2634 """
2625 """
2635 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2626 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2636 index = r.index
2627 index = r.index
2637 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2628 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2638
2629
2639 def revinfo(rev):
2630 def revinfo(rev):
2640 e = index[rev]
2631 e = index[rev]
2641 compsize = e[1]
2632 compsize = e[1]
2642 uncompsize = e[2]
2633 uncompsize = e[2]
2643 chainsize = 0
2634 chainsize = 0
2644
2635
2645 if generaldelta:
2636 if generaldelta:
2646 if e[3] == e[5]:
2637 if e[3] == e[5]:
2647 deltatype = 'p1'
2638 deltatype = 'p1'
2648 elif e[3] == e[6]:
2639 elif e[3] == e[6]:
2649 deltatype = 'p2'
2640 deltatype = 'p2'
2650 elif e[3] == rev - 1:
2641 elif e[3] == rev - 1:
2651 deltatype = 'prev'
2642 deltatype = 'prev'
2652 elif e[3] == rev:
2643 elif e[3] == rev:
2653 deltatype = 'base'
2644 deltatype = 'base'
2654 else:
2645 else:
2655 deltatype = 'other'
2646 deltatype = 'other'
2656 else:
2647 else:
2657 if e[3] == rev:
2648 if e[3] == rev:
2658 deltatype = 'base'
2649 deltatype = 'base'
2659 else:
2650 else:
2660 deltatype = 'prev'
2651 deltatype = 'prev'
2661
2652
2662 chain = r._deltachain(rev)[0]
2653 chain = r._deltachain(rev)[0]
2663 for iterrev in chain:
2654 for iterrev in chain:
2664 e = index[iterrev]
2655 e = index[iterrev]
2665 chainsize += e[1]
2656 chainsize += e[1]
2666
2657
2667 return compsize, uncompsize, deltatype, chain, chainsize
2658 return compsize, uncompsize, deltatype, chain, chainsize
2668
2659
2669 fm = ui.formatter('debugdeltachain', opts)
2660 fm = ui.formatter('debugdeltachain', opts)
2670
2661
2671 fm.plain(' rev chain# chainlen prev delta '
2662 fm.plain(' rev chain# chainlen prev delta '
2672 'size rawsize chainsize ratio lindist extradist '
2663 'size rawsize chainsize ratio lindist extradist '
2673 'extraratio\n')
2664 'extraratio\n')
2674
2665
2675 chainbases = {}
2666 chainbases = {}
2676 for rev in r:
2667 for rev in r:
2677 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2668 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2678 chainbase = chain[0]
2669 chainbase = chain[0]
2679 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2670 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2680 basestart = r.start(chainbase)
2671 basestart = r.start(chainbase)
2681 revstart = r.start(rev)
2672 revstart = r.start(rev)
2682 lineardist = revstart + comp - basestart
2673 lineardist = revstart + comp - basestart
2683 extradist = lineardist - chainsize
2674 extradist = lineardist - chainsize
2684 try:
2675 try:
2685 prevrev = chain[-2]
2676 prevrev = chain[-2]
2686 except IndexError:
2677 except IndexError:
2687 prevrev = -1
2678 prevrev = -1
2688
2679
2689 chainratio = float(chainsize) / float(uncomp)
2680 chainratio = float(chainsize) / float(uncomp)
2690 extraratio = float(extradist) / float(chainsize)
2681 extraratio = float(extradist) / float(chainsize)
2691
2682
2692 fm.startitem()
2683 fm.startitem()
2693 fm.write('rev chainid chainlen prevrev deltatype compsize '
2684 fm.write('rev chainid chainlen prevrev deltatype compsize '
2694 'uncompsize chainsize chainratio lindist extradist '
2685 'uncompsize chainsize chainratio lindist extradist '
2695 'extraratio',
2686 'extraratio',
2696 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2687 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2697 rev, chainid, len(chain), prevrev, deltatype, comp,
2688 rev, chainid, len(chain), prevrev, deltatype, comp,
2698 uncomp, chainsize, chainratio, lineardist, extradist,
2689 uncomp, chainsize, chainratio, lineardist, extradist,
2699 extraratio,
2690 extraratio,
2700 rev=rev, chainid=chainid, chainlen=len(chain),
2691 rev=rev, chainid=chainid, chainlen=len(chain),
2701 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2692 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2702 uncompsize=uncomp, chainsize=chainsize,
2693 uncompsize=uncomp, chainsize=chainsize,
2703 chainratio=chainratio, lindist=lineardist,
2694 chainratio=chainratio, lindist=lineardist,
2704 extradist=extradist, extraratio=extraratio)
2695 extradist=extradist, extraratio=extraratio)
2705
2696
2706 fm.end()
2697 fm.end()
2707
2698
2708 @command('debuginstall', [] + formatteropts, '', norepo=True)
2699 @command('debuginstall', [] + formatteropts, '', norepo=True)
2709 def debuginstall(ui, **opts):
2700 def debuginstall(ui, **opts):
2710 '''test Mercurial installation
2701 '''test Mercurial installation
2711
2702
2712 Returns 0 on success.
2703 Returns 0 on success.
2713 '''
2704 '''
2714
2705
2715 def writetemp(contents):
2706 def writetemp(contents):
2716 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2707 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2717 f = os.fdopen(fd, "wb")
2708 f = os.fdopen(fd, "wb")
2718 f.write(contents)
2709 f.write(contents)
2719 f.close()
2710 f.close()
2720 return name
2711 return name
2721
2712
2722 problems = 0
2713 problems = 0
2723
2714
2724 fm = ui.formatter('debuginstall', opts)
2715 fm = ui.formatter('debuginstall', opts)
2725 fm.startitem()
2716 fm.startitem()
2726
2717
2727 # encoding
2718 # encoding
2728 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2719 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2729 err = None
2720 err = None
2730 try:
2721 try:
2731 encoding.fromlocal("test")
2722 encoding.fromlocal("test")
2732 except error.Abort as inst:
2723 except error.Abort as inst:
2733 err = inst
2724 err = inst
2734 problems += 1
2725 problems += 1
2735 fm.condwrite(err, 'encodingerror', _(" %s\n"
2726 fm.condwrite(err, 'encodingerror', _(" %s\n"
2736 " (check that your locale is properly set)\n"), err)
2727 " (check that your locale is properly set)\n"), err)
2737
2728
2738 # Python
2729 # Python
2739 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2730 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2740 sys.executable)
2731 sys.executable)
2741 fm.write('pythonver', _("checking Python version (%s)\n"),
2732 fm.write('pythonver', _("checking Python version (%s)\n"),
2742 ("%s.%s.%s" % sys.version_info[:3]))
2733 ("%s.%s.%s" % sys.version_info[:3]))
2743 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2734 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2744 os.path.dirname(os.__file__))
2735 os.path.dirname(os.__file__))
2745
2736
2746 # hg version
2737 # hg version
2747 hgver = util.version()
2738 hgver = util.version()
2748 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2739 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2749 hgver.split('+')[0])
2740 hgver.split('+')[0])
2750 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2741 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2751 '+'.join(hgver.split('+')[1:]))
2742 '+'.join(hgver.split('+')[1:]))
2752
2743
2753 # compiled modules
2744 # compiled modules
2754 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2745 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2755 policy.policy)
2746 policy.policy)
2756 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2747 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2757 os.path.dirname(__file__))
2748 os.path.dirname(__file__))
2758
2749
2759 err = None
2750 err = None
2760 try:
2751 try:
2761 from . import (
2752 from . import (
2762 base85,
2753 base85,
2763 bdiff,
2754 bdiff,
2764 mpatch,
2755 mpatch,
2765 osutil,
2756 osutil,
2766 )
2757 )
2767 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2758 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2768 except Exception as inst:
2759 except Exception as inst:
2769 err = inst
2760 err = inst
2770 problems += 1
2761 problems += 1
2771 fm.condwrite(err, 'extensionserror', " %s\n", err)
2762 fm.condwrite(err, 'extensionserror', " %s\n", err)
2772
2763
2773 # templates
2764 # templates
2774 p = templater.templatepaths()
2765 p = templater.templatepaths()
2775 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2766 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2776 fm.condwrite(not p, '', _(" no template directories found\n"))
2767 fm.condwrite(not p, '', _(" no template directories found\n"))
2777 if p:
2768 if p:
2778 m = templater.templatepath("map-cmdline.default")
2769 m = templater.templatepath("map-cmdline.default")
2779 if m:
2770 if m:
2780 # template found, check if it is working
2771 # template found, check if it is working
2781 err = None
2772 err = None
2782 try:
2773 try:
2783 templater.templater.frommapfile(m)
2774 templater.templater.frommapfile(m)
2784 except Exception as inst:
2775 except Exception as inst:
2785 err = inst
2776 err = inst
2786 p = None
2777 p = None
2787 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2778 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2788 else:
2779 else:
2789 p = None
2780 p = None
2790 fm.condwrite(p, 'defaulttemplate',
2781 fm.condwrite(p, 'defaulttemplate',
2791 _("checking default template (%s)\n"), m)
2782 _("checking default template (%s)\n"), m)
2792 fm.condwrite(not m, 'defaulttemplatenotfound',
2783 fm.condwrite(not m, 'defaulttemplatenotfound',
2793 _(" template '%s' not found\n"), "default")
2784 _(" template '%s' not found\n"), "default")
2794 if not p:
2785 if not p:
2795 problems += 1
2786 problems += 1
2796 fm.condwrite(not p, '',
2787 fm.condwrite(not p, '',
2797 _(" (templates seem to have been installed incorrectly)\n"))
2788 _(" (templates seem to have been installed incorrectly)\n"))
2798
2789
2799 # editor
2790 # editor
2800 editor = ui.geteditor()
2791 editor = ui.geteditor()
2801 editor = util.expandpath(editor)
2792 editor = util.expandpath(editor)
2802 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2793 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2803 cmdpath = util.findexe(shlex.split(editor)[0])
2794 cmdpath = util.findexe(shlex.split(editor)[0])
2804 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2795 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2805 _(" No commit editor set and can't find %s in PATH\n"
2796 _(" No commit editor set and can't find %s in PATH\n"
2806 " (specify a commit editor in your configuration"
2797 " (specify a commit editor in your configuration"
2807 " file)\n"), not cmdpath and editor == 'vi' and editor)
2798 " file)\n"), not cmdpath and editor == 'vi' and editor)
2808 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2799 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2809 _(" Can't find editor '%s' in PATH\n"
2800 _(" Can't find editor '%s' in PATH\n"
2810 " (specify a commit editor in your configuration"
2801 " (specify a commit editor in your configuration"
2811 " file)\n"), not cmdpath and editor)
2802 " file)\n"), not cmdpath and editor)
2812 if not cmdpath and editor != 'vi':
2803 if not cmdpath and editor != 'vi':
2813 problems += 1
2804 problems += 1
2814
2805
2815 # check username
2806 # check username
2816 username = None
2807 username = None
2817 err = None
2808 err = None
2818 try:
2809 try:
2819 username = ui.username()
2810 username = ui.username()
2820 except error.Abort as e:
2811 except error.Abort as e:
2821 err = e
2812 err = e
2822 problems += 1
2813 problems += 1
2823
2814
2824 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2815 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2825 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2816 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2826 " (specify a username in your configuration file)\n"), err)
2817 " (specify a username in your configuration file)\n"), err)
2827
2818
2828 fm.condwrite(not problems, '',
2819 fm.condwrite(not problems, '',
2829 _("no problems detected\n"))
2820 _("no problems detected\n"))
2830 if not problems:
2821 if not problems:
2831 fm.data(problems=problems)
2822 fm.data(problems=problems)
2832 fm.condwrite(problems, 'problems',
2823 fm.condwrite(problems, 'problems',
2833 _("%s problems detected,"
2824 _("%s problems detected,"
2834 " please check your install!\n"), problems)
2825 " please check your install!\n"), problems)
2835 fm.end()
2826 fm.end()
2836
2827
2837 return problems
2828 return problems
2838
2829
2839 @command('debugknown', [], _('REPO ID...'), norepo=True)
2830 @command('debugknown', [], _('REPO ID...'), norepo=True)
2840 def debugknown(ui, repopath, *ids, **opts):
2831 def debugknown(ui, repopath, *ids, **opts):
2841 """test whether node ids are known to a repo
2832 """test whether node ids are known to a repo
2842
2833
2843 Every ID must be a full-length hex node id string. Returns a list of 0s
2834 Every ID must be a full-length hex node id string. Returns a list of 0s
2844 and 1s indicating unknown/known.
2835 and 1s indicating unknown/known.
2845 """
2836 """
2846 repo = hg.peer(ui, opts, repopath)
2837 repo = hg.peer(ui, opts, repopath)
2847 if not repo.capable('known'):
2838 if not repo.capable('known'):
2848 raise error.Abort("known() not supported by target repository")
2839 raise error.Abort("known() not supported by target repository")
2849 flags = repo.known([bin(s) for s in ids])
2840 flags = repo.known([bin(s) for s in ids])
2850 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2841 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2851
2842
2852 @command('debuglabelcomplete', [], _('LABEL...'))
2843 @command('debuglabelcomplete', [], _('LABEL...'))
2853 def debuglabelcomplete(ui, repo, *args):
2844 def debuglabelcomplete(ui, repo, *args):
2854 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2845 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2855 debugnamecomplete(ui, repo, *args)
2846 debugnamecomplete(ui, repo, *args)
2856
2847
2857 @command('debugmergestate', [], '')
2848 @command('debugmergestate', [], '')
2858 def debugmergestate(ui, repo, *args):
2849 def debugmergestate(ui, repo, *args):
2859 """print merge state
2850 """print merge state
2860
2851
2861 Use --verbose to print out information about whether v1 or v2 merge state
2852 Use --verbose to print out information about whether v1 or v2 merge state
2862 was chosen."""
2853 was chosen."""
2863 def _hashornull(h):
2854 def _hashornull(h):
2864 if h == nullhex:
2855 if h == nullhex:
2865 return 'null'
2856 return 'null'
2866 else:
2857 else:
2867 return h
2858 return h
2868
2859
2869 def printrecords(version):
2860 def printrecords(version):
2870 ui.write(('* version %s records\n') % version)
2861 ui.write(('* version %s records\n') % version)
2871 if version == 1:
2862 if version == 1:
2872 records = v1records
2863 records = v1records
2873 else:
2864 else:
2874 records = v2records
2865 records = v2records
2875
2866
2876 for rtype, record in records:
2867 for rtype, record in records:
2877 # pretty print some record types
2868 # pretty print some record types
2878 if rtype == 'L':
2869 if rtype == 'L':
2879 ui.write(('local: %s\n') % record)
2870 ui.write(('local: %s\n') % record)
2880 elif rtype == 'O':
2871 elif rtype == 'O':
2881 ui.write(('other: %s\n') % record)
2872 ui.write(('other: %s\n') % record)
2882 elif rtype == 'm':
2873 elif rtype == 'm':
2883 driver, mdstate = record.split('\0', 1)
2874 driver, mdstate = record.split('\0', 1)
2884 ui.write(('merge driver: %s (state "%s")\n')
2875 ui.write(('merge driver: %s (state "%s")\n')
2885 % (driver, mdstate))
2876 % (driver, mdstate))
2886 elif rtype in 'FDC':
2877 elif rtype in 'FDC':
2887 r = record.split('\0')
2878 r = record.split('\0')
2888 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2879 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2889 if version == 1:
2880 if version == 1:
2890 onode = 'not stored in v1 format'
2881 onode = 'not stored in v1 format'
2891 flags = r[7]
2882 flags = r[7]
2892 else:
2883 else:
2893 onode, flags = r[7:9]
2884 onode, flags = r[7:9]
2894 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2885 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2895 % (f, rtype, state, _hashornull(hash)))
2886 % (f, rtype, state, _hashornull(hash)))
2896 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2887 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2897 ui.write((' ancestor path: %s (node %s)\n')
2888 ui.write((' ancestor path: %s (node %s)\n')
2898 % (afile, _hashornull(anode)))
2889 % (afile, _hashornull(anode)))
2899 ui.write((' other path: %s (node %s)\n')
2890 ui.write((' other path: %s (node %s)\n')
2900 % (ofile, _hashornull(onode)))
2891 % (ofile, _hashornull(onode)))
2901 elif rtype == 'f':
2892 elif rtype == 'f':
2902 filename, rawextras = record.split('\0', 1)
2893 filename, rawextras = record.split('\0', 1)
2903 extras = rawextras.split('\0')
2894 extras = rawextras.split('\0')
2904 i = 0
2895 i = 0
2905 extrastrings = []
2896 extrastrings = []
2906 while i < len(extras):
2897 while i < len(extras):
2907 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2898 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2908 i += 2
2899 i += 2
2909
2900
2910 ui.write(('file extras: %s (%s)\n')
2901 ui.write(('file extras: %s (%s)\n')
2911 % (filename, ', '.join(extrastrings)))
2902 % (filename, ', '.join(extrastrings)))
2912 elif rtype == 'l':
2903 elif rtype == 'l':
2913 labels = record.split('\0', 2)
2904 labels = record.split('\0', 2)
2914 labels = [l for l in labels if len(l) > 0]
2905 labels = [l for l in labels if len(l) > 0]
2915 ui.write(('labels:\n'))
2906 ui.write(('labels:\n'))
2916 ui.write((' local: %s\n' % labels[0]))
2907 ui.write((' local: %s\n' % labels[0]))
2917 ui.write((' other: %s\n' % labels[1]))
2908 ui.write((' other: %s\n' % labels[1]))
2918 if len(labels) > 2:
2909 if len(labels) > 2:
2919 ui.write((' base: %s\n' % labels[2]))
2910 ui.write((' base: %s\n' % labels[2]))
2920 else:
2911 else:
2921 ui.write(('unrecognized entry: %s\t%s\n')
2912 ui.write(('unrecognized entry: %s\t%s\n')
2922 % (rtype, record.replace('\0', '\t')))
2913 % (rtype, record.replace('\0', '\t')))
2923
2914
2924 # Avoid mergestate.read() since it may raise an exception for unsupported
2915 # Avoid mergestate.read() since it may raise an exception for unsupported
2925 # merge state records. We shouldn't be doing this, but this is OK since this
2916 # merge state records. We shouldn't be doing this, but this is OK since this
2926 # command is pretty low-level.
2917 # command is pretty low-level.
2927 ms = mergemod.mergestate(repo)
2918 ms = mergemod.mergestate(repo)
2928
2919
2929 # sort so that reasonable information is on top
2920 # sort so that reasonable information is on top
2930 v1records = ms._readrecordsv1()
2921 v1records = ms._readrecordsv1()
2931 v2records = ms._readrecordsv2()
2922 v2records = ms._readrecordsv2()
2932 order = 'LOml'
2923 order = 'LOml'
2933 def key(r):
2924 def key(r):
2934 idx = order.find(r[0])
2925 idx = order.find(r[0])
2935 if idx == -1:
2926 if idx == -1:
2936 return (1, r[1])
2927 return (1, r[1])
2937 else:
2928 else:
2938 return (0, idx)
2929 return (0, idx)
2939 v1records.sort(key=key)
2930 v1records.sort(key=key)
2940 v2records.sort(key=key)
2931 v2records.sort(key=key)
2941
2932
2942 if not v1records and not v2records:
2933 if not v1records and not v2records:
2943 ui.write(('no merge state found\n'))
2934 ui.write(('no merge state found\n'))
2944 elif not v2records:
2935 elif not v2records:
2945 ui.note(('no version 2 merge state\n'))
2936 ui.note(('no version 2 merge state\n'))
2946 printrecords(1)
2937 printrecords(1)
2947 elif ms._v1v2match(v1records, v2records):
2938 elif ms._v1v2match(v1records, v2records):
2948 ui.note(('v1 and v2 states match: using v2\n'))
2939 ui.note(('v1 and v2 states match: using v2\n'))
2949 printrecords(2)
2940 printrecords(2)
2950 else:
2941 else:
2951 ui.note(('v1 and v2 states mismatch: using v1\n'))
2942 ui.note(('v1 and v2 states mismatch: using v1\n'))
2952 printrecords(1)
2943 printrecords(1)
2953 if ui.verbose:
2944 if ui.verbose:
2954 printrecords(2)
2945 printrecords(2)
2955
2946
2956 @command('debugnamecomplete', [], _('NAME...'))
2947 @command('debugnamecomplete', [], _('NAME...'))
2957 def debugnamecomplete(ui, repo, *args):
2948 def debugnamecomplete(ui, repo, *args):
2958 '''complete "names" - tags, open branch names, bookmark names'''
2949 '''complete "names" - tags, open branch names, bookmark names'''
2959
2950
2960 names = set()
2951 names = set()
2961 # since we previously only listed open branches, we will handle that
2952 # since we previously only listed open branches, we will handle that
2962 # specially (after this for loop)
2953 # specially (after this for loop)
2963 for name, ns in repo.names.iteritems():
2954 for name, ns in repo.names.iteritems():
2964 if name != 'branches':
2955 if name != 'branches':
2965 names.update(ns.listnames(repo))
2956 names.update(ns.listnames(repo))
2966 names.update(tag for (tag, heads, tip, closed)
2957 names.update(tag for (tag, heads, tip, closed)
2967 in repo.branchmap().iterbranches() if not closed)
2958 in repo.branchmap().iterbranches() if not closed)
2968 completions = set()
2959 completions = set()
2969 if not args:
2960 if not args:
2970 args = ['']
2961 args = ['']
2971 for a in args:
2962 for a in args:
2972 completions.update(n for n in names if n.startswith(a))
2963 completions.update(n for n in names if n.startswith(a))
2973 ui.write('\n'.join(sorted(completions)))
2964 ui.write('\n'.join(sorted(completions)))
2974 ui.write('\n')
2965 ui.write('\n')
2975
2966
2976 @command('debuglocks',
2967 @command('debuglocks',
2977 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2968 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2978 ('W', 'force-wlock', None,
2969 ('W', 'force-wlock', None,
2979 _('free the working state lock (DANGEROUS)'))],
2970 _('free the working state lock (DANGEROUS)'))],
2980 _('[OPTION]...'))
2971 _('[OPTION]...'))
2981 def debuglocks(ui, repo, **opts):
2972 def debuglocks(ui, repo, **opts):
2982 """show or modify state of locks
2973 """show or modify state of locks
2983
2974
2984 By default, this command will show which locks are held. This
2975 By default, this command will show which locks are held. This
2985 includes the user and process holding the lock, the amount of time
2976 includes the user and process holding the lock, the amount of time
2986 the lock has been held, and the machine name where the process is
2977 the lock has been held, and the machine name where the process is
2987 running if it's not local.
2978 running if it's not local.
2988
2979
2989 Locks protect the integrity of Mercurial's data, so should be
2980 Locks protect the integrity of Mercurial's data, so should be
2990 treated with care. System crashes or other interruptions may cause
2981 treated with care. System crashes or other interruptions may cause
2991 locks to not be properly released, though Mercurial will usually
2982 locks to not be properly released, though Mercurial will usually
2992 detect and remove such stale locks automatically.
2983 detect and remove such stale locks automatically.
2993
2984
2994 However, detecting stale locks may not always be possible (for
2985 However, detecting stale locks may not always be possible (for
2995 instance, on a shared filesystem). Removing locks may also be
2986 instance, on a shared filesystem). Removing locks may also be
2996 blocked by filesystem permissions.
2987 blocked by filesystem permissions.
2997
2988
2998 Returns 0 if no locks are held.
2989 Returns 0 if no locks are held.
2999
2990
3000 """
2991 """
3001
2992
3002 if opts.get('force_lock'):
2993 if opts.get('force_lock'):
3003 repo.svfs.unlink('lock')
2994 repo.svfs.unlink('lock')
3004 if opts.get('force_wlock'):
2995 if opts.get('force_wlock'):
3005 repo.vfs.unlink('wlock')
2996 repo.vfs.unlink('wlock')
3006 if opts.get('force_lock') or opts.get('force_lock'):
2997 if opts.get('force_lock') or opts.get('force_lock'):
3007 return 0
2998 return 0
3008
2999
3009 now = time.time()
3000 now = time.time()
3010 held = 0
3001 held = 0
3011
3002
3012 def report(vfs, name, method):
3003 def report(vfs, name, method):
3013 # this causes stale locks to get reaped for more accurate reporting
3004 # this causes stale locks to get reaped for more accurate reporting
3014 try:
3005 try:
3015 l = method(False)
3006 l = method(False)
3016 except error.LockHeld:
3007 except error.LockHeld:
3017 l = None
3008 l = None
3018
3009
3019 if l:
3010 if l:
3020 l.release()
3011 l.release()
3021 else:
3012 else:
3022 try:
3013 try:
3023 stat = vfs.lstat(name)
3014 stat = vfs.lstat(name)
3024 age = now - stat.st_mtime
3015 age = now - stat.st_mtime
3025 user = util.username(stat.st_uid)
3016 user = util.username(stat.st_uid)
3026 locker = vfs.readlock(name)
3017 locker = vfs.readlock(name)
3027 if ":" in locker:
3018 if ":" in locker:
3028 host, pid = locker.split(':')
3019 host, pid = locker.split(':')
3029 if host == socket.gethostname():
3020 if host == socket.gethostname():
3030 locker = 'user %s, process %s' % (user, pid)
3021 locker = 'user %s, process %s' % (user, pid)
3031 else:
3022 else:
3032 locker = 'user %s, process %s, host %s' \
3023 locker = 'user %s, process %s, host %s' \
3033 % (user, pid, host)
3024 % (user, pid, host)
3034 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3025 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3035 return 1
3026 return 1
3036 except OSError as e:
3027 except OSError as e:
3037 if e.errno != errno.ENOENT:
3028 if e.errno != errno.ENOENT:
3038 raise
3029 raise
3039
3030
3040 ui.write(("%-6s free\n") % (name + ":"))
3031 ui.write(("%-6s free\n") % (name + ":"))
3041 return 0
3032 return 0
3042
3033
3043 held += report(repo.svfs, "lock", repo.lock)
3034 held += report(repo.svfs, "lock", repo.lock)
3044 held += report(repo.vfs, "wlock", repo.wlock)
3035 held += report(repo.vfs, "wlock", repo.wlock)
3045
3036
3046 return held
3037 return held
3047
3038
3048 @command('debugobsolete',
3039 @command('debugobsolete',
3049 [('', 'flags', 0, _('markers flag')),
3040 [('', 'flags', 0, _('markers flag')),
3050 ('', 'record-parents', False,
3041 ('', 'record-parents', False,
3051 _('record parent information for the precursor')),
3042 _('record parent information for the precursor')),
3052 ('r', 'rev', [], _('display markers relevant to REV')),
3043 ('r', 'rev', [], _('display markers relevant to REV')),
3053 ('', 'index', False, _('display index of the marker')),
3044 ('', 'index', False, _('display index of the marker')),
3054 ('', 'delete', [], _('delete markers specified by indices')),
3045 ('', 'delete', [], _('delete markers specified by indices')),
3055 ] + commitopts2,
3046 ] + commitopts2,
3056 _('[OBSOLETED [REPLACEMENT ...]]'))
3047 _('[OBSOLETED [REPLACEMENT ...]]'))
3057 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3048 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3058 """create arbitrary obsolete marker
3049 """create arbitrary obsolete marker
3059
3050
3060 With no arguments, displays the list of obsolescence markers."""
3051 With no arguments, displays the list of obsolescence markers."""
3061
3052
3062 def parsenodeid(s):
3053 def parsenodeid(s):
3063 try:
3054 try:
3064 # We do not use revsingle/revrange functions here to accept
3055 # We do not use revsingle/revrange functions here to accept
3065 # arbitrary node identifiers, possibly not present in the
3056 # arbitrary node identifiers, possibly not present in the
3066 # local repository.
3057 # local repository.
3067 n = bin(s)
3058 n = bin(s)
3068 if len(n) != len(nullid):
3059 if len(n) != len(nullid):
3069 raise TypeError()
3060 raise TypeError()
3070 return n
3061 return n
3071 except TypeError:
3062 except TypeError:
3072 raise error.Abort('changeset references must be full hexadecimal '
3063 raise error.Abort('changeset references must be full hexadecimal '
3073 'node identifiers')
3064 'node identifiers')
3074
3065
3075 if opts.get('delete'):
3066 if opts.get('delete'):
3076 indices = []
3067 indices = []
3077 for v in opts.get('delete'):
3068 for v in opts.get('delete'):
3078 try:
3069 try:
3079 indices.append(int(v))
3070 indices.append(int(v))
3080 except ValueError:
3071 except ValueError:
3081 raise error.Abort(_('invalid index value: %r') % v,
3072 raise error.Abort(_('invalid index value: %r') % v,
3082 hint=_('use integers for indices'))
3073 hint=_('use integers for indices'))
3083
3074
3084 if repo.currenttransaction():
3075 if repo.currenttransaction():
3085 raise error.Abort(_('cannot delete obsmarkers in the middle '
3076 raise error.Abort(_('cannot delete obsmarkers in the middle '
3086 'of transaction.'))
3077 'of transaction.'))
3087
3078
3088 with repo.lock():
3079 with repo.lock():
3089 n = repair.deleteobsmarkers(repo.obsstore, indices)
3080 n = repair.deleteobsmarkers(repo.obsstore, indices)
3090 ui.write(_('deleted %i obsolescense markers\n') % n)
3081 ui.write(_('deleted %i obsolescense markers\n') % n)
3091
3082
3092 return
3083 return
3093
3084
3094 if precursor is not None:
3085 if precursor is not None:
3095 if opts['rev']:
3086 if opts['rev']:
3096 raise error.Abort('cannot select revision when creating marker')
3087 raise error.Abort('cannot select revision when creating marker')
3097 metadata = {}
3088 metadata = {}
3098 metadata['user'] = opts['user'] or ui.username()
3089 metadata['user'] = opts['user'] or ui.username()
3099 succs = tuple(parsenodeid(succ) for succ in successors)
3090 succs = tuple(parsenodeid(succ) for succ in successors)
3100 l = repo.lock()
3091 l = repo.lock()
3101 try:
3092 try:
3102 tr = repo.transaction('debugobsolete')
3093 tr = repo.transaction('debugobsolete')
3103 try:
3094 try:
3104 date = opts.get('date')
3095 date = opts.get('date')
3105 if date:
3096 if date:
3106 date = util.parsedate(date)
3097 date = util.parsedate(date)
3107 else:
3098 else:
3108 date = None
3099 date = None
3109 prec = parsenodeid(precursor)
3100 prec = parsenodeid(precursor)
3110 parents = None
3101 parents = None
3111 if opts['record_parents']:
3102 if opts['record_parents']:
3112 if prec not in repo.unfiltered():
3103 if prec not in repo.unfiltered():
3113 raise error.Abort('cannot used --record-parents on '
3104 raise error.Abort('cannot used --record-parents on '
3114 'unknown changesets')
3105 'unknown changesets')
3115 parents = repo.unfiltered()[prec].parents()
3106 parents = repo.unfiltered()[prec].parents()
3116 parents = tuple(p.node() for p in parents)
3107 parents = tuple(p.node() for p in parents)
3117 repo.obsstore.create(tr, prec, succs, opts['flags'],
3108 repo.obsstore.create(tr, prec, succs, opts['flags'],
3118 parents=parents, date=date,
3109 parents=parents, date=date,
3119 metadata=metadata)
3110 metadata=metadata)
3120 tr.close()
3111 tr.close()
3121 except ValueError as exc:
3112 except ValueError as exc:
3122 raise error.Abort(_('bad obsmarker input: %s') % exc)
3113 raise error.Abort(_('bad obsmarker input: %s') % exc)
3123 finally:
3114 finally:
3124 tr.release()
3115 tr.release()
3125 finally:
3116 finally:
3126 l.release()
3117 l.release()
3127 else:
3118 else:
3128 if opts['rev']:
3119 if opts['rev']:
3129 revs = scmutil.revrange(repo, opts['rev'])
3120 revs = scmutil.revrange(repo, opts['rev'])
3130 nodes = [repo[r].node() for r in revs]
3121 nodes = [repo[r].node() for r in revs]
3131 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3122 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3132 markers.sort(key=lambda x: x._data)
3123 markers.sort(key=lambda x: x._data)
3133 else:
3124 else:
3134 markers = obsolete.getmarkers(repo)
3125 markers = obsolete.getmarkers(repo)
3135
3126
3136 markerstoiter = markers
3127 markerstoiter = markers
3137 isrelevant = lambda m: True
3128 isrelevant = lambda m: True
3138 if opts.get('rev') and opts.get('index'):
3129 if opts.get('rev') and opts.get('index'):
3139 markerstoiter = obsolete.getmarkers(repo)
3130 markerstoiter = obsolete.getmarkers(repo)
3140 markerset = set(markers)
3131 markerset = set(markers)
3141 isrelevant = lambda m: m in markerset
3132 isrelevant = lambda m: m in markerset
3142
3133
3143 for i, m in enumerate(markerstoiter):
3134 for i, m in enumerate(markerstoiter):
3144 if not isrelevant(m):
3135 if not isrelevant(m):
3145 # marker can be irrelevant when we're iterating over a set
3136 # marker can be irrelevant when we're iterating over a set
3146 # of markers (markerstoiter) which is bigger than the set
3137 # of markers (markerstoiter) which is bigger than the set
3147 # of markers we want to display (markers)
3138 # of markers we want to display (markers)
3148 # this can happen if both --index and --rev options are
3139 # this can happen if both --index and --rev options are
3149 # provided and thus we need to iterate over all of the markers
3140 # provided and thus we need to iterate over all of the markers
3150 # to get the correct indices, but only display the ones that
3141 # to get the correct indices, but only display the ones that
3151 # are relevant to --rev value
3142 # are relevant to --rev value
3152 continue
3143 continue
3153 ind = i if opts.get('index') else None
3144 ind = i if opts.get('index') else None
3154 cmdutil.showmarker(ui, m, index=ind)
3145 cmdutil.showmarker(ui, m, index=ind)
3155
3146
3156 @command('debugpathcomplete',
3147 @command('debugpathcomplete',
3157 [('f', 'full', None, _('complete an entire path')),
3148 [('f', 'full', None, _('complete an entire path')),
3158 ('n', 'normal', None, _('show only normal files')),
3149 ('n', 'normal', None, _('show only normal files')),
3159 ('a', 'added', None, _('show only added files')),
3150 ('a', 'added', None, _('show only added files')),
3160 ('r', 'removed', None, _('show only removed files'))],
3151 ('r', 'removed', None, _('show only removed files'))],
3161 _('FILESPEC...'))
3152 _('FILESPEC...'))
3162 def debugpathcomplete(ui, repo, *specs, **opts):
3153 def debugpathcomplete(ui, repo, *specs, **opts):
3163 '''complete part or all of a tracked path
3154 '''complete part or all of a tracked path
3164
3155
3165 This command supports shells that offer path name completion. It
3156 This command supports shells that offer path name completion. It
3166 currently completes only files already known to the dirstate.
3157 currently completes only files already known to the dirstate.
3167
3158
3168 Completion extends only to the next path segment unless
3159 Completion extends only to the next path segment unless
3169 --full is specified, in which case entire paths are used.'''
3160 --full is specified, in which case entire paths are used.'''
3170
3161
3171 def complete(path, acceptable):
3162 def complete(path, acceptable):
3172 dirstate = repo.dirstate
3163 dirstate = repo.dirstate
3173 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3164 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3174 rootdir = repo.root + os.sep
3165 rootdir = repo.root + os.sep
3175 if spec != repo.root and not spec.startswith(rootdir):
3166 if spec != repo.root and not spec.startswith(rootdir):
3176 return [], []
3167 return [], []
3177 if os.path.isdir(spec):
3168 if os.path.isdir(spec):
3178 spec += '/'
3169 spec += '/'
3179 spec = spec[len(rootdir):]
3170 spec = spec[len(rootdir):]
3180 fixpaths = os.sep != '/'
3171 fixpaths = os.sep != '/'
3181 if fixpaths:
3172 if fixpaths:
3182 spec = spec.replace(os.sep, '/')
3173 spec = spec.replace(os.sep, '/')
3183 speclen = len(spec)
3174 speclen = len(spec)
3184 fullpaths = opts['full']
3175 fullpaths = opts['full']
3185 files, dirs = set(), set()
3176 files, dirs = set(), set()
3186 adddir, addfile = dirs.add, files.add
3177 adddir, addfile = dirs.add, files.add
3187 for f, st in dirstate.iteritems():
3178 for f, st in dirstate.iteritems():
3188 if f.startswith(spec) and st[0] in acceptable:
3179 if f.startswith(spec) and st[0] in acceptable:
3189 if fixpaths:
3180 if fixpaths:
3190 f = f.replace('/', os.sep)
3181 f = f.replace('/', os.sep)
3191 if fullpaths:
3182 if fullpaths:
3192 addfile(f)
3183 addfile(f)
3193 continue
3184 continue
3194 s = f.find(os.sep, speclen)
3185 s = f.find(os.sep, speclen)
3195 if s >= 0:
3186 if s >= 0:
3196 adddir(f[:s])
3187 adddir(f[:s])
3197 else:
3188 else:
3198 addfile(f)
3189 addfile(f)
3199 return files, dirs
3190 return files, dirs
3200
3191
3201 acceptable = ''
3192 acceptable = ''
3202 if opts['normal']:
3193 if opts['normal']:
3203 acceptable += 'nm'
3194 acceptable += 'nm'
3204 if opts['added']:
3195 if opts['added']:
3205 acceptable += 'a'
3196 acceptable += 'a'
3206 if opts['removed']:
3197 if opts['removed']:
3207 acceptable += 'r'
3198 acceptable += 'r'
3208 cwd = repo.getcwd()
3199 cwd = repo.getcwd()
3209 if not specs:
3200 if not specs:
3210 specs = ['.']
3201 specs = ['.']
3211
3202
3212 files, dirs = set(), set()
3203 files, dirs = set(), set()
3213 for spec in specs:
3204 for spec in specs:
3214 f, d = complete(spec, acceptable or 'nmar')
3205 f, d = complete(spec, acceptable or 'nmar')
3215 files.update(f)
3206 files.update(f)
3216 dirs.update(d)
3207 dirs.update(d)
3217 files.update(dirs)
3208 files.update(dirs)
3218 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3209 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3219 ui.write('\n')
3210 ui.write('\n')
3220
3211
3221 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3212 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3222 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3213 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3223 '''access the pushkey key/value protocol
3214 '''access the pushkey key/value protocol
3224
3215
3225 With two args, list the keys in the given namespace.
3216 With two args, list the keys in the given namespace.
3226
3217
3227 With five args, set a key to new if it currently is set to old.
3218 With five args, set a key to new if it currently is set to old.
3228 Reports success or failure.
3219 Reports success or failure.
3229 '''
3220 '''
3230
3221
3231 target = hg.peer(ui, {}, repopath)
3222 target = hg.peer(ui, {}, repopath)
3232 if keyinfo:
3223 if keyinfo:
3233 key, old, new = keyinfo
3224 key, old, new = keyinfo
3234 r = target.pushkey(namespace, key, old, new)
3225 r = target.pushkey(namespace, key, old, new)
3235 ui.status(str(r) + '\n')
3226 ui.status(str(r) + '\n')
3236 return not r
3227 return not r
3237 else:
3228 else:
3238 for k, v in sorted(target.listkeys(namespace).iteritems()):
3229 for k, v in sorted(target.listkeys(namespace).iteritems()):
3239 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3230 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3240 v.encode('string-escape')))
3231 v.encode('string-escape')))
3241
3232
3242 @command('debugpvec', [], _('A B'))
3233 @command('debugpvec', [], _('A B'))
3243 def debugpvec(ui, repo, a, b=None):
3234 def debugpvec(ui, repo, a, b=None):
3244 ca = scmutil.revsingle(repo, a)
3235 ca = scmutil.revsingle(repo, a)
3245 cb = scmutil.revsingle(repo, b)
3236 cb = scmutil.revsingle(repo, b)
3246 pa = pvec.ctxpvec(ca)
3237 pa = pvec.ctxpvec(ca)
3247 pb = pvec.ctxpvec(cb)
3238 pb = pvec.ctxpvec(cb)
3248 if pa == pb:
3239 if pa == pb:
3249 rel = "="
3240 rel = "="
3250 elif pa > pb:
3241 elif pa > pb:
3251 rel = ">"
3242 rel = ">"
3252 elif pa < pb:
3243 elif pa < pb:
3253 rel = "<"
3244 rel = "<"
3254 elif pa | pb:
3245 elif pa | pb:
3255 rel = "|"
3246 rel = "|"
3256 ui.write(_("a: %s\n") % pa)
3247 ui.write(_("a: %s\n") % pa)
3257 ui.write(_("b: %s\n") % pb)
3248 ui.write(_("b: %s\n") % pb)
3258 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3249 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3259 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3250 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3260 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3251 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3261 pa.distance(pb), rel))
3252 pa.distance(pb), rel))
3262
3253
3263 @command('debugrebuilddirstate|debugrebuildstate',
3254 @command('debugrebuilddirstate|debugrebuildstate',
3264 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3255 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3265 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3256 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3266 'the working copy parent')),
3257 'the working copy parent')),
3267 ],
3258 ],
3268 _('[-r REV]'))
3259 _('[-r REV]'))
3269 def debugrebuilddirstate(ui, repo, rev, **opts):
3260 def debugrebuilddirstate(ui, repo, rev, **opts):
3270 """rebuild the dirstate as it would look like for the given revision
3261 """rebuild the dirstate as it would look like for the given revision
3271
3262
3272 If no revision is specified the first current parent will be used.
3263 If no revision is specified the first current parent will be used.
3273
3264
3274 The dirstate will be set to the files of the given revision.
3265 The dirstate will be set to the files of the given revision.
3275 The actual working directory content or existing dirstate
3266 The actual working directory content or existing dirstate
3276 information such as adds or removes is not considered.
3267 information such as adds or removes is not considered.
3277
3268
3278 ``minimal`` will only rebuild the dirstate status for files that claim to be
3269 ``minimal`` will only rebuild the dirstate status for files that claim to be
3279 tracked but are not in the parent manifest, or that exist in the parent
3270 tracked but are not in the parent manifest, or that exist in the parent
3280 manifest but are not in the dirstate. It will not change adds, removes, or
3271 manifest but are not in the dirstate. It will not change adds, removes, or
3281 modified files that are in the working copy parent.
3272 modified files that are in the working copy parent.
3282
3273
3283 One use of this command is to make the next :hg:`status` invocation
3274 One use of this command is to make the next :hg:`status` invocation
3284 check the actual file content.
3275 check the actual file content.
3285 """
3276 """
3286 ctx = scmutil.revsingle(repo, rev)
3277 ctx = scmutil.revsingle(repo, rev)
3287 with repo.wlock():
3278 with repo.wlock():
3288 dirstate = repo.dirstate
3279 dirstate = repo.dirstate
3289 changedfiles = None
3280 changedfiles = None
3290 # See command doc for what minimal does.
3281 # See command doc for what minimal does.
3291 if opts.get('minimal'):
3282 if opts.get('minimal'):
3292 manifestfiles = set(ctx.manifest().keys())
3283 manifestfiles = set(ctx.manifest().keys())
3293 dirstatefiles = set(dirstate)
3284 dirstatefiles = set(dirstate)
3294 manifestonly = manifestfiles - dirstatefiles
3285 manifestonly = manifestfiles - dirstatefiles
3295 dsonly = dirstatefiles - manifestfiles
3286 dsonly = dirstatefiles - manifestfiles
3296 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3287 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3297 changedfiles = manifestonly | dsnotadded
3288 changedfiles = manifestonly | dsnotadded
3298
3289
3299 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3290 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3300
3291
3301 @command('debugrebuildfncache', [], '')
3292 @command('debugrebuildfncache', [], '')
3302 def debugrebuildfncache(ui, repo):
3293 def debugrebuildfncache(ui, repo):
3303 """rebuild the fncache file"""
3294 """rebuild the fncache file"""
3304 repair.rebuildfncache(ui, repo)
3295 repair.rebuildfncache(ui, repo)
3305
3296
3306 @command('debugrename',
3297 @command('debugrename',
3307 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3298 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3308 _('[-r REV] FILE'))
3299 _('[-r REV] FILE'))
3309 def debugrename(ui, repo, file1, *pats, **opts):
3300 def debugrename(ui, repo, file1, *pats, **opts):
3310 """dump rename information"""
3301 """dump rename information"""
3311
3302
3312 ctx = scmutil.revsingle(repo, opts.get('rev'))
3303 ctx = scmutil.revsingle(repo, opts.get('rev'))
3313 m = scmutil.match(ctx, (file1,) + pats, opts)
3304 m = scmutil.match(ctx, (file1,) + pats, opts)
3314 for abs in ctx.walk(m):
3305 for abs in ctx.walk(m):
3315 fctx = ctx[abs]
3306 fctx = ctx[abs]
3316 o = fctx.filelog().renamed(fctx.filenode())
3307 o = fctx.filelog().renamed(fctx.filenode())
3317 rel = m.rel(abs)
3308 rel = m.rel(abs)
3318 if o:
3309 if o:
3319 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3310 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3320 else:
3311 else:
3321 ui.write(_("%s not renamed\n") % rel)
3312 ui.write(_("%s not renamed\n") % rel)
3322
3313
3323 @command('debugrevlog', debugrevlogopts +
3314 @command('debugrevlog', debugrevlogopts +
3324 [('d', 'dump', False, _('dump index data'))],
3315 [('d', 'dump', False, _('dump index data'))],
3325 _('-c|-m|FILE'),
3316 _('-c|-m|FILE'),
3326 optionalrepo=True)
3317 optionalrepo=True)
3327 def debugrevlog(ui, repo, file_=None, **opts):
3318 def debugrevlog(ui, repo, file_=None, **opts):
3328 """show data and statistics about a revlog"""
3319 """show data and statistics about a revlog"""
3329 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3320 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3330
3321
3331 if opts.get("dump"):
3322 if opts.get("dump"):
3332 numrevs = len(r)
3323 numrevs = len(r)
3333 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3324 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3334 " rawsize totalsize compression heads chainlen\n"))
3325 " rawsize totalsize compression heads chainlen\n"))
3335 ts = 0
3326 ts = 0
3336 heads = set()
3327 heads = set()
3337
3328
3338 for rev in xrange(numrevs):
3329 for rev in xrange(numrevs):
3339 dbase = r.deltaparent(rev)
3330 dbase = r.deltaparent(rev)
3340 if dbase == -1:
3331 if dbase == -1:
3341 dbase = rev
3332 dbase = rev
3342 cbase = r.chainbase(rev)
3333 cbase = r.chainbase(rev)
3343 clen = r.chainlen(rev)
3334 clen = r.chainlen(rev)
3344 p1, p2 = r.parentrevs(rev)
3335 p1, p2 = r.parentrevs(rev)
3345 rs = r.rawsize(rev)
3336 rs = r.rawsize(rev)
3346 ts = ts + rs
3337 ts = ts + rs
3347 heads -= set(r.parentrevs(rev))
3338 heads -= set(r.parentrevs(rev))
3348 heads.add(rev)
3339 heads.add(rev)
3349 try:
3340 try:
3350 compression = ts / r.end(rev)
3341 compression = ts / r.end(rev)
3351 except ZeroDivisionError:
3342 except ZeroDivisionError:
3352 compression = 0
3343 compression = 0
3353 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3344 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3354 "%11d %5d %8d\n" %
3345 "%11d %5d %8d\n" %
3355 (rev, p1, p2, r.start(rev), r.end(rev),
3346 (rev, p1, p2, r.start(rev), r.end(rev),
3356 r.start(dbase), r.start(cbase),
3347 r.start(dbase), r.start(cbase),
3357 r.start(p1), r.start(p2),
3348 r.start(p1), r.start(p2),
3358 rs, ts, compression, len(heads), clen))
3349 rs, ts, compression, len(heads), clen))
3359 return 0
3350 return 0
3360
3351
3361 v = r.version
3352 v = r.version
3362 format = v & 0xFFFF
3353 format = v & 0xFFFF
3363 flags = []
3354 flags = []
3364 gdelta = False
3355 gdelta = False
3365 if v & revlog.REVLOGNGINLINEDATA:
3356 if v & revlog.REVLOGNGINLINEDATA:
3366 flags.append('inline')
3357 flags.append('inline')
3367 if v & revlog.REVLOGGENERALDELTA:
3358 if v & revlog.REVLOGGENERALDELTA:
3368 gdelta = True
3359 gdelta = True
3369 flags.append('generaldelta')
3360 flags.append('generaldelta')
3370 if not flags:
3361 if not flags:
3371 flags = ['(none)']
3362 flags = ['(none)']
3372
3363
3373 nummerges = 0
3364 nummerges = 0
3374 numfull = 0
3365 numfull = 0
3375 numprev = 0
3366 numprev = 0
3376 nump1 = 0
3367 nump1 = 0
3377 nump2 = 0
3368 nump2 = 0
3378 numother = 0
3369 numother = 0
3379 nump1prev = 0
3370 nump1prev = 0
3380 nump2prev = 0
3371 nump2prev = 0
3381 chainlengths = []
3372 chainlengths = []
3382
3373
3383 datasize = [None, 0, 0L]
3374 datasize = [None, 0, 0L]
3384 fullsize = [None, 0, 0L]
3375 fullsize = [None, 0, 0L]
3385 deltasize = [None, 0, 0L]
3376 deltasize = [None, 0, 0L]
3386
3377
3387 def addsize(size, l):
3378 def addsize(size, l):
3388 if l[0] is None or size < l[0]:
3379 if l[0] is None or size < l[0]:
3389 l[0] = size
3380 l[0] = size
3390 if size > l[1]:
3381 if size > l[1]:
3391 l[1] = size
3382 l[1] = size
3392 l[2] += size
3383 l[2] += size
3393
3384
3394 numrevs = len(r)
3385 numrevs = len(r)
3395 for rev in xrange(numrevs):
3386 for rev in xrange(numrevs):
3396 p1, p2 = r.parentrevs(rev)
3387 p1, p2 = r.parentrevs(rev)
3397 delta = r.deltaparent(rev)
3388 delta = r.deltaparent(rev)
3398 if format > 0:
3389 if format > 0:
3399 addsize(r.rawsize(rev), datasize)
3390 addsize(r.rawsize(rev), datasize)
3400 if p2 != nullrev:
3391 if p2 != nullrev:
3401 nummerges += 1
3392 nummerges += 1
3402 size = r.length(rev)
3393 size = r.length(rev)
3403 if delta == nullrev:
3394 if delta == nullrev:
3404 chainlengths.append(0)
3395 chainlengths.append(0)
3405 numfull += 1
3396 numfull += 1
3406 addsize(size, fullsize)
3397 addsize(size, fullsize)
3407 else:
3398 else:
3408 chainlengths.append(chainlengths[delta] + 1)
3399 chainlengths.append(chainlengths[delta] + 1)
3409 addsize(size, deltasize)
3400 addsize(size, deltasize)
3410 if delta == rev - 1:
3401 if delta == rev - 1:
3411 numprev += 1
3402 numprev += 1
3412 if delta == p1:
3403 if delta == p1:
3413 nump1prev += 1
3404 nump1prev += 1
3414 elif delta == p2:
3405 elif delta == p2:
3415 nump2prev += 1
3406 nump2prev += 1
3416 elif delta == p1:
3407 elif delta == p1:
3417 nump1 += 1
3408 nump1 += 1
3418 elif delta == p2:
3409 elif delta == p2:
3419 nump2 += 1
3410 nump2 += 1
3420 elif delta != nullrev:
3411 elif delta != nullrev:
3421 numother += 1
3412 numother += 1
3422
3413
3423 # Adjust size min value for empty cases
3414 # Adjust size min value for empty cases
3424 for size in (datasize, fullsize, deltasize):
3415 for size in (datasize, fullsize, deltasize):
3425 if size[0] is None:
3416 if size[0] is None:
3426 size[0] = 0
3417 size[0] = 0
3427
3418
3428 numdeltas = numrevs - numfull
3419 numdeltas = numrevs - numfull
3429 numoprev = numprev - nump1prev - nump2prev
3420 numoprev = numprev - nump1prev - nump2prev
3430 totalrawsize = datasize[2]
3421 totalrawsize = datasize[2]
3431 datasize[2] /= numrevs
3422 datasize[2] /= numrevs
3432 fulltotal = fullsize[2]
3423 fulltotal = fullsize[2]
3433 fullsize[2] /= numfull
3424 fullsize[2] /= numfull
3434 deltatotal = deltasize[2]
3425 deltatotal = deltasize[2]
3435 if numrevs - numfull > 0:
3426 if numrevs - numfull > 0:
3436 deltasize[2] /= numrevs - numfull
3427 deltasize[2] /= numrevs - numfull
3437 totalsize = fulltotal + deltatotal
3428 totalsize = fulltotal + deltatotal
3438 avgchainlen = sum(chainlengths) / numrevs
3429 avgchainlen = sum(chainlengths) / numrevs
3439 maxchainlen = max(chainlengths)
3430 maxchainlen = max(chainlengths)
3440 compratio = 1
3431 compratio = 1
3441 if totalsize:
3432 if totalsize:
3442 compratio = totalrawsize / totalsize
3433 compratio = totalrawsize / totalsize
3443
3434
3444 basedfmtstr = '%%%dd\n'
3435 basedfmtstr = '%%%dd\n'
3445 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3436 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3446
3437
3447 def dfmtstr(max):
3438 def dfmtstr(max):
3448 return basedfmtstr % len(str(max))
3439 return basedfmtstr % len(str(max))
3449 def pcfmtstr(max, padding=0):
3440 def pcfmtstr(max, padding=0):
3450 return basepcfmtstr % (len(str(max)), ' ' * padding)
3441 return basepcfmtstr % (len(str(max)), ' ' * padding)
3451
3442
3452 def pcfmt(value, total):
3443 def pcfmt(value, total):
3453 if total:
3444 if total:
3454 return (value, 100 * float(value) / total)
3445 return (value, 100 * float(value) / total)
3455 else:
3446 else:
3456 return value, 100.0
3447 return value, 100.0
3457
3448
3458 ui.write(('format : %d\n') % format)
3449 ui.write(('format : %d\n') % format)
3459 ui.write(('flags : %s\n') % ', '.join(flags))
3450 ui.write(('flags : %s\n') % ', '.join(flags))
3460
3451
3461 ui.write('\n')
3452 ui.write('\n')
3462 fmt = pcfmtstr(totalsize)
3453 fmt = pcfmtstr(totalsize)
3463 fmt2 = dfmtstr(totalsize)
3454 fmt2 = dfmtstr(totalsize)
3464 ui.write(('revisions : ') + fmt2 % numrevs)
3455 ui.write(('revisions : ') + fmt2 % numrevs)
3465 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3456 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3466 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3457 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3467 ui.write(('revisions : ') + fmt2 % numrevs)
3458 ui.write(('revisions : ') + fmt2 % numrevs)
3468 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3459 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3469 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3460 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3470 ui.write(('revision size : ') + fmt2 % totalsize)
3461 ui.write(('revision size : ') + fmt2 % totalsize)
3471 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3462 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3472 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3463 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3473
3464
3474 ui.write('\n')
3465 ui.write('\n')
3475 fmt = dfmtstr(max(avgchainlen, compratio))
3466 fmt = dfmtstr(max(avgchainlen, compratio))
3476 ui.write(('avg chain length : ') + fmt % avgchainlen)
3467 ui.write(('avg chain length : ') + fmt % avgchainlen)
3477 ui.write(('max chain length : ') + fmt % maxchainlen)
3468 ui.write(('max chain length : ') + fmt % maxchainlen)
3478 ui.write(('compression ratio : ') + fmt % compratio)
3469 ui.write(('compression ratio : ') + fmt % compratio)
3479
3470
3480 if format > 0:
3471 if format > 0:
3481 ui.write('\n')
3472 ui.write('\n')
3482 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3473 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3483 % tuple(datasize))
3474 % tuple(datasize))
3484 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3475 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3485 % tuple(fullsize))
3476 % tuple(fullsize))
3486 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3477 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3487 % tuple(deltasize))
3478 % tuple(deltasize))
3488
3479
3489 if numdeltas > 0:
3480 if numdeltas > 0:
3490 ui.write('\n')
3481 ui.write('\n')
3491 fmt = pcfmtstr(numdeltas)
3482 fmt = pcfmtstr(numdeltas)
3492 fmt2 = pcfmtstr(numdeltas, 4)
3483 fmt2 = pcfmtstr(numdeltas, 4)
3493 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3484 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3494 if numprev > 0:
3485 if numprev > 0:
3495 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3486 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3496 numprev))
3487 numprev))
3497 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3488 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3498 numprev))
3489 numprev))
3499 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3490 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3500 numprev))
3491 numprev))
3501 if gdelta:
3492 if gdelta:
3502 ui.write(('deltas against p1 : ')
3493 ui.write(('deltas against p1 : ')
3503 + fmt % pcfmt(nump1, numdeltas))
3494 + fmt % pcfmt(nump1, numdeltas))
3504 ui.write(('deltas against p2 : ')
3495 ui.write(('deltas against p2 : ')
3505 + fmt % pcfmt(nump2, numdeltas))
3496 + fmt % pcfmt(nump2, numdeltas))
3506 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3497 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3507 numdeltas))
3498 numdeltas))
3508
3499
3509 @command('debugrevspec',
3500 @command('debugrevspec',
3510 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3501 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3511 ('REVSPEC'))
3502 ('REVSPEC'))
3512 def debugrevspec(ui, repo, expr, **opts):
3503 def debugrevspec(ui, repo, expr, **opts):
3513 """parse and apply a revision specification
3504 """parse and apply a revision specification
3514
3505
3515 Use --verbose to print the parsed tree before and after aliases
3506 Use --verbose to print the parsed tree before and after aliases
3516 expansion.
3507 expansion.
3517 """
3508 """
3518 if ui.verbose:
3509 if ui.verbose:
3519 tree = revset.parse(expr, lookup=repo.__contains__)
3510 tree = revset.parse(expr, lookup=repo.__contains__)
3520 ui.note(revset.prettyformat(tree), "\n")
3511 ui.note(revset.prettyformat(tree), "\n")
3521 newtree = revset.expandaliases(ui, tree)
3512 newtree = revset.expandaliases(ui, tree)
3522 if newtree != tree:
3513 if newtree != tree:
3523 ui.note(("* expanded:\n"), revset.prettyformat(newtree), "\n")
3514 ui.note(("* expanded:\n"), revset.prettyformat(newtree), "\n")
3524 tree = newtree
3515 tree = newtree
3525 newtree = revset.foldconcat(tree)
3516 newtree = revset.foldconcat(tree)
3526 if newtree != tree:
3517 if newtree != tree:
3527 ui.note(("* concatenated:\n"), revset.prettyformat(newtree), "\n")
3518 ui.note(("* concatenated:\n"), revset.prettyformat(newtree), "\n")
3528 if opts["optimize"]:
3519 if opts["optimize"]:
3529 optimizedtree = revset.optimize(newtree)
3520 optimizedtree = revset.optimize(newtree)
3530 ui.note(("* optimized:\n"),
3521 ui.note(("* optimized:\n"),
3531 revset.prettyformat(optimizedtree), "\n")
3522 revset.prettyformat(optimizedtree), "\n")
3532 func = revset.match(ui, expr, repo)
3523 func = revset.match(ui, expr, repo)
3533 revs = func(repo)
3524 revs = func(repo)
3534 if ui.verbose:
3525 if ui.verbose:
3535 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3526 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3536 for c in revs:
3527 for c in revs:
3537 ui.write("%s\n" % c)
3528 ui.write("%s\n" % c)
3538
3529
3539 @command('debugsetparents', [], _('REV1 [REV2]'))
3530 @command('debugsetparents', [], _('REV1 [REV2]'))
3540 def debugsetparents(ui, repo, rev1, rev2=None):
3531 def debugsetparents(ui, repo, rev1, rev2=None):
3541 """manually set the parents of the current working directory
3532 """manually set the parents of the current working directory
3542
3533
3543 This is useful for writing repository conversion tools, but should
3534 This is useful for writing repository conversion tools, but should
3544 be used with care. For example, neither the working directory nor the
3535 be used with care. For example, neither the working directory nor the
3545 dirstate is updated, so file status may be incorrect after running this
3536 dirstate is updated, so file status may be incorrect after running this
3546 command.
3537 command.
3547
3538
3548 Returns 0 on success.
3539 Returns 0 on success.
3549 """
3540 """
3550
3541
3551 r1 = scmutil.revsingle(repo, rev1).node()
3542 r1 = scmutil.revsingle(repo, rev1).node()
3552 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3543 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3553
3544
3554 with repo.wlock():
3545 with repo.wlock():
3555 repo.setparents(r1, r2)
3546 repo.setparents(r1, r2)
3556
3547
3557 @command('debugdirstate|debugstate',
3548 @command('debugdirstate|debugstate',
3558 [('', 'nodates', None, _('do not display the saved mtime')),
3549 [('', 'nodates', None, _('do not display the saved mtime')),
3559 ('', 'datesort', None, _('sort by saved mtime'))],
3550 ('', 'datesort', None, _('sort by saved mtime'))],
3560 _('[OPTION]...'))
3551 _('[OPTION]...'))
3561 def debugstate(ui, repo, **opts):
3552 def debugstate(ui, repo, **opts):
3562 """show the contents of the current dirstate"""
3553 """show the contents of the current dirstate"""
3563
3554
3564 nodates = opts.get('nodates')
3555 nodates = opts.get('nodates')
3565 datesort = opts.get('datesort')
3556 datesort = opts.get('datesort')
3566
3557
3567 timestr = ""
3558 timestr = ""
3568 if datesort:
3559 if datesort:
3569 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3560 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3570 else:
3561 else:
3571 keyfunc = None # sort by filename
3562 keyfunc = None # sort by filename
3572 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3563 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3573 if ent[3] == -1:
3564 if ent[3] == -1:
3574 timestr = 'unset '
3565 timestr = 'unset '
3575 elif nodates:
3566 elif nodates:
3576 timestr = 'set '
3567 timestr = 'set '
3577 else:
3568 else:
3578 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3569 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3579 time.localtime(ent[3]))
3570 time.localtime(ent[3]))
3580 if ent[1] & 0o20000:
3571 if ent[1] & 0o20000:
3581 mode = 'lnk'
3572 mode = 'lnk'
3582 else:
3573 else:
3583 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3574 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3584 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3575 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3585 for f in repo.dirstate.copies():
3576 for f in repo.dirstate.copies():
3586 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3577 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3587
3578
3588 @command('debugsub',
3579 @command('debugsub',
3589 [('r', 'rev', '',
3580 [('r', 'rev', '',
3590 _('revision to check'), _('REV'))],
3581 _('revision to check'), _('REV'))],
3591 _('[-r REV] [REV]'))
3582 _('[-r REV] [REV]'))
3592 def debugsub(ui, repo, rev=None):
3583 def debugsub(ui, repo, rev=None):
3593 ctx = scmutil.revsingle(repo, rev, None)
3584 ctx = scmutil.revsingle(repo, rev, None)
3594 for k, v in sorted(ctx.substate.items()):
3585 for k, v in sorted(ctx.substate.items()):
3595 ui.write(('path %s\n') % k)
3586 ui.write(('path %s\n') % k)
3596 ui.write((' source %s\n') % v[0])
3587 ui.write((' source %s\n') % v[0])
3597 ui.write((' revision %s\n') % v[1])
3588 ui.write((' revision %s\n') % v[1])
3598
3589
3599 @command('debugsuccessorssets',
3590 @command('debugsuccessorssets',
3600 [],
3591 [],
3601 _('[REV]'))
3592 _('[REV]'))
3602 def debugsuccessorssets(ui, repo, *revs):
3593 def debugsuccessorssets(ui, repo, *revs):
3603 """show set of successors for revision
3594 """show set of successors for revision
3604
3595
3605 A successors set of changeset A is a consistent group of revisions that
3596 A successors set of changeset A is a consistent group of revisions that
3606 succeed A. It contains non-obsolete changesets only.
3597 succeed A. It contains non-obsolete changesets only.
3607
3598
3608 In most cases a changeset A has a single successors set containing a single
3599 In most cases a changeset A has a single successors set containing a single
3609 successor (changeset A replaced by A').
3600 successor (changeset A replaced by A').
3610
3601
3611 A changeset that is made obsolete with no successors are called "pruned".
3602 A changeset that is made obsolete with no successors are called "pruned".
3612 Such changesets have no successors sets at all.
3603 Such changesets have no successors sets at all.
3613
3604
3614 A changeset that has been "split" will have a successors set containing
3605 A changeset that has been "split" will have a successors set containing
3615 more than one successor.
3606 more than one successor.
3616
3607
3617 A changeset that has been rewritten in multiple different ways is called
3608 A changeset that has been rewritten in multiple different ways is called
3618 "divergent". Such changesets have multiple successor sets (each of which
3609 "divergent". Such changesets have multiple successor sets (each of which
3619 may also be split, i.e. have multiple successors).
3610 may also be split, i.e. have multiple successors).
3620
3611
3621 Results are displayed as follows::
3612 Results are displayed as follows::
3622
3613
3623 <rev1>
3614 <rev1>
3624 <successors-1A>
3615 <successors-1A>
3625 <rev2>
3616 <rev2>
3626 <successors-2A>
3617 <successors-2A>
3627 <successors-2B1> <successors-2B2> <successors-2B3>
3618 <successors-2B1> <successors-2B2> <successors-2B3>
3628
3619
3629 Here rev2 has two possible (i.e. divergent) successors sets. The first
3620 Here rev2 has two possible (i.e. divergent) successors sets. The first
3630 holds one element, whereas the second holds three (i.e. the changeset has
3621 holds one element, whereas the second holds three (i.e. the changeset has
3631 been split).
3622 been split).
3632 """
3623 """
3633 # passed to successorssets caching computation from one call to another
3624 # passed to successorssets caching computation from one call to another
3634 cache = {}
3625 cache = {}
3635 ctx2str = str
3626 ctx2str = str
3636 node2str = short
3627 node2str = short
3637 if ui.debug():
3628 if ui.debug():
3638 def ctx2str(ctx):
3629 def ctx2str(ctx):
3639 return ctx.hex()
3630 return ctx.hex()
3640 node2str = hex
3631 node2str = hex
3641 for rev in scmutil.revrange(repo, revs):
3632 for rev in scmutil.revrange(repo, revs):
3642 ctx = repo[rev]
3633 ctx = repo[rev]
3643 ui.write('%s\n'% ctx2str(ctx))
3634 ui.write('%s\n'% ctx2str(ctx))
3644 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3635 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3645 if succsset:
3636 if succsset:
3646 ui.write(' ')
3637 ui.write(' ')
3647 ui.write(node2str(succsset[0]))
3638 ui.write(node2str(succsset[0]))
3648 for node in succsset[1:]:
3639 for node in succsset[1:]:
3649 ui.write(' ')
3640 ui.write(' ')
3650 ui.write(node2str(node))
3641 ui.write(node2str(node))
3651 ui.write('\n')
3642 ui.write('\n')
3652
3643
3653 @command('debugtemplate',
3644 @command('debugtemplate',
3654 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3645 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3655 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3646 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3656 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3647 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3657 optionalrepo=True)
3648 optionalrepo=True)
3658 def debugtemplate(ui, repo, tmpl, **opts):
3649 def debugtemplate(ui, repo, tmpl, **opts):
3659 """parse and apply a template
3650 """parse and apply a template
3660
3651
3661 If -r/--rev is given, the template is processed as a log template and
3652 If -r/--rev is given, the template is processed as a log template and
3662 applied to the given changesets. Otherwise, it is processed as a generic
3653 applied to the given changesets. Otherwise, it is processed as a generic
3663 template.
3654 template.
3664
3655
3665 Use --verbose to print the parsed tree.
3656 Use --verbose to print the parsed tree.
3666 """
3657 """
3667 revs = None
3658 revs = None
3668 if opts['rev']:
3659 if opts['rev']:
3669 if repo is None:
3660 if repo is None:
3670 raise error.RepoError(_('there is no Mercurial repository here '
3661 raise error.RepoError(_('there is no Mercurial repository here '
3671 '(.hg not found)'))
3662 '(.hg not found)'))
3672 revs = scmutil.revrange(repo, opts['rev'])
3663 revs = scmutil.revrange(repo, opts['rev'])
3673
3664
3674 props = {}
3665 props = {}
3675 for d in opts['define']:
3666 for d in opts['define']:
3676 try:
3667 try:
3677 k, v = (e.strip() for e in d.split('=', 1))
3668 k, v = (e.strip() for e in d.split('=', 1))
3678 if not k:
3669 if not k:
3679 raise ValueError
3670 raise ValueError
3680 props[k] = v
3671 props[k] = v
3681 except ValueError:
3672 except ValueError:
3682 raise error.Abort(_('malformed keyword definition: %s') % d)
3673 raise error.Abort(_('malformed keyword definition: %s') % d)
3683
3674
3684 if ui.verbose:
3675 if ui.verbose:
3685 aliases = ui.configitems('templatealias')
3676 aliases = ui.configitems('templatealias')
3686 tree = templater.parse(tmpl)
3677 tree = templater.parse(tmpl)
3687 ui.note(templater.prettyformat(tree), '\n')
3678 ui.note(templater.prettyformat(tree), '\n')
3688 newtree = templater.expandaliases(tree, aliases)
3679 newtree = templater.expandaliases(tree, aliases)
3689 if newtree != tree:
3680 if newtree != tree:
3690 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3681 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3691
3682
3692 mapfile = None
3683 mapfile = None
3693 if revs is None:
3684 if revs is None:
3694 k = 'debugtemplate'
3685 k = 'debugtemplate'
3695 t = formatter.maketemplater(ui, k, tmpl)
3686 t = formatter.maketemplater(ui, k, tmpl)
3696 ui.write(templater.stringify(t(k, **props)))
3687 ui.write(templater.stringify(t(k, **props)))
3697 else:
3688 else:
3698 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3689 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3699 mapfile, buffered=False)
3690 mapfile, buffered=False)
3700 for r in revs:
3691 for r in revs:
3701 displayer.show(repo[r], **props)
3692 displayer.show(repo[r], **props)
3702 displayer.close()
3693 displayer.close()
3703
3694
3704 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3695 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3705 def debugwalk(ui, repo, *pats, **opts):
3696 def debugwalk(ui, repo, *pats, **opts):
3706 """show how files match on given patterns"""
3697 """show how files match on given patterns"""
3707 m = scmutil.match(repo[None], pats, opts)
3698 m = scmutil.match(repo[None], pats, opts)
3708 items = list(repo.walk(m))
3699 items = list(repo.walk(m))
3709 if not items:
3700 if not items:
3710 return
3701 return
3711 f = lambda fn: fn
3702 f = lambda fn: fn
3712 if ui.configbool('ui', 'slash') and os.sep != '/':
3703 if ui.configbool('ui', 'slash') and os.sep != '/':
3713 f = lambda fn: util.normpath(fn)
3704 f = lambda fn: util.normpath(fn)
3714 fmt = 'f %%-%ds %%-%ds %%s' % (
3705 fmt = 'f %%-%ds %%-%ds %%s' % (
3715 max([len(abs) for abs in items]),
3706 max([len(abs) for abs in items]),
3716 max([len(m.rel(abs)) for abs in items]))
3707 max([len(m.rel(abs)) for abs in items]))
3717 for abs in items:
3708 for abs in items:
3718 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3709 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3719 ui.write("%s\n" % line.rstrip())
3710 ui.write("%s\n" % line.rstrip())
3720
3711
3721 @command('debugwireargs',
3712 @command('debugwireargs',
3722 [('', 'three', '', 'three'),
3713 [('', 'three', '', 'three'),
3723 ('', 'four', '', 'four'),
3714 ('', 'four', '', 'four'),
3724 ('', 'five', '', 'five'),
3715 ('', 'five', '', 'five'),
3725 ] + remoteopts,
3716 ] + remoteopts,
3726 _('REPO [OPTIONS]... [ONE [TWO]]'),
3717 _('REPO [OPTIONS]... [ONE [TWO]]'),
3727 norepo=True)
3718 norepo=True)
3728 def debugwireargs(ui, repopath, *vals, **opts):
3719 def debugwireargs(ui, repopath, *vals, **opts):
3729 repo = hg.peer(ui, opts, repopath)
3720 repo = hg.peer(ui, opts, repopath)
3730 for opt in remoteopts:
3721 for opt in remoteopts:
3731 del opts[opt[1]]
3722 del opts[opt[1]]
3732 args = {}
3723 args = {}
3733 for k, v in opts.iteritems():
3724 for k, v in opts.iteritems():
3734 if v:
3725 if v:
3735 args[k] = v
3726 args[k] = v
3736 # run twice to check that we don't mess up the stream for the next command
3727 # run twice to check that we don't mess up the stream for the next command
3737 res1 = repo.debugwireargs(*vals, **args)
3728 res1 = repo.debugwireargs(*vals, **args)
3738 res2 = repo.debugwireargs(*vals, **args)
3729 res2 = repo.debugwireargs(*vals, **args)
3739 ui.write("%s\n" % res1)
3730 ui.write("%s\n" % res1)
3740 if res1 != res2:
3731 if res1 != res2:
3741 ui.warn("%s\n" % res2)
3732 ui.warn("%s\n" % res2)
3742
3733
3743 @command('^diff',
3734 @command('^diff',
3744 [('r', 'rev', [], _('revision'), _('REV')),
3735 [('r', 'rev', [], _('revision'), _('REV')),
3745 ('c', 'change', '', _('change made by revision'), _('REV'))
3736 ('c', 'change', '', _('change made by revision'), _('REV'))
3746 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3737 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3747 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3738 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3748 inferrepo=True)
3739 inferrepo=True)
3749 def diff(ui, repo, *pats, **opts):
3740 def diff(ui, repo, *pats, **opts):
3750 """diff repository (or selected files)
3741 """diff repository (or selected files)
3751
3742
3752 Show differences between revisions for the specified files.
3743 Show differences between revisions for the specified files.
3753
3744
3754 Differences between files are shown using the unified diff format.
3745 Differences between files are shown using the unified diff format.
3755
3746
3756 .. note::
3747 .. note::
3757
3748
3758 :hg:`diff` may generate unexpected results for merges, as it will
3749 :hg:`diff` may generate unexpected results for merges, as it will
3759 default to comparing against the working directory's first
3750 default to comparing against the working directory's first
3760 parent changeset if no revisions are specified.
3751 parent changeset if no revisions are specified.
3761
3752
3762 When two revision arguments are given, then changes are shown
3753 When two revision arguments are given, then changes are shown
3763 between those revisions. If only one revision is specified then
3754 between those revisions. If only one revision is specified then
3764 that revision is compared to the working directory, and, when no
3755 that revision is compared to the working directory, and, when no
3765 revisions are specified, the working directory files are compared
3756 revisions are specified, the working directory files are compared
3766 to its first parent.
3757 to its first parent.
3767
3758
3768 Alternatively you can specify -c/--change with a revision to see
3759 Alternatively you can specify -c/--change with a revision to see
3769 the changes in that changeset relative to its first parent.
3760 the changes in that changeset relative to its first parent.
3770
3761
3771 Without the -a/--text option, diff will avoid generating diffs of
3762 Without the -a/--text option, diff will avoid generating diffs of
3772 files it detects as binary. With -a, diff will generate a diff
3763 files it detects as binary. With -a, diff will generate a diff
3773 anyway, probably with undesirable results.
3764 anyway, probably with undesirable results.
3774
3765
3775 Use the -g/--git option to generate diffs in the git extended diff
3766 Use the -g/--git option to generate diffs in the git extended diff
3776 format. For more information, read :hg:`help diffs`.
3767 format. For more information, read :hg:`help diffs`.
3777
3768
3778 .. container:: verbose
3769 .. container:: verbose
3779
3770
3780 Examples:
3771 Examples:
3781
3772
3782 - compare a file in the current working directory to its parent::
3773 - compare a file in the current working directory to its parent::
3783
3774
3784 hg diff foo.c
3775 hg diff foo.c
3785
3776
3786 - compare two historical versions of a directory, with rename info::
3777 - compare two historical versions of a directory, with rename info::
3787
3778
3788 hg diff --git -r 1.0:1.2 lib/
3779 hg diff --git -r 1.0:1.2 lib/
3789
3780
3790 - get change stats relative to the last change on some date::
3781 - get change stats relative to the last change on some date::
3791
3782
3792 hg diff --stat -r "date('may 2')"
3783 hg diff --stat -r "date('may 2')"
3793
3784
3794 - diff all newly-added files that contain a keyword::
3785 - diff all newly-added files that contain a keyword::
3795
3786
3796 hg diff "set:added() and grep(GNU)"
3787 hg diff "set:added() and grep(GNU)"
3797
3788
3798 - compare a revision and its parents::
3789 - compare a revision and its parents::
3799
3790
3800 hg diff -c 9353 # compare against first parent
3791 hg diff -c 9353 # compare against first parent
3801 hg diff -r 9353^:9353 # same using revset syntax
3792 hg diff -r 9353^:9353 # same using revset syntax
3802 hg diff -r 9353^2:9353 # compare against the second parent
3793 hg diff -r 9353^2:9353 # compare against the second parent
3803
3794
3804 Returns 0 on success.
3795 Returns 0 on success.
3805 """
3796 """
3806
3797
3807 revs = opts.get('rev')
3798 revs = opts.get('rev')
3808 change = opts.get('change')
3799 change = opts.get('change')
3809 stat = opts.get('stat')
3800 stat = opts.get('stat')
3810 reverse = opts.get('reverse')
3801 reverse = opts.get('reverse')
3811
3802
3812 if revs and change:
3803 if revs and change:
3813 msg = _('cannot specify --rev and --change at the same time')
3804 msg = _('cannot specify --rev and --change at the same time')
3814 raise error.Abort(msg)
3805 raise error.Abort(msg)
3815 elif change:
3806 elif change:
3816 node2 = scmutil.revsingle(repo, change, None).node()
3807 node2 = scmutil.revsingle(repo, change, None).node()
3817 node1 = repo[node2].p1().node()
3808 node1 = repo[node2].p1().node()
3818 else:
3809 else:
3819 node1, node2 = scmutil.revpair(repo, revs)
3810 node1, node2 = scmutil.revpair(repo, revs)
3820
3811
3821 if reverse:
3812 if reverse:
3822 node1, node2 = node2, node1
3813 node1, node2 = node2, node1
3823
3814
3824 diffopts = patch.diffallopts(ui, opts)
3815 diffopts = patch.diffallopts(ui, opts)
3825 m = scmutil.match(repo[node2], pats, opts)
3816 m = scmutil.match(repo[node2], pats, opts)
3826 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3817 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3827 listsubrepos=opts.get('subrepos'),
3818 listsubrepos=opts.get('subrepos'),
3828 root=opts.get('root'))
3819 root=opts.get('root'))
3829
3820
3830 @command('^export',
3821 @command('^export',
3831 [('o', 'output', '',
3822 [('o', 'output', '',
3832 _('print output to file with formatted name'), _('FORMAT')),
3823 _('print output to file with formatted name'), _('FORMAT')),
3833 ('', 'switch-parent', None, _('diff against the second parent')),
3824 ('', 'switch-parent', None, _('diff against the second parent')),
3834 ('r', 'rev', [], _('revisions to export'), _('REV')),
3825 ('r', 'rev', [], _('revisions to export'), _('REV')),
3835 ] + diffopts,
3826 ] + diffopts,
3836 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3827 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3837 def export(ui, repo, *changesets, **opts):
3828 def export(ui, repo, *changesets, **opts):
3838 """dump the header and diffs for one or more changesets
3829 """dump the header and diffs for one or more changesets
3839
3830
3840 Print the changeset header and diffs for one or more revisions.
3831 Print the changeset header and diffs for one or more revisions.
3841 If no revision is given, the parent of the working directory is used.
3832 If no revision is given, the parent of the working directory is used.
3842
3833
3843 The information shown in the changeset header is: author, date,
3834 The information shown in the changeset header is: author, date,
3844 branch name (if non-default), changeset hash, parent(s) and commit
3835 branch name (if non-default), changeset hash, parent(s) and commit
3845 comment.
3836 comment.
3846
3837
3847 .. note::
3838 .. note::
3848
3839
3849 :hg:`export` may generate unexpected diff output for merge
3840 :hg:`export` may generate unexpected diff output for merge
3850 changesets, as it will compare the merge changeset against its
3841 changesets, as it will compare the merge changeset against its
3851 first parent only.
3842 first parent only.
3852
3843
3853 Output may be to a file, in which case the name of the file is
3844 Output may be to a file, in which case the name of the file is
3854 given using a format string. The formatting rules are as follows:
3845 given using a format string. The formatting rules are as follows:
3855
3846
3856 :``%%``: literal "%" character
3847 :``%%``: literal "%" character
3857 :``%H``: changeset hash (40 hexadecimal digits)
3848 :``%H``: changeset hash (40 hexadecimal digits)
3858 :``%N``: number of patches being generated
3849 :``%N``: number of patches being generated
3859 :``%R``: changeset revision number
3850 :``%R``: changeset revision number
3860 :``%b``: basename of the exporting repository
3851 :``%b``: basename of the exporting repository
3861 :``%h``: short-form changeset hash (12 hexadecimal digits)
3852 :``%h``: short-form changeset hash (12 hexadecimal digits)
3862 :``%m``: first line of the commit message (only alphanumeric characters)
3853 :``%m``: first line of the commit message (only alphanumeric characters)
3863 :``%n``: zero-padded sequence number, starting at 1
3854 :``%n``: zero-padded sequence number, starting at 1
3864 :``%r``: zero-padded changeset revision number
3855 :``%r``: zero-padded changeset revision number
3865
3856
3866 Without the -a/--text option, export will avoid generating diffs
3857 Without the -a/--text option, export will avoid generating diffs
3867 of files it detects as binary. With -a, export will generate a
3858 of files it detects as binary. With -a, export will generate a
3868 diff anyway, probably with undesirable results.
3859 diff anyway, probably with undesirable results.
3869
3860
3870 Use the -g/--git option to generate diffs in the git extended diff
3861 Use the -g/--git option to generate diffs in the git extended diff
3871 format. See :hg:`help diffs` for more information.
3862 format. See :hg:`help diffs` for more information.
3872
3863
3873 With the --switch-parent option, the diff will be against the
3864 With the --switch-parent option, the diff will be against the
3874 second parent. It can be useful to review a merge.
3865 second parent. It can be useful to review a merge.
3875
3866
3876 .. container:: verbose
3867 .. container:: verbose
3877
3868
3878 Examples:
3869 Examples:
3879
3870
3880 - use export and import to transplant a bugfix to the current
3871 - use export and import to transplant a bugfix to the current
3881 branch::
3872 branch::
3882
3873
3883 hg export -r 9353 | hg import -
3874 hg export -r 9353 | hg import -
3884
3875
3885 - export all the changesets between two revisions to a file with
3876 - export all the changesets between two revisions to a file with
3886 rename information::
3877 rename information::
3887
3878
3888 hg export --git -r 123:150 > changes.txt
3879 hg export --git -r 123:150 > changes.txt
3889
3880
3890 - split outgoing changes into a series of patches with
3881 - split outgoing changes into a series of patches with
3891 descriptive names::
3882 descriptive names::
3892
3883
3893 hg export -r "outgoing()" -o "%n-%m.patch"
3884 hg export -r "outgoing()" -o "%n-%m.patch"
3894
3885
3895 Returns 0 on success.
3886 Returns 0 on success.
3896 """
3887 """
3897 changesets += tuple(opts.get('rev', []))
3888 changesets += tuple(opts.get('rev', []))
3898 if not changesets:
3889 if not changesets:
3899 changesets = ['.']
3890 changesets = ['.']
3900 revs = scmutil.revrange(repo, changesets)
3891 revs = scmutil.revrange(repo, changesets)
3901 if not revs:
3892 if not revs:
3902 raise error.Abort(_("export requires at least one changeset"))
3893 raise error.Abort(_("export requires at least one changeset"))
3903 if len(revs) > 1:
3894 if len(revs) > 1:
3904 ui.note(_('exporting patches:\n'))
3895 ui.note(_('exporting patches:\n'))
3905 else:
3896 else:
3906 ui.note(_('exporting patch:\n'))
3897 ui.note(_('exporting patch:\n'))
3907 cmdutil.export(repo, revs, template=opts.get('output'),
3898 cmdutil.export(repo, revs, template=opts.get('output'),
3908 switch_parent=opts.get('switch_parent'),
3899 switch_parent=opts.get('switch_parent'),
3909 opts=patch.diffallopts(ui, opts))
3900 opts=patch.diffallopts(ui, opts))
3910
3901
3911 @command('files',
3902 @command('files',
3912 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3903 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3913 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3904 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3914 ] + walkopts + formatteropts + subrepoopts,
3905 ] + walkopts + formatteropts + subrepoopts,
3915 _('[OPTION]... [PATTERN]...'))
3906 _('[OPTION]... [PATTERN]...'))
3916 def files(ui, repo, *pats, **opts):
3907 def files(ui, repo, *pats, **opts):
3917 """list tracked files
3908 """list tracked files
3918
3909
3919 Print files under Mercurial control in the working directory or
3910 Print files under Mercurial control in the working directory or
3920 specified revision whose names match the given patterns (excluding
3911 specified revision whose names match the given patterns (excluding
3921 removed files).
3912 removed files).
3922
3913
3923 If no patterns are given to match, this command prints the names
3914 If no patterns are given to match, this command prints the names
3924 of all files under Mercurial control in the working directory.
3915 of all files under Mercurial control in the working directory.
3925
3916
3926 .. container:: verbose
3917 .. container:: verbose
3927
3918
3928 Examples:
3919 Examples:
3929
3920
3930 - list all files under the current directory::
3921 - list all files under the current directory::
3931
3922
3932 hg files .
3923 hg files .
3933
3924
3934 - shows sizes and flags for current revision::
3925 - shows sizes and flags for current revision::
3935
3926
3936 hg files -vr .
3927 hg files -vr .
3937
3928
3938 - list all files named README::
3929 - list all files named README::
3939
3930
3940 hg files -I "**/README"
3931 hg files -I "**/README"
3941
3932
3942 - list all binary files::
3933 - list all binary files::
3943
3934
3944 hg files "set:binary()"
3935 hg files "set:binary()"
3945
3936
3946 - find files containing a regular expression::
3937 - find files containing a regular expression::
3947
3938
3948 hg files "set:grep('bob')"
3939 hg files "set:grep('bob')"
3949
3940
3950 - search tracked file contents with xargs and grep::
3941 - search tracked file contents with xargs and grep::
3951
3942
3952 hg files -0 | xargs -0 grep foo
3943 hg files -0 | xargs -0 grep foo
3953
3944
3954 See :hg:`help patterns` and :hg:`help filesets` for more information
3945 See :hg:`help patterns` and :hg:`help filesets` for more information
3955 on specifying file patterns.
3946 on specifying file patterns.
3956
3947
3957 Returns 0 if a match is found, 1 otherwise.
3948 Returns 0 if a match is found, 1 otherwise.
3958
3949
3959 """
3950 """
3960 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3951 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3961
3952
3962 end = '\n'
3953 end = '\n'
3963 if opts.get('print0'):
3954 if opts.get('print0'):
3964 end = '\0'
3955 end = '\0'
3965 fm = ui.formatter('files', opts)
3956 fm = ui.formatter('files', opts)
3966 fmt = '%s' + end
3957 fmt = '%s' + end
3967
3958
3968 m = scmutil.match(ctx, pats, opts)
3959 m = scmutil.match(ctx, pats, opts)
3969 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3960 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3970
3961
3971 fm.end()
3962 fm.end()
3972
3963
3973 return ret
3964 return ret
3974
3965
3975 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3966 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3976 def forget(ui, repo, *pats, **opts):
3967 def forget(ui, repo, *pats, **opts):
3977 """forget the specified files on the next commit
3968 """forget the specified files on the next commit
3978
3969
3979 Mark the specified files so they will no longer be tracked
3970 Mark the specified files so they will no longer be tracked
3980 after the next commit.
3971 after the next commit.
3981
3972
3982 This only removes files from the current branch, not from the
3973 This only removes files from the current branch, not from the
3983 entire project history, and it does not delete them from the
3974 entire project history, and it does not delete them from the
3984 working directory.
3975 working directory.
3985
3976
3986 To delete the file from the working directory, see :hg:`remove`.
3977 To delete the file from the working directory, see :hg:`remove`.
3987
3978
3988 To undo a forget before the next commit, see :hg:`add`.
3979 To undo a forget before the next commit, see :hg:`add`.
3989
3980
3990 .. container:: verbose
3981 .. container:: verbose
3991
3982
3992 Examples:
3983 Examples:
3993
3984
3994 - forget newly-added binary files::
3985 - forget newly-added binary files::
3995
3986
3996 hg forget "set:added() and binary()"
3987 hg forget "set:added() and binary()"
3997
3988
3998 - forget files that would be excluded by .hgignore::
3989 - forget files that would be excluded by .hgignore::
3999
3990
4000 hg forget "set:hgignore()"
3991 hg forget "set:hgignore()"
4001
3992
4002 Returns 0 on success.
3993 Returns 0 on success.
4003 """
3994 """
4004
3995
4005 if not pats:
3996 if not pats:
4006 raise error.Abort(_('no files specified'))
3997 raise error.Abort(_('no files specified'))
4007
3998
4008 m = scmutil.match(repo[None], pats, opts)
3999 m = scmutil.match(repo[None], pats, opts)
4009 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4000 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4010 return rejected and 1 or 0
4001 return rejected and 1 or 0
4011
4002
4012 @command(
4003 @command(
4013 'graft',
4004 'graft',
4014 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4005 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4015 ('c', 'continue', False, _('resume interrupted graft')),
4006 ('c', 'continue', False, _('resume interrupted graft')),
4016 ('e', 'edit', False, _('invoke editor on commit messages')),
4007 ('e', 'edit', False, _('invoke editor on commit messages')),
4017 ('', 'log', None, _('append graft info to log message')),
4008 ('', 'log', None, _('append graft info to log message')),
4018 ('f', 'force', False, _('force graft')),
4009 ('f', 'force', False, _('force graft')),
4019 ('D', 'currentdate', False,
4010 ('D', 'currentdate', False,
4020 _('record the current date as commit date')),
4011 _('record the current date as commit date')),
4021 ('U', 'currentuser', False,
4012 ('U', 'currentuser', False,
4022 _('record the current user as committer'), _('DATE'))]
4013 _('record the current user as committer'), _('DATE'))]
4023 + commitopts2 + mergetoolopts + dryrunopts,
4014 + commitopts2 + mergetoolopts + dryrunopts,
4024 _('[OPTION]... [-r REV]... REV...'))
4015 _('[OPTION]... [-r REV]... REV...'))
4025 def graft(ui, repo, *revs, **opts):
4016 def graft(ui, repo, *revs, **opts):
4026 '''copy changes from other branches onto the current branch
4017 '''copy changes from other branches onto the current branch
4027
4018
4028 This command uses Mercurial's merge logic to copy individual
4019 This command uses Mercurial's merge logic to copy individual
4029 changes from other branches without merging branches in the
4020 changes from other branches without merging branches in the
4030 history graph. This is sometimes known as 'backporting' or
4021 history graph. This is sometimes known as 'backporting' or
4031 'cherry-picking'. By default, graft will copy user, date, and
4022 'cherry-picking'. By default, graft will copy user, date, and
4032 description from the source changesets.
4023 description from the source changesets.
4033
4024
4034 Changesets that are ancestors of the current revision, that have
4025 Changesets that are ancestors of the current revision, that have
4035 already been grafted, or that are merges will be skipped.
4026 already been grafted, or that are merges will be skipped.
4036
4027
4037 If --log is specified, log messages will have a comment appended
4028 If --log is specified, log messages will have a comment appended
4038 of the form::
4029 of the form::
4039
4030
4040 (grafted from CHANGESETHASH)
4031 (grafted from CHANGESETHASH)
4041
4032
4042 If --force is specified, revisions will be grafted even if they
4033 If --force is specified, revisions will be grafted even if they
4043 are already ancestors of or have been grafted to the destination.
4034 are already ancestors of or have been grafted to the destination.
4044 This is useful when the revisions have since been backed out.
4035 This is useful when the revisions have since been backed out.
4045
4036
4046 If a graft merge results in conflicts, the graft process is
4037 If a graft merge results in conflicts, the graft process is
4047 interrupted so that the current merge can be manually resolved.
4038 interrupted so that the current merge can be manually resolved.
4048 Once all conflicts are addressed, the graft process can be
4039 Once all conflicts are addressed, the graft process can be
4049 continued with the -c/--continue option.
4040 continued with the -c/--continue option.
4050
4041
4051 .. note::
4042 .. note::
4052
4043
4053 The -c/--continue option does not reapply earlier options, except
4044 The -c/--continue option does not reapply earlier options, except
4054 for --force.
4045 for --force.
4055
4046
4056 .. container:: verbose
4047 .. container:: verbose
4057
4048
4058 Examples:
4049 Examples:
4059
4050
4060 - copy a single change to the stable branch and edit its description::
4051 - copy a single change to the stable branch and edit its description::
4061
4052
4062 hg update stable
4053 hg update stable
4063 hg graft --edit 9393
4054 hg graft --edit 9393
4064
4055
4065 - graft a range of changesets with one exception, updating dates::
4056 - graft a range of changesets with one exception, updating dates::
4066
4057
4067 hg graft -D "2085::2093 and not 2091"
4058 hg graft -D "2085::2093 and not 2091"
4068
4059
4069 - continue a graft after resolving conflicts::
4060 - continue a graft after resolving conflicts::
4070
4061
4071 hg graft -c
4062 hg graft -c
4072
4063
4073 - show the source of a grafted changeset::
4064 - show the source of a grafted changeset::
4074
4065
4075 hg log --debug -r .
4066 hg log --debug -r .
4076
4067
4077 - show revisions sorted by date::
4068 - show revisions sorted by date::
4078
4069
4079 hg log -r "sort(all(), date)"
4070 hg log -r "sort(all(), date)"
4080
4071
4081 See :hg:`help revisions` and :hg:`help revsets` for more about
4072 See :hg:`help revisions` and :hg:`help revsets` for more about
4082 specifying revisions.
4073 specifying revisions.
4083
4074
4084 Returns 0 on successful completion.
4075 Returns 0 on successful completion.
4085 '''
4076 '''
4086 with repo.wlock():
4077 with repo.wlock():
4087 return _dograft(ui, repo, *revs, **opts)
4078 return _dograft(ui, repo, *revs, **opts)
4088
4079
4089 def _dograft(ui, repo, *revs, **opts):
4080 def _dograft(ui, repo, *revs, **opts):
4090 if revs and opts.get('rev'):
4081 if revs and opts.get('rev'):
4091 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4082 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4092 'revision ordering!\n'))
4083 'revision ordering!\n'))
4093
4084
4094 revs = list(revs)
4085 revs = list(revs)
4095 revs.extend(opts.get('rev'))
4086 revs.extend(opts.get('rev'))
4096
4087
4097 if not opts.get('user') and opts.get('currentuser'):
4088 if not opts.get('user') and opts.get('currentuser'):
4098 opts['user'] = ui.username()
4089 opts['user'] = ui.username()
4099 if not opts.get('date') and opts.get('currentdate'):
4090 if not opts.get('date') and opts.get('currentdate'):
4100 opts['date'] = "%d %d" % util.makedate()
4091 opts['date'] = "%d %d" % util.makedate()
4101
4092
4102 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4093 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4103
4094
4104 cont = False
4095 cont = False
4105 if opts.get('continue'):
4096 if opts.get('continue'):
4106 cont = True
4097 cont = True
4107 if revs:
4098 if revs:
4108 raise error.Abort(_("can't specify --continue and revisions"))
4099 raise error.Abort(_("can't specify --continue and revisions"))
4109 # read in unfinished revisions
4100 # read in unfinished revisions
4110 try:
4101 try:
4111 nodes = repo.vfs.read('graftstate').splitlines()
4102 nodes = repo.vfs.read('graftstate').splitlines()
4112 revs = [repo[node].rev() for node in nodes]
4103 revs = [repo[node].rev() for node in nodes]
4113 except IOError as inst:
4104 except IOError as inst:
4114 if inst.errno != errno.ENOENT:
4105 if inst.errno != errno.ENOENT:
4115 raise
4106 raise
4116 cmdutil.wrongtooltocontinue(repo, _('graft'))
4107 cmdutil.wrongtooltocontinue(repo, _('graft'))
4117 else:
4108 else:
4118 cmdutil.checkunfinished(repo)
4109 cmdutil.checkunfinished(repo)
4119 cmdutil.bailifchanged(repo)
4110 cmdutil.bailifchanged(repo)
4120 if not revs:
4111 if not revs:
4121 raise error.Abort(_('no revisions specified'))
4112 raise error.Abort(_('no revisions specified'))
4122 revs = scmutil.revrange(repo, revs)
4113 revs = scmutil.revrange(repo, revs)
4123
4114
4124 skipped = set()
4115 skipped = set()
4125 # check for merges
4116 # check for merges
4126 for rev in repo.revs('%ld and merge()', revs):
4117 for rev in repo.revs('%ld and merge()', revs):
4127 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4118 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4128 skipped.add(rev)
4119 skipped.add(rev)
4129 revs = [r for r in revs if r not in skipped]
4120 revs = [r for r in revs if r not in skipped]
4130 if not revs:
4121 if not revs:
4131 return -1
4122 return -1
4132
4123
4133 # Don't check in the --continue case, in effect retaining --force across
4124 # Don't check in the --continue case, in effect retaining --force across
4134 # --continues. That's because without --force, any revisions we decided to
4125 # --continues. That's because without --force, any revisions we decided to
4135 # skip would have been filtered out here, so they wouldn't have made their
4126 # skip would have been filtered out here, so they wouldn't have made their
4136 # way to the graftstate. With --force, any revisions we would have otherwise
4127 # way to the graftstate. With --force, any revisions we would have otherwise
4137 # skipped would not have been filtered out, and if they hadn't been applied
4128 # skipped would not have been filtered out, and if they hadn't been applied
4138 # already, they'd have been in the graftstate.
4129 # already, they'd have been in the graftstate.
4139 if not (cont or opts.get('force')):
4130 if not (cont or opts.get('force')):
4140 # check for ancestors of dest branch
4131 # check for ancestors of dest branch
4141 crev = repo['.'].rev()
4132 crev = repo['.'].rev()
4142 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4133 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4143 # Cannot use x.remove(y) on smart set, this has to be a list.
4134 # Cannot use x.remove(y) on smart set, this has to be a list.
4144 # XXX make this lazy in the future
4135 # XXX make this lazy in the future
4145 revs = list(revs)
4136 revs = list(revs)
4146 # don't mutate while iterating, create a copy
4137 # don't mutate while iterating, create a copy
4147 for rev in list(revs):
4138 for rev in list(revs):
4148 if rev in ancestors:
4139 if rev in ancestors:
4149 ui.warn(_('skipping ancestor revision %d:%s\n') %
4140 ui.warn(_('skipping ancestor revision %d:%s\n') %
4150 (rev, repo[rev]))
4141 (rev, repo[rev]))
4151 # XXX remove on list is slow
4142 # XXX remove on list is slow
4152 revs.remove(rev)
4143 revs.remove(rev)
4153 if not revs:
4144 if not revs:
4154 return -1
4145 return -1
4155
4146
4156 # analyze revs for earlier grafts
4147 # analyze revs for earlier grafts
4157 ids = {}
4148 ids = {}
4158 for ctx in repo.set("%ld", revs):
4149 for ctx in repo.set("%ld", revs):
4159 ids[ctx.hex()] = ctx.rev()
4150 ids[ctx.hex()] = ctx.rev()
4160 n = ctx.extra().get('source')
4151 n = ctx.extra().get('source')
4161 if n:
4152 if n:
4162 ids[n] = ctx.rev()
4153 ids[n] = ctx.rev()
4163
4154
4164 # check ancestors for earlier grafts
4155 # check ancestors for earlier grafts
4165 ui.debug('scanning for duplicate grafts\n')
4156 ui.debug('scanning for duplicate grafts\n')
4166
4157
4167 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4158 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4168 ctx = repo[rev]
4159 ctx = repo[rev]
4169 n = ctx.extra().get('source')
4160 n = ctx.extra().get('source')
4170 if n in ids:
4161 if n in ids:
4171 try:
4162 try:
4172 r = repo[n].rev()
4163 r = repo[n].rev()
4173 except error.RepoLookupError:
4164 except error.RepoLookupError:
4174 r = None
4165 r = None
4175 if r in revs:
4166 if r in revs:
4176 ui.warn(_('skipping revision %d:%s '
4167 ui.warn(_('skipping revision %d:%s '
4177 '(already grafted to %d:%s)\n')
4168 '(already grafted to %d:%s)\n')
4178 % (r, repo[r], rev, ctx))
4169 % (r, repo[r], rev, ctx))
4179 revs.remove(r)
4170 revs.remove(r)
4180 elif ids[n] in revs:
4171 elif ids[n] in revs:
4181 if r is None:
4172 if r is None:
4182 ui.warn(_('skipping already grafted revision %d:%s '
4173 ui.warn(_('skipping already grafted revision %d:%s '
4183 '(%d:%s also has unknown origin %s)\n')
4174 '(%d:%s also has unknown origin %s)\n')
4184 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4175 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4185 else:
4176 else:
4186 ui.warn(_('skipping already grafted revision %d:%s '
4177 ui.warn(_('skipping already grafted revision %d:%s '
4187 '(%d:%s also has origin %d:%s)\n')
4178 '(%d:%s also has origin %d:%s)\n')
4188 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4179 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4189 revs.remove(ids[n])
4180 revs.remove(ids[n])
4190 elif ctx.hex() in ids:
4181 elif ctx.hex() in ids:
4191 r = ids[ctx.hex()]
4182 r = ids[ctx.hex()]
4192 ui.warn(_('skipping already grafted revision %d:%s '
4183 ui.warn(_('skipping already grafted revision %d:%s '
4193 '(was grafted from %d:%s)\n') %
4184 '(was grafted from %d:%s)\n') %
4194 (r, repo[r], rev, ctx))
4185 (r, repo[r], rev, ctx))
4195 revs.remove(r)
4186 revs.remove(r)
4196 if not revs:
4187 if not revs:
4197 return -1
4188 return -1
4198
4189
4199 for pos, ctx in enumerate(repo.set("%ld", revs)):
4190 for pos, ctx in enumerate(repo.set("%ld", revs)):
4200 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4191 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4201 ctx.description().split('\n', 1)[0])
4192 ctx.description().split('\n', 1)[0])
4202 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4193 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4203 if names:
4194 if names:
4204 desc += ' (%s)' % ' '.join(names)
4195 desc += ' (%s)' % ' '.join(names)
4205 ui.status(_('grafting %s\n') % desc)
4196 ui.status(_('grafting %s\n') % desc)
4206 if opts.get('dry_run'):
4197 if opts.get('dry_run'):
4207 continue
4198 continue
4208
4199
4209 source = ctx.extra().get('source')
4200 source = ctx.extra().get('source')
4210 extra = {}
4201 extra = {}
4211 if source:
4202 if source:
4212 extra['source'] = source
4203 extra['source'] = source
4213 extra['intermediate-source'] = ctx.hex()
4204 extra['intermediate-source'] = ctx.hex()
4214 else:
4205 else:
4215 extra['source'] = ctx.hex()
4206 extra['source'] = ctx.hex()
4216 user = ctx.user()
4207 user = ctx.user()
4217 if opts.get('user'):
4208 if opts.get('user'):
4218 user = opts['user']
4209 user = opts['user']
4219 date = ctx.date()
4210 date = ctx.date()
4220 if opts.get('date'):
4211 if opts.get('date'):
4221 date = opts['date']
4212 date = opts['date']
4222 message = ctx.description()
4213 message = ctx.description()
4223 if opts.get('log'):
4214 if opts.get('log'):
4224 message += '\n(grafted from %s)' % ctx.hex()
4215 message += '\n(grafted from %s)' % ctx.hex()
4225
4216
4226 # we don't merge the first commit when continuing
4217 # we don't merge the first commit when continuing
4227 if not cont:
4218 if not cont:
4228 # perform the graft merge with p1(rev) as 'ancestor'
4219 # perform the graft merge with p1(rev) as 'ancestor'
4229 try:
4220 try:
4230 # ui.forcemerge is an internal variable, do not document
4221 # ui.forcemerge is an internal variable, do not document
4231 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4222 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4232 'graft')
4223 'graft')
4233 stats = mergemod.graft(repo, ctx, ctx.p1(),
4224 stats = mergemod.graft(repo, ctx, ctx.p1(),
4234 ['local', 'graft'])
4225 ['local', 'graft'])
4235 finally:
4226 finally:
4236 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4227 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4237 # report any conflicts
4228 # report any conflicts
4238 if stats and stats[3] > 0:
4229 if stats and stats[3] > 0:
4239 # write out state for --continue
4230 # write out state for --continue
4240 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4231 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4241 repo.vfs.write('graftstate', ''.join(nodelines))
4232 repo.vfs.write('graftstate', ''.join(nodelines))
4242 extra = ''
4233 extra = ''
4243 if opts.get('user'):
4234 if opts.get('user'):
4244 extra += ' --user %s' % util.shellquote(opts['user'])
4235 extra += ' --user %s' % util.shellquote(opts['user'])
4245 if opts.get('date'):
4236 if opts.get('date'):
4246 extra += ' --date %s' % util.shellquote(opts['date'])
4237 extra += ' --date %s' % util.shellquote(opts['date'])
4247 if opts.get('log'):
4238 if opts.get('log'):
4248 extra += ' --log'
4239 extra += ' --log'
4249 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4240 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4250 raise error.Abort(
4241 raise error.Abort(
4251 _("unresolved conflicts, can't continue"),
4242 _("unresolved conflicts, can't continue"),
4252 hint=hint)
4243 hint=hint)
4253 else:
4244 else:
4254 cont = False
4245 cont = False
4255
4246
4256 # commit
4247 # commit
4257 node = repo.commit(text=message, user=user,
4248 node = repo.commit(text=message, user=user,
4258 date=date, extra=extra, editor=editor)
4249 date=date, extra=extra, editor=editor)
4259 if node is None:
4250 if node is None:
4260 ui.warn(
4251 ui.warn(
4261 _('note: graft of %d:%s created no changes to commit\n') %
4252 _('note: graft of %d:%s created no changes to commit\n') %
4262 (ctx.rev(), ctx))
4253 (ctx.rev(), ctx))
4263
4254
4264 # remove state when we complete successfully
4255 # remove state when we complete successfully
4265 if not opts.get('dry_run'):
4256 if not opts.get('dry_run'):
4266 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4257 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4267
4258
4268 return 0
4259 return 0
4269
4260
4270 @command('grep',
4261 @command('grep',
4271 [('0', 'print0', None, _('end fields with NUL')),
4262 [('0', 'print0', None, _('end fields with NUL')),
4272 ('', 'all', None, _('print all revisions that match')),
4263 ('', 'all', None, _('print all revisions that match')),
4273 ('a', 'text', None, _('treat all files as text')),
4264 ('a', 'text', None, _('treat all files as text')),
4274 ('f', 'follow', None,
4265 ('f', 'follow', None,
4275 _('follow changeset history,'
4266 _('follow changeset history,'
4276 ' or file history across copies and renames')),
4267 ' or file history across copies and renames')),
4277 ('i', 'ignore-case', None, _('ignore case when matching')),
4268 ('i', 'ignore-case', None, _('ignore case when matching')),
4278 ('l', 'files-with-matches', None,
4269 ('l', 'files-with-matches', None,
4279 _('print only filenames and revisions that match')),
4270 _('print only filenames and revisions that match')),
4280 ('n', 'line-number', None, _('print matching line numbers')),
4271 ('n', 'line-number', None, _('print matching line numbers')),
4281 ('r', 'rev', [],
4272 ('r', 'rev', [],
4282 _('only search files changed within revision range'), _('REV')),
4273 _('only search files changed within revision range'), _('REV')),
4283 ('u', 'user', None, _('list the author (long with -v)')),
4274 ('u', 'user', None, _('list the author (long with -v)')),
4284 ('d', 'date', None, _('list the date (short with -q)')),
4275 ('d', 'date', None, _('list the date (short with -q)')),
4285 ] + walkopts,
4276 ] + walkopts,
4286 _('[OPTION]... PATTERN [FILE]...'),
4277 _('[OPTION]... PATTERN [FILE]...'),
4287 inferrepo=True)
4278 inferrepo=True)
4288 def grep(ui, repo, pattern, *pats, **opts):
4279 def grep(ui, repo, pattern, *pats, **opts):
4289 """search for a pattern in specified files and revisions
4280 """search for a pattern in specified files and revisions
4290
4281
4291 Search revisions of files for a regular expression.
4282 Search revisions of files for a regular expression.
4292
4283
4293 This command behaves differently than Unix grep. It only accepts
4284 This command behaves differently than Unix grep. It only accepts
4294 Python/Perl regexps. It searches repository history, not the
4285 Python/Perl regexps. It searches repository history, not the
4295 working directory. It always prints the revision number in which a
4286 working directory. It always prints the revision number in which a
4296 match appears.
4287 match appears.
4297
4288
4298 By default, grep only prints output for the first revision of a
4289 By default, grep only prints output for the first revision of a
4299 file in which it finds a match. To get it to print every revision
4290 file in which it finds a match. To get it to print every revision
4300 that contains a change in match status ("-" for a match that
4291 that contains a change in match status ("-" for a match that
4301 becomes a non-match, or "+" for a non-match that becomes a match),
4292 becomes a non-match, or "+" for a non-match that becomes a match),
4302 use the --all flag.
4293 use the --all flag.
4303
4294
4304 Returns 0 if a match is found, 1 otherwise.
4295 Returns 0 if a match is found, 1 otherwise.
4305 """
4296 """
4306 reflags = re.M
4297 reflags = re.M
4307 if opts.get('ignore_case'):
4298 if opts.get('ignore_case'):
4308 reflags |= re.I
4299 reflags |= re.I
4309 try:
4300 try:
4310 regexp = util.re.compile(pattern, reflags)
4301 regexp = util.re.compile(pattern, reflags)
4311 except re.error as inst:
4302 except re.error as inst:
4312 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4303 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4313 return 1
4304 return 1
4314 sep, eol = ':', '\n'
4305 sep, eol = ':', '\n'
4315 if opts.get('print0'):
4306 if opts.get('print0'):
4316 sep = eol = '\0'
4307 sep = eol = '\0'
4317
4308
4318 getfile = util.lrucachefunc(repo.file)
4309 getfile = util.lrucachefunc(repo.file)
4319
4310
4320 def matchlines(body):
4311 def matchlines(body):
4321 begin = 0
4312 begin = 0
4322 linenum = 0
4313 linenum = 0
4323 while begin < len(body):
4314 while begin < len(body):
4324 match = regexp.search(body, begin)
4315 match = regexp.search(body, begin)
4325 if not match:
4316 if not match:
4326 break
4317 break
4327 mstart, mend = match.span()
4318 mstart, mend = match.span()
4328 linenum += body.count('\n', begin, mstart) + 1
4319 linenum += body.count('\n', begin, mstart) + 1
4329 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4320 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4330 begin = body.find('\n', mend) + 1 or len(body) + 1
4321 begin = body.find('\n', mend) + 1 or len(body) + 1
4331 lend = begin - 1
4322 lend = begin - 1
4332 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4323 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4333
4324
4334 class linestate(object):
4325 class linestate(object):
4335 def __init__(self, line, linenum, colstart, colend):
4326 def __init__(self, line, linenum, colstart, colend):
4336 self.line = line
4327 self.line = line
4337 self.linenum = linenum
4328 self.linenum = linenum
4338 self.colstart = colstart
4329 self.colstart = colstart
4339 self.colend = colend
4330 self.colend = colend
4340
4331
4341 def __hash__(self):
4332 def __hash__(self):
4342 return hash((self.linenum, self.line))
4333 return hash((self.linenum, self.line))
4343
4334
4344 def __eq__(self, other):
4335 def __eq__(self, other):
4345 return self.line == other.line
4336 return self.line == other.line
4346
4337
4347 def __iter__(self):
4338 def __iter__(self):
4348 yield (self.line[:self.colstart], '')
4339 yield (self.line[:self.colstart], '')
4349 yield (self.line[self.colstart:self.colend], 'grep.match')
4340 yield (self.line[self.colstart:self.colend], 'grep.match')
4350 rest = self.line[self.colend:]
4341 rest = self.line[self.colend:]
4351 while rest != '':
4342 while rest != '':
4352 match = regexp.search(rest)
4343 match = regexp.search(rest)
4353 if not match:
4344 if not match:
4354 yield (rest, '')
4345 yield (rest, '')
4355 break
4346 break
4356 mstart, mend = match.span()
4347 mstart, mend = match.span()
4357 yield (rest[:mstart], '')
4348 yield (rest[:mstart], '')
4358 yield (rest[mstart:mend], 'grep.match')
4349 yield (rest[mstart:mend], 'grep.match')
4359 rest = rest[mend:]
4350 rest = rest[mend:]
4360
4351
4361 matches = {}
4352 matches = {}
4362 copies = {}
4353 copies = {}
4363 def grepbody(fn, rev, body):
4354 def grepbody(fn, rev, body):
4364 matches[rev].setdefault(fn, [])
4355 matches[rev].setdefault(fn, [])
4365 m = matches[rev][fn]
4356 m = matches[rev][fn]
4366 for lnum, cstart, cend, line in matchlines(body):
4357 for lnum, cstart, cend, line in matchlines(body):
4367 s = linestate(line, lnum, cstart, cend)
4358 s = linestate(line, lnum, cstart, cend)
4368 m.append(s)
4359 m.append(s)
4369
4360
4370 def difflinestates(a, b):
4361 def difflinestates(a, b):
4371 sm = difflib.SequenceMatcher(None, a, b)
4362 sm = difflib.SequenceMatcher(None, a, b)
4372 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4363 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4373 if tag == 'insert':
4364 if tag == 'insert':
4374 for i in xrange(blo, bhi):
4365 for i in xrange(blo, bhi):
4375 yield ('+', b[i])
4366 yield ('+', b[i])
4376 elif tag == 'delete':
4367 elif tag == 'delete':
4377 for i in xrange(alo, ahi):
4368 for i in xrange(alo, ahi):
4378 yield ('-', a[i])
4369 yield ('-', a[i])
4379 elif tag == 'replace':
4370 elif tag == 'replace':
4380 for i in xrange(alo, ahi):
4371 for i in xrange(alo, ahi):
4381 yield ('-', a[i])
4372 yield ('-', a[i])
4382 for i in xrange(blo, bhi):
4373 for i in xrange(blo, bhi):
4383 yield ('+', b[i])
4374 yield ('+', b[i])
4384
4375
4385 def display(fn, ctx, pstates, states):
4376 def display(fn, ctx, pstates, states):
4386 rev = ctx.rev()
4377 rev = ctx.rev()
4387 if ui.quiet:
4378 if ui.quiet:
4388 datefunc = util.shortdate
4379 datefunc = util.shortdate
4389 else:
4380 else:
4390 datefunc = util.datestr
4381 datefunc = util.datestr
4391 found = False
4382 found = False
4392 @util.cachefunc
4383 @util.cachefunc
4393 def binary():
4384 def binary():
4394 flog = getfile(fn)
4385 flog = getfile(fn)
4395 return util.binary(flog.read(ctx.filenode(fn)))
4386 return util.binary(flog.read(ctx.filenode(fn)))
4396
4387
4397 if opts.get('all'):
4388 if opts.get('all'):
4398 iter = difflinestates(pstates, states)
4389 iter = difflinestates(pstates, states)
4399 else:
4390 else:
4400 iter = [('', l) for l in states]
4391 iter = [('', l) for l in states]
4401 for change, l in iter:
4392 for change, l in iter:
4402 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4393 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4403
4394
4404 if opts.get('line_number'):
4395 if opts.get('line_number'):
4405 cols.append((str(l.linenum), 'grep.linenumber'))
4396 cols.append((str(l.linenum), 'grep.linenumber'))
4406 if opts.get('all'):
4397 if opts.get('all'):
4407 cols.append((change, 'grep.change'))
4398 cols.append((change, 'grep.change'))
4408 if opts.get('user'):
4399 if opts.get('user'):
4409 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4400 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4410 if opts.get('date'):
4401 if opts.get('date'):
4411 cols.append((datefunc(ctx.date()), 'grep.date'))
4402 cols.append((datefunc(ctx.date()), 'grep.date'))
4412 for col, label in cols[:-1]:
4403 for col, label in cols[:-1]:
4413 ui.write(col, label=label)
4404 ui.write(col, label=label)
4414 ui.write(sep, label='grep.sep')
4405 ui.write(sep, label='grep.sep')
4415 ui.write(cols[-1][0], label=cols[-1][1])
4406 ui.write(cols[-1][0], label=cols[-1][1])
4416 if not opts.get('files_with_matches'):
4407 if not opts.get('files_with_matches'):
4417 ui.write(sep, label='grep.sep')
4408 ui.write(sep, label='grep.sep')
4418 if not opts.get('text') and binary():
4409 if not opts.get('text') and binary():
4419 ui.write(_(" Binary file matches"))
4410 ui.write(_(" Binary file matches"))
4420 else:
4411 else:
4421 for s, label in l:
4412 for s, label in l:
4422 ui.write(s, label=label)
4413 ui.write(s, label=label)
4423 ui.write(eol)
4414 ui.write(eol)
4424 found = True
4415 found = True
4425 if opts.get('files_with_matches'):
4416 if opts.get('files_with_matches'):
4426 break
4417 break
4427 return found
4418 return found
4428
4419
4429 skip = {}
4420 skip = {}
4430 revfiles = {}
4421 revfiles = {}
4431 matchfn = scmutil.match(repo[None], pats, opts)
4422 matchfn = scmutil.match(repo[None], pats, opts)
4432 found = False
4423 found = False
4433 follow = opts.get('follow')
4424 follow = opts.get('follow')
4434
4425
4435 def prep(ctx, fns):
4426 def prep(ctx, fns):
4436 rev = ctx.rev()
4427 rev = ctx.rev()
4437 pctx = ctx.p1()
4428 pctx = ctx.p1()
4438 parent = pctx.rev()
4429 parent = pctx.rev()
4439 matches.setdefault(rev, {})
4430 matches.setdefault(rev, {})
4440 matches.setdefault(parent, {})
4431 matches.setdefault(parent, {})
4441 files = revfiles.setdefault(rev, [])
4432 files = revfiles.setdefault(rev, [])
4442 for fn in fns:
4433 for fn in fns:
4443 flog = getfile(fn)
4434 flog = getfile(fn)
4444 try:
4435 try:
4445 fnode = ctx.filenode(fn)
4436 fnode = ctx.filenode(fn)
4446 except error.LookupError:
4437 except error.LookupError:
4447 continue
4438 continue
4448
4439
4449 copied = flog.renamed(fnode)
4440 copied = flog.renamed(fnode)
4450 copy = follow and copied and copied[0]
4441 copy = follow and copied and copied[0]
4451 if copy:
4442 if copy:
4452 copies.setdefault(rev, {})[fn] = copy
4443 copies.setdefault(rev, {})[fn] = copy
4453 if fn in skip:
4444 if fn in skip:
4454 if copy:
4445 if copy:
4455 skip[copy] = True
4446 skip[copy] = True
4456 continue
4447 continue
4457 files.append(fn)
4448 files.append(fn)
4458
4449
4459 if fn not in matches[rev]:
4450 if fn not in matches[rev]:
4460 grepbody(fn, rev, flog.read(fnode))
4451 grepbody(fn, rev, flog.read(fnode))
4461
4452
4462 pfn = copy or fn
4453 pfn = copy or fn
4463 if pfn not in matches[parent]:
4454 if pfn not in matches[parent]:
4464 try:
4455 try:
4465 fnode = pctx.filenode(pfn)
4456 fnode = pctx.filenode(pfn)
4466 grepbody(pfn, parent, flog.read(fnode))
4457 grepbody(pfn, parent, flog.read(fnode))
4467 except error.LookupError:
4458 except error.LookupError:
4468 pass
4459 pass
4469
4460
4470 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4461 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4471 rev = ctx.rev()
4462 rev = ctx.rev()
4472 parent = ctx.p1().rev()
4463 parent = ctx.p1().rev()
4473 for fn in sorted(revfiles.get(rev, [])):
4464 for fn in sorted(revfiles.get(rev, [])):
4474 states = matches[rev][fn]
4465 states = matches[rev][fn]
4475 copy = copies.get(rev, {}).get(fn)
4466 copy = copies.get(rev, {}).get(fn)
4476 if fn in skip:
4467 if fn in skip:
4477 if copy:
4468 if copy:
4478 skip[copy] = True
4469 skip[copy] = True
4479 continue
4470 continue
4480 pstates = matches.get(parent, {}).get(copy or fn, [])
4471 pstates = matches.get(parent, {}).get(copy or fn, [])
4481 if pstates or states:
4472 if pstates or states:
4482 r = display(fn, ctx, pstates, states)
4473 r = display(fn, ctx, pstates, states)
4483 found = found or r
4474 found = found or r
4484 if r and not opts.get('all'):
4475 if r and not opts.get('all'):
4485 skip[fn] = True
4476 skip[fn] = True
4486 if copy:
4477 if copy:
4487 skip[copy] = True
4478 skip[copy] = True
4488 del matches[rev]
4479 del matches[rev]
4489 del revfiles[rev]
4480 del revfiles[rev]
4490
4481
4491 return not found
4482 return not found
4492
4483
4493 @command('heads',
4484 @command('heads',
4494 [('r', 'rev', '',
4485 [('r', 'rev', '',
4495 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4486 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4496 ('t', 'topo', False, _('show topological heads only')),
4487 ('t', 'topo', False, _('show topological heads only')),
4497 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4488 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4498 ('c', 'closed', False, _('show normal and closed branch heads')),
4489 ('c', 'closed', False, _('show normal and closed branch heads')),
4499 ] + templateopts,
4490 ] + templateopts,
4500 _('[-ct] [-r STARTREV] [REV]...'))
4491 _('[-ct] [-r STARTREV] [REV]...'))
4501 def heads(ui, repo, *branchrevs, **opts):
4492 def heads(ui, repo, *branchrevs, **opts):
4502 """show branch heads
4493 """show branch heads
4503
4494
4504 With no arguments, show all open branch heads in the repository.
4495 With no arguments, show all open branch heads in the repository.
4505 Branch heads are changesets that have no descendants on the
4496 Branch heads are changesets that have no descendants on the
4506 same branch. They are where development generally takes place and
4497 same branch. They are where development generally takes place and
4507 are the usual targets for update and merge operations.
4498 are the usual targets for update and merge operations.
4508
4499
4509 If one or more REVs are given, only open branch heads on the
4500 If one or more REVs are given, only open branch heads on the
4510 branches associated with the specified changesets are shown. This
4501 branches associated with the specified changesets are shown. This
4511 means that you can use :hg:`heads .` to see the heads on the
4502 means that you can use :hg:`heads .` to see the heads on the
4512 currently checked-out branch.
4503 currently checked-out branch.
4513
4504
4514 If -c/--closed is specified, also show branch heads marked closed
4505 If -c/--closed is specified, also show branch heads marked closed
4515 (see :hg:`commit --close-branch`).
4506 (see :hg:`commit --close-branch`).
4516
4507
4517 If STARTREV is specified, only those heads that are descendants of
4508 If STARTREV is specified, only those heads that are descendants of
4518 STARTREV will be displayed.
4509 STARTREV will be displayed.
4519
4510
4520 If -t/--topo is specified, named branch mechanics will be ignored and only
4511 If -t/--topo is specified, named branch mechanics will be ignored and only
4521 topological heads (changesets with no children) will be shown.
4512 topological heads (changesets with no children) will be shown.
4522
4513
4523 Returns 0 if matching heads are found, 1 if not.
4514 Returns 0 if matching heads are found, 1 if not.
4524 """
4515 """
4525
4516
4526 start = None
4517 start = None
4527 if 'rev' in opts:
4518 if 'rev' in opts:
4528 start = scmutil.revsingle(repo, opts['rev'], None).node()
4519 start = scmutil.revsingle(repo, opts['rev'], None).node()
4529
4520
4530 if opts.get('topo'):
4521 if opts.get('topo'):
4531 heads = [repo[h] for h in repo.heads(start)]
4522 heads = [repo[h] for h in repo.heads(start)]
4532 else:
4523 else:
4533 heads = []
4524 heads = []
4534 for branch in repo.branchmap():
4525 for branch in repo.branchmap():
4535 heads += repo.branchheads(branch, start, opts.get('closed'))
4526 heads += repo.branchheads(branch, start, opts.get('closed'))
4536 heads = [repo[h] for h in heads]
4527 heads = [repo[h] for h in heads]
4537
4528
4538 if branchrevs:
4529 if branchrevs:
4539 branches = set(repo[br].branch() for br in branchrevs)
4530 branches = set(repo[br].branch() for br in branchrevs)
4540 heads = [h for h in heads if h.branch() in branches]
4531 heads = [h for h in heads if h.branch() in branches]
4541
4532
4542 if opts.get('active') and branchrevs:
4533 if opts.get('active') and branchrevs:
4543 dagheads = repo.heads(start)
4534 dagheads = repo.heads(start)
4544 heads = [h for h in heads if h.node() in dagheads]
4535 heads = [h for h in heads if h.node() in dagheads]
4545
4536
4546 if branchrevs:
4537 if branchrevs:
4547 haveheads = set(h.branch() for h in heads)
4538 haveheads = set(h.branch() for h in heads)
4548 if branches - haveheads:
4539 if branches - haveheads:
4549 headless = ', '.join(b for b in branches - haveheads)
4540 headless = ', '.join(b for b in branches - haveheads)
4550 msg = _('no open branch heads found on branches %s')
4541 msg = _('no open branch heads found on branches %s')
4551 if opts.get('rev'):
4542 if opts.get('rev'):
4552 msg += _(' (started at %s)') % opts['rev']
4543 msg += _(' (started at %s)') % opts['rev']
4553 ui.warn((msg + '\n') % headless)
4544 ui.warn((msg + '\n') % headless)
4554
4545
4555 if not heads:
4546 if not heads:
4556 return 1
4547 return 1
4557
4548
4558 heads = sorted(heads, key=lambda x: -x.rev())
4549 heads = sorted(heads, key=lambda x: -x.rev())
4559 displayer = cmdutil.show_changeset(ui, repo, opts)
4550 displayer = cmdutil.show_changeset(ui, repo, opts)
4560 for ctx in heads:
4551 for ctx in heads:
4561 displayer.show(ctx)
4552 displayer.show(ctx)
4562 displayer.close()
4553 displayer.close()
4563
4554
4564 @command('help',
4555 @command('help',
4565 [('e', 'extension', None, _('show only help for extensions')),
4556 [('e', 'extension', None, _('show only help for extensions')),
4566 ('c', 'command', None, _('show only help for commands')),
4557 ('c', 'command', None, _('show only help for commands')),
4567 ('k', 'keyword', None, _('show topics matching keyword')),
4558 ('k', 'keyword', None, _('show topics matching keyword')),
4568 ('s', 'system', [], _('show help for specific platform(s)')),
4559 ('s', 'system', [], _('show help for specific platform(s)')),
4569 ],
4560 ],
4570 _('[-ecks] [TOPIC]'),
4561 _('[-ecks] [TOPIC]'),
4571 norepo=True)
4562 norepo=True)
4572 def help_(ui, name=None, **opts):
4563 def help_(ui, name=None, **opts):
4573 """show help for a given topic or a help overview
4564 """show help for a given topic or a help overview
4574
4565
4575 With no arguments, print a list of commands with short help messages.
4566 With no arguments, print a list of commands with short help messages.
4576
4567
4577 Given a topic, extension, or command name, print help for that
4568 Given a topic, extension, or command name, print help for that
4578 topic.
4569 topic.
4579
4570
4580 Returns 0 if successful.
4571 Returns 0 if successful.
4581 """
4572 """
4582
4573
4583 textwidth = ui.configint('ui', 'textwidth', 78)
4574 textwidth = ui.configint('ui', 'textwidth', 78)
4584 termwidth = ui.termwidth() - 2
4575 termwidth = ui.termwidth() - 2
4585 if textwidth <= 0 or termwidth < textwidth:
4576 if textwidth <= 0 or termwidth < textwidth:
4586 textwidth = termwidth
4577 textwidth = termwidth
4587
4578
4588 keep = opts.get('system') or []
4579 keep = opts.get('system') or []
4589 if len(keep) == 0:
4580 if len(keep) == 0:
4590 if sys.platform.startswith('win'):
4581 if sys.platform.startswith('win'):
4591 keep.append('windows')
4582 keep.append('windows')
4592 elif sys.platform == 'OpenVMS':
4583 elif sys.platform == 'OpenVMS':
4593 keep.append('vms')
4584 keep.append('vms')
4594 elif sys.platform == 'plan9':
4585 elif sys.platform == 'plan9':
4595 keep.append('plan9')
4586 keep.append('plan9')
4596 else:
4587 else:
4597 keep.append('unix')
4588 keep.append('unix')
4598 keep.append(sys.platform.lower())
4589 keep.append(sys.platform.lower())
4599 if ui.verbose:
4590 if ui.verbose:
4600 keep.append('verbose')
4591 keep.append('verbose')
4601
4592
4602 section = None
4593 section = None
4603 subtopic = None
4594 subtopic = None
4604 if name and '.' in name:
4595 if name and '.' in name:
4605 name, section = name.split('.', 1)
4596 name, section = name.split('.', 1)
4606 section = encoding.lower(section)
4597 section = encoding.lower(section)
4607 if '.' in section:
4598 if '.' in section:
4608 subtopic, section = section.split('.', 1)
4599 subtopic, section = section.split('.', 1)
4609 else:
4600 else:
4610 subtopic = section
4601 subtopic = section
4611
4602
4612 text = help.help_(ui, name, subtopic=subtopic, **opts)
4603 text = help.help_(ui, name, subtopic=subtopic, **opts)
4613
4604
4614 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4605 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4615 section=section)
4606 section=section)
4616
4607
4617 # We could have been given a weird ".foo" section without a name
4608 # We could have been given a weird ".foo" section without a name
4618 # to look for, or we could have simply failed to found "foo.bar"
4609 # to look for, or we could have simply failed to found "foo.bar"
4619 # because bar isn't a section of foo
4610 # because bar isn't a section of foo
4620 if section and not (formatted and name):
4611 if section and not (formatted and name):
4621 raise error.Abort(_("help section not found"))
4612 raise error.Abort(_("help section not found"))
4622
4613
4623 if 'verbose' in pruned:
4614 if 'verbose' in pruned:
4624 keep.append('omitted')
4615 keep.append('omitted')
4625 else:
4616 else:
4626 keep.append('notomitted')
4617 keep.append('notomitted')
4627 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4618 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4628 section=section)
4619 section=section)
4629 ui.write(formatted)
4620 ui.write(formatted)
4630
4621
4631
4622
4632 @command('identify|id',
4623 @command('identify|id',
4633 [('r', 'rev', '',
4624 [('r', 'rev', '',
4634 _('identify the specified revision'), _('REV')),
4625 _('identify the specified revision'), _('REV')),
4635 ('n', 'num', None, _('show local revision number')),
4626 ('n', 'num', None, _('show local revision number')),
4636 ('i', 'id', None, _('show global revision id')),
4627 ('i', 'id', None, _('show global revision id')),
4637 ('b', 'branch', None, _('show branch')),
4628 ('b', 'branch', None, _('show branch')),
4638 ('t', 'tags', None, _('show tags')),
4629 ('t', 'tags', None, _('show tags')),
4639 ('B', 'bookmarks', None, _('show bookmarks')),
4630 ('B', 'bookmarks', None, _('show bookmarks')),
4640 ] + remoteopts,
4631 ] + remoteopts,
4641 _('[-nibtB] [-r REV] [SOURCE]'),
4632 _('[-nibtB] [-r REV] [SOURCE]'),
4642 optionalrepo=True)
4633 optionalrepo=True)
4643 def identify(ui, repo, source=None, rev=None,
4634 def identify(ui, repo, source=None, rev=None,
4644 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4635 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4645 """identify the working directory or specified revision
4636 """identify the working directory or specified revision
4646
4637
4647 Print a summary identifying the repository state at REV using one or
4638 Print a summary identifying the repository state at REV using one or
4648 two parent hash identifiers, followed by a "+" if the working
4639 two parent hash identifiers, followed by a "+" if the working
4649 directory has uncommitted changes, the branch name (if not default),
4640 directory has uncommitted changes, the branch name (if not default),
4650 a list of tags, and a list of bookmarks.
4641 a list of tags, and a list of bookmarks.
4651
4642
4652 When REV is not given, print a summary of the current state of the
4643 When REV is not given, print a summary of the current state of the
4653 repository.
4644 repository.
4654
4645
4655 Specifying a path to a repository root or Mercurial bundle will
4646 Specifying a path to a repository root or Mercurial bundle will
4656 cause lookup to operate on that repository/bundle.
4647 cause lookup to operate on that repository/bundle.
4657
4648
4658 .. container:: verbose
4649 .. container:: verbose
4659
4650
4660 Examples:
4651 Examples:
4661
4652
4662 - generate a build identifier for the working directory::
4653 - generate a build identifier for the working directory::
4663
4654
4664 hg id --id > build-id.dat
4655 hg id --id > build-id.dat
4665
4656
4666 - find the revision corresponding to a tag::
4657 - find the revision corresponding to a tag::
4667
4658
4668 hg id -n -r 1.3
4659 hg id -n -r 1.3
4669
4660
4670 - check the most recent revision of a remote repository::
4661 - check the most recent revision of a remote repository::
4671
4662
4672 hg id -r tip http://selenic.com/hg/
4663 hg id -r tip http://selenic.com/hg/
4673
4664
4674 See :hg:`log` for generating more information about specific revisions,
4665 See :hg:`log` for generating more information about specific revisions,
4675 including full hash identifiers.
4666 including full hash identifiers.
4676
4667
4677 Returns 0 if successful.
4668 Returns 0 if successful.
4678 """
4669 """
4679
4670
4680 if not repo and not source:
4671 if not repo and not source:
4681 raise error.Abort(_("there is no Mercurial repository here "
4672 raise error.Abort(_("there is no Mercurial repository here "
4682 "(.hg not found)"))
4673 "(.hg not found)"))
4683
4674
4684 if ui.debugflag:
4675 if ui.debugflag:
4685 hexfunc = hex
4676 hexfunc = hex
4686 else:
4677 else:
4687 hexfunc = short
4678 hexfunc = short
4688 default = not (num or id or branch or tags or bookmarks)
4679 default = not (num or id or branch or tags or bookmarks)
4689 output = []
4680 output = []
4690 revs = []
4681 revs = []
4691
4682
4692 if source:
4683 if source:
4693 source, branches = hg.parseurl(ui.expandpath(source))
4684 source, branches = hg.parseurl(ui.expandpath(source))
4694 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4685 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4695 repo = peer.local()
4686 repo = peer.local()
4696 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4687 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4697
4688
4698 if not repo:
4689 if not repo:
4699 if num or branch or tags:
4690 if num or branch or tags:
4700 raise error.Abort(
4691 raise error.Abort(
4701 _("can't query remote revision number, branch, or tags"))
4692 _("can't query remote revision number, branch, or tags"))
4702 if not rev and revs:
4693 if not rev and revs:
4703 rev = revs[0]
4694 rev = revs[0]
4704 if not rev:
4695 if not rev:
4705 rev = "tip"
4696 rev = "tip"
4706
4697
4707 remoterev = peer.lookup(rev)
4698 remoterev = peer.lookup(rev)
4708 if default or id:
4699 if default or id:
4709 output = [hexfunc(remoterev)]
4700 output = [hexfunc(remoterev)]
4710
4701
4711 def getbms():
4702 def getbms():
4712 bms = []
4703 bms = []
4713
4704
4714 if 'bookmarks' in peer.listkeys('namespaces'):
4705 if 'bookmarks' in peer.listkeys('namespaces'):
4715 hexremoterev = hex(remoterev)
4706 hexremoterev = hex(remoterev)
4716 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4707 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4717 if bmr == hexremoterev]
4708 if bmr == hexremoterev]
4718
4709
4719 return sorted(bms)
4710 return sorted(bms)
4720
4711
4721 if bookmarks:
4712 if bookmarks:
4722 output.extend(getbms())
4713 output.extend(getbms())
4723 elif default and not ui.quiet:
4714 elif default and not ui.quiet:
4724 # multiple bookmarks for a single parent separated by '/'
4715 # multiple bookmarks for a single parent separated by '/'
4725 bm = '/'.join(getbms())
4716 bm = '/'.join(getbms())
4726 if bm:
4717 if bm:
4727 output.append(bm)
4718 output.append(bm)
4728 else:
4719 else:
4729 ctx = scmutil.revsingle(repo, rev, None)
4720 ctx = scmutil.revsingle(repo, rev, None)
4730
4721
4731 if ctx.rev() is None:
4722 if ctx.rev() is None:
4732 ctx = repo[None]
4723 ctx = repo[None]
4733 parents = ctx.parents()
4724 parents = ctx.parents()
4734 taglist = []
4725 taglist = []
4735 for p in parents:
4726 for p in parents:
4736 taglist.extend(p.tags())
4727 taglist.extend(p.tags())
4737
4728
4738 changed = ""
4729 changed = ""
4739 if default or id or num:
4730 if default or id or num:
4740 if (any(repo.status())
4731 if (any(repo.status())
4741 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4732 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4742 changed = '+'
4733 changed = '+'
4743 if default or id:
4734 if default or id:
4744 output = ["%s%s" %
4735 output = ["%s%s" %
4745 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4736 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4746 if num:
4737 if num:
4747 output.append("%s%s" %
4738 output.append("%s%s" %
4748 ('+'.join([str(p.rev()) for p in parents]), changed))
4739 ('+'.join([str(p.rev()) for p in parents]), changed))
4749 else:
4740 else:
4750 if default or id:
4741 if default or id:
4751 output = [hexfunc(ctx.node())]
4742 output = [hexfunc(ctx.node())]
4752 if num:
4743 if num:
4753 output.append(str(ctx.rev()))
4744 output.append(str(ctx.rev()))
4754 taglist = ctx.tags()
4745 taglist = ctx.tags()
4755
4746
4756 if default and not ui.quiet:
4747 if default and not ui.quiet:
4757 b = ctx.branch()
4748 b = ctx.branch()
4758 if b != 'default':
4749 if b != 'default':
4759 output.append("(%s)" % b)
4750 output.append("(%s)" % b)
4760
4751
4761 # multiple tags for a single parent separated by '/'
4752 # multiple tags for a single parent separated by '/'
4762 t = '/'.join(taglist)
4753 t = '/'.join(taglist)
4763 if t:
4754 if t:
4764 output.append(t)
4755 output.append(t)
4765
4756
4766 # multiple bookmarks for a single parent separated by '/'
4757 # multiple bookmarks for a single parent separated by '/'
4767 bm = '/'.join(ctx.bookmarks())
4758 bm = '/'.join(ctx.bookmarks())
4768 if bm:
4759 if bm:
4769 output.append(bm)
4760 output.append(bm)
4770 else:
4761 else:
4771 if branch:
4762 if branch:
4772 output.append(ctx.branch())
4763 output.append(ctx.branch())
4773
4764
4774 if tags:
4765 if tags:
4775 output.extend(taglist)
4766 output.extend(taglist)
4776
4767
4777 if bookmarks:
4768 if bookmarks:
4778 output.extend(ctx.bookmarks())
4769 output.extend(ctx.bookmarks())
4779
4770
4780 ui.write("%s\n" % ' '.join(output))
4771 ui.write("%s\n" % ' '.join(output))
4781
4772
4782 @command('import|patch',
4773 @command('import|patch',
4783 [('p', 'strip', 1,
4774 [('p', 'strip', 1,
4784 _('directory strip option for patch. This has the same '
4775 _('directory strip option for patch. This has the same '
4785 'meaning as the corresponding patch option'), _('NUM')),
4776 'meaning as the corresponding patch option'), _('NUM')),
4786 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4777 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4787 ('e', 'edit', False, _('invoke editor on commit messages')),
4778 ('e', 'edit', False, _('invoke editor on commit messages')),
4788 ('f', 'force', None,
4779 ('f', 'force', None,
4789 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4780 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4790 ('', 'no-commit', None,
4781 ('', 'no-commit', None,
4791 _("don't commit, just update the working directory")),
4782 _("don't commit, just update the working directory")),
4792 ('', 'bypass', None,
4783 ('', 'bypass', None,
4793 _("apply patch without touching the working directory")),
4784 _("apply patch without touching the working directory")),
4794 ('', 'partial', None,
4785 ('', 'partial', None,
4795 _('commit even if some hunks fail')),
4786 _('commit even if some hunks fail')),
4796 ('', 'exact', None,
4787 ('', 'exact', None,
4797 _('abort if patch would apply lossily')),
4788 _('abort if patch would apply lossily')),
4798 ('', 'prefix', '',
4789 ('', 'prefix', '',
4799 _('apply patch to subdirectory'), _('DIR')),
4790 _('apply patch to subdirectory'), _('DIR')),
4800 ('', 'import-branch', None,
4791 ('', 'import-branch', None,
4801 _('use any branch information in patch (implied by --exact)'))] +
4792 _('use any branch information in patch (implied by --exact)'))] +
4802 commitopts + commitopts2 + similarityopts,
4793 commitopts + commitopts2 + similarityopts,
4803 _('[OPTION]... PATCH...'))
4794 _('[OPTION]... PATCH...'))
4804 def import_(ui, repo, patch1=None, *patches, **opts):
4795 def import_(ui, repo, patch1=None, *patches, **opts):
4805 """import an ordered set of patches
4796 """import an ordered set of patches
4806
4797
4807 Import a list of patches and commit them individually (unless
4798 Import a list of patches and commit them individually (unless
4808 --no-commit is specified).
4799 --no-commit is specified).
4809
4800
4810 To read a patch from standard input, use "-" as the patch name. If
4801 To read a patch from standard input, use "-" as the patch name. If
4811 a URL is specified, the patch will be downloaded from there.
4802 a URL is specified, the patch will be downloaded from there.
4812
4803
4813 Import first applies changes to the working directory (unless
4804 Import first applies changes to the working directory (unless
4814 --bypass is specified), import will abort if there are outstanding
4805 --bypass is specified), import will abort if there are outstanding
4815 changes.
4806 changes.
4816
4807
4817 Use --bypass to apply and commit patches directly to the
4808 Use --bypass to apply and commit patches directly to the
4818 repository, without affecting the working directory. Without
4809 repository, without affecting the working directory. Without
4819 --exact, patches will be applied on top of the working directory
4810 --exact, patches will be applied on top of the working directory
4820 parent revision.
4811 parent revision.
4821
4812
4822 You can import a patch straight from a mail message. Even patches
4813 You can import a patch straight from a mail message. Even patches
4823 as attachments work (to use the body part, it must have type
4814 as attachments work (to use the body part, it must have type
4824 text/plain or text/x-patch). From and Subject headers of email
4815 text/plain or text/x-patch). From and Subject headers of email
4825 message are used as default committer and commit message. All
4816 message are used as default committer and commit message. All
4826 text/plain body parts before first diff are added to the commit
4817 text/plain body parts before first diff are added to the commit
4827 message.
4818 message.
4828
4819
4829 If the imported patch was generated by :hg:`export`, user and
4820 If the imported patch was generated by :hg:`export`, user and
4830 description from patch override values from message headers and
4821 description from patch override values from message headers and
4831 body. Values given on command line with -m/--message and -u/--user
4822 body. Values given on command line with -m/--message and -u/--user
4832 override these.
4823 override these.
4833
4824
4834 If --exact is specified, import will set the working directory to
4825 If --exact is specified, import will set the working directory to
4835 the parent of each patch before applying it, and will abort if the
4826 the parent of each patch before applying it, and will abort if the
4836 resulting changeset has a different ID than the one recorded in
4827 resulting changeset has a different ID than the one recorded in
4837 the patch. This will guard against various ways that portable
4828 the patch. This will guard against various ways that portable
4838 patch formats and mail systems might fail to transfer Mercurial
4829 patch formats and mail systems might fail to transfer Mercurial
4839 data or metadata. See :hg:`bundle` for lossless transmission.
4830 data or metadata. See :hg:`bundle` for lossless transmission.
4840
4831
4841 Use --partial to ensure a changeset will be created from the patch
4832 Use --partial to ensure a changeset will be created from the patch
4842 even if some hunks fail to apply. Hunks that fail to apply will be
4833 even if some hunks fail to apply. Hunks that fail to apply will be
4843 written to a <target-file>.rej file. Conflicts can then be resolved
4834 written to a <target-file>.rej file. Conflicts can then be resolved
4844 by hand before :hg:`commit --amend` is run to update the created
4835 by hand before :hg:`commit --amend` is run to update the created
4845 changeset. This flag exists to let people import patches that
4836 changeset. This flag exists to let people import patches that
4846 partially apply without losing the associated metadata (author,
4837 partially apply without losing the associated metadata (author,
4847 date, description, ...).
4838 date, description, ...).
4848
4839
4849 .. note::
4840 .. note::
4850
4841
4851 When no hunks apply cleanly, :hg:`import --partial` will create
4842 When no hunks apply cleanly, :hg:`import --partial` will create
4852 an empty changeset, importing only the patch metadata.
4843 an empty changeset, importing only the patch metadata.
4853
4844
4854 With -s/--similarity, hg will attempt to discover renames and
4845 With -s/--similarity, hg will attempt to discover renames and
4855 copies in the patch in the same way as :hg:`addremove`.
4846 copies in the patch in the same way as :hg:`addremove`.
4856
4847
4857 It is possible to use external patch programs to perform the patch
4848 It is possible to use external patch programs to perform the patch
4858 by setting the ``ui.patch`` configuration option. For the default
4849 by setting the ``ui.patch`` configuration option. For the default
4859 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4850 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4860 See :hg:`help config` for more information about configuration
4851 See :hg:`help config` for more information about configuration
4861 files and how to use these options.
4852 files and how to use these options.
4862
4853
4863 See :hg:`help dates` for a list of formats valid for -d/--date.
4854 See :hg:`help dates` for a list of formats valid for -d/--date.
4864
4855
4865 .. container:: verbose
4856 .. container:: verbose
4866
4857
4867 Examples:
4858 Examples:
4868
4859
4869 - import a traditional patch from a website and detect renames::
4860 - import a traditional patch from a website and detect renames::
4870
4861
4871 hg import -s 80 http://example.com/bugfix.patch
4862 hg import -s 80 http://example.com/bugfix.patch
4872
4863
4873 - import a changeset from an hgweb server::
4864 - import a changeset from an hgweb server::
4874
4865
4875 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4866 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4876
4867
4877 - import all the patches in an Unix-style mbox::
4868 - import all the patches in an Unix-style mbox::
4878
4869
4879 hg import incoming-patches.mbox
4870 hg import incoming-patches.mbox
4880
4871
4881 - attempt to exactly restore an exported changeset (not always
4872 - attempt to exactly restore an exported changeset (not always
4882 possible)::
4873 possible)::
4883
4874
4884 hg import --exact proposed-fix.patch
4875 hg import --exact proposed-fix.patch
4885
4876
4886 - use an external tool to apply a patch which is too fuzzy for
4877 - use an external tool to apply a patch which is too fuzzy for
4887 the default internal tool.
4878 the default internal tool.
4888
4879
4889 hg import --config ui.patch="patch --merge" fuzzy.patch
4880 hg import --config ui.patch="patch --merge" fuzzy.patch
4890
4881
4891 - change the default fuzzing from 2 to a less strict 7
4882 - change the default fuzzing from 2 to a less strict 7
4892
4883
4893 hg import --config ui.fuzz=7 fuzz.patch
4884 hg import --config ui.fuzz=7 fuzz.patch
4894
4885
4895 Returns 0 on success, 1 on partial success (see --partial).
4886 Returns 0 on success, 1 on partial success (see --partial).
4896 """
4887 """
4897
4888
4898 if not patch1:
4889 if not patch1:
4899 raise error.Abort(_('need at least one patch to import'))
4890 raise error.Abort(_('need at least one patch to import'))
4900
4891
4901 patches = (patch1,) + patches
4892 patches = (patch1,) + patches
4902
4893
4903 date = opts.get('date')
4894 date = opts.get('date')
4904 if date:
4895 if date:
4905 opts['date'] = util.parsedate(date)
4896 opts['date'] = util.parsedate(date)
4906
4897
4907 exact = opts.get('exact')
4898 exact = opts.get('exact')
4908 update = not opts.get('bypass')
4899 update = not opts.get('bypass')
4909 if not update and opts.get('no_commit'):
4900 if not update and opts.get('no_commit'):
4910 raise error.Abort(_('cannot use --no-commit with --bypass'))
4901 raise error.Abort(_('cannot use --no-commit with --bypass'))
4911 try:
4902 try:
4912 sim = float(opts.get('similarity') or 0)
4903 sim = float(opts.get('similarity') or 0)
4913 except ValueError:
4904 except ValueError:
4914 raise error.Abort(_('similarity must be a number'))
4905 raise error.Abort(_('similarity must be a number'))
4915 if sim < 0 or sim > 100:
4906 if sim < 0 or sim > 100:
4916 raise error.Abort(_('similarity must be between 0 and 100'))
4907 raise error.Abort(_('similarity must be between 0 and 100'))
4917 if sim and not update:
4908 if sim and not update:
4918 raise error.Abort(_('cannot use --similarity with --bypass'))
4909 raise error.Abort(_('cannot use --similarity with --bypass'))
4919 if exact:
4910 if exact:
4920 if opts.get('edit'):
4911 if opts.get('edit'):
4921 raise error.Abort(_('cannot use --exact with --edit'))
4912 raise error.Abort(_('cannot use --exact with --edit'))
4922 if opts.get('prefix'):
4913 if opts.get('prefix'):
4923 raise error.Abort(_('cannot use --exact with --prefix'))
4914 raise error.Abort(_('cannot use --exact with --prefix'))
4924
4915
4925 base = opts["base"]
4916 base = opts["base"]
4926 wlock = dsguard = lock = tr = None
4917 wlock = dsguard = lock = tr = None
4927 msgs = []
4918 msgs = []
4928 ret = 0
4919 ret = 0
4929
4920
4930
4921
4931 try:
4922 try:
4932 wlock = repo.wlock()
4923 wlock = repo.wlock()
4933
4924
4934 if update:
4925 if update:
4935 cmdutil.checkunfinished(repo)
4926 cmdutil.checkunfinished(repo)
4936 if (exact or not opts.get('force')):
4927 if (exact or not opts.get('force')):
4937 cmdutil.bailifchanged(repo)
4928 cmdutil.bailifchanged(repo)
4938
4929
4939 if not opts.get('no_commit'):
4930 if not opts.get('no_commit'):
4940 lock = repo.lock()
4931 lock = repo.lock()
4941 tr = repo.transaction('import')
4932 tr = repo.transaction('import')
4942 else:
4933 else:
4943 dsguard = cmdutil.dirstateguard(repo, 'import')
4934 dsguard = cmdutil.dirstateguard(repo, 'import')
4944 parents = repo[None].parents()
4935 parents = repo[None].parents()
4945 for patchurl in patches:
4936 for patchurl in patches:
4946 if patchurl == '-':
4937 if patchurl == '-':
4947 ui.status(_('applying patch from stdin\n'))
4938 ui.status(_('applying patch from stdin\n'))
4948 patchfile = ui.fin
4939 patchfile = ui.fin
4949 patchurl = 'stdin' # for error message
4940 patchurl = 'stdin' # for error message
4950 else:
4941 else:
4951 patchurl = os.path.join(base, patchurl)
4942 patchurl = os.path.join(base, patchurl)
4952 ui.status(_('applying %s\n') % patchurl)
4943 ui.status(_('applying %s\n') % patchurl)
4953 patchfile = hg.openpath(ui, patchurl)
4944 patchfile = hg.openpath(ui, patchurl)
4954
4945
4955 haspatch = False
4946 haspatch = False
4956 for hunk in patch.split(patchfile):
4947 for hunk in patch.split(patchfile):
4957 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4948 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4958 parents, opts,
4949 parents, opts,
4959 msgs, hg.clean)
4950 msgs, hg.clean)
4960 if msg:
4951 if msg:
4961 haspatch = True
4952 haspatch = True
4962 ui.note(msg + '\n')
4953 ui.note(msg + '\n')
4963 if update or exact:
4954 if update or exact:
4964 parents = repo[None].parents()
4955 parents = repo[None].parents()
4965 else:
4956 else:
4966 parents = [repo[node]]
4957 parents = [repo[node]]
4967 if rej:
4958 if rej:
4968 ui.write_err(_("patch applied partially\n"))
4959 ui.write_err(_("patch applied partially\n"))
4969 ui.write_err(_("(fix the .rej files and run "
4960 ui.write_err(_("(fix the .rej files and run "
4970 "`hg commit --amend`)\n"))
4961 "`hg commit --amend`)\n"))
4971 ret = 1
4962 ret = 1
4972 break
4963 break
4973
4964
4974 if not haspatch:
4965 if not haspatch:
4975 raise error.Abort(_('%s: no diffs found') % patchurl)
4966 raise error.Abort(_('%s: no diffs found') % patchurl)
4976
4967
4977 if tr:
4968 if tr:
4978 tr.close()
4969 tr.close()
4979 if msgs:
4970 if msgs:
4980 repo.savecommitmessage('\n* * *\n'.join(msgs))
4971 repo.savecommitmessage('\n* * *\n'.join(msgs))
4981 if dsguard:
4972 if dsguard:
4982 dsguard.close()
4973 dsguard.close()
4983 return ret
4974 return ret
4984 finally:
4975 finally:
4985 if tr:
4976 if tr:
4986 tr.release()
4977 tr.release()
4987 release(lock, dsguard, wlock)
4978 release(lock, dsguard, wlock)
4988
4979
4989 @command('incoming|in',
4980 @command('incoming|in',
4990 [('f', 'force', None,
4981 [('f', 'force', None,
4991 _('run even if remote repository is unrelated')),
4982 _('run even if remote repository is unrelated')),
4992 ('n', 'newest-first', None, _('show newest record first')),
4983 ('n', 'newest-first', None, _('show newest record first')),
4993 ('', 'bundle', '',
4984 ('', 'bundle', '',
4994 _('file to store the bundles into'), _('FILE')),
4985 _('file to store the bundles into'), _('FILE')),
4995 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4986 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4996 ('B', 'bookmarks', False, _("compare bookmarks")),
4987 ('B', 'bookmarks', False, _("compare bookmarks")),
4997 ('b', 'branch', [],
4988 ('b', 'branch', [],
4998 _('a specific branch you would like to pull'), _('BRANCH')),
4989 _('a specific branch you would like to pull'), _('BRANCH')),
4999 ] + logopts + remoteopts + subrepoopts,
4990 ] + logopts + remoteopts + subrepoopts,
5000 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4991 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5001 def incoming(ui, repo, source="default", **opts):
4992 def incoming(ui, repo, source="default", **opts):
5002 """show new changesets found in source
4993 """show new changesets found in source
5003
4994
5004 Show new changesets found in the specified path/URL or the default
4995 Show new changesets found in the specified path/URL or the default
5005 pull location. These are the changesets that would have been pulled
4996 pull location. These are the changesets that would have been pulled
5006 if a pull at the time you issued this command.
4997 if a pull at the time you issued this command.
5007
4998
5008 See pull for valid source format details.
4999 See pull for valid source format details.
5009
5000
5010 .. container:: verbose
5001 .. container:: verbose
5011
5002
5012 With -B/--bookmarks, the result of bookmark comparison between
5003 With -B/--bookmarks, the result of bookmark comparison between
5013 local and remote repositories is displayed. With -v/--verbose,
5004 local and remote repositories is displayed. With -v/--verbose,
5014 status is also displayed for each bookmark like below::
5005 status is also displayed for each bookmark like below::
5015
5006
5016 BM1 01234567890a added
5007 BM1 01234567890a added
5017 BM2 1234567890ab advanced
5008 BM2 1234567890ab advanced
5018 BM3 234567890abc diverged
5009 BM3 234567890abc diverged
5019 BM4 34567890abcd changed
5010 BM4 34567890abcd changed
5020
5011
5021 The action taken locally when pulling depends on the
5012 The action taken locally when pulling depends on the
5022 status of each bookmark:
5013 status of each bookmark:
5023
5014
5024 :``added``: pull will create it
5015 :``added``: pull will create it
5025 :``advanced``: pull will update it
5016 :``advanced``: pull will update it
5026 :``diverged``: pull will create a divergent bookmark
5017 :``diverged``: pull will create a divergent bookmark
5027 :``changed``: result depends on remote changesets
5018 :``changed``: result depends on remote changesets
5028
5019
5029 From the point of view of pulling behavior, bookmark
5020 From the point of view of pulling behavior, bookmark
5030 existing only in the remote repository are treated as ``added``,
5021 existing only in the remote repository are treated as ``added``,
5031 even if it is in fact locally deleted.
5022 even if it is in fact locally deleted.
5032
5023
5033 .. container:: verbose
5024 .. container:: verbose
5034
5025
5035 For remote repository, using --bundle avoids downloading the
5026 For remote repository, using --bundle avoids downloading the
5036 changesets twice if the incoming is followed by a pull.
5027 changesets twice if the incoming is followed by a pull.
5037
5028
5038 Examples:
5029 Examples:
5039
5030
5040 - show incoming changes with patches and full description::
5031 - show incoming changes with patches and full description::
5041
5032
5042 hg incoming -vp
5033 hg incoming -vp
5043
5034
5044 - show incoming changes excluding merges, store a bundle::
5035 - show incoming changes excluding merges, store a bundle::
5045
5036
5046 hg in -vpM --bundle incoming.hg
5037 hg in -vpM --bundle incoming.hg
5047 hg pull incoming.hg
5038 hg pull incoming.hg
5048
5039
5049 - briefly list changes inside a bundle::
5040 - briefly list changes inside a bundle::
5050
5041
5051 hg in changes.hg -T "{desc|firstline}\\n"
5042 hg in changes.hg -T "{desc|firstline}\\n"
5052
5043
5053 Returns 0 if there are incoming changes, 1 otherwise.
5044 Returns 0 if there are incoming changes, 1 otherwise.
5054 """
5045 """
5055 if opts.get('graph'):
5046 if opts.get('graph'):
5056 cmdutil.checkunsupportedgraphflags([], opts)
5047 cmdutil.checkunsupportedgraphflags([], opts)
5057 def display(other, chlist, displayer):
5048 def display(other, chlist, displayer):
5058 revdag = cmdutil.graphrevs(other, chlist, opts)
5049 revdag = cmdutil.graphrevs(other, chlist, opts)
5059 cmdutil.displaygraph(ui, repo, revdag, displayer,
5050 cmdutil.displaygraph(ui, repo, revdag, displayer,
5060 graphmod.asciiedges)
5051 graphmod.asciiedges)
5061
5052
5062 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5053 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5063 return 0
5054 return 0
5064
5055
5065 if opts.get('bundle') and opts.get('subrepos'):
5056 if opts.get('bundle') and opts.get('subrepos'):
5066 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5057 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5067
5058
5068 if opts.get('bookmarks'):
5059 if opts.get('bookmarks'):
5069 source, branches = hg.parseurl(ui.expandpath(source),
5060 source, branches = hg.parseurl(ui.expandpath(source),
5070 opts.get('branch'))
5061 opts.get('branch'))
5071 other = hg.peer(repo, opts, source)
5062 other = hg.peer(repo, opts, source)
5072 if 'bookmarks' not in other.listkeys('namespaces'):
5063 if 'bookmarks' not in other.listkeys('namespaces'):
5073 ui.warn(_("remote doesn't support bookmarks\n"))
5064 ui.warn(_("remote doesn't support bookmarks\n"))
5074 return 0
5065 return 0
5075 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5066 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5076 return bookmarks.incoming(ui, repo, other)
5067 return bookmarks.incoming(ui, repo, other)
5077
5068
5078 repo._subtoppath = ui.expandpath(source)
5069 repo._subtoppath = ui.expandpath(source)
5079 try:
5070 try:
5080 return hg.incoming(ui, repo, source, opts)
5071 return hg.incoming(ui, repo, source, opts)
5081 finally:
5072 finally:
5082 del repo._subtoppath
5073 del repo._subtoppath
5083
5074
5084
5075
5085 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5076 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5086 norepo=True)
5077 norepo=True)
5087 def init(ui, dest=".", **opts):
5078 def init(ui, dest=".", **opts):
5088 """create a new repository in the given directory
5079 """create a new repository in the given directory
5089
5080
5090 Initialize a new repository in the given directory. If the given
5081 Initialize a new repository in the given directory. If the given
5091 directory does not exist, it will be created.
5082 directory does not exist, it will be created.
5092
5083
5093 If no directory is given, the current directory is used.
5084 If no directory is given, the current directory is used.
5094
5085
5095 It is possible to specify an ``ssh://`` URL as the destination.
5086 It is possible to specify an ``ssh://`` URL as the destination.
5096 See :hg:`help urls` for more information.
5087 See :hg:`help urls` for more information.
5097
5088
5098 Returns 0 on success.
5089 Returns 0 on success.
5099 """
5090 """
5100 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5091 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5101
5092
5102 @command('locate',
5093 @command('locate',
5103 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5094 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5104 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5095 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5105 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5096 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5106 ] + walkopts,
5097 ] + walkopts,
5107 _('[OPTION]... [PATTERN]...'))
5098 _('[OPTION]... [PATTERN]...'))
5108 def locate(ui, repo, *pats, **opts):
5099 def locate(ui, repo, *pats, **opts):
5109 """locate files matching specific patterns (DEPRECATED)
5100 """locate files matching specific patterns (DEPRECATED)
5110
5101
5111 Print files under Mercurial control in the working directory whose
5102 Print files under Mercurial control in the working directory whose
5112 names match the given patterns.
5103 names match the given patterns.
5113
5104
5114 By default, this command searches all directories in the working
5105 By default, this command searches all directories in the working
5115 directory. To search just the current directory and its
5106 directory. To search just the current directory and its
5116 subdirectories, use "--include .".
5107 subdirectories, use "--include .".
5117
5108
5118 If no patterns are given to match, this command prints the names
5109 If no patterns are given to match, this command prints the names
5119 of all files under Mercurial control in the working directory.
5110 of all files under Mercurial control in the working directory.
5120
5111
5121 If you want to feed the output of this command into the "xargs"
5112 If you want to feed the output of this command into the "xargs"
5122 command, use the -0 option to both this command and "xargs". This
5113 command, use the -0 option to both this command and "xargs". This
5123 will avoid the problem of "xargs" treating single filenames that
5114 will avoid the problem of "xargs" treating single filenames that
5124 contain whitespace as multiple filenames.
5115 contain whitespace as multiple filenames.
5125
5116
5126 See :hg:`help files` for a more versatile command.
5117 See :hg:`help files` for a more versatile command.
5127
5118
5128 Returns 0 if a match is found, 1 otherwise.
5119 Returns 0 if a match is found, 1 otherwise.
5129 """
5120 """
5130 if opts.get('print0'):
5121 if opts.get('print0'):
5131 end = '\0'
5122 end = '\0'
5132 else:
5123 else:
5133 end = '\n'
5124 end = '\n'
5134 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5125 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5135
5126
5136 ret = 1
5127 ret = 1
5137 ctx = repo[rev]
5128 ctx = repo[rev]
5138 m = scmutil.match(ctx, pats, opts, default='relglob',
5129 m = scmutil.match(ctx, pats, opts, default='relglob',
5139 badfn=lambda x, y: False)
5130 badfn=lambda x, y: False)
5140
5131
5141 for abs in ctx.matches(m):
5132 for abs in ctx.matches(m):
5142 if opts.get('fullpath'):
5133 if opts.get('fullpath'):
5143 ui.write(repo.wjoin(abs), end)
5134 ui.write(repo.wjoin(abs), end)
5144 else:
5135 else:
5145 ui.write(((pats and m.rel(abs)) or abs), end)
5136 ui.write(((pats and m.rel(abs)) or abs), end)
5146 ret = 0
5137 ret = 0
5147
5138
5148 return ret
5139 return ret
5149
5140
5150 @command('^log|history',
5141 @command('^log|history',
5151 [('f', 'follow', None,
5142 [('f', 'follow', None,
5152 _('follow changeset history, or file history across copies and renames')),
5143 _('follow changeset history, or file history across copies and renames')),
5153 ('', 'follow-first', None,
5144 ('', 'follow-first', None,
5154 _('only follow the first parent of merge changesets (DEPRECATED)')),
5145 _('only follow the first parent of merge changesets (DEPRECATED)')),
5155 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5146 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5156 ('C', 'copies', None, _('show copied files')),
5147 ('C', 'copies', None, _('show copied files')),
5157 ('k', 'keyword', [],
5148 ('k', 'keyword', [],
5158 _('do case-insensitive search for a given text'), _('TEXT')),
5149 _('do case-insensitive search for a given text'), _('TEXT')),
5159 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5150 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5160 ('', 'removed', None, _('include revisions where files were removed')),
5151 ('', 'removed', None, _('include revisions where files were removed')),
5161 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5152 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5162 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5153 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5163 ('', 'only-branch', [],
5154 ('', 'only-branch', [],
5164 _('show only changesets within the given named branch (DEPRECATED)'),
5155 _('show only changesets within the given named branch (DEPRECATED)'),
5165 _('BRANCH')),
5156 _('BRANCH')),
5166 ('b', 'branch', [],
5157 ('b', 'branch', [],
5167 _('show changesets within the given named branch'), _('BRANCH')),
5158 _('show changesets within the given named branch'), _('BRANCH')),
5168 ('P', 'prune', [],
5159 ('P', 'prune', [],
5169 _('do not display revision or any of its ancestors'), _('REV')),
5160 _('do not display revision or any of its ancestors'), _('REV')),
5170 ] + logopts + walkopts,
5161 ] + logopts + walkopts,
5171 _('[OPTION]... [FILE]'),
5162 _('[OPTION]... [FILE]'),
5172 inferrepo=True)
5163 inferrepo=True)
5173 def log(ui, repo, *pats, **opts):
5164 def log(ui, repo, *pats, **opts):
5174 """show revision history of entire repository or files
5165 """show revision history of entire repository or files
5175
5166
5176 Print the revision history of the specified files or the entire
5167 Print the revision history of the specified files or the entire
5177 project.
5168 project.
5178
5169
5179 If no revision range is specified, the default is ``tip:0`` unless
5170 If no revision range is specified, the default is ``tip:0`` unless
5180 --follow is set, in which case the working directory parent is
5171 --follow is set, in which case the working directory parent is
5181 used as the starting revision.
5172 used as the starting revision.
5182
5173
5183 File history is shown without following rename or copy history of
5174 File history is shown without following rename or copy history of
5184 files. Use -f/--follow with a filename to follow history across
5175 files. Use -f/--follow with a filename to follow history across
5185 renames and copies. --follow without a filename will only show
5176 renames and copies. --follow without a filename will only show
5186 ancestors or descendants of the starting revision.
5177 ancestors or descendants of the starting revision.
5187
5178
5188 By default this command prints revision number and changeset id,
5179 By default this command prints revision number and changeset id,
5189 tags, non-trivial parents, user, date and time, and a summary for
5180 tags, non-trivial parents, user, date and time, and a summary for
5190 each commit. When the -v/--verbose switch is used, the list of
5181 each commit. When the -v/--verbose switch is used, the list of
5191 changed files and full commit message are shown.
5182 changed files and full commit message are shown.
5192
5183
5193 With --graph the revisions are shown as an ASCII art DAG with the most
5184 With --graph the revisions are shown as an ASCII art DAG with the most
5194 recent changeset at the top.
5185 recent changeset at the top.
5195 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5186 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5196 and '+' represents a fork where the changeset from the lines below is a
5187 and '+' represents a fork where the changeset from the lines below is a
5197 parent of the 'o' merge on the same line.
5188 parent of the 'o' merge on the same line.
5198
5189
5199 .. note::
5190 .. note::
5200
5191
5201 :hg:`log --patch` may generate unexpected diff output for merge
5192 :hg:`log --patch` may generate unexpected diff output for merge
5202 changesets, as it will only compare the merge changeset against
5193 changesets, as it will only compare the merge changeset against
5203 its first parent. Also, only files different from BOTH parents
5194 its first parent. Also, only files different from BOTH parents
5204 will appear in files:.
5195 will appear in files:.
5205
5196
5206 .. note::
5197 .. note::
5207
5198
5208 For performance reasons, :hg:`log FILE` may omit duplicate changes
5199 For performance reasons, :hg:`log FILE` may omit duplicate changes
5209 made on branches and will not show removals or mode changes. To
5200 made on branches and will not show removals or mode changes. To
5210 see all such changes, use the --removed switch.
5201 see all such changes, use the --removed switch.
5211
5202
5212 .. container:: verbose
5203 .. container:: verbose
5213
5204
5214 Some examples:
5205 Some examples:
5215
5206
5216 - changesets with full descriptions and file lists::
5207 - changesets with full descriptions and file lists::
5217
5208
5218 hg log -v
5209 hg log -v
5219
5210
5220 - changesets ancestral to the working directory::
5211 - changesets ancestral to the working directory::
5221
5212
5222 hg log -f
5213 hg log -f
5223
5214
5224 - last 10 commits on the current branch::
5215 - last 10 commits on the current branch::
5225
5216
5226 hg log -l 10 -b .
5217 hg log -l 10 -b .
5227
5218
5228 - changesets showing all modifications of a file, including removals::
5219 - changesets showing all modifications of a file, including removals::
5229
5220
5230 hg log --removed file.c
5221 hg log --removed file.c
5231
5222
5232 - all changesets that touch a directory, with diffs, excluding merges::
5223 - all changesets that touch a directory, with diffs, excluding merges::
5233
5224
5234 hg log -Mp lib/
5225 hg log -Mp lib/
5235
5226
5236 - all revision numbers that match a keyword::
5227 - all revision numbers that match a keyword::
5237
5228
5238 hg log -k bug --template "{rev}\\n"
5229 hg log -k bug --template "{rev}\\n"
5239
5230
5240 - the full hash identifier of the working directory parent::
5231 - the full hash identifier of the working directory parent::
5241
5232
5242 hg log -r . --template "{node}\\n"
5233 hg log -r . --template "{node}\\n"
5243
5234
5244 - list available log templates::
5235 - list available log templates::
5245
5236
5246 hg log -T list
5237 hg log -T list
5247
5238
5248 - check if a given changeset is included in a tagged release::
5239 - check if a given changeset is included in a tagged release::
5249
5240
5250 hg log -r "a21ccf and ancestor(1.9)"
5241 hg log -r "a21ccf and ancestor(1.9)"
5251
5242
5252 - find all changesets by some user in a date range::
5243 - find all changesets by some user in a date range::
5253
5244
5254 hg log -k alice -d "may 2008 to jul 2008"
5245 hg log -k alice -d "may 2008 to jul 2008"
5255
5246
5256 - summary of all changesets after the last tag::
5247 - summary of all changesets after the last tag::
5257
5248
5258 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5249 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5259
5250
5260 See :hg:`help dates` for a list of formats valid for -d/--date.
5251 See :hg:`help dates` for a list of formats valid for -d/--date.
5261
5252
5262 See :hg:`help revisions` and :hg:`help revsets` for more about
5253 See :hg:`help revisions` and :hg:`help revsets` for more about
5263 specifying and ordering revisions.
5254 specifying and ordering revisions.
5264
5255
5265 See :hg:`help templates` for more about pre-packaged styles and
5256 See :hg:`help templates` for more about pre-packaged styles and
5266 specifying custom templates.
5257 specifying custom templates.
5267
5258
5268 Returns 0 on success.
5259 Returns 0 on success.
5269
5260
5270 """
5261 """
5271 if opts.get('follow') and opts.get('rev'):
5262 if opts.get('follow') and opts.get('rev'):
5272 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5263 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5273 del opts['follow']
5264 del opts['follow']
5274
5265
5275 if opts.get('graph'):
5266 if opts.get('graph'):
5276 return cmdutil.graphlog(ui, repo, *pats, **opts)
5267 return cmdutil.graphlog(ui, repo, *pats, **opts)
5277
5268
5278 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5269 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5279 limit = cmdutil.loglimit(opts)
5270 limit = cmdutil.loglimit(opts)
5280 count = 0
5271 count = 0
5281
5272
5282 getrenamed = None
5273 getrenamed = None
5283 if opts.get('copies'):
5274 if opts.get('copies'):
5284 endrev = None
5275 endrev = None
5285 if opts.get('rev'):
5276 if opts.get('rev'):
5286 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5277 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5287 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5278 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5288
5279
5289 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5280 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5290 for rev in revs:
5281 for rev in revs:
5291 if count == limit:
5282 if count == limit:
5292 break
5283 break
5293 ctx = repo[rev]
5284 ctx = repo[rev]
5294 copies = None
5285 copies = None
5295 if getrenamed is not None and rev:
5286 if getrenamed is not None and rev:
5296 copies = []
5287 copies = []
5297 for fn in ctx.files():
5288 for fn in ctx.files():
5298 rename = getrenamed(fn, rev)
5289 rename = getrenamed(fn, rev)
5299 if rename:
5290 if rename:
5300 copies.append((fn, rename[0]))
5291 copies.append((fn, rename[0]))
5301 if filematcher:
5292 if filematcher:
5302 revmatchfn = filematcher(ctx.rev())
5293 revmatchfn = filematcher(ctx.rev())
5303 else:
5294 else:
5304 revmatchfn = None
5295 revmatchfn = None
5305 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5296 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5306 if displayer.flush(ctx):
5297 if displayer.flush(ctx):
5307 count += 1
5298 count += 1
5308
5299
5309 displayer.close()
5300 displayer.close()
5310
5301
5311 @command('manifest',
5302 @command('manifest',
5312 [('r', 'rev', '', _('revision to display'), _('REV')),
5303 [('r', 'rev', '', _('revision to display'), _('REV')),
5313 ('', 'all', False, _("list files from all revisions"))]
5304 ('', 'all', False, _("list files from all revisions"))]
5314 + formatteropts,
5305 + formatteropts,
5315 _('[-r REV]'))
5306 _('[-r REV]'))
5316 def manifest(ui, repo, node=None, rev=None, **opts):
5307 def manifest(ui, repo, node=None, rev=None, **opts):
5317 """output the current or given revision of the project manifest
5308 """output the current or given revision of the project manifest
5318
5309
5319 Print a list of version controlled files for the given revision.
5310 Print a list of version controlled files for the given revision.
5320 If no revision is given, the first parent of the working directory
5311 If no revision is given, the first parent of the working directory
5321 is used, or the null revision if no revision is checked out.
5312 is used, or the null revision if no revision is checked out.
5322
5313
5323 With -v, print file permissions, symlink and executable bits.
5314 With -v, print file permissions, symlink and executable bits.
5324 With --debug, print file revision hashes.
5315 With --debug, print file revision hashes.
5325
5316
5326 If option --all is specified, the list of all files from all revisions
5317 If option --all is specified, the list of all files from all revisions
5327 is printed. This includes deleted and renamed files.
5318 is printed. This includes deleted and renamed files.
5328
5319
5329 Returns 0 on success.
5320 Returns 0 on success.
5330 """
5321 """
5331
5322
5332 fm = ui.formatter('manifest', opts)
5323 fm = ui.formatter('manifest', opts)
5333
5324
5334 if opts.get('all'):
5325 if opts.get('all'):
5335 if rev or node:
5326 if rev or node:
5336 raise error.Abort(_("can't specify a revision with --all"))
5327 raise error.Abort(_("can't specify a revision with --all"))
5337
5328
5338 res = []
5329 res = []
5339 prefix = "data/"
5330 prefix = "data/"
5340 suffix = ".i"
5331 suffix = ".i"
5341 plen = len(prefix)
5332 plen = len(prefix)
5342 slen = len(suffix)
5333 slen = len(suffix)
5343 with repo.lock():
5334 with repo.lock():
5344 for fn, b, size in repo.store.datafiles():
5335 for fn, b, size in repo.store.datafiles():
5345 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5336 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5346 res.append(fn[plen:-slen])
5337 res.append(fn[plen:-slen])
5347 for f in res:
5338 for f in res:
5348 fm.startitem()
5339 fm.startitem()
5349 fm.write("path", '%s\n', f)
5340 fm.write("path", '%s\n', f)
5350 fm.end()
5341 fm.end()
5351 return
5342 return
5352
5343
5353 if rev and node:
5344 if rev and node:
5354 raise error.Abort(_("please specify just one revision"))
5345 raise error.Abort(_("please specify just one revision"))
5355
5346
5356 if not node:
5347 if not node:
5357 node = rev
5348 node = rev
5358
5349
5359 char = {'l': '@', 'x': '*', '': ''}
5350 char = {'l': '@', 'x': '*', '': ''}
5360 mode = {'l': '644', 'x': '755', '': '644'}
5351 mode = {'l': '644', 'x': '755', '': '644'}
5361 ctx = scmutil.revsingle(repo, node)
5352 ctx = scmutil.revsingle(repo, node)
5362 mf = ctx.manifest()
5353 mf = ctx.manifest()
5363 for f in ctx:
5354 for f in ctx:
5364 fm.startitem()
5355 fm.startitem()
5365 fl = ctx[f].flags()
5356 fl = ctx[f].flags()
5366 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5357 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5367 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5358 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5368 fm.write('path', '%s\n', f)
5359 fm.write('path', '%s\n', f)
5369 fm.end()
5360 fm.end()
5370
5361
5371 @command('^merge',
5362 @command('^merge',
5372 [('f', 'force', None,
5363 [('f', 'force', None,
5373 _('force a merge including outstanding changes (DEPRECATED)')),
5364 _('force a merge including outstanding changes (DEPRECATED)')),
5374 ('r', 'rev', '', _('revision to merge'), _('REV')),
5365 ('r', 'rev', '', _('revision to merge'), _('REV')),
5375 ('P', 'preview', None,
5366 ('P', 'preview', None,
5376 _('review revisions to merge (no merge is performed)'))
5367 _('review revisions to merge (no merge is performed)'))
5377 ] + mergetoolopts,
5368 ] + mergetoolopts,
5378 _('[-P] [[-r] REV]'))
5369 _('[-P] [[-r] REV]'))
5379 def merge(ui, repo, node=None, **opts):
5370 def merge(ui, repo, node=None, **opts):
5380 """merge another revision into working directory
5371 """merge another revision into working directory
5381
5372
5382 The current working directory is updated with all changes made in
5373 The current working directory is updated with all changes made in
5383 the requested revision since the last common predecessor revision.
5374 the requested revision since the last common predecessor revision.
5384
5375
5385 Files that changed between either parent are marked as changed for
5376 Files that changed between either parent are marked as changed for
5386 the next commit and a commit must be performed before any further
5377 the next commit and a commit must be performed before any further
5387 updates to the repository are allowed. The next commit will have
5378 updates to the repository are allowed. The next commit will have
5388 two parents.
5379 two parents.
5389
5380
5390 ``--tool`` can be used to specify the merge tool used for file
5381 ``--tool`` can be used to specify the merge tool used for file
5391 merges. It overrides the HGMERGE environment variable and your
5382 merges. It overrides the HGMERGE environment variable and your
5392 configuration files. See :hg:`help merge-tools` for options.
5383 configuration files. See :hg:`help merge-tools` for options.
5393
5384
5394 If no revision is specified, the working directory's parent is a
5385 If no revision is specified, the working directory's parent is a
5395 head revision, and the current branch contains exactly one other
5386 head revision, and the current branch contains exactly one other
5396 head, the other head is merged with by default. Otherwise, an
5387 head, the other head is merged with by default. Otherwise, an
5397 explicit revision with which to merge with must be provided.
5388 explicit revision with which to merge with must be provided.
5398
5389
5399 See :hg:`help resolve` for information on handling file conflicts.
5390 See :hg:`help resolve` for information on handling file conflicts.
5400
5391
5401 To undo an uncommitted merge, use :hg:`update --clean .` which
5392 To undo an uncommitted merge, use :hg:`update --clean .` which
5402 will check out a clean copy of the original merge parent, losing
5393 will check out a clean copy of the original merge parent, losing
5403 all changes.
5394 all changes.
5404
5395
5405 Returns 0 on success, 1 if there are unresolved files.
5396 Returns 0 on success, 1 if there are unresolved files.
5406 """
5397 """
5407
5398
5408 if opts.get('rev') and node:
5399 if opts.get('rev') and node:
5409 raise error.Abort(_("please specify just one revision"))
5400 raise error.Abort(_("please specify just one revision"))
5410 if not node:
5401 if not node:
5411 node = opts.get('rev')
5402 node = opts.get('rev')
5412
5403
5413 if node:
5404 if node:
5414 node = scmutil.revsingle(repo, node).node()
5405 node = scmutil.revsingle(repo, node).node()
5415
5406
5416 if not node:
5407 if not node:
5417 node = repo[destutil.destmerge(repo)].node()
5408 node = repo[destutil.destmerge(repo)].node()
5418
5409
5419 if opts.get('preview'):
5410 if opts.get('preview'):
5420 # find nodes that are ancestors of p2 but not of p1
5411 # find nodes that are ancestors of p2 but not of p1
5421 p1 = repo.lookup('.')
5412 p1 = repo.lookup('.')
5422 p2 = repo.lookup(node)
5413 p2 = repo.lookup(node)
5423 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5414 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5424
5415
5425 displayer = cmdutil.show_changeset(ui, repo, opts)
5416 displayer = cmdutil.show_changeset(ui, repo, opts)
5426 for node in nodes:
5417 for node in nodes:
5427 displayer.show(repo[node])
5418 displayer.show(repo[node])
5428 displayer.close()
5419 displayer.close()
5429 return 0
5420 return 0
5430
5421
5431 try:
5422 try:
5432 # ui.forcemerge is an internal variable, do not document
5423 # ui.forcemerge is an internal variable, do not document
5433 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5424 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5434 force = opts.get('force')
5425 force = opts.get('force')
5435 return hg.merge(repo, node, force=force, mergeforce=force)
5426 return hg.merge(repo, node, force=force, mergeforce=force)
5436 finally:
5427 finally:
5437 ui.setconfig('ui', 'forcemerge', '', 'merge')
5428 ui.setconfig('ui', 'forcemerge', '', 'merge')
5438
5429
5439 @command('outgoing|out',
5430 @command('outgoing|out',
5440 [('f', 'force', None, _('run even when the destination is unrelated')),
5431 [('f', 'force', None, _('run even when the destination is unrelated')),
5441 ('r', 'rev', [],
5432 ('r', 'rev', [],
5442 _('a changeset intended to be included in the destination'), _('REV')),
5433 _('a changeset intended to be included in the destination'), _('REV')),
5443 ('n', 'newest-first', None, _('show newest record first')),
5434 ('n', 'newest-first', None, _('show newest record first')),
5444 ('B', 'bookmarks', False, _('compare bookmarks')),
5435 ('B', 'bookmarks', False, _('compare bookmarks')),
5445 ('b', 'branch', [], _('a specific branch you would like to push'),
5436 ('b', 'branch', [], _('a specific branch you would like to push'),
5446 _('BRANCH')),
5437 _('BRANCH')),
5447 ] + logopts + remoteopts + subrepoopts,
5438 ] + logopts + remoteopts + subrepoopts,
5448 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5439 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5449 def outgoing(ui, repo, dest=None, **opts):
5440 def outgoing(ui, repo, dest=None, **opts):
5450 """show changesets not found in the destination
5441 """show changesets not found in the destination
5451
5442
5452 Show changesets not found in the specified destination repository
5443 Show changesets not found in the specified destination repository
5453 or the default push location. These are the changesets that would
5444 or the default push location. These are the changesets that would
5454 be pushed if a push was requested.
5445 be pushed if a push was requested.
5455
5446
5456 See pull for details of valid destination formats.
5447 See pull for details of valid destination formats.
5457
5448
5458 .. container:: verbose
5449 .. container:: verbose
5459
5450
5460 With -B/--bookmarks, the result of bookmark comparison between
5451 With -B/--bookmarks, the result of bookmark comparison between
5461 local and remote repositories is displayed. With -v/--verbose,
5452 local and remote repositories is displayed. With -v/--verbose,
5462 status is also displayed for each bookmark like below::
5453 status is also displayed for each bookmark like below::
5463
5454
5464 BM1 01234567890a added
5455 BM1 01234567890a added
5465 BM2 deleted
5456 BM2 deleted
5466 BM3 234567890abc advanced
5457 BM3 234567890abc advanced
5467 BM4 34567890abcd diverged
5458 BM4 34567890abcd diverged
5468 BM5 4567890abcde changed
5459 BM5 4567890abcde changed
5469
5460
5470 The action taken when pushing depends on the
5461 The action taken when pushing depends on the
5471 status of each bookmark:
5462 status of each bookmark:
5472
5463
5473 :``added``: push with ``-B`` will create it
5464 :``added``: push with ``-B`` will create it
5474 :``deleted``: push with ``-B`` will delete it
5465 :``deleted``: push with ``-B`` will delete it
5475 :``advanced``: push will update it
5466 :``advanced``: push will update it
5476 :``diverged``: push with ``-B`` will update it
5467 :``diverged``: push with ``-B`` will update it
5477 :``changed``: push with ``-B`` will update it
5468 :``changed``: push with ``-B`` will update it
5478
5469
5479 From the point of view of pushing behavior, bookmarks
5470 From the point of view of pushing behavior, bookmarks
5480 existing only in the remote repository are treated as
5471 existing only in the remote repository are treated as
5481 ``deleted``, even if it is in fact added remotely.
5472 ``deleted``, even if it is in fact added remotely.
5482
5473
5483 Returns 0 if there are outgoing changes, 1 otherwise.
5474 Returns 0 if there are outgoing changes, 1 otherwise.
5484 """
5475 """
5485 if opts.get('graph'):
5476 if opts.get('graph'):
5486 cmdutil.checkunsupportedgraphflags([], opts)
5477 cmdutil.checkunsupportedgraphflags([], opts)
5487 o, other = hg._outgoing(ui, repo, dest, opts)
5478 o, other = hg._outgoing(ui, repo, dest, opts)
5488 if not o:
5479 if not o:
5489 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5480 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5490 return
5481 return
5491
5482
5492 revdag = cmdutil.graphrevs(repo, o, opts)
5483 revdag = cmdutil.graphrevs(repo, o, opts)
5493 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5484 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5494 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5485 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5495 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5486 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5496 return 0
5487 return 0
5497
5488
5498 if opts.get('bookmarks'):
5489 if opts.get('bookmarks'):
5499 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5490 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5500 dest, branches = hg.parseurl(dest, opts.get('branch'))
5491 dest, branches = hg.parseurl(dest, opts.get('branch'))
5501 other = hg.peer(repo, opts, dest)
5492 other = hg.peer(repo, opts, dest)
5502 if 'bookmarks' not in other.listkeys('namespaces'):
5493 if 'bookmarks' not in other.listkeys('namespaces'):
5503 ui.warn(_("remote doesn't support bookmarks\n"))
5494 ui.warn(_("remote doesn't support bookmarks\n"))
5504 return 0
5495 return 0
5505 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5496 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5506 return bookmarks.outgoing(ui, repo, other)
5497 return bookmarks.outgoing(ui, repo, other)
5507
5498
5508 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5499 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5509 try:
5500 try:
5510 return hg.outgoing(ui, repo, dest, opts)
5501 return hg.outgoing(ui, repo, dest, opts)
5511 finally:
5502 finally:
5512 del repo._subtoppath
5503 del repo._subtoppath
5513
5504
5514 @command('parents',
5505 @command('parents',
5515 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5506 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5516 ] + templateopts,
5507 ] + templateopts,
5517 _('[-r REV] [FILE]'),
5508 _('[-r REV] [FILE]'),
5518 inferrepo=True)
5509 inferrepo=True)
5519 def parents(ui, repo, file_=None, **opts):
5510 def parents(ui, repo, file_=None, **opts):
5520 """show the parents of the working directory or revision (DEPRECATED)
5511 """show the parents of the working directory or revision (DEPRECATED)
5521
5512
5522 Print the working directory's parent revisions. If a revision is
5513 Print the working directory's parent revisions. If a revision is
5523 given via -r/--rev, the parent of that revision will be printed.
5514 given via -r/--rev, the parent of that revision will be printed.
5524 If a file argument is given, the revision in which the file was
5515 If a file argument is given, the revision in which the file was
5525 last changed (before the working directory revision or the
5516 last changed (before the working directory revision or the
5526 argument to --rev if given) is printed.
5517 argument to --rev if given) is printed.
5527
5518
5528 This command is equivalent to::
5519 This command is equivalent to::
5529
5520
5530 hg log -r "p1()+p2()" or
5521 hg log -r "p1()+p2()" or
5531 hg log -r "p1(REV)+p2(REV)" or
5522 hg log -r "p1(REV)+p2(REV)" or
5532 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5523 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5533 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5524 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5534
5525
5535 See :hg:`summary` and :hg:`help revsets` for related information.
5526 See :hg:`summary` and :hg:`help revsets` for related information.
5536
5527
5537 Returns 0 on success.
5528 Returns 0 on success.
5538 """
5529 """
5539
5530
5540 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5531 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5541
5532
5542 if file_:
5533 if file_:
5543 m = scmutil.match(ctx, (file_,), opts)
5534 m = scmutil.match(ctx, (file_,), opts)
5544 if m.anypats() or len(m.files()) != 1:
5535 if m.anypats() or len(m.files()) != 1:
5545 raise error.Abort(_('can only specify an explicit filename'))
5536 raise error.Abort(_('can only specify an explicit filename'))
5546 file_ = m.files()[0]
5537 file_ = m.files()[0]
5547 filenodes = []
5538 filenodes = []
5548 for cp in ctx.parents():
5539 for cp in ctx.parents():
5549 if not cp:
5540 if not cp:
5550 continue
5541 continue
5551 try:
5542 try:
5552 filenodes.append(cp.filenode(file_))
5543 filenodes.append(cp.filenode(file_))
5553 except error.LookupError:
5544 except error.LookupError:
5554 pass
5545 pass
5555 if not filenodes:
5546 if not filenodes:
5556 raise error.Abort(_("'%s' not found in manifest!") % file_)
5547 raise error.Abort(_("'%s' not found in manifest!") % file_)
5557 p = []
5548 p = []
5558 for fn in filenodes:
5549 for fn in filenodes:
5559 fctx = repo.filectx(file_, fileid=fn)
5550 fctx = repo.filectx(file_, fileid=fn)
5560 p.append(fctx.node())
5551 p.append(fctx.node())
5561 else:
5552 else:
5562 p = [cp.node() for cp in ctx.parents()]
5553 p = [cp.node() for cp in ctx.parents()]
5563
5554
5564 displayer = cmdutil.show_changeset(ui, repo, opts)
5555 displayer = cmdutil.show_changeset(ui, repo, opts)
5565 for n in p:
5556 for n in p:
5566 if n != nullid:
5557 if n != nullid:
5567 displayer.show(repo[n])
5558 displayer.show(repo[n])
5568 displayer.close()
5559 displayer.close()
5569
5560
5570 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5561 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5571 def paths(ui, repo, search=None, **opts):
5562 def paths(ui, repo, search=None, **opts):
5572 """show aliases for remote repositories
5563 """show aliases for remote repositories
5573
5564
5574 Show definition of symbolic path name NAME. If no name is given,
5565 Show definition of symbolic path name NAME. If no name is given,
5575 show definition of all available names.
5566 show definition of all available names.
5576
5567
5577 Option -q/--quiet suppresses all output when searching for NAME
5568 Option -q/--quiet suppresses all output when searching for NAME
5578 and shows only the path names when listing all definitions.
5569 and shows only the path names when listing all definitions.
5579
5570
5580 Path names are defined in the [paths] section of your
5571 Path names are defined in the [paths] section of your
5581 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5572 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5582 repository, ``.hg/hgrc`` is used, too.
5573 repository, ``.hg/hgrc`` is used, too.
5583
5574
5584 The path names ``default`` and ``default-push`` have a special
5575 The path names ``default`` and ``default-push`` have a special
5585 meaning. When performing a push or pull operation, they are used
5576 meaning. When performing a push or pull operation, they are used
5586 as fallbacks if no location is specified on the command-line.
5577 as fallbacks if no location is specified on the command-line.
5587 When ``default-push`` is set, it will be used for push and
5578 When ``default-push`` is set, it will be used for push and
5588 ``default`` will be used for pull; otherwise ``default`` is used
5579 ``default`` will be used for pull; otherwise ``default`` is used
5589 as the fallback for both. When cloning a repository, the clone
5580 as the fallback for both. When cloning a repository, the clone
5590 source is written as ``default`` in ``.hg/hgrc``.
5581 source is written as ``default`` in ``.hg/hgrc``.
5591
5582
5592 .. note::
5583 .. note::
5593
5584
5594 ``default`` and ``default-push`` apply to all inbound (e.g.
5585 ``default`` and ``default-push`` apply to all inbound (e.g.
5595 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5586 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5596 and :hg:`bundle`) operations.
5587 and :hg:`bundle`) operations.
5597
5588
5598 See :hg:`help urls` for more information.
5589 See :hg:`help urls` for more information.
5599
5590
5600 Returns 0 on success.
5591 Returns 0 on success.
5601 """
5592 """
5602 if search:
5593 if search:
5603 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5594 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5604 if name == search]
5595 if name == search]
5605 else:
5596 else:
5606 pathitems = sorted(ui.paths.iteritems())
5597 pathitems = sorted(ui.paths.iteritems())
5607
5598
5608 fm = ui.formatter('paths', opts)
5599 fm = ui.formatter('paths', opts)
5609 if fm:
5600 if fm:
5610 hidepassword = str
5601 hidepassword = str
5611 else:
5602 else:
5612 hidepassword = util.hidepassword
5603 hidepassword = util.hidepassword
5613 if ui.quiet:
5604 if ui.quiet:
5614 namefmt = '%s\n'
5605 namefmt = '%s\n'
5615 else:
5606 else:
5616 namefmt = '%s = '
5607 namefmt = '%s = '
5617 showsubopts = not search and not ui.quiet
5608 showsubopts = not search and not ui.quiet
5618
5609
5619 for name, path in pathitems:
5610 for name, path in pathitems:
5620 fm.startitem()
5611 fm.startitem()
5621 fm.condwrite(not search, 'name', namefmt, name)
5612 fm.condwrite(not search, 'name', namefmt, name)
5622 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5613 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5623 for subopt, value in sorted(path.suboptions.items()):
5614 for subopt, value in sorted(path.suboptions.items()):
5624 assert subopt not in ('name', 'url')
5615 assert subopt not in ('name', 'url')
5625 if showsubopts:
5616 if showsubopts:
5626 fm.plain('%s:%s = ' % (name, subopt))
5617 fm.plain('%s:%s = ' % (name, subopt))
5627 fm.condwrite(showsubopts, subopt, '%s\n', value)
5618 fm.condwrite(showsubopts, subopt, '%s\n', value)
5628
5619
5629 fm.end()
5620 fm.end()
5630
5621
5631 if search and not pathitems:
5622 if search and not pathitems:
5632 if not ui.quiet:
5623 if not ui.quiet:
5633 ui.warn(_("not found!\n"))
5624 ui.warn(_("not found!\n"))
5634 return 1
5625 return 1
5635 else:
5626 else:
5636 return 0
5627 return 0
5637
5628
5638 @command('phase',
5629 @command('phase',
5639 [('p', 'public', False, _('set changeset phase to public')),
5630 [('p', 'public', False, _('set changeset phase to public')),
5640 ('d', 'draft', False, _('set changeset phase to draft')),
5631 ('d', 'draft', False, _('set changeset phase to draft')),
5641 ('s', 'secret', False, _('set changeset phase to secret')),
5632 ('s', 'secret', False, _('set changeset phase to secret')),
5642 ('f', 'force', False, _('allow to move boundary backward')),
5633 ('f', 'force', False, _('allow to move boundary backward')),
5643 ('r', 'rev', [], _('target revision'), _('REV')),
5634 ('r', 'rev', [], _('target revision'), _('REV')),
5644 ],
5635 ],
5645 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5636 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5646 def phase(ui, repo, *revs, **opts):
5637 def phase(ui, repo, *revs, **opts):
5647 """set or show the current phase name
5638 """set or show the current phase name
5648
5639
5649 With no argument, show the phase name of the current revision(s).
5640 With no argument, show the phase name of the current revision(s).
5650
5641
5651 With one of -p/--public, -d/--draft or -s/--secret, change the
5642 With one of -p/--public, -d/--draft or -s/--secret, change the
5652 phase value of the specified revisions.
5643 phase value of the specified revisions.
5653
5644
5654 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5645 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5655 lower phase to an higher phase. Phases are ordered as follows::
5646 lower phase to an higher phase. Phases are ordered as follows::
5656
5647
5657 public < draft < secret
5648 public < draft < secret
5658
5649
5659 Returns 0 on success, 1 if some phases could not be changed.
5650 Returns 0 on success, 1 if some phases could not be changed.
5660
5651
5661 (For more information about the phases concept, see :hg:`help phases`.)
5652 (For more information about the phases concept, see :hg:`help phases`.)
5662 """
5653 """
5663 # search for a unique phase argument
5654 # search for a unique phase argument
5664 targetphase = None
5655 targetphase = None
5665 for idx, name in enumerate(phases.phasenames):
5656 for idx, name in enumerate(phases.phasenames):
5666 if opts[name]:
5657 if opts[name]:
5667 if targetphase is not None:
5658 if targetphase is not None:
5668 raise error.Abort(_('only one phase can be specified'))
5659 raise error.Abort(_('only one phase can be specified'))
5669 targetphase = idx
5660 targetphase = idx
5670
5661
5671 # look for specified revision
5662 # look for specified revision
5672 revs = list(revs)
5663 revs = list(revs)
5673 revs.extend(opts['rev'])
5664 revs.extend(opts['rev'])
5674 if not revs:
5665 if not revs:
5675 # display both parents as the second parent phase can influence
5666 # display both parents as the second parent phase can influence
5676 # the phase of a merge commit
5667 # the phase of a merge commit
5677 revs = [c.rev() for c in repo[None].parents()]
5668 revs = [c.rev() for c in repo[None].parents()]
5678
5669
5679 revs = scmutil.revrange(repo, revs)
5670 revs = scmutil.revrange(repo, revs)
5680
5671
5681 lock = None
5672 lock = None
5682 ret = 0
5673 ret = 0
5683 if targetphase is None:
5674 if targetphase is None:
5684 # display
5675 # display
5685 for r in revs:
5676 for r in revs:
5686 ctx = repo[r]
5677 ctx = repo[r]
5687 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5678 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5688 else:
5679 else:
5689 tr = None
5680 tr = None
5690 lock = repo.lock()
5681 lock = repo.lock()
5691 try:
5682 try:
5692 tr = repo.transaction("phase")
5683 tr = repo.transaction("phase")
5693 # set phase
5684 # set phase
5694 if not revs:
5685 if not revs:
5695 raise error.Abort(_('empty revision set'))
5686 raise error.Abort(_('empty revision set'))
5696 nodes = [repo[r].node() for r in revs]
5687 nodes = [repo[r].node() for r in revs]
5697 # moving revision from public to draft may hide them
5688 # moving revision from public to draft may hide them
5698 # We have to check result on an unfiltered repository
5689 # We have to check result on an unfiltered repository
5699 unfi = repo.unfiltered()
5690 unfi = repo.unfiltered()
5700 getphase = unfi._phasecache.phase
5691 getphase = unfi._phasecache.phase
5701 olddata = [getphase(unfi, r) for r in unfi]
5692 olddata = [getphase(unfi, r) for r in unfi]
5702 phases.advanceboundary(repo, tr, targetphase, nodes)
5693 phases.advanceboundary(repo, tr, targetphase, nodes)
5703 if opts['force']:
5694 if opts['force']:
5704 phases.retractboundary(repo, tr, targetphase, nodes)
5695 phases.retractboundary(repo, tr, targetphase, nodes)
5705 tr.close()
5696 tr.close()
5706 finally:
5697 finally:
5707 if tr is not None:
5698 if tr is not None:
5708 tr.release()
5699 tr.release()
5709 lock.release()
5700 lock.release()
5710 getphase = unfi._phasecache.phase
5701 getphase = unfi._phasecache.phase
5711 newdata = [getphase(unfi, r) for r in unfi]
5702 newdata = [getphase(unfi, r) for r in unfi]
5712 changes = sum(newdata[r] != olddata[r] for r in unfi)
5703 changes = sum(newdata[r] != olddata[r] for r in unfi)
5713 cl = unfi.changelog
5704 cl = unfi.changelog
5714 rejected = [n for n in nodes
5705 rejected = [n for n in nodes
5715 if newdata[cl.rev(n)] < targetphase]
5706 if newdata[cl.rev(n)] < targetphase]
5716 if rejected:
5707 if rejected:
5717 ui.warn(_('cannot move %i changesets to a higher '
5708 ui.warn(_('cannot move %i changesets to a higher '
5718 'phase, use --force\n') % len(rejected))
5709 'phase, use --force\n') % len(rejected))
5719 ret = 1
5710 ret = 1
5720 if changes:
5711 if changes:
5721 msg = _('phase changed for %i changesets\n') % changes
5712 msg = _('phase changed for %i changesets\n') % changes
5722 if ret:
5713 if ret:
5723 ui.status(msg)
5714 ui.status(msg)
5724 else:
5715 else:
5725 ui.note(msg)
5716 ui.note(msg)
5726 else:
5717 else:
5727 ui.warn(_('no phases changed\n'))
5718 ui.warn(_('no phases changed\n'))
5728 return ret
5719 return ret
5729
5720
5730 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5721 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5731 """Run after a changegroup has been added via pull/unbundle
5722 """Run after a changegroup has been added via pull/unbundle
5732
5723
5733 This takes arguments below:
5724 This takes arguments below:
5734
5725
5735 :modheads: change of heads by pull/unbundle
5726 :modheads: change of heads by pull/unbundle
5736 :optupdate: updating working directory is needed or not
5727 :optupdate: updating working directory is needed or not
5737 :checkout: update destination revision (or None to default destination)
5728 :checkout: update destination revision (or None to default destination)
5738 :brev: a name, which might be a bookmark to be activated after updating
5729 :brev: a name, which might be a bookmark to be activated after updating
5739 """
5730 """
5740 if modheads == 0:
5731 if modheads == 0:
5741 return
5732 return
5742 if optupdate:
5733 if optupdate:
5743 try:
5734 try:
5744 return hg.updatetotally(ui, repo, checkout, brev)
5735 return hg.updatetotally(ui, repo, checkout, brev)
5745 except error.UpdateAbort as inst:
5736 except error.UpdateAbort as inst:
5746 msg = _("not updating: %s") % str(inst)
5737 msg = _("not updating: %s") % str(inst)
5747 hint = inst.hint
5738 hint = inst.hint
5748 raise error.UpdateAbort(msg, hint=hint)
5739 raise error.UpdateAbort(msg, hint=hint)
5749 if modheads > 1:
5740 if modheads > 1:
5750 currentbranchheads = len(repo.branchheads())
5741 currentbranchheads = len(repo.branchheads())
5751 if currentbranchheads == modheads:
5742 if currentbranchheads == modheads:
5752 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5743 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5753 elif currentbranchheads > 1:
5744 elif currentbranchheads > 1:
5754 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5745 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5755 "merge)\n"))
5746 "merge)\n"))
5756 else:
5747 else:
5757 ui.status(_("(run 'hg heads' to see heads)\n"))
5748 ui.status(_("(run 'hg heads' to see heads)\n"))
5758 else:
5749 else:
5759 ui.status(_("(run 'hg update' to get a working copy)\n"))
5750 ui.status(_("(run 'hg update' to get a working copy)\n"))
5760
5751
5761 @command('^pull',
5752 @command('^pull',
5762 [('u', 'update', None,
5753 [('u', 'update', None,
5763 _('update to new branch head if changesets were pulled')),
5754 _('update to new branch head if changesets were pulled')),
5764 ('f', 'force', None, _('run even when remote repository is unrelated')),
5755 ('f', 'force', None, _('run even when remote repository is unrelated')),
5765 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5756 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5766 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5757 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5767 ('b', 'branch', [], _('a specific branch you would like to pull'),
5758 ('b', 'branch', [], _('a specific branch you would like to pull'),
5768 _('BRANCH')),
5759 _('BRANCH')),
5769 ] + remoteopts,
5760 ] + remoteopts,
5770 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5761 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5771 def pull(ui, repo, source="default", **opts):
5762 def pull(ui, repo, source="default", **opts):
5772 """pull changes from the specified source
5763 """pull changes from the specified source
5773
5764
5774 Pull changes from a remote repository to a local one.
5765 Pull changes from a remote repository to a local one.
5775
5766
5776 This finds all changes from the repository at the specified path
5767 This finds all changes from the repository at the specified path
5777 or URL and adds them to a local repository (the current one unless
5768 or URL and adds them to a local repository (the current one unless
5778 -R is specified). By default, this does not update the copy of the
5769 -R is specified). By default, this does not update the copy of the
5779 project in the working directory.
5770 project in the working directory.
5780
5771
5781 Use :hg:`incoming` if you want to see what would have been added
5772 Use :hg:`incoming` if you want to see what would have been added
5782 by a pull at the time you issued this command. If you then decide
5773 by a pull at the time you issued this command. If you then decide
5783 to add those changes to the repository, you should use :hg:`pull
5774 to add those changes to the repository, you should use :hg:`pull
5784 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5775 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5785
5776
5786 If SOURCE is omitted, the 'default' path will be used.
5777 If SOURCE is omitted, the 'default' path will be used.
5787 See :hg:`help urls` for more information.
5778 See :hg:`help urls` for more information.
5788
5779
5789 Specifying bookmark as ``.`` is equivalent to specifying the active
5780 Specifying bookmark as ``.`` is equivalent to specifying the active
5790 bookmark's name.
5781 bookmark's name.
5791
5782
5792 Returns 0 on success, 1 if an update had unresolved files.
5783 Returns 0 on success, 1 if an update had unresolved files.
5793 """
5784 """
5794 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5785 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5795 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5786 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5796 other = hg.peer(repo, opts, source)
5787 other = hg.peer(repo, opts, source)
5797 try:
5788 try:
5798 revs, checkout = hg.addbranchrevs(repo, other, branches,
5789 revs, checkout = hg.addbranchrevs(repo, other, branches,
5799 opts.get('rev'))
5790 opts.get('rev'))
5800
5791
5801
5792
5802 pullopargs = {}
5793 pullopargs = {}
5803 if opts.get('bookmark'):
5794 if opts.get('bookmark'):
5804 if not revs:
5795 if not revs:
5805 revs = []
5796 revs = []
5806 # The list of bookmark used here is not the one used to actually
5797 # The list of bookmark used here is not the one used to actually
5807 # update the bookmark name. This can result in the revision pulled
5798 # update the bookmark name. This can result in the revision pulled
5808 # not ending up with the name of the bookmark because of a race
5799 # not ending up with the name of the bookmark because of a race
5809 # condition on the server. (See issue 4689 for details)
5800 # condition on the server. (See issue 4689 for details)
5810 remotebookmarks = other.listkeys('bookmarks')
5801 remotebookmarks = other.listkeys('bookmarks')
5811 pullopargs['remotebookmarks'] = remotebookmarks
5802 pullopargs['remotebookmarks'] = remotebookmarks
5812 for b in opts['bookmark']:
5803 for b in opts['bookmark']:
5813 b = repo._bookmarks.expandname(b)
5804 b = repo._bookmarks.expandname(b)
5814 if b not in remotebookmarks:
5805 if b not in remotebookmarks:
5815 raise error.Abort(_('remote bookmark %s not found!') % b)
5806 raise error.Abort(_('remote bookmark %s not found!') % b)
5816 revs.append(remotebookmarks[b])
5807 revs.append(remotebookmarks[b])
5817
5808
5818 if revs:
5809 if revs:
5819 try:
5810 try:
5820 # When 'rev' is a bookmark name, we cannot guarantee that it
5811 # When 'rev' is a bookmark name, we cannot guarantee that it
5821 # will be updated with that name because of a race condition
5812 # will be updated with that name because of a race condition
5822 # server side. (See issue 4689 for details)
5813 # server side. (See issue 4689 for details)
5823 oldrevs = revs
5814 oldrevs = revs
5824 revs = [] # actually, nodes
5815 revs = [] # actually, nodes
5825 for r in oldrevs:
5816 for r in oldrevs:
5826 node = other.lookup(r)
5817 node = other.lookup(r)
5827 revs.append(node)
5818 revs.append(node)
5828 if r == checkout:
5819 if r == checkout:
5829 checkout = node
5820 checkout = node
5830 except error.CapabilityError:
5821 except error.CapabilityError:
5831 err = _("other repository doesn't support revision lookup, "
5822 err = _("other repository doesn't support revision lookup, "
5832 "so a rev cannot be specified.")
5823 "so a rev cannot be specified.")
5833 raise error.Abort(err)
5824 raise error.Abort(err)
5834
5825
5835 pullopargs.update(opts.get('opargs', {}))
5826 pullopargs.update(opts.get('opargs', {}))
5836 modheads = exchange.pull(repo, other, heads=revs,
5827 modheads = exchange.pull(repo, other, heads=revs,
5837 force=opts.get('force'),
5828 force=opts.get('force'),
5838 bookmarks=opts.get('bookmark', ()),
5829 bookmarks=opts.get('bookmark', ()),
5839 opargs=pullopargs).cgresult
5830 opargs=pullopargs).cgresult
5840
5831
5841 # brev is a name, which might be a bookmark to be activated at
5832 # brev is a name, which might be a bookmark to be activated at
5842 # the end of the update. In other words, it is an explicit
5833 # the end of the update. In other words, it is an explicit
5843 # destination of the update
5834 # destination of the update
5844 brev = None
5835 brev = None
5845
5836
5846 if checkout:
5837 if checkout:
5847 checkout = str(repo.changelog.rev(checkout))
5838 checkout = str(repo.changelog.rev(checkout))
5848
5839
5849 # order below depends on implementation of
5840 # order below depends on implementation of
5850 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5841 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5851 # because 'checkout' is determined without it.
5842 # because 'checkout' is determined without it.
5852 if opts.get('rev'):
5843 if opts.get('rev'):
5853 brev = opts['rev'][0]
5844 brev = opts['rev'][0]
5854 elif opts.get('branch'):
5845 elif opts.get('branch'):
5855 brev = opts['branch'][0]
5846 brev = opts['branch'][0]
5856 else:
5847 else:
5857 brev = branches[0]
5848 brev = branches[0]
5858 repo._subtoppath = source
5849 repo._subtoppath = source
5859 try:
5850 try:
5860 ret = postincoming(ui, repo, modheads, opts.get('update'),
5851 ret = postincoming(ui, repo, modheads, opts.get('update'),
5861 checkout, brev)
5852 checkout, brev)
5862
5853
5863 finally:
5854 finally:
5864 del repo._subtoppath
5855 del repo._subtoppath
5865
5856
5866 finally:
5857 finally:
5867 other.close()
5858 other.close()
5868 return ret
5859 return ret
5869
5860
5870 @command('^push',
5861 @command('^push',
5871 [('f', 'force', None, _('force push')),
5862 [('f', 'force', None, _('force push')),
5872 ('r', 'rev', [],
5863 ('r', 'rev', [],
5873 _('a changeset intended to be included in the destination'),
5864 _('a changeset intended to be included in the destination'),
5874 _('REV')),
5865 _('REV')),
5875 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5866 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5876 ('b', 'branch', [],
5867 ('b', 'branch', [],
5877 _('a specific branch you would like to push'), _('BRANCH')),
5868 _('a specific branch you would like to push'), _('BRANCH')),
5878 ('', 'new-branch', False, _('allow pushing a new branch')),
5869 ('', 'new-branch', False, _('allow pushing a new branch')),
5879 ] + remoteopts,
5870 ] + remoteopts,
5880 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5871 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5881 def push(ui, repo, dest=None, **opts):
5872 def push(ui, repo, dest=None, **opts):
5882 """push changes to the specified destination
5873 """push changes to the specified destination
5883
5874
5884 Push changesets from the local repository to the specified
5875 Push changesets from the local repository to the specified
5885 destination.
5876 destination.
5886
5877
5887 This operation is symmetrical to pull: it is identical to a pull
5878 This operation is symmetrical to pull: it is identical to a pull
5888 in the destination repository from the current one.
5879 in the destination repository from the current one.
5889
5880
5890 By default, push will not allow creation of new heads at the
5881 By default, push will not allow creation of new heads at the
5891 destination, since multiple heads would make it unclear which head
5882 destination, since multiple heads would make it unclear which head
5892 to use. In this situation, it is recommended to pull and merge
5883 to use. In this situation, it is recommended to pull and merge
5893 before pushing.
5884 before pushing.
5894
5885
5895 Use --new-branch if you want to allow push to create a new named
5886 Use --new-branch if you want to allow push to create a new named
5896 branch that is not present at the destination. This allows you to
5887 branch that is not present at the destination. This allows you to
5897 only create a new branch without forcing other changes.
5888 only create a new branch without forcing other changes.
5898
5889
5899 .. note::
5890 .. note::
5900
5891
5901 Extra care should be taken with the -f/--force option,
5892 Extra care should be taken with the -f/--force option,
5902 which will push all new heads on all branches, an action which will
5893 which will push all new heads on all branches, an action which will
5903 almost always cause confusion for collaborators.
5894 almost always cause confusion for collaborators.
5904
5895
5905 If -r/--rev is used, the specified revision and all its ancestors
5896 If -r/--rev is used, the specified revision and all its ancestors
5906 will be pushed to the remote repository.
5897 will be pushed to the remote repository.
5907
5898
5908 If -B/--bookmark is used, the specified bookmarked revision, its
5899 If -B/--bookmark is used, the specified bookmarked revision, its
5909 ancestors, and the bookmark will be pushed to the remote
5900 ancestors, and the bookmark will be pushed to the remote
5910 repository. Specifying ``.`` is equivalent to specifying the active
5901 repository. Specifying ``.`` is equivalent to specifying the active
5911 bookmark's name.
5902 bookmark's name.
5912
5903
5913 Please see :hg:`help urls` for important details about ``ssh://``
5904 Please see :hg:`help urls` for important details about ``ssh://``
5914 URLs. If DESTINATION is omitted, a default path will be used.
5905 URLs. If DESTINATION is omitted, a default path will be used.
5915
5906
5916 Returns 0 if push was successful, 1 if nothing to push.
5907 Returns 0 if push was successful, 1 if nothing to push.
5917 """
5908 """
5918
5909
5919 if opts.get('bookmark'):
5910 if opts.get('bookmark'):
5920 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5911 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5921 for b in opts['bookmark']:
5912 for b in opts['bookmark']:
5922 # translate -B options to -r so changesets get pushed
5913 # translate -B options to -r so changesets get pushed
5923 b = repo._bookmarks.expandname(b)
5914 b = repo._bookmarks.expandname(b)
5924 if b in repo._bookmarks:
5915 if b in repo._bookmarks:
5925 opts.setdefault('rev', []).append(b)
5916 opts.setdefault('rev', []).append(b)
5926 else:
5917 else:
5927 # if we try to push a deleted bookmark, translate it to null
5918 # if we try to push a deleted bookmark, translate it to null
5928 # this lets simultaneous -r, -b options continue working
5919 # this lets simultaneous -r, -b options continue working
5929 opts.setdefault('rev', []).append("null")
5920 opts.setdefault('rev', []).append("null")
5930
5921
5931 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5922 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5932 if not path:
5923 if not path:
5933 raise error.Abort(_('default repository not configured!'),
5924 raise error.Abort(_('default repository not configured!'),
5934 hint=_('see the "path" section in "hg help config"'))
5925 hint=_('see the "path" section in "hg help config"'))
5935 dest = path.pushloc or path.loc
5926 dest = path.pushloc or path.loc
5936 branches = (path.branch, opts.get('branch') or [])
5927 branches = (path.branch, opts.get('branch') or [])
5937 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5928 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5938 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5929 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5939 other = hg.peer(repo, opts, dest)
5930 other = hg.peer(repo, opts, dest)
5940
5931
5941 if revs:
5932 if revs:
5942 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5933 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5943 if not revs:
5934 if not revs:
5944 raise error.Abort(_("specified revisions evaluate to an empty set"),
5935 raise error.Abort(_("specified revisions evaluate to an empty set"),
5945 hint=_("use different revision arguments"))
5936 hint=_("use different revision arguments"))
5946 elif path.pushrev:
5937 elif path.pushrev:
5947 # It doesn't make any sense to specify ancestor revisions. So limit
5938 # It doesn't make any sense to specify ancestor revisions. So limit
5948 # to DAG heads to make discovery simpler.
5939 # to DAG heads to make discovery simpler.
5949 expr = revset.formatspec('heads(%r)', path.pushrev)
5940 expr = revset.formatspec('heads(%r)', path.pushrev)
5950 revs = scmutil.revrange(repo, [expr])
5941 revs = scmutil.revrange(repo, [expr])
5951 revs = [repo[rev].node() for rev in revs]
5942 revs = [repo[rev].node() for rev in revs]
5952 if not revs:
5943 if not revs:
5953 raise error.Abort(_('default push revset for path evaluates to an '
5944 raise error.Abort(_('default push revset for path evaluates to an '
5954 'empty set'))
5945 'empty set'))
5955
5946
5956 repo._subtoppath = dest
5947 repo._subtoppath = dest
5957 try:
5948 try:
5958 # push subrepos depth-first for coherent ordering
5949 # push subrepos depth-first for coherent ordering
5959 c = repo['']
5950 c = repo['']
5960 subs = c.substate # only repos that are committed
5951 subs = c.substate # only repos that are committed
5961 for s in sorted(subs):
5952 for s in sorted(subs):
5962 result = c.sub(s).push(opts)
5953 result = c.sub(s).push(opts)
5963 if result == 0:
5954 if result == 0:
5964 return not result
5955 return not result
5965 finally:
5956 finally:
5966 del repo._subtoppath
5957 del repo._subtoppath
5967 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5958 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5968 newbranch=opts.get('new_branch'),
5959 newbranch=opts.get('new_branch'),
5969 bookmarks=opts.get('bookmark', ()),
5960 bookmarks=opts.get('bookmark', ()),
5970 opargs=opts.get('opargs'))
5961 opargs=opts.get('opargs'))
5971
5962
5972 result = not pushop.cgresult
5963 result = not pushop.cgresult
5973
5964
5974 if pushop.bkresult is not None:
5965 if pushop.bkresult is not None:
5975 if pushop.bkresult == 2:
5966 if pushop.bkresult == 2:
5976 result = 2
5967 result = 2
5977 elif not result and pushop.bkresult:
5968 elif not result and pushop.bkresult:
5978 result = 2
5969 result = 2
5979
5970
5980 return result
5971 return result
5981
5972
5982 @command('recover', [])
5973 @command('recover', [])
5983 def recover(ui, repo):
5974 def recover(ui, repo):
5984 """roll back an interrupted transaction
5975 """roll back an interrupted transaction
5985
5976
5986 Recover from an interrupted commit or pull.
5977 Recover from an interrupted commit or pull.
5987
5978
5988 This command tries to fix the repository status after an
5979 This command tries to fix the repository status after an
5989 interrupted operation. It should only be necessary when Mercurial
5980 interrupted operation. It should only be necessary when Mercurial
5990 suggests it.
5981 suggests it.
5991
5982
5992 Returns 0 if successful, 1 if nothing to recover or verify fails.
5983 Returns 0 if successful, 1 if nothing to recover or verify fails.
5993 """
5984 """
5994 if repo.recover():
5985 if repo.recover():
5995 return hg.verify(repo)
5986 return hg.verify(repo)
5996 return 1
5987 return 1
5997
5988
5998 @command('^remove|rm',
5989 @command('^remove|rm',
5999 [('A', 'after', None, _('record delete for missing files')),
5990 [('A', 'after', None, _('record delete for missing files')),
6000 ('f', 'force', None,
5991 ('f', 'force', None,
6001 _('forget added files, delete modified files')),
5992 _('forget added files, delete modified files')),
6002 ] + subrepoopts + walkopts,
5993 ] + subrepoopts + walkopts,
6003 _('[OPTION]... FILE...'),
5994 _('[OPTION]... FILE...'),
6004 inferrepo=True)
5995 inferrepo=True)
6005 def remove(ui, repo, *pats, **opts):
5996 def remove(ui, repo, *pats, **opts):
6006 """remove the specified files on the next commit
5997 """remove the specified files on the next commit
6007
5998
6008 Schedule the indicated files for removal from the current branch.
5999 Schedule the indicated files for removal from the current branch.
6009
6000
6010 This command schedules the files to be removed at the next commit.
6001 This command schedules the files to be removed at the next commit.
6011 To undo a remove before that, see :hg:`revert`. To undo added
6002 To undo a remove before that, see :hg:`revert`. To undo added
6012 files, see :hg:`forget`.
6003 files, see :hg:`forget`.
6013
6004
6014 .. container:: verbose
6005 .. container:: verbose
6015
6006
6016 -A/--after can be used to remove only files that have already
6007 -A/--after can be used to remove only files that have already
6017 been deleted, -f/--force can be used to force deletion, and -Af
6008 been deleted, -f/--force can be used to force deletion, and -Af
6018 can be used to remove files from the next revision without
6009 can be used to remove files from the next revision without
6019 deleting them from the working directory.
6010 deleting them from the working directory.
6020
6011
6021 The following table details the behavior of remove for different
6012 The following table details the behavior of remove for different
6022 file states (columns) and option combinations (rows). The file
6013 file states (columns) and option combinations (rows). The file
6023 states are Added [A], Clean [C], Modified [M] and Missing [!]
6014 states are Added [A], Clean [C], Modified [M] and Missing [!]
6024 (as reported by :hg:`status`). The actions are Warn, Remove
6015 (as reported by :hg:`status`). The actions are Warn, Remove
6025 (from branch) and Delete (from disk):
6016 (from branch) and Delete (from disk):
6026
6017
6027 ========= == == == ==
6018 ========= == == == ==
6028 opt/state A C M !
6019 opt/state A C M !
6029 ========= == == == ==
6020 ========= == == == ==
6030 none W RD W R
6021 none W RD W R
6031 -f R RD RD R
6022 -f R RD RD R
6032 -A W W W R
6023 -A W W W R
6033 -Af R R R R
6024 -Af R R R R
6034 ========= == == == ==
6025 ========= == == == ==
6035
6026
6036 .. note::
6027 .. note::
6037
6028
6038 :hg:`remove` never deletes files in Added [A] state from the
6029 :hg:`remove` never deletes files in Added [A] state from the
6039 working directory, not even if ``--force`` is specified.
6030 working directory, not even if ``--force`` is specified.
6040
6031
6041 Returns 0 on success, 1 if any warnings encountered.
6032 Returns 0 on success, 1 if any warnings encountered.
6042 """
6033 """
6043
6034
6044 after, force = opts.get('after'), opts.get('force')
6035 after, force = opts.get('after'), opts.get('force')
6045 if not pats and not after:
6036 if not pats and not after:
6046 raise error.Abort(_('no files specified'))
6037 raise error.Abort(_('no files specified'))
6047
6038
6048 m = scmutil.match(repo[None], pats, opts)
6039 m = scmutil.match(repo[None], pats, opts)
6049 subrepos = opts.get('subrepos')
6040 subrepos = opts.get('subrepos')
6050 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6041 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6051
6042
6052 @command('rename|move|mv',
6043 @command('rename|move|mv',
6053 [('A', 'after', None, _('record a rename that has already occurred')),
6044 [('A', 'after', None, _('record a rename that has already occurred')),
6054 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6045 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6055 ] + walkopts + dryrunopts,
6046 ] + walkopts + dryrunopts,
6056 _('[OPTION]... SOURCE... DEST'))
6047 _('[OPTION]... SOURCE... DEST'))
6057 def rename(ui, repo, *pats, **opts):
6048 def rename(ui, repo, *pats, **opts):
6058 """rename files; equivalent of copy + remove
6049 """rename files; equivalent of copy + remove
6059
6050
6060 Mark dest as copies of sources; mark sources for deletion. If dest
6051 Mark dest as copies of sources; mark sources for deletion. If dest
6061 is a directory, copies are put in that directory. If dest is a
6052 is a directory, copies are put in that directory. If dest is a
6062 file, there can only be one source.
6053 file, there can only be one source.
6063
6054
6064 By default, this command copies the contents of files as they
6055 By default, this command copies the contents of files as they
6065 exist in the working directory. If invoked with -A/--after, the
6056 exist in the working directory. If invoked with -A/--after, the
6066 operation is recorded, but no copying is performed.
6057 operation is recorded, but no copying is performed.
6067
6058
6068 This command takes effect at the next commit. To undo a rename
6059 This command takes effect at the next commit. To undo a rename
6069 before that, see :hg:`revert`.
6060 before that, see :hg:`revert`.
6070
6061
6071 Returns 0 on success, 1 if errors are encountered.
6062 Returns 0 on success, 1 if errors are encountered.
6072 """
6063 """
6073 with repo.wlock(False):
6064 with repo.wlock(False):
6074 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6065 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6075
6066
6076 @command('resolve',
6067 @command('resolve',
6077 [('a', 'all', None, _('select all unresolved files')),
6068 [('a', 'all', None, _('select all unresolved files')),
6078 ('l', 'list', None, _('list state of files needing merge')),
6069 ('l', 'list', None, _('list state of files needing merge')),
6079 ('m', 'mark', None, _('mark files as resolved')),
6070 ('m', 'mark', None, _('mark files as resolved')),
6080 ('u', 'unmark', None, _('mark files as unresolved')),
6071 ('u', 'unmark', None, _('mark files as unresolved')),
6081 ('n', 'no-status', None, _('hide status prefix'))]
6072 ('n', 'no-status', None, _('hide status prefix'))]
6082 + mergetoolopts + walkopts + formatteropts,
6073 + mergetoolopts + walkopts + formatteropts,
6083 _('[OPTION]... [FILE]...'),
6074 _('[OPTION]... [FILE]...'),
6084 inferrepo=True)
6075 inferrepo=True)
6085 def resolve(ui, repo, *pats, **opts):
6076 def resolve(ui, repo, *pats, **opts):
6086 """redo merges or set/view the merge status of files
6077 """redo merges or set/view the merge status of files
6087
6078
6088 Merges with unresolved conflicts are often the result of
6079 Merges with unresolved conflicts are often the result of
6089 non-interactive merging using the ``internal:merge`` configuration
6080 non-interactive merging using the ``internal:merge`` configuration
6090 setting, or a command-line merge tool like ``diff3``. The resolve
6081 setting, or a command-line merge tool like ``diff3``. The resolve
6091 command is used to manage the files involved in a merge, after
6082 command is used to manage the files involved in a merge, after
6092 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6083 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6093 working directory must have two parents). See :hg:`help
6084 working directory must have two parents). See :hg:`help
6094 merge-tools` for information on configuring merge tools.
6085 merge-tools` for information on configuring merge tools.
6095
6086
6096 The resolve command can be used in the following ways:
6087 The resolve command can be used in the following ways:
6097
6088
6098 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6089 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6099 files, discarding any previous merge attempts. Re-merging is not
6090 files, discarding any previous merge attempts. Re-merging is not
6100 performed for files already marked as resolved. Use ``--all/-a``
6091 performed for files already marked as resolved. Use ``--all/-a``
6101 to select all unresolved files. ``--tool`` can be used to specify
6092 to select all unresolved files. ``--tool`` can be used to specify
6102 the merge tool used for the given files. It overrides the HGMERGE
6093 the merge tool used for the given files. It overrides the HGMERGE
6103 environment variable and your configuration files. Previous file
6094 environment variable and your configuration files. Previous file
6104 contents are saved with a ``.orig`` suffix.
6095 contents are saved with a ``.orig`` suffix.
6105
6096
6106 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6097 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6107 (e.g. after having manually fixed-up the files). The default is
6098 (e.g. after having manually fixed-up the files). The default is
6108 to mark all unresolved files.
6099 to mark all unresolved files.
6109
6100
6110 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6101 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6111 default is to mark all resolved files.
6102 default is to mark all resolved files.
6112
6103
6113 - :hg:`resolve -l`: list files which had or still have conflicts.
6104 - :hg:`resolve -l`: list files which had or still have conflicts.
6114 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6105 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6115
6106
6116 .. note::
6107 .. note::
6117
6108
6118 Mercurial will not let you commit files with unresolved merge
6109 Mercurial will not let you commit files with unresolved merge
6119 conflicts. You must use :hg:`resolve -m ...` before you can
6110 conflicts. You must use :hg:`resolve -m ...` before you can
6120 commit after a conflicting merge.
6111 commit after a conflicting merge.
6121
6112
6122 Returns 0 on success, 1 if any files fail a resolve attempt.
6113 Returns 0 on success, 1 if any files fail a resolve attempt.
6123 """
6114 """
6124
6115
6125 flaglist = 'all mark unmark list no_status'.split()
6116 flaglist = 'all mark unmark list no_status'.split()
6126 all, mark, unmark, show, nostatus = \
6117 all, mark, unmark, show, nostatus = \
6127 [opts.get(o) for o in flaglist]
6118 [opts.get(o) for o in flaglist]
6128
6119
6129 if (show and (mark or unmark)) or (mark and unmark):
6120 if (show and (mark or unmark)) or (mark and unmark):
6130 raise error.Abort(_("too many options specified"))
6121 raise error.Abort(_("too many options specified"))
6131 if pats and all:
6122 if pats and all:
6132 raise error.Abort(_("can't specify --all and patterns"))
6123 raise error.Abort(_("can't specify --all and patterns"))
6133 if not (all or pats or show or mark or unmark):
6124 if not (all or pats or show or mark or unmark):
6134 raise error.Abort(_('no files or directories specified'),
6125 raise error.Abort(_('no files or directories specified'),
6135 hint=('use --all to re-merge all unresolved files'))
6126 hint=('use --all to re-merge all unresolved files'))
6136
6127
6137 if show:
6128 if show:
6138 fm = ui.formatter('resolve', opts)
6129 fm = ui.formatter('resolve', opts)
6139 ms = mergemod.mergestate.read(repo)
6130 ms = mergemod.mergestate.read(repo)
6140 m = scmutil.match(repo[None], pats, opts)
6131 m = scmutil.match(repo[None], pats, opts)
6141 for f in ms:
6132 for f in ms:
6142 if not m(f):
6133 if not m(f):
6143 continue
6134 continue
6144 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6135 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6145 'd': 'driverresolved'}[ms[f]]
6136 'd': 'driverresolved'}[ms[f]]
6146 fm.startitem()
6137 fm.startitem()
6147 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6138 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6148 fm.write('path', '%s\n', f, label=l)
6139 fm.write('path', '%s\n', f, label=l)
6149 fm.end()
6140 fm.end()
6150 return 0
6141 return 0
6151
6142
6152 with repo.wlock():
6143 with repo.wlock():
6153 ms = mergemod.mergestate.read(repo)
6144 ms = mergemod.mergestate.read(repo)
6154
6145
6155 if not (ms.active() or repo.dirstate.p2() != nullid):
6146 if not (ms.active() or repo.dirstate.p2() != nullid):
6156 raise error.Abort(
6147 raise error.Abort(
6157 _('resolve command not applicable when not merging'))
6148 _('resolve command not applicable when not merging'))
6158
6149
6159 wctx = repo[None]
6150 wctx = repo[None]
6160
6151
6161 if ms.mergedriver and ms.mdstate() == 'u':
6152 if ms.mergedriver and ms.mdstate() == 'u':
6162 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6153 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6163 ms.commit()
6154 ms.commit()
6164 # allow mark and unmark to go through
6155 # allow mark and unmark to go through
6165 if not mark and not unmark and not proceed:
6156 if not mark and not unmark and not proceed:
6166 return 1
6157 return 1
6167
6158
6168 m = scmutil.match(wctx, pats, opts)
6159 m = scmutil.match(wctx, pats, opts)
6169 ret = 0
6160 ret = 0
6170 didwork = False
6161 didwork = False
6171 runconclude = False
6162 runconclude = False
6172
6163
6173 tocomplete = []
6164 tocomplete = []
6174 for f in ms:
6165 for f in ms:
6175 if not m(f):
6166 if not m(f):
6176 continue
6167 continue
6177
6168
6178 didwork = True
6169 didwork = True
6179
6170
6180 # don't let driver-resolved files be marked, and run the conclude
6171 # don't let driver-resolved files be marked, and run the conclude
6181 # step if asked to resolve
6172 # step if asked to resolve
6182 if ms[f] == "d":
6173 if ms[f] == "d":
6183 exact = m.exact(f)
6174 exact = m.exact(f)
6184 if mark:
6175 if mark:
6185 if exact:
6176 if exact:
6186 ui.warn(_('not marking %s as it is driver-resolved\n')
6177 ui.warn(_('not marking %s as it is driver-resolved\n')
6187 % f)
6178 % f)
6188 elif unmark:
6179 elif unmark:
6189 if exact:
6180 if exact:
6190 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6181 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6191 % f)
6182 % f)
6192 else:
6183 else:
6193 runconclude = True
6184 runconclude = True
6194 continue
6185 continue
6195
6186
6196 if mark:
6187 if mark:
6197 ms.mark(f, "r")
6188 ms.mark(f, "r")
6198 elif unmark:
6189 elif unmark:
6199 ms.mark(f, "u")
6190 ms.mark(f, "u")
6200 else:
6191 else:
6201 # backup pre-resolve (merge uses .orig for its own purposes)
6192 # backup pre-resolve (merge uses .orig for its own purposes)
6202 a = repo.wjoin(f)
6193 a = repo.wjoin(f)
6203 try:
6194 try:
6204 util.copyfile(a, a + ".resolve")
6195 util.copyfile(a, a + ".resolve")
6205 except (IOError, OSError) as inst:
6196 except (IOError, OSError) as inst:
6206 if inst.errno != errno.ENOENT:
6197 if inst.errno != errno.ENOENT:
6207 raise
6198 raise
6208
6199
6209 try:
6200 try:
6210 # preresolve file
6201 # preresolve file
6211 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6202 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6212 'resolve')
6203 'resolve')
6213 complete, r = ms.preresolve(f, wctx)
6204 complete, r = ms.preresolve(f, wctx)
6214 if not complete:
6205 if not complete:
6215 tocomplete.append(f)
6206 tocomplete.append(f)
6216 elif r:
6207 elif r:
6217 ret = 1
6208 ret = 1
6218 finally:
6209 finally:
6219 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6210 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6220 ms.commit()
6211 ms.commit()
6221
6212
6222 # replace filemerge's .orig file with our resolve file, but only
6213 # replace filemerge's .orig file with our resolve file, but only
6223 # for merges that are complete
6214 # for merges that are complete
6224 if complete:
6215 if complete:
6225 try:
6216 try:
6226 util.rename(a + ".resolve",
6217 util.rename(a + ".resolve",
6227 scmutil.origpath(ui, repo, a))
6218 scmutil.origpath(ui, repo, a))
6228 except OSError as inst:
6219 except OSError as inst:
6229 if inst.errno != errno.ENOENT:
6220 if inst.errno != errno.ENOENT:
6230 raise
6221 raise
6231
6222
6232 for f in tocomplete:
6223 for f in tocomplete:
6233 try:
6224 try:
6234 # resolve file
6225 # resolve file
6235 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6226 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6236 'resolve')
6227 'resolve')
6237 r = ms.resolve(f, wctx)
6228 r = ms.resolve(f, wctx)
6238 if r:
6229 if r:
6239 ret = 1
6230 ret = 1
6240 finally:
6231 finally:
6241 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6232 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6242 ms.commit()
6233 ms.commit()
6243
6234
6244 # replace filemerge's .orig file with our resolve file
6235 # replace filemerge's .orig file with our resolve file
6245 a = repo.wjoin(f)
6236 a = repo.wjoin(f)
6246 try:
6237 try:
6247 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6238 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6248 except OSError as inst:
6239 except OSError as inst:
6249 if inst.errno != errno.ENOENT:
6240 if inst.errno != errno.ENOENT:
6250 raise
6241 raise
6251
6242
6252 ms.commit()
6243 ms.commit()
6253 ms.recordactions()
6244 ms.recordactions()
6254
6245
6255 if not didwork and pats:
6246 if not didwork and pats:
6256 hint = None
6247 hint = None
6257 if not any([p for p in pats if p.find(':') >= 0]):
6248 if not any([p for p in pats if p.find(':') >= 0]):
6258 pats = ['path:%s' % p for p in pats]
6249 pats = ['path:%s' % p for p in pats]
6259 m = scmutil.match(wctx, pats, opts)
6250 m = scmutil.match(wctx, pats, opts)
6260 for f in ms:
6251 for f in ms:
6261 if not m(f):
6252 if not m(f):
6262 continue
6253 continue
6263 flags = ''.join(['-%s ' % o[0] for o in flaglist
6254 flags = ''.join(['-%s ' % o[0] for o in flaglist
6264 if opts.get(o)])
6255 if opts.get(o)])
6265 hint = _("(try: hg resolve %s%s)\n") % (
6256 hint = _("(try: hg resolve %s%s)\n") % (
6266 flags,
6257 flags,
6267 ' '.join(pats))
6258 ' '.join(pats))
6268 break
6259 break
6269 ui.warn(_("arguments do not match paths that need resolving\n"))
6260 ui.warn(_("arguments do not match paths that need resolving\n"))
6270 if hint:
6261 if hint:
6271 ui.warn(hint)
6262 ui.warn(hint)
6272 elif ms.mergedriver and ms.mdstate() != 's':
6263 elif ms.mergedriver and ms.mdstate() != 's':
6273 # run conclude step when either a driver-resolved file is requested
6264 # run conclude step when either a driver-resolved file is requested
6274 # or there are no driver-resolved files
6265 # or there are no driver-resolved files
6275 # we can't use 'ret' to determine whether any files are unresolved
6266 # we can't use 'ret' to determine whether any files are unresolved
6276 # because we might not have tried to resolve some
6267 # because we might not have tried to resolve some
6277 if ((runconclude or not list(ms.driverresolved()))
6268 if ((runconclude or not list(ms.driverresolved()))
6278 and not list(ms.unresolved())):
6269 and not list(ms.unresolved())):
6279 proceed = mergemod.driverconclude(repo, ms, wctx)
6270 proceed = mergemod.driverconclude(repo, ms, wctx)
6280 ms.commit()
6271 ms.commit()
6281 if not proceed:
6272 if not proceed:
6282 return 1
6273 return 1
6283
6274
6284 # Nudge users into finishing an unfinished operation
6275 # Nudge users into finishing an unfinished operation
6285 unresolvedf = list(ms.unresolved())
6276 unresolvedf = list(ms.unresolved())
6286 driverresolvedf = list(ms.driverresolved())
6277 driverresolvedf = list(ms.driverresolved())
6287 if not unresolvedf and not driverresolvedf:
6278 if not unresolvedf and not driverresolvedf:
6288 ui.status(_('(no more unresolved files)\n'))
6279 ui.status(_('(no more unresolved files)\n'))
6289 cmdutil.checkafterresolved(repo)
6280 cmdutil.checkafterresolved(repo)
6290 elif not unresolvedf:
6281 elif not unresolvedf:
6291 ui.status(_('(no more unresolved files -- '
6282 ui.status(_('(no more unresolved files -- '
6292 'run "hg resolve --all" to conclude)\n'))
6283 'run "hg resolve --all" to conclude)\n'))
6293
6284
6294 return ret
6285 return ret
6295
6286
6296 @command('revert',
6287 @command('revert',
6297 [('a', 'all', None, _('revert all changes when no arguments given')),
6288 [('a', 'all', None, _('revert all changes when no arguments given')),
6298 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6289 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6299 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6290 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6300 ('C', 'no-backup', None, _('do not save backup copies of files')),
6291 ('C', 'no-backup', None, _('do not save backup copies of files')),
6301 ('i', 'interactive', None,
6292 ('i', 'interactive', None,
6302 _('interactively select the changes (EXPERIMENTAL)')),
6293 _('interactively select the changes (EXPERIMENTAL)')),
6303 ] + walkopts + dryrunopts,
6294 ] + walkopts + dryrunopts,
6304 _('[OPTION]... [-r REV] [NAME]...'))
6295 _('[OPTION]... [-r REV] [NAME]...'))
6305 def revert(ui, repo, *pats, **opts):
6296 def revert(ui, repo, *pats, **opts):
6306 """restore files to their checkout state
6297 """restore files to their checkout state
6307
6298
6308 .. note::
6299 .. note::
6309
6300
6310 To check out earlier revisions, you should use :hg:`update REV`.
6301 To check out earlier revisions, you should use :hg:`update REV`.
6311 To cancel an uncommitted merge (and lose your changes),
6302 To cancel an uncommitted merge (and lose your changes),
6312 use :hg:`update --clean .`.
6303 use :hg:`update --clean .`.
6313
6304
6314 With no revision specified, revert the specified files or directories
6305 With no revision specified, revert the specified files or directories
6315 to the contents they had in the parent of the working directory.
6306 to the contents they had in the parent of the working directory.
6316 This restores the contents of files to an unmodified
6307 This restores the contents of files to an unmodified
6317 state and unschedules adds, removes, copies, and renames. If the
6308 state and unschedules adds, removes, copies, and renames. If the
6318 working directory has two parents, you must explicitly specify a
6309 working directory has two parents, you must explicitly specify a
6319 revision.
6310 revision.
6320
6311
6321 Using the -r/--rev or -d/--date options, revert the given files or
6312 Using the -r/--rev or -d/--date options, revert the given files or
6322 directories to their states as of a specific revision. Because
6313 directories to their states as of a specific revision. Because
6323 revert does not change the working directory parents, this will
6314 revert does not change the working directory parents, this will
6324 cause these files to appear modified. This can be helpful to "back
6315 cause these files to appear modified. This can be helpful to "back
6325 out" some or all of an earlier change. See :hg:`backout` for a
6316 out" some or all of an earlier change. See :hg:`backout` for a
6326 related method.
6317 related method.
6327
6318
6328 Modified files are saved with a .orig suffix before reverting.
6319 Modified files are saved with a .orig suffix before reverting.
6329 To disable these backups, use --no-backup. It is possible to store
6320 To disable these backups, use --no-backup. It is possible to store
6330 the backup files in a custom directory relative to the root of the
6321 the backup files in a custom directory relative to the root of the
6331 repository by setting the ``ui.origbackuppath`` configuration
6322 repository by setting the ``ui.origbackuppath`` configuration
6332 option.
6323 option.
6333
6324
6334 See :hg:`help dates` for a list of formats valid for -d/--date.
6325 See :hg:`help dates` for a list of formats valid for -d/--date.
6335
6326
6336 See :hg:`help backout` for a way to reverse the effect of an
6327 See :hg:`help backout` for a way to reverse the effect of an
6337 earlier changeset.
6328 earlier changeset.
6338
6329
6339 Returns 0 on success.
6330 Returns 0 on success.
6340 """
6331 """
6341
6332
6342 if opts.get("date"):
6333 if opts.get("date"):
6343 if opts.get("rev"):
6334 if opts.get("rev"):
6344 raise error.Abort(_("you can't specify a revision and a date"))
6335 raise error.Abort(_("you can't specify a revision and a date"))
6345 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6336 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6346
6337
6347 parent, p2 = repo.dirstate.parents()
6338 parent, p2 = repo.dirstate.parents()
6348 if not opts.get('rev') and p2 != nullid:
6339 if not opts.get('rev') and p2 != nullid:
6349 # revert after merge is a trap for new users (issue2915)
6340 # revert after merge is a trap for new users (issue2915)
6350 raise error.Abort(_('uncommitted merge with no revision specified'),
6341 raise error.Abort(_('uncommitted merge with no revision specified'),
6351 hint=_("use 'hg update' or see 'hg help revert'"))
6342 hint=_("use 'hg update' or see 'hg help revert'"))
6352
6343
6353 ctx = scmutil.revsingle(repo, opts.get('rev'))
6344 ctx = scmutil.revsingle(repo, opts.get('rev'))
6354
6345
6355 if (not (pats or opts.get('include') or opts.get('exclude') or
6346 if (not (pats or opts.get('include') or opts.get('exclude') or
6356 opts.get('all') or opts.get('interactive'))):
6347 opts.get('all') or opts.get('interactive'))):
6357 msg = _("no files or directories specified")
6348 msg = _("no files or directories specified")
6358 if p2 != nullid:
6349 if p2 != nullid:
6359 hint = _("uncommitted merge, use --all to discard all changes,"
6350 hint = _("uncommitted merge, use --all to discard all changes,"
6360 " or 'hg update -C .' to abort the merge")
6351 " or 'hg update -C .' to abort the merge")
6361 raise error.Abort(msg, hint=hint)
6352 raise error.Abort(msg, hint=hint)
6362 dirty = any(repo.status())
6353 dirty = any(repo.status())
6363 node = ctx.node()
6354 node = ctx.node()
6364 if node != parent:
6355 if node != parent:
6365 if dirty:
6356 if dirty:
6366 hint = _("uncommitted changes, use --all to discard all"
6357 hint = _("uncommitted changes, use --all to discard all"
6367 " changes, or 'hg update %s' to update") % ctx.rev()
6358 " changes, or 'hg update %s' to update") % ctx.rev()
6368 else:
6359 else:
6369 hint = _("use --all to revert all files,"
6360 hint = _("use --all to revert all files,"
6370 " or 'hg update %s' to update") % ctx.rev()
6361 " or 'hg update %s' to update") % ctx.rev()
6371 elif dirty:
6362 elif dirty:
6372 hint = _("uncommitted changes, use --all to discard all changes")
6363 hint = _("uncommitted changes, use --all to discard all changes")
6373 else:
6364 else:
6374 hint = _("use --all to revert all files")
6365 hint = _("use --all to revert all files")
6375 raise error.Abort(msg, hint=hint)
6366 raise error.Abort(msg, hint=hint)
6376
6367
6377 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6368 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6378
6369
6379 @command('rollback', dryrunopts +
6370 @command('rollback', dryrunopts +
6380 [('f', 'force', False, _('ignore safety measures'))])
6371 [('f', 'force', False, _('ignore safety measures'))])
6381 def rollback(ui, repo, **opts):
6372 def rollback(ui, repo, **opts):
6382 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6373 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6383
6374
6384 Please use :hg:`commit --amend` instead of rollback to correct
6375 Please use :hg:`commit --amend` instead of rollback to correct
6385 mistakes in the last commit.
6376 mistakes in the last commit.
6386
6377
6387 This command should be used with care. There is only one level of
6378 This command should be used with care. There is only one level of
6388 rollback, and there is no way to undo a rollback. It will also
6379 rollback, and there is no way to undo a rollback. It will also
6389 restore the dirstate at the time of the last transaction, losing
6380 restore the dirstate at the time of the last transaction, losing
6390 any dirstate changes since that time. This command does not alter
6381 any dirstate changes since that time. This command does not alter
6391 the working directory.
6382 the working directory.
6392
6383
6393 Transactions are used to encapsulate the effects of all commands
6384 Transactions are used to encapsulate the effects of all commands
6394 that create new changesets or propagate existing changesets into a
6385 that create new changesets or propagate existing changesets into a
6395 repository.
6386 repository.
6396
6387
6397 .. container:: verbose
6388 .. container:: verbose
6398
6389
6399 For example, the following commands are transactional, and their
6390 For example, the following commands are transactional, and their
6400 effects can be rolled back:
6391 effects can be rolled back:
6401
6392
6402 - commit
6393 - commit
6403 - import
6394 - import
6404 - pull
6395 - pull
6405 - push (with this repository as the destination)
6396 - push (with this repository as the destination)
6406 - unbundle
6397 - unbundle
6407
6398
6408 To avoid permanent data loss, rollback will refuse to rollback a
6399 To avoid permanent data loss, rollback will refuse to rollback a
6409 commit transaction if it isn't checked out. Use --force to
6400 commit transaction if it isn't checked out. Use --force to
6410 override this protection.
6401 override this protection.
6411
6402
6412 The rollback command can be entirely disabled by setting the
6403 The rollback command can be entirely disabled by setting the
6413 ``ui.rollback`` configuration setting to false. If you're here
6404 ``ui.rollback`` configuration setting to false. If you're here
6414 because you want to use rollback and it's disabled, you can
6405 because you want to use rollback and it's disabled, you can
6415 re-enable the command by setting ``ui.rollback`` to true.
6406 re-enable the command by setting ``ui.rollback`` to true.
6416
6407
6417 This command is not intended for use on public repositories. Once
6408 This command is not intended for use on public repositories. Once
6418 changes are visible for pull by other users, rolling a transaction
6409 changes are visible for pull by other users, rolling a transaction
6419 back locally is ineffective (someone else may already have pulled
6410 back locally is ineffective (someone else may already have pulled
6420 the changes). Furthermore, a race is possible with readers of the
6411 the changes). Furthermore, a race is possible with readers of the
6421 repository; for example an in-progress pull from the repository
6412 repository; for example an in-progress pull from the repository
6422 may fail if a rollback is performed.
6413 may fail if a rollback is performed.
6423
6414
6424 Returns 0 on success, 1 if no rollback data is available.
6415 Returns 0 on success, 1 if no rollback data is available.
6425 """
6416 """
6426 if not ui.configbool('ui', 'rollback', True):
6417 if not ui.configbool('ui', 'rollback', True):
6427 raise error.Abort(_('rollback is disabled because it is unsafe'),
6418 raise error.Abort(_('rollback is disabled because it is unsafe'),
6428 hint=('see `hg help -v rollback` for information'))
6419 hint=('see `hg help -v rollback` for information'))
6429 return repo.rollback(dryrun=opts.get('dry_run'),
6420 return repo.rollback(dryrun=opts.get('dry_run'),
6430 force=opts.get('force'))
6421 force=opts.get('force'))
6431
6422
6432 @command('root', [])
6423 @command('root', [])
6433 def root(ui, repo):
6424 def root(ui, repo):
6434 """print the root (top) of the current working directory
6425 """print the root (top) of the current working directory
6435
6426
6436 Print the root directory of the current repository.
6427 Print the root directory of the current repository.
6437
6428
6438 Returns 0 on success.
6429 Returns 0 on success.
6439 """
6430 """
6440 ui.write(repo.root + "\n")
6431 ui.write(repo.root + "\n")
6441
6432
6442 @command('^serve',
6433 @command('^serve',
6443 [('A', 'accesslog', '', _('name of access log file to write to'),
6434 [('A', 'accesslog', '', _('name of access log file to write to'),
6444 _('FILE')),
6435 _('FILE')),
6445 ('d', 'daemon', None, _('run server in background')),
6436 ('d', 'daemon', None, _('run server in background')),
6446 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6437 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6447 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6438 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6448 # use string type, then we can check if something was passed
6439 # use string type, then we can check if something was passed
6449 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6440 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6450 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6441 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6451 _('ADDR')),
6442 _('ADDR')),
6452 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6443 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6453 _('PREFIX')),
6444 _('PREFIX')),
6454 ('n', 'name', '',
6445 ('n', 'name', '',
6455 _('name to show in web pages (default: working directory)'), _('NAME')),
6446 _('name to show in web pages (default: working directory)'), _('NAME')),
6456 ('', 'web-conf', '',
6447 ('', 'web-conf', '',
6457 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6448 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6458 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6449 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6459 _('FILE')),
6450 _('FILE')),
6460 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6451 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6461 ('', 'stdio', None, _('for remote clients')),
6452 ('', 'stdio', None, _('for remote clients')),
6462 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6453 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6463 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6454 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6464 ('', 'style', '', _('template style to use'), _('STYLE')),
6455 ('', 'style', '', _('template style to use'), _('STYLE')),
6465 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6456 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6466 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6457 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6467 _('[OPTION]...'),
6458 _('[OPTION]...'),
6468 optionalrepo=True)
6459 optionalrepo=True)
6469 def serve(ui, repo, **opts):
6460 def serve(ui, repo, **opts):
6470 """start stand-alone webserver
6461 """start stand-alone webserver
6471
6462
6472 Start a local HTTP repository browser and pull server. You can use
6463 Start a local HTTP repository browser and pull server. You can use
6473 this for ad-hoc sharing and browsing of repositories. It is
6464 this for ad-hoc sharing and browsing of repositories. It is
6474 recommended to use a real web server to serve a repository for
6465 recommended to use a real web server to serve a repository for
6475 longer periods of time.
6466 longer periods of time.
6476
6467
6477 Please note that the server does not implement access control.
6468 Please note that the server does not implement access control.
6478 This means that, by default, anybody can read from the server and
6469 This means that, by default, anybody can read from the server and
6479 nobody can write to it by default. Set the ``web.allow_push``
6470 nobody can write to it by default. Set the ``web.allow_push``
6480 option to ``*`` to allow everybody to push to the server. You
6471 option to ``*`` to allow everybody to push to the server. You
6481 should use a real web server if you need to authenticate users.
6472 should use a real web server if you need to authenticate users.
6482
6473
6483 By default, the server logs accesses to stdout and errors to
6474 By default, the server logs accesses to stdout and errors to
6484 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6475 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6485 files.
6476 files.
6486
6477
6487 To have the server choose a free port number to listen on, specify
6478 To have the server choose a free port number to listen on, specify
6488 a port number of 0; in this case, the server will print the port
6479 a port number of 0; in this case, the server will print the port
6489 number it uses.
6480 number it uses.
6490
6481
6491 Returns 0 on success.
6482 Returns 0 on success.
6492 """
6483 """
6493
6484
6494 if opts["stdio"] and opts["cmdserver"]:
6485 if opts["stdio"] and opts["cmdserver"]:
6495 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6486 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6496
6487
6497 if opts["stdio"]:
6488 if opts["stdio"]:
6498 if repo is None:
6489 if repo is None:
6499 raise error.RepoError(_("there is no Mercurial repository here"
6490 raise error.RepoError(_("there is no Mercurial repository here"
6500 " (.hg not found)"))
6491 " (.hg not found)"))
6501 s = sshserver.sshserver(ui, repo)
6492 s = sshserver.sshserver(ui, repo)
6502 s.serve_forever()
6493 s.serve_forever()
6503
6494
6504 if opts["cmdserver"]:
6495 if opts["cmdserver"]:
6505 service = commandserver.createservice(ui, repo, opts)
6496 service = commandserver.createservice(ui, repo, opts)
6506 else:
6497 else:
6507 service = hgweb.createservice(ui, repo, opts)
6498 service = hgweb.createservice(ui, repo, opts)
6508 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6499 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6509
6500
6510 @command('^status|st',
6501 @command('^status|st',
6511 [('A', 'all', None, _('show status of all files')),
6502 [('A', 'all', None, _('show status of all files')),
6512 ('m', 'modified', None, _('show only modified files')),
6503 ('m', 'modified', None, _('show only modified files')),
6513 ('a', 'added', None, _('show only added files')),
6504 ('a', 'added', None, _('show only added files')),
6514 ('r', 'removed', None, _('show only removed files')),
6505 ('r', 'removed', None, _('show only removed files')),
6515 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6506 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6516 ('c', 'clean', None, _('show only files without changes')),
6507 ('c', 'clean', None, _('show only files without changes')),
6517 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6508 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6518 ('i', 'ignored', None, _('show only ignored files')),
6509 ('i', 'ignored', None, _('show only ignored files')),
6519 ('n', 'no-status', None, _('hide status prefix')),
6510 ('n', 'no-status', None, _('hide status prefix')),
6520 ('C', 'copies', None, _('show source of copied files')),
6511 ('C', 'copies', None, _('show source of copied files')),
6521 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6512 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6522 ('', 'rev', [], _('show difference from revision'), _('REV')),
6513 ('', 'rev', [], _('show difference from revision'), _('REV')),
6523 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6514 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6524 ] + walkopts + subrepoopts + formatteropts,
6515 ] + walkopts + subrepoopts + formatteropts,
6525 _('[OPTION]... [FILE]...'),
6516 _('[OPTION]... [FILE]...'),
6526 inferrepo=True)
6517 inferrepo=True)
6527 def status(ui, repo, *pats, **opts):
6518 def status(ui, repo, *pats, **opts):
6528 """show changed files in the working directory
6519 """show changed files in the working directory
6529
6520
6530 Show status of files in the repository. If names are given, only
6521 Show status of files in the repository. If names are given, only
6531 files that match are shown. Files that are clean or ignored or
6522 files that match are shown. Files that are clean or ignored or
6532 the source of a copy/move operation, are not listed unless
6523 the source of a copy/move operation, are not listed unless
6533 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6524 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6534 Unless options described with "show only ..." are given, the
6525 Unless options described with "show only ..." are given, the
6535 options -mardu are used.
6526 options -mardu are used.
6536
6527
6537 Option -q/--quiet hides untracked (unknown and ignored) files
6528 Option -q/--quiet hides untracked (unknown and ignored) files
6538 unless explicitly requested with -u/--unknown or -i/--ignored.
6529 unless explicitly requested with -u/--unknown or -i/--ignored.
6539
6530
6540 .. note::
6531 .. note::
6541
6532
6542 :hg:`status` may appear to disagree with diff if permissions have
6533 :hg:`status` may appear to disagree with diff if permissions have
6543 changed or a merge has occurred. The standard diff format does
6534 changed or a merge has occurred. The standard diff format does
6544 not report permission changes and diff only reports changes
6535 not report permission changes and diff only reports changes
6545 relative to one merge parent.
6536 relative to one merge parent.
6546
6537
6547 If one revision is given, it is used as the base revision.
6538 If one revision is given, it is used as the base revision.
6548 If two revisions are given, the differences between them are
6539 If two revisions are given, the differences between them are
6549 shown. The --change option can also be used as a shortcut to list
6540 shown. The --change option can also be used as a shortcut to list
6550 the changed files of a revision from its first parent.
6541 the changed files of a revision from its first parent.
6551
6542
6552 The codes used to show the status of files are::
6543 The codes used to show the status of files are::
6553
6544
6554 M = modified
6545 M = modified
6555 A = added
6546 A = added
6556 R = removed
6547 R = removed
6557 C = clean
6548 C = clean
6558 ! = missing (deleted by non-hg command, but still tracked)
6549 ! = missing (deleted by non-hg command, but still tracked)
6559 ? = not tracked
6550 ? = not tracked
6560 I = ignored
6551 I = ignored
6561 = origin of the previous file (with --copies)
6552 = origin of the previous file (with --copies)
6562
6553
6563 .. container:: verbose
6554 .. container:: verbose
6564
6555
6565 Examples:
6556 Examples:
6566
6557
6567 - show changes in the working directory relative to a
6558 - show changes in the working directory relative to a
6568 changeset::
6559 changeset::
6569
6560
6570 hg status --rev 9353
6561 hg status --rev 9353
6571
6562
6572 - show changes in the working directory relative to the
6563 - show changes in the working directory relative to the
6573 current directory (see :hg:`help patterns` for more information)::
6564 current directory (see :hg:`help patterns` for more information)::
6574
6565
6575 hg status re:
6566 hg status re:
6576
6567
6577 - show all changes including copies in an existing changeset::
6568 - show all changes including copies in an existing changeset::
6578
6569
6579 hg status --copies --change 9353
6570 hg status --copies --change 9353
6580
6571
6581 - get a NUL separated list of added files, suitable for xargs::
6572 - get a NUL separated list of added files, suitable for xargs::
6582
6573
6583 hg status -an0
6574 hg status -an0
6584
6575
6585 Returns 0 on success.
6576 Returns 0 on success.
6586 """
6577 """
6587
6578
6588 revs = opts.get('rev')
6579 revs = opts.get('rev')
6589 change = opts.get('change')
6580 change = opts.get('change')
6590
6581
6591 if revs and change:
6582 if revs and change:
6592 msg = _('cannot specify --rev and --change at the same time')
6583 msg = _('cannot specify --rev and --change at the same time')
6593 raise error.Abort(msg)
6584 raise error.Abort(msg)
6594 elif change:
6585 elif change:
6595 node2 = scmutil.revsingle(repo, change, None).node()
6586 node2 = scmutil.revsingle(repo, change, None).node()
6596 node1 = repo[node2].p1().node()
6587 node1 = repo[node2].p1().node()
6597 else:
6588 else:
6598 node1, node2 = scmutil.revpair(repo, revs)
6589 node1, node2 = scmutil.revpair(repo, revs)
6599
6590
6600 if pats:
6591 if pats:
6601 cwd = repo.getcwd()
6592 cwd = repo.getcwd()
6602 else:
6593 else:
6603 cwd = ''
6594 cwd = ''
6604
6595
6605 if opts.get('print0'):
6596 if opts.get('print0'):
6606 end = '\0'
6597 end = '\0'
6607 else:
6598 else:
6608 end = '\n'
6599 end = '\n'
6609 copy = {}
6600 copy = {}
6610 states = 'modified added removed deleted unknown ignored clean'.split()
6601 states = 'modified added removed deleted unknown ignored clean'.split()
6611 show = [k for k in states if opts.get(k)]
6602 show = [k for k in states if opts.get(k)]
6612 if opts.get('all'):
6603 if opts.get('all'):
6613 show += ui.quiet and (states[:4] + ['clean']) or states
6604 show += ui.quiet and (states[:4] + ['clean']) or states
6614 if not show:
6605 if not show:
6615 if ui.quiet:
6606 if ui.quiet:
6616 show = states[:4]
6607 show = states[:4]
6617 else:
6608 else:
6618 show = states[:5]
6609 show = states[:5]
6619
6610
6620 m = scmutil.match(repo[node2], pats, opts)
6611 m = scmutil.match(repo[node2], pats, opts)
6621 stat = repo.status(node1, node2, m,
6612 stat = repo.status(node1, node2, m,
6622 'ignored' in show, 'clean' in show, 'unknown' in show,
6613 'ignored' in show, 'clean' in show, 'unknown' in show,
6623 opts.get('subrepos'))
6614 opts.get('subrepos'))
6624 changestates = zip(states, 'MAR!?IC', stat)
6615 changestates = zip(states, 'MAR!?IC', stat)
6625
6616
6626 if (opts.get('all') or opts.get('copies')
6617 if (opts.get('all') or opts.get('copies')
6627 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6618 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6628 copy = copies.pathcopies(repo[node1], repo[node2], m)
6619 copy = copies.pathcopies(repo[node1], repo[node2], m)
6629
6620
6630 fm = ui.formatter('status', opts)
6621 fm = ui.formatter('status', opts)
6631 fmt = '%s' + end
6622 fmt = '%s' + end
6632 showchar = not opts.get('no_status')
6623 showchar = not opts.get('no_status')
6633
6624
6634 for state, char, files in changestates:
6625 for state, char, files in changestates:
6635 if state in show:
6626 if state in show:
6636 label = 'status.' + state
6627 label = 'status.' + state
6637 for f in files:
6628 for f in files:
6638 fm.startitem()
6629 fm.startitem()
6639 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6630 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6640 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6631 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6641 if f in copy:
6632 if f in copy:
6642 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6633 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6643 label='status.copied')
6634 label='status.copied')
6644 fm.end()
6635 fm.end()
6645
6636
6646 @command('^summary|sum',
6637 @command('^summary|sum',
6647 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6638 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6648 def summary(ui, repo, **opts):
6639 def summary(ui, repo, **opts):
6649 """summarize working directory state
6640 """summarize working directory state
6650
6641
6651 This generates a brief summary of the working directory state,
6642 This generates a brief summary of the working directory state,
6652 including parents, branch, commit status, phase and available updates.
6643 including parents, branch, commit status, phase and available updates.
6653
6644
6654 With the --remote option, this will check the default paths for
6645 With the --remote option, this will check the default paths for
6655 incoming and outgoing changes. This can be time-consuming.
6646 incoming and outgoing changes. This can be time-consuming.
6656
6647
6657 Returns 0 on success.
6648 Returns 0 on success.
6658 """
6649 """
6659
6650
6660 ctx = repo[None]
6651 ctx = repo[None]
6661 parents = ctx.parents()
6652 parents = ctx.parents()
6662 pnode = parents[0].node()
6653 pnode = parents[0].node()
6663 marks = []
6654 marks = []
6664
6655
6665 ms = None
6656 ms = None
6666 try:
6657 try:
6667 ms = mergemod.mergestate.read(repo)
6658 ms = mergemod.mergestate.read(repo)
6668 except error.UnsupportedMergeRecords as e:
6659 except error.UnsupportedMergeRecords as e:
6669 s = ' '.join(e.recordtypes)
6660 s = ' '.join(e.recordtypes)
6670 ui.warn(
6661 ui.warn(
6671 _('warning: merge state has unsupported record types: %s\n') % s)
6662 _('warning: merge state has unsupported record types: %s\n') % s)
6672 unresolved = 0
6663 unresolved = 0
6673 else:
6664 else:
6674 unresolved = [f for f in ms if ms[f] == 'u']
6665 unresolved = [f for f in ms if ms[f] == 'u']
6675
6666
6676 for p in parents:
6667 for p in parents:
6677 # label with log.changeset (instead of log.parent) since this
6668 # label with log.changeset (instead of log.parent) since this
6678 # shows a working directory parent *changeset*:
6669 # shows a working directory parent *changeset*:
6679 # i18n: column positioning for "hg summary"
6670 # i18n: column positioning for "hg summary"
6680 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6671 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6681 label='log.changeset changeset.%s' % p.phasestr())
6672 label='log.changeset changeset.%s' % p.phasestr())
6682 ui.write(' '.join(p.tags()), label='log.tag')
6673 ui.write(' '.join(p.tags()), label='log.tag')
6683 if p.bookmarks():
6674 if p.bookmarks():
6684 marks.extend(p.bookmarks())
6675 marks.extend(p.bookmarks())
6685 if p.rev() == -1:
6676 if p.rev() == -1:
6686 if not len(repo):
6677 if not len(repo):
6687 ui.write(_(' (empty repository)'))
6678 ui.write(_(' (empty repository)'))
6688 else:
6679 else:
6689 ui.write(_(' (no revision checked out)'))
6680 ui.write(_(' (no revision checked out)'))
6690 ui.write('\n')
6681 ui.write('\n')
6691 if p.description():
6682 if p.description():
6692 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6683 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6693 label='log.summary')
6684 label='log.summary')
6694
6685
6695 branch = ctx.branch()
6686 branch = ctx.branch()
6696 bheads = repo.branchheads(branch)
6687 bheads = repo.branchheads(branch)
6697 # i18n: column positioning for "hg summary"
6688 # i18n: column positioning for "hg summary"
6698 m = _('branch: %s\n') % branch
6689 m = _('branch: %s\n') % branch
6699 if branch != 'default':
6690 if branch != 'default':
6700 ui.write(m, label='log.branch')
6691 ui.write(m, label='log.branch')
6701 else:
6692 else:
6702 ui.status(m, label='log.branch')
6693 ui.status(m, label='log.branch')
6703
6694
6704 if marks:
6695 if marks:
6705 active = repo._activebookmark
6696 active = repo._activebookmark
6706 # i18n: column positioning for "hg summary"
6697 # i18n: column positioning for "hg summary"
6707 ui.write(_('bookmarks:'), label='log.bookmark')
6698 ui.write(_('bookmarks:'), label='log.bookmark')
6708 if active is not None:
6699 if active is not None:
6709 if active in marks:
6700 if active in marks:
6710 ui.write(' *' + active, label=activebookmarklabel)
6701 ui.write(' *' + active, label=activebookmarklabel)
6711 marks.remove(active)
6702 marks.remove(active)
6712 else:
6703 else:
6713 ui.write(' [%s]' % active, label=activebookmarklabel)
6704 ui.write(' [%s]' % active, label=activebookmarklabel)
6714 for m in marks:
6705 for m in marks:
6715 ui.write(' ' + m, label='log.bookmark')
6706 ui.write(' ' + m, label='log.bookmark')
6716 ui.write('\n', label='log.bookmark')
6707 ui.write('\n', label='log.bookmark')
6717
6708
6718 status = repo.status(unknown=True)
6709 status = repo.status(unknown=True)
6719
6710
6720 c = repo.dirstate.copies()
6711 c = repo.dirstate.copies()
6721 copied, renamed = [], []
6712 copied, renamed = [], []
6722 for d, s in c.iteritems():
6713 for d, s in c.iteritems():
6723 if s in status.removed:
6714 if s in status.removed:
6724 status.removed.remove(s)
6715 status.removed.remove(s)
6725 renamed.append(d)
6716 renamed.append(d)
6726 else:
6717 else:
6727 copied.append(d)
6718 copied.append(d)
6728 if d in status.added:
6719 if d in status.added:
6729 status.added.remove(d)
6720 status.added.remove(d)
6730
6721
6731 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6722 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6732
6723
6733 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6724 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6734 (ui.label(_('%d added'), 'status.added'), status.added),
6725 (ui.label(_('%d added'), 'status.added'), status.added),
6735 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6726 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6736 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6727 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6737 (ui.label(_('%d copied'), 'status.copied'), copied),
6728 (ui.label(_('%d copied'), 'status.copied'), copied),
6738 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6729 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6739 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6730 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6740 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6731 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6741 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6732 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6742 t = []
6733 t = []
6743 for l, s in labels:
6734 for l, s in labels:
6744 if s:
6735 if s:
6745 t.append(l % len(s))
6736 t.append(l % len(s))
6746
6737
6747 t = ', '.join(t)
6738 t = ', '.join(t)
6748 cleanworkdir = False
6739 cleanworkdir = False
6749
6740
6750 if repo.vfs.exists('graftstate'):
6741 if repo.vfs.exists('graftstate'):
6751 t += _(' (graft in progress)')
6742 t += _(' (graft in progress)')
6752 if repo.vfs.exists('updatestate'):
6743 if repo.vfs.exists('updatestate'):
6753 t += _(' (interrupted update)')
6744 t += _(' (interrupted update)')
6754 elif len(parents) > 1:
6745 elif len(parents) > 1:
6755 t += _(' (merge)')
6746 t += _(' (merge)')
6756 elif branch != parents[0].branch():
6747 elif branch != parents[0].branch():
6757 t += _(' (new branch)')
6748 t += _(' (new branch)')
6758 elif (parents[0].closesbranch() and
6749 elif (parents[0].closesbranch() and
6759 pnode in repo.branchheads(branch, closed=True)):
6750 pnode in repo.branchheads(branch, closed=True)):
6760 t += _(' (head closed)')
6751 t += _(' (head closed)')
6761 elif not (status.modified or status.added or status.removed or renamed or
6752 elif not (status.modified or status.added or status.removed or renamed or
6762 copied or subs):
6753 copied or subs):
6763 t += _(' (clean)')
6754 t += _(' (clean)')
6764 cleanworkdir = True
6755 cleanworkdir = True
6765 elif pnode not in bheads:
6756 elif pnode not in bheads:
6766 t += _(' (new branch head)')
6757 t += _(' (new branch head)')
6767
6758
6768 if parents:
6759 if parents:
6769 pendingphase = max(p.phase() for p in parents)
6760 pendingphase = max(p.phase() for p in parents)
6770 else:
6761 else:
6771 pendingphase = phases.public
6762 pendingphase = phases.public
6772
6763
6773 if pendingphase > phases.newcommitphase(ui):
6764 if pendingphase > phases.newcommitphase(ui):
6774 t += ' (%s)' % phases.phasenames[pendingphase]
6765 t += ' (%s)' % phases.phasenames[pendingphase]
6775
6766
6776 if cleanworkdir:
6767 if cleanworkdir:
6777 # i18n: column positioning for "hg summary"
6768 # i18n: column positioning for "hg summary"
6778 ui.status(_('commit: %s\n') % t.strip())
6769 ui.status(_('commit: %s\n') % t.strip())
6779 else:
6770 else:
6780 # i18n: column positioning for "hg summary"
6771 # i18n: column positioning for "hg summary"
6781 ui.write(_('commit: %s\n') % t.strip())
6772 ui.write(_('commit: %s\n') % t.strip())
6782
6773
6783 # all ancestors of branch heads - all ancestors of parent = new csets
6774 # all ancestors of branch heads - all ancestors of parent = new csets
6784 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6775 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6785 bheads))
6776 bheads))
6786
6777
6787 if new == 0:
6778 if new == 0:
6788 # i18n: column positioning for "hg summary"
6779 # i18n: column positioning for "hg summary"
6789 ui.status(_('update: (current)\n'))
6780 ui.status(_('update: (current)\n'))
6790 elif pnode not in bheads:
6781 elif pnode not in bheads:
6791 # i18n: column positioning for "hg summary"
6782 # i18n: column positioning for "hg summary"
6792 ui.write(_('update: %d new changesets (update)\n') % new)
6783 ui.write(_('update: %d new changesets (update)\n') % new)
6793 else:
6784 else:
6794 # i18n: column positioning for "hg summary"
6785 # i18n: column positioning for "hg summary"
6795 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6786 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6796 (new, len(bheads)))
6787 (new, len(bheads)))
6797
6788
6798 t = []
6789 t = []
6799 draft = len(repo.revs('draft()'))
6790 draft = len(repo.revs('draft()'))
6800 if draft:
6791 if draft:
6801 t.append(_('%d draft') % draft)
6792 t.append(_('%d draft') % draft)
6802 secret = len(repo.revs('secret()'))
6793 secret = len(repo.revs('secret()'))
6803 if secret:
6794 if secret:
6804 t.append(_('%d secret') % secret)
6795 t.append(_('%d secret') % secret)
6805
6796
6806 if draft or secret:
6797 if draft or secret:
6807 ui.status(_('phases: %s\n') % ', '.join(t))
6798 ui.status(_('phases: %s\n') % ', '.join(t))
6808
6799
6809 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6800 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6810 for trouble in ("unstable", "divergent", "bumped"):
6801 for trouble in ("unstable", "divergent", "bumped"):
6811 numtrouble = len(repo.revs(trouble + "()"))
6802 numtrouble = len(repo.revs(trouble + "()"))
6812 # We write all the possibilities to ease translation
6803 # We write all the possibilities to ease translation
6813 troublemsg = {
6804 troublemsg = {
6814 "unstable": _("unstable: %d changesets"),
6805 "unstable": _("unstable: %d changesets"),
6815 "divergent": _("divergent: %d changesets"),
6806 "divergent": _("divergent: %d changesets"),
6816 "bumped": _("bumped: %d changesets"),
6807 "bumped": _("bumped: %d changesets"),
6817 }
6808 }
6818 if numtrouble > 0:
6809 if numtrouble > 0:
6819 ui.status(troublemsg[trouble] % numtrouble + "\n")
6810 ui.status(troublemsg[trouble] % numtrouble + "\n")
6820
6811
6821 cmdutil.summaryhooks(ui, repo)
6812 cmdutil.summaryhooks(ui, repo)
6822
6813
6823 if opts.get('remote'):
6814 if opts.get('remote'):
6824 needsincoming, needsoutgoing = True, True
6815 needsincoming, needsoutgoing = True, True
6825 else:
6816 else:
6826 needsincoming, needsoutgoing = False, False
6817 needsincoming, needsoutgoing = False, False
6827 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6818 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6828 if i:
6819 if i:
6829 needsincoming = True
6820 needsincoming = True
6830 if o:
6821 if o:
6831 needsoutgoing = True
6822 needsoutgoing = True
6832 if not needsincoming and not needsoutgoing:
6823 if not needsincoming and not needsoutgoing:
6833 return
6824 return
6834
6825
6835 def getincoming():
6826 def getincoming():
6836 source, branches = hg.parseurl(ui.expandpath('default'))
6827 source, branches = hg.parseurl(ui.expandpath('default'))
6837 sbranch = branches[0]
6828 sbranch = branches[0]
6838 try:
6829 try:
6839 other = hg.peer(repo, {}, source)
6830 other = hg.peer(repo, {}, source)
6840 except error.RepoError:
6831 except error.RepoError:
6841 if opts.get('remote'):
6832 if opts.get('remote'):
6842 raise
6833 raise
6843 return source, sbranch, None, None, None
6834 return source, sbranch, None, None, None
6844 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6835 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6845 if revs:
6836 if revs:
6846 revs = [other.lookup(rev) for rev in revs]
6837 revs = [other.lookup(rev) for rev in revs]
6847 ui.debug('comparing with %s\n' % util.hidepassword(source))
6838 ui.debug('comparing with %s\n' % util.hidepassword(source))
6848 repo.ui.pushbuffer()
6839 repo.ui.pushbuffer()
6849 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6840 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6850 repo.ui.popbuffer()
6841 repo.ui.popbuffer()
6851 return source, sbranch, other, commoninc, commoninc[1]
6842 return source, sbranch, other, commoninc, commoninc[1]
6852
6843
6853 if needsincoming:
6844 if needsincoming:
6854 source, sbranch, sother, commoninc, incoming = getincoming()
6845 source, sbranch, sother, commoninc, incoming = getincoming()
6855 else:
6846 else:
6856 source = sbranch = sother = commoninc = incoming = None
6847 source = sbranch = sother = commoninc = incoming = None
6857
6848
6858 def getoutgoing():
6849 def getoutgoing():
6859 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6850 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6860 dbranch = branches[0]
6851 dbranch = branches[0]
6861 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6852 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6862 if source != dest:
6853 if source != dest:
6863 try:
6854 try:
6864 dother = hg.peer(repo, {}, dest)
6855 dother = hg.peer(repo, {}, dest)
6865 except error.RepoError:
6856 except error.RepoError:
6866 if opts.get('remote'):
6857 if opts.get('remote'):
6867 raise
6858 raise
6868 return dest, dbranch, None, None
6859 return dest, dbranch, None, None
6869 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6860 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6870 elif sother is None:
6861 elif sother is None:
6871 # there is no explicit destination peer, but source one is invalid
6862 # there is no explicit destination peer, but source one is invalid
6872 return dest, dbranch, None, None
6863 return dest, dbranch, None, None
6873 else:
6864 else:
6874 dother = sother
6865 dother = sother
6875 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6866 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6876 common = None
6867 common = None
6877 else:
6868 else:
6878 common = commoninc
6869 common = commoninc
6879 if revs:
6870 if revs:
6880 revs = [repo.lookup(rev) for rev in revs]
6871 revs = [repo.lookup(rev) for rev in revs]
6881 repo.ui.pushbuffer()
6872 repo.ui.pushbuffer()
6882 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6873 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6883 commoninc=common)
6874 commoninc=common)
6884 repo.ui.popbuffer()
6875 repo.ui.popbuffer()
6885 return dest, dbranch, dother, outgoing
6876 return dest, dbranch, dother, outgoing
6886
6877
6887 if needsoutgoing:
6878 if needsoutgoing:
6888 dest, dbranch, dother, outgoing = getoutgoing()
6879 dest, dbranch, dother, outgoing = getoutgoing()
6889 else:
6880 else:
6890 dest = dbranch = dother = outgoing = None
6881 dest = dbranch = dother = outgoing = None
6891
6882
6892 if opts.get('remote'):
6883 if opts.get('remote'):
6893 t = []
6884 t = []
6894 if incoming:
6885 if incoming:
6895 t.append(_('1 or more incoming'))
6886 t.append(_('1 or more incoming'))
6896 o = outgoing.missing
6887 o = outgoing.missing
6897 if o:
6888 if o:
6898 t.append(_('%d outgoing') % len(o))
6889 t.append(_('%d outgoing') % len(o))
6899 other = dother or sother
6890 other = dother or sother
6900 if 'bookmarks' in other.listkeys('namespaces'):
6891 if 'bookmarks' in other.listkeys('namespaces'):
6901 counts = bookmarks.summary(repo, other)
6892 counts = bookmarks.summary(repo, other)
6902 if counts[0] > 0:
6893 if counts[0] > 0:
6903 t.append(_('%d incoming bookmarks') % counts[0])
6894 t.append(_('%d incoming bookmarks') % counts[0])
6904 if counts[1] > 0:
6895 if counts[1] > 0:
6905 t.append(_('%d outgoing bookmarks') % counts[1])
6896 t.append(_('%d outgoing bookmarks') % counts[1])
6906
6897
6907 if t:
6898 if t:
6908 # i18n: column positioning for "hg summary"
6899 # i18n: column positioning for "hg summary"
6909 ui.write(_('remote: %s\n') % (', '.join(t)))
6900 ui.write(_('remote: %s\n') % (', '.join(t)))
6910 else:
6901 else:
6911 # i18n: column positioning for "hg summary"
6902 # i18n: column positioning for "hg summary"
6912 ui.status(_('remote: (synced)\n'))
6903 ui.status(_('remote: (synced)\n'))
6913
6904
6914 cmdutil.summaryremotehooks(ui, repo, opts,
6905 cmdutil.summaryremotehooks(ui, repo, opts,
6915 ((source, sbranch, sother, commoninc),
6906 ((source, sbranch, sother, commoninc),
6916 (dest, dbranch, dother, outgoing)))
6907 (dest, dbranch, dother, outgoing)))
6917
6908
6918 @command('tag',
6909 @command('tag',
6919 [('f', 'force', None, _('force tag')),
6910 [('f', 'force', None, _('force tag')),
6920 ('l', 'local', None, _('make the tag local')),
6911 ('l', 'local', None, _('make the tag local')),
6921 ('r', 'rev', '', _('revision to tag'), _('REV')),
6912 ('r', 'rev', '', _('revision to tag'), _('REV')),
6922 ('', 'remove', None, _('remove a tag')),
6913 ('', 'remove', None, _('remove a tag')),
6923 # -l/--local is already there, commitopts cannot be used
6914 # -l/--local is already there, commitopts cannot be used
6924 ('e', 'edit', None, _('invoke editor on commit messages')),
6915 ('e', 'edit', None, _('invoke editor on commit messages')),
6925 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6916 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6926 ] + commitopts2,
6917 ] + commitopts2,
6927 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6918 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6928 def tag(ui, repo, name1, *names, **opts):
6919 def tag(ui, repo, name1, *names, **opts):
6929 """add one or more tags for the current or given revision
6920 """add one or more tags for the current or given revision
6930
6921
6931 Name a particular revision using <name>.
6922 Name a particular revision using <name>.
6932
6923
6933 Tags are used to name particular revisions of the repository and are
6924 Tags are used to name particular revisions of the repository and are
6934 very useful to compare different revisions, to go back to significant
6925 very useful to compare different revisions, to go back to significant
6935 earlier versions or to mark branch points as releases, etc. Changing
6926 earlier versions or to mark branch points as releases, etc. Changing
6936 an existing tag is normally disallowed; use -f/--force to override.
6927 an existing tag is normally disallowed; use -f/--force to override.
6937
6928
6938 If no revision is given, the parent of the working directory is
6929 If no revision is given, the parent of the working directory is
6939 used.
6930 used.
6940
6931
6941 To facilitate version control, distribution, and merging of tags,
6932 To facilitate version control, distribution, and merging of tags,
6942 they are stored as a file named ".hgtags" which is managed similarly
6933 they are stored as a file named ".hgtags" which is managed similarly
6943 to other project files and can be hand-edited if necessary. This
6934 to other project files and can be hand-edited if necessary. This
6944 also means that tagging creates a new commit. The file
6935 also means that tagging creates a new commit. The file
6945 ".hg/localtags" is used for local tags (not shared among
6936 ".hg/localtags" is used for local tags (not shared among
6946 repositories).
6937 repositories).
6947
6938
6948 Tag commits are usually made at the head of a branch. If the parent
6939 Tag commits are usually made at the head of a branch. If the parent
6949 of the working directory is not a branch head, :hg:`tag` aborts; use
6940 of the working directory is not a branch head, :hg:`tag` aborts; use
6950 -f/--force to force the tag commit to be based on a non-head
6941 -f/--force to force the tag commit to be based on a non-head
6951 changeset.
6942 changeset.
6952
6943
6953 See :hg:`help dates` for a list of formats valid for -d/--date.
6944 See :hg:`help dates` for a list of formats valid for -d/--date.
6954
6945
6955 Since tag names have priority over branch names during revision
6946 Since tag names have priority over branch names during revision
6956 lookup, using an existing branch name as a tag name is discouraged.
6947 lookup, using an existing branch name as a tag name is discouraged.
6957
6948
6958 Returns 0 on success.
6949 Returns 0 on success.
6959 """
6950 """
6960 wlock = lock = None
6951 wlock = lock = None
6961 try:
6952 try:
6962 wlock = repo.wlock()
6953 wlock = repo.wlock()
6963 lock = repo.lock()
6954 lock = repo.lock()
6964 rev_ = "."
6955 rev_ = "."
6965 names = [t.strip() for t in (name1,) + names]
6956 names = [t.strip() for t in (name1,) + names]
6966 if len(names) != len(set(names)):
6957 if len(names) != len(set(names)):
6967 raise error.Abort(_('tag names must be unique'))
6958 raise error.Abort(_('tag names must be unique'))
6968 for n in names:
6959 for n in names:
6969 scmutil.checknewlabel(repo, n, 'tag')
6960 scmutil.checknewlabel(repo, n, 'tag')
6970 if not n:
6961 if not n:
6971 raise error.Abort(_('tag names cannot consist entirely of '
6962 raise error.Abort(_('tag names cannot consist entirely of '
6972 'whitespace'))
6963 'whitespace'))
6973 if opts.get('rev') and opts.get('remove'):
6964 if opts.get('rev') and opts.get('remove'):
6974 raise error.Abort(_("--rev and --remove are incompatible"))
6965 raise error.Abort(_("--rev and --remove are incompatible"))
6975 if opts.get('rev'):
6966 if opts.get('rev'):
6976 rev_ = opts['rev']
6967 rev_ = opts['rev']
6977 message = opts.get('message')
6968 message = opts.get('message')
6978 if opts.get('remove'):
6969 if opts.get('remove'):
6979 if opts.get('local'):
6970 if opts.get('local'):
6980 expectedtype = 'local'
6971 expectedtype = 'local'
6981 else:
6972 else:
6982 expectedtype = 'global'
6973 expectedtype = 'global'
6983
6974
6984 for n in names:
6975 for n in names:
6985 if not repo.tagtype(n):
6976 if not repo.tagtype(n):
6986 raise error.Abort(_("tag '%s' does not exist") % n)
6977 raise error.Abort(_("tag '%s' does not exist") % n)
6987 if repo.tagtype(n) != expectedtype:
6978 if repo.tagtype(n) != expectedtype:
6988 if expectedtype == 'global':
6979 if expectedtype == 'global':
6989 raise error.Abort(_("tag '%s' is not a global tag") % n)
6980 raise error.Abort(_("tag '%s' is not a global tag") % n)
6990 else:
6981 else:
6991 raise error.Abort(_("tag '%s' is not a local tag") % n)
6982 raise error.Abort(_("tag '%s' is not a local tag") % n)
6992 rev_ = 'null'
6983 rev_ = 'null'
6993 if not message:
6984 if not message:
6994 # we don't translate commit messages
6985 # we don't translate commit messages
6995 message = 'Removed tag %s' % ', '.join(names)
6986 message = 'Removed tag %s' % ', '.join(names)
6996 elif not opts.get('force'):
6987 elif not opts.get('force'):
6997 for n in names:
6988 for n in names:
6998 if n in repo.tags():
6989 if n in repo.tags():
6999 raise error.Abort(_("tag '%s' already exists "
6990 raise error.Abort(_("tag '%s' already exists "
7000 "(use -f to force)") % n)
6991 "(use -f to force)") % n)
7001 if not opts.get('local'):
6992 if not opts.get('local'):
7002 p1, p2 = repo.dirstate.parents()
6993 p1, p2 = repo.dirstate.parents()
7003 if p2 != nullid:
6994 if p2 != nullid:
7004 raise error.Abort(_('uncommitted merge'))
6995 raise error.Abort(_('uncommitted merge'))
7005 bheads = repo.branchheads()
6996 bheads = repo.branchheads()
7006 if not opts.get('force') and bheads and p1 not in bheads:
6997 if not opts.get('force') and bheads and p1 not in bheads:
7007 raise error.Abort(_('not at a branch head (use -f to force)'))
6998 raise error.Abort(_('not at a branch head (use -f to force)'))
7008 r = scmutil.revsingle(repo, rev_).node()
6999 r = scmutil.revsingle(repo, rev_).node()
7009
7000
7010 if not message:
7001 if not message:
7011 # we don't translate commit messages
7002 # we don't translate commit messages
7012 message = ('Added tag %s for changeset %s' %
7003 message = ('Added tag %s for changeset %s' %
7013 (', '.join(names), short(r)))
7004 (', '.join(names), short(r)))
7014
7005
7015 date = opts.get('date')
7006 date = opts.get('date')
7016 if date:
7007 if date:
7017 date = util.parsedate(date)
7008 date = util.parsedate(date)
7018
7009
7019 if opts.get('remove'):
7010 if opts.get('remove'):
7020 editform = 'tag.remove'
7011 editform = 'tag.remove'
7021 else:
7012 else:
7022 editform = 'tag.add'
7013 editform = 'tag.add'
7023 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7014 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7024
7015
7025 # don't allow tagging the null rev
7016 # don't allow tagging the null rev
7026 if (not opts.get('remove') and
7017 if (not opts.get('remove') and
7027 scmutil.revsingle(repo, rev_).rev() == nullrev):
7018 scmutil.revsingle(repo, rev_).rev() == nullrev):
7028 raise error.Abort(_("cannot tag null revision"))
7019 raise error.Abort(_("cannot tag null revision"))
7029
7020
7030 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7021 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7031 editor=editor)
7022 editor=editor)
7032 finally:
7023 finally:
7033 release(lock, wlock)
7024 release(lock, wlock)
7034
7025
7035 @command('tags', formatteropts, '')
7026 @command('tags', formatteropts, '')
7036 def tags(ui, repo, **opts):
7027 def tags(ui, repo, **opts):
7037 """list repository tags
7028 """list repository tags
7038
7029
7039 This lists both regular and local tags. When the -v/--verbose
7030 This lists both regular and local tags. When the -v/--verbose
7040 switch is used, a third column "local" is printed for local tags.
7031 switch is used, a third column "local" is printed for local tags.
7041 When the -q/--quiet switch is used, only the tag name is printed.
7032 When the -q/--quiet switch is used, only the tag name is printed.
7042
7033
7043 Returns 0 on success.
7034 Returns 0 on success.
7044 """
7035 """
7045
7036
7046 fm = ui.formatter('tags', opts)
7037 fm = ui.formatter('tags', opts)
7047 hexfunc = fm.hexfunc
7038 hexfunc = fm.hexfunc
7048 tagtype = ""
7039 tagtype = ""
7049
7040
7050 for t, n in reversed(repo.tagslist()):
7041 for t, n in reversed(repo.tagslist()):
7051 hn = hexfunc(n)
7042 hn = hexfunc(n)
7052 label = 'tags.normal'
7043 label = 'tags.normal'
7053 tagtype = ''
7044 tagtype = ''
7054 if repo.tagtype(t) == 'local':
7045 if repo.tagtype(t) == 'local':
7055 label = 'tags.local'
7046 label = 'tags.local'
7056 tagtype = 'local'
7047 tagtype = 'local'
7057
7048
7058 fm.startitem()
7049 fm.startitem()
7059 fm.write('tag', '%s', t, label=label)
7050 fm.write('tag', '%s', t, label=label)
7060 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7051 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7061 fm.condwrite(not ui.quiet, 'rev node', fmt,
7052 fm.condwrite(not ui.quiet, 'rev node', fmt,
7062 repo.changelog.rev(n), hn, label=label)
7053 repo.changelog.rev(n), hn, label=label)
7063 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7054 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7064 tagtype, label=label)
7055 tagtype, label=label)
7065 fm.plain('\n')
7056 fm.plain('\n')
7066 fm.end()
7057 fm.end()
7067
7058
7068 @command('tip',
7059 @command('tip',
7069 [('p', 'patch', None, _('show patch')),
7060 [('p', 'patch', None, _('show patch')),
7070 ('g', 'git', None, _('use git extended diff format')),
7061 ('g', 'git', None, _('use git extended diff format')),
7071 ] + templateopts,
7062 ] + templateopts,
7072 _('[-p] [-g]'))
7063 _('[-p] [-g]'))
7073 def tip(ui, repo, **opts):
7064 def tip(ui, repo, **opts):
7074 """show the tip revision (DEPRECATED)
7065 """show the tip revision (DEPRECATED)
7075
7066
7076 The tip revision (usually just called the tip) is the changeset
7067 The tip revision (usually just called the tip) is the changeset
7077 most recently added to the repository (and therefore the most
7068 most recently added to the repository (and therefore the most
7078 recently changed head).
7069 recently changed head).
7079
7070
7080 If you have just made a commit, that commit will be the tip. If
7071 If you have just made a commit, that commit will be the tip. If
7081 you have just pulled changes from another repository, the tip of
7072 you have just pulled changes from another repository, the tip of
7082 that repository becomes the current tip. The "tip" tag is special
7073 that repository becomes the current tip. The "tip" tag is special
7083 and cannot be renamed or assigned to a different changeset.
7074 and cannot be renamed or assigned to a different changeset.
7084
7075
7085 This command is deprecated, please use :hg:`heads` instead.
7076 This command is deprecated, please use :hg:`heads` instead.
7086
7077
7087 Returns 0 on success.
7078 Returns 0 on success.
7088 """
7079 """
7089 displayer = cmdutil.show_changeset(ui, repo, opts)
7080 displayer = cmdutil.show_changeset(ui, repo, opts)
7090 displayer.show(repo['tip'])
7081 displayer.show(repo['tip'])
7091 displayer.close()
7082 displayer.close()
7092
7083
7093 @command('unbundle',
7084 @command('unbundle',
7094 [('u', 'update', None,
7085 [('u', 'update', None,
7095 _('update to new branch head if changesets were unbundled'))],
7086 _('update to new branch head if changesets were unbundled'))],
7096 _('[-u] FILE...'))
7087 _('[-u] FILE...'))
7097 def unbundle(ui, repo, fname1, *fnames, **opts):
7088 def unbundle(ui, repo, fname1, *fnames, **opts):
7098 """apply one or more changegroup files
7089 """apply one or more changegroup files
7099
7090
7100 Apply one or more compressed changegroup files generated by the
7091 Apply one or more compressed changegroup files generated by the
7101 bundle command.
7092 bundle command.
7102
7093
7103 Returns 0 on success, 1 if an update has unresolved files.
7094 Returns 0 on success, 1 if an update has unresolved files.
7104 """
7095 """
7105 fnames = (fname1,) + fnames
7096 fnames = (fname1,) + fnames
7106
7097
7107 with repo.lock():
7098 with repo.lock():
7108 for fname in fnames:
7099 for fname in fnames:
7109 f = hg.openpath(ui, fname)
7100 f = hg.openpath(ui, fname)
7110 gen = exchange.readbundle(ui, f, fname)
7101 gen = exchange.readbundle(ui, f, fname)
7111 if isinstance(gen, bundle2.unbundle20):
7102 if isinstance(gen, bundle2.unbundle20):
7112 tr = repo.transaction('unbundle')
7103 tr = repo.transaction('unbundle')
7113 try:
7104 try:
7114 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7105 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7115 url='bundle:' + fname)
7106 url='bundle:' + fname)
7116 tr.close()
7107 tr.close()
7117 except error.BundleUnknownFeatureError as exc:
7108 except error.BundleUnknownFeatureError as exc:
7118 raise error.Abort(_('%s: unknown bundle feature, %s')
7109 raise error.Abort(_('%s: unknown bundle feature, %s')
7119 % (fname, exc),
7110 % (fname, exc),
7120 hint=_("see https://mercurial-scm.org/"
7111 hint=_("see https://mercurial-scm.org/"
7121 "wiki/BundleFeature for more "
7112 "wiki/BundleFeature for more "
7122 "information"))
7113 "information"))
7123 finally:
7114 finally:
7124 if tr:
7115 if tr:
7125 tr.release()
7116 tr.release()
7126 changes = [r.get('return', 0)
7117 changes = [r.get('return', 0)
7127 for r in op.records['changegroup']]
7118 for r in op.records['changegroup']]
7128 modheads = changegroup.combineresults(changes)
7119 modheads = changegroup.combineresults(changes)
7129 elif isinstance(gen, streamclone.streamcloneapplier):
7120 elif isinstance(gen, streamclone.streamcloneapplier):
7130 raise error.Abort(
7121 raise error.Abort(
7131 _('packed bundles cannot be applied with '
7122 _('packed bundles cannot be applied with '
7132 '"hg unbundle"'),
7123 '"hg unbundle"'),
7133 hint=_('use "hg debugapplystreamclonebundle"'))
7124 hint=_('use "hg debugapplystreamclonebundle"'))
7134 else:
7125 else:
7135 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7126 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7136
7127
7137 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7128 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7138
7129
7139 @command('^update|up|checkout|co',
7130 @command('^update|up|checkout|co',
7140 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7131 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7141 ('c', 'check', None, _('require clean working directory')),
7132 ('c', 'check', None, _('require clean working directory')),
7142 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7133 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7143 ('r', 'rev', '', _('revision'), _('REV'))
7134 ('r', 'rev', '', _('revision'), _('REV'))
7144 ] + mergetoolopts,
7135 ] + mergetoolopts,
7145 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7136 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7146 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7137 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7147 tool=None):
7138 tool=None):
7148 """update working directory (or switch revisions)
7139 """update working directory (or switch revisions)
7149
7140
7150 Update the repository's working directory to the specified
7141 Update the repository's working directory to the specified
7151 changeset. If no changeset is specified, update to the tip of the
7142 changeset. If no changeset is specified, update to the tip of the
7152 current named branch and move the active bookmark (see :hg:`help
7143 current named branch and move the active bookmark (see :hg:`help
7153 bookmarks`).
7144 bookmarks`).
7154
7145
7155 Update sets the working directory's parent revision to the specified
7146 Update sets the working directory's parent revision to the specified
7156 changeset (see :hg:`help parents`).
7147 changeset (see :hg:`help parents`).
7157
7148
7158 If the changeset is not a descendant or ancestor of the working
7149 If the changeset is not a descendant or ancestor of the working
7159 directory's parent, the update is aborted. With the -c/--check
7150 directory's parent, the update is aborted. With the -c/--check
7160 option, the working directory is checked for uncommitted changes; if
7151 option, the working directory is checked for uncommitted changes; if
7161 none are found, the working directory is updated to the specified
7152 none are found, the working directory is updated to the specified
7162 changeset.
7153 changeset.
7163
7154
7164 .. container:: verbose
7155 .. container:: verbose
7165
7156
7166 The following rules apply when the working directory contains
7157 The following rules apply when the working directory contains
7167 uncommitted changes:
7158 uncommitted changes:
7168
7159
7169 1. If neither -c/--check nor -C/--clean is specified, and if
7160 1. If neither -c/--check nor -C/--clean is specified, and if
7170 the requested changeset is an ancestor or descendant of
7161 the requested changeset is an ancestor or descendant of
7171 the working directory's parent, the uncommitted changes
7162 the working directory's parent, the uncommitted changes
7172 are merged into the requested changeset and the merged
7163 are merged into the requested changeset and the merged
7173 result is left uncommitted. If the requested changeset is
7164 result is left uncommitted. If the requested changeset is
7174 not an ancestor or descendant (that is, it is on another
7165 not an ancestor or descendant (that is, it is on another
7175 branch), the update is aborted and the uncommitted changes
7166 branch), the update is aborted and the uncommitted changes
7176 are preserved.
7167 are preserved.
7177
7168
7178 2. With the -c/--check option, the update is aborted and the
7169 2. With the -c/--check option, the update is aborted and the
7179 uncommitted changes are preserved.
7170 uncommitted changes are preserved.
7180
7171
7181 3. With the -C/--clean option, uncommitted changes are discarded and
7172 3. With the -C/--clean option, uncommitted changes are discarded and
7182 the working directory is updated to the requested changeset.
7173 the working directory is updated to the requested changeset.
7183
7174
7184 To cancel an uncommitted merge (and lose your changes), use
7175 To cancel an uncommitted merge (and lose your changes), use
7185 :hg:`update --clean .`.
7176 :hg:`update --clean .`.
7186
7177
7187 Use null as the changeset to remove the working directory (like
7178 Use null as the changeset to remove the working directory (like
7188 :hg:`clone -U`).
7179 :hg:`clone -U`).
7189
7180
7190 If you want to revert just one file to an older revision, use
7181 If you want to revert just one file to an older revision, use
7191 :hg:`revert [-r REV] NAME`.
7182 :hg:`revert [-r REV] NAME`.
7192
7183
7193 See :hg:`help dates` for a list of formats valid for -d/--date.
7184 See :hg:`help dates` for a list of formats valid for -d/--date.
7194
7185
7195 Returns 0 on success, 1 if there are unresolved files.
7186 Returns 0 on success, 1 if there are unresolved files.
7196 """
7187 """
7197 if rev and node:
7188 if rev and node:
7198 raise error.Abort(_("please specify just one revision"))
7189 raise error.Abort(_("please specify just one revision"))
7199
7190
7200 if rev is None or rev == '':
7191 if rev is None or rev == '':
7201 rev = node
7192 rev = node
7202
7193
7203 if date and rev is not None:
7194 if date and rev is not None:
7204 raise error.Abort(_("you can't specify a revision and a date"))
7195 raise error.Abort(_("you can't specify a revision and a date"))
7205
7196
7206 if check and clean:
7197 if check and clean:
7207 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7198 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7208
7199
7209 with repo.wlock():
7200 with repo.wlock():
7210 cmdutil.clearunfinished(repo)
7201 cmdutil.clearunfinished(repo)
7211
7202
7212 if date:
7203 if date:
7213 rev = cmdutil.finddate(ui, repo, date)
7204 rev = cmdutil.finddate(ui, repo, date)
7214
7205
7215 # if we defined a bookmark, we have to remember the original name
7206 # if we defined a bookmark, we have to remember the original name
7216 brev = rev
7207 brev = rev
7217 rev = scmutil.revsingle(repo, rev, rev).rev()
7208 rev = scmutil.revsingle(repo, rev, rev).rev()
7218
7209
7219 if check:
7210 if check:
7220 cmdutil.bailifchanged(repo, merge=False)
7211 cmdutil.bailifchanged(repo, merge=False)
7221
7212
7222 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7213 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7223
7214
7224 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7215 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7225
7216
7226 @command('verify', [])
7217 @command('verify', [])
7227 def verify(ui, repo):
7218 def verify(ui, repo):
7228 """verify the integrity of the repository
7219 """verify the integrity of the repository
7229
7220
7230 Verify the integrity of the current repository.
7221 Verify the integrity of the current repository.
7231
7222
7232 This will perform an extensive check of the repository's
7223 This will perform an extensive check of the repository's
7233 integrity, validating the hashes and checksums of each entry in
7224 integrity, validating the hashes and checksums of each entry in
7234 the changelog, manifest, and tracked files, as well as the
7225 the changelog, manifest, and tracked files, as well as the
7235 integrity of their crosslinks and indices.
7226 integrity of their crosslinks and indices.
7236
7227
7237 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7228 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7238 for more information about recovery from corruption of the
7229 for more information about recovery from corruption of the
7239 repository.
7230 repository.
7240
7231
7241 Returns 0 on success, 1 if errors are encountered.
7232 Returns 0 on success, 1 if errors are encountered.
7242 """
7233 """
7243 return hg.verify(repo)
7234 return hg.verify(repo)
7244
7235
7245 @command('version', [], norepo=True)
7236 @command('version', [], norepo=True)
7246 def version_(ui):
7237 def version_(ui):
7247 """output version and copyright information"""
7238 """output version and copyright information"""
7248 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7239 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7249 % util.version())
7240 % util.version())
7250 ui.status(_(
7241 ui.status(_(
7251 "(see https://mercurial-scm.org for more information)\n"
7242 "(see https://mercurial-scm.org for more information)\n"
7252 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7243 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7253 "This is free software; see the source for copying conditions. "
7244 "This is free software; see the source for copying conditions. "
7254 "There is NO\nwarranty; "
7245 "There is NO\nwarranty; "
7255 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7246 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7256 ))
7247 ))
7257
7248
7258 ui.note(_("\nEnabled extensions:\n\n"))
7249 ui.note(_("\nEnabled extensions:\n\n"))
7259 if ui.verbose:
7250 if ui.verbose:
7260 # format names and versions into columns
7251 # format names and versions into columns
7261 names = []
7252 names = []
7262 vers = []
7253 vers = []
7263 place = []
7254 place = []
7264 for name, module in extensions.extensions():
7255 for name, module in extensions.extensions():
7265 names.append(name)
7256 names.append(name)
7266 vers.append(extensions.moduleversion(module))
7257 vers.append(extensions.moduleversion(module))
7267 if extensions.ismoduleinternal(module):
7258 if extensions.ismoduleinternal(module):
7268 place.append(_("internal"))
7259 place.append(_("internal"))
7269 else:
7260 else:
7270 place.append(_("external"))
7261 place.append(_("external"))
7271 if names:
7262 if names:
7272 maxnamelen = max(len(n) for n in names)
7263 maxnamelen = max(len(n) for n in names)
7273 for i, name in enumerate(names):
7264 for i, name in enumerate(names):
7274 ui.write(" %-*s %s %s\n" %
7265 ui.write(" %-*s %s %s\n" %
7275 (maxnamelen, name, place[i], vers[i]))
7266 (maxnamelen, name, place[i], vers[i]))
7276
7267
7277 def loadcmdtable(ui, name, cmdtable):
7268 def loadcmdtable(ui, name, cmdtable):
7278 """Load command functions from specified cmdtable
7269 """Load command functions from specified cmdtable
7279 """
7270 """
7280 overrides = [cmd for cmd in cmdtable if cmd in table]
7271 overrides = [cmd for cmd in cmdtable if cmd in table]
7281 if overrides:
7272 if overrides:
7282 ui.warn(_("extension '%s' overrides commands: %s\n")
7273 ui.warn(_("extension '%s' overrides commands: %s\n")
7283 % (name, " ".join(overrides)))
7274 % (name, " ".join(overrides)))
7284 table.update(cmdtable)
7275 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now