##// END OF EJS Templates
debugextension: change "testedwith" to a list (BC)...
Yuya Nishihara -
r29703:3ef9aa7a default
parent child Browse files
Show More
@@ -1,7283 +1,7284 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 while True:
2106 chunkdata = gen.deltachunk(chain)
2106 chunkdata = gen.deltachunk(chain)
2107 if not chunkdata:
2107 if not chunkdata:
2108 break
2108 break
2109 node = chunkdata['node']
2109 node = chunkdata['node']
2110 p1 = chunkdata['p1']
2110 p1 = chunkdata['p1']
2111 p2 = chunkdata['p2']
2111 p2 = chunkdata['p2']
2112 cs = chunkdata['cs']
2112 cs = chunkdata['cs']
2113 deltabase = chunkdata['deltabase']
2113 deltabase = chunkdata['deltabase']
2114 delta = chunkdata['delta']
2114 delta = chunkdata['delta']
2115 ui.write("%s%s %s %s %s %s %s\n" %
2115 ui.write("%s%s %s %s %s %s %s\n" %
2116 (indent_string, hex(node), hex(p1), hex(p2),
2116 (indent_string, hex(node), hex(p1), hex(p2),
2117 hex(cs), hex(deltabase), len(delta)))
2117 hex(cs), hex(deltabase), len(delta)))
2118 chain = node
2118 chain = node
2119
2119
2120 chunkdata = gen.changelogheader()
2120 chunkdata = gen.changelogheader()
2121 showchunks("changelog")
2121 showchunks("changelog")
2122 chunkdata = gen.manifestheader()
2122 chunkdata = gen.manifestheader()
2123 showchunks("manifest")
2123 showchunks("manifest")
2124 while True:
2124 while True:
2125 chunkdata = gen.filelogheader()
2125 chunkdata = gen.filelogheader()
2126 if not chunkdata:
2126 if not chunkdata:
2127 break
2127 break
2128 fname = chunkdata['filename']
2128 fname = chunkdata['filename']
2129 showchunks(fname)
2129 showchunks(fname)
2130 else:
2130 else:
2131 if isinstance(gen, bundle2.unbundle20):
2131 if isinstance(gen, bundle2.unbundle20):
2132 raise error.Abort(_('use debugbundle2 for this file'))
2132 raise error.Abort(_('use debugbundle2 for this file'))
2133 chunkdata = gen.changelogheader()
2133 chunkdata = gen.changelogheader()
2134 chain = None
2134 chain = None
2135 while True:
2135 while True:
2136 chunkdata = gen.deltachunk(chain)
2136 chunkdata = gen.deltachunk(chain)
2137 if not chunkdata:
2137 if not chunkdata:
2138 break
2138 break
2139 node = chunkdata['node']
2139 node = chunkdata['node']
2140 ui.write("%s%s\n" % (indent_string, hex(node)))
2140 ui.write("%s%s\n" % (indent_string, hex(node)))
2141 chain = node
2141 chain = node
2142
2142
2143 def _debugbundle2(ui, gen, all=None, **opts):
2143 def _debugbundle2(ui, gen, all=None, **opts):
2144 """lists the contents of a bundle2"""
2144 """lists the contents of a bundle2"""
2145 if not isinstance(gen, bundle2.unbundle20):
2145 if not isinstance(gen, bundle2.unbundle20):
2146 raise error.Abort(_('not a bundle2 file'))
2146 raise error.Abort(_('not a bundle2 file'))
2147 ui.write(('Stream params: %s\n' % repr(gen.params)))
2147 ui.write(('Stream params: %s\n' % repr(gen.params)))
2148 for part in gen.iterparts():
2148 for part in gen.iterparts():
2149 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2149 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2150 if part.type == 'changegroup':
2150 if part.type == 'changegroup':
2151 version = part.params.get('version', '01')
2151 version = part.params.get('version', '01')
2152 cg = changegroup.getunbundler(version, part, 'UN')
2152 cg = changegroup.getunbundler(version, part, 'UN')
2153 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2153 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2154
2154
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2157 """create a stream clone bundle file
2157 """create a stream clone bundle file
2158
2158
2159 Stream bundles are special bundles that are essentially archives of
2159 Stream bundles are special bundles that are essentially archives of
2160 revlog files. They are commonly used for cloning very quickly.
2160 revlog files. They are commonly used for cloning very quickly.
2161 """
2161 """
2162 requirements, gen = streamclone.generatebundlev1(repo)
2162 requirements, gen = streamclone.generatebundlev1(repo)
2163 changegroup.writechunks(ui, gen, fname)
2163 changegroup.writechunks(ui, gen, fname)
2164
2164
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2166
2166
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2168 def debugapplystreamclonebundle(ui, repo, fname):
2168 def debugapplystreamclonebundle(ui, repo, fname):
2169 """apply a stream clone bundle file"""
2169 """apply a stream clone bundle file"""
2170 f = hg.openpath(ui, fname)
2170 f = hg.openpath(ui, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2172 gen.apply(repo)
2172 gen.apply(repo)
2173
2173
2174 @command('debugcheckstate', [], '')
2174 @command('debugcheckstate', [], '')
2175 def debugcheckstate(ui, repo):
2175 def debugcheckstate(ui, repo):
2176 """validate the correctness of the current dirstate"""
2176 """validate the correctness of the current dirstate"""
2177 parent1, parent2 = repo.dirstate.parents()
2177 parent1, parent2 = repo.dirstate.parents()
2178 m1 = repo[parent1].manifest()
2178 m1 = repo[parent1].manifest()
2179 m2 = repo[parent2].manifest()
2179 m2 = repo[parent2].manifest()
2180 errors = 0
2180 errors = 0
2181 for f in repo.dirstate:
2181 for f in repo.dirstate:
2182 state = repo.dirstate[f]
2182 state = repo.dirstate[f]
2183 if state in "nr" and f not in m1:
2183 if state in "nr" and f not in m1:
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "a" and f in m1:
2186 if state in "a" and f in m1:
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2188 errors += 1
2188 errors += 1
2189 if state in "m" and f not in m1 and f not in m2:
2189 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") %
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2191 (f, state))
2191 (f, state))
2192 errors += 1
2192 errors += 1
2193 for f in m1:
2193 for f in m1:
2194 state = repo.dirstate[f]
2194 state = repo.dirstate[f]
2195 if state not in "nrm":
2195 if state not in "nrm":
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2197 errors += 1
2197 errors += 1
2198 if errors:
2198 if errors:
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2200 raise error.Abort(error)
2200 raise error.Abort(error)
2201
2201
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2203 def debugcommands(ui, cmd='', *args):
2203 def debugcommands(ui, cmd='', *args):
2204 """list all available commands and options"""
2204 """list all available commands and options"""
2205 for cmd, vals in sorted(table.iteritems()):
2205 for cmd, vals in sorted(table.iteritems()):
2206 cmd = cmd.split('|')[0].strip('^')
2206 cmd = cmd.split('|')[0].strip('^')
2207 opts = ', '.join([i[1] for i in vals[1]])
2207 opts = ', '.join([i[1] for i in vals[1]])
2208 ui.write('%s: %s\n' % (cmd, opts))
2208 ui.write('%s: %s\n' % (cmd, opts))
2209
2209
2210 @command('debugcomplete',
2210 @command('debugcomplete',
2211 [('o', 'options', None, _('show the command options'))],
2211 [('o', 'options', None, _('show the command options'))],
2212 _('[-o] CMD'),
2212 _('[-o] CMD'),
2213 norepo=True)
2213 norepo=True)
2214 def debugcomplete(ui, cmd='', **opts):
2214 def debugcomplete(ui, cmd='', **opts):
2215 """returns the completion list associated with the given command"""
2215 """returns the completion list associated with the given command"""
2216
2216
2217 if opts.get('options'):
2217 if opts.get('options'):
2218 options = []
2218 options = []
2219 otables = [globalopts]
2219 otables = [globalopts]
2220 if cmd:
2220 if cmd:
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2222 otables.append(entry[1])
2222 otables.append(entry[1])
2223 for t in otables:
2223 for t in otables:
2224 for o in t:
2224 for o in t:
2225 if "(DEPRECATED)" in o[3]:
2225 if "(DEPRECATED)" in o[3]:
2226 continue
2226 continue
2227 if o[0]:
2227 if o[0]:
2228 options.append('-%s' % o[0])
2228 options.append('-%s' % o[0])
2229 options.append('--%s' % o[1])
2229 options.append('--%s' % o[1])
2230 ui.write("%s\n" % "\n".join(options))
2230 ui.write("%s\n" % "\n".join(options))
2231 return
2231 return
2232
2232
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2234 if ui.verbose:
2234 if ui.verbose:
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2237
2237
2238 @command('debugdag',
2238 @command('debugdag',
2239 [('t', 'tags', None, _('use tags as labels')),
2239 [('t', 'tags', None, _('use tags as labels')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2241 ('', 'dots', None, _('use dots for runs')),
2241 ('', 'dots', None, _('use dots for runs')),
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2243 _('[OPTION]... [FILE [REV]...]'),
2243 _('[OPTION]... [FILE [REV]...]'),
2244 optionalrepo=True)
2244 optionalrepo=True)
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2246 """format the changelog or an index DAG as a concise textual description
2246 """format the changelog or an index DAG as a concise textual description
2247
2247
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2248 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.
2249 revision numbers, they get labeled in the output as rN.
2250
2250
2251 Otherwise, the changelog DAG of the current repo is emitted.
2251 Otherwise, the changelog DAG of the current repo is emitted.
2252 """
2252 """
2253 spaces = opts.get('spaces')
2253 spaces = opts.get('spaces')
2254 dots = opts.get('dots')
2254 dots = opts.get('dots')
2255 if file_:
2255 if file_:
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2257 revs = set((int(r) for r in revs))
2257 revs = set((int(r) for r in revs))
2258 def events():
2258 def events():
2259 for r in rlog:
2259 for r in rlog:
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2261 if p != -1))
2261 if p != -1))
2262 if r in revs:
2262 if r in revs:
2263 yield 'l', (r, "r%i" % r)
2263 yield 'l', (r, "r%i" % r)
2264 elif repo:
2264 elif repo:
2265 cl = repo.changelog
2265 cl = repo.changelog
2266 tags = opts.get('tags')
2266 tags = opts.get('tags')
2267 branches = opts.get('branches')
2267 branches = opts.get('branches')
2268 if tags:
2268 if tags:
2269 labels = {}
2269 labels = {}
2270 for l, n in repo.tags().items():
2270 for l, n in repo.tags().items():
2271 labels.setdefault(cl.rev(n), []).append(l)
2271 labels.setdefault(cl.rev(n), []).append(l)
2272 def events():
2272 def events():
2273 b = "default"
2273 b = "default"
2274 for r in cl:
2274 for r in cl:
2275 if branches:
2275 if branches:
2276 newb = cl.read(cl.node(r))[5]['branch']
2276 newb = cl.read(cl.node(r))[5]['branch']
2277 if newb != b:
2277 if newb != b:
2278 yield 'a', newb
2278 yield 'a', newb
2279 b = newb
2279 b = newb
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2281 if p != -1))
2281 if p != -1))
2282 if tags:
2282 if tags:
2283 ls = labels.get(r)
2283 ls = labels.get(r)
2284 if ls:
2284 if ls:
2285 for l in ls:
2285 for l in ls:
2286 yield 'l', (r, l)
2286 yield 'l', (r, l)
2287 else:
2287 else:
2288 raise error.Abort(_('need repo for changelog dag'))
2288 raise error.Abort(_('need repo for changelog dag'))
2289
2289
2290 for line in dagparser.dagtextlines(events(),
2290 for line in dagparser.dagtextlines(events(),
2291 addspaces=spaces,
2291 addspaces=spaces,
2292 wraplabels=True,
2292 wraplabels=True,
2293 wrapannotations=True,
2293 wrapannotations=True,
2294 wrapnonlinear=dots,
2294 wrapnonlinear=dots,
2295 usedots=dots,
2295 usedots=dots,
2296 maxlinewidth=70):
2296 maxlinewidth=70):
2297 ui.write(line)
2297 ui.write(line)
2298 ui.write("\n")
2298 ui.write("\n")
2299
2299
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2302 """dump the contents of a data file revision"""
2302 """dump the contents of a data file revision"""
2303 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2303 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2304 if rev is not None:
2304 if rev is not None:
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2306 file_, rev = None, file_
2306 file_, rev = None, file_
2307 elif rev is None:
2307 elif rev is None:
2308 raise error.CommandError('debugdata', _('invalid arguments'))
2308 raise error.CommandError('debugdata', _('invalid arguments'))
2309 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2309 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2310 try:
2310 try:
2311 ui.write(r.revision(r.lookup(rev)))
2311 ui.write(r.revision(r.lookup(rev)))
2312 except KeyError:
2312 except KeyError:
2313 raise error.Abort(_('invalid revision identifier %s') % rev)
2313 raise error.Abort(_('invalid revision identifier %s') % rev)
2314
2314
2315 @command('debugdate',
2315 @command('debugdate',
2316 [('e', 'extended', None, _('try extended date formats'))],
2316 [('e', 'extended', None, _('try extended date formats'))],
2317 _('[-e] DATE [RANGE]'),
2317 _('[-e] DATE [RANGE]'),
2318 norepo=True, optionalrepo=True)
2318 norepo=True, optionalrepo=True)
2319 def debugdate(ui, date, range=None, **opts):
2319 def debugdate(ui, date, range=None, **opts):
2320 """parse and display a date"""
2320 """parse and display a date"""
2321 if opts["extended"]:
2321 if opts["extended"]:
2322 d = util.parsedate(date, util.extendeddateformats)
2322 d = util.parsedate(date, util.extendeddateformats)
2323 else:
2323 else:
2324 d = util.parsedate(date)
2324 d = util.parsedate(date)
2325 ui.write(("internal: %s %s\n") % d)
2325 ui.write(("internal: %s %s\n") % d)
2326 ui.write(("standard: %s\n") % util.datestr(d))
2326 ui.write(("standard: %s\n") % util.datestr(d))
2327 if range:
2327 if range:
2328 m = util.matchdate(range)
2328 m = util.matchdate(range)
2329 ui.write(("match: %s\n") % m(d[0]))
2329 ui.write(("match: %s\n") % m(d[0]))
2330
2330
2331 @command('debugdiscovery',
2331 @command('debugdiscovery',
2332 [('', 'old', None, _('use old-style discovery')),
2332 [('', 'old', None, _('use old-style discovery')),
2333 ('', 'nonheads', None,
2333 ('', 'nonheads', None,
2334 _('use old-style discovery with non-heads included')),
2334 _('use old-style discovery with non-heads included')),
2335 ] + remoteopts,
2335 ] + remoteopts,
2336 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2336 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2337 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2337 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2338 """runs the changeset discovery protocol in isolation"""
2338 """runs the changeset discovery protocol in isolation"""
2339 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2339 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2340 opts.get('branch'))
2340 opts.get('branch'))
2341 remote = hg.peer(repo, opts, remoteurl)
2341 remote = hg.peer(repo, opts, remoteurl)
2342 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2342 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2343
2343
2344 # make sure tests are repeatable
2344 # make sure tests are repeatable
2345 random.seed(12323)
2345 random.seed(12323)
2346
2346
2347 def doit(localheads, remoteheads, remote=remote):
2347 def doit(localheads, remoteheads, remote=remote):
2348 if opts.get('old'):
2348 if opts.get('old'):
2349 if localheads:
2349 if localheads:
2350 raise error.Abort('cannot use localheads with old style '
2350 raise error.Abort('cannot use localheads with old style '
2351 'discovery')
2351 'discovery')
2352 if not util.safehasattr(remote, 'branches'):
2352 if not util.safehasattr(remote, 'branches'):
2353 # enable in-client legacy support
2353 # enable in-client legacy support
2354 remote = localrepo.locallegacypeer(remote.local())
2354 remote = localrepo.locallegacypeer(remote.local())
2355 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2355 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2356 force=True)
2356 force=True)
2357 common = set(common)
2357 common = set(common)
2358 if not opts.get('nonheads'):
2358 if not opts.get('nonheads'):
2359 ui.write(("unpruned common: %s\n") %
2359 ui.write(("unpruned common: %s\n") %
2360 " ".join(sorted(short(n) for n in common)))
2360 " ".join(sorted(short(n) for n in common)))
2361 dag = dagutil.revlogdag(repo.changelog)
2361 dag = dagutil.revlogdag(repo.changelog)
2362 all = dag.ancestorset(dag.internalizeall(common))
2362 all = dag.ancestorset(dag.internalizeall(common))
2363 common = dag.externalizeall(dag.headsetofconnecteds(all))
2363 common = dag.externalizeall(dag.headsetofconnecteds(all))
2364 else:
2364 else:
2365 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2365 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2366 common = set(common)
2366 common = set(common)
2367 rheads = set(hds)
2367 rheads = set(hds)
2368 lheads = set(repo.heads())
2368 lheads = set(repo.heads())
2369 ui.write(("common heads: %s\n") %
2369 ui.write(("common heads: %s\n") %
2370 " ".join(sorted(short(n) for n in common)))
2370 " ".join(sorted(short(n) for n in common)))
2371 if lheads <= common:
2371 if lheads <= common:
2372 ui.write(("local is subset\n"))
2372 ui.write(("local is subset\n"))
2373 elif rheads <= common:
2373 elif rheads <= common:
2374 ui.write(("remote is subset\n"))
2374 ui.write(("remote is subset\n"))
2375
2375
2376 serverlogs = opts.get('serverlog')
2376 serverlogs = opts.get('serverlog')
2377 if serverlogs:
2377 if serverlogs:
2378 for filename in serverlogs:
2378 for filename in serverlogs:
2379 with open(filename, 'r') as logfile:
2379 with open(filename, 'r') as logfile:
2380 line = logfile.readline()
2380 line = logfile.readline()
2381 while line:
2381 while line:
2382 parts = line.strip().split(';')
2382 parts = line.strip().split(';')
2383 op = parts[1]
2383 op = parts[1]
2384 if op == 'cg':
2384 if op == 'cg':
2385 pass
2385 pass
2386 elif op == 'cgss':
2386 elif op == 'cgss':
2387 doit(parts[2].split(' '), parts[3].split(' '))
2387 doit(parts[2].split(' '), parts[3].split(' '))
2388 elif op == 'unb':
2388 elif op == 'unb':
2389 doit(parts[3].split(' '), parts[2].split(' '))
2389 doit(parts[3].split(' '), parts[2].split(' '))
2390 line = logfile.readline()
2390 line = logfile.readline()
2391 else:
2391 else:
2392 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2392 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2393 opts.get('remote_head'))
2393 opts.get('remote_head'))
2394 localrevs = opts.get('local_head')
2394 localrevs = opts.get('local_head')
2395 doit(localrevs, remoterevs)
2395 doit(localrevs, remoterevs)
2396
2396
2397 @command('debugextensions', formatteropts, [], norepo=True)
2397 @command('debugextensions', formatteropts, [], norepo=True)
2398 def debugextensions(ui, **opts):
2398 def debugextensions(ui, **opts):
2399 '''show information about active extensions'''
2399 '''show information about active extensions'''
2400 exts = extensions.extensions(ui)
2400 exts = extensions.extensions(ui)
2401 hgver = util.version()
2401 hgver = util.version()
2402 fm = ui.formatter('debugextensions', opts)
2402 fm = ui.formatter('debugextensions', opts)
2403 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2403 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2404 extsource = extmod.__file__
2404 extsource = extmod.__file__
2405 exttestedwith = getattr(extmod, 'testedwith', '').split()
2405 exttestedwith = getattr(extmod, 'testedwith', '').split()
2406 extbuglink = getattr(extmod, 'buglink', None)
2406 extbuglink = getattr(extmod, 'buglink', None)
2407
2407
2408 fm.startitem()
2408 fm.startitem()
2409
2409
2410 if ui.quiet or ui.verbose:
2410 if ui.quiet or ui.verbose:
2411 fm.write('name', '%s\n', extname)
2411 fm.write('name', '%s\n', extname)
2412 else:
2412 else:
2413 fm.write('name', '%s', extname)
2413 fm.write('name', '%s', extname)
2414 if not exttestedwith:
2414 if not exttestedwith:
2415 fm.plain(_(' (untested!)\n'))
2415 fm.plain(_(' (untested!)\n'))
2416 elif exttestedwith == ['internal'] or hgver in exttestedwith:
2416 elif exttestedwith == ['internal'] or hgver in exttestedwith:
2417 fm.plain('\n')
2417 fm.plain('\n')
2418 else:
2418 else:
2419 lasttestedversion = exttestedwith[-1]
2419 lasttestedversion = exttestedwith[-1]
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2421
2421
2422 fm.condwrite(ui.verbose and extsource, 'source',
2422 fm.condwrite(ui.verbose and extsource, 'source',
2423 _(' location: %s\n'), extsource or "")
2423 _(' location: %s\n'), extsource or "")
2424
2424
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 _(' tested with: %s\n'), ' '.join(exttestedwith))
2426 _(' tested with: %s\n'),
2427 fm.formatlist(exttestedwith, name='ver'))
2427
2428
2428 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 _(' bug reporting: %s\n'), extbuglink or "")
2430 _(' bug reporting: %s\n'), extbuglink or "")
2430
2431
2431 fm.end()
2432 fm.end()
2432
2433
2433 @command('debugfileset',
2434 @command('debugfileset',
2434 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 _('[-r REV] FILESPEC'))
2436 _('[-r REV] FILESPEC'))
2436 def debugfileset(ui, repo, expr, **opts):
2437 def debugfileset(ui, repo, expr, **opts):
2437 '''parse and apply a fileset specification'''
2438 '''parse and apply a fileset specification'''
2438 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 if ui.verbose:
2440 if ui.verbose:
2440 tree = fileset.parse(expr)
2441 tree = fileset.parse(expr)
2441 ui.note(fileset.prettyformat(tree), "\n")
2442 ui.note(fileset.prettyformat(tree), "\n")
2442
2443
2443 for f in ctx.getfileset(expr):
2444 for f in ctx.getfileset(expr):
2444 ui.write("%s\n" % f)
2445 ui.write("%s\n" % f)
2445
2446
2446 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 def debugfsinfo(ui, path="."):
2448 def debugfsinfo(ui, path="."):
2448 """show information detected about current filesystem"""
2449 """show information detected about current filesystem"""
2449 util.writefile('.debugfsinfo', '')
2450 util.writefile('.debugfsinfo', '')
2450 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2451 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2452 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2453 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 and 'yes' or 'no'))
2455 and 'yes' or 'no'))
2455 os.unlink('.debugfsinfo')
2456 os.unlink('.debugfsinfo')
2456
2457
2457 @command('debuggetbundle',
2458 @command('debuggetbundle',
2458 [('H', 'head', [], _('id of head node'), _('ID')),
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2459 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 _('REPO FILE [-H|-C ID]...'),
2462 _('REPO FILE [-H|-C ID]...'),
2462 norepo=True)
2463 norepo=True)
2463 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 """retrieves a bundle from a repo
2465 """retrieves a bundle from a repo
2465
2466
2466 Every ID must be a full-length hex node id string. Saves the bundle to the
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2467 given file.
2468 given file.
2468 """
2469 """
2469 repo = hg.peer(ui, opts, repopath)
2470 repo = hg.peer(ui, opts, repopath)
2470 if not repo.capable('getbundle'):
2471 if not repo.capable('getbundle'):
2471 raise error.Abort("getbundle() not supported by target repository")
2472 raise error.Abort("getbundle() not supported by target repository")
2472 args = {}
2473 args = {}
2473 if common:
2474 if common:
2474 args['common'] = [bin(s) for s in common]
2475 args['common'] = [bin(s) for s in common]
2475 if head:
2476 if head:
2476 args['heads'] = [bin(s) for s in head]
2477 args['heads'] = [bin(s) for s in head]
2477 # TODO: get desired bundlecaps from command line.
2478 # TODO: get desired bundlecaps from command line.
2478 args['bundlecaps'] = None
2479 args['bundlecaps'] = None
2479 bundle = repo.getbundle('debug', **args)
2480 bundle = repo.getbundle('debug', **args)
2480
2481
2481 bundletype = opts.get('type', 'bzip2').lower()
2482 bundletype = opts.get('type', 'bzip2').lower()
2482 btypes = {'none': 'HG10UN',
2483 btypes = {'none': 'HG10UN',
2483 'bzip2': 'HG10BZ',
2484 'bzip2': 'HG10BZ',
2484 'gzip': 'HG10GZ',
2485 'gzip': 'HG10GZ',
2485 'bundle2': 'HG20'}
2486 'bundle2': 'HG20'}
2486 bundletype = btypes.get(bundletype)
2487 bundletype = btypes.get(bundletype)
2487 if bundletype not in bundle2.bundletypes:
2488 if bundletype not in bundle2.bundletypes:
2488 raise error.Abort(_('unknown bundle type specified with --type'))
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2489 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490
2491
2491 @command('debugignore', [], '[FILE]')
2492 @command('debugignore', [], '[FILE]')
2492 def debugignore(ui, repo, *files, **opts):
2493 def debugignore(ui, repo, *files, **opts):
2493 """display the combined ignore pattern and information about ignored files
2494 """display the combined ignore pattern and information about ignored files
2494
2495
2495 With no argument display the combined ignore pattern.
2496 With no argument display the combined ignore pattern.
2496
2497
2497 Given space separated file names, shows if the given file is ignored and
2498 Given space separated file names, shows if the given file is ignored and
2498 if so, show the ignore rule (file and line number) that matched it.
2499 if so, show the ignore rule (file and line number) that matched it.
2499 """
2500 """
2500 ignore = repo.dirstate._ignore
2501 ignore = repo.dirstate._ignore
2501 if not files:
2502 if not files:
2502 # Show all the patterns
2503 # Show all the patterns
2503 includepat = getattr(ignore, 'includepat', None)
2504 includepat = getattr(ignore, 'includepat', None)
2504 if includepat is not None:
2505 if includepat is not None:
2505 ui.write("%s\n" % includepat)
2506 ui.write("%s\n" % includepat)
2506 else:
2507 else:
2507 raise error.Abort(_("no ignore patterns found"))
2508 raise error.Abort(_("no ignore patterns found"))
2508 else:
2509 else:
2509 for f in files:
2510 for f in files:
2510 nf = util.normpath(f)
2511 nf = util.normpath(f)
2511 ignored = None
2512 ignored = None
2512 ignoredata = None
2513 ignoredata = None
2513 if nf != '.':
2514 if nf != '.':
2514 if ignore(nf):
2515 if ignore(nf):
2515 ignored = nf
2516 ignored = nf
2516 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 else:
2518 else:
2518 for p in util.finddirs(nf):
2519 for p in util.finddirs(nf):
2519 if ignore(p):
2520 if ignore(p):
2520 ignored = p
2521 ignored = p
2521 ignoredata = repo.dirstate._ignorefileandline(p)
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2522 break
2523 break
2523 if ignored:
2524 if ignored:
2524 if ignored == nf:
2525 if ignored == nf:
2525 ui.write(_("%s is ignored\n") % f)
2526 ui.write(_("%s is ignored\n") % f)
2526 else:
2527 else:
2527 ui.write(_("%s is ignored because of "
2528 ui.write(_("%s is ignored because of "
2528 "containing folder %s\n")
2529 "containing folder %s\n")
2529 % (f, ignored))
2530 % (f, ignored))
2530 ignorefile, lineno, line = ignoredata
2531 ignorefile, lineno, line = ignoredata
2531 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2532 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2532 % (ignorefile, lineno, line))
2533 % (ignorefile, lineno, line))
2533 else:
2534 else:
2534 ui.write(_("%s is not ignored\n") % f)
2535 ui.write(_("%s is not ignored\n") % f)
2535
2536
2536 @command('debugindex', debugrevlogopts +
2537 @command('debugindex', debugrevlogopts +
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2538 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2538 _('[-f FORMAT] -c|-m|FILE'),
2539 _('[-f FORMAT] -c|-m|FILE'),
2539 optionalrepo=True)
2540 optionalrepo=True)
2540 def debugindex(ui, repo, file_=None, **opts):
2541 def debugindex(ui, repo, file_=None, **opts):
2541 """dump the contents of an index file"""
2542 """dump the contents of an index file"""
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2543 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2543 format = opts.get('format', 0)
2544 format = opts.get('format', 0)
2544 if format not in (0, 1):
2545 if format not in (0, 1):
2545 raise error.Abort(_("unknown format %d") % format)
2546 raise error.Abort(_("unknown format %d") % format)
2546
2547
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 if generaldelta:
2549 if generaldelta:
2549 basehdr = ' delta'
2550 basehdr = ' delta'
2550 else:
2551 else:
2551 basehdr = ' base'
2552 basehdr = ' base'
2552
2553
2553 if ui.debugflag:
2554 if ui.debugflag:
2554 shortfn = hex
2555 shortfn = hex
2555 else:
2556 else:
2556 shortfn = short
2557 shortfn = short
2557
2558
2558 # There might not be anything in r, so have a sane default
2559 # There might not be anything in r, so have a sane default
2559 idlen = 12
2560 idlen = 12
2560 for i in r:
2561 for i in r:
2561 idlen = len(shortfn(r.node(i)))
2562 idlen = len(shortfn(r.node(i)))
2562 break
2563 break
2563
2564
2564 if format == 0:
2565 if format == 0:
2565 ui.write((" rev offset length " + basehdr + " linkrev"
2566 ui.write((" rev offset length " + basehdr + " linkrev"
2566 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2567 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2567 elif format == 1:
2568 elif format == 1:
2568 ui.write((" rev flag offset length"
2569 ui.write((" rev flag offset length"
2569 " size " + basehdr + " link p1 p2"
2570 " size " + basehdr + " link p1 p2"
2570 " %s\n") % "nodeid".rjust(idlen))
2571 " %s\n") % "nodeid".rjust(idlen))
2571
2572
2572 for i in r:
2573 for i in r:
2573 node = r.node(i)
2574 node = r.node(i)
2574 if generaldelta:
2575 if generaldelta:
2575 base = r.deltaparent(i)
2576 base = r.deltaparent(i)
2576 else:
2577 else:
2577 base = r.chainbase(i)
2578 base = r.chainbase(i)
2578 if format == 0:
2579 if format == 0:
2579 try:
2580 try:
2580 pp = r.parents(node)
2581 pp = r.parents(node)
2581 except Exception:
2582 except Exception:
2582 pp = [nullid, nullid]
2583 pp = [nullid, nullid]
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2584 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2585 i, r.start(i), r.length(i), base, r.linkrev(i),
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2586 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2586 elif format == 1:
2587 elif format == 1:
2587 pr = r.parentrevs(i)
2588 pr = r.parentrevs(i)
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2589 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2590 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2591 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2591
2592
2592 @command('debugindexdot', debugrevlogopts,
2593 @command('debugindexdot', debugrevlogopts,
2593 _('-c|-m|FILE'), optionalrepo=True)
2594 _('-c|-m|FILE'), optionalrepo=True)
2594 def debugindexdot(ui, repo, file_=None, **opts):
2595 def debugindexdot(ui, repo, file_=None, **opts):
2595 """dump an index DAG as a graphviz dot file"""
2596 """dump an index DAG as a graphviz dot file"""
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2597 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2597 ui.write(("digraph G {\n"))
2598 ui.write(("digraph G {\n"))
2598 for i in r:
2599 for i in r:
2599 node = r.node(i)
2600 node = r.node(i)
2600 pp = r.parents(node)
2601 pp = r.parents(node)
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2602 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2602 if pp[1] != nullid:
2603 if pp[1] != nullid:
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2604 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2604 ui.write("}\n")
2605 ui.write("}\n")
2605
2606
2606 @command('debugdeltachain',
2607 @command('debugdeltachain',
2607 debugrevlogopts + formatteropts,
2608 debugrevlogopts + formatteropts,
2608 _('-c|-m|FILE'),
2609 _('-c|-m|FILE'),
2609 optionalrepo=True)
2610 optionalrepo=True)
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2611 def debugdeltachain(ui, repo, file_=None, **opts):
2611 """dump information about delta chains in a revlog
2612 """dump information about delta chains in a revlog
2612
2613
2613 Output can be templatized. Available template keywords are:
2614 Output can be templatized. Available template keywords are:
2614
2615
2615 :``rev``: revision number
2616 :``rev``: revision number
2616 :``chainid``: delta chain identifier (numbered by unique base)
2617 :``chainid``: delta chain identifier (numbered by unique base)
2617 :``chainlen``: delta chain length to this revision
2618 :``chainlen``: delta chain length to this revision
2618 :``prevrev``: previous revision in delta chain
2619 :``prevrev``: previous revision in delta chain
2619 :``deltatype``: role of delta / how it was computed
2620 :``deltatype``: role of delta / how it was computed
2620 :``compsize``: compressed size of revision
2621 :``compsize``: compressed size of revision
2621 :``uncompsize``: uncompressed size of revision
2622 :``uncompsize``: uncompressed size of revision
2622 :``chainsize``: total size of compressed revisions in chain
2623 :``chainsize``: total size of compressed revisions in chain
2623 :``chainratio``: total chain size divided by uncompressed revision size
2624 :``chainratio``: total chain size divided by uncompressed revision size
2624 (new delta chains typically start at ratio 2.00)
2625 (new delta chains typically start at ratio 2.00)
2625 :``lindist``: linear distance from base revision in delta chain to end
2626 :``lindist``: linear distance from base revision in delta chain to end
2626 of this revision
2627 of this revision
2627 :``extradist``: total size of revisions not part of this delta chain from
2628 :``extradist``: total size of revisions not part of this delta chain from
2628 base of delta chain to end of this revision; a measurement
2629 base of delta chain to end of this revision; a measurement
2629 of how much extra data we need to read/seek across to read
2630 of how much extra data we need to read/seek across to read
2630 the delta chain for this revision
2631 the delta chain for this revision
2631 :``extraratio``: extradist divided by chainsize; another representation of
2632 :``extraratio``: extradist divided by chainsize; another representation of
2632 how much unrelated data is needed to load this delta chain
2633 how much unrelated data is needed to load this delta chain
2633 """
2634 """
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2635 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2635 index = r.index
2636 index = r.index
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2637 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2637
2638
2638 def revinfo(rev):
2639 def revinfo(rev):
2639 e = index[rev]
2640 e = index[rev]
2640 compsize = e[1]
2641 compsize = e[1]
2641 uncompsize = e[2]
2642 uncompsize = e[2]
2642 chainsize = 0
2643 chainsize = 0
2643
2644
2644 if generaldelta:
2645 if generaldelta:
2645 if e[3] == e[5]:
2646 if e[3] == e[5]:
2646 deltatype = 'p1'
2647 deltatype = 'p1'
2647 elif e[3] == e[6]:
2648 elif e[3] == e[6]:
2648 deltatype = 'p2'
2649 deltatype = 'p2'
2649 elif e[3] == rev - 1:
2650 elif e[3] == rev - 1:
2650 deltatype = 'prev'
2651 deltatype = 'prev'
2651 elif e[3] == rev:
2652 elif e[3] == rev:
2652 deltatype = 'base'
2653 deltatype = 'base'
2653 else:
2654 else:
2654 deltatype = 'other'
2655 deltatype = 'other'
2655 else:
2656 else:
2656 if e[3] == rev:
2657 if e[3] == rev:
2657 deltatype = 'base'
2658 deltatype = 'base'
2658 else:
2659 else:
2659 deltatype = 'prev'
2660 deltatype = 'prev'
2660
2661
2661 chain = r._deltachain(rev)[0]
2662 chain = r._deltachain(rev)[0]
2662 for iterrev in chain:
2663 for iterrev in chain:
2663 e = index[iterrev]
2664 e = index[iterrev]
2664 chainsize += e[1]
2665 chainsize += e[1]
2665
2666
2666 return compsize, uncompsize, deltatype, chain, chainsize
2667 return compsize, uncompsize, deltatype, chain, chainsize
2667
2668
2668 fm = ui.formatter('debugdeltachain', opts)
2669 fm = ui.formatter('debugdeltachain', opts)
2669
2670
2670 fm.plain(' rev chain# chainlen prev delta '
2671 fm.plain(' rev chain# chainlen prev delta '
2671 'size rawsize chainsize ratio lindist extradist '
2672 'size rawsize chainsize ratio lindist extradist '
2672 'extraratio\n')
2673 'extraratio\n')
2673
2674
2674 chainbases = {}
2675 chainbases = {}
2675 for rev in r:
2676 for rev in r:
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2677 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2677 chainbase = chain[0]
2678 chainbase = chain[0]
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2679 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2679 basestart = r.start(chainbase)
2680 basestart = r.start(chainbase)
2680 revstart = r.start(rev)
2681 revstart = r.start(rev)
2681 lineardist = revstart + comp - basestart
2682 lineardist = revstart + comp - basestart
2682 extradist = lineardist - chainsize
2683 extradist = lineardist - chainsize
2683 try:
2684 try:
2684 prevrev = chain[-2]
2685 prevrev = chain[-2]
2685 except IndexError:
2686 except IndexError:
2686 prevrev = -1
2687 prevrev = -1
2687
2688
2688 chainratio = float(chainsize) / float(uncomp)
2689 chainratio = float(chainsize) / float(uncomp)
2689 extraratio = float(extradist) / float(chainsize)
2690 extraratio = float(extradist) / float(chainsize)
2690
2691
2691 fm.startitem()
2692 fm.startitem()
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2693 fm.write('rev chainid chainlen prevrev deltatype compsize '
2693 'uncompsize chainsize chainratio lindist extradist '
2694 'uncompsize chainsize chainratio lindist extradist '
2694 'extraratio',
2695 'extraratio',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2696 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2697 rev, chainid, len(chain), prevrev, deltatype, comp,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2698 uncomp, chainsize, chainratio, lineardist, extradist,
2698 extraratio,
2699 extraratio,
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2700 rev=rev, chainid=chainid, chainlen=len(chain),
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2701 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2701 uncompsize=uncomp, chainsize=chainsize,
2702 uncompsize=uncomp, chainsize=chainsize,
2702 chainratio=chainratio, lindist=lineardist,
2703 chainratio=chainratio, lindist=lineardist,
2703 extradist=extradist, extraratio=extraratio)
2704 extradist=extradist, extraratio=extraratio)
2704
2705
2705 fm.end()
2706 fm.end()
2706
2707
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2708 @command('debuginstall', [] + formatteropts, '', norepo=True)
2708 def debuginstall(ui, **opts):
2709 def debuginstall(ui, **opts):
2709 '''test Mercurial installation
2710 '''test Mercurial installation
2710
2711
2711 Returns 0 on success.
2712 Returns 0 on success.
2712 '''
2713 '''
2713
2714
2714 def writetemp(contents):
2715 def writetemp(contents):
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2716 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2716 f = os.fdopen(fd, "wb")
2717 f = os.fdopen(fd, "wb")
2717 f.write(contents)
2718 f.write(contents)
2718 f.close()
2719 f.close()
2719 return name
2720 return name
2720
2721
2721 problems = 0
2722 problems = 0
2722
2723
2723 fm = ui.formatter('debuginstall', opts)
2724 fm = ui.formatter('debuginstall', opts)
2724 fm.startitem()
2725 fm.startitem()
2725
2726
2726 # encoding
2727 # encoding
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2728 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2728 err = None
2729 err = None
2729 try:
2730 try:
2730 encoding.fromlocal("test")
2731 encoding.fromlocal("test")
2731 except error.Abort as inst:
2732 except error.Abort as inst:
2732 err = inst
2733 err = inst
2733 problems += 1
2734 problems += 1
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2735 fm.condwrite(err, 'encodingerror', _(" %s\n"
2735 " (check that your locale is properly set)\n"), err)
2736 " (check that your locale is properly set)\n"), err)
2736
2737
2737 # Python
2738 # Python
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2739 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2739 sys.executable)
2740 sys.executable)
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2741 fm.write('pythonver', _("checking Python version (%s)\n"),
2741 ("%s.%s.%s" % sys.version_info[:3]))
2742 ("%s.%s.%s" % sys.version_info[:3]))
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2743 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2743 os.path.dirname(os.__file__))
2744 os.path.dirname(os.__file__))
2744
2745
2745 # hg version
2746 # hg version
2746 hgver = util.version()
2747 hgver = util.version()
2747 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2748 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2748 hgver.split('+')[0])
2749 hgver.split('+')[0])
2749 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2750 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2750 '+'.join(hgver.split('+')[1:]))
2751 '+'.join(hgver.split('+')[1:]))
2751
2752
2752 # compiled modules
2753 # compiled modules
2753 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2754 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2754 policy.policy)
2755 policy.policy)
2755 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2756 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2756 os.path.dirname(__file__))
2757 os.path.dirname(__file__))
2757
2758
2758 err = None
2759 err = None
2759 try:
2760 try:
2760 from . import (
2761 from . import (
2761 base85,
2762 base85,
2762 bdiff,
2763 bdiff,
2763 mpatch,
2764 mpatch,
2764 osutil,
2765 osutil,
2765 )
2766 )
2766 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2767 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2767 except Exception as inst:
2768 except Exception as inst:
2768 err = inst
2769 err = inst
2769 problems += 1
2770 problems += 1
2770 fm.condwrite(err, 'extensionserror', " %s\n", err)
2771 fm.condwrite(err, 'extensionserror', " %s\n", err)
2771
2772
2772 # templates
2773 # templates
2773 p = templater.templatepaths()
2774 p = templater.templatepaths()
2774 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2775 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2775 fm.condwrite(not p, '', _(" no template directories found\n"))
2776 fm.condwrite(not p, '', _(" no template directories found\n"))
2776 if p:
2777 if p:
2777 m = templater.templatepath("map-cmdline.default")
2778 m = templater.templatepath("map-cmdline.default")
2778 if m:
2779 if m:
2779 # template found, check if it is working
2780 # template found, check if it is working
2780 err = None
2781 err = None
2781 try:
2782 try:
2782 templater.templater.frommapfile(m)
2783 templater.templater.frommapfile(m)
2783 except Exception as inst:
2784 except Exception as inst:
2784 err = inst
2785 err = inst
2785 p = None
2786 p = None
2786 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2787 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2787 else:
2788 else:
2788 p = None
2789 p = None
2789 fm.condwrite(p, 'defaulttemplate',
2790 fm.condwrite(p, 'defaulttemplate',
2790 _("checking default template (%s)\n"), m)
2791 _("checking default template (%s)\n"), m)
2791 fm.condwrite(not m, 'defaulttemplatenotfound',
2792 fm.condwrite(not m, 'defaulttemplatenotfound',
2792 _(" template '%s' not found\n"), "default")
2793 _(" template '%s' not found\n"), "default")
2793 if not p:
2794 if not p:
2794 problems += 1
2795 problems += 1
2795 fm.condwrite(not p, '',
2796 fm.condwrite(not p, '',
2796 _(" (templates seem to have been installed incorrectly)\n"))
2797 _(" (templates seem to have been installed incorrectly)\n"))
2797
2798
2798 # editor
2799 # editor
2799 editor = ui.geteditor()
2800 editor = ui.geteditor()
2800 editor = util.expandpath(editor)
2801 editor = util.expandpath(editor)
2801 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2802 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2802 cmdpath = util.findexe(shlex.split(editor)[0])
2803 cmdpath = util.findexe(shlex.split(editor)[0])
2803 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2804 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2804 _(" No commit editor set and can't find %s in PATH\n"
2805 _(" No commit editor set and can't find %s in PATH\n"
2805 " (specify a commit editor in your configuration"
2806 " (specify a commit editor in your configuration"
2806 " file)\n"), not cmdpath and editor == 'vi' and editor)
2807 " file)\n"), not cmdpath and editor == 'vi' and editor)
2807 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2808 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2808 _(" Can't find editor '%s' in PATH\n"
2809 _(" Can't find editor '%s' in PATH\n"
2809 " (specify a commit editor in your configuration"
2810 " (specify a commit editor in your configuration"
2810 " file)\n"), not cmdpath and editor)
2811 " file)\n"), not cmdpath and editor)
2811 if not cmdpath and editor != 'vi':
2812 if not cmdpath and editor != 'vi':
2812 problems += 1
2813 problems += 1
2813
2814
2814 # check username
2815 # check username
2815 username = None
2816 username = None
2816 err = None
2817 err = None
2817 try:
2818 try:
2818 username = ui.username()
2819 username = ui.username()
2819 except error.Abort as e:
2820 except error.Abort as e:
2820 err = e
2821 err = e
2821 problems += 1
2822 problems += 1
2822
2823
2823 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2824 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2824 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2825 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2825 " (specify a username in your configuration file)\n"), err)
2826 " (specify a username in your configuration file)\n"), err)
2826
2827
2827 fm.condwrite(not problems, '',
2828 fm.condwrite(not problems, '',
2828 _("no problems detected\n"))
2829 _("no problems detected\n"))
2829 if not problems:
2830 if not problems:
2830 fm.data(problems=problems)
2831 fm.data(problems=problems)
2831 fm.condwrite(problems, 'problems',
2832 fm.condwrite(problems, 'problems',
2832 _("%s problems detected,"
2833 _("%s problems detected,"
2833 " please check your install!\n"), problems)
2834 " please check your install!\n"), problems)
2834 fm.end()
2835 fm.end()
2835
2836
2836 return problems
2837 return problems
2837
2838
2838 @command('debugknown', [], _('REPO ID...'), norepo=True)
2839 @command('debugknown', [], _('REPO ID...'), norepo=True)
2839 def debugknown(ui, repopath, *ids, **opts):
2840 def debugknown(ui, repopath, *ids, **opts):
2840 """test whether node ids are known to a repo
2841 """test whether node ids are known to a repo
2841
2842
2842 Every ID must be a full-length hex node id string. Returns a list of 0s
2843 Every ID must be a full-length hex node id string. Returns a list of 0s
2843 and 1s indicating unknown/known.
2844 and 1s indicating unknown/known.
2844 """
2845 """
2845 repo = hg.peer(ui, opts, repopath)
2846 repo = hg.peer(ui, opts, repopath)
2846 if not repo.capable('known'):
2847 if not repo.capable('known'):
2847 raise error.Abort("known() not supported by target repository")
2848 raise error.Abort("known() not supported by target repository")
2848 flags = repo.known([bin(s) for s in ids])
2849 flags = repo.known([bin(s) for s in ids])
2849 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2850 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2850
2851
2851 @command('debuglabelcomplete', [], _('LABEL...'))
2852 @command('debuglabelcomplete', [], _('LABEL...'))
2852 def debuglabelcomplete(ui, repo, *args):
2853 def debuglabelcomplete(ui, repo, *args):
2853 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2854 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2854 debugnamecomplete(ui, repo, *args)
2855 debugnamecomplete(ui, repo, *args)
2855
2856
2856 @command('debugmergestate', [], '')
2857 @command('debugmergestate', [], '')
2857 def debugmergestate(ui, repo, *args):
2858 def debugmergestate(ui, repo, *args):
2858 """print merge state
2859 """print merge state
2859
2860
2860 Use --verbose to print out information about whether v1 or v2 merge state
2861 Use --verbose to print out information about whether v1 or v2 merge state
2861 was chosen."""
2862 was chosen."""
2862 def _hashornull(h):
2863 def _hashornull(h):
2863 if h == nullhex:
2864 if h == nullhex:
2864 return 'null'
2865 return 'null'
2865 else:
2866 else:
2866 return h
2867 return h
2867
2868
2868 def printrecords(version):
2869 def printrecords(version):
2869 ui.write(('* version %s records\n') % version)
2870 ui.write(('* version %s records\n') % version)
2870 if version == 1:
2871 if version == 1:
2871 records = v1records
2872 records = v1records
2872 else:
2873 else:
2873 records = v2records
2874 records = v2records
2874
2875
2875 for rtype, record in records:
2876 for rtype, record in records:
2876 # pretty print some record types
2877 # pretty print some record types
2877 if rtype == 'L':
2878 if rtype == 'L':
2878 ui.write(('local: %s\n') % record)
2879 ui.write(('local: %s\n') % record)
2879 elif rtype == 'O':
2880 elif rtype == 'O':
2880 ui.write(('other: %s\n') % record)
2881 ui.write(('other: %s\n') % record)
2881 elif rtype == 'm':
2882 elif rtype == 'm':
2882 driver, mdstate = record.split('\0', 1)
2883 driver, mdstate = record.split('\0', 1)
2883 ui.write(('merge driver: %s (state "%s")\n')
2884 ui.write(('merge driver: %s (state "%s")\n')
2884 % (driver, mdstate))
2885 % (driver, mdstate))
2885 elif rtype in 'FDC':
2886 elif rtype in 'FDC':
2886 r = record.split('\0')
2887 r = record.split('\0')
2887 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2888 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2888 if version == 1:
2889 if version == 1:
2889 onode = 'not stored in v1 format'
2890 onode = 'not stored in v1 format'
2890 flags = r[7]
2891 flags = r[7]
2891 else:
2892 else:
2892 onode, flags = r[7:9]
2893 onode, flags = r[7:9]
2893 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2894 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2894 % (f, rtype, state, _hashornull(hash)))
2895 % (f, rtype, state, _hashornull(hash)))
2895 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2896 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2896 ui.write((' ancestor path: %s (node %s)\n')
2897 ui.write((' ancestor path: %s (node %s)\n')
2897 % (afile, _hashornull(anode)))
2898 % (afile, _hashornull(anode)))
2898 ui.write((' other path: %s (node %s)\n')
2899 ui.write((' other path: %s (node %s)\n')
2899 % (ofile, _hashornull(onode)))
2900 % (ofile, _hashornull(onode)))
2900 elif rtype == 'f':
2901 elif rtype == 'f':
2901 filename, rawextras = record.split('\0', 1)
2902 filename, rawextras = record.split('\0', 1)
2902 extras = rawextras.split('\0')
2903 extras = rawextras.split('\0')
2903 i = 0
2904 i = 0
2904 extrastrings = []
2905 extrastrings = []
2905 while i < len(extras):
2906 while i < len(extras):
2906 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2907 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2907 i += 2
2908 i += 2
2908
2909
2909 ui.write(('file extras: %s (%s)\n')
2910 ui.write(('file extras: %s (%s)\n')
2910 % (filename, ', '.join(extrastrings)))
2911 % (filename, ', '.join(extrastrings)))
2911 elif rtype == 'l':
2912 elif rtype == 'l':
2912 labels = record.split('\0', 2)
2913 labels = record.split('\0', 2)
2913 labels = [l for l in labels if len(l) > 0]
2914 labels = [l for l in labels if len(l) > 0]
2914 ui.write(('labels:\n'))
2915 ui.write(('labels:\n'))
2915 ui.write((' local: %s\n' % labels[0]))
2916 ui.write((' local: %s\n' % labels[0]))
2916 ui.write((' other: %s\n' % labels[1]))
2917 ui.write((' other: %s\n' % labels[1]))
2917 if len(labels) > 2:
2918 if len(labels) > 2:
2918 ui.write((' base: %s\n' % labels[2]))
2919 ui.write((' base: %s\n' % labels[2]))
2919 else:
2920 else:
2920 ui.write(('unrecognized entry: %s\t%s\n')
2921 ui.write(('unrecognized entry: %s\t%s\n')
2921 % (rtype, record.replace('\0', '\t')))
2922 % (rtype, record.replace('\0', '\t')))
2922
2923
2923 # Avoid mergestate.read() since it may raise an exception for unsupported
2924 # Avoid mergestate.read() since it may raise an exception for unsupported
2924 # merge state records. We shouldn't be doing this, but this is OK since this
2925 # merge state records. We shouldn't be doing this, but this is OK since this
2925 # command is pretty low-level.
2926 # command is pretty low-level.
2926 ms = mergemod.mergestate(repo)
2927 ms = mergemod.mergestate(repo)
2927
2928
2928 # sort so that reasonable information is on top
2929 # sort so that reasonable information is on top
2929 v1records = ms._readrecordsv1()
2930 v1records = ms._readrecordsv1()
2930 v2records = ms._readrecordsv2()
2931 v2records = ms._readrecordsv2()
2931 order = 'LOml'
2932 order = 'LOml'
2932 def key(r):
2933 def key(r):
2933 idx = order.find(r[0])
2934 idx = order.find(r[0])
2934 if idx == -1:
2935 if idx == -1:
2935 return (1, r[1])
2936 return (1, r[1])
2936 else:
2937 else:
2937 return (0, idx)
2938 return (0, idx)
2938 v1records.sort(key=key)
2939 v1records.sort(key=key)
2939 v2records.sort(key=key)
2940 v2records.sort(key=key)
2940
2941
2941 if not v1records and not v2records:
2942 if not v1records and not v2records:
2942 ui.write(('no merge state found\n'))
2943 ui.write(('no merge state found\n'))
2943 elif not v2records:
2944 elif not v2records:
2944 ui.note(('no version 2 merge state\n'))
2945 ui.note(('no version 2 merge state\n'))
2945 printrecords(1)
2946 printrecords(1)
2946 elif ms._v1v2match(v1records, v2records):
2947 elif ms._v1v2match(v1records, v2records):
2947 ui.note(('v1 and v2 states match: using v2\n'))
2948 ui.note(('v1 and v2 states match: using v2\n'))
2948 printrecords(2)
2949 printrecords(2)
2949 else:
2950 else:
2950 ui.note(('v1 and v2 states mismatch: using v1\n'))
2951 ui.note(('v1 and v2 states mismatch: using v1\n'))
2951 printrecords(1)
2952 printrecords(1)
2952 if ui.verbose:
2953 if ui.verbose:
2953 printrecords(2)
2954 printrecords(2)
2954
2955
2955 @command('debugnamecomplete', [], _('NAME...'))
2956 @command('debugnamecomplete', [], _('NAME...'))
2956 def debugnamecomplete(ui, repo, *args):
2957 def debugnamecomplete(ui, repo, *args):
2957 '''complete "names" - tags, open branch names, bookmark names'''
2958 '''complete "names" - tags, open branch names, bookmark names'''
2958
2959
2959 names = set()
2960 names = set()
2960 # since we previously only listed open branches, we will handle that
2961 # since we previously only listed open branches, we will handle that
2961 # specially (after this for loop)
2962 # specially (after this for loop)
2962 for name, ns in repo.names.iteritems():
2963 for name, ns in repo.names.iteritems():
2963 if name != 'branches':
2964 if name != 'branches':
2964 names.update(ns.listnames(repo))
2965 names.update(ns.listnames(repo))
2965 names.update(tag for (tag, heads, tip, closed)
2966 names.update(tag for (tag, heads, tip, closed)
2966 in repo.branchmap().iterbranches() if not closed)
2967 in repo.branchmap().iterbranches() if not closed)
2967 completions = set()
2968 completions = set()
2968 if not args:
2969 if not args:
2969 args = ['']
2970 args = ['']
2970 for a in args:
2971 for a in args:
2971 completions.update(n for n in names if n.startswith(a))
2972 completions.update(n for n in names if n.startswith(a))
2972 ui.write('\n'.join(sorted(completions)))
2973 ui.write('\n'.join(sorted(completions)))
2973 ui.write('\n')
2974 ui.write('\n')
2974
2975
2975 @command('debuglocks',
2976 @command('debuglocks',
2976 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2977 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2977 ('W', 'force-wlock', None,
2978 ('W', 'force-wlock', None,
2978 _('free the working state lock (DANGEROUS)'))],
2979 _('free the working state lock (DANGEROUS)'))],
2979 _('[OPTION]...'))
2980 _('[OPTION]...'))
2980 def debuglocks(ui, repo, **opts):
2981 def debuglocks(ui, repo, **opts):
2981 """show or modify state of locks
2982 """show or modify state of locks
2982
2983
2983 By default, this command will show which locks are held. This
2984 By default, this command will show which locks are held. This
2984 includes the user and process holding the lock, the amount of time
2985 includes the user and process holding the lock, the amount of time
2985 the lock has been held, and the machine name where the process is
2986 the lock has been held, and the machine name where the process is
2986 running if it's not local.
2987 running if it's not local.
2987
2988
2988 Locks protect the integrity of Mercurial's data, so should be
2989 Locks protect the integrity of Mercurial's data, so should be
2989 treated with care. System crashes or other interruptions may cause
2990 treated with care. System crashes or other interruptions may cause
2990 locks to not be properly released, though Mercurial will usually
2991 locks to not be properly released, though Mercurial will usually
2991 detect and remove such stale locks automatically.
2992 detect and remove such stale locks automatically.
2992
2993
2993 However, detecting stale locks may not always be possible (for
2994 However, detecting stale locks may not always be possible (for
2994 instance, on a shared filesystem). Removing locks may also be
2995 instance, on a shared filesystem). Removing locks may also be
2995 blocked by filesystem permissions.
2996 blocked by filesystem permissions.
2996
2997
2997 Returns 0 if no locks are held.
2998 Returns 0 if no locks are held.
2998
2999
2999 """
3000 """
3000
3001
3001 if opts.get('force_lock'):
3002 if opts.get('force_lock'):
3002 repo.svfs.unlink('lock')
3003 repo.svfs.unlink('lock')
3003 if opts.get('force_wlock'):
3004 if opts.get('force_wlock'):
3004 repo.vfs.unlink('wlock')
3005 repo.vfs.unlink('wlock')
3005 if opts.get('force_lock') or opts.get('force_lock'):
3006 if opts.get('force_lock') or opts.get('force_lock'):
3006 return 0
3007 return 0
3007
3008
3008 now = time.time()
3009 now = time.time()
3009 held = 0
3010 held = 0
3010
3011
3011 def report(vfs, name, method):
3012 def report(vfs, name, method):
3012 # this causes stale locks to get reaped for more accurate reporting
3013 # this causes stale locks to get reaped for more accurate reporting
3013 try:
3014 try:
3014 l = method(False)
3015 l = method(False)
3015 except error.LockHeld:
3016 except error.LockHeld:
3016 l = None
3017 l = None
3017
3018
3018 if l:
3019 if l:
3019 l.release()
3020 l.release()
3020 else:
3021 else:
3021 try:
3022 try:
3022 stat = vfs.lstat(name)
3023 stat = vfs.lstat(name)
3023 age = now - stat.st_mtime
3024 age = now - stat.st_mtime
3024 user = util.username(stat.st_uid)
3025 user = util.username(stat.st_uid)
3025 locker = vfs.readlock(name)
3026 locker = vfs.readlock(name)
3026 if ":" in locker:
3027 if ":" in locker:
3027 host, pid = locker.split(':')
3028 host, pid = locker.split(':')
3028 if host == socket.gethostname():
3029 if host == socket.gethostname():
3029 locker = 'user %s, process %s' % (user, pid)
3030 locker = 'user %s, process %s' % (user, pid)
3030 else:
3031 else:
3031 locker = 'user %s, process %s, host %s' \
3032 locker = 'user %s, process %s, host %s' \
3032 % (user, pid, host)
3033 % (user, pid, host)
3033 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3034 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
3034 return 1
3035 return 1
3035 except OSError as e:
3036 except OSError as e:
3036 if e.errno != errno.ENOENT:
3037 if e.errno != errno.ENOENT:
3037 raise
3038 raise
3038
3039
3039 ui.write(("%-6s free\n") % (name + ":"))
3040 ui.write(("%-6s free\n") % (name + ":"))
3040 return 0
3041 return 0
3041
3042
3042 held += report(repo.svfs, "lock", repo.lock)
3043 held += report(repo.svfs, "lock", repo.lock)
3043 held += report(repo.vfs, "wlock", repo.wlock)
3044 held += report(repo.vfs, "wlock", repo.wlock)
3044
3045
3045 return held
3046 return held
3046
3047
3047 @command('debugobsolete',
3048 @command('debugobsolete',
3048 [('', 'flags', 0, _('markers flag')),
3049 [('', 'flags', 0, _('markers flag')),
3049 ('', 'record-parents', False,
3050 ('', 'record-parents', False,
3050 _('record parent information for the precursor')),
3051 _('record parent information for the precursor')),
3051 ('r', 'rev', [], _('display markers relevant to REV')),
3052 ('r', 'rev', [], _('display markers relevant to REV')),
3052 ('', 'index', False, _('display index of the marker')),
3053 ('', 'index', False, _('display index of the marker')),
3053 ('', 'delete', [], _('delete markers specified by indices')),
3054 ('', 'delete', [], _('delete markers specified by indices')),
3054 ] + commitopts2,
3055 ] + commitopts2,
3055 _('[OBSOLETED [REPLACEMENT ...]]'))
3056 _('[OBSOLETED [REPLACEMENT ...]]'))
3056 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3057 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3057 """create arbitrary obsolete marker
3058 """create arbitrary obsolete marker
3058
3059
3059 With no arguments, displays the list of obsolescence markers."""
3060 With no arguments, displays the list of obsolescence markers."""
3060
3061
3061 def parsenodeid(s):
3062 def parsenodeid(s):
3062 try:
3063 try:
3063 # We do not use revsingle/revrange functions here to accept
3064 # We do not use revsingle/revrange functions here to accept
3064 # arbitrary node identifiers, possibly not present in the
3065 # arbitrary node identifiers, possibly not present in the
3065 # local repository.
3066 # local repository.
3066 n = bin(s)
3067 n = bin(s)
3067 if len(n) != len(nullid):
3068 if len(n) != len(nullid):
3068 raise TypeError()
3069 raise TypeError()
3069 return n
3070 return n
3070 except TypeError:
3071 except TypeError:
3071 raise error.Abort('changeset references must be full hexadecimal '
3072 raise error.Abort('changeset references must be full hexadecimal '
3072 'node identifiers')
3073 'node identifiers')
3073
3074
3074 if opts.get('delete'):
3075 if opts.get('delete'):
3075 indices = []
3076 indices = []
3076 for v in opts.get('delete'):
3077 for v in opts.get('delete'):
3077 try:
3078 try:
3078 indices.append(int(v))
3079 indices.append(int(v))
3079 except ValueError:
3080 except ValueError:
3080 raise error.Abort(_('invalid index value: %r') % v,
3081 raise error.Abort(_('invalid index value: %r') % v,
3081 hint=_('use integers for indices'))
3082 hint=_('use integers for indices'))
3082
3083
3083 if repo.currenttransaction():
3084 if repo.currenttransaction():
3084 raise error.Abort(_('cannot delete obsmarkers in the middle '
3085 raise error.Abort(_('cannot delete obsmarkers in the middle '
3085 'of transaction.'))
3086 'of transaction.'))
3086
3087
3087 with repo.lock():
3088 with repo.lock():
3088 n = repair.deleteobsmarkers(repo.obsstore, indices)
3089 n = repair.deleteobsmarkers(repo.obsstore, indices)
3089 ui.write(_('deleted %i obsolescense markers\n') % n)
3090 ui.write(_('deleted %i obsolescense markers\n') % n)
3090
3091
3091 return
3092 return
3092
3093
3093 if precursor is not None:
3094 if precursor is not None:
3094 if opts['rev']:
3095 if opts['rev']:
3095 raise error.Abort('cannot select revision when creating marker')
3096 raise error.Abort('cannot select revision when creating marker')
3096 metadata = {}
3097 metadata = {}
3097 metadata['user'] = opts['user'] or ui.username()
3098 metadata['user'] = opts['user'] or ui.username()
3098 succs = tuple(parsenodeid(succ) for succ in successors)
3099 succs = tuple(parsenodeid(succ) for succ in successors)
3099 l = repo.lock()
3100 l = repo.lock()
3100 try:
3101 try:
3101 tr = repo.transaction('debugobsolete')
3102 tr = repo.transaction('debugobsolete')
3102 try:
3103 try:
3103 date = opts.get('date')
3104 date = opts.get('date')
3104 if date:
3105 if date:
3105 date = util.parsedate(date)
3106 date = util.parsedate(date)
3106 else:
3107 else:
3107 date = None
3108 date = None
3108 prec = parsenodeid(precursor)
3109 prec = parsenodeid(precursor)
3109 parents = None
3110 parents = None
3110 if opts['record_parents']:
3111 if opts['record_parents']:
3111 if prec not in repo.unfiltered():
3112 if prec not in repo.unfiltered():
3112 raise error.Abort('cannot used --record-parents on '
3113 raise error.Abort('cannot used --record-parents on '
3113 'unknown changesets')
3114 'unknown changesets')
3114 parents = repo.unfiltered()[prec].parents()
3115 parents = repo.unfiltered()[prec].parents()
3115 parents = tuple(p.node() for p in parents)
3116 parents = tuple(p.node() for p in parents)
3116 repo.obsstore.create(tr, prec, succs, opts['flags'],
3117 repo.obsstore.create(tr, prec, succs, opts['flags'],
3117 parents=parents, date=date,
3118 parents=parents, date=date,
3118 metadata=metadata)
3119 metadata=metadata)
3119 tr.close()
3120 tr.close()
3120 except ValueError as exc:
3121 except ValueError as exc:
3121 raise error.Abort(_('bad obsmarker input: %s') % exc)
3122 raise error.Abort(_('bad obsmarker input: %s') % exc)
3122 finally:
3123 finally:
3123 tr.release()
3124 tr.release()
3124 finally:
3125 finally:
3125 l.release()
3126 l.release()
3126 else:
3127 else:
3127 if opts['rev']:
3128 if opts['rev']:
3128 revs = scmutil.revrange(repo, opts['rev'])
3129 revs = scmutil.revrange(repo, opts['rev'])
3129 nodes = [repo[r].node() for r in revs]
3130 nodes = [repo[r].node() for r in revs]
3130 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3131 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3131 markers.sort(key=lambda x: x._data)
3132 markers.sort(key=lambda x: x._data)
3132 else:
3133 else:
3133 markers = obsolete.getmarkers(repo)
3134 markers = obsolete.getmarkers(repo)
3134
3135
3135 markerstoiter = markers
3136 markerstoiter = markers
3136 isrelevant = lambda m: True
3137 isrelevant = lambda m: True
3137 if opts.get('rev') and opts.get('index'):
3138 if opts.get('rev') and opts.get('index'):
3138 markerstoiter = obsolete.getmarkers(repo)
3139 markerstoiter = obsolete.getmarkers(repo)
3139 markerset = set(markers)
3140 markerset = set(markers)
3140 isrelevant = lambda m: m in markerset
3141 isrelevant = lambda m: m in markerset
3141
3142
3142 for i, m in enumerate(markerstoiter):
3143 for i, m in enumerate(markerstoiter):
3143 if not isrelevant(m):
3144 if not isrelevant(m):
3144 # marker can be irrelevant when we're iterating over a set
3145 # marker can be irrelevant when we're iterating over a set
3145 # of markers (markerstoiter) which is bigger than the set
3146 # of markers (markerstoiter) which is bigger than the set
3146 # of markers we want to display (markers)
3147 # of markers we want to display (markers)
3147 # this can happen if both --index and --rev options are
3148 # this can happen if both --index and --rev options are
3148 # provided and thus we need to iterate over all of the markers
3149 # provided and thus we need to iterate over all of the markers
3149 # to get the correct indices, but only display the ones that
3150 # to get the correct indices, but only display the ones that
3150 # are relevant to --rev value
3151 # are relevant to --rev value
3151 continue
3152 continue
3152 ind = i if opts.get('index') else None
3153 ind = i if opts.get('index') else None
3153 cmdutil.showmarker(ui, m, index=ind)
3154 cmdutil.showmarker(ui, m, index=ind)
3154
3155
3155 @command('debugpathcomplete',
3156 @command('debugpathcomplete',
3156 [('f', 'full', None, _('complete an entire path')),
3157 [('f', 'full', None, _('complete an entire path')),
3157 ('n', 'normal', None, _('show only normal files')),
3158 ('n', 'normal', None, _('show only normal files')),
3158 ('a', 'added', None, _('show only added files')),
3159 ('a', 'added', None, _('show only added files')),
3159 ('r', 'removed', None, _('show only removed files'))],
3160 ('r', 'removed', None, _('show only removed files'))],
3160 _('FILESPEC...'))
3161 _('FILESPEC...'))
3161 def debugpathcomplete(ui, repo, *specs, **opts):
3162 def debugpathcomplete(ui, repo, *specs, **opts):
3162 '''complete part or all of a tracked path
3163 '''complete part or all of a tracked path
3163
3164
3164 This command supports shells that offer path name completion. It
3165 This command supports shells that offer path name completion. It
3165 currently completes only files already known to the dirstate.
3166 currently completes only files already known to the dirstate.
3166
3167
3167 Completion extends only to the next path segment unless
3168 Completion extends only to the next path segment unless
3168 --full is specified, in which case entire paths are used.'''
3169 --full is specified, in which case entire paths are used.'''
3169
3170
3170 def complete(path, acceptable):
3171 def complete(path, acceptable):
3171 dirstate = repo.dirstate
3172 dirstate = repo.dirstate
3172 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3173 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3173 rootdir = repo.root + os.sep
3174 rootdir = repo.root + os.sep
3174 if spec != repo.root and not spec.startswith(rootdir):
3175 if spec != repo.root and not spec.startswith(rootdir):
3175 return [], []
3176 return [], []
3176 if os.path.isdir(spec):
3177 if os.path.isdir(spec):
3177 spec += '/'
3178 spec += '/'
3178 spec = spec[len(rootdir):]
3179 spec = spec[len(rootdir):]
3179 fixpaths = os.sep != '/'
3180 fixpaths = os.sep != '/'
3180 if fixpaths:
3181 if fixpaths:
3181 spec = spec.replace(os.sep, '/')
3182 spec = spec.replace(os.sep, '/')
3182 speclen = len(spec)
3183 speclen = len(spec)
3183 fullpaths = opts['full']
3184 fullpaths = opts['full']
3184 files, dirs = set(), set()
3185 files, dirs = set(), set()
3185 adddir, addfile = dirs.add, files.add
3186 adddir, addfile = dirs.add, files.add
3186 for f, st in dirstate.iteritems():
3187 for f, st in dirstate.iteritems():
3187 if f.startswith(spec) and st[0] in acceptable:
3188 if f.startswith(spec) and st[0] in acceptable:
3188 if fixpaths:
3189 if fixpaths:
3189 f = f.replace('/', os.sep)
3190 f = f.replace('/', os.sep)
3190 if fullpaths:
3191 if fullpaths:
3191 addfile(f)
3192 addfile(f)
3192 continue
3193 continue
3193 s = f.find(os.sep, speclen)
3194 s = f.find(os.sep, speclen)
3194 if s >= 0:
3195 if s >= 0:
3195 adddir(f[:s])
3196 adddir(f[:s])
3196 else:
3197 else:
3197 addfile(f)
3198 addfile(f)
3198 return files, dirs
3199 return files, dirs
3199
3200
3200 acceptable = ''
3201 acceptable = ''
3201 if opts['normal']:
3202 if opts['normal']:
3202 acceptable += 'nm'
3203 acceptable += 'nm'
3203 if opts['added']:
3204 if opts['added']:
3204 acceptable += 'a'
3205 acceptable += 'a'
3205 if opts['removed']:
3206 if opts['removed']:
3206 acceptable += 'r'
3207 acceptable += 'r'
3207 cwd = repo.getcwd()
3208 cwd = repo.getcwd()
3208 if not specs:
3209 if not specs:
3209 specs = ['.']
3210 specs = ['.']
3210
3211
3211 files, dirs = set(), set()
3212 files, dirs = set(), set()
3212 for spec in specs:
3213 for spec in specs:
3213 f, d = complete(spec, acceptable or 'nmar')
3214 f, d = complete(spec, acceptable or 'nmar')
3214 files.update(f)
3215 files.update(f)
3215 dirs.update(d)
3216 dirs.update(d)
3216 files.update(dirs)
3217 files.update(dirs)
3217 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3218 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3218 ui.write('\n')
3219 ui.write('\n')
3219
3220
3220 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3221 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3221 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3222 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3222 '''access the pushkey key/value protocol
3223 '''access the pushkey key/value protocol
3223
3224
3224 With two args, list the keys in the given namespace.
3225 With two args, list the keys in the given namespace.
3225
3226
3226 With five args, set a key to new if it currently is set to old.
3227 With five args, set a key to new if it currently is set to old.
3227 Reports success or failure.
3228 Reports success or failure.
3228 '''
3229 '''
3229
3230
3230 target = hg.peer(ui, {}, repopath)
3231 target = hg.peer(ui, {}, repopath)
3231 if keyinfo:
3232 if keyinfo:
3232 key, old, new = keyinfo
3233 key, old, new = keyinfo
3233 r = target.pushkey(namespace, key, old, new)
3234 r = target.pushkey(namespace, key, old, new)
3234 ui.status(str(r) + '\n')
3235 ui.status(str(r) + '\n')
3235 return not r
3236 return not r
3236 else:
3237 else:
3237 for k, v in sorted(target.listkeys(namespace).iteritems()):
3238 for k, v in sorted(target.listkeys(namespace).iteritems()):
3238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3239 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3239 v.encode('string-escape')))
3240 v.encode('string-escape')))
3240
3241
3241 @command('debugpvec', [], _('A B'))
3242 @command('debugpvec', [], _('A B'))
3242 def debugpvec(ui, repo, a, b=None):
3243 def debugpvec(ui, repo, a, b=None):
3243 ca = scmutil.revsingle(repo, a)
3244 ca = scmutil.revsingle(repo, a)
3244 cb = scmutil.revsingle(repo, b)
3245 cb = scmutil.revsingle(repo, b)
3245 pa = pvec.ctxpvec(ca)
3246 pa = pvec.ctxpvec(ca)
3246 pb = pvec.ctxpvec(cb)
3247 pb = pvec.ctxpvec(cb)
3247 if pa == pb:
3248 if pa == pb:
3248 rel = "="
3249 rel = "="
3249 elif pa > pb:
3250 elif pa > pb:
3250 rel = ">"
3251 rel = ">"
3251 elif pa < pb:
3252 elif pa < pb:
3252 rel = "<"
3253 rel = "<"
3253 elif pa | pb:
3254 elif pa | pb:
3254 rel = "|"
3255 rel = "|"
3255 ui.write(_("a: %s\n") % pa)
3256 ui.write(_("a: %s\n") % pa)
3256 ui.write(_("b: %s\n") % pb)
3257 ui.write(_("b: %s\n") % pb)
3257 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3258 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3258 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3259 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3259 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3260 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3260 pa.distance(pb), rel))
3261 pa.distance(pb), rel))
3261
3262
3262 @command('debugrebuilddirstate|debugrebuildstate',
3263 @command('debugrebuilddirstate|debugrebuildstate',
3263 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3264 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3264 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3265 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3265 'the working copy parent')),
3266 'the working copy parent')),
3266 ],
3267 ],
3267 _('[-r REV]'))
3268 _('[-r REV]'))
3268 def debugrebuilddirstate(ui, repo, rev, **opts):
3269 def debugrebuilddirstate(ui, repo, rev, **opts):
3269 """rebuild the dirstate as it would look like for the given revision
3270 """rebuild the dirstate as it would look like for the given revision
3270
3271
3271 If no revision is specified the first current parent will be used.
3272 If no revision is specified the first current parent will be used.
3272
3273
3273 The dirstate will be set to the files of the given revision.
3274 The dirstate will be set to the files of the given revision.
3274 The actual working directory content or existing dirstate
3275 The actual working directory content or existing dirstate
3275 information such as adds or removes is not considered.
3276 information such as adds or removes is not considered.
3276
3277
3277 ``minimal`` will only rebuild the dirstate status for files that claim to be
3278 ``minimal`` will only rebuild the dirstate status for files that claim to be
3278 tracked but are not in the parent manifest, or that exist in the parent
3279 tracked but are not in the parent manifest, or that exist in the parent
3279 manifest but are not in the dirstate. It will not change adds, removes, or
3280 manifest but are not in the dirstate. It will not change adds, removes, or
3280 modified files that are in the working copy parent.
3281 modified files that are in the working copy parent.
3281
3282
3282 One use of this command is to make the next :hg:`status` invocation
3283 One use of this command is to make the next :hg:`status` invocation
3283 check the actual file content.
3284 check the actual file content.
3284 """
3285 """
3285 ctx = scmutil.revsingle(repo, rev)
3286 ctx = scmutil.revsingle(repo, rev)
3286 with repo.wlock():
3287 with repo.wlock():
3287 dirstate = repo.dirstate
3288 dirstate = repo.dirstate
3288 changedfiles = None
3289 changedfiles = None
3289 # See command doc for what minimal does.
3290 # See command doc for what minimal does.
3290 if opts.get('minimal'):
3291 if opts.get('minimal'):
3291 manifestfiles = set(ctx.manifest().keys())
3292 manifestfiles = set(ctx.manifest().keys())
3292 dirstatefiles = set(dirstate)
3293 dirstatefiles = set(dirstate)
3293 manifestonly = manifestfiles - dirstatefiles
3294 manifestonly = manifestfiles - dirstatefiles
3294 dsonly = dirstatefiles - manifestfiles
3295 dsonly = dirstatefiles - manifestfiles
3295 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3296 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3296 changedfiles = manifestonly | dsnotadded
3297 changedfiles = manifestonly | dsnotadded
3297
3298
3298 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3299 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3299
3300
3300 @command('debugrebuildfncache', [], '')
3301 @command('debugrebuildfncache', [], '')
3301 def debugrebuildfncache(ui, repo):
3302 def debugrebuildfncache(ui, repo):
3302 """rebuild the fncache file"""
3303 """rebuild the fncache file"""
3303 repair.rebuildfncache(ui, repo)
3304 repair.rebuildfncache(ui, repo)
3304
3305
3305 @command('debugrename',
3306 @command('debugrename',
3306 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3307 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3307 _('[-r REV] FILE'))
3308 _('[-r REV] FILE'))
3308 def debugrename(ui, repo, file1, *pats, **opts):
3309 def debugrename(ui, repo, file1, *pats, **opts):
3309 """dump rename information"""
3310 """dump rename information"""
3310
3311
3311 ctx = scmutil.revsingle(repo, opts.get('rev'))
3312 ctx = scmutil.revsingle(repo, opts.get('rev'))
3312 m = scmutil.match(ctx, (file1,) + pats, opts)
3313 m = scmutil.match(ctx, (file1,) + pats, opts)
3313 for abs in ctx.walk(m):
3314 for abs in ctx.walk(m):
3314 fctx = ctx[abs]
3315 fctx = ctx[abs]
3315 o = fctx.filelog().renamed(fctx.filenode())
3316 o = fctx.filelog().renamed(fctx.filenode())
3316 rel = m.rel(abs)
3317 rel = m.rel(abs)
3317 if o:
3318 if o:
3318 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3319 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3319 else:
3320 else:
3320 ui.write(_("%s not renamed\n") % rel)
3321 ui.write(_("%s not renamed\n") % rel)
3321
3322
3322 @command('debugrevlog', debugrevlogopts +
3323 @command('debugrevlog', debugrevlogopts +
3323 [('d', 'dump', False, _('dump index data'))],
3324 [('d', 'dump', False, _('dump index data'))],
3324 _('-c|-m|FILE'),
3325 _('-c|-m|FILE'),
3325 optionalrepo=True)
3326 optionalrepo=True)
3326 def debugrevlog(ui, repo, file_=None, **opts):
3327 def debugrevlog(ui, repo, file_=None, **opts):
3327 """show data and statistics about a revlog"""
3328 """show data and statistics about a revlog"""
3328 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3329 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3329
3330
3330 if opts.get("dump"):
3331 if opts.get("dump"):
3331 numrevs = len(r)
3332 numrevs = len(r)
3332 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3333 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3333 " rawsize totalsize compression heads chainlen\n"))
3334 " rawsize totalsize compression heads chainlen\n"))
3334 ts = 0
3335 ts = 0
3335 heads = set()
3336 heads = set()
3336
3337
3337 for rev in xrange(numrevs):
3338 for rev in xrange(numrevs):
3338 dbase = r.deltaparent(rev)
3339 dbase = r.deltaparent(rev)
3339 if dbase == -1:
3340 if dbase == -1:
3340 dbase = rev
3341 dbase = rev
3341 cbase = r.chainbase(rev)
3342 cbase = r.chainbase(rev)
3342 clen = r.chainlen(rev)
3343 clen = r.chainlen(rev)
3343 p1, p2 = r.parentrevs(rev)
3344 p1, p2 = r.parentrevs(rev)
3344 rs = r.rawsize(rev)
3345 rs = r.rawsize(rev)
3345 ts = ts + rs
3346 ts = ts + rs
3346 heads -= set(r.parentrevs(rev))
3347 heads -= set(r.parentrevs(rev))
3347 heads.add(rev)
3348 heads.add(rev)
3348 try:
3349 try:
3349 compression = ts / r.end(rev)
3350 compression = ts / r.end(rev)
3350 except ZeroDivisionError:
3351 except ZeroDivisionError:
3351 compression = 0
3352 compression = 0
3352 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3353 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3353 "%11d %5d %8d\n" %
3354 "%11d %5d %8d\n" %
3354 (rev, p1, p2, r.start(rev), r.end(rev),
3355 (rev, p1, p2, r.start(rev), r.end(rev),
3355 r.start(dbase), r.start(cbase),
3356 r.start(dbase), r.start(cbase),
3356 r.start(p1), r.start(p2),
3357 r.start(p1), r.start(p2),
3357 rs, ts, compression, len(heads), clen))
3358 rs, ts, compression, len(heads), clen))
3358 return 0
3359 return 0
3359
3360
3360 v = r.version
3361 v = r.version
3361 format = v & 0xFFFF
3362 format = v & 0xFFFF
3362 flags = []
3363 flags = []
3363 gdelta = False
3364 gdelta = False
3364 if v & revlog.REVLOGNGINLINEDATA:
3365 if v & revlog.REVLOGNGINLINEDATA:
3365 flags.append('inline')
3366 flags.append('inline')
3366 if v & revlog.REVLOGGENERALDELTA:
3367 if v & revlog.REVLOGGENERALDELTA:
3367 gdelta = True
3368 gdelta = True
3368 flags.append('generaldelta')
3369 flags.append('generaldelta')
3369 if not flags:
3370 if not flags:
3370 flags = ['(none)']
3371 flags = ['(none)']
3371
3372
3372 nummerges = 0
3373 nummerges = 0
3373 numfull = 0
3374 numfull = 0
3374 numprev = 0
3375 numprev = 0
3375 nump1 = 0
3376 nump1 = 0
3376 nump2 = 0
3377 nump2 = 0
3377 numother = 0
3378 numother = 0
3378 nump1prev = 0
3379 nump1prev = 0
3379 nump2prev = 0
3380 nump2prev = 0
3380 chainlengths = []
3381 chainlengths = []
3381
3382
3382 datasize = [None, 0, 0L]
3383 datasize = [None, 0, 0L]
3383 fullsize = [None, 0, 0L]
3384 fullsize = [None, 0, 0L]
3384 deltasize = [None, 0, 0L]
3385 deltasize = [None, 0, 0L]
3385
3386
3386 def addsize(size, l):
3387 def addsize(size, l):
3387 if l[0] is None or size < l[0]:
3388 if l[0] is None or size < l[0]:
3388 l[0] = size
3389 l[0] = size
3389 if size > l[1]:
3390 if size > l[1]:
3390 l[1] = size
3391 l[1] = size
3391 l[2] += size
3392 l[2] += size
3392
3393
3393 numrevs = len(r)
3394 numrevs = len(r)
3394 for rev in xrange(numrevs):
3395 for rev in xrange(numrevs):
3395 p1, p2 = r.parentrevs(rev)
3396 p1, p2 = r.parentrevs(rev)
3396 delta = r.deltaparent(rev)
3397 delta = r.deltaparent(rev)
3397 if format > 0:
3398 if format > 0:
3398 addsize(r.rawsize(rev), datasize)
3399 addsize(r.rawsize(rev), datasize)
3399 if p2 != nullrev:
3400 if p2 != nullrev:
3400 nummerges += 1
3401 nummerges += 1
3401 size = r.length(rev)
3402 size = r.length(rev)
3402 if delta == nullrev:
3403 if delta == nullrev:
3403 chainlengths.append(0)
3404 chainlengths.append(0)
3404 numfull += 1
3405 numfull += 1
3405 addsize(size, fullsize)
3406 addsize(size, fullsize)
3406 else:
3407 else:
3407 chainlengths.append(chainlengths[delta] + 1)
3408 chainlengths.append(chainlengths[delta] + 1)
3408 addsize(size, deltasize)
3409 addsize(size, deltasize)
3409 if delta == rev - 1:
3410 if delta == rev - 1:
3410 numprev += 1
3411 numprev += 1
3411 if delta == p1:
3412 if delta == p1:
3412 nump1prev += 1
3413 nump1prev += 1
3413 elif delta == p2:
3414 elif delta == p2:
3414 nump2prev += 1
3415 nump2prev += 1
3415 elif delta == p1:
3416 elif delta == p1:
3416 nump1 += 1
3417 nump1 += 1
3417 elif delta == p2:
3418 elif delta == p2:
3418 nump2 += 1
3419 nump2 += 1
3419 elif delta != nullrev:
3420 elif delta != nullrev:
3420 numother += 1
3421 numother += 1
3421
3422
3422 # Adjust size min value for empty cases
3423 # Adjust size min value for empty cases
3423 for size in (datasize, fullsize, deltasize):
3424 for size in (datasize, fullsize, deltasize):
3424 if size[0] is None:
3425 if size[0] is None:
3425 size[0] = 0
3426 size[0] = 0
3426
3427
3427 numdeltas = numrevs - numfull
3428 numdeltas = numrevs - numfull
3428 numoprev = numprev - nump1prev - nump2prev
3429 numoprev = numprev - nump1prev - nump2prev
3429 totalrawsize = datasize[2]
3430 totalrawsize = datasize[2]
3430 datasize[2] /= numrevs
3431 datasize[2] /= numrevs
3431 fulltotal = fullsize[2]
3432 fulltotal = fullsize[2]
3432 fullsize[2] /= numfull
3433 fullsize[2] /= numfull
3433 deltatotal = deltasize[2]
3434 deltatotal = deltasize[2]
3434 if numrevs - numfull > 0:
3435 if numrevs - numfull > 0:
3435 deltasize[2] /= numrevs - numfull
3436 deltasize[2] /= numrevs - numfull
3436 totalsize = fulltotal + deltatotal
3437 totalsize = fulltotal + deltatotal
3437 avgchainlen = sum(chainlengths) / numrevs
3438 avgchainlen = sum(chainlengths) / numrevs
3438 maxchainlen = max(chainlengths)
3439 maxchainlen = max(chainlengths)
3439 compratio = 1
3440 compratio = 1
3440 if totalsize:
3441 if totalsize:
3441 compratio = totalrawsize / totalsize
3442 compratio = totalrawsize / totalsize
3442
3443
3443 basedfmtstr = '%%%dd\n'
3444 basedfmtstr = '%%%dd\n'
3444 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3445 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3445
3446
3446 def dfmtstr(max):
3447 def dfmtstr(max):
3447 return basedfmtstr % len(str(max))
3448 return basedfmtstr % len(str(max))
3448 def pcfmtstr(max, padding=0):
3449 def pcfmtstr(max, padding=0):
3449 return basepcfmtstr % (len(str(max)), ' ' * padding)
3450 return basepcfmtstr % (len(str(max)), ' ' * padding)
3450
3451
3451 def pcfmt(value, total):
3452 def pcfmt(value, total):
3452 if total:
3453 if total:
3453 return (value, 100 * float(value) / total)
3454 return (value, 100 * float(value) / total)
3454 else:
3455 else:
3455 return value, 100.0
3456 return value, 100.0
3456
3457
3457 ui.write(('format : %d\n') % format)
3458 ui.write(('format : %d\n') % format)
3458 ui.write(('flags : %s\n') % ', '.join(flags))
3459 ui.write(('flags : %s\n') % ', '.join(flags))
3459
3460
3460 ui.write('\n')
3461 ui.write('\n')
3461 fmt = pcfmtstr(totalsize)
3462 fmt = pcfmtstr(totalsize)
3462 fmt2 = dfmtstr(totalsize)
3463 fmt2 = dfmtstr(totalsize)
3463 ui.write(('revisions : ') + fmt2 % numrevs)
3464 ui.write(('revisions : ') + fmt2 % numrevs)
3464 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3465 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3465 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3466 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3466 ui.write(('revisions : ') + fmt2 % numrevs)
3467 ui.write(('revisions : ') + fmt2 % numrevs)
3467 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3468 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3468 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3469 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3469 ui.write(('revision size : ') + fmt2 % totalsize)
3470 ui.write(('revision size : ') + fmt2 % totalsize)
3470 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3471 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3471 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3472 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3472
3473
3473 ui.write('\n')
3474 ui.write('\n')
3474 fmt = dfmtstr(max(avgchainlen, compratio))
3475 fmt = dfmtstr(max(avgchainlen, compratio))
3475 ui.write(('avg chain length : ') + fmt % avgchainlen)
3476 ui.write(('avg chain length : ') + fmt % avgchainlen)
3476 ui.write(('max chain length : ') + fmt % maxchainlen)
3477 ui.write(('max chain length : ') + fmt % maxchainlen)
3477 ui.write(('compression ratio : ') + fmt % compratio)
3478 ui.write(('compression ratio : ') + fmt % compratio)
3478
3479
3479 if format > 0:
3480 if format > 0:
3480 ui.write('\n')
3481 ui.write('\n')
3481 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3482 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3482 % tuple(datasize))
3483 % tuple(datasize))
3483 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3484 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3484 % tuple(fullsize))
3485 % tuple(fullsize))
3485 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3486 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3486 % tuple(deltasize))
3487 % tuple(deltasize))
3487
3488
3488 if numdeltas > 0:
3489 if numdeltas > 0:
3489 ui.write('\n')
3490 ui.write('\n')
3490 fmt = pcfmtstr(numdeltas)
3491 fmt = pcfmtstr(numdeltas)
3491 fmt2 = pcfmtstr(numdeltas, 4)
3492 fmt2 = pcfmtstr(numdeltas, 4)
3492 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3493 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3493 if numprev > 0:
3494 if numprev > 0:
3494 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3495 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3495 numprev))
3496 numprev))
3496 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3497 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3497 numprev))
3498 numprev))
3498 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3499 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3499 numprev))
3500 numprev))
3500 if gdelta:
3501 if gdelta:
3501 ui.write(('deltas against p1 : ')
3502 ui.write(('deltas against p1 : ')
3502 + fmt % pcfmt(nump1, numdeltas))
3503 + fmt % pcfmt(nump1, numdeltas))
3503 ui.write(('deltas against p2 : ')
3504 ui.write(('deltas against p2 : ')
3504 + fmt % pcfmt(nump2, numdeltas))
3505 + fmt % pcfmt(nump2, numdeltas))
3505 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3506 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3506 numdeltas))
3507 numdeltas))
3507
3508
3508 @command('debugrevspec',
3509 @command('debugrevspec',
3509 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3510 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3510 ('REVSPEC'))
3511 ('REVSPEC'))
3511 def debugrevspec(ui, repo, expr, **opts):
3512 def debugrevspec(ui, repo, expr, **opts):
3512 """parse and apply a revision specification
3513 """parse and apply a revision specification
3513
3514
3514 Use --verbose to print the parsed tree before and after aliases
3515 Use --verbose to print the parsed tree before and after aliases
3515 expansion.
3516 expansion.
3516 """
3517 """
3517 if ui.verbose:
3518 if ui.verbose:
3518 tree = revset.parse(expr, lookup=repo.__contains__)
3519 tree = revset.parse(expr, lookup=repo.__contains__)
3519 ui.note(revset.prettyformat(tree), "\n")
3520 ui.note(revset.prettyformat(tree), "\n")
3520 newtree = revset.expandaliases(ui, tree)
3521 newtree = revset.expandaliases(ui, tree)
3521 if newtree != tree:
3522 if newtree != tree:
3522 ui.note(("* expanded:\n"), revset.prettyformat(newtree), "\n")
3523 ui.note(("* expanded:\n"), revset.prettyformat(newtree), "\n")
3523 tree = newtree
3524 tree = newtree
3524 newtree = revset.foldconcat(tree)
3525 newtree = revset.foldconcat(tree)
3525 if newtree != tree:
3526 if newtree != tree:
3526 ui.note(("* concatenated:\n"), revset.prettyformat(newtree), "\n")
3527 ui.note(("* concatenated:\n"), revset.prettyformat(newtree), "\n")
3527 if opts["optimize"]:
3528 if opts["optimize"]:
3528 optimizedtree = revset.optimize(newtree)
3529 optimizedtree = revset.optimize(newtree)
3529 ui.note(("* optimized:\n"),
3530 ui.note(("* optimized:\n"),
3530 revset.prettyformat(optimizedtree), "\n")
3531 revset.prettyformat(optimizedtree), "\n")
3531 func = revset.match(ui, expr, repo)
3532 func = revset.match(ui, expr, repo)
3532 revs = func(repo)
3533 revs = func(repo)
3533 if ui.verbose:
3534 if ui.verbose:
3534 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3535 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3535 for c in revs:
3536 for c in revs:
3536 ui.write("%s\n" % c)
3537 ui.write("%s\n" % c)
3537
3538
3538 @command('debugsetparents', [], _('REV1 [REV2]'))
3539 @command('debugsetparents', [], _('REV1 [REV2]'))
3539 def debugsetparents(ui, repo, rev1, rev2=None):
3540 def debugsetparents(ui, repo, rev1, rev2=None):
3540 """manually set the parents of the current working directory
3541 """manually set the parents of the current working directory
3541
3542
3542 This is useful for writing repository conversion tools, but should
3543 This is useful for writing repository conversion tools, but should
3543 be used with care. For example, neither the working directory nor the
3544 be used with care. For example, neither the working directory nor the
3544 dirstate is updated, so file status may be incorrect after running this
3545 dirstate is updated, so file status may be incorrect after running this
3545 command.
3546 command.
3546
3547
3547 Returns 0 on success.
3548 Returns 0 on success.
3548 """
3549 """
3549
3550
3550 r1 = scmutil.revsingle(repo, rev1).node()
3551 r1 = scmutil.revsingle(repo, rev1).node()
3551 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3552 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3552
3553
3553 with repo.wlock():
3554 with repo.wlock():
3554 repo.setparents(r1, r2)
3555 repo.setparents(r1, r2)
3555
3556
3556 @command('debugdirstate|debugstate',
3557 @command('debugdirstate|debugstate',
3557 [('', 'nodates', None, _('do not display the saved mtime')),
3558 [('', 'nodates', None, _('do not display the saved mtime')),
3558 ('', 'datesort', None, _('sort by saved mtime'))],
3559 ('', 'datesort', None, _('sort by saved mtime'))],
3559 _('[OPTION]...'))
3560 _('[OPTION]...'))
3560 def debugstate(ui, repo, **opts):
3561 def debugstate(ui, repo, **opts):
3561 """show the contents of the current dirstate"""
3562 """show the contents of the current dirstate"""
3562
3563
3563 nodates = opts.get('nodates')
3564 nodates = opts.get('nodates')
3564 datesort = opts.get('datesort')
3565 datesort = opts.get('datesort')
3565
3566
3566 timestr = ""
3567 timestr = ""
3567 if datesort:
3568 if datesort:
3568 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3569 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3569 else:
3570 else:
3570 keyfunc = None # sort by filename
3571 keyfunc = None # sort by filename
3571 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3572 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3572 if ent[3] == -1:
3573 if ent[3] == -1:
3573 timestr = 'unset '
3574 timestr = 'unset '
3574 elif nodates:
3575 elif nodates:
3575 timestr = 'set '
3576 timestr = 'set '
3576 else:
3577 else:
3577 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3578 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3578 time.localtime(ent[3]))
3579 time.localtime(ent[3]))
3579 if ent[1] & 0o20000:
3580 if ent[1] & 0o20000:
3580 mode = 'lnk'
3581 mode = 'lnk'
3581 else:
3582 else:
3582 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3583 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3583 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3584 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3584 for f in repo.dirstate.copies():
3585 for f in repo.dirstate.copies():
3585 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3586 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3586
3587
3587 @command('debugsub',
3588 @command('debugsub',
3588 [('r', 'rev', '',
3589 [('r', 'rev', '',
3589 _('revision to check'), _('REV'))],
3590 _('revision to check'), _('REV'))],
3590 _('[-r REV] [REV]'))
3591 _('[-r REV] [REV]'))
3591 def debugsub(ui, repo, rev=None):
3592 def debugsub(ui, repo, rev=None):
3592 ctx = scmutil.revsingle(repo, rev, None)
3593 ctx = scmutil.revsingle(repo, rev, None)
3593 for k, v in sorted(ctx.substate.items()):
3594 for k, v in sorted(ctx.substate.items()):
3594 ui.write(('path %s\n') % k)
3595 ui.write(('path %s\n') % k)
3595 ui.write((' source %s\n') % v[0])
3596 ui.write((' source %s\n') % v[0])
3596 ui.write((' revision %s\n') % v[1])
3597 ui.write((' revision %s\n') % v[1])
3597
3598
3598 @command('debugsuccessorssets',
3599 @command('debugsuccessorssets',
3599 [],
3600 [],
3600 _('[REV]'))
3601 _('[REV]'))
3601 def debugsuccessorssets(ui, repo, *revs):
3602 def debugsuccessorssets(ui, repo, *revs):
3602 """show set of successors for revision
3603 """show set of successors for revision
3603
3604
3604 A successors set of changeset A is a consistent group of revisions that
3605 A successors set of changeset A is a consistent group of revisions that
3605 succeed A. It contains non-obsolete changesets only.
3606 succeed A. It contains non-obsolete changesets only.
3606
3607
3607 In most cases a changeset A has a single successors set containing a single
3608 In most cases a changeset A has a single successors set containing a single
3608 successor (changeset A replaced by A').
3609 successor (changeset A replaced by A').
3609
3610
3610 A changeset that is made obsolete with no successors are called "pruned".
3611 A changeset that is made obsolete with no successors are called "pruned".
3611 Such changesets have no successors sets at all.
3612 Such changesets have no successors sets at all.
3612
3613
3613 A changeset that has been "split" will have a successors set containing
3614 A changeset that has been "split" will have a successors set containing
3614 more than one successor.
3615 more than one successor.
3615
3616
3616 A changeset that has been rewritten in multiple different ways is called
3617 A changeset that has been rewritten in multiple different ways is called
3617 "divergent". Such changesets have multiple successor sets (each of which
3618 "divergent". Such changesets have multiple successor sets (each of which
3618 may also be split, i.e. have multiple successors).
3619 may also be split, i.e. have multiple successors).
3619
3620
3620 Results are displayed as follows::
3621 Results are displayed as follows::
3621
3622
3622 <rev1>
3623 <rev1>
3623 <successors-1A>
3624 <successors-1A>
3624 <rev2>
3625 <rev2>
3625 <successors-2A>
3626 <successors-2A>
3626 <successors-2B1> <successors-2B2> <successors-2B3>
3627 <successors-2B1> <successors-2B2> <successors-2B3>
3627
3628
3628 Here rev2 has two possible (i.e. divergent) successors sets. The first
3629 Here rev2 has two possible (i.e. divergent) successors sets. The first
3629 holds one element, whereas the second holds three (i.e. the changeset has
3630 holds one element, whereas the second holds three (i.e. the changeset has
3630 been split).
3631 been split).
3631 """
3632 """
3632 # passed to successorssets caching computation from one call to another
3633 # passed to successorssets caching computation from one call to another
3633 cache = {}
3634 cache = {}
3634 ctx2str = str
3635 ctx2str = str
3635 node2str = short
3636 node2str = short
3636 if ui.debug():
3637 if ui.debug():
3637 def ctx2str(ctx):
3638 def ctx2str(ctx):
3638 return ctx.hex()
3639 return ctx.hex()
3639 node2str = hex
3640 node2str = hex
3640 for rev in scmutil.revrange(repo, revs):
3641 for rev in scmutil.revrange(repo, revs):
3641 ctx = repo[rev]
3642 ctx = repo[rev]
3642 ui.write('%s\n'% ctx2str(ctx))
3643 ui.write('%s\n'% ctx2str(ctx))
3643 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3644 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3644 if succsset:
3645 if succsset:
3645 ui.write(' ')
3646 ui.write(' ')
3646 ui.write(node2str(succsset[0]))
3647 ui.write(node2str(succsset[0]))
3647 for node in succsset[1:]:
3648 for node in succsset[1:]:
3648 ui.write(' ')
3649 ui.write(' ')
3649 ui.write(node2str(node))
3650 ui.write(node2str(node))
3650 ui.write('\n')
3651 ui.write('\n')
3651
3652
3652 @command('debugtemplate',
3653 @command('debugtemplate',
3653 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3654 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3654 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3655 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3655 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3656 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3656 optionalrepo=True)
3657 optionalrepo=True)
3657 def debugtemplate(ui, repo, tmpl, **opts):
3658 def debugtemplate(ui, repo, tmpl, **opts):
3658 """parse and apply a template
3659 """parse and apply a template
3659
3660
3660 If -r/--rev is given, the template is processed as a log template and
3661 If -r/--rev is given, the template is processed as a log template and
3661 applied to the given changesets. Otherwise, it is processed as a generic
3662 applied to the given changesets. Otherwise, it is processed as a generic
3662 template.
3663 template.
3663
3664
3664 Use --verbose to print the parsed tree.
3665 Use --verbose to print the parsed tree.
3665 """
3666 """
3666 revs = None
3667 revs = None
3667 if opts['rev']:
3668 if opts['rev']:
3668 if repo is None:
3669 if repo is None:
3669 raise error.RepoError(_('there is no Mercurial repository here '
3670 raise error.RepoError(_('there is no Mercurial repository here '
3670 '(.hg not found)'))
3671 '(.hg not found)'))
3671 revs = scmutil.revrange(repo, opts['rev'])
3672 revs = scmutil.revrange(repo, opts['rev'])
3672
3673
3673 props = {}
3674 props = {}
3674 for d in opts['define']:
3675 for d in opts['define']:
3675 try:
3676 try:
3676 k, v = (e.strip() for e in d.split('=', 1))
3677 k, v = (e.strip() for e in d.split('=', 1))
3677 if not k:
3678 if not k:
3678 raise ValueError
3679 raise ValueError
3679 props[k] = v
3680 props[k] = v
3680 except ValueError:
3681 except ValueError:
3681 raise error.Abort(_('malformed keyword definition: %s') % d)
3682 raise error.Abort(_('malformed keyword definition: %s') % d)
3682
3683
3683 if ui.verbose:
3684 if ui.verbose:
3684 aliases = ui.configitems('templatealias')
3685 aliases = ui.configitems('templatealias')
3685 tree = templater.parse(tmpl)
3686 tree = templater.parse(tmpl)
3686 ui.note(templater.prettyformat(tree), '\n')
3687 ui.note(templater.prettyformat(tree), '\n')
3687 newtree = templater.expandaliases(tree, aliases)
3688 newtree = templater.expandaliases(tree, aliases)
3688 if newtree != tree:
3689 if newtree != tree:
3689 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3690 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3690
3691
3691 mapfile = None
3692 mapfile = None
3692 if revs is None:
3693 if revs is None:
3693 k = 'debugtemplate'
3694 k = 'debugtemplate'
3694 t = formatter.maketemplater(ui, k, tmpl)
3695 t = formatter.maketemplater(ui, k, tmpl)
3695 ui.write(templater.stringify(t(k, **props)))
3696 ui.write(templater.stringify(t(k, **props)))
3696 else:
3697 else:
3697 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3698 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3698 mapfile, buffered=False)
3699 mapfile, buffered=False)
3699 for r in revs:
3700 for r in revs:
3700 displayer.show(repo[r], **props)
3701 displayer.show(repo[r], **props)
3701 displayer.close()
3702 displayer.close()
3702
3703
3703 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3704 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3704 def debugwalk(ui, repo, *pats, **opts):
3705 def debugwalk(ui, repo, *pats, **opts):
3705 """show how files match on given patterns"""
3706 """show how files match on given patterns"""
3706 m = scmutil.match(repo[None], pats, opts)
3707 m = scmutil.match(repo[None], pats, opts)
3707 items = list(repo.walk(m))
3708 items = list(repo.walk(m))
3708 if not items:
3709 if not items:
3709 return
3710 return
3710 f = lambda fn: fn
3711 f = lambda fn: fn
3711 if ui.configbool('ui', 'slash') and os.sep != '/':
3712 if ui.configbool('ui', 'slash') and os.sep != '/':
3712 f = lambda fn: util.normpath(fn)
3713 f = lambda fn: util.normpath(fn)
3713 fmt = 'f %%-%ds %%-%ds %%s' % (
3714 fmt = 'f %%-%ds %%-%ds %%s' % (
3714 max([len(abs) for abs in items]),
3715 max([len(abs) for abs in items]),
3715 max([len(m.rel(abs)) for abs in items]))
3716 max([len(m.rel(abs)) for abs in items]))
3716 for abs in items:
3717 for abs in items:
3717 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3718 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3718 ui.write("%s\n" % line.rstrip())
3719 ui.write("%s\n" % line.rstrip())
3719
3720
3720 @command('debugwireargs',
3721 @command('debugwireargs',
3721 [('', 'three', '', 'three'),
3722 [('', 'three', '', 'three'),
3722 ('', 'four', '', 'four'),
3723 ('', 'four', '', 'four'),
3723 ('', 'five', '', 'five'),
3724 ('', 'five', '', 'five'),
3724 ] + remoteopts,
3725 ] + remoteopts,
3725 _('REPO [OPTIONS]... [ONE [TWO]]'),
3726 _('REPO [OPTIONS]... [ONE [TWO]]'),
3726 norepo=True)
3727 norepo=True)
3727 def debugwireargs(ui, repopath, *vals, **opts):
3728 def debugwireargs(ui, repopath, *vals, **opts):
3728 repo = hg.peer(ui, opts, repopath)
3729 repo = hg.peer(ui, opts, repopath)
3729 for opt in remoteopts:
3730 for opt in remoteopts:
3730 del opts[opt[1]]
3731 del opts[opt[1]]
3731 args = {}
3732 args = {}
3732 for k, v in opts.iteritems():
3733 for k, v in opts.iteritems():
3733 if v:
3734 if v:
3734 args[k] = v
3735 args[k] = v
3735 # run twice to check that we don't mess up the stream for the next command
3736 # run twice to check that we don't mess up the stream for the next command
3736 res1 = repo.debugwireargs(*vals, **args)
3737 res1 = repo.debugwireargs(*vals, **args)
3737 res2 = repo.debugwireargs(*vals, **args)
3738 res2 = repo.debugwireargs(*vals, **args)
3738 ui.write("%s\n" % res1)
3739 ui.write("%s\n" % res1)
3739 if res1 != res2:
3740 if res1 != res2:
3740 ui.warn("%s\n" % res2)
3741 ui.warn("%s\n" % res2)
3741
3742
3742 @command('^diff',
3743 @command('^diff',
3743 [('r', 'rev', [], _('revision'), _('REV')),
3744 [('r', 'rev', [], _('revision'), _('REV')),
3744 ('c', 'change', '', _('change made by revision'), _('REV'))
3745 ('c', 'change', '', _('change made by revision'), _('REV'))
3745 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3746 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3746 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3747 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3747 inferrepo=True)
3748 inferrepo=True)
3748 def diff(ui, repo, *pats, **opts):
3749 def diff(ui, repo, *pats, **opts):
3749 """diff repository (or selected files)
3750 """diff repository (or selected files)
3750
3751
3751 Show differences between revisions for the specified files.
3752 Show differences between revisions for the specified files.
3752
3753
3753 Differences between files are shown using the unified diff format.
3754 Differences between files are shown using the unified diff format.
3754
3755
3755 .. note::
3756 .. note::
3756
3757
3757 :hg:`diff` may generate unexpected results for merges, as it will
3758 :hg:`diff` may generate unexpected results for merges, as it will
3758 default to comparing against the working directory's first
3759 default to comparing against the working directory's first
3759 parent changeset if no revisions are specified.
3760 parent changeset if no revisions are specified.
3760
3761
3761 When two revision arguments are given, then changes are shown
3762 When two revision arguments are given, then changes are shown
3762 between those revisions. If only one revision is specified then
3763 between those revisions. If only one revision is specified then
3763 that revision is compared to the working directory, and, when no
3764 that revision is compared to the working directory, and, when no
3764 revisions are specified, the working directory files are compared
3765 revisions are specified, the working directory files are compared
3765 to its first parent.
3766 to its first parent.
3766
3767
3767 Alternatively you can specify -c/--change with a revision to see
3768 Alternatively you can specify -c/--change with a revision to see
3768 the changes in that changeset relative to its first parent.
3769 the changes in that changeset relative to its first parent.
3769
3770
3770 Without the -a/--text option, diff will avoid generating diffs of
3771 Without the -a/--text option, diff will avoid generating diffs of
3771 files it detects as binary. With -a, diff will generate a diff
3772 files it detects as binary. With -a, diff will generate a diff
3772 anyway, probably with undesirable results.
3773 anyway, probably with undesirable results.
3773
3774
3774 Use the -g/--git option to generate diffs in the git extended diff
3775 Use the -g/--git option to generate diffs in the git extended diff
3775 format. For more information, read :hg:`help diffs`.
3776 format. For more information, read :hg:`help diffs`.
3776
3777
3777 .. container:: verbose
3778 .. container:: verbose
3778
3779
3779 Examples:
3780 Examples:
3780
3781
3781 - compare a file in the current working directory to its parent::
3782 - compare a file in the current working directory to its parent::
3782
3783
3783 hg diff foo.c
3784 hg diff foo.c
3784
3785
3785 - compare two historical versions of a directory, with rename info::
3786 - compare two historical versions of a directory, with rename info::
3786
3787
3787 hg diff --git -r 1.0:1.2 lib/
3788 hg diff --git -r 1.0:1.2 lib/
3788
3789
3789 - get change stats relative to the last change on some date::
3790 - get change stats relative to the last change on some date::
3790
3791
3791 hg diff --stat -r "date('may 2')"
3792 hg diff --stat -r "date('may 2')"
3792
3793
3793 - diff all newly-added files that contain a keyword::
3794 - diff all newly-added files that contain a keyword::
3794
3795
3795 hg diff "set:added() and grep(GNU)"
3796 hg diff "set:added() and grep(GNU)"
3796
3797
3797 - compare a revision and its parents::
3798 - compare a revision and its parents::
3798
3799
3799 hg diff -c 9353 # compare against first parent
3800 hg diff -c 9353 # compare against first parent
3800 hg diff -r 9353^:9353 # same using revset syntax
3801 hg diff -r 9353^:9353 # same using revset syntax
3801 hg diff -r 9353^2:9353 # compare against the second parent
3802 hg diff -r 9353^2:9353 # compare against the second parent
3802
3803
3803 Returns 0 on success.
3804 Returns 0 on success.
3804 """
3805 """
3805
3806
3806 revs = opts.get('rev')
3807 revs = opts.get('rev')
3807 change = opts.get('change')
3808 change = opts.get('change')
3808 stat = opts.get('stat')
3809 stat = opts.get('stat')
3809 reverse = opts.get('reverse')
3810 reverse = opts.get('reverse')
3810
3811
3811 if revs and change:
3812 if revs and change:
3812 msg = _('cannot specify --rev and --change at the same time')
3813 msg = _('cannot specify --rev and --change at the same time')
3813 raise error.Abort(msg)
3814 raise error.Abort(msg)
3814 elif change:
3815 elif change:
3815 node2 = scmutil.revsingle(repo, change, None).node()
3816 node2 = scmutil.revsingle(repo, change, None).node()
3816 node1 = repo[node2].p1().node()
3817 node1 = repo[node2].p1().node()
3817 else:
3818 else:
3818 node1, node2 = scmutil.revpair(repo, revs)
3819 node1, node2 = scmutil.revpair(repo, revs)
3819
3820
3820 if reverse:
3821 if reverse:
3821 node1, node2 = node2, node1
3822 node1, node2 = node2, node1
3822
3823
3823 diffopts = patch.diffallopts(ui, opts)
3824 diffopts = patch.diffallopts(ui, opts)
3824 m = scmutil.match(repo[node2], pats, opts)
3825 m = scmutil.match(repo[node2], pats, opts)
3825 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3826 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3826 listsubrepos=opts.get('subrepos'),
3827 listsubrepos=opts.get('subrepos'),
3827 root=opts.get('root'))
3828 root=opts.get('root'))
3828
3829
3829 @command('^export',
3830 @command('^export',
3830 [('o', 'output', '',
3831 [('o', 'output', '',
3831 _('print output to file with formatted name'), _('FORMAT')),
3832 _('print output to file with formatted name'), _('FORMAT')),
3832 ('', 'switch-parent', None, _('diff against the second parent')),
3833 ('', 'switch-parent', None, _('diff against the second parent')),
3833 ('r', 'rev', [], _('revisions to export'), _('REV')),
3834 ('r', 'rev', [], _('revisions to export'), _('REV')),
3834 ] + diffopts,
3835 ] + diffopts,
3835 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3836 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3836 def export(ui, repo, *changesets, **opts):
3837 def export(ui, repo, *changesets, **opts):
3837 """dump the header and diffs for one or more changesets
3838 """dump the header and diffs for one or more changesets
3838
3839
3839 Print the changeset header and diffs for one or more revisions.
3840 Print the changeset header and diffs for one or more revisions.
3840 If no revision is given, the parent of the working directory is used.
3841 If no revision is given, the parent of the working directory is used.
3841
3842
3842 The information shown in the changeset header is: author, date,
3843 The information shown in the changeset header is: author, date,
3843 branch name (if non-default), changeset hash, parent(s) and commit
3844 branch name (if non-default), changeset hash, parent(s) and commit
3844 comment.
3845 comment.
3845
3846
3846 .. note::
3847 .. note::
3847
3848
3848 :hg:`export` may generate unexpected diff output for merge
3849 :hg:`export` may generate unexpected diff output for merge
3849 changesets, as it will compare the merge changeset against its
3850 changesets, as it will compare the merge changeset against its
3850 first parent only.
3851 first parent only.
3851
3852
3852 Output may be to a file, in which case the name of the file is
3853 Output may be to a file, in which case the name of the file is
3853 given using a format string. The formatting rules are as follows:
3854 given using a format string. The formatting rules are as follows:
3854
3855
3855 :``%%``: literal "%" character
3856 :``%%``: literal "%" character
3856 :``%H``: changeset hash (40 hexadecimal digits)
3857 :``%H``: changeset hash (40 hexadecimal digits)
3857 :``%N``: number of patches being generated
3858 :``%N``: number of patches being generated
3858 :``%R``: changeset revision number
3859 :``%R``: changeset revision number
3859 :``%b``: basename of the exporting repository
3860 :``%b``: basename of the exporting repository
3860 :``%h``: short-form changeset hash (12 hexadecimal digits)
3861 :``%h``: short-form changeset hash (12 hexadecimal digits)
3861 :``%m``: first line of the commit message (only alphanumeric characters)
3862 :``%m``: first line of the commit message (only alphanumeric characters)
3862 :``%n``: zero-padded sequence number, starting at 1
3863 :``%n``: zero-padded sequence number, starting at 1
3863 :``%r``: zero-padded changeset revision number
3864 :``%r``: zero-padded changeset revision number
3864
3865
3865 Without the -a/--text option, export will avoid generating diffs
3866 Without the -a/--text option, export will avoid generating diffs
3866 of files it detects as binary. With -a, export will generate a
3867 of files it detects as binary. With -a, export will generate a
3867 diff anyway, probably with undesirable results.
3868 diff anyway, probably with undesirable results.
3868
3869
3869 Use the -g/--git option to generate diffs in the git extended diff
3870 Use the -g/--git option to generate diffs in the git extended diff
3870 format. See :hg:`help diffs` for more information.
3871 format. See :hg:`help diffs` for more information.
3871
3872
3872 With the --switch-parent option, the diff will be against the
3873 With the --switch-parent option, the diff will be against the
3873 second parent. It can be useful to review a merge.
3874 second parent. It can be useful to review a merge.
3874
3875
3875 .. container:: verbose
3876 .. container:: verbose
3876
3877
3877 Examples:
3878 Examples:
3878
3879
3879 - use export and import to transplant a bugfix to the current
3880 - use export and import to transplant a bugfix to the current
3880 branch::
3881 branch::
3881
3882
3882 hg export -r 9353 | hg import -
3883 hg export -r 9353 | hg import -
3883
3884
3884 - export all the changesets between two revisions to a file with
3885 - export all the changesets between two revisions to a file with
3885 rename information::
3886 rename information::
3886
3887
3887 hg export --git -r 123:150 > changes.txt
3888 hg export --git -r 123:150 > changes.txt
3888
3889
3889 - split outgoing changes into a series of patches with
3890 - split outgoing changes into a series of patches with
3890 descriptive names::
3891 descriptive names::
3891
3892
3892 hg export -r "outgoing()" -o "%n-%m.patch"
3893 hg export -r "outgoing()" -o "%n-%m.patch"
3893
3894
3894 Returns 0 on success.
3895 Returns 0 on success.
3895 """
3896 """
3896 changesets += tuple(opts.get('rev', []))
3897 changesets += tuple(opts.get('rev', []))
3897 if not changesets:
3898 if not changesets:
3898 changesets = ['.']
3899 changesets = ['.']
3899 revs = scmutil.revrange(repo, changesets)
3900 revs = scmutil.revrange(repo, changesets)
3900 if not revs:
3901 if not revs:
3901 raise error.Abort(_("export requires at least one changeset"))
3902 raise error.Abort(_("export requires at least one changeset"))
3902 if len(revs) > 1:
3903 if len(revs) > 1:
3903 ui.note(_('exporting patches:\n'))
3904 ui.note(_('exporting patches:\n'))
3904 else:
3905 else:
3905 ui.note(_('exporting patch:\n'))
3906 ui.note(_('exporting patch:\n'))
3906 cmdutil.export(repo, revs, template=opts.get('output'),
3907 cmdutil.export(repo, revs, template=opts.get('output'),
3907 switch_parent=opts.get('switch_parent'),
3908 switch_parent=opts.get('switch_parent'),
3908 opts=patch.diffallopts(ui, opts))
3909 opts=patch.diffallopts(ui, opts))
3909
3910
3910 @command('files',
3911 @command('files',
3911 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3912 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3912 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3913 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3913 ] + walkopts + formatteropts + subrepoopts,
3914 ] + walkopts + formatteropts + subrepoopts,
3914 _('[OPTION]... [PATTERN]...'))
3915 _('[OPTION]... [PATTERN]...'))
3915 def files(ui, repo, *pats, **opts):
3916 def files(ui, repo, *pats, **opts):
3916 """list tracked files
3917 """list tracked files
3917
3918
3918 Print files under Mercurial control in the working directory or
3919 Print files under Mercurial control in the working directory or
3919 specified revision whose names match the given patterns (excluding
3920 specified revision whose names match the given patterns (excluding
3920 removed files).
3921 removed files).
3921
3922
3922 If no patterns are given to match, this command prints the names
3923 If no patterns are given to match, this command prints the names
3923 of all files under Mercurial control in the working directory.
3924 of all files under Mercurial control in the working directory.
3924
3925
3925 .. container:: verbose
3926 .. container:: verbose
3926
3927
3927 Examples:
3928 Examples:
3928
3929
3929 - list all files under the current directory::
3930 - list all files under the current directory::
3930
3931
3931 hg files .
3932 hg files .
3932
3933
3933 - shows sizes and flags for current revision::
3934 - shows sizes and flags for current revision::
3934
3935
3935 hg files -vr .
3936 hg files -vr .
3936
3937
3937 - list all files named README::
3938 - list all files named README::
3938
3939
3939 hg files -I "**/README"
3940 hg files -I "**/README"
3940
3941
3941 - list all binary files::
3942 - list all binary files::
3942
3943
3943 hg files "set:binary()"
3944 hg files "set:binary()"
3944
3945
3945 - find files containing a regular expression::
3946 - find files containing a regular expression::
3946
3947
3947 hg files "set:grep('bob')"
3948 hg files "set:grep('bob')"
3948
3949
3949 - search tracked file contents with xargs and grep::
3950 - search tracked file contents with xargs and grep::
3950
3951
3951 hg files -0 | xargs -0 grep foo
3952 hg files -0 | xargs -0 grep foo
3952
3953
3953 See :hg:`help patterns` and :hg:`help filesets` for more information
3954 See :hg:`help patterns` and :hg:`help filesets` for more information
3954 on specifying file patterns.
3955 on specifying file patterns.
3955
3956
3956 Returns 0 if a match is found, 1 otherwise.
3957 Returns 0 if a match is found, 1 otherwise.
3957
3958
3958 """
3959 """
3959 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3960 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3960
3961
3961 end = '\n'
3962 end = '\n'
3962 if opts.get('print0'):
3963 if opts.get('print0'):
3963 end = '\0'
3964 end = '\0'
3964 fm = ui.formatter('files', opts)
3965 fm = ui.formatter('files', opts)
3965 fmt = '%s' + end
3966 fmt = '%s' + end
3966
3967
3967 m = scmutil.match(ctx, pats, opts)
3968 m = scmutil.match(ctx, pats, opts)
3968 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3969 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3969
3970
3970 fm.end()
3971 fm.end()
3971
3972
3972 return ret
3973 return ret
3973
3974
3974 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3975 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3975 def forget(ui, repo, *pats, **opts):
3976 def forget(ui, repo, *pats, **opts):
3976 """forget the specified files on the next commit
3977 """forget the specified files on the next commit
3977
3978
3978 Mark the specified files so they will no longer be tracked
3979 Mark the specified files so they will no longer be tracked
3979 after the next commit.
3980 after the next commit.
3980
3981
3981 This only removes files from the current branch, not from the
3982 This only removes files from the current branch, not from the
3982 entire project history, and it does not delete them from the
3983 entire project history, and it does not delete them from the
3983 working directory.
3984 working directory.
3984
3985
3985 To delete the file from the working directory, see :hg:`remove`.
3986 To delete the file from the working directory, see :hg:`remove`.
3986
3987
3987 To undo a forget before the next commit, see :hg:`add`.
3988 To undo a forget before the next commit, see :hg:`add`.
3988
3989
3989 .. container:: verbose
3990 .. container:: verbose
3990
3991
3991 Examples:
3992 Examples:
3992
3993
3993 - forget newly-added binary files::
3994 - forget newly-added binary files::
3994
3995
3995 hg forget "set:added() and binary()"
3996 hg forget "set:added() and binary()"
3996
3997
3997 - forget files that would be excluded by .hgignore::
3998 - forget files that would be excluded by .hgignore::
3998
3999
3999 hg forget "set:hgignore()"
4000 hg forget "set:hgignore()"
4000
4001
4001 Returns 0 on success.
4002 Returns 0 on success.
4002 """
4003 """
4003
4004
4004 if not pats:
4005 if not pats:
4005 raise error.Abort(_('no files specified'))
4006 raise error.Abort(_('no files specified'))
4006
4007
4007 m = scmutil.match(repo[None], pats, opts)
4008 m = scmutil.match(repo[None], pats, opts)
4008 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4009 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4009 return rejected and 1 or 0
4010 return rejected and 1 or 0
4010
4011
4011 @command(
4012 @command(
4012 'graft',
4013 'graft',
4013 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4014 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4014 ('c', 'continue', False, _('resume interrupted graft')),
4015 ('c', 'continue', False, _('resume interrupted graft')),
4015 ('e', 'edit', False, _('invoke editor on commit messages')),
4016 ('e', 'edit', False, _('invoke editor on commit messages')),
4016 ('', 'log', None, _('append graft info to log message')),
4017 ('', 'log', None, _('append graft info to log message')),
4017 ('f', 'force', False, _('force graft')),
4018 ('f', 'force', False, _('force graft')),
4018 ('D', 'currentdate', False,
4019 ('D', 'currentdate', False,
4019 _('record the current date as commit date')),
4020 _('record the current date as commit date')),
4020 ('U', 'currentuser', False,
4021 ('U', 'currentuser', False,
4021 _('record the current user as committer'), _('DATE'))]
4022 _('record the current user as committer'), _('DATE'))]
4022 + commitopts2 + mergetoolopts + dryrunopts,
4023 + commitopts2 + mergetoolopts + dryrunopts,
4023 _('[OPTION]... [-r REV]... REV...'))
4024 _('[OPTION]... [-r REV]... REV...'))
4024 def graft(ui, repo, *revs, **opts):
4025 def graft(ui, repo, *revs, **opts):
4025 '''copy changes from other branches onto the current branch
4026 '''copy changes from other branches onto the current branch
4026
4027
4027 This command uses Mercurial's merge logic to copy individual
4028 This command uses Mercurial's merge logic to copy individual
4028 changes from other branches without merging branches in the
4029 changes from other branches without merging branches in the
4029 history graph. This is sometimes known as 'backporting' or
4030 history graph. This is sometimes known as 'backporting' or
4030 'cherry-picking'. By default, graft will copy user, date, and
4031 'cherry-picking'. By default, graft will copy user, date, and
4031 description from the source changesets.
4032 description from the source changesets.
4032
4033
4033 Changesets that are ancestors of the current revision, that have
4034 Changesets that are ancestors of the current revision, that have
4034 already been grafted, or that are merges will be skipped.
4035 already been grafted, or that are merges will be skipped.
4035
4036
4036 If --log is specified, log messages will have a comment appended
4037 If --log is specified, log messages will have a comment appended
4037 of the form::
4038 of the form::
4038
4039
4039 (grafted from CHANGESETHASH)
4040 (grafted from CHANGESETHASH)
4040
4041
4041 If --force is specified, revisions will be grafted even if they
4042 If --force is specified, revisions will be grafted even if they
4042 are already ancestors of or have been grafted to the destination.
4043 are already ancestors of or have been grafted to the destination.
4043 This is useful when the revisions have since been backed out.
4044 This is useful when the revisions have since been backed out.
4044
4045
4045 If a graft merge results in conflicts, the graft process is
4046 If a graft merge results in conflicts, the graft process is
4046 interrupted so that the current merge can be manually resolved.
4047 interrupted so that the current merge can be manually resolved.
4047 Once all conflicts are addressed, the graft process can be
4048 Once all conflicts are addressed, the graft process can be
4048 continued with the -c/--continue option.
4049 continued with the -c/--continue option.
4049
4050
4050 .. note::
4051 .. note::
4051
4052
4052 The -c/--continue option does not reapply earlier options, except
4053 The -c/--continue option does not reapply earlier options, except
4053 for --force.
4054 for --force.
4054
4055
4055 .. container:: verbose
4056 .. container:: verbose
4056
4057
4057 Examples:
4058 Examples:
4058
4059
4059 - copy a single change to the stable branch and edit its description::
4060 - copy a single change to the stable branch and edit its description::
4060
4061
4061 hg update stable
4062 hg update stable
4062 hg graft --edit 9393
4063 hg graft --edit 9393
4063
4064
4064 - graft a range of changesets with one exception, updating dates::
4065 - graft a range of changesets with one exception, updating dates::
4065
4066
4066 hg graft -D "2085::2093 and not 2091"
4067 hg graft -D "2085::2093 and not 2091"
4067
4068
4068 - continue a graft after resolving conflicts::
4069 - continue a graft after resolving conflicts::
4069
4070
4070 hg graft -c
4071 hg graft -c
4071
4072
4072 - show the source of a grafted changeset::
4073 - show the source of a grafted changeset::
4073
4074
4074 hg log --debug -r .
4075 hg log --debug -r .
4075
4076
4076 - show revisions sorted by date::
4077 - show revisions sorted by date::
4077
4078
4078 hg log -r "sort(all(), date)"
4079 hg log -r "sort(all(), date)"
4079
4080
4080 See :hg:`help revisions` and :hg:`help revsets` for more about
4081 See :hg:`help revisions` and :hg:`help revsets` for more about
4081 specifying revisions.
4082 specifying revisions.
4082
4083
4083 Returns 0 on successful completion.
4084 Returns 0 on successful completion.
4084 '''
4085 '''
4085 with repo.wlock():
4086 with repo.wlock():
4086 return _dograft(ui, repo, *revs, **opts)
4087 return _dograft(ui, repo, *revs, **opts)
4087
4088
4088 def _dograft(ui, repo, *revs, **opts):
4089 def _dograft(ui, repo, *revs, **opts):
4089 if revs and opts.get('rev'):
4090 if revs and opts.get('rev'):
4090 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4091 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4091 'revision ordering!\n'))
4092 'revision ordering!\n'))
4092
4093
4093 revs = list(revs)
4094 revs = list(revs)
4094 revs.extend(opts.get('rev'))
4095 revs.extend(opts.get('rev'))
4095
4096
4096 if not opts.get('user') and opts.get('currentuser'):
4097 if not opts.get('user') and opts.get('currentuser'):
4097 opts['user'] = ui.username()
4098 opts['user'] = ui.username()
4098 if not opts.get('date') and opts.get('currentdate'):
4099 if not opts.get('date') and opts.get('currentdate'):
4099 opts['date'] = "%d %d" % util.makedate()
4100 opts['date'] = "%d %d" % util.makedate()
4100
4101
4101 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4102 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4102
4103
4103 cont = False
4104 cont = False
4104 if opts.get('continue'):
4105 if opts.get('continue'):
4105 cont = True
4106 cont = True
4106 if revs:
4107 if revs:
4107 raise error.Abort(_("can't specify --continue and revisions"))
4108 raise error.Abort(_("can't specify --continue and revisions"))
4108 # read in unfinished revisions
4109 # read in unfinished revisions
4109 try:
4110 try:
4110 nodes = repo.vfs.read('graftstate').splitlines()
4111 nodes = repo.vfs.read('graftstate').splitlines()
4111 revs = [repo[node].rev() for node in nodes]
4112 revs = [repo[node].rev() for node in nodes]
4112 except IOError as inst:
4113 except IOError as inst:
4113 if inst.errno != errno.ENOENT:
4114 if inst.errno != errno.ENOENT:
4114 raise
4115 raise
4115 cmdutil.wrongtooltocontinue(repo, _('graft'))
4116 cmdutil.wrongtooltocontinue(repo, _('graft'))
4116 else:
4117 else:
4117 cmdutil.checkunfinished(repo)
4118 cmdutil.checkunfinished(repo)
4118 cmdutil.bailifchanged(repo)
4119 cmdutil.bailifchanged(repo)
4119 if not revs:
4120 if not revs:
4120 raise error.Abort(_('no revisions specified'))
4121 raise error.Abort(_('no revisions specified'))
4121 revs = scmutil.revrange(repo, revs)
4122 revs = scmutil.revrange(repo, revs)
4122
4123
4123 skipped = set()
4124 skipped = set()
4124 # check for merges
4125 # check for merges
4125 for rev in repo.revs('%ld and merge()', revs):
4126 for rev in repo.revs('%ld and merge()', revs):
4126 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4127 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4127 skipped.add(rev)
4128 skipped.add(rev)
4128 revs = [r for r in revs if r not in skipped]
4129 revs = [r for r in revs if r not in skipped]
4129 if not revs:
4130 if not revs:
4130 return -1
4131 return -1
4131
4132
4132 # Don't check in the --continue case, in effect retaining --force across
4133 # Don't check in the --continue case, in effect retaining --force across
4133 # --continues. That's because without --force, any revisions we decided to
4134 # --continues. That's because without --force, any revisions we decided to
4134 # skip would have been filtered out here, so they wouldn't have made their
4135 # skip would have been filtered out here, so they wouldn't have made their
4135 # way to the graftstate. With --force, any revisions we would have otherwise
4136 # way to the graftstate. With --force, any revisions we would have otherwise
4136 # skipped would not have been filtered out, and if they hadn't been applied
4137 # skipped would not have been filtered out, and if they hadn't been applied
4137 # already, they'd have been in the graftstate.
4138 # already, they'd have been in the graftstate.
4138 if not (cont or opts.get('force')):
4139 if not (cont or opts.get('force')):
4139 # check for ancestors of dest branch
4140 # check for ancestors of dest branch
4140 crev = repo['.'].rev()
4141 crev = repo['.'].rev()
4141 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4142 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4142 # Cannot use x.remove(y) on smart set, this has to be a list.
4143 # Cannot use x.remove(y) on smart set, this has to be a list.
4143 # XXX make this lazy in the future
4144 # XXX make this lazy in the future
4144 revs = list(revs)
4145 revs = list(revs)
4145 # don't mutate while iterating, create a copy
4146 # don't mutate while iterating, create a copy
4146 for rev in list(revs):
4147 for rev in list(revs):
4147 if rev in ancestors:
4148 if rev in ancestors:
4148 ui.warn(_('skipping ancestor revision %d:%s\n') %
4149 ui.warn(_('skipping ancestor revision %d:%s\n') %
4149 (rev, repo[rev]))
4150 (rev, repo[rev]))
4150 # XXX remove on list is slow
4151 # XXX remove on list is slow
4151 revs.remove(rev)
4152 revs.remove(rev)
4152 if not revs:
4153 if not revs:
4153 return -1
4154 return -1
4154
4155
4155 # analyze revs for earlier grafts
4156 # analyze revs for earlier grafts
4156 ids = {}
4157 ids = {}
4157 for ctx in repo.set("%ld", revs):
4158 for ctx in repo.set("%ld", revs):
4158 ids[ctx.hex()] = ctx.rev()
4159 ids[ctx.hex()] = ctx.rev()
4159 n = ctx.extra().get('source')
4160 n = ctx.extra().get('source')
4160 if n:
4161 if n:
4161 ids[n] = ctx.rev()
4162 ids[n] = ctx.rev()
4162
4163
4163 # check ancestors for earlier grafts
4164 # check ancestors for earlier grafts
4164 ui.debug('scanning for duplicate grafts\n')
4165 ui.debug('scanning for duplicate grafts\n')
4165
4166
4166 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4167 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4167 ctx = repo[rev]
4168 ctx = repo[rev]
4168 n = ctx.extra().get('source')
4169 n = ctx.extra().get('source')
4169 if n in ids:
4170 if n in ids:
4170 try:
4171 try:
4171 r = repo[n].rev()
4172 r = repo[n].rev()
4172 except error.RepoLookupError:
4173 except error.RepoLookupError:
4173 r = None
4174 r = None
4174 if r in revs:
4175 if r in revs:
4175 ui.warn(_('skipping revision %d:%s '
4176 ui.warn(_('skipping revision %d:%s '
4176 '(already grafted to %d:%s)\n')
4177 '(already grafted to %d:%s)\n')
4177 % (r, repo[r], rev, ctx))
4178 % (r, repo[r], rev, ctx))
4178 revs.remove(r)
4179 revs.remove(r)
4179 elif ids[n] in revs:
4180 elif ids[n] in revs:
4180 if r is None:
4181 if r is None:
4181 ui.warn(_('skipping already grafted revision %d:%s '
4182 ui.warn(_('skipping already grafted revision %d:%s '
4182 '(%d:%s also has unknown origin %s)\n')
4183 '(%d:%s also has unknown origin %s)\n')
4183 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4184 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4184 else:
4185 else:
4185 ui.warn(_('skipping already grafted revision %d:%s '
4186 ui.warn(_('skipping already grafted revision %d:%s '
4186 '(%d:%s also has origin %d:%s)\n')
4187 '(%d:%s also has origin %d:%s)\n')
4187 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4188 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4188 revs.remove(ids[n])
4189 revs.remove(ids[n])
4189 elif ctx.hex() in ids:
4190 elif ctx.hex() in ids:
4190 r = ids[ctx.hex()]
4191 r = ids[ctx.hex()]
4191 ui.warn(_('skipping already grafted revision %d:%s '
4192 ui.warn(_('skipping already grafted revision %d:%s '
4192 '(was grafted from %d:%s)\n') %
4193 '(was grafted from %d:%s)\n') %
4193 (r, repo[r], rev, ctx))
4194 (r, repo[r], rev, ctx))
4194 revs.remove(r)
4195 revs.remove(r)
4195 if not revs:
4196 if not revs:
4196 return -1
4197 return -1
4197
4198
4198 for pos, ctx in enumerate(repo.set("%ld", revs)):
4199 for pos, ctx in enumerate(repo.set("%ld", revs)):
4199 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4200 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4200 ctx.description().split('\n', 1)[0])
4201 ctx.description().split('\n', 1)[0])
4201 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4202 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4202 if names:
4203 if names:
4203 desc += ' (%s)' % ' '.join(names)
4204 desc += ' (%s)' % ' '.join(names)
4204 ui.status(_('grafting %s\n') % desc)
4205 ui.status(_('grafting %s\n') % desc)
4205 if opts.get('dry_run'):
4206 if opts.get('dry_run'):
4206 continue
4207 continue
4207
4208
4208 source = ctx.extra().get('source')
4209 source = ctx.extra().get('source')
4209 extra = {}
4210 extra = {}
4210 if source:
4211 if source:
4211 extra['source'] = source
4212 extra['source'] = source
4212 extra['intermediate-source'] = ctx.hex()
4213 extra['intermediate-source'] = ctx.hex()
4213 else:
4214 else:
4214 extra['source'] = ctx.hex()
4215 extra['source'] = ctx.hex()
4215 user = ctx.user()
4216 user = ctx.user()
4216 if opts.get('user'):
4217 if opts.get('user'):
4217 user = opts['user']
4218 user = opts['user']
4218 date = ctx.date()
4219 date = ctx.date()
4219 if opts.get('date'):
4220 if opts.get('date'):
4220 date = opts['date']
4221 date = opts['date']
4221 message = ctx.description()
4222 message = ctx.description()
4222 if opts.get('log'):
4223 if opts.get('log'):
4223 message += '\n(grafted from %s)' % ctx.hex()
4224 message += '\n(grafted from %s)' % ctx.hex()
4224
4225
4225 # we don't merge the first commit when continuing
4226 # we don't merge the first commit when continuing
4226 if not cont:
4227 if not cont:
4227 # perform the graft merge with p1(rev) as 'ancestor'
4228 # perform the graft merge with p1(rev) as 'ancestor'
4228 try:
4229 try:
4229 # ui.forcemerge is an internal variable, do not document
4230 # ui.forcemerge is an internal variable, do not document
4230 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4231 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4231 'graft')
4232 'graft')
4232 stats = mergemod.graft(repo, ctx, ctx.p1(),
4233 stats = mergemod.graft(repo, ctx, ctx.p1(),
4233 ['local', 'graft'])
4234 ['local', 'graft'])
4234 finally:
4235 finally:
4235 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4236 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4236 # report any conflicts
4237 # report any conflicts
4237 if stats and stats[3] > 0:
4238 if stats and stats[3] > 0:
4238 # write out state for --continue
4239 # write out state for --continue
4239 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4240 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4240 repo.vfs.write('graftstate', ''.join(nodelines))
4241 repo.vfs.write('graftstate', ''.join(nodelines))
4241 extra = ''
4242 extra = ''
4242 if opts.get('user'):
4243 if opts.get('user'):
4243 extra += ' --user %s' % util.shellquote(opts['user'])
4244 extra += ' --user %s' % util.shellquote(opts['user'])
4244 if opts.get('date'):
4245 if opts.get('date'):
4245 extra += ' --date %s' % util.shellquote(opts['date'])
4246 extra += ' --date %s' % util.shellquote(opts['date'])
4246 if opts.get('log'):
4247 if opts.get('log'):
4247 extra += ' --log'
4248 extra += ' --log'
4248 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4249 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4249 raise error.Abort(
4250 raise error.Abort(
4250 _("unresolved conflicts, can't continue"),
4251 _("unresolved conflicts, can't continue"),
4251 hint=hint)
4252 hint=hint)
4252 else:
4253 else:
4253 cont = False
4254 cont = False
4254
4255
4255 # commit
4256 # commit
4256 node = repo.commit(text=message, user=user,
4257 node = repo.commit(text=message, user=user,
4257 date=date, extra=extra, editor=editor)
4258 date=date, extra=extra, editor=editor)
4258 if node is None:
4259 if node is None:
4259 ui.warn(
4260 ui.warn(
4260 _('note: graft of %d:%s created no changes to commit\n') %
4261 _('note: graft of %d:%s created no changes to commit\n') %
4261 (ctx.rev(), ctx))
4262 (ctx.rev(), ctx))
4262
4263
4263 # remove state when we complete successfully
4264 # remove state when we complete successfully
4264 if not opts.get('dry_run'):
4265 if not opts.get('dry_run'):
4265 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4266 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4266
4267
4267 return 0
4268 return 0
4268
4269
4269 @command('grep',
4270 @command('grep',
4270 [('0', 'print0', None, _('end fields with NUL')),
4271 [('0', 'print0', None, _('end fields with NUL')),
4271 ('', 'all', None, _('print all revisions that match')),
4272 ('', 'all', None, _('print all revisions that match')),
4272 ('a', 'text', None, _('treat all files as text')),
4273 ('a', 'text', None, _('treat all files as text')),
4273 ('f', 'follow', None,
4274 ('f', 'follow', None,
4274 _('follow changeset history,'
4275 _('follow changeset history,'
4275 ' or file history across copies and renames')),
4276 ' or file history across copies and renames')),
4276 ('i', 'ignore-case', None, _('ignore case when matching')),
4277 ('i', 'ignore-case', None, _('ignore case when matching')),
4277 ('l', 'files-with-matches', None,
4278 ('l', 'files-with-matches', None,
4278 _('print only filenames and revisions that match')),
4279 _('print only filenames and revisions that match')),
4279 ('n', 'line-number', None, _('print matching line numbers')),
4280 ('n', 'line-number', None, _('print matching line numbers')),
4280 ('r', 'rev', [],
4281 ('r', 'rev', [],
4281 _('only search files changed within revision range'), _('REV')),
4282 _('only search files changed within revision range'), _('REV')),
4282 ('u', 'user', None, _('list the author (long with -v)')),
4283 ('u', 'user', None, _('list the author (long with -v)')),
4283 ('d', 'date', None, _('list the date (short with -q)')),
4284 ('d', 'date', None, _('list the date (short with -q)')),
4284 ] + walkopts,
4285 ] + walkopts,
4285 _('[OPTION]... PATTERN [FILE]...'),
4286 _('[OPTION]... PATTERN [FILE]...'),
4286 inferrepo=True)
4287 inferrepo=True)
4287 def grep(ui, repo, pattern, *pats, **opts):
4288 def grep(ui, repo, pattern, *pats, **opts):
4288 """search for a pattern in specified files and revisions
4289 """search for a pattern in specified files and revisions
4289
4290
4290 Search revisions of files for a regular expression.
4291 Search revisions of files for a regular expression.
4291
4292
4292 This command behaves differently than Unix grep. It only accepts
4293 This command behaves differently than Unix grep. It only accepts
4293 Python/Perl regexps. It searches repository history, not the
4294 Python/Perl regexps. It searches repository history, not the
4294 working directory. It always prints the revision number in which a
4295 working directory. It always prints the revision number in which a
4295 match appears.
4296 match appears.
4296
4297
4297 By default, grep only prints output for the first revision of a
4298 By default, grep only prints output for the first revision of a
4298 file in which it finds a match. To get it to print every revision
4299 file in which it finds a match. To get it to print every revision
4299 that contains a change in match status ("-" for a match that
4300 that contains a change in match status ("-" for a match that
4300 becomes a non-match, or "+" for a non-match that becomes a match),
4301 becomes a non-match, or "+" for a non-match that becomes a match),
4301 use the --all flag.
4302 use the --all flag.
4302
4303
4303 Returns 0 if a match is found, 1 otherwise.
4304 Returns 0 if a match is found, 1 otherwise.
4304 """
4305 """
4305 reflags = re.M
4306 reflags = re.M
4306 if opts.get('ignore_case'):
4307 if opts.get('ignore_case'):
4307 reflags |= re.I
4308 reflags |= re.I
4308 try:
4309 try:
4309 regexp = util.re.compile(pattern, reflags)
4310 regexp = util.re.compile(pattern, reflags)
4310 except re.error as inst:
4311 except re.error as inst:
4311 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4312 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4312 return 1
4313 return 1
4313 sep, eol = ':', '\n'
4314 sep, eol = ':', '\n'
4314 if opts.get('print0'):
4315 if opts.get('print0'):
4315 sep = eol = '\0'
4316 sep = eol = '\0'
4316
4317
4317 getfile = util.lrucachefunc(repo.file)
4318 getfile = util.lrucachefunc(repo.file)
4318
4319
4319 def matchlines(body):
4320 def matchlines(body):
4320 begin = 0
4321 begin = 0
4321 linenum = 0
4322 linenum = 0
4322 while begin < len(body):
4323 while begin < len(body):
4323 match = regexp.search(body, begin)
4324 match = regexp.search(body, begin)
4324 if not match:
4325 if not match:
4325 break
4326 break
4326 mstart, mend = match.span()
4327 mstart, mend = match.span()
4327 linenum += body.count('\n', begin, mstart) + 1
4328 linenum += body.count('\n', begin, mstart) + 1
4328 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4329 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4329 begin = body.find('\n', mend) + 1 or len(body) + 1
4330 begin = body.find('\n', mend) + 1 or len(body) + 1
4330 lend = begin - 1
4331 lend = begin - 1
4331 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4332 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4332
4333
4333 class linestate(object):
4334 class linestate(object):
4334 def __init__(self, line, linenum, colstart, colend):
4335 def __init__(self, line, linenum, colstart, colend):
4335 self.line = line
4336 self.line = line
4336 self.linenum = linenum
4337 self.linenum = linenum
4337 self.colstart = colstart
4338 self.colstart = colstart
4338 self.colend = colend
4339 self.colend = colend
4339
4340
4340 def __hash__(self):
4341 def __hash__(self):
4341 return hash((self.linenum, self.line))
4342 return hash((self.linenum, self.line))
4342
4343
4343 def __eq__(self, other):
4344 def __eq__(self, other):
4344 return self.line == other.line
4345 return self.line == other.line
4345
4346
4346 def __iter__(self):
4347 def __iter__(self):
4347 yield (self.line[:self.colstart], '')
4348 yield (self.line[:self.colstart], '')
4348 yield (self.line[self.colstart:self.colend], 'grep.match')
4349 yield (self.line[self.colstart:self.colend], 'grep.match')
4349 rest = self.line[self.colend:]
4350 rest = self.line[self.colend:]
4350 while rest != '':
4351 while rest != '':
4351 match = regexp.search(rest)
4352 match = regexp.search(rest)
4352 if not match:
4353 if not match:
4353 yield (rest, '')
4354 yield (rest, '')
4354 break
4355 break
4355 mstart, mend = match.span()
4356 mstart, mend = match.span()
4356 yield (rest[:mstart], '')
4357 yield (rest[:mstart], '')
4357 yield (rest[mstart:mend], 'grep.match')
4358 yield (rest[mstart:mend], 'grep.match')
4358 rest = rest[mend:]
4359 rest = rest[mend:]
4359
4360
4360 matches = {}
4361 matches = {}
4361 copies = {}
4362 copies = {}
4362 def grepbody(fn, rev, body):
4363 def grepbody(fn, rev, body):
4363 matches[rev].setdefault(fn, [])
4364 matches[rev].setdefault(fn, [])
4364 m = matches[rev][fn]
4365 m = matches[rev][fn]
4365 for lnum, cstart, cend, line in matchlines(body):
4366 for lnum, cstart, cend, line in matchlines(body):
4366 s = linestate(line, lnum, cstart, cend)
4367 s = linestate(line, lnum, cstart, cend)
4367 m.append(s)
4368 m.append(s)
4368
4369
4369 def difflinestates(a, b):
4370 def difflinestates(a, b):
4370 sm = difflib.SequenceMatcher(None, a, b)
4371 sm = difflib.SequenceMatcher(None, a, b)
4371 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4372 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4372 if tag == 'insert':
4373 if tag == 'insert':
4373 for i in xrange(blo, bhi):
4374 for i in xrange(blo, bhi):
4374 yield ('+', b[i])
4375 yield ('+', b[i])
4375 elif tag == 'delete':
4376 elif tag == 'delete':
4376 for i in xrange(alo, ahi):
4377 for i in xrange(alo, ahi):
4377 yield ('-', a[i])
4378 yield ('-', a[i])
4378 elif tag == 'replace':
4379 elif tag == 'replace':
4379 for i in xrange(alo, ahi):
4380 for i in xrange(alo, ahi):
4380 yield ('-', a[i])
4381 yield ('-', a[i])
4381 for i in xrange(blo, bhi):
4382 for i in xrange(blo, bhi):
4382 yield ('+', b[i])
4383 yield ('+', b[i])
4383
4384
4384 def display(fn, ctx, pstates, states):
4385 def display(fn, ctx, pstates, states):
4385 rev = ctx.rev()
4386 rev = ctx.rev()
4386 if ui.quiet:
4387 if ui.quiet:
4387 datefunc = util.shortdate
4388 datefunc = util.shortdate
4388 else:
4389 else:
4389 datefunc = util.datestr
4390 datefunc = util.datestr
4390 found = False
4391 found = False
4391 @util.cachefunc
4392 @util.cachefunc
4392 def binary():
4393 def binary():
4393 flog = getfile(fn)
4394 flog = getfile(fn)
4394 return util.binary(flog.read(ctx.filenode(fn)))
4395 return util.binary(flog.read(ctx.filenode(fn)))
4395
4396
4396 if opts.get('all'):
4397 if opts.get('all'):
4397 iter = difflinestates(pstates, states)
4398 iter = difflinestates(pstates, states)
4398 else:
4399 else:
4399 iter = [('', l) for l in states]
4400 iter = [('', l) for l in states]
4400 for change, l in iter:
4401 for change, l in iter:
4401 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4402 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4402
4403
4403 if opts.get('line_number'):
4404 if opts.get('line_number'):
4404 cols.append((str(l.linenum), 'grep.linenumber'))
4405 cols.append((str(l.linenum), 'grep.linenumber'))
4405 if opts.get('all'):
4406 if opts.get('all'):
4406 cols.append((change, 'grep.change'))
4407 cols.append((change, 'grep.change'))
4407 if opts.get('user'):
4408 if opts.get('user'):
4408 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4409 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4409 if opts.get('date'):
4410 if opts.get('date'):
4410 cols.append((datefunc(ctx.date()), 'grep.date'))
4411 cols.append((datefunc(ctx.date()), 'grep.date'))
4411 for col, label in cols[:-1]:
4412 for col, label in cols[:-1]:
4412 ui.write(col, label=label)
4413 ui.write(col, label=label)
4413 ui.write(sep, label='grep.sep')
4414 ui.write(sep, label='grep.sep')
4414 ui.write(cols[-1][0], label=cols[-1][1])
4415 ui.write(cols[-1][0], label=cols[-1][1])
4415 if not opts.get('files_with_matches'):
4416 if not opts.get('files_with_matches'):
4416 ui.write(sep, label='grep.sep')
4417 ui.write(sep, label='grep.sep')
4417 if not opts.get('text') and binary():
4418 if not opts.get('text') and binary():
4418 ui.write(_(" Binary file matches"))
4419 ui.write(_(" Binary file matches"))
4419 else:
4420 else:
4420 for s, label in l:
4421 for s, label in l:
4421 ui.write(s, label=label)
4422 ui.write(s, label=label)
4422 ui.write(eol)
4423 ui.write(eol)
4423 found = True
4424 found = True
4424 if opts.get('files_with_matches'):
4425 if opts.get('files_with_matches'):
4425 break
4426 break
4426 return found
4427 return found
4427
4428
4428 skip = {}
4429 skip = {}
4429 revfiles = {}
4430 revfiles = {}
4430 matchfn = scmutil.match(repo[None], pats, opts)
4431 matchfn = scmutil.match(repo[None], pats, opts)
4431 found = False
4432 found = False
4432 follow = opts.get('follow')
4433 follow = opts.get('follow')
4433
4434
4434 def prep(ctx, fns):
4435 def prep(ctx, fns):
4435 rev = ctx.rev()
4436 rev = ctx.rev()
4436 pctx = ctx.p1()
4437 pctx = ctx.p1()
4437 parent = pctx.rev()
4438 parent = pctx.rev()
4438 matches.setdefault(rev, {})
4439 matches.setdefault(rev, {})
4439 matches.setdefault(parent, {})
4440 matches.setdefault(parent, {})
4440 files = revfiles.setdefault(rev, [])
4441 files = revfiles.setdefault(rev, [])
4441 for fn in fns:
4442 for fn in fns:
4442 flog = getfile(fn)
4443 flog = getfile(fn)
4443 try:
4444 try:
4444 fnode = ctx.filenode(fn)
4445 fnode = ctx.filenode(fn)
4445 except error.LookupError:
4446 except error.LookupError:
4446 continue
4447 continue
4447
4448
4448 copied = flog.renamed(fnode)
4449 copied = flog.renamed(fnode)
4449 copy = follow and copied and copied[0]
4450 copy = follow and copied and copied[0]
4450 if copy:
4451 if copy:
4451 copies.setdefault(rev, {})[fn] = copy
4452 copies.setdefault(rev, {})[fn] = copy
4452 if fn in skip:
4453 if fn in skip:
4453 if copy:
4454 if copy:
4454 skip[copy] = True
4455 skip[copy] = True
4455 continue
4456 continue
4456 files.append(fn)
4457 files.append(fn)
4457
4458
4458 if fn not in matches[rev]:
4459 if fn not in matches[rev]:
4459 grepbody(fn, rev, flog.read(fnode))
4460 grepbody(fn, rev, flog.read(fnode))
4460
4461
4461 pfn = copy or fn
4462 pfn = copy or fn
4462 if pfn not in matches[parent]:
4463 if pfn not in matches[parent]:
4463 try:
4464 try:
4464 fnode = pctx.filenode(pfn)
4465 fnode = pctx.filenode(pfn)
4465 grepbody(pfn, parent, flog.read(fnode))
4466 grepbody(pfn, parent, flog.read(fnode))
4466 except error.LookupError:
4467 except error.LookupError:
4467 pass
4468 pass
4468
4469
4469 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4470 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4470 rev = ctx.rev()
4471 rev = ctx.rev()
4471 parent = ctx.p1().rev()
4472 parent = ctx.p1().rev()
4472 for fn in sorted(revfiles.get(rev, [])):
4473 for fn in sorted(revfiles.get(rev, [])):
4473 states = matches[rev][fn]
4474 states = matches[rev][fn]
4474 copy = copies.get(rev, {}).get(fn)
4475 copy = copies.get(rev, {}).get(fn)
4475 if fn in skip:
4476 if fn in skip:
4476 if copy:
4477 if copy:
4477 skip[copy] = True
4478 skip[copy] = True
4478 continue
4479 continue
4479 pstates = matches.get(parent, {}).get(copy or fn, [])
4480 pstates = matches.get(parent, {}).get(copy or fn, [])
4480 if pstates or states:
4481 if pstates or states:
4481 r = display(fn, ctx, pstates, states)
4482 r = display(fn, ctx, pstates, states)
4482 found = found or r
4483 found = found or r
4483 if r and not opts.get('all'):
4484 if r and not opts.get('all'):
4484 skip[fn] = True
4485 skip[fn] = True
4485 if copy:
4486 if copy:
4486 skip[copy] = True
4487 skip[copy] = True
4487 del matches[rev]
4488 del matches[rev]
4488 del revfiles[rev]
4489 del revfiles[rev]
4489
4490
4490 return not found
4491 return not found
4491
4492
4492 @command('heads',
4493 @command('heads',
4493 [('r', 'rev', '',
4494 [('r', 'rev', '',
4494 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4495 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4495 ('t', 'topo', False, _('show topological heads only')),
4496 ('t', 'topo', False, _('show topological heads only')),
4496 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4497 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4497 ('c', 'closed', False, _('show normal and closed branch heads')),
4498 ('c', 'closed', False, _('show normal and closed branch heads')),
4498 ] + templateopts,
4499 ] + templateopts,
4499 _('[-ct] [-r STARTREV] [REV]...'))
4500 _('[-ct] [-r STARTREV] [REV]...'))
4500 def heads(ui, repo, *branchrevs, **opts):
4501 def heads(ui, repo, *branchrevs, **opts):
4501 """show branch heads
4502 """show branch heads
4502
4503
4503 With no arguments, show all open branch heads in the repository.
4504 With no arguments, show all open branch heads in the repository.
4504 Branch heads are changesets that have no descendants on the
4505 Branch heads are changesets that have no descendants on the
4505 same branch. They are where development generally takes place and
4506 same branch. They are where development generally takes place and
4506 are the usual targets for update and merge operations.
4507 are the usual targets for update and merge operations.
4507
4508
4508 If one or more REVs are given, only open branch heads on the
4509 If one or more REVs are given, only open branch heads on the
4509 branches associated with the specified changesets are shown. This
4510 branches associated with the specified changesets are shown. This
4510 means that you can use :hg:`heads .` to see the heads on the
4511 means that you can use :hg:`heads .` to see the heads on the
4511 currently checked-out branch.
4512 currently checked-out branch.
4512
4513
4513 If -c/--closed is specified, also show branch heads marked closed
4514 If -c/--closed is specified, also show branch heads marked closed
4514 (see :hg:`commit --close-branch`).
4515 (see :hg:`commit --close-branch`).
4515
4516
4516 If STARTREV is specified, only those heads that are descendants of
4517 If STARTREV is specified, only those heads that are descendants of
4517 STARTREV will be displayed.
4518 STARTREV will be displayed.
4518
4519
4519 If -t/--topo is specified, named branch mechanics will be ignored and only
4520 If -t/--topo is specified, named branch mechanics will be ignored and only
4520 topological heads (changesets with no children) will be shown.
4521 topological heads (changesets with no children) will be shown.
4521
4522
4522 Returns 0 if matching heads are found, 1 if not.
4523 Returns 0 if matching heads are found, 1 if not.
4523 """
4524 """
4524
4525
4525 start = None
4526 start = None
4526 if 'rev' in opts:
4527 if 'rev' in opts:
4527 start = scmutil.revsingle(repo, opts['rev'], None).node()
4528 start = scmutil.revsingle(repo, opts['rev'], None).node()
4528
4529
4529 if opts.get('topo'):
4530 if opts.get('topo'):
4530 heads = [repo[h] for h in repo.heads(start)]
4531 heads = [repo[h] for h in repo.heads(start)]
4531 else:
4532 else:
4532 heads = []
4533 heads = []
4533 for branch in repo.branchmap():
4534 for branch in repo.branchmap():
4534 heads += repo.branchheads(branch, start, opts.get('closed'))
4535 heads += repo.branchheads(branch, start, opts.get('closed'))
4535 heads = [repo[h] for h in heads]
4536 heads = [repo[h] for h in heads]
4536
4537
4537 if branchrevs:
4538 if branchrevs:
4538 branches = set(repo[br].branch() for br in branchrevs)
4539 branches = set(repo[br].branch() for br in branchrevs)
4539 heads = [h for h in heads if h.branch() in branches]
4540 heads = [h for h in heads if h.branch() in branches]
4540
4541
4541 if opts.get('active') and branchrevs:
4542 if opts.get('active') and branchrevs:
4542 dagheads = repo.heads(start)
4543 dagheads = repo.heads(start)
4543 heads = [h for h in heads if h.node() in dagheads]
4544 heads = [h for h in heads if h.node() in dagheads]
4544
4545
4545 if branchrevs:
4546 if branchrevs:
4546 haveheads = set(h.branch() for h in heads)
4547 haveheads = set(h.branch() for h in heads)
4547 if branches - haveheads:
4548 if branches - haveheads:
4548 headless = ', '.join(b for b in branches - haveheads)
4549 headless = ', '.join(b for b in branches - haveheads)
4549 msg = _('no open branch heads found on branches %s')
4550 msg = _('no open branch heads found on branches %s')
4550 if opts.get('rev'):
4551 if opts.get('rev'):
4551 msg += _(' (started at %s)') % opts['rev']
4552 msg += _(' (started at %s)') % opts['rev']
4552 ui.warn((msg + '\n') % headless)
4553 ui.warn((msg + '\n') % headless)
4553
4554
4554 if not heads:
4555 if not heads:
4555 return 1
4556 return 1
4556
4557
4557 heads = sorted(heads, key=lambda x: -x.rev())
4558 heads = sorted(heads, key=lambda x: -x.rev())
4558 displayer = cmdutil.show_changeset(ui, repo, opts)
4559 displayer = cmdutil.show_changeset(ui, repo, opts)
4559 for ctx in heads:
4560 for ctx in heads:
4560 displayer.show(ctx)
4561 displayer.show(ctx)
4561 displayer.close()
4562 displayer.close()
4562
4563
4563 @command('help',
4564 @command('help',
4564 [('e', 'extension', None, _('show only help for extensions')),
4565 [('e', 'extension', None, _('show only help for extensions')),
4565 ('c', 'command', None, _('show only help for commands')),
4566 ('c', 'command', None, _('show only help for commands')),
4566 ('k', 'keyword', None, _('show topics matching keyword')),
4567 ('k', 'keyword', None, _('show topics matching keyword')),
4567 ('s', 'system', [], _('show help for specific platform(s)')),
4568 ('s', 'system', [], _('show help for specific platform(s)')),
4568 ],
4569 ],
4569 _('[-ecks] [TOPIC]'),
4570 _('[-ecks] [TOPIC]'),
4570 norepo=True)
4571 norepo=True)
4571 def help_(ui, name=None, **opts):
4572 def help_(ui, name=None, **opts):
4572 """show help for a given topic or a help overview
4573 """show help for a given topic or a help overview
4573
4574
4574 With no arguments, print a list of commands with short help messages.
4575 With no arguments, print a list of commands with short help messages.
4575
4576
4576 Given a topic, extension, or command name, print help for that
4577 Given a topic, extension, or command name, print help for that
4577 topic.
4578 topic.
4578
4579
4579 Returns 0 if successful.
4580 Returns 0 if successful.
4580 """
4581 """
4581
4582
4582 textwidth = ui.configint('ui', 'textwidth', 78)
4583 textwidth = ui.configint('ui', 'textwidth', 78)
4583 termwidth = ui.termwidth() - 2
4584 termwidth = ui.termwidth() - 2
4584 if textwidth <= 0 or termwidth < textwidth:
4585 if textwidth <= 0 or termwidth < textwidth:
4585 textwidth = termwidth
4586 textwidth = termwidth
4586
4587
4587 keep = opts.get('system') or []
4588 keep = opts.get('system') or []
4588 if len(keep) == 0:
4589 if len(keep) == 0:
4589 if sys.platform.startswith('win'):
4590 if sys.platform.startswith('win'):
4590 keep.append('windows')
4591 keep.append('windows')
4591 elif sys.platform == 'OpenVMS':
4592 elif sys.platform == 'OpenVMS':
4592 keep.append('vms')
4593 keep.append('vms')
4593 elif sys.platform == 'plan9':
4594 elif sys.platform == 'plan9':
4594 keep.append('plan9')
4595 keep.append('plan9')
4595 else:
4596 else:
4596 keep.append('unix')
4597 keep.append('unix')
4597 keep.append(sys.platform.lower())
4598 keep.append(sys.platform.lower())
4598 if ui.verbose:
4599 if ui.verbose:
4599 keep.append('verbose')
4600 keep.append('verbose')
4600
4601
4601 section = None
4602 section = None
4602 subtopic = None
4603 subtopic = None
4603 if name and '.' in name:
4604 if name and '.' in name:
4604 name, section = name.split('.', 1)
4605 name, section = name.split('.', 1)
4605 section = encoding.lower(section)
4606 section = encoding.lower(section)
4606 if '.' in section:
4607 if '.' in section:
4607 subtopic, section = section.split('.', 1)
4608 subtopic, section = section.split('.', 1)
4608 else:
4609 else:
4609 subtopic = section
4610 subtopic = section
4610
4611
4611 text = help.help_(ui, name, subtopic=subtopic, **opts)
4612 text = help.help_(ui, name, subtopic=subtopic, **opts)
4612
4613
4613 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4614 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4614 section=section)
4615 section=section)
4615
4616
4616 # We could have been given a weird ".foo" section without a name
4617 # We could have been given a weird ".foo" section without a name
4617 # to look for, or we could have simply failed to found "foo.bar"
4618 # to look for, or we could have simply failed to found "foo.bar"
4618 # because bar isn't a section of foo
4619 # because bar isn't a section of foo
4619 if section and not (formatted and name):
4620 if section and not (formatted and name):
4620 raise error.Abort(_("help section not found"))
4621 raise error.Abort(_("help section not found"))
4621
4622
4622 if 'verbose' in pruned:
4623 if 'verbose' in pruned:
4623 keep.append('omitted')
4624 keep.append('omitted')
4624 else:
4625 else:
4625 keep.append('notomitted')
4626 keep.append('notomitted')
4626 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4627 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4627 section=section)
4628 section=section)
4628 ui.write(formatted)
4629 ui.write(formatted)
4629
4630
4630
4631
4631 @command('identify|id',
4632 @command('identify|id',
4632 [('r', 'rev', '',
4633 [('r', 'rev', '',
4633 _('identify the specified revision'), _('REV')),
4634 _('identify the specified revision'), _('REV')),
4634 ('n', 'num', None, _('show local revision number')),
4635 ('n', 'num', None, _('show local revision number')),
4635 ('i', 'id', None, _('show global revision id')),
4636 ('i', 'id', None, _('show global revision id')),
4636 ('b', 'branch', None, _('show branch')),
4637 ('b', 'branch', None, _('show branch')),
4637 ('t', 'tags', None, _('show tags')),
4638 ('t', 'tags', None, _('show tags')),
4638 ('B', 'bookmarks', None, _('show bookmarks')),
4639 ('B', 'bookmarks', None, _('show bookmarks')),
4639 ] + remoteopts,
4640 ] + remoteopts,
4640 _('[-nibtB] [-r REV] [SOURCE]'),
4641 _('[-nibtB] [-r REV] [SOURCE]'),
4641 optionalrepo=True)
4642 optionalrepo=True)
4642 def identify(ui, repo, source=None, rev=None,
4643 def identify(ui, repo, source=None, rev=None,
4643 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4644 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4644 """identify the working directory or specified revision
4645 """identify the working directory or specified revision
4645
4646
4646 Print a summary identifying the repository state at REV using one or
4647 Print a summary identifying the repository state at REV using one or
4647 two parent hash identifiers, followed by a "+" if the working
4648 two parent hash identifiers, followed by a "+" if the working
4648 directory has uncommitted changes, the branch name (if not default),
4649 directory has uncommitted changes, the branch name (if not default),
4649 a list of tags, and a list of bookmarks.
4650 a list of tags, and a list of bookmarks.
4650
4651
4651 When REV is not given, print a summary of the current state of the
4652 When REV is not given, print a summary of the current state of the
4652 repository.
4653 repository.
4653
4654
4654 Specifying a path to a repository root or Mercurial bundle will
4655 Specifying a path to a repository root or Mercurial bundle will
4655 cause lookup to operate on that repository/bundle.
4656 cause lookup to operate on that repository/bundle.
4656
4657
4657 .. container:: verbose
4658 .. container:: verbose
4658
4659
4659 Examples:
4660 Examples:
4660
4661
4661 - generate a build identifier for the working directory::
4662 - generate a build identifier for the working directory::
4662
4663
4663 hg id --id > build-id.dat
4664 hg id --id > build-id.dat
4664
4665
4665 - find the revision corresponding to a tag::
4666 - find the revision corresponding to a tag::
4666
4667
4667 hg id -n -r 1.3
4668 hg id -n -r 1.3
4668
4669
4669 - check the most recent revision of a remote repository::
4670 - check the most recent revision of a remote repository::
4670
4671
4671 hg id -r tip http://selenic.com/hg/
4672 hg id -r tip http://selenic.com/hg/
4672
4673
4673 See :hg:`log` for generating more information about specific revisions,
4674 See :hg:`log` for generating more information about specific revisions,
4674 including full hash identifiers.
4675 including full hash identifiers.
4675
4676
4676 Returns 0 if successful.
4677 Returns 0 if successful.
4677 """
4678 """
4678
4679
4679 if not repo and not source:
4680 if not repo and not source:
4680 raise error.Abort(_("there is no Mercurial repository here "
4681 raise error.Abort(_("there is no Mercurial repository here "
4681 "(.hg not found)"))
4682 "(.hg not found)"))
4682
4683
4683 if ui.debugflag:
4684 if ui.debugflag:
4684 hexfunc = hex
4685 hexfunc = hex
4685 else:
4686 else:
4686 hexfunc = short
4687 hexfunc = short
4687 default = not (num or id or branch or tags or bookmarks)
4688 default = not (num or id or branch or tags or bookmarks)
4688 output = []
4689 output = []
4689 revs = []
4690 revs = []
4690
4691
4691 if source:
4692 if source:
4692 source, branches = hg.parseurl(ui.expandpath(source))
4693 source, branches = hg.parseurl(ui.expandpath(source))
4693 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4694 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4694 repo = peer.local()
4695 repo = peer.local()
4695 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4696 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4696
4697
4697 if not repo:
4698 if not repo:
4698 if num or branch or tags:
4699 if num or branch or tags:
4699 raise error.Abort(
4700 raise error.Abort(
4700 _("can't query remote revision number, branch, or tags"))
4701 _("can't query remote revision number, branch, or tags"))
4701 if not rev and revs:
4702 if not rev and revs:
4702 rev = revs[0]
4703 rev = revs[0]
4703 if not rev:
4704 if not rev:
4704 rev = "tip"
4705 rev = "tip"
4705
4706
4706 remoterev = peer.lookup(rev)
4707 remoterev = peer.lookup(rev)
4707 if default or id:
4708 if default or id:
4708 output = [hexfunc(remoterev)]
4709 output = [hexfunc(remoterev)]
4709
4710
4710 def getbms():
4711 def getbms():
4711 bms = []
4712 bms = []
4712
4713
4713 if 'bookmarks' in peer.listkeys('namespaces'):
4714 if 'bookmarks' in peer.listkeys('namespaces'):
4714 hexremoterev = hex(remoterev)
4715 hexremoterev = hex(remoterev)
4715 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4716 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4716 if bmr == hexremoterev]
4717 if bmr == hexremoterev]
4717
4718
4718 return sorted(bms)
4719 return sorted(bms)
4719
4720
4720 if bookmarks:
4721 if bookmarks:
4721 output.extend(getbms())
4722 output.extend(getbms())
4722 elif default and not ui.quiet:
4723 elif default and not ui.quiet:
4723 # multiple bookmarks for a single parent separated by '/'
4724 # multiple bookmarks for a single parent separated by '/'
4724 bm = '/'.join(getbms())
4725 bm = '/'.join(getbms())
4725 if bm:
4726 if bm:
4726 output.append(bm)
4727 output.append(bm)
4727 else:
4728 else:
4728 ctx = scmutil.revsingle(repo, rev, None)
4729 ctx = scmutil.revsingle(repo, rev, None)
4729
4730
4730 if ctx.rev() is None:
4731 if ctx.rev() is None:
4731 ctx = repo[None]
4732 ctx = repo[None]
4732 parents = ctx.parents()
4733 parents = ctx.parents()
4733 taglist = []
4734 taglist = []
4734 for p in parents:
4735 for p in parents:
4735 taglist.extend(p.tags())
4736 taglist.extend(p.tags())
4736
4737
4737 changed = ""
4738 changed = ""
4738 if default or id or num:
4739 if default or id or num:
4739 if (any(repo.status())
4740 if (any(repo.status())
4740 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4741 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4741 changed = '+'
4742 changed = '+'
4742 if default or id:
4743 if default or id:
4743 output = ["%s%s" %
4744 output = ["%s%s" %
4744 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4745 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4745 if num:
4746 if num:
4746 output.append("%s%s" %
4747 output.append("%s%s" %
4747 ('+'.join([str(p.rev()) for p in parents]), changed))
4748 ('+'.join([str(p.rev()) for p in parents]), changed))
4748 else:
4749 else:
4749 if default or id:
4750 if default or id:
4750 output = [hexfunc(ctx.node())]
4751 output = [hexfunc(ctx.node())]
4751 if num:
4752 if num:
4752 output.append(str(ctx.rev()))
4753 output.append(str(ctx.rev()))
4753 taglist = ctx.tags()
4754 taglist = ctx.tags()
4754
4755
4755 if default and not ui.quiet:
4756 if default and not ui.quiet:
4756 b = ctx.branch()
4757 b = ctx.branch()
4757 if b != 'default':
4758 if b != 'default':
4758 output.append("(%s)" % b)
4759 output.append("(%s)" % b)
4759
4760
4760 # multiple tags for a single parent separated by '/'
4761 # multiple tags for a single parent separated by '/'
4761 t = '/'.join(taglist)
4762 t = '/'.join(taglist)
4762 if t:
4763 if t:
4763 output.append(t)
4764 output.append(t)
4764
4765
4765 # multiple bookmarks for a single parent separated by '/'
4766 # multiple bookmarks for a single parent separated by '/'
4766 bm = '/'.join(ctx.bookmarks())
4767 bm = '/'.join(ctx.bookmarks())
4767 if bm:
4768 if bm:
4768 output.append(bm)
4769 output.append(bm)
4769 else:
4770 else:
4770 if branch:
4771 if branch:
4771 output.append(ctx.branch())
4772 output.append(ctx.branch())
4772
4773
4773 if tags:
4774 if tags:
4774 output.extend(taglist)
4775 output.extend(taglist)
4775
4776
4776 if bookmarks:
4777 if bookmarks:
4777 output.extend(ctx.bookmarks())
4778 output.extend(ctx.bookmarks())
4778
4779
4779 ui.write("%s\n" % ' '.join(output))
4780 ui.write("%s\n" % ' '.join(output))
4780
4781
4781 @command('import|patch',
4782 @command('import|patch',
4782 [('p', 'strip', 1,
4783 [('p', 'strip', 1,
4783 _('directory strip option for patch. This has the same '
4784 _('directory strip option for patch. This has the same '
4784 'meaning as the corresponding patch option'), _('NUM')),
4785 'meaning as the corresponding patch option'), _('NUM')),
4785 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4786 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4786 ('e', 'edit', False, _('invoke editor on commit messages')),
4787 ('e', 'edit', False, _('invoke editor on commit messages')),
4787 ('f', 'force', None,
4788 ('f', 'force', None,
4788 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4789 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4789 ('', 'no-commit', None,
4790 ('', 'no-commit', None,
4790 _("don't commit, just update the working directory")),
4791 _("don't commit, just update the working directory")),
4791 ('', 'bypass', None,
4792 ('', 'bypass', None,
4792 _("apply patch without touching the working directory")),
4793 _("apply patch without touching the working directory")),
4793 ('', 'partial', None,
4794 ('', 'partial', None,
4794 _('commit even if some hunks fail')),
4795 _('commit even if some hunks fail')),
4795 ('', 'exact', None,
4796 ('', 'exact', None,
4796 _('abort if patch would apply lossily')),
4797 _('abort if patch would apply lossily')),
4797 ('', 'prefix', '',
4798 ('', 'prefix', '',
4798 _('apply patch to subdirectory'), _('DIR')),
4799 _('apply patch to subdirectory'), _('DIR')),
4799 ('', 'import-branch', None,
4800 ('', 'import-branch', None,
4800 _('use any branch information in patch (implied by --exact)'))] +
4801 _('use any branch information in patch (implied by --exact)'))] +
4801 commitopts + commitopts2 + similarityopts,
4802 commitopts + commitopts2 + similarityopts,
4802 _('[OPTION]... PATCH...'))
4803 _('[OPTION]... PATCH...'))
4803 def import_(ui, repo, patch1=None, *patches, **opts):
4804 def import_(ui, repo, patch1=None, *patches, **opts):
4804 """import an ordered set of patches
4805 """import an ordered set of patches
4805
4806
4806 Import a list of patches and commit them individually (unless
4807 Import a list of patches and commit them individually (unless
4807 --no-commit is specified).
4808 --no-commit is specified).
4808
4809
4809 To read a patch from standard input, use "-" as the patch name. If
4810 To read a patch from standard input, use "-" as the patch name. If
4810 a URL is specified, the patch will be downloaded from there.
4811 a URL is specified, the patch will be downloaded from there.
4811
4812
4812 Import first applies changes to the working directory (unless
4813 Import first applies changes to the working directory (unless
4813 --bypass is specified), import will abort if there are outstanding
4814 --bypass is specified), import will abort if there are outstanding
4814 changes.
4815 changes.
4815
4816
4816 Use --bypass to apply and commit patches directly to the
4817 Use --bypass to apply and commit patches directly to the
4817 repository, without affecting the working directory. Without
4818 repository, without affecting the working directory. Without
4818 --exact, patches will be applied on top of the working directory
4819 --exact, patches will be applied on top of the working directory
4819 parent revision.
4820 parent revision.
4820
4821
4821 You can import a patch straight from a mail message. Even patches
4822 You can import a patch straight from a mail message. Even patches
4822 as attachments work (to use the body part, it must have type
4823 as attachments work (to use the body part, it must have type
4823 text/plain or text/x-patch). From and Subject headers of email
4824 text/plain or text/x-patch). From and Subject headers of email
4824 message are used as default committer and commit message. All
4825 message are used as default committer and commit message. All
4825 text/plain body parts before first diff are added to the commit
4826 text/plain body parts before first diff are added to the commit
4826 message.
4827 message.
4827
4828
4828 If the imported patch was generated by :hg:`export`, user and
4829 If the imported patch was generated by :hg:`export`, user and
4829 description from patch override values from message headers and
4830 description from patch override values from message headers and
4830 body. Values given on command line with -m/--message and -u/--user
4831 body. Values given on command line with -m/--message and -u/--user
4831 override these.
4832 override these.
4832
4833
4833 If --exact is specified, import will set the working directory to
4834 If --exact is specified, import will set the working directory to
4834 the parent of each patch before applying it, and will abort if the
4835 the parent of each patch before applying it, and will abort if the
4835 resulting changeset has a different ID than the one recorded in
4836 resulting changeset has a different ID than the one recorded in
4836 the patch. This will guard against various ways that portable
4837 the patch. This will guard against various ways that portable
4837 patch formats and mail systems might fail to transfer Mercurial
4838 patch formats and mail systems might fail to transfer Mercurial
4838 data or metadata. See :hg:`bundle` for lossless transmission.
4839 data or metadata. See :hg:`bundle` for lossless transmission.
4839
4840
4840 Use --partial to ensure a changeset will be created from the patch
4841 Use --partial to ensure a changeset will be created from the patch
4841 even if some hunks fail to apply. Hunks that fail to apply will be
4842 even if some hunks fail to apply. Hunks that fail to apply will be
4842 written to a <target-file>.rej file. Conflicts can then be resolved
4843 written to a <target-file>.rej file. Conflicts can then be resolved
4843 by hand before :hg:`commit --amend` is run to update the created
4844 by hand before :hg:`commit --amend` is run to update the created
4844 changeset. This flag exists to let people import patches that
4845 changeset. This flag exists to let people import patches that
4845 partially apply without losing the associated metadata (author,
4846 partially apply without losing the associated metadata (author,
4846 date, description, ...).
4847 date, description, ...).
4847
4848
4848 .. note::
4849 .. note::
4849
4850
4850 When no hunks apply cleanly, :hg:`import --partial` will create
4851 When no hunks apply cleanly, :hg:`import --partial` will create
4851 an empty changeset, importing only the patch metadata.
4852 an empty changeset, importing only the patch metadata.
4852
4853
4853 With -s/--similarity, hg will attempt to discover renames and
4854 With -s/--similarity, hg will attempt to discover renames and
4854 copies in the patch in the same way as :hg:`addremove`.
4855 copies in the patch in the same way as :hg:`addremove`.
4855
4856
4856 It is possible to use external patch programs to perform the patch
4857 It is possible to use external patch programs to perform the patch
4857 by setting the ``ui.patch`` configuration option. For the default
4858 by setting the ``ui.patch`` configuration option. For the default
4858 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4859 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4859 See :hg:`help config` for more information about configuration
4860 See :hg:`help config` for more information about configuration
4860 files and how to use these options.
4861 files and how to use these options.
4861
4862
4862 See :hg:`help dates` for a list of formats valid for -d/--date.
4863 See :hg:`help dates` for a list of formats valid for -d/--date.
4863
4864
4864 .. container:: verbose
4865 .. container:: verbose
4865
4866
4866 Examples:
4867 Examples:
4867
4868
4868 - import a traditional patch from a website and detect renames::
4869 - import a traditional patch from a website and detect renames::
4869
4870
4870 hg import -s 80 http://example.com/bugfix.patch
4871 hg import -s 80 http://example.com/bugfix.patch
4871
4872
4872 - import a changeset from an hgweb server::
4873 - import a changeset from an hgweb server::
4873
4874
4874 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4875 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4875
4876
4876 - import all the patches in an Unix-style mbox::
4877 - import all the patches in an Unix-style mbox::
4877
4878
4878 hg import incoming-patches.mbox
4879 hg import incoming-patches.mbox
4879
4880
4880 - attempt to exactly restore an exported changeset (not always
4881 - attempt to exactly restore an exported changeset (not always
4881 possible)::
4882 possible)::
4882
4883
4883 hg import --exact proposed-fix.patch
4884 hg import --exact proposed-fix.patch
4884
4885
4885 - use an external tool to apply a patch which is too fuzzy for
4886 - use an external tool to apply a patch which is too fuzzy for
4886 the default internal tool.
4887 the default internal tool.
4887
4888
4888 hg import --config ui.patch="patch --merge" fuzzy.patch
4889 hg import --config ui.patch="patch --merge" fuzzy.patch
4889
4890
4890 - change the default fuzzing from 2 to a less strict 7
4891 - change the default fuzzing from 2 to a less strict 7
4891
4892
4892 hg import --config ui.fuzz=7 fuzz.patch
4893 hg import --config ui.fuzz=7 fuzz.patch
4893
4894
4894 Returns 0 on success, 1 on partial success (see --partial).
4895 Returns 0 on success, 1 on partial success (see --partial).
4895 """
4896 """
4896
4897
4897 if not patch1:
4898 if not patch1:
4898 raise error.Abort(_('need at least one patch to import'))
4899 raise error.Abort(_('need at least one patch to import'))
4899
4900
4900 patches = (patch1,) + patches
4901 patches = (patch1,) + patches
4901
4902
4902 date = opts.get('date')
4903 date = opts.get('date')
4903 if date:
4904 if date:
4904 opts['date'] = util.parsedate(date)
4905 opts['date'] = util.parsedate(date)
4905
4906
4906 exact = opts.get('exact')
4907 exact = opts.get('exact')
4907 update = not opts.get('bypass')
4908 update = not opts.get('bypass')
4908 if not update and opts.get('no_commit'):
4909 if not update and opts.get('no_commit'):
4909 raise error.Abort(_('cannot use --no-commit with --bypass'))
4910 raise error.Abort(_('cannot use --no-commit with --bypass'))
4910 try:
4911 try:
4911 sim = float(opts.get('similarity') or 0)
4912 sim = float(opts.get('similarity') or 0)
4912 except ValueError:
4913 except ValueError:
4913 raise error.Abort(_('similarity must be a number'))
4914 raise error.Abort(_('similarity must be a number'))
4914 if sim < 0 or sim > 100:
4915 if sim < 0 or sim > 100:
4915 raise error.Abort(_('similarity must be between 0 and 100'))
4916 raise error.Abort(_('similarity must be between 0 and 100'))
4916 if sim and not update:
4917 if sim and not update:
4917 raise error.Abort(_('cannot use --similarity with --bypass'))
4918 raise error.Abort(_('cannot use --similarity with --bypass'))
4918 if exact:
4919 if exact:
4919 if opts.get('edit'):
4920 if opts.get('edit'):
4920 raise error.Abort(_('cannot use --exact with --edit'))
4921 raise error.Abort(_('cannot use --exact with --edit'))
4921 if opts.get('prefix'):
4922 if opts.get('prefix'):
4922 raise error.Abort(_('cannot use --exact with --prefix'))
4923 raise error.Abort(_('cannot use --exact with --prefix'))
4923
4924
4924 base = opts["base"]
4925 base = opts["base"]
4925 wlock = dsguard = lock = tr = None
4926 wlock = dsguard = lock = tr = None
4926 msgs = []
4927 msgs = []
4927 ret = 0
4928 ret = 0
4928
4929
4929
4930
4930 try:
4931 try:
4931 wlock = repo.wlock()
4932 wlock = repo.wlock()
4932
4933
4933 if update:
4934 if update:
4934 cmdutil.checkunfinished(repo)
4935 cmdutil.checkunfinished(repo)
4935 if (exact or not opts.get('force')):
4936 if (exact or not opts.get('force')):
4936 cmdutil.bailifchanged(repo)
4937 cmdutil.bailifchanged(repo)
4937
4938
4938 if not opts.get('no_commit'):
4939 if not opts.get('no_commit'):
4939 lock = repo.lock()
4940 lock = repo.lock()
4940 tr = repo.transaction('import')
4941 tr = repo.transaction('import')
4941 else:
4942 else:
4942 dsguard = cmdutil.dirstateguard(repo, 'import')
4943 dsguard = cmdutil.dirstateguard(repo, 'import')
4943 parents = repo[None].parents()
4944 parents = repo[None].parents()
4944 for patchurl in patches:
4945 for patchurl in patches:
4945 if patchurl == '-':
4946 if patchurl == '-':
4946 ui.status(_('applying patch from stdin\n'))
4947 ui.status(_('applying patch from stdin\n'))
4947 patchfile = ui.fin
4948 patchfile = ui.fin
4948 patchurl = 'stdin' # for error message
4949 patchurl = 'stdin' # for error message
4949 else:
4950 else:
4950 patchurl = os.path.join(base, patchurl)
4951 patchurl = os.path.join(base, patchurl)
4951 ui.status(_('applying %s\n') % patchurl)
4952 ui.status(_('applying %s\n') % patchurl)
4952 patchfile = hg.openpath(ui, patchurl)
4953 patchfile = hg.openpath(ui, patchurl)
4953
4954
4954 haspatch = False
4955 haspatch = False
4955 for hunk in patch.split(patchfile):
4956 for hunk in patch.split(patchfile):
4956 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4957 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4957 parents, opts,
4958 parents, opts,
4958 msgs, hg.clean)
4959 msgs, hg.clean)
4959 if msg:
4960 if msg:
4960 haspatch = True
4961 haspatch = True
4961 ui.note(msg + '\n')
4962 ui.note(msg + '\n')
4962 if update or exact:
4963 if update or exact:
4963 parents = repo[None].parents()
4964 parents = repo[None].parents()
4964 else:
4965 else:
4965 parents = [repo[node]]
4966 parents = [repo[node]]
4966 if rej:
4967 if rej:
4967 ui.write_err(_("patch applied partially\n"))
4968 ui.write_err(_("patch applied partially\n"))
4968 ui.write_err(_("(fix the .rej files and run "
4969 ui.write_err(_("(fix the .rej files and run "
4969 "`hg commit --amend`)\n"))
4970 "`hg commit --amend`)\n"))
4970 ret = 1
4971 ret = 1
4971 break
4972 break
4972
4973
4973 if not haspatch:
4974 if not haspatch:
4974 raise error.Abort(_('%s: no diffs found') % patchurl)
4975 raise error.Abort(_('%s: no diffs found') % patchurl)
4975
4976
4976 if tr:
4977 if tr:
4977 tr.close()
4978 tr.close()
4978 if msgs:
4979 if msgs:
4979 repo.savecommitmessage('\n* * *\n'.join(msgs))
4980 repo.savecommitmessage('\n* * *\n'.join(msgs))
4980 if dsguard:
4981 if dsguard:
4981 dsguard.close()
4982 dsguard.close()
4982 return ret
4983 return ret
4983 finally:
4984 finally:
4984 if tr:
4985 if tr:
4985 tr.release()
4986 tr.release()
4986 release(lock, dsguard, wlock)
4987 release(lock, dsguard, wlock)
4987
4988
4988 @command('incoming|in',
4989 @command('incoming|in',
4989 [('f', 'force', None,
4990 [('f', 'force', None,
4990 _('run even if remote repository is unrelated')),
4991 _('run even if remote repository is unrelated')),
4991 ('n', 'newest-first', None, _('show newest record first')),
4992 ('n', 'newest-first', None, _('show newest record first')),
4992 ('', 'bundle', '',
4993 ('', 'bundle', '',
4993 _('file to store the bundles into'), _('FILE')),
4994 _('file to store the bundles into'), _('FILE')),
4994 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4995 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4995 ('B', 'bookmarks', False, _("compare bookmarks")),
4996 ('B', 'bookmarks', False, _("compare bookmarks")),
4996 ('b', 'branch', [],
4997 ('b', 'branch', [],
4997 _('a specific branch you would like to pull'), _('BRANCH')),
4998 _('a specific branch you would like to pull'), _('BRANCH')),
4998 ] + logopts + remoteopts + subrepoopts,
4999 ] + logopts + remoteopts + subrepoopts,
4999 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5000 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5000 def incoming(ui, repo, source="default", **opts):
5001 def incoming(ui, repo, source="default", **opts):
5001 """show new changesets found in source
5002 """show new changesets found in source
5002
5003
5003 Show new changesets found in the specified path/URL or the default
5004 Show new changesets found in the specified path/URL or the default
5004 pull location. These are the changesets that would have been pulled
5005 pull location. These are the changesets that would have been pulled
5005 if a pull at the time you issued this command.
5006 if a pull at the time you issued this command.
5006
5007
5007 See pull for valid source format details.
5008 See pull for valid source format details.
5008
5009
5009 .. container:: verbose
5010 .. container:: verbose
5010
5011
5011 With -B/--bookmarks, the result of bookmark comparison between
5012 With -B/--bookmarks, the result of bookmark comparison between
5012 local and remote repositories is displayed. With -v/--verbose,
5013 local and remote repositories is displayed. With -v/--verbose,
5013 status is also displayed for each bookmark like below::
5014 status is also displayed for each bookmark like below::
5014
5015
5015 BM1 01234567890a added
5016 BM1 01234567890a added
5016 BM2 1234567890ab advanced
5017 BM2 1234567890ab advanced
5017 BM3 234567890abc diverged
5018 BM3 234567890abc diverged
5018 BM4 34567890abcd changed
5019 BM4 34567890abcd changed
5019
5020
5020 The action taken locally when pulling depends on the
5021 The action taken locally when pulling depends on the
5021 status of each bookmark:
5022 status of each bookmark:
5022
5023
5023 :``added``: pull will create it
5024 :``added``: pull will create it
5024 :``advanced``: pull will update it
5025 :``advanced``: pull will update it
5025 :``diverged``: pull will create a divergent bookmark
5026 :``diverged``: pull will create a divergent bookmark
5026 :``changed``: result depends on remote changesets
5027 :``changed``: result depends on remote changesets
5027
5028
5028 From the point of view of pulling behavior, bookmark
5029 From the point of view of pulling behavior, bookmark
5029 existing only in the remote repository are treated as ``added``,
5030 existing only in the remote repository are treated as ``added``,
5030 even if it is in fact locally deleted.
5031 even if it is in fact locally deleted.
5031
5032
5032 .. container:: verbose
5033 .. container:: verbose
5033
5034
5034 For remote repository, using --bundle avoids downloading the
5035 For remote repository, using --bundle avoids downloading the
5035 changesets twice if the incoming is followed by a pull.
5036 changesets twice if the incoming is followed by a pull.
5036
5037
5037 Examples:
5038 Examples:
5038
5039
5039 - show incoming changes with patches and full description::
5040 - show incoming changes with patches and full description::
5040
5041
5041 hg incoming -vp
5042 hg incoming -vp
5042
5043
5043 - show incoming changes excluding merges, store a bundle::
5044 - show incoming changes excluding merges, store a bundle::
5044
5045
5045 hg in -vpM --bundle incoming.hg
5046 hg in -vpM --bundle incoming.hg
5046 hg pull incoming.hg
5047 hg pull incoming.hg
5047
5048
5048 - briefly list changes inside a bundle::
5049 - briefly list changes inside a bundle::
5049
5050
5050 hg in changes.hg -T "{desc|firstline}\\n"
5051 hg in changes.hg -T "{desc|firstline}\\n"
5051
5052
5052 Returns 0 if there are incoming changes, 1 otherwise.
5053 Returns 0 if there are incoming changes, 1 otherwise.
5053 """
5054 """
5054 if opts.get('graph'):
5055 if opts.get('graph'):
5055 cmdutil.checkunsupportedgraphflags([], opts)
5056 cmdutil.checkunsupportedgraphflags([], opts)
5056 def display(other, chlist, displayer):
5057 def display(other, chlist, displayer):
5057 revdag = cmdutil.graphrevs(other, chlist, opts)
5058 revdag = cmdutil.graphrevs(other, chlist, opts)
5058 cmdutil.displaygraph(ui, repo, revdag, displayer,
5059 cmdutil.displaygraph(ui, repo, revdag, displayer,
5059 graphmod.asciiedges)
5060 graphmod.asciiedges)
5060
5061
5061 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5062 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5062 return 0
5063 return 0
5063
5064
5064 if opts.get('bundle') and opts.get('subrepos'):
5065 if opts.get('bundle') and opts.get('subrepos'):
5065 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5066 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5066
5067
5067 if opts.get('bookmarks'):
5068 if opts.get('bookmarks'):
5068 source, branches = hg.parseurl(ui.expandpath(source),
5069 source, branches = hg.parseurl(ui.expandpath(source),
5069 opts.get('branch'))
5070 opts.get('branch'))
5070 other = hg.peer(repo, opts, source)
5071 other = hg.peer(repo, opts, source)
5071 if 'bookmarks' not in other.listkeys('namespaces'):
5072 if 'bookmarks' not in other.listkeys('namespaces'):
5072 ui.warn(_("remote doesn't support bookmarks\n"))
5073 ui.warn(_("remote doesn't support bookmarks\n"))
5073 return 0
5074 return 0
5074 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5075 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5075 return bookmarks.incoming(ui, repo, other)
5076 return bookmarks.incoming(ui, repo, other)
5076
5077
5077 repo._subtoppath = ui.expandpath(source)
5078 repo._subtoppath = ui.expandpath(source)
5078 try:
5079 try:
5079 return hg.incoming(ui, repo, source, opts)
5080 return hg.incoming(ui, repo, source, opts)
5080 finally:
5081 finally:
5081 del repo._subtoppath
5082 del repo._subtoppath
5082
5083
5083
5084
5084 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5085 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5085 norepo=True)
5086 norepo=True)
5086 def init(ui, dest=".", **opts):
5087 def init(ui, dest=".", **opts):
5087 """create a new repository in the given directory
5088 """create a new repository in the given directory
5088
5089
5089 Initialize a new repository in the given directory. If the given
5090 Initialize a new repository in the given directory. If the given
5090 directory does not exist, it will be created.
5091 directory does not exist, it will be created.
5091
5092
5092 If no directory is given, the current directory is used.
5093 If no directory is given, the current directory is used.
5093
5094
5094 It is possible to specify an ``ssh://`` URL as the destination.
5095 It is possible to specify an ``ssh://`` URL as the destination.
5095 See :hg:`help urls` for more information.
5096 See :hg:`help urls` for more information.
5096
5097
5097 Returns 0 on success.
5098 Returns 0 on success.
5098 """
5099 """
5099 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5100 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5100
5101
5101 @command('locate',
5102 @command('locate',
5102 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5103 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5103 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5104 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5104 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5105 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5105 ] + walkopts,
5106 ] + walkopts,
5106 _('[OPTION]... [PATTERN]...'))
5107 _('[OPTION]... [PATTERN]...'))
5107 def locate(ui, repo, *pats, **opts):
5108 def locate(ui, repo, *pats, **opts):
5108 """locate files matching specific patterns (DEPRECATED)
5109 """locate files matching specific patterns (DEPRECATED)
5109
5110
5110 Print files under Mercurial control in the working directory whose
5111 Print files under Mercurial control in the working directory whose
5111 names match the given patterns.
5112 names match the given patterns.
5112
5113
5113 By default, this command searches all directories in the working
5114 By default, this command searches all directories in the working
5114 directory. To search just the current directory and its
5115 directory. To search just the current directory and its
5115 subdirectories, use "--include .".
5116 subdirectories, use "--include .".
5116
5117
5117 If no patterns are given to match, this command prints the names
5118 If no patterns are given to match, this command prints the names
5118 of all files under Mercurial control in the working directory.
5119 of all files under Mercurial control in the working directory.
5119
5120
5120 If you want to feed the output of this command into the "xargs"
5121 If you want to feed the output of this command into the "xargs"
5121 command, use the -0 option to both this command and "xargs". This
5122 command, use the -0 option to both this command and "xargs". This
5122 will avoid the problem of "xargs" treating single filenames that
5123 will avoid the problem of "xargs" treating single filenames that
5123 contain whitespace as multiple filenames.
5124 contain whitespace as multiple filenames.
5124
5125
5125 See :hg:`help files` for a more versatile command.
5126 See :hg:`help files` for a more versatile command.
5126
5127
5127 Returns 0 if a match is found, 1 otherwise.
5128 Returns 0 if a match is found, 1 otherwise.
5128 """
5129 """
5129 if opts.get('print0'):
5130 if opts.get('print0'):
5130 end = '\0'
5131 end = '\0'
5131 else:
5132 else:
5132 end = '\n'
5133 end = '\n'
5133 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5134 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5134
5135
5135 ret = 1
5136 ret = 1
5136 ctx = repo[rev]
5137 ctx = repo[rev]
5137 m = scmutil.match(ctx, pats, opts, default='relglob',
5138 m = scmutil.match(ctx, pats, opts, default='relglob',
5138 badfn=lambda x, y: False)
5139 badfn=lambda x, y: False)
5139
5140
5140 for abs in ctx.matches(m):
5141 for abs in ctx.matches(m):
5141 if opts.get('fullpath'):
5142 if opts.get('fullpath'):
5142 ui.write(repo.wjoin(abs), end)
5143 ui.write(repo.wjoin(abs), end)
5143 else:
5144 else:
5144 ui.write(((pats and m.rel(abs)) or abs), end)
5145 ui.write(((pats and m.rel(abs)) or abs), end)
5145 ret = 0
5146 ret = 0
5146
5147
5147 return ret
5148 return ret
5148
5149
5149 @command('^log|history',
5150 @command('^log|history',
5150 [('f', 'follow', None,
5151 [('f', 'follow', None,
5151 _('follow changeset history, or file history across copies and renames')),
5152 _('follow changeset history, or file history across copies and renames')),
5152 ('', 'follow-first', None,
5153 ('', 'follow-first', None,
5153 _('only follow the first parent of merge changesets (DEPRECATED)')),
5154 _('only follow the first parent of merge changesets (DEPRECATED)')),
5154 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5155 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5155 ('C', 'copies', None, _('show copied files')),
5156 ('C', 'copies', None, _('show copied files')),
5156 ('k', 'keyword', [],
5157 ('k', 'keyword', [],
5157 _('do case-insensitive search for a given text'), _('TEXT')),
5158 _('do case-insensitive search for a given text'), _('TEXT')),
5158 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5159 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5159 ('', 'removed', None, _('include revisions where files were removed')),
5160 ('', 'removed', None, _('include revisions where files were removed')),
5160 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5161 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5161 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5162 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5162 ('', 'only-branch', [],
5163 ('', 'only-branch', [],
5163 _('show only changesets within the given named branch (DEPRECATED)'),
5164 _('show only changesets within the given named branch (DEPRECATED)'),
5164 _('BRANCH')),
5165 _('BRANCH')),
5165 ('b', 'branch', [],
5166 ('b', 'branch', [],
5166 _('show changesets within the given named branch'), _('BRANCH')),
5167 _('show changesets within the given named branch'), _('BRANCH')),
5167 ('P', 'prune', [],
5168 ('P', 'prune', [],
5168 _('do not display revision or any of its ancestors'), _('REV')),
5169 _('do not display revision or any of its ancestors'), _('REV')),
5169 ] + logopts + walkopts,
5170 ] + logopts + walkopts,
5170 _('[OPTION]... [FILE]'),
5171 _('[OPTION]... [FILE]'),
5171 inferrepo=True)
5172 inferrepo=True)
5172 def log(ui, repo, *pats, **opts):
5173 def log(ui, repo, *pats, **opts):
5173 """show revision history of entire repository or files
5174 """show revision history of entire repository or files
5174
5175
5175 Print the revision history of the specified files or the entire
5176 Print the revision history of the specified files or the entire
5176 project.
5177 project.
5177
5178
5178 If no revision range is specified, the default is ``tip:0`` unless
5179 If no revision range is specified, the default is ``tip:0`` unless
5179 --follow is set, in which case the working directory parent is
5180 --follow is set, in which case the working directory parent is
5180 used as the starting revision.
5181 used as the starting revision.
5181
5182
5182 File history is shown without following rename or copy history of
5183 File history is shown without following rename or copy history of
5183 files. Use -f/--follow with a filename to follow history across
5184 files. Use -f/--follow with a filename to follow history across
5184 renames and copies. --follow without a filename will only show
5185 renames and copies. --follow without a filename will only show
5185 ancestors or descendants of the starting revision.
5186 ancestors or descendants of the starting revision.
5186
5187
5187 By default this command prints revision number and changeset id,
5188 By default this command prints revision number and changeset id,
5188 tags, non-trivial parents, user, date and time, and a summary for
5189 tags, non-trivial parents, user, date and time, and a summary for
5189 each commit. When the -v/--verbose switch is used, the list of
5190 each commit. When the -v/--verbose switch is used, the list of
5190 changed files and full commit message are shown.
5191 changed files and full commit message are shown.
5191
5192
5192 With --graph the revisions are shown as an ASCII art DAG with the most
5193 With --graph the revisions are shown as an ASCII art DAG with the most
5193 recent changeset at the top.
5194 recent changeset at the top.
5194 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5195 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5195 and '+' represents a fork where the changeset from the lines below is a
5196 and '+' represents a fork where the changeset from the lines below is a
5196 parent of the 'o' merge on the same line.
5197 parent of the 'o' merge on the same line.
5197
5198
5198 .. note::
5199 .. note::
5199
5200
5200 :hg:`log --patch` may generate unexpected diff output for merge
5201 :hg:`log --patch` may generate unexpected diff output for merge
5201 changesets, as it will only compare the merge changeset against
5202 changesets, as it will only compare the merge changeset against
5202 its first parent. Also, only files different from BOTH parents
5203 its first parent. Also, only files different from BOTH parents
5203 will appear in files:.
5204 will appear in files:.
5204
5205
5205 .. note::
5206 .. note::
5206
5207
5207 For performance reasons, :hg:`log FILE` may omit duplicate changes
5208 For performance reasons, :hg:`log FILE` may omit duplicate changes
5208 made on branches and will not show removals or mode changes. To
5209 made on branches and will not show removals or mode changes. To
5209 see all such changes, use the --removed switch.
5210 see all such changes, use the --removed switch.
5210
5211
5211 .. container:: verbose
5212 .. container:: verbose
5212
5213
5213 Some examples:
5214 Some examples:
5214
5215
5215 - changesets with full descriptions and file lists::
5216 - changesets with full descriptions and file lists::
5216
5217
5217 hg log -v
5218 hg log -v
5218
5219
5219 - changesets ancestral to the working directory::
5220 - changesets ancestral to the working directory::
5220
5221
5221 hg log -f
5222 hg log -f
5222
5223
5223 - last 10 commits on the current branch::
5224 - last 10 commits on the current branch::
5224
5225
5225 hg log -l 10 -b .
5226 hg log -l 10 -b .
5226
5227
5227 - changesets showing all modifications of a file, including removals::
5228 - changesets showing all modifications of a file, including removals::
5228
5229
5229 hg log --removed file.c
5230 hg log --removed file.c
5230
5231
5231 - all changesets that touch a directory, with diffs, excluding merges::
5232 - all changesets that touch a directory, with diffs, excluding merges::
5232
5233
5233 hg log -Mp lib/
5234 hg log -Mp lib/
5234
5235
5235 - all revision numbers that match a keyword::
5236 - all revision numbers that match a keyword::
5236
5237
5237 hg log -k bug --template "{rev}\\n"
5238 hg log -k bug --template "{rev}\\n"
5238
5239
5239 - the full hash identifier of the working directory parent::
5240 - the full hash identifier of the working directory parent::
5240
5241
5241 hg log -r . --template "{node}\\n"
5242 hg log -r . --template "{node}\\n"
5242
5243
5243 - list available log templates::
5244 - list available log templates::
5244
5245
5245 hg log -T list
5246 hg log -T list
5246
5247
5247 - check if a given changeset is included in a tagged release::
5248 - check if a given changeset is included in a tagged release::
5248
5249
5249 hg log -r "a21ccf and ancestor(1.9)"
5250 hg log -r "a21ccf and ancestor(1.9)"
5250
5251
5251 - find all changesets by some user in a date range::
5252 - find all changesets by some user in a date range::
5252
5253
5253 hg log -k alice -d "may 2008 to jul 2008"
5254 hg log -k alice -d "may 2008 to jul 2008"
5254
5255
5255 - summary of all changesets after the last tag::
5256 - summary of all changesets after the last tag::
5256
5257
5257 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5258 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5258
5259
5259 See :hg:`help dates` for a list of formats valid for -d/--date.
5260 See :hg:`help dates` for a list of formats valid for -d/--date.
5260
5261
5261 See :hg:`help revisions` and :hg:`help revsets` for more about
5262 See :hg:`help revisions` and :hg:`help revsets` for more about
5262 specifying and ordering revisions.
5263 specifying and ordering revisions.
5263
5264
5264 See :hg:`help templates` for more about pre-packaged styles and
5265 See :hg:`help templates` for more about pre-packaged styles and
5265 specifying custom templates.
5266 specifying custom templates.
5266
5267
5267 Returns 0 on success.
5268 Returns 0 on success.
5268
5269
5269 """
5270 """
5270 if opts.get('follow') and opts.get('rev'):
5271 if opts.get('follow') and opts.get('rev'):
5271 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5272 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5272 del opts['follow']
5273 del opts['follow']
5273
5274
5274 if opts.get('graph'):
5275 if opts.get('graph'):
5275 return cmdutil.graphlog(ui, repo, *pats, **opts)
5276 return cmdutil.graphlog(ui, repo, *pats, **opts)
5276
5277
5277 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5278 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5278 limit = cmdutil.loglimit(opts)
5279 limit = cmdutil.loglimit(opts)
5279 count = 0
5280 count = 0
5280
5281
5281 getrenamed = None
5282 getrenamed = None
5282 if opts.get('copies'):
5283 if opts.get('copies'):
5283 endrev = None
5284 endrev = None
5284 if opts.get('rev'):
5285 if opts.get('rev'):
5285 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5286 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5286 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5287 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5287
5288
5288 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5289 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5289 for rev in revs:
5290 for rev in revs:
5290 if count == limit:
5291 if count == limit:
5291 break
5292 break
5292 ctx = repo[rev]
5293 ctx = repo[rev]
5293 copies = None
5294 copies = None
5294 if getrenamed is not None and rev:
5295 if getrenamed is not None and rev:
5295 copies = []
5296 copies = []
5296 for fn in ctx.files():
5297 for fn in ctx.files():
5297 rename = getrenamed(fn, rev)
5298 rename = getrenamed(fn, rev)
5298 if rename:
5299 if rename:
5299 copies.append((fn, rename[0]))
5300 copies.append((fn, rename[0]))
5300 if filematcher:
5301 if filematcher:
5301 revmatchfn = filematcher(ctx.rev())
5302 revmatchfn = filematcher(ctx.rev())
5302 else:
5303 else:
5303 revmatchfn = None
5304 revmatchfn = None
5304 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5305 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5305 if displayer.flush(ctx):
5306 if displayer.flush(ctx):
5306 count += 1
5307 count += 1
5307
5308
5308 displayer.close()
5309 displayer.close()
5309
5310
5310 @command('manifest',
5311 @command('manifest',
5311 [('r', 'rev', '', _('revision to display'), _('REV')),
5312 [('r', 'rev', '', _('revision to display'), _('REV')),
5312 ('', 'all', False, _("list files from all revisions"))]
5313 ('', 'all', False, _("list files from all revisions"))]
5313 + formatteropts,
5314 + formatteropts,
5314 _('[-r REV]'))
5315 _('[-r REV]'))
5315 def manifest(ui, repo, node=None, rev=None, **opts):
5316 def manifest(ui, repo, node=None, rev=None, **opts):
5316 """output the current or given revision of the project manifest
5317 """output the current or given revision of the project manifest
5317
5318
5318 Print a list of version controlled files for the given revision.
5319 Print a list of version controlled files for the given revision.
5319 If no revision is given, the first parent of the working directory
5320 If no revision is given, the first parent of the working directory
5320 is used, or the null revision if no revision is checked out.
5321 is used, or the null revision if no revision is checked out.
5321
5322
5322 With -v, print file permissions, symlink and executable bits.
5323 With -v, print file permissions, symlink and executable bits.
5323 With --debug, print file revision hashes.
5324 With --debug, print file revision hashes.
5324
5325
5325 If option --all is specified, the list of all files from all revisions
5326 If option --all is specified, the list of all files from all revisions
5326 is printed. This includes deleted and renamed files.
5327 is printed. This includes deleted and renamed files.
5327
5328
5328 Returns 0 on success.
5329 Returns 0 on success.
5329 """
5330 """
5330
5331
5331 fm = ui.formatter('manifest', opts)
5332 fm = ui.formatter('manifest', opts)
5332
5333
5333 if opts.get('all'):
5334 if opts.get('all'):
5334 if rev or node:
5335 if rev or node:
5335 raise error.Abort(_("can't specify a revision with --all"))
5336 raise error.Abort(_("can't specify a revision with --all"))
5336
5337
5337 res = []
5338 res = []
5338 prefix = "data/"
5339 prefix = "data/"
5339 suffix = ".i"
5340 suffix = ".i"
5340 plen = len(prefix)
5341 plen = len(prefix)
5341 slen = len(suffix)
5342 slen = len(suffix)
5342 with repo.lock():
5343 with repo.lock():
5343 for fn, b, size in repo.store.datafiles():
5344 for fn, b, size in repo.store.datafiles():
5344 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5345 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5345 res.append(fn[plen:-slen])
5346 res.append(fn[plen:-slen])
5346 for f in res:
5347 for f in res:
5347 fm.startitem()
5348 fm.startitem()
5348 fm.write("path", '%s\n', f)
5349 fm.write("path", '%s\n', f)
5349 fm.end()
5350 fm.end()
5350 return
5351 return
5351
5352
5352 if rev and node:
5353 if rev and node:
5353 raise error.Abort(_("please specify just one revision"))
5354 raise error.Abort(_("please specify just one revision"))
5354
5355
5355 if not node:
5356 if not node:
5356 node = rev
5357 node = rev
5357
5358
5358 char = {'l': '@', 'x': '*', '': ''}
5359 char = {'l': '@', 'x': '*', '': ''}
5359 mode = {'l': '644', 'x': '755', '': '644'}
5360 mode = {'l': '644', 'x': '755', '': '644'}
5360 ctx = scmutil.revsingle(repo, node)
5361 ctx = scmutil.revsingle(repo, node)
5361 mf = ctx.manifest()
5362 mf = ctx.manifest()
5362 for f in ctx:
5363 for f in ctx:
5363 fm.startitem()
5364 fm.startitem()
5364 fl = ctx[f].flags()
5365 fl = ctx[f].flags()
5365 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5366 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5366 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5367 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5367 fm.write('path', '%s\n', f)
5368 fm.write('path', '%s\n', f)
5368 fm.end()
5369 fm.end()
5369
5370
5370 @command('^merge',
5371 @command('^merge',
5371 [('f', 'force', None,
5372 [('f', 'force', None,
5372 _('force a merge including outstanding changes (DEPRECATED)')),
5373 _('force a merge including outstanding changes (DEPRECATED)')),
5373 ('r', 'rev', '', _('revision to merge'), _('REV')),
5374 ('r', 'rev', '', _('revision to merge'), _('REV')),
5374 ('P', 'preview', None,
5375 ('P', 'preview', None,
5375 _('review revisions to merge (no merge is performed)'))
5376 _('review revisions to merge (no merge is performed)'))
5376 ] + mergetoolopts,
5377 ] + mergetoolopts,
5377 _('[-P] [[-r] REV]'))
5378 _('[-P] [[-r] REV]'))
5378 def merge(ui, repo, node=None, **opts):
5379 def merge(ui, repo, node=None, **opts):
5379 """merge another revision into working directory
5380 """merge another revision into working directory
5380
5381
5381 The current working directory is updated with all changes made in
5382 The current working directory is updated with all changes made in
5382 the requested revision since the last common predecessor revision.
5383 the requested revision since the last common predecessor revision.
5383
5384
5384 Files that changed between either parent are marked as changed for
5385 Files that changed between either parent are marked as changed for
5385 the next commit and a commit must be performed before any further
5386 the next commit and a commit must be performed before any further
5386 updates to the repository are allowed. The next commit will have
5387 updates to the repository are allowed. The next commit will have
5387 two parents.
5388 two parents.
5388
5389
5389 ``--tool`` can be used to specify the merge tool used for file
5390 ``--tool`` can be used to specify the merge tool used for file
5390 merges. It overrides the HGMERGE environment variable and your
5391 merges. It overrides the HGMERGE environment variable and your
5391 configuration files. See :hg:`help merge-tools` for options.
5392 configuration files. See :hg:`help merge-tools` for options.
5392
5393
5393 If no revision is specified, the working directory's parent is a
5394 If no revision is specified, the working directory's parent is a
5394 head revision, and the current branch contains exactly one other
5395 head revision, and the current branch contains exactly one other
5395 head, the other head is merged with by default. Otherwise, an
5396 head, the other head is merged with by default. Otherwise, an
5396 explicit revision with which to merge with must be provided.
5397 explicit revision with which to merge with must be provided.
5397
5398
5398 See :hg:`help resolve` for information on handling file conflicts.
5399 See :hg:`help resolve` for information on handling file conflicts.
5399
5400
5400 To undo an uncommitted merge, use :hg:`update --clean .` which
5401 To undo an uncommitted merge, use :hg:`update --clean .` which
5401 will check out a clean copy of the original merge parent, losing
5402 will check out a clean copy of the original merge parent, losing
5402 all changes.
5403 all changes.
5403
5404
5404 Returns 0 on success, 1 if there are unresolved files.
5405 Returns 0 on success, 1 if there are unresolved files.
5405 """
5406 """
5406
5407
5407 if opts.get('rev') and node:
5408 if opts.get('rev') and node:
5408 raise error.Abort(_("please specify just one revision"))
5409 raise error.Abort(_("please specify just one revision"))
5409 if not node:
5410 if not node:
5410 node = opts.get('rev')
5411 node = opts.get('rev')
5411
5412
5412 if node:
5413 if node:
5413 node = scmutil.revsingle(repo, node).node()
5414 node = scmutil.revsingle(repo, node).node()
5414
5415
5415 if not node:
5416 if not node:
5416 node = repo[destutil.destmerge(repo)].node()
5417 node = repo[destutil.destmerge(repo)].node()
5417
5418
5418 if opts.get('preview'):
5419 if opts.get('preview'):
5419 # find nodes that are ancestors of p2 but not of p1
5420 # find nodes that are ancestors of p2 but not of p1
5420 p1 = repo.lookup('.')
5421 p1 = repo.lookup('.')
5421 p2 = repo.lookup(node)
5422 p2 = repo.lookup(node)
5422 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5423 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5423
5424
5424 displayer = cmdutil.show_changeset(ui, repo, opts)
5425 displayer = cmdutil.show_changeset(ui, repo, opts)
5425 for node in nodes:
5426 for node in nodes:
5426 displayer.show(repo[node])
5427 displayer.show(repo[node])
5427 displayer.close()
5428 displayer.close()
5428 return 0
5429 return 0
5429
5430
5430 try:
5431 try:
5431 # ui.forcemerge is an internal variable, do not document
5432 # ui.forcemerge is an internal variable, do not document
5432 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5433 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5433 force = opts.get('force')
5434 force = opts.get('force')
5434 return hg.merge(repo, node, force=force, mergeforce=force)
5435 return hg.merge(repo, node, force=force, mergeforce=force)
5435 finally:
5436 finally:
5436 ui.setconfig('ui', 'forcemerge', '', 'merge')
5437 ui.setconfig('ui', 'forcemerge', '', 'merge')
5437
5438
5438 @command('outgoing|out',
5439 @command('outgoing|out',
5439 [('f', 'force', None, _('run even when the destination is unrelated')),
5440 [('f', 'force', None, _('run even when the destination is unrelated')),
5440 ('r', 'rev', [],
5441 ('r', 'rev', [],
5441 _('a changeset intended to be included in the destination'), _('REV')),
5442 _('a changeset intended to be included in the destination'), _('REV')),
5442 ('n', 'newest-first', None, _('show newest record first')),
5443 ('n', 'newest-first', None, _('show newest record first')),
5443 ('B', 'bookmarks', False, _('compare bookmarks')),
5444 ('B', 'bookmarks', False, _('compare bookmarks')),
5444 ('b', 'branch', [], _('a specific branch you would like to push'),
5445 ('b', 'branch', [], _('a specific branch you would like to push'),
5445 _('BRANCH')),
5446 _('BRANCH')),
5446 ] + logopts + remoteopts + subrepoopts,
5447 ] + logopts + remoteopts + subrepoopts,
5447 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5448 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5448 def outgoing(ui, repo, dest=None, **opts):
5449 def outgoing(ui, repo, dest=None, **opts):
5449 """show changesets not found in the destination
5450 """show changesets not found in the destination
5450
5451
5451 Show changesets not found in the specified destination repository
5452 Show changesets not found in the specified destination repository
5452 or the default push location. These are the changesets that would
5453 or the default push location. These are the changesets that would
5453 be pushed if a push was requested.
5454 be pushed if a push was requested.
5454
5455
5455 See pull for details of valid destination formats.
5456 See pull for details of valid destination formats.
5456
5457
5457 .. container:: verbose
5458 .. container:: verbose
5458
5459
5459 With -B/--bookmarks, the result of bookmark comparison between
5460 With -B/--bookmarks, the result of bookmark comparison between
5460 local and remote repositories is displayed. With -v/--verbose,
5461 local and remote repositories is displayed. With -v/--verbose,
5461 status is also displayed for each bookmark like below::
5462 status is also displayed for each bookmark like below::
5462
5463
5463 BM1 01234567890a added
5464 BM1 01234567890a added
5464 BM2 deleted
5465 BM2 deleted
5465 BM3 234567890abc advanced
5466 BM3 234567890abc advanced
5466 BM4 34567890abcd diverged
5467 BM4 34567890abcd diverged
5467 BM5 4567890abcde changed
5468 BM5 4567890abcde changed
5468
5469
5469 The action taken when pushing depends on the
5470 The action taken when pushing depends on the
5470 status of each bookmark:
5471 status of each bookmark:
5471
5472
5472 :``added``: push with ``-B`` will create it
5473 :``added``: push with ``-B`` will create it
5473 :``deleted``: push with ``-B`` will delete it
5474 :``deleted``: push with ``-B`` will delete it
5474 :``advanced``: push will update it
5475 :``advanced``: push will update it
5475 :``diverged``: push with ``-B`` will update it
5476 :``diverged``: push with ``-B`` will update it
5476 :``changed``: push with ``-B`` will update it
5477 :``changed``: push with ``-B`` will update it
5477
5478
5478 From the point of view of pushing behavior, bookmarks
5479 From the point of view of pushing behavior, bookmarks
5479 existing only in the remote repository are treated as
5480 existing only in the remote repository are treated as
5480 ``deleted``, even if it is in fact added remotely.
5481 ``deleted``, even if it is in fact added remotely.
5481
5482
5482 Returns 0 if there are outgoing changes, 1 otherwise.
5483 Returns 0 if there are outgoing changes, 1 otherwise.
5483 """
5484 """
5484 if opts.get('graph'):
5485 if opts.get('graph'):
5485 cmdutil.checkunsupportedgraphflags([], opts)
5486 cmdutil.checkunsupportedgraphflags([], opts)
5486 o, other = hg._outgoing(ui, repo, dest, opts)
5487 o, other = hg._outgoing(ui, repo, dest, opts)
5487 if not o:
5488 if not o:
5488 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5489 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5489 return
5490 return
5490
5491
5491 revdag = cmdutil.graphrevs(repo, o, opts)
5492 revdag = cmdutil.graphrevs(repo, o, opts)
5492 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5493 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5493 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5494 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5494 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5495 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5495 return 0
5496 return 0
5496
5497
5497 if opts.get('bookmarks'):
5498 if opts.get('bookmarks'):
5498 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5499 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5499 dest, branches = hg.parseurl(dest, opts.get('branch'))
5500 dest, branches = hg.parseurl(dest, opts.get('branch'))
5500 other = hg.peer(repo, opts, dest)
5501 other = hg.peer(repo, opts, dest)
5501 if 'bookmarks' not in other.listkeys('namespaces'):
5502 if 'bookmarks' not in other.listkeys('namespaces'):
5502 ui.warn(_("remote doesn't support bookmarks\n"))
5503 ui.warn(_("remote doesn't support bookmarks\n"))
5503 return 0
5504 return 0
5504 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5505 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5505 return bookmarks.outgoing(ui, repo, other)
5506 return bookmarks.outgoing(ui, repo, other)
5506
5507
5507 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5508 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5508 try:
5509 try:
5509 return hg.outgoing(ui, repo, dest, opts)
5510 return hg.outgoing(ui, repo, dest, opts)
5510 finally:
5511 finally:
5511 del repo._subtoppath
5512 del repo._subtoppath
5512
5513
5513 @command('parents',
5514 @command('parents',
5514 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5515 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5515 ] + templateopts,
5516 ] + templateopts,
5516 _('[-r REV] [FILE]'),
5517 _('[-r REV] [FILE]'),
5517 inferrepo=True)
5518 inferrepo=True)
5518 def parents(ui, repo, file_=None, **opts):
5519 def parents(ui, repo, file_=None, **opts):
5519 """show the parents of the working directory or revision (DEPRECATED)
5520 """show the parents of the working directory or revision (DEPRECATED)
5520
5521
5521 Print the working directory's parent revisions. If a revision is
5522 Print the working directory's parent revisions. If a revision is
5522 given via -r/--rev, the parent of that revision will be printed.
5523 given via -r/--rev, the parent of that revision will be printed.
5523 If a file argument is given, the revision in which the file was
5524 If a file argument is given, the revision in which the file was
5524 last changed (before the working directory revision or the
5525 last changed (before the working directory revision or the
5525 argument to --rev if given) is printed.
5526 argument to --rev if given) is printed.
5526
5527
5527 This command is equivalent to::
5528 This command is equivalent to::
5528
5529
5529 hg log -r "p1()+p2()" or
5530 hg log -r "p1()+p2()" or
5530 hg log -r "p1(REV)+p2(REV)" or
5531 hg log -r "p1(REV)+p2(REV)" or
5531 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5532 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5532 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5533 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5533
5534
5534 See :hg:`summary` and :hg:`help revsets` for related information.
5535 See :hg:`summary` and :hg:`help revsets` for related information.
5535
5536
5536 Returns 0 on success.
5537 Returns 0 on success.
5537 """
5538 """
5538
5539
5539 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5540 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5540
5541
5541 if file_:
5542 if file_:
5542 m = scmutil.match(ctx, (file_,), opts)
5543 m = scmutil.match(ctx, (file_,), opts)
5543 if m.anypats() or len(m.files()) != 1:
5544 if m.anypats() or len(m.files()) != 1:
5544 raise error.Abort(_('can only specify an explicit filename'))
5545 raise error.Abort(_('can only specify an explicit filename'))
5545 file_ = m.files()[0]
5546 file_ = m.files()[0]
5546 filenodes = []
5547 filenodes = []
5547 for cp in ctx.parents():
5548 for cp in ctx.parents():
5548 if not cp:
5549 if not cp:
5549 continue
5550 continue
5550 try:
5551 try:
5551 filenodes.append(cp.filenode(file_))
5552 filenodes.append(cp.filenode(file_))
5552 except error.LookupError:
5553 except error.LookupError:
5553 pass
5554 pass
5554 if not filenodes:
5555 if not filenodes:
5555 raise error.Abort(_("'%s' not found in manifest!") % file_)
5556 raise error.Abort(_("'%s' not found in manifest!") % file_)
5556 p = []
5557 p = []
5557 for fn in filenodes:
5558 for fn in filenodes:
5558 fctx = repo.filectx(file_, fileid=fn)
5559 fctx = repo.filectx(file_, fileid=fn)
5559 p.append(fctx.node())
5560 p.append(fctx.node())
5560 else:
5561 else:
5561 p = [cp.node() for cp in ctx.parents()]
5562 p = [cp.node() for cp in ctx.parents()]
5562
5563
5563 displayer = cmdutil.show_changeset(ui, repo, opts)
5564 displayer = cmdutil.show_changeset(ui, repo, opts)
5564 for n in p:
5565 for n in p:
5565 if n != nullid:
5566 if n != nullid:
5566 displayer.show(repo[n])
5567 displayer.show(repo[n])
5567 displayer.close()
5568 displayer.close()
5568
5569
5569 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5570 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5570 def paths(ui, repo, search=None, **opts):
5571 def paths(ui, repo, search=None, **opts):
5571 """show aliases for remote repositories
5572 """show aliases for remote repositories
5572
5573
5573 Show definition of symbolic path name NAME. If no name is given,
5574 Show definition of symbolic path name NAME. If no name is given,
5574 show definition of all available names.
5575 show definition of all available names.
5575
5576
5576 Option -q/--quiet suppresses all output when searching for NAME
5577 Option -q/--quiet suppresses all output when searching for NAME
5577 and shows only the path names when listing all definitions.
5578 and shows only the path names when listing all definitions.
5578
5579
5579 Path names are defined in the [paths] section of your
5580 Path names are defined in the [paths] section of your
5580 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5581 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5581 repository, ``.hg/hgrc`` is used, too.
5582 repository, ``.hg/hgrc`` is used, too.
5582
5583
5583 The path names ``default`` and ``default-push`` have a special
5584 The path names ``default`` and ``default-push`` have a special
5584 meaning. When performing a push or pull operation, they are used
5585 meaning. When performing a push or pull operation, they are used
5585 as fallbacks if no location is specified on the command-line.
5586 as fallbacks if no location is specified on the command-line.
5586 When ``default-push`` is set, it will be used for push and
5587 When ``default-push`` is set, it will be used for push and
5587 ``default`` will be used for pull; otherwise ``default`` is used
5588 ``default`` will be used for pull; otherwise ``default`` is used
5588 as the fallback for both. When cloning a repository, the clone
5589 as the fallback for both. When cloning a repository, the clone
5589 source is written as ``default`` in ``.hg/hgrc``.
5590 source is written as ``default`` in ``.hg/hgrc``.
5590
5591
5591 .. note::
5592 .. note::
5592
5593
5593 ``default`` and ``default-push`` apply to all inbound (e.g.
5594 ``default`` and ``default-push`` apply to all inbound (e.g.
5594 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5595 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5595 and :hg:`bundle`) operations.
5596 and :hg:`bundle`) operations.
5596
5597
5597 See :hg:`help urls` for more information.
5598 See :hg:`help urls` for more information.
5598
5599
5599 Returns 0 on success.
5600 Returns 0 on success.
5600 """
5601 """
5601 if search:
5602 if search:
5602 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5603 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5603 if name == search]
5604 if name == search]
5604 else:
5605 else:
5605 pathitems = sorted(ui.paths.iteritems())
5606 pathitems = sorted(ui.paths.iteritems())
5606
5607
5607 fm = ui.formatter('paths', opts)
5608 fm = ui.formatter('paths', opts)
5608 if fm:
5609 if fm:
5609 hidepassword = str
5610 hidepassword = str
5610 else:
5611 else:
5611 hidepassword = util.hidepassword
5612 hidepassword = util.hidepassword
5612 if ui.quiet:
5613 if ui.quiet:
5613 namefmt = '%s\n'
5614 namefmt = '%s\n'
5614 else:
5615 else:
5615 namefmt = '%s = '
5616 namefmt = '%s = '
5616 showsubopts = not search and not ui.quiet
5617 showsubopts = not search and not ui.quiet
5617
5618
5618 for name, path in pathitems:
5619 for name, path in pathitems:
5619 fm.startitem()
5620 fm.startitem()
5620 fm.condwrite(not search, 'name', namefmt, name)
5621 fm.condwrite(not search, 'name', namefmt, name)
5621 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5622 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5622 for subopt, value in sorted(path.suboptions.items()):
5623 for subopt, value in sorted(path.suboptions.items()):
5623 assert subopt not in ('name', 'url')
5624 assert subopt not in ('name', 'url')
5624 if showsubopts:
5625 if showsubopts:
5625 fm.plain('%s:%s = ' % (name, subopt))
5626 fm.plain('%s:%s = ' % (name, subopt))
5626 fm.condwrite(showsubopts, subopt, '%s\n', value)
5627 fm.condwrite(showsubopts, subopt, '%s\n', value)
5627
5628
5628 fm.end()
5629 fm.end()
5629
5630
5630 if search and not pathitems:
5631 if search and not pathitems:
5631 if not ui.quiet:
5632 if not ui.quiet:
5632 ui.warn(_("not found!\n"))
5633 ui.warn(_("not found!\n"))
5633 return 1
5634 return 1
5634 else:
5635 else:
5635 return 0
5636 return 0
5636
5637
5637 @command('phase',
5638 @command('phase',
5638 [('p', 'public', False, _('set changeset phase to public')),
5639 [('p', 'public', False, _('set changeset phase to public')),
5639 ('d', 'draft', False, _('set changeset phase to draft')),
5640 ('d', 'draft', False, _('set changeset phase to draft')),
5640 ('s', 'secret', False, _('set changeset phase to secret')),
5641 ('s', 'secret', False, _('set changeset phase to secret')),
5641 ('f', 'force', False, _('allow to move boundary backward')),
5642 ('f', 'force', False, _('allow to move boundary backward')),
5642 ('r', 'rev', [], _('target revision'), _('REV')),
5643 ('r', 'rev', [], _('target revision'), _('REV')),
5643 ],
5644 ],
5644 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5645 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5645 def phase(ui, repo, *revs, **opts):
5646 def phase(ui, repo, *revs, **opts):
5646 """set or show the current phase name
5647 """set or show the current phase name
5647
5648
5648 With no argument, show the phase name of the current revision(s).
5649 With no argument, show the phase name of the current revision(s).
5649
5650
5650 With one of -p/--public, -d/--draft or -s/--secret, change the
5651 With one of -p/--public, -d/--draft or -s/--secret, change the
5651 phase value of the specified revisions.
5652 phase value of the specified revisions.
5652
5653
5653 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5654 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5654 lower phase to an higher phase. Phases are ordered as follows::
5655 lower phase to an higher phase. Phases are ordered as follows::
5655
5656
5656 public < draft < secret
5657 public < draft < secret
5657
5658
5658 Returns 0 on success, 1 if some phases could not be changed.
5659 Returns 0 on success, 1 if some phases could not be changed.
5659
5660
5660 (For more information about the phases concept, see :hg:`help phases`.)
5661 (For more information about the phases concept, see :hg:`help phases`.)
5661 """
5662 """
5662 # search for a unique phase argument
5663 # search for a unique phase argument
5663 targetphase = None
5664 targetphase = None
5664 for idx, name in enumerate(phases.phasenames):
5665 for idx, name in enumerate(phases.phasenames):
5665 if opts[name]:
5666 if opts[name]:
5666 if targetphase is not None:
5667 if targetphase is not None:
5667 raise error.Abort(_('only one phase can be specified'))
5668 raise error.Abort(_('only one phase can be specified'))
5668 targetphase = idx
5669 targetphase = idx
5669
5670
5670 # look for specified revision
5671 # look for specified revision
5671 revs = list(revs)
5672 revs = list(revs)
5672 revs.extend(opts['rev'])
5673 revs.extend(opts['rev'])
5673 if not revs:
5674 if not revs:
5674 # display both parents as the second parent phase can influence
5675 # display both parents as the second parent phase can influence
5675 # the phase of a merge commit
5676 # the phase of a merge commit
5676 revs = [c.rev() for c in repo[None].parents()]
5677 revs = [c.rev() for c in repo[None].parents()]
5677
5678
5678 revs = scmutil.revrange(repo, revs)
5679 revs = scmutil.revrange(repo, revs)
5679
5680
5680 lock = None
5681 lock = None
5681 ret = 0
5682 ret = 0
5682 if targetphase is None:
5683 if targetphase is None:
5683 # display
5684 # display
5684 for r in revs:
5685 for r in revs:
5685 ctx = repo[r]
5686 ctx = repo[r]
5686 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5687 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5687 else:
5688 else:
5688 tr = None
5689 tr = None
5689 lock = repo.lock()
5690 lock = repo.lock()
5690 try:
5691 try:
5691 tr = repo.transaction("phase")
5692 tr = repo.transaction("phase")
5692 # set phase
5693 # set phase
5693 if not revs:
5694 if not revs:
5694 raise error.Abort(_('empty revision set'))
5695 raise error.Abort(_('empty revision set'))
5695 nodes = [repo[r].node() for r in revs]
5696 nodes = [repo[r].node() for r in revs]
5696 # moving revision from public to draft may hide them
5697 # moving revision from public to draft may hide them
5697 # We have to check result on an unfiltered repository
5698 # We have to check result on an unfiltered repository
5698 unfi = repo.unfiltered()
5699 unfi = repo.unfiltered()
5699 getphase = unfi._phasecache.phase
5700 getphase = unfi._phasecache.phase
5700 olddata = [getphase(unfi, r) for r in unfi]
5701 olddata = [getphase(unfi, r) for r in unfi]
5701 phases.advanceboundary(repo, tr, targetphase, nodes)
5702 phases.advanceboundary(repo, tr, targetphase, nodes)
5702 if opts['force']:
5703 if opts['force']:
5703 phases.retractboundary(repo, tr, targetphase, nodes)
5704 phases.retractboundary(repo, tr, targetphase, nodes)
5704 tr.close()
5705 tr.close()
5705 finally:
5706 finally:
5706 if tr is not None:
5707 if tr is not None:
5707 tr.release()
5708 tr.release()
5708 lock.release()
5709 lock.release()
5709 getphase = unfi._phasecache.phase
5710 getphase = unfi._phasecache.phase
5710 newdata = [getphase(unfi, r) for r in unfi]
5711 newdata = [getphase(unfi, r) for r in unfi]
5711 changes = sum(newdata[r] != olddata[r] for r in unfi)
5712 changes = sum(newdata[r] != olddata[r] for r in unfi)
5712 cl = unfi.changelog
5713 cl = unfi.changelog
5713 rejected = [n for n in nodes
5714 rejected = [n for n in nodes
5714 if newdata[cl.rev(n)] < targetphase]
5715 if newdata[cl.rev(n)] < targetphase]
5715 if rejected:
5716 if rejected:
5716 ui.warn(_('cannot move %i changesets to a higher '
5717 ui.warn(_('cannot move %i changesets to a higher '
5717 'phase, use --force\n') % len(rejected))
5718 'phase, use --force\n') % len(rejected))
5718 ret = 1
5719 ret = 1
5719 if changes:
5720 if changes:
5720 msg = _('phase changed for %i changesets\n') % changes
5721 msg = _('phase changed for %i changesets\n') % changes
5721 if ret:
5722 if ret:
5722 ui.status(msg)
5723 ui.status(msg)
5723 else:
5724 else:
5724 ui.note(msg)
5725 ui.note(msg)
5725 else:
5726 else:
5726 ui.warn(_('no phases changed\n'))
5727 ui.warn(_('no phases changed\n'))
5727 return ret
5728 return ret
5728
5729
5729 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5730 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5730 """Run after a changegroup has been added via pull/unbundle
5731 """Run after a changegroup has been added via pull/unbundle
5731
5732
5732 This takes arguments below:
5733 This takes arguments below:
5733
5734
5734 :modheads: change of heads by pull/unbundle
5735 :modheads: change of heads by pull/unbundle
5735 :optupdate: updating working directory is needed or not
5736 :optupdate: updating working directory is needed or not
5736 :checkout: update destination revision (or None to default destination)
5737 :checkout: update destination revision (or None to default destination)
5737 :brev: a name, which might be a bookmark to be activated after updating
5738 :brev: a name, which might be a bookmark to be activated after updating
5738 """
5739 """
5739 if modheads == 0:
5740 if modheads == 0:
5740 return
5741 return
5741 if optupdate:
5742 if optupdate:
5742 try:
5743 try:
5743 return hg.updatetotally(ui, repo, checkout, brev)
5744 return hg.updatetotally(ui, repo, checkout, brev)
5744 except error.UpdateAbort as inst:
5745 except error.UpdateAbort as inst:
5745 msg = _("not updating: %s") % str(inst)
5746 msg = _("not updating: %s") % str(inst)
5746 hint = inst.hint
5747 hint = inst.hint
5747 raise error.UpdateAbort(msg, hint=hint)
5748 raise error.UpdateAbort(msg, hint=hint)
5748 if modheads > 1:
5749 if modheads > 1:
5749 currentbranchheads = len(repo.branchheads())
5750 currentbranchheads = len(repo.branchheads())
5750 if currentbranchheads == modheads:
5751 if currentbranchheads == modheads:
5751 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5752 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5752 elif currentbranchheads > 1:
5753 elif currentbranchheads > 1:
5753 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5754 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5754 "merge)\n"))
5755 "merge)\n"))
5755 else:
5756 else:
5756 ui.status(_("(run 'hg heads' to see heads)\n"))
5757 ui.status(_("(run 'hg heads' to see heads)\n"))
5757 else:
5758 else:
5758 ui.status(_("(run 'hg update' to get a working copy)\n"))
5759 ui.status(_("(run 'hg update' to get a working copy)\n"))
5759
5760
5760 @command('^pull',
5761 @command('^pull',
5761 [('u', 'update', None,
5762 [('u', 'update', None,
5762 _('update to new branch head if changesets were pulled')),
5763 _('update to new branch head if changesets were pulled')),
5763 ('f', 'force', None, _('run even when remote repository is unrelated')),
5764 ('f', 'force', None, _('run even when remote repository is unrelated')),
5764 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5765 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5765 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5766 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5766 ('b', 'branch', [], _('a specific branch you would like to pull'),
5767 ('b', 'branch', [], _('a specific branch you would like to pull'),
5767 _('BRANCH')),
5768 _('BRANCH')),
5768 ] + remoteopts,
5769 ] + remoteopts,
5769 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5770 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5770 def pull(ui, repo, source="default", **opts):
5771 def pull(ui, repo, source="default", **opts):
5771 """pull changes from the specified source
5772 """pull changes from the specified source
5772
5773
5773 Pull changes from a remote repository to a local one.
5774 Pull changes from a remote repository to a local one.
5774
5775
5775 This finds all changes from the repository at the specified path
5776 This finds all changes from the repository at the specified path
5776 or URL and adds them to a local repository (the current one unless
5777 or URL and adds them to a local repository (the current one unless
5777 -R is specified). By default, this does not update the copy of the
5778 -R is specified). By default, this does not update the copy of the
5778 project in the working directory.
5779 project in the working directory.
5779
5780
5780 Use :hg:`incoming` if you want to see what would have been added
5781 Use :hg:`incoming` if you want to see what would have been added
5781 by a pull at the time you issued this command. If you then decide
5782 by a pull at the time you issued this command. If you then decide
5782 to add those changes to the repository, you should use :hg:`pull
5783 to add those changes to the repository, you should use :hg:`pull
5783 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5784 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5784
5785
5785 If SOURCE is omitted, the 'default' path will be used.
5786 If SOURCE is omitted, the 'default' path will be used.
5786 See :hg:`help urls` for more information.
5787 See :hg:`help urls` for more information.
5787
5788
5788 Specifying bookmark as ``.`` is equivalent to specifying the active
5789 Specifying bookmark as ``.`` is equivalent to specifying the active
5789 bookmark's name.
5790 bookmark's name.
5790
5791
5791 Returns 0 on success, 1 if an update had unresolved files.
5792 Returns 0 on success, 1 if an update had unresolved files.
5792 """
5793 """
5793 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5794 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5794 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5795 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5795 other = hg.peer(repo, opts, source)
5796 other = hg.peer(repo, opts, source)
5796 try:
5797 try:
5797 revs, checkout = hg.addbranchrevs(repo, other, branches,
5798 revs, checkout = hg.addbranchrevs(repo, other, branches,
5798 opts.get('rev'))
5799 opts.get('rev'))
5799
5800
5800
5801
5801 pullopargs = {}
5802 pullopargs = {}
5802 if opts.get('bookmark'):
5803 if opts.get('bookmark'):
5803 if not revs:
5804 if not revs:
5804 revs = []
5805 revs = []
5805 # The list of bookmark used here is not the one used to actually
5806 # The list of bookmark used here is not the one used to actually
5806 # update the bookmark name. This can result in the revision pulled
5807 # update the bookmark name. This can result in the revision pulled
5807 # not ending up with the name of the bookmark because of a race
5808 # not ending up with the name of the bookmark because of a race
5808 # condition on the server. (See issue 4689 for details)
5809 # condition on the server. (See issue 4689 for details)
5809 remotebookmarks = other.listkeys('bookmarks')
5810 remotebookmarks = other.listkeys('bookmarks')
5810 pullopargs['remotebookmarks'] = remotebookmarks
5811 pullopargs['remotebookmarks'] = remotebookmarks
5811 for b in opts['bookmark']:
5812 for b in opts['bookmark']:
5812 b = repo._bookmarks.expandname(b)
5813 b = repo._bookmarks.expandname(b)
5813 if b not in remotebookmarks:
5814 if b not in remotebookmarks:
5814 raise error.Abort(_('remote bookmark %s not found!') % b)
5815 raise error.Abort(_('remote bookmark %s not found!') % b)
5815 revs.append(remotebookmarks[b])
5816 revs.append(remotebookmarks[b])
5816
5817
5817 if revs:
5818 if revs:
5818 try:
5819 try:
5819 # When 'rev' is a bookmark name, we cannot guarantee that it
5820 # When 'rev' is a bookmark name, we cannot guarantee that it
5820 # will be updated with that name because of a race condition
5821 # will be updated with that name because of a race condition
5821 # server side. (See issue 4689 for details)
5822 # server side. (See issue 4689 for details)
5822 oldrevs = revs
5823 oldrevs = revs
5823 revs = [] # actually, nodes
5824 revs = [] # actually, nodes
5824 for r in oldrevs:
5825 for r in oldrevs:
5825 node = other.lookup(r)
5826 node = other.lookup(r)
5826 revs.append(node)
5827 revs.append(node)
5827 if r == checkout:
5828 if r == checkout:
5828 checkout = node
5829 checkout = node
5829 except error.CapabilityError:
5830 except error.CapabilityError:
5830 err = _("other repository doesn't support revision lookup, "
5831 err = _("other repository doesn't support revision lookup, "
5831 "so a rev cannot be specified.")
5832 "so a rev cannot be specified.")
5832 raise error.Abort(err)
5833 raise error.Abort(err)
5833
5834
5834 pullopargs.update(opts.get('opargs', {}))
5835 pullopargs.update(opts.get('opargs', {}))
5835 modheads = exchange.pull(repo, other, heads=revs,
5836 modheads = exchange.pull(repo, other, heads=revs,
5836 force=opts.get('force'),
5837 force=opts.get('force'),
5837 bookmarks=opts.get('bookmark', ()),
5838 bookmarks=opts.get('bookmark', ()),
5838 opargs=pullopargs).cgresult
5839 opargs=pullopargs).cgresult
5839
5840
5840 # brev is a name, which might be a bookmark to be activated at
5841 # brev is a name, which might be a bookmark to be activated at
5841 # the end of the update. In other words, it is an explicit
5842 # the end of the update. In other words, it is an explicit
5842 # destination of the update
5843 # destination of the update
5843 brev = None
5844 brev = None
5844
5845
5845 if checkout:
5846 if checkout:
5846 checkout = str(repo.changelog.rev(checkout))
5847 checkout = str(repo.changelog.rev(checkout))
5847
5848
5848 # order below depends on implementation of
5849 # order below depends on implementation of
5849 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5850 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5850 # because 'checkout' is determined without it.
5851 # because 'checkout' is determined without it.
5851 if opts.get('rev'):
5852 if opts.get('rev'):
5852 brev = opts['rev'][0]
5853 brev = opts['rev'][0]
5853 elif opts.get('branch'):
5854 elif opts.get('branch'):
5854 brev = opts['branch'][0]
5855 brev = opts['branch'][0]
5855 else:
5856 else:
5856 brev = branches[0]
5857 brev = branches[0]
5857 repo._subtoppath = source
5858 repo._subtoppath = source
5858 try:
5859 try:
5859 ret = postincoming(ui, repo, modheads, opts.get('update'),
5860 ret = postincoming(ui, repo, modheads, opts.get('update'),
5860 checkout, brev)
5861 checkout, brev)
5861
5862
5862 finally:
5863 finally:
5863 del repo._subtoppath
5864 del repo._subtoppath
5864
5865
5865 finally:
5866 finally:
5866 other.close()
5867 other.close()
5867 return ret
5868 return ret
5868
5869
5869 @command('^push',
5870 @command('^push',
5870 [('f', 'force', None, _('force push')),
5871 [('f', 'force', None, _('force push')),
5871 ('r', 'rev', [],
5872 ('r', 'rev', [],
5872 _('a changeset intended to be included in the destination'),
5873 _('a changeset intended to be included in the destination'),
5873 _('REV')),
5874 _('REV')),
5874 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5875 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5875 ('b', 'branch', [],
5876 ('b', 'branch', [],
5876 _('a specific branch you would like to push'), _('BRANCH')),
5877 _('a specific branch you would like to push'), _('BRANCH')),
5877 ('', 'new-branch', False, _('allow pushing a new branch')),
5878 ('', 'new-branch', False, _('allow pushing a new branch')),
5878 ] + remoteopts,
5879 ] + remoteopts,
5879 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5880 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5880 def push(ui, repo, dest=None, **opts):
5881 def push(ui, repo, dest=None, **opts):
5881 """push changes to the specified destination
5882 """push changes to the specified destination
5882
5883
5883 Push changesets from the local repository to the specified
5884 Push changesets from the local repository to the specified
5884 destination.
5885 destination.
5885
5886
5886 This operation is symmetrical to pull: it is identical to a pull
5887 This operation is symmetrical to pull: it is identical to a pull
5887 in the destination repository from the current one.
5888 in the destination repository from the current one.
5888
5889
5889 By default, push will not allow creation of new heads at the
5890 By default, push will not allow creation of new heads at the
5890 destination, since multiple heads would make it unclear which head
5891 destination, since multiple heads would make it unclear which head
5891 to use. In this situation, it is recommended to pull and merge
5892 to use. In this situation, it is recommended to pull and merge
5892 before pushing.
5893 before pushing.
5893
5894
5894 Use --new-branch if you want to allow push to create a new named
5895 Use --new-branch if you want to allow push to create a new named
5895 branch that is not present at the destination. This allows you to
5896 branch that is not present at the destination. This allows you to
5896 only create a new branch without forcing other changes.
5897 only create a new branch without forcing other changes.
5897
5898
5898 .. note::
5899 .. note::
5899
5900
5900 Extra care should be taken with the -f/--force option,
5901 Extra care should be taken with the -f/--force option,
5901 which will push all new heads on all branches, an action which will
5902 which will push all new heads on all branches, an action which will
5902 almost always cause confusion for collaborators.
5903 almost always cause confusion for collaborators.
5903
5904
5904 If -r/--rev is used, the specified revision and all its ancestors
5905 If -r/--rev is used, the specified revision and all its ancestors
5905 will be pushed to the remote repository.
5906 will be pushed to the remote repository.
5906
5907
5907 If -B/--bookmark is used, the specified bookmarked revision, its
5908 If -B/--bookmark is used, the specified bookmarked revision, its
5908 ancestors, and the bookmark will be pushed to the remote
5909 ancestors, and the bookmark will be pushed to the remote
5909 repository. Specifying ``.`` is equivalent to specifying the active
5910 repository. Specifying ``.`` is equivalent to specifying the active
5910 bookmark's name.
5911 bookmark's name.
5911
5912
5912 Please see :hg:`help urls` for important details about ``ssh://``
5913 Please see :hg:`help urls` for important details about ``ssh://``
5913 URLs. If DESTINATION is omitted, a default path will be used.
5914 URLs. If DESTINATION is omitted, a default path will be used.
5914
5915
5915 Returns 0 if push was successful, 1 if nothing to push.
5916 Returns 0 if push was successful, 1 if nothing to push.
5916 """
5917 """
5917
5918
5918 if opts.get('bookmark'):
5919 if opts.get('bookmark'):
5919 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5920 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5920 for b in opts['bookmark']:
5921 for b in opts['bookmark']:
5921 # translate -B options to -r so changesets get pushed
5922 # translate -B options to -r so changesets get pushed
5922 b = repo._bookmarks.expandname(b)
5923 b = repo._bookmarks.expandname(b)
5923 if b in repo._bookmarks:
5924 if b in repo._bookmarks:
5924 opts.setdefault('rev', []).append(b)
5925 opts.setdefault('rev', []).append(b)
5925 else:
5926 else:
5926 # if we try to push a deleted bookmark, translate it to null
5927 # if we try to push a deleted bookmark, translate it to null
5927 # this lets simultaneous -r, -b options continue working
5928 # this lets simultaneous -r, -b options continue working
5928 opts.setdefault('rev', []).append("null")
5929 opts.setdefault('rev', []).append("null")
5929
5930
5930 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5931 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5931 if not path:
5932 if not path:
5932 raise error.Abort(_('default repository not configured!'),
5933 raise error.Abort(_('default repository not configured!'),
5933 hint=_('see the "path" section in "hg help config"'))
5934 hint=_('see the "path" section in "hg help config"'))
5934 dest = path.pushloc or path.loc
5935 dest = path.pushloc or path.loc
5935 branches = (path.branch, opts.get('branch') or [])
5936 branches = (path.branch, opts.get('branch') or [])
5936 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5937 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5937 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5938 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5938 other = hg.peer(repo, opts, dest)
5939 other = hg.peer(repo, opts, dest)
5939
5940
5940 if revs:
5941 if revs:
5941 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5942 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5942 if not revs:
5943 if not revs:
5943 raise error.Abort(_("specified revisions evaluate to an empty set"),
5944 raise error.Abort(_("specified revisions evaluate to an empty set"),
5944 hint=_("use different revision arguments"))
5945 hint=_("use different revision arguments"))
5945 elif path.pushrev:
5946 elif path.pushrev:
5946 # It doesn't make any sense to specify ancestor revisions. So limit
5947 # It doesn't make any sense to specify ancestor revisions. So limit
5947 # to DAG heads to make discovery simpler.
5948 # to DAG heads to make discovery simpler.
5948 expr = revset.formatspec('heads(%r)', path.pushrev)
5949 expr = revset.formatspec('heads(%r)', path.pushrev)
5949 revs = scmutil.revrange(repo, [expr])
5950 revs = scmutil.revrange(repo, [expr])
5950 revs = [repo[rev].node() for rev in revs]
5951 revs = [repo[rev].node() for rev in revs]
5951 if not revs:
5952 if not revs:
5952 raise error.Abort(_('default push revset for path evaluates to an '
5953 raise error.Abort(_('default push revset for path evaluates to an '
5953 'empty set'))
5954 'empty set'))
5954
5955
5955 repo._subtoppath = dest
5956 repo._subtoppath = dest
5956 try:
5957 try:
5957 # push subrepos depth-first for coherent ordering
5958 # push subrepos depth-first for coherent ordering
5958 c = repo['']
5959 c = repo['']
5959 subs = c.substate # only repos that are committed
5960 subs = c.substate # only repos that are committed
5960 for s in sorted(subs):
5961 for s in sorted(subs):
5961 result = c.sub(s).push(opts)
5962 result = c.sub(s).push(opts)
5962 if result == 0:
5963 if result == 0:
5963 return not result
5964 return not result
5964 finally:
5965 finally:
5965 del repo._subtoppath
5966 del repo._subtoppath
5966 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5967 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5967 newbranch=opts.get('new_branch'),
5968 newbranch=opts.get('new_branch'),
5968 bookmarks=opts.get('bookmark', ()),
5969 bookmarks=opts.get('bookmark', ()),
5969 opargs=opts.get('opargs'))
5970 opargs=opts.get('opargs'))
5970
5971
5971 result = not pushop.cgresult
5972 result = not pushop.cgresult
5972
5973
5973 if pushop.bkresult is not None:
5974 if pushop.bkresult is not None:
5974 if pushop.bkresult == 2:
5975 if pushop.bkresult == 2:
5975 result = 2
5976 result = 2
5976 elif not result and pushop.bkresult:
5977 elif not result and pushop.bkresult:
5977 result = 2
5978 result = 2
5978
5979
5979 return result
5980 return result
5980
5981
5981 @command('recover', [])
5982 @command('recover', [])
5982 def recover(ui, repo):
5983 def recover(ui, repo):
5983 """roll back an interrupted transaction
5984 """roll back an interrupted transaction
5984
5985
5985 Recover from an interrupted commit or pull.
5986 Recover from an interrupted commit or pull.
5986
5987
5987 This command tries to fix the repository status after an
5988 This command tries to fix the repository status after an
5988 interrupted operation. It should only be necessary when Mercurial
5989 interrupted operation. It should only be necessary when Mercurial
5989 suggests it.
5990 suggests it.
5990
5991
5991 Returns 0 if successful, 1 if nothing to recover or verify fails.
5992 Returns 0 if successful, 1 if nothing to recover or verify fails.
5992 """
5993 """
5993 if repo.recover():
5994 if repo.recover():
5994 return hg.verify(repo)
5995 return hg.verify(repo)
5995 return 1
5996 return 1
5996
5997
5997 @command('^remove|rm',
5998 @command('^remove|rm',
5998 [('A', 'after', None, _('record delete for missing files')),
5999 [('A', 'after', None, _('record delete for missing files')),
5999 ('f', 'force', None,
6000 ('f', 'force', None,
6000 _('forget added files, delete modified files')),
6001 _('forget added files, delete modified files')),
6001 ] + subrepoopts + walkopts,
6002 ] + subrepoopts + walkopts,
6002 _('[OPTION]... FILE...'),
6003 _('[OPTION]... FILE...'),
6003 inferrepo=True)
6004 inferrepo=True)
6004 def remove(ui, repo, *pats, **opts):
6005 def remove(ui, repo, *pats, **opts):
6005 """remove the specified files on the next commit
6006 """remove the specified files on the next commit
6006
6007
6007 Schedule the indicated files for removal from the current branch.
6008 Schedule the indicated files for removal from the current branch.
6008
6009
6009 This command schedules the files to be removed at the next commit.
6010 This command schedules the files to be removed at the next commit.
6010 To undo a remove before that, see :hg:`revert`. To undo added
6011 To undo a remove before that, see :hg:`revert`. To undo added
6011 files, see :hg:`forget`.
6012 files, see :hg:`forget`.
6012
6013
6013 .. container:: verbose
6014 .. container:: verbose
6014
6015
6015 -A/--after can be used to remove only files that have already
6016 -A/--after can be used to remove only files that have already
6016 been deleted, -f/--force can be used to force deletion, and -Af
6017 been deleted, -f/--force can be used to force deletion, and -Af
6017 can be used to remove files from the next revision without
6018 can be used to remove files from the next revision without
6018 deleting them from the working directory.
6019 deleting them from the working directory.
6019
6020
6020 The following table details the behavior of remove for different
6021 The following table details the behavior of remove for different
6021 file states (columns) and option combinations (rows). The file
6022 file states (columns) and option combinations (rows). The file
6022 states are Added [A], Clean [C], Modified [M] and Missing [!]
6023 states are Added [A], Clean [C], Modified [M] and Missing [!]
6023 (as reported by :hg:`status`). The actions are Warn, Remove
6024 (as reported by :hg:`status`). The actions are Warn, Remove
6024 (from branch) and Delete (from disk):
6025 (from branch) and Delete (from disk):
6025
6026
6026 ========= == == == ==
6027 ========= == == == ==
6027 opt/state A C M !
6028 opt/state A C M !
6028 ========= == == == ==
6029 ========= == == == ==
6029 none W RD W R
6030 none W RD W R
6030 -f R RD RD R
6031 -f R RD RD R
6031 -A W W W R
6032 -A W W W R
6032 -Af R R R R
6033 -Af R R R R
6033 ========= == == == ==
6034 ========= == == == ==
6034
6035
6035 .. note::
6036 .. note::
6036
6037
6037 :hg:`remove` never deletes files in Added [A] state from the
6038 :hg:`remove` never deletes files in Added [A] state from the
6038 working directory, not even if ``--force`` is specified.
6039 working directory, not even if ``--force`` is specified.
6039
6040
6040 Returns 0 on success, 1 if any warnings encountered.
6041 Returns 0 on success, 1 if any warnings encountered.
6041 """
6042 """
6042
6043
6043 after, force = opts.get('after'), opts.get('force')
6044 after, force = opts.get('after'), opts.get('force')
6044 if not pats and not after:
6045 if not pats and not after:
6045 raise error.Abort(_('no files specified'))
6046 raise error.Abort(_('no files specified'))
6046
6047
6047 m = scmutil.match(repo[None], pats, opts)
6048 m = scmutil.match(repo[None], pats, opts)
6048 subrepos = opts.get('subrepos')
6049 subrepos = opts.get('subrepos')
6049 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6050 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6050
6051
6051 @command('rename|move|mv',
6052 @command('rename|move|mv',
6052 [('A', 'after', None, _('record a rename that has already occurred')),
6053 [('A', 'after', None, _('record a rename that has already occurred')),
6053 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6054 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6054 ] + walkopts + dryrunopts,
6055 ] + walkopts + dryrunopts,
6055 _('[OPTION]... SOURCE... DEST'))
6056 _('[OPTION]... SOURCE... DEST'))
6056 def rename(ui, repo, *pats, **opts):
6057 def rename(ui, repo, *pats, **opts):
6057 """rename files; equivalent of copy + remove
6058 """rename files; equivalent of copy + remove
6058
6059
6059 Mark dest as copies of sources; mark sources for deletion. If dest
6060 Mark dest as copies of sources; mark sources for deletion. If dest
6060 is a directory, copies are put in that directory. If dest is a
6061 is a directory, copies are put in that directory. If dest is a
6061 file, there can only be one source.
6062 file, there can only be one source.
6062
6063
6063 By default, this command copies the contents of files as they
6064 By default, this command copies the contents of files as they
6064 exist in the working directory. If invoked with -A/--after, the
6065 exist in the working directory. If invoked with -A/--after, the
6065 operation is recorded, but no copying is performed.
6066 operation is recorded, but no copying is performed.
6066
6067
6067 This command takes effect at the next commit. To undo a rename
6068 This command takes effect at the next commit. To undo a rename
6068 before that, see :hg:`revert`.
6069 before that, see :hg:`revert`.
6069
6070
6070 Returns 0 on success, 1 if errors are encountered.
6071 Returns 0 on success, 1 if errors are encountered.
6071 """
6072 """
6072 with repo.wlock(False):
6073 with repo.wlock(False):
6073 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6074 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6074
6075
6075 @command('resolve',
6076 @command('resolve',
6076 [('a', 'all', None, _('select all unresolved files')),
6077 [('a', 'all', None, _('select all unresolved files')),
6077 ('l', 'list', None, _('list state of files needing merge')),
6078 ('l', 'list', None, _('list state of files needing merge')),
6078 ('m', 'mark', None, _('mark files as resolved')),
6079 ('m', 'mark', None, _('mark files as resolved')),
6079 ('u', 'unmark', None, _('mark files as unresolved')),
6080 ('u', 'unmark', None, _('mark files as unresolved')),
6080 ('n', 'no-status', None, _('hide status prefix'))]
6081 ('n', 'no-status', None, _('hide status prefix'))]
6081 + mergetoolopts + walkopts + formatteropts,
6082 + mergetoolopts + walkopts + formatteropts,
6082 _('[OPTION]... [FILE]...'),
6083 _('[OPTION]... [FILE]...'),
6083 inferrepo=True)
6084 inferrepo=True)
6084 def resolve(ui, repo, *pats, **opts):
6085 def resolve(ui, repo, *pats, **opts):
6085 """redo merges or set/view the merge status of files
6086 """redo merges or set/view the merge status of files
6086
6087
6087 Merges with unresolved conflicts are often the result of
6088 Merges with unresolved conflicts are often the result of
6088 non-interactive merging using the ``internal:merge`` configuration
6089 non-interactive merging using the ``internal:merge`` configuration
6089 setting, or a command-line merge tool like ``diff3``. The resolve
6090 setting, or a command-line merge tool like ``diff3``. The resolve
6090 command is used to manage the files involved in a merge, after
6091 command is used to manage the files involved in a merge, after
6091 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6092 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6092 working directory must have two parents). See :hg:`help
6093 working directory must have two parents). See :hg:`help
6093 merge-tools` for information on configuring merge tools.
6094 merge-tools` for information on configuring merge tools.
6094
6095
6095 The resolve command can be used in the following ways:
6096 The resolve command can be used in the following ways:
6096
6097
6097 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6098 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6098 files, discarding any previous merge attempts. Re-merging is not
6099 files, discarding any previous merge attempts. Re-merging is not
6099 performed for files already marked as resolved. Use ``--all/-a``
6100 performed for files already marked as resolved. Use ``--all/-a``
6100 to select all unresolved files. ``--tool`` can be used to specify
6101 to select all unresolved files. ``--tool`` can be used to specify
6101 the merge tool used for the given files. It overrides the HGMERGE
6102 the merge tool used for the given files. It overrides the HGMERGE
6102 environment variable and your configuration files. Previous file
6103 environment variable and your configuration files. Previous file
6103 contents are saved with a ``.orig`` suffix.
6104 contents are saved with a ``.orig`` suffix.
6104
6105
6105 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6106 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6106 (e.g. after having manually fixed-up the files). The default is
6107 (e.g. after having manually fixed-up the files). The default is
6107 to mark all unresolved files.
6108 to mark all unresolved files.
6108
6109
6109 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6110 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6110 default is to mark all resolved files.
6111 default is to mark all resolved files.
6111
6112
6112 - :hg:`resolve -l`: list files which had or still have conflicts.
6113 - :hg:`resolve -l`: list files which had or still have conflicts.
6113 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6114 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6114
6115
6115 .. note::
6116 .. note::
6116
6117
6117 Mercurial will not let you commit files with unresolved merge
6118 Mercurial will not let you commit files with unresolved merge
6118 conflicts. You must use :hg:`resolve -m ...` before you can
6119 conflicts. You must use :hg:`resolve -m ...` before you can
6119 commit after a conflicting merge.
6120 commit after a conflicting merge.
6120
6121
6121 Returns 0 on success, 1 if any files fail a resolve attempt.
6122 Returns 0 on success, 1 if any files fail a resolve attempt.
6122 """
6123 """
6123
6124
6124 flaglist = 'all mark unmark list no_status'.split()
6125 flaglist = 'all mark unmark list no_status'.split()
6125 all, mark, unmark, show, nostatus = \
6126 all, mark, unmark, show, nostatus = \
6126 [opts.get(o) for o in flaglist]
6127 [opts.get(o) for o in flaglist]
6127
6128
6128 if (show and (mark or unmark)) or (mark and unmark):
6129 if (show and (mark or unmark)) or (mark and unmark):
6129 raise error.Abort(_("too many options specified"))
6130 raise error.Abort(_("too many options specified"))
6130 if pats and all:
6131 if pats and all:
6131 raise error.Abort(_("can't specify --all and patterns"))
6132 raise error.Abort(_("can't specify --all and patterns"))
6132 if not (all or pats or show or mark or unmark):
6133 if not (all or pats or show or mark or unmark):
6133 raise error.Abort(_('no files or directories specified'),
6134 raise error.Abort(_('no files or directories specified'),
6134 hint=('use --all to re-merge all unresolved files'))
6135 hint=('use --all to re-merge all unresolved files'))
6135
6136
6136 if show:
6137 if show:
6137 fm = ui.formatter('resolve', opts)
6138 fm = ui.formatter('resolve', opts)
6138 ms = mergemod.mergestate.read(repo)
6139 ms = mergemod.mergestate.read(repo)
6139 m = scmutil.match(repo[None], pats, opts)
6140 m = scmutil.match(repo[None], pats, opts)
6140 for f in ms:
6141 for f in ms:
6141 if not m(f):
6142 if not m(f):
6142 continue
6143 continue
6143 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6144 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6144 'd': 'driverresolved'}[ms[f]]
6145 'd': 'driverresolved'}[ms[f]]
6145 fm.startitem()
6146 fm.startitem()
6146 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6147 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6147 fm.write('path', '%s\n', f, label=l)
6148 fm.write('path', '%s\n', f, label=l)
6148 fm.end()
6149 fm.end()
6149 return 0
6150 return 0
6150
6151
6151 with repo.wlock():
6152 with repo.wlock():
6152 ms = mergemod.mergestate.read(repo)
6153 ms = mergemod.mergestate.read(repo)
6153
6154
6154 if not (ms.active() or repo.dirstate.p2() != nullid):
6155 if not (ms.active() or repo.dirstate.p2() != nullid):
6155 raise error.Abort(
6156 raise error.Abort(
6156 _('resolve command not applicable when not merging'))
6157 _('resolve command not applicable when not merging'))
6157
6158
6158 wctx = repo[None]
6159 wctx = repo[None]
6159
6160
6160 if ms.mergedriver and ms.mdstate() == 'u':
6161 if ms.mergedriver and ms.mdstate() == 'u':
6161 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6162 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6162 ms.commit()
6163 ms.commit()
6163 # allow mark and unmark to go through
6164 # allow mark and unmark to go through
6164 if not mark and not unmark and not proceed:
6165 if not mark and not unmark and not proceed:
6165 return 1
6166 return 1
6166
6167
6167 m = scmutil.match(wctx, pats, opts)
6168 m = scmutil.match(wctx, pats, opts)
6168 ret = 0
6169 ret = 0
6169 didwork = False
6170 didwork = False
6170 runconclude = False
6171 runconclude = False
6171
6172
6172 tocomplete = []
6173 tocomplete = []
6173 for f in ms:
6174 for f in ms:
6174 if not m(f):
6175 if not m(f):
6175 continue
6176 continue
6176
6177
6177 didwork = True
6178 didwork = True
6178
6179
6179 # don't let driver-resolved files be marked, and run the conclude
6180 # don't let driver-resolved files be marked, and run the conclude
6180 # step if asked to resolve
6181 # step if asked to resolve
6181 if ms[f] == "d":
6182 if ms[f] == "d":
6182 exact = m.exact(f)
6183 exact = m.exact(f)
6183 if mark:
6184 if mark:
6184 if exact:
6185 if exact:
6185 ui.warn(_('not marking %s as it is driver-resolved\n')
6186 ui.warn(_('not marking %s as it is driver-resolved\n')
6186 % f)
6187 % f)
6187 elif unmark:
6188 elif unmark:
6188 if exact:
6189 if exact:
6189 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6190 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6190 % f)
6191 % f)
6191 else:
6192 else:
6192 runconclude = True
6193 runconclude = True
6193 continue
6194 continue
6194
6195
6195 if mark:
6196 if mark:
6196 ms.mark(f, "r")
6197 ms.mark(f, "r")
6197 elif unmark:
6198 elif unmark:
6198 ms.mark(f, "u")
6199 ms.mark(f, "u")
6199 else:
6200 else:
6200 # backup pre-resolve (merge uses .orig for its own purposes)
6201 # backup pre-resolve (merge uses .orig for its own purposes)
6201 a = repo.wjoin(f)
6202 a = repo.wjoin(f)
6202 try:
6203 try:
6203 util.copyfile(a, a + ".resolve")
6204 util.copyfile(a, a + ".resolve")
6204 except (IOError, OSError) as inst:
6205 except (IOError, OSError) as inst:
6205 if inst.errno != errno.ENOENT:
6206 if inst.errno != errno.ENOENT:
6206 raise
6207 raise
6207
6208
6208 try:
6209 try:
6209 # preresolve file
6210 # preresolve file
6210 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6211 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6211 'resolve')
6212 'resolve')
6212 complete, r = ms.preresolve(f, wctx)
6213 complete, r = ms.preresolve(f, wctx)
6213 if not complete:
6214 if not complete:
6214 tocomplete.append(f)
6215 tocomplete.append(f)
6215 elif r:
6216 elif r:
6216 ret = 1
6217 ret = 1
6217 finally:
6218 finally:
6218 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6219 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6219 ms.commit()
6220 ms.commit()
6220
6221
6221 # replace filemerge's .orig file with our resolve file, but only
6222 # replace filemerge's .orig file with our resolve file, but only
6222 # for merges that are complete
6223 # for merges that are complete
6223 if complete:
6224 if complete:
6224 try:
6225 try:
6225 util.rename(a + ".resolve",
6226 util.rename(a + ".resolve",
6226 scmutil.origpath(ui, repo, a))
6227 scmutil.origpath(ui, repo, a))
6227 except OSError as inst:
6228 except OSError as inst:
6228 if inst.errno != errno.ENOENT:
6229 if inst.errno != errno.ENOENT:
6229 raise
6230 raise
6230
6231
6231 for f in tocomplete:
6232 for f in tocomplete:
6232 try:
6233 try:
6233 # resolve file
6234 # resolve file
6234 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6235 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6235 'resolve')
6236 'resolve')
6236 r = ms.resolve(f, wctx)
6237 r = ms.resolve(f, wctx)
6237 if r:
6238 if r:
6238 ret = 1
6239 ret = 1
6239 finally:
6240 finally:
6240 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6241 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6241 ms.commit()
6242 ms.commit()
6242
6243
6243 # replace filemerge's .orig file with our resolve file
6244 # replace filemerge's .orig file with our resolve file
6244 a = repo.wjoin(f)
6245 a = repo.wjoin(f)
6245 try:
6246 try:
6246 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6247 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6247 except OSError as inst:
6248 except OSError as inst:
6248 if inst.errno != errno.ENOENT:
6249 if inst.errno != errno.ENOENT:
6249 raise
6250 raise
6250
6251
6251 ms.commit()
6252 ms.commit()
6252 ms.recordactions()
6253 ms.recordactions()
6253
6254
6254 if not didwork and pats:
6255 if not didwork and pats:
6255 hint = None
6256 hint = None
6256 if not any([p for p in pats if p.find(':') >= 0]):
6257 if not any([p for p in pats if p.find(':') >= 0]):
6257 pats = ['path:%s' % p for p in pats]
6258 pats = ['path:%s' % p for p in pats]
6258 m = scmutil.match(wctx, pats, opts)
6259 m = scmutil.match(wctx, pats, opts)
6259 for f in ms:
6260 for f in ms:
6260 if not m(f):
6261 if not m(f):
6261 continue
6262 continue
6262 flags = ''.join(['-%s ' % o[0] for o in flaglist
6263 flags = ''.join(['-%s ' % o[0] for o in flaglist
6263 if opts.get(o)])
6264 if opts.get(o)])
6264 hint = _("(try: hg resolve %s%s)\n") % (
6265 hint = _("(try: hg resolve %s%s)\n") % (
6265 flags,
6266 flags,
6266 ' '.join(pats))
6267 ' '.join(pats))
6267 break
6268 break
6268 ui.warn(_("arguments do not match paths that need resolving\n"))
6269 ui.warn(_("arguments do not match paths that need resolving\n"))
6269 if hint:
6270 if hint:
6270 ui.warn(hint)
6271 ui.warn(hint)
6271 elif ms.mergedriver and ms.mdstate() != 's':
6272 elif ms.mergedriver and ms.mdstate() != 's':
6272 # run conclude step when either a driver-resolved file is requested
6273 # run conclude step when either a driver-resolved file is requested
6273 # or there are no driver-resolved files
6274 # or there are no driver-resolved files
6274 # we can't use 'ret' to determine whether any files are unresolved
6275 # we can't use 'ret' to determine whether any files are unresolved
6275 # because we might not have tried to resolve some
6276 # because we might not have tried to resolve some
6276 if ((runconclude or not list(ms.driverresolved()))
6277 if ((runconclude or not list(ms.driverresolved()))
6277 and not list(ms.unresolved())):
6278 and not list(ms.unresolved())):
6278 proceed = mergemod.driverconclude(repo, ms, wctx)
6279 proceed = mergemod.driverconclude(repo, ms, wctx)
6279 ms.commit()
6280 ms.commit()
6280 if not proceed:
6281 if not proceed:
6281 return 1
6282 return 1
6282
6283
6283 # Nudge users into finishing an unfinished operation
6284 # Nudge users into finishing an unfinished operation
6284 unresolvedf = list(ms.unresolved())
6285 unresolvedf = list(ms.unresolved())
6285 driverresolvedf = list(ms.driverresolved())
6286 driverresolvedf = list(ms.driverresolved())
6286 if not unresolvedf and not driverresolvedf:
6287 if not unresolvedf and not driverresolvedf:
6287 ui.status(_('(no more unresolved files)\n'))
6288 ui.status(_('(no more unresolved files)\n'))
6288 cmdutil.checkafterresolved(repo)
6289 cmdutil.checkafterresolved(repo)
6289 elif not unresolvedf:
6290 elif not unresolvedf:
6290 ui.status(_('(no more unresolved files -- '
6291 ui.status(_('(no more unresolved files -- '
6291 'run "hg resolve --all" to conclude)\n'))
6292 'run "hg resolve --all" to conclude)\n'))
6292
6293
6293 return ret
6294 return ret
6294
6295
6295 @command('revert',
6296 @command('revert',
6296 [('a', 'all', None, _('revert all changes when no arguments given')),
6297 [('a', 'all', None, _('revert all changes when no arguments given')),
6297 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6298 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6298 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6299 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6299 ('C', 'no-backup', None, _('do not save backup copies of files')),
6300 ('C', 'no-backup', None, _('do not save backup copies of files')),
6300 ('i', 'interactive', None,
6301 ('i', 'interactive', None,
6301 _('interactively select the changes (EXPERIMENTAL)')),
6302 _('interactively select the changes (EXPERIMENTAL)')),
6302 ] + walkopts + dryrunopts,
6303 ] + walkopts + dryrunopts,
6303 _('[OPTION]... [-r REV] [NAME]...'))
6304 _('[OPTION]... [-r REV] [NAME]...'))
6304 def revert(ui, repo, *pats, **opts):
6305 def revert(ui, repo, *pats, **opts):
6305 """restore files to their checkout state
6306 """restore files to their checkout state
6306
6307
6307 .. note::
6308 .. note::
6308
6309
6309 To check out earlier revisions, you should use :hg:`update REV`.
6310 To check out earlier revisions, you should use :hg:`update REV`.
6310 To cancel an uncommitted merge (and lose your changes),
6311 To cancel an uncommitted merge (and lose your changes),
6311 use :hg:`update --clean .`.
6312 use :hg:`update --clean .`.
6312
6313
6313 With no revision specified, revert the specified files or directories
6314 With no revision specified, revert the specified files or directories
6314 to the contents they had in the parent of the working directory.
6315 to the contents they had in the parent of the working directory.
6315 This restores the contents of files to an unmodified
6316 This restores the contents of files to an unmodified
6316 state and unschedules adds, removes, copies, and renames. If the
6317 state and unschedules adds, removes, copies, and renames. If the
6317 working directory has two parents, you must explicitly specify a
6318 working directory has two parents, you must explicitly specify a
6318 revision.
6319 revision.
6319
6320
6320 Using the -r/--rev or -d/--date options, revert the given files or
6321 Using the -r/--rev or -d/--date options, revert the given files or
6321 directories to their states as of a specific revision. Because
6322 directories to their states as of a specific revision. Because
6322 revert does not change the working directory parents, this will
6323 revert does not change the working directory parents, this will
6323 cause these files to appear modified. This can be helpful to "back
6324 cause these files to appear modified. This can be helpful to "back
6324 out" some or all of an earlier change. See :hg:`backout` for a
6325 out" some or all of an earlier change. See :hg:`backout` for a
6325 related method.
6326 related method.
6326
6327
6327 Modified files are saved with a .orig suffix before reverting.
6328 Modified files are saved with a .orig suffix before reverting.
6328 To disable these backups, use --no-backup. It is possible to store
6329 To disable these backups, use --no-backup. It is possible to store
6329 the backup files in a custom directory relative to the root of the
6330 the backup files in a custom directory relative to the root of the
6330 repository by setting the ``ui.origbackuppath`` configuration
6331 repository by setting the ``ui.origbackuppath`` configuration
6331 option.
6332 option.
6332
6333
6333 See :hg:`help dates` for a list of formats valid for -d/--date.
6334 See :hg:`help dates` for a list of formats valid for -d/--date.
6334
6335
6335 See :hg:`help backout` for a way to reverse the effect of an
6336 See :hg:`help backout` for a way to reverse the effect of an
6336 earlier changeset.
6337 earlier changeset.
6337
6338
6338 Returns 0 on success.
6339 Returns 0 on success.
6339 """
6340 """
6340
6341
6341 if opts.get("date"):
6342 if opts.get("date"):
6342 if opts.get("rev"):
6343 if opts.get("rev"):
6343 raise error.Abort(_("you can't specify a revision and a date"))
6344 raise error.Abort(_("you can't specify a revision and a date"))
6344 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6345 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6345
6346
6346 parent, p2 = repo.dirstate.parents()
6347 parent, p2 = repo.dirstate.parents()
6347 if not opts.get('rev') and p2 != nullid:
6348 if not opts.get('rev') and p2 != nullid:
6348 # revert after merge is a trap for new users (issue2915)
6349 # revert after merge is a trap for new users (issue2915)
6349 raise error.Abort(_('uncommitted merge with no revision specified'),
6350 raise error.Abort(_('uncommitted merge with no revision specified'),
6350 hint=_("use 'hg update' or see 'hg help revert'"))
6351 hint=_("use 'hg update' or see 'hg help revert'"))
6351
6352
6352 ctx = scmutil.revsingle(repo, opts.get('rev'))
6353 ctx = scmutil.revsingle(repo, opts.get('rev'))
6353
6354
6354 if (not (pats or opts.get('include') or opts.get('exclude') or
6355 if (not (pats or opts.get('include') or opts.get('exclude') or
6355 opts.get('all') or opts.get('interactive'))):
6356 opts.get('all') or opts.get('interactive'))):
6356 msg = _("no files or directories specified")
6357 msg = _("no files or directories specified")
6357 if p2 != nullid:
6358 if p2 != nullid:
6358 hint = _("uncommitted merge, use --all to discard all changes,"
6359 hint = _("uncommitted merge, use --all to discard all changes,"
6359 " or 'hg update -C .' to abort the merge")
6360 " or 'hg update -C .' to abort the merge")
6360 raise error.Abort(msg, hint=hint)
6361 raise error.Abort(msg, hint=hint)
6361 dirty = any(repo.status())
6362 dirty = any(repo.status())
6362 node = ctx.node()
6363 node = ctx.node()
6363 if node != parent:
6364 if node != parent:
6364 if dirty:
6365 if dirty:
6365 hint = _("uncommitted changes, use --all to discard all"
6366 hint = _("uncommitted changes, use --all to discard all"
6366 " changes, or 'hg update %s' to update") % ctx.rev()
6367 " changes, or 'hg update %s' to update") % ctx.rev()
6367 else:
6368 else:
6368 hint = _("use --all to revert all files,"
6369 hint = _("use --all to revert all files,"
6369 " or 'hg update %s' to update") % ctx.rev()
6370 " or 'hg update %s' to update") % ctx.rev()
6370 elif dirty:
6371 elif dirty:
6371 hint = _("uncommitted changes, use --all to discard all changes")
6372 hint = _("uncommitted changes, use --all to discard all changes")
6372 else:
6373 else:
6373 hint = _("use --all to revert all files")
6374 hint = _("use --all to revert all files")
6374 raise error.Abort(msg, hint=hint)
6375 raise error.Abort(msg, hint=hint)
6375
6376
6376 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6377 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6377
6378
6378 @command('rollback', dryrunopts +
6379 @command('rollback', dryrunopts +
6379 [('f', 'force', False, _('ignore safety measures'))])
6380 [('f', 'force', False, _('ignore safety measures'))])
6380 def rollback(ui, repo, **opts):
6381 def rollback(ui, repo, **opts):
6381 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6382 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6382
6383
6383 Please use :hg:`commit --amend` instead of rollback to correct
6384 Please use :hg:`commit --amend` instead of rollback to correct
6384 mistakes in the last commit.
6385 mistakes in the last commit.
6385
6386
6386 This command should be used with care. There is only one level of
6387 This command should be used with care. There is only one level of
6387 rollback, and there is no way to undo a rollback. It will also
6388 rollback, and there is no way to undo a rollback. It will also
6388 restore the dirstate at the time of the last transaction, losing
6389 restore the dirstate at the time of the last transaction, losing
6389 any dirstate changes since that time. This command does not alter
6390 any dirstate changes since that time. This command does not alter
6390 the working directory.
6391 the working directory.
6391
6392
6392 Transactions are used to encapsulate the effects of all commands
6393 Transactions are used to encapsulate the effects of all commands
6393 that create new changesets or propagate existing changesets into a
6394 that create new changesets or propagate existing changesets into a
6394 repository.
6395 repository.
6395
6396
6396 .. container:: verbose
6397 .. container:: verbose
6397
6398
6398 For example, the following commands are transactional, and their
6399 For example, the following commands are transactional, and their
6399 effects can be rolled back:
6400 effects can be rolled back:
6400
6401
6401 - commit
6402 - commit
6402 - import
6403 - import
6403 - pull
6404 - pull
6404 - push (with this repository as the destination)
6405 - push (with this repository as the destination)
6405 - unbundle
6406 - unbundle
6406
6407
6407 To avoid permanent data loss, rollback will refuse to rollback a
6408 To avoid permanent data loss, rollback will refuse to rollback a
6408 commit transaction if it isn't checked out. Use --force to
6409 commit transaction if it isn't checked out. Use --force to
6409 override this protection.
6410 override this protection.
6410
6411
6411 The rollback command can be entirely disabled by setting the
6412 The rollback command can be entirely disabled by setting the
6412 ``ui.rollback`` configuration setting to false. If you're here
6413 ``ui.rollback`` configuration setting to false. If you're here
6413 because you want to use rollback and it's disabled, you can
6414 because you want to use rollback and it's disabled, you can
6414 re-enable the command by setting ``ui.rollback`` to true.
6415 re-enable the command by setting ``ui.rollback`` to true.
6415
6416
6416 This command is not intended for use on public repositories. Once
6417 This command is not intended for use on public repositories. Once
6417 changes are visible for pull by other users, rolling a transaction
6418 changes are visible for pull by other users, rolling a transaction
6418 back locally is ineffective (someone else may already have pulled
6419 back locally is ineffective (someone else may already have pulled
6419 the changes). Furthermore, a race is possible with readers of the
6420 the changes). Furthermore, a race is possible with readers of the
6420 repository; for example an in-progress pull from the repository
6421 repository; for example an in-progress pull from the repository
6421 may fail if a rollback is performed.
6422 may fail if a rollback is performed.
6422
6423
6423 Returns 0 on success, 1 if no rollback data is available.
6424 Returns 0 on success, 1 if no rollback data is available.
6424 """
6425 """
6425 if not ui.configbool('ui', 'rollback', True):
6426 if not ui.configbool('ui', 'rollback', True):
6426 raise error.Abort(_('rollback is disabled because it is unsafe'),
6427 raise error.Abort(_('rollback is disabled because it is unsafe'),
6427 hint=('see `hg help -v rollback` for information'))
6428 hint=('see `hg help -v rollback` for information'))
6428 return repo.rollback(dryrun=opts.get('dry_run'),
6429 return repo.rollback(dryrun=opts.get('dry_run'),
6429 force=opts.get('force'))
6430 force=opts.get('force'))
6430
6431
6431 @command('root', [])
6432 @command('root', [])
6432 def root(ui, repo):
6433 def root(ui, repo):
6433 """print the root (top) of the current working directory
6434 """print the root (top) of the current working directory
6434
6435
6435 Print the root directory of the current repository.
6436 Print the root directory of the current repository.
6436
6437
6437 Returns 0 on success.
6438 Returns 0 on success.
6438 """
6439 """
6439 ui.write(repo.root + "\n")
6440 ui.write(repo.root + "\n")
6440
6441
6441 @command('^serve',
6442 @command('^serve',
6442 [('A', 'accesslog', '', _('name of access log file to write to'),
6443 [('A', 'accesslog', '', _('name of access log file to write to'),
6443 _('FILE')),
6444 _('FILE')),
6444 ('d', 'daemon', None, _('run server in background')),
6445 ('d', 'daemon', None, _('run server in background')),
6445 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6446 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6446 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6447 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6447 # use string type, then we can check if something was passed
6448 # use string type, then we can check if something was passed
6448 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6449 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6449 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6450 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6450 _('ADDR')),
6451 _('ADDR')),
6451 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6452 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6452 _('PREFIX')),
6453 _('PREFIX')),
6453 ('n', 'name', '',
6454 ('n', 'name', '',
6454 _('name to show in web pages (default: working directory)'), _('NAME')),
6455 _('name to show in web pages (default: working directory)'), _('NAME')),
6455 ('', 'web-conf', '',
6456 ('', 'web-conf', '',
6456 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6457 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6457 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6458 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6458 _('FILE')),
6459 _('FILE')),
6459 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6460 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6460 ('', 'stdio', None, _('for remote clients')),
6461 ('', 'stdio', None, _('for remote clients')),
6461 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6462 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6462 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6463 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6463 ('', 'style', '', _('template style to use'), _('STYLE')),
6464 ('', 'style', '', _('template style to use'), _('STYLE')),
6464 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6465 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6465 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6466 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6466 _('[OPTION]...'),
6467 _('[OPTION]...'),
6467 optionalrepo=True)
6468 optionalrepo=True)
6468 def serve(ui, repo, **opts):
6469 def serve(ui, repo, **opts):
6469 """start stand-alone webserver
6470 """start stand-alone webserver
6470
6471
6471 Start a local HTTP repository browser and pull server. You can use
6472 Start a local HTTP repository browser and pull server. You can use
6472 this for ad-hoc sharing and browsing of repositories. It is
6473 this for ad-hoc sharing and browsing of repositories. It is
6473 recommended to use a real web server to serve a repository for
6474 recommended to use a real web server to serve a repository for
6474 longer periods of time.
6475 longer periods of time.
6475
6476
6476 Please note that the server does not implement access control.
6477 Please note that the server does not implement access control.
6477 This means that, by default, anybody can read from the server and
6478 This means that, by default, anybody can read from the server and
6478 nobody can write to it by default. Set the ``web.allow_push``
6479 nobody can write to it by default. Set the ``web.allow_push``
6479 option to ``*`` to allow everybody to push to the server. You
6480 option to ``*`` to allow everybody to push to the server. You
6480 should use a real web server if you need to authenticate users.
6481 should use a real web server if you need to authenticate users.
6481
6482
6482 By default, the server logs accesses to stdout and errors to
6483 By default, the server logs accesses to stdout and errors to
6483 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6484 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6484 files.
6485 files.
6485
6486
6486 To have the server choose a free port number to listen on, specify
6487 To have the server choose a free port number to listen on, specify
6487 a port number of 0; in this case, the server will print the port
6488 a port number of 0; in this case, the server will print the port
6488 number it uses.
6489 number it uses.
6489
6490
6490 Returns 0 on success.
6491 Returns 0 on success.
6491 """
6492 """
6492
6493
6493 if opts["stdio"] and opts["cmdserver"]:
6494 if opts["stdio"] and opts["cmdserver"]:
6494 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6495 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6495
6496
6496 if opts["stdio"]:
6497 if opts["stdio"]:
6497 if repo is None:
6498 if repo is None:
6498 raise error.RepoError(_("there is no Mercurial repository here"
6499 raise error.RepoError(_("there is no Mercurial repository here"
6499 " (.hg not found)"))
6500 " (.hg not found)"))
6500 s = sshserver.sshserver(ui, repo)
6501 s = sshserver.sshserver(ui, repo)
6501 s.serve_forever()
6502 s.serve_forever()
6502
6503
6503 if opts["cmdserver"]:
6504 if opts["cmdserver"]:
6504 service = commandserver.createservice(ui, repo, opts)
6505 service = commandserver.createservice(ui, repo, opts)
6505 else:
6506 else:
6506 service = hgweb.createservice(ui, repo, opts)
6507 service = hgweb.createservice(ui, repo, opts)
6507 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6508 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6508
6509
6509 @command('^status|st',
6510 @command('^status|st',
6510 [('A', 'all', None, _('show status of all files')),
6511 [('A', 'all', None, _('show status of all files')),
6511 ('m', 'modified', None, _('show only modified files')),
6512 ('m', 'modified', None, _('show only modified files')),
6512 ('a', 'added', None, _('show only added files')),
6513 ('a', 'added', None, _('show only added files')),
6513 ('r', 'removed', None, _('show only removed files')),
6514 ('r', 'removed', None, _('show only removed files')),
6514 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6515 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6515 ('c', 'clean', None, _('show only files without changes')),
6516 ('c', 'clean', None, _('show only files without changes')),
6516 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6517 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6517 ('i', 'ignored', None, _('show only ignored files')),
6518 ('i', 'ignored', None, _('show only ignored files')),
6518 ('n', 'no-status', None, _('hide status prefix')),
6519 ('n', 'no-status', None, _('hide status prefix')),
6519 ('C', 'copies', None, _('show source of copied files')),
6520 ('C', 'copies', None, _('show source of copied files')),
6520 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6521 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6521 ('', 'rev', [], _('show difference from revision'), _('REV')),
6522 ('', 'rev', [], _('show difference from revision'), _('REV')),
6522 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6523 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6523 ] + walkopts + subrepoopts + formatteropts,
6524 ] + walkopts + subrepoopts + formatteropts,
6524 _('[OPTION]... [FILE]...'),
6525 _('[OPTION]... [FILE]...'),
6525 inferrepo=True)
6526 inferrepo=True)
6526 def status(ui, repo, *pats, **opts):
6527 def status(ui, repo, *pats, **opts):
6527 """show changed files in the working directory
6528 """show changed files in the working directory
6528
6529
6529 Show status of files in the repository. If names are given, only
6530 Show status of files in the repository. If names are given, only
6530 files that match are shown. Files that are clean or ignored or
6531 files that match are shown. Files that are clean or ignored or
6531 the source of a copy/move operation, are not listed unless
6532 the source of a copy/move operation, are not listed unless
6532 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6533 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6533 Unless options described with "show only ..." are given, the
6534 Unless options described with "show only ..." are given, the
6534 options -mardu are used.
6535 options -mardu are used.
6535
6536
6536 Option -q/--quiet hides untracked (unknown and ignored) files
6537 Option -q/--quiet hides untracked (unknown and ignored) files
6537 unless explicitly requested with -u/--unknown or -i/--ignored.
6538 unless explicitly requested with -u/--unknown or -i/--ignored.
6538
6539
6539 .. note::
6540 .. note::
6540
6541
6541 :hg:`status` may appear to disagree with diff if permissions have
6542 :hg:`status` may appear to disagree with diff if permissions have
6542 changed or a merge has occurred. The standard diff format does
6543 changed or a merge has occurred. The standard diff format does
6543 not report permission changes and diff only reports changes
6544 not report permission changes and diff only reports changes
6544 relative to one merge parent.
6545 relative to one merge parent.
6545
6546
6546 If one revision is given, it is used as the base revision.
6547 If one revision is given, it is used as the base revision.
6547 If two revisions are given, the differences between them are
6548 If two revisions are given, the differences between them are
6548 shown. The --change option can also be used as a shortcut to list
6549 shown. The --change option can also be used as a shortcut to list
6549 the changed files of a revision from its first parent.
6550 the changed files of a revision from its first parent.
6550
6551
6551 The codes used to show the status of files are::
6552 The codes used to show the status of files are::
6552
6553
6553 M = modified
6554 M = modified
6554 A = added
6555 A = added
6555 R = removed
6556 R = removed
6556 C = clean
6557 C = clean
6557 ! = missing (deleted by non-hg command, but still tracked)
6558 ! = missing (deleted by non-hg command, but still tracked)
6558 ? = not tracked
6559 ? = not tracked
6559 I = ignored
6560 I = ignored
6560 = origin of the previous file (with --copies)
6561 = origin of the previous file (with --copies)
6561
6562
6562 .. container:: verbose
6563 .. container:: verbose
6563
6564
6564 Examples:
6565 Examples:
6565
6566
6566 - show changes in the working directory relative to a
6567 - show changes in the working directory relative to a
6567 changeset::
6568 changeset::
6568
6569
6569 hg status --rev 9353
6570 hg status --rev 9353
6570
6571
6571 - show changes in the working directory relative to the
6572 - show changes in the working directory relative to the
6572 current directory (see :hg:`help patterns` for more information)::
6573 current directory (see :hg:`help patterns` for more information)::
6573
6574
6574 hg status re:
6575 hg status re:
6575
6576
6576 - show all changes including copies in an existing changeset::
6577 - show all changes including copies in an existing changeset::
6577
6578
6578 hg status --copies --change 9353
6579 hg status --copies --change 9353
6579
6580
6580 - get a NUL separated list of added files, suitable for xargs::
6581 - get a NUL separated list of added files, suitable for xargs::
6581
6582
6582 hg status -an0
6583 hg status -an0
6583
6584
6584 Returns 0 on success.
6585 Returns 0 on success.
6585 """
6586 """
6586
6587
6587 revs = opts.get('rev')
6588 revs = opts.get('rev')
6588 change = opts.get('change')
6589 change = opts.get('change')
6589
6590
6590 if revs and change:
6591 if revs and change:
6591 msg = _('cannot specify --rev and --change at the same time')
6592 msg = _('cannot specify --rev and --change at the same time')
6592 raise error.Abort(msg)
6593 raise error.Abort(msg)
6593 elif change:
6594 elif change:
6594 node2 = scmutil.revsingle(repo, change, None).node()
6595 node2 = scmutil.revsingle(repo, change, None).node()
6595 node1 = repo[node2].p1().node()
6596 node1 = repo[node2].p1().node()
6596 else:
6597 else:
6597 node1, node2 = scmutil.revpair(repo, revs)
6598 node1, node2 = scmutil.revpair(repo, revs)
6598
6599
6599 if pats:
6600 if pats:
6600 cwd = repo.getcwd()
6601 cwd = repo.getcwd()
6601 else:
6602 else:
6602 cwd = ''
6603 cwd = ''
6603
6604
6604 if opts.get('print0'):
6605 if opts.get('print0'):
6605 end = '\0'
6606 end = '\0'
6606 else:
6607 else:
6607 end = '\n'
6608 end = '\n'
6608 copy = {}
6609 copy = {}
6609 states = 'modified added removed deleted unknown ignored clean'.split()
6610 states = 'modified added removed deleted unknown ignored clean'.split()
6610 show = [k for k in states if opts.get(k)]
6611 show = [k for k in states if opts.get(k)]
6611 if opts.get('all'):
6612 if opts.get('all'):
6612 show += ui.quiet and (states[:4] + ['clean']) or states
6613 show += ui.quiet and (states[:4] + ['clean']) or states
6613 if not show:
6614 if not show:
6614 if ui.quiet:
6615 if ui.quiet:
6615 show = states[:4]
6616 show = states[:4]
6616 else:
6617 else:
6617 show = states[:5]
6618 show = states[:5]
6618
6619
6619 m = scmutil.match(repo[node2], pats, opts)
6620 m = scmutil.match(repo[node2], pats, opts)
6620 stat = repo.status(node1, node2, m,
6621 stat = repo.status(node1, node2, m,
6621 'ignored' in show, 'clean' in show, 'unknown' in show,
6622 'ignored' in show, 'clean' in show, 'unknown' in show,
6622 opts.get('subrepos'))
6623 opts.get('subrepos'))
6623 changestates = zip(states, 'MAR!?IC', stat)
6624 changestates = zip(states, 'MAR!?IC', stat)
6624
6625
6625 if (opts.get('all') or opts.get('copies')
6626 if (opts.get('all') or opts.get('copies')
6626 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6627 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6627 copy = copies.pathcopies(repo[node1], repo[node2], m)
6628 copy = copies.pathcopies(repo[node1], repo[node2], m)
6628
6629
6629 fm = ui.formatter('status', opts)
6630 fm = ui.formatter('status', opts)
6630 fmt = '%s' + end
6631 fmt = '%s' + end
6631 showchar = not opts.get('no_status')
6632 showchar = not opts.get('no_status')
6632
6633
6633 for state, char, files in changestates:
6634 for state, char, files in changestates:
6634 if state in show:
6635 if state in show:
6635 label = 'status.' + state
6636 label = 'status.' + state
6636 for f in files:
6637 for f in files:
6637 fm.startitem()
6638 fm.startitem()
6638 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6639 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6639 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6640 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6640 if f in copy:
6641 if f in copy:
6641 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6642 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6642 label='status.copied')
6643 label='status.copied')
6643 fm.end()
6644 fm.end()
6644
6645
6645 @command('^summary|sum',
6646 @command('^summary|sum',
6646 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6647 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6647 def summary(ui, repo, **opts):
6648 def summary(ui, repo, **opts):
6648 """summarize working directory state
6649 """summarize working directory state
6649
6650
6650 This generates a brief summary of the working directory state,
6651 This generates a brief summary of the working directory state,
6651 including parents, branch, commit status, phase and available updates.
6652 including parents, branch, commit status, phase and available updates.
6652
6653
6653 With the --remote option, this will check the default paths for
6654 With the --remote option, this will check the default paths for
6654 incoming and outgoing changes. This can be time-consuming.
6655 incoming and outgoing changes. This can be time-consuming.
6655
6656
6656 Returns 0 on success.
6657 Returns 0 on success.
6657 """
6658 """
6658
6659
6659 ctx = repo[None]
6660 ctx = repo[None]
6660 parents = ctx.parents()
6661 parents = ctx.parents()
6661 pnode = parents[0].node()
6662 pnode = parents[0].node()
6662 marks = []
6663 marks = []
6663
6664
6664 ms = None
6665 ms = None
6665 try:
6666 try:
6666 ms = mergemod.mergestate.read(repo)
6667 ms = mergemod.mergestate.read(repo)
6667 except error.UnsupportedMergeRecords as e:
6668 except error.UnsupportedMergeRecords as e:
6668 s = ' '.join(e.recordtypes)
6669 s = ' '.join(e.recordtypes)
6669 ui.warn(
6670 ui.warn(
6670 _('warning: merge state has unsupported record types: %s\n') % s)
6671 _('warning: merge state has unsupported record types: %s\n') % s)
6671 unresolved = 0
6672 unresolved = 0
6672 else:
6673 else:
6673 unresolved = [f for f in ms if ms[f] == 'u']
6674 unresolved = [f for f in ms if ms[f] == 'u']
6674
6675
6675 for p in parents:
6676 for p in parents:
6676 # label with log.changeset (instead of log.parent) since this
6677 # label with log.changeset (instead of log.parent) since this
6677 # shows a working directory parent *changeset*:
6678 # shows a working directory parent *changeset*:
6678 # i18n: column positioning for "hg summary"
6679 # i18n: column positioning for "hg summary"
6679 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6680 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6680 label='log.changeset changeset.%s' % p.phasestr())
6681 label='log.changeset changeset.%s' % p.phasestr())
6681 ui.write(' '.join(p.tags()), label='log.tag')
6682 ui.write(' '.join(p.tags()), label='log.tag')
6682 if p.bookmarks():
6683 if p.bookmarks():
6683 marks.extend(p.bookmarks())
6684 marks.extend(p.bookmarks())
6684 if p.rev() == -1:
6685 if p.rev() == -1:
6685 if not len(repo):
6686 if not len(repo):
6686 ui.write(_(' (empty repository)'))
6687 ui.write(_(' (empty repository)'))
6687 else:
6688 else:
6688 ui.write(_(' (no revision checked out)'))
6689 ui.write(_(' (no revision checked out)'))
6689 ui.write('\n')
6690 ui.write('\n')
6690 if p.description():
6691 if p.description():
6691 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6692 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6692 label='log.summary')
6693 label='log.summary')
6693
6694
6694 branch = ctx.branch()
6695 branch = ctx.branch()
6695 bheads = repo.branchheads(branch)
6696 bheads = repo.branchheads(branch)
6696 # i18n: column positioning for "hg summary"
6697 # i18n: column positioning for "hg summary"
6697 m = _('branch: %s\n') % branch
6698 m = _('branch: %s\n') % branch
6698 if branch != 'default':
6699 if branch != 'default':
6699 ui.write(m, label='log.branch')
6700 ui.write(m, label='log.branch')
6700 else:
6701 else:
6701 ui.status(m, label='log.branch')
6702 ui.status(m, label='log.branch')
6702
6703
6703 if marks:
6704 if marks:
6704 active = repo._activebookmark
6705 active = repo._activebookmark
6705 # i18n: column positioning for "hg summary"
6706 # i18n: column positioning for "hg summary"
6706 ui.write(_('bookmarks:'), label='log.bookmark')
6707 ui.write(_('bookmarks:'), label='log.bookmark')
6707 if active is not None:
6708 if active is not None:
6708 if active in marks:
6709 if active in marks:
6709 ui.write(' *' + active, label=activebookmarklabel)
6710 ui.write(' *' + active, label=activebookmarklabel)
6710 marks.remove(active)
6711 marks.remove(active)
6711 else:
6712 else:
6712 ui.write(' [%s]' % active, label=activebookmarklabel)
6713 ui.write(' [%s]' % active, label=activebookmarklabel)
6713 for m in marks:
6714 for m in marks:
6714 ui.write(' ' + m, label='log.bookmark')
6715 ui.write(' ' + m, label='log.bookmark')
6715 ui.write('\n', label='log.bookmark')
6716 ui.write('\n', label='log.bookmark')
6716
6717
6717 status = repo.status(unknown=True)
6718 status = repo.status(unknown=True)
6718
6719
6719 c = repo.dirstate.copies()
6720 c = repo.dirstate.copies()
6720 copied, renamed = [], []
6721 copied, renamed = [], []
6721 for d, s in c.iteritems():
6722 for d, s in c.iteritems():
6722 if s in status.removed:
6723 if s in status.removed:
6723 status.removed.remove(s)
6724 status.removed.remove(s)
6724 renamed.append(d)
6725 renamed.append(d)
6725 else:
6726 else:
6726 copied.append(d)
6727 copied.append(d)
6727 if d in status.added:
6728 if d in status.added:
6728 status.added.remove(d)
6729 status.added.remove(d)
6729
6730
6730 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6731 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6731
6732
6732 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6733 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6733 (ui.label(_('%d added'), 'status.added'), status.added),
6734 (ui.label(_('%d added'), 'status.added'), status.added),
6734 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6735 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6735 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6736 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6736 (ui.label(_('%d copied'), 'status.copied'), copied),
6737 (ui.label(_('%d copied'), 'status.copied'), copied),
6737 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6738 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6738 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6739 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6739 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6740 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6740 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6741 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6741 t = []
6742 t = []
6742 for l, s in labels:
6743 for l, s in labels:
6743 if s:
6744 if s:
6744 t.append(l % len(s))
6745 t.append(l % len(s))
6745
6746
6746 t = ', '.join(t)
6747 t = ', '.join(t)
6747 cleanworkdir = False
6748 cleanworkdir = False
6748
6749
6749 if repo.vfs.exists('graftstate'):
6750 if repo.vfs.exists('graftstate'):
6750 t += _(' (graft in progress)')
6751 t += _(' (graft in progress)')
6751 if repo.vfs.exists('updatestate'):
6752 if repo.vfs.exists('updatestate'):
6752 t += _(' (interrupted update)')
6753 t += _(' (interrupted update)')
6753 elif len(parents) > 1:
6754 elif len(parents) > 1:
6754 t += _(' (merge)')
6755 t += _(' (merge)')
6755 elif branch != parents[0].branch():
6756 elif branch != parents[0].branch():
6756 t += _(' (new branch)')
6757 t += _(' (new branch)')
6757 elif (parents[0].closesbranch() and
6758 elif (parents[0].closesbranch() and
6758 pnode in repo.branchheads(branch, closed=True)):
6759 pnode in repo.branchheads(branch, closed=True)):
6759 t += _(' (head closed)')
6760 t += _(' (head closed)')
6760 elif not (status.modified or status.added or status.removed or renamed or
6761 elif not (status.modified or status.added or status.removed or renamed or
6761 copied or subs):
6762 copied or subs):
6762 t += _(' (clean)')
6763 t += _(' (clean)')
6763 cleanworkdir = True
6764 cleanworkdir = True
6764 elif pnode not in bheads:
6765 elif pnode not in bheads:
6765 t += _(' (new branch head)')
6766 t += _(' (new branch head)')
6766
6767
6767 if parents:
6768 if parents:
6768 pendingphase = max(p.phase() for p in parents)
6769 pendingphase = max(p.phase() for p in parents)
6769 else:
6770 else:
6770 pendingphase = phases.public
6771 pendingphase = phases.public
6771
6772
6772 if pendingphase > phases.newcommitphase(ui):
6773 if pendingphase > phases.newcommitphase(ui):
6773 t += ' (%s)' % phases.phasenames[pendingphase]
6774 t += ' (%s)' % phases.phasenames[pendingphase]
6774
6775
6775 if cleanworkdir:
6776 if cleanworkdir:
6776 # i18n: column positioning for "hg summary"
6777 # i18n: column positioning for "hg summary"
6777 ui.status(_('commit: %s\n') % t.strip())
6778 ui.status(_('commit: %s\n') % t.strip())
6778 else:
6779 else:
6779 # i18n: column positioning for "hg summary"
6780 # i18n: column positioning for "hg summary"
6780 ui.write(_('commit: %s\n') % t.strip())
6781 ui.write(_('commit: %s\n') % t.strip())
6781
6782
6782 # all ancestors of branch heads - all ancestors of parent = new csets
6783 # all ancestors of branch heads - all ancestors of parent = new csets
6783 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6784 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6784 bheads))
6785 bheads))
6785
6786
6786 if new == 0:
6787 if new == 0:
6787 # i18n: column positioning for "hg summary"
6788 # i18n: column positioning for "hg summary"
6788 ui.status(_('update: (current)\n'))
6789 ui.status(_('update: (current)\n'))
6789 elif pnode not in bheads:
6790 elif pnode not in bheads:
6790 # i18n: column positioning for "hg summary"
6791 # i18n: column positioning for "hg summary"
6791 ui.write(_('update: %d new changesets (update)\n') % new)
6792 ui.write(_('update: %d new changesets (update)\n') % new)
6792 else:
6793 else:
6793 # i18n: column positioning for "hg summary"
6794 # i18n: column positioning for "hg summary"
6794 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6795 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6795 (new, len(bheads)))
6796 (new, len(bheads)))
6796
6797
6797 t = []
6798 t = []
6798 draft = len(repo.revs('draft()'))
6799 draft = len(repo.revs('draft()'))
6799 if draft:
6800 if draft:
6800 t.append(_('%d draft') % draft)
6801 t.append(_('%d draft') % draft)
6801 secret = len(repo.revs('secret()'))
6802 secret = len(repo.revs('secret()'))
6802 if secret:
6803 if secret:
6803 t.append(_('%d secret') % secret)
6804 t.append(_('%d secret') % secret)
6804
6805
6805 if draft or secret:
6806 if draft or secret:
6806 ui.status(_('phases: %s\n') % ', '.join(t))
6807 ui.status(_('phases: %s\n') % ', '.join(t))
6807
6808
6808 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6809 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6809 for trouble in ("unstable", "divergent", "bumped"):
6810 for trouble in ("unstable", "divergent", "bumped"):
6810 numtrouble = len(repo.revs(trouble + "()"))
6811 numtrouble = len(repo.revs(trouble + "()"))
6811 # We write all the possibilities to ease translation
6812 # We write all the possibilities to ease translation
6812 troublemsg = {
6813 troublemsg = {
6813 "unstable": _("unstable: %d changesets"),
6814 "unstable": _("unstable: %d changesets"),
6814 "divergent": _("divergent: %d changesets"),
6815 "divergent": _("divergent: %d changesets"),
6815 "bumped": _("bumped: %d changesets"),
6816 "bumped": _("bumped: %d changesets"),
6816 }
6817 }
6817 if numtrouble > 0:
6818 if numtrouble > 0:
6818 ui.status(troublemsg[trouble] % numtrouble + "\n")
6819 ui.status(troublemsg[trouble] % numtrouble + "\n")
6819
6820
6820 cmdutil.summaryhooks(ui, repo)
6821 cmdutil.summaryhooks(ui, repo)
6821
6822
6822 if opts.get('remote'):
6823 if opts.get('remote'):
6823 needsincoming, needsoutgoing = True, True
6824 needsincoming, needsoutgoing = True, True
6824 else:
6825 else:
6825 needsincoming, needsoutgoing = False, False
6826 needsincoming, needsoutgoing = False, False
6826 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6827 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6827 if i:
6828 if i:
6828 needsincoming = True
6829 needsincoming = True
6829 if o:
6830 if o:
6830 needsoutgoing = True
6831 needsoutgoing = True
6831 if not needsincoming and not needsoutgoing:
6832 if not needsincoming and not needsoutgoing:
6832 return
6833 return
6833
6834
6834 def getincoming():
6835 def getincoming():
6835 source, branches = hg.parseurl(ui.expandpath('default'))
6836 source, branches = hg.parseurl(ui.expandpath('default'))
6836 sbranch = branches[0]
6837 sbranch = branches[0]
6837 try:
6838 try:
6838 other = hg.peer(repo, {}, source)
6839 other = hg.peer(repo, {}, source)
6839 except error.RepoError:
6840 except error.RepoError:
6840 if opts.get('remote'):
6841 if opts.get('remote'):
6841 raise
6842 raise
6842 return source, sbranch, None, None, None
6843 return source, sbranch, None, None, None
6843 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6844 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6844 if revs:
6845 if revs:
6845 revs = [other.lookup(rev) for rev in revs]
6846 revs = [other.lookup(rev) for rev in revs]
6846 ui.debug('comparing with %s\n' % util.hidepassword(source))
6847 ui.debug('comparing with %s\n' % util.hidepassword(source))
6847 repo.ui.pushbuffer()
6848 repo.ui.pushbuffer()
6848 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6849 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6849 repo.ui.popbuffer()
6850 repo.ui.popbuffer()
6850 return source, sbranch, other, commoninc, commoninc[1]
6851 return source, sbranch, other, commoninc, commoninc[1]
6851
6852
6852 if needsincoming:
6853 if needsincoming:
6853 source, sbranch, sother, commoninc, incoming = getincoming()
6854 source, sbranch, sother, commoninc, incoming = getincoming()
6854 else:
6855 else:
6855 source = sbranch = sother = commoninc = incoming = None
6856 source = sbranch = sother = commoninc = incoming = None
6856
6857
6857 def getoutgoing():
6858 def getoutgoing():
6858 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6859 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6859 dbranch = branches[0]
6860 dbranch = branches[0]
6860 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6861 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6861 if source != dest:
6862 if source != dest:
6862 try:
6863 try:
6863 dother = hg.peer(repo, {}, dest)
6864 dother = hg.peer(repo, {}, dest)
6864 except error.RepoError:
6865 except error.RepoError:
6865 if opts.get('remote'):
6866 if opts.get('remote'):
6866 raise
6867 raise
6867 return dest, dbranch, None, None
6868 return dest, dbranch, None, None
6868 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6869 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6869 elif sother is None:
6870 elif sother is None:
6870 # there is no explicit destination peer, but source one is invalid
6871 # there is no explicit destination peer, but source one is invalid
6871 return dest, dbranch, None, None
6872 return dest, dbranch, None, None
6872 else:
6873 else:
6873 dother = sother
6874 dother = sother
6874 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6875 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6875 common = None
6876 common = None
6876 else:
6877 else:
6877 common = commoninc
6878 common = commoninc
6878 if revs:
6879 if revs:
6879 revs = [repo.lookup(rev) for rev in revs]
6880 revs = [repo.lookup(rev) for rev in revs]
6880 repo.ui.pushbuffer()
6881 repo.ui.pushbuffer()
6881 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6882 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6882 commoninc=common)
6883 commoninc=common)
6883 repo.ui.popbuffer()
6884 repo.ui.popbuffer()
6884 return dest, dbranch, dother, outgoing
6885 return dest, dbranch, dother, outgoing
6885
6886
6886 if needsoutgoing:
6887 if needsoutgoing:
6887 dest, dbranch, dother, outgoing = getoutgoing()
6888 dest, dbranch, dother, outgoing = getoutgoing()
6888 else:
6889 else:
6889 dest = dbranch = dother = outgoing = None
6890 dest = dbranch = dother = outgoing = None
6890
6891
6891 if opts.get('remote'):
6892 if opts.get('remote'):
6892 t = []
6893 t = []
6893 if incoming:
6894 if incoming:
6894 t.append(_('1 or more incoming'))
6895 t.append(_('1 or more incoming'))
6895 o = outgoing.missing
6896 o = outgoing.missing
6896 if o:
6897 if o:
6897 t.append(_('%d outgoing') % len(o))
6898 t.append(_('%d outgoing') % len(o))
6898 other = dother or sother
6899 other = dother or sother
6899 if 'bookmarks' in other.listkeys('namespaces'):
6900 if 'bookmarks' in other.listkeys('namespaces'):
6900 counts = bookmarks.summary(repo, other)
6901 counts = bookmarks.summary(repo, other)
6901 if counts[0] > 0:
6902 if counts[0] > 0:
6902 t.append(_('%d incoming bookmarks') % counts[0])
6903 t.append(_('%d incoming bookmarks') % counts[0])
6903 if counts[1] > 0:
6904 if counts[1] > 0:
6904 t.append(_('%d outgoing bookmarks') % counts[1])
6905 t.append(_('%d outgoing bookmarks') % counts[1])
6905
6906
6906 if t:
6907 if t:
6907 # i18n: column positioning for "hg summary"
6908 # i18n: column positioning for "hg summary"
6908 ui.write(_('remote: %s\n') % (', '.join(t)))
6909 ui.write(_('remote: %s\n') % (', '.join(t)))
6909 else:
6910 else:
6910 # i18n: column positioning for "hg summary"
6911 # i18n: column positioning for "hg summary"
6911 ui.status(_('remote: (synced)\n'))
6912 ui.status(_('remote: (synced)\n'))
6912
6913
6913 cmdutil.summaryremotehooks(ui, repo, opts,
6914 cmdutil.summaryremotehooks(ui, repo, opts,
6914 ((source, sbranch, sother, commoninc),
6915 ((source, sbranch, sother, commoninc),
6915 (dest, dbranch, dother, outgoing)))
6916 (dest, dbranch, dother, outgoing)))
6916
6917
6917 @command('tag',
6918 @command('tag',
6918 [('f', 'force', None, _('force tag')),
6919 [('f', 'force', None, _('force tag')),
6919 ('l', 'local', None, _('make the tag local')),
6920 ('l', 'local', None, _('make the tag local')),
6920 ('r', 'rev', '', _('revision to tag'), _('REV')),
6921 ('r', 'rev', '', _('revision to tag'), _('REV')),
6921 ('', 'remove', None, _('remove a tag')),
6922 ('', 'remove', None, _('remove a tag')),
6922 # -l/--local is already there, commitopts cannot be used
6923 # -l/--local is already there, commitopts cannot be used
6923 ('e', 'edit', None, _('invoke editor on commit messages')),
6924 ('e', 'edit', None, _('invoke editor on commit messages')),
6924 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6925 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6925 ] + commitopts2,
6926 ] + commitopts2,
6926 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6927 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6927 def tag(ui, repo, name1, *names, **opts):
6928 def tag(ui, repo, name1, *names, **opts):
6928 """add one or more tags for the current or given revision
6929 """add one or more tags for the current or given revision
6929
6930
6930 Name a particular revision using <name>.
6931 Name a particular revision using <name>.
6931
6932
6932 Tags are used to name particular revisions of the repository and are
6933 Tags are used to name particular revisions of the repository and are
6933 very useful to compare different revisions, to go back to significant
6934 very useful to compare different revisions, to go back to significant
6934 earlier versions or to mark branch points as releases, etc. Changing
6935 earlier versions or to mark branch points as releases, etc. Changing
6935 an existing tag is normally disallowed; use -f/--force to override.
6936 an existing tag is normally disallowed; use -f/--force to override.
6936
6937
6937 If no revision is given, the parent of the working directory is
6938 If no revision is given, the parent of the working directory is
6938 used.
6939 used.
6939
6940
6940 To facilitate version control, distribution, and merging of tags,
6941 To facilitate version control, distribution, and merging of tags,
6941 they are stored as a file named ".hgtags" which is managed similarly
6942 they are stored as a file named ".hgtags" which is managed similarly
6942 to other project files and can be hand-edited if necessary. This
6943 to other project files and can be hand-edited if necessary. This
6943 also means that tagging creates a new commit. The file
6944 also means that tagging creates a new commit. The file
6944 ".hg/localtags" is used for local tags (not shared among
6945 ".hg/localtags" is used for local tags (not shared among
6945 repositories).
6946 repositories).
6946
6947
6947 Tag commits are usually made at the head of a branch. If the parent
6948 Tag commits are usually made at the head of a branch. If the parent
6948 of the working directory is not a branch head, :hg:`tag` aborts; use
6949 of the working directory is not a branch head, :hg:`tag` aborts; use
6949 -f/--force to force the tag commit to be based on a non-head
6950 -f/--force to force the tag commit to be based on a non-head
6950 changeset.
6951 changeset.
6951
6952
6952 See :hg:`help dates` for a list of formats valid for -d/--date.
6953 See :hg:`help dates` for a list of formats valid for -d/--date.
6953
6954
6954 Since tag names have priority over branch names during revision
6955 Since tag names have priority over branch names during revision
6955 lookup, using an existing branch name as a tag name is discouraged.
6956 lookup, using an existing branch name as a tag name is discouraged.
6956
6957
6957 Returns 0 on success.
6958 Returns 0 on success.
6958 """
6959 """
6959 wlock = lock = None
6960 wlock = lock = None
6960 try:
6961 try:
6961 wlock = repo.wlock()
6962 wlock = repo.wlock()
6962 lock = repo.lock()
6963 lock = repo.lock()
6963 rev_ = "."
6964 rev_ = "."
6964 names = [t.strip() for t in (name1,) + names]
6965 names = [t.strip() for t in (name1,) + names]
6965 if len(names) != len(set(names)):
6966 if len(names) != len(set(names)):
6966 raise error.Abort(_('tag names must be unique'))
6967 raise error.Abort(_('tag names must be unique'))
6967 for n in names:
6968 for n in names:
6968 scmutil.checknewlabel(repo, n, 'tag')
6969 scmutil.checknewlabel(repo, n, 'tag')
6969 if not n:
6970 if not n:
6970 raise error.Abort(_('tag names cannot consist entirely of '
6971 raise error.Abort(_('tag names cannot consist entirely of '
6971 'whitespace'))
6972 'whitespace'))
6972 if opts.get('rev') and opts.get('remove'):
6973 if opts.get('rev') and opts.get('remove'):
6973 raise error.Abort(_("--rev and --remove are incompatible"))
6974 raise error.Abort(_("--rev and --remove are incompatible"))
6974 if opts.get('rev'):
6975 if opts.get('rev'):
6975 rev_ = opts['rev']
6976 rev_ = opts['rev']
6976 message = opts.get('message')
6977 message = opts.get('message')
6977 if opts.get('remove'):
6978 if opts.get('remove'):
6978 if opts.get('local'):
6979 if opts.get('local'):
6979 expectedtype = 'local'
6980 expectedtype = 'local'
6980 else:
6981 else:
6981 expectedtype = 'global'
6982 expectedtype = 'global'
6982
6983
6983 for n in names:
6984 for n in names:
6984 if not repo.tagtype(n):
6985 if not repo.tagtype(n):
6985 raise error.Abort(_("tag '%s' does not exist") % n)
6986 raise error.Abort(_("tag '%s' does not exist") % n)
6986 if repo.tagtype(n) != expectedtype:
6987 if repo.tagtype(n) != expectedtype:
6987 if expectedtype == 'global':
6988 if expectedtype == 'global':
6988 raise error.Abort(_("tag '%s' is not a global tag") % n)
6989 raise error.Abort(_("tag '%s' is not a global tag") % n)
6989 else:
6990 else:
6990 raise error.Abort(_("tag '%s' is not a local tag") % n)
6991 raise error.Abort(_("tag '%s' is not a local tag") % n)
6991 rev_ = 'null'
6992 rev_ = 'null'
6992 if not message:
6993 if not message:
6993 # we don't translate commit messages
6994 # we don't translate commit messages
6994 message = 'Removed tag %s' % ', '.join(names)
6995 message = 'Removed tag %s' % ', '.join(names)
6995 elif not opts.get('force'):
6996 elif not opts.get('force'):
6996 for n in names:
6997 for n in names:
6997 if n in repo.tags():
6998 if n in repo.tags():
6998 raise error.Abort(_("tag '%s' already exists "
6999 raise error.Abort(_("tag '%s' already exists "
6999 "(use -f to force)") % n)
7000 "(use -f to force)") % n)
7000 if not opts.get('local'):
7001 if not opts.get('local'):
7001 p1, p2 = repo.dirstate.parents()
7002 p1, p2 = repo.dirstate.parents()
7002 if p2 != nullid:
7003 if p2 != nullid:
7003 raise error.Abort(_('uncommitted merge'))
7004 raise error.Abort(_('uncommitted merge'))
7004 bheads = repo.branchheads()
7005 bheads = repo.branchheads()
7005 if not opts.get('force') and bheads and p1 not in bheads:
7006 if not opts.get('force') and bheads and p1 not in bheads:
7006 raise error.Abort(_('not at a branch head (use -f to force)'))
7007 raise error.Abort(_('not at a branch head (use -f to force)'))
7007 r = scmutil.revsingle(repo, rev_).node()
7008 r = scmutil.revsingle(repo, rev_).node()
7008
7009
7009 if not message:
7010 if not message:
7010 # we don't translate commit messages
7011 # we don't translate commit messages
7011 message = ('Added tag %s for changeset %s' %
7012 message = ('Added tag %s for changeset %s' %
7012 (', '.join(names), short(r)))
7013 (', '.join(names), short(r)))
7013
7014
7014 date = opts.get('date')
7015 date = opts.get('date')
7015 if date:
7016 if date:
7016 date = util.parsedate(date)
7017 date = util.parsedate(date)
7017
7018
7018 if opts.get('remove'):
7019 if opts.get('remove'):
7019 editform = 'tag.remove'
7020 editform = 'tag.remove'
7020 else:
7021 else:
7021 editform = 'tag.add'
7022 editform = 'tag.add'
7022 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7023 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7023
7024
7024 # don't allow tagging the null rev
7025 # don't allow tagging the null rev
7025 if (not opts.get('remove') and
7026 if (not opts.get('remove') and
7026 scmutil.revsingle(repo, rev_).rev() == nullrev):
7027 scmutil.revsingle(repo, rev_).rev() == nullrev):
7027 raise error.Abort(_("cannot tag null revision"))
7028 raise error.Abort(_("cannot tag null revision"))
7028
7029
7029 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7030 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7030 editor=editor)
7031 editor=editor)
7031 finally:
7032 finally:
7032 release(lock, wlock)
7033 release(lock, wlock)
7033
7034
7034 @command('tags', formatteropts, '')
7035 @command('tags', formatteropts, '')
7035 def tags(ui, repo, **opts):
7036 def tags(ui, repo, **opts):
7036 """list repository tags
7037 """list repository tags
7037
7038
7038 This lists both regular and local tags. When the -v/--verbose
7039 This lists both regular and local tags. When the -v/--verbose
7039 switch is used, a third column "local" is printed for local tags.
7040 switch is used, a third column "local" is printed for local tags.
7040 When the -q/--quiet switch is used, only the tag name is printed.
7041 When the -q/--quiet switch is used, only the tag name is printed.
7041
7042
7042 Returns 0 on success.
7043 Returns 0 on success.
7043 """
7044 """
7044
7045
7045 fm = ui.formatter('tags', opts)
7046 fm = ui.formatter('tags', opts)
7046 hexfunc = fm.hexfunc
7047 hexfunc = fm.hexfunc
7047 tagtype = ""
7048 tagtype = ""
7048
7049
7049 for t, n in reversed(repo.tagslist()):
7050 for t, n in reversed(repo.tagslist()):
7050 hn = hexfunc(n)
7051 hn = hexfunc(n)
7051 label = 'tags.normal'
7052 label = 'tags.normal'
7052 tagtype = ''
7053 tagtype = ''
7053 if repo.tagtype(t) == 'local':
7054 if repo.tagtype(t) == 'local':
7054 label = 'tags.local'
7055 label = 'tags.local'
7055 tagtype = 'local'
7056 tagtype = 'local'
7056
7057
7057 fm.startitem()
7058 fm.startitem()
7058 fm.write('tag', '%s', t, label=label)
7059 fm.write('tag', '%s', t, label=label)
7059 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7060 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7060 fm.condwrite(not ui.quiet, 'rev node', fmt,
7061 fm.condwrite(not ui.quiet, 'rev node', fmt,
7061 repo.changelog.rev(n), hn, label=label)
7062 repo.changelog.rev(n), hn, label=label)
7062 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7063 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7063 tagtype, label=label)
7064 tagtype, label=label)
7064 fm.plain('\n')
7065 fm.plain('\n')
7065 fm.end()
7066 fm.end()
7066
7067
7067 @command('tip',
7068 @command('tip',
7068 [('p', 'patch', None, _('show patch')),
7069 [('p', 'patch', None, _('show patch')),
7069 ('g', 'git', None, _('use git extended diff format')),
7070 ('g', 'git', None, _('use git extended diff format')),
7070 ] + templateopts,
7071 ] + templateopts,
7071 _('[-p] [-g]'))
7072 _('[-p] [-g]'))
7072 def tip(ui, repo, **opts):
7073 def tip(ui, repo, **opts):
7073 """show the tip revision (DEPRECATED)
7074 """show the tip revision (DEPRECATED)
7074
7075
7075 The tip revision (usually just called the tip) is the changeset
7076 The tip revision (usually just called the tip) is the changeset
7076 most recently added to the repository (and therefore the most
7077 most recently added to the repository (and therefore the most
7077 recently changed head).
7078 recently changed head).
7078
7079
7079 If you have just made a commit, that commit will be the tip. If
7080 If you have just made a commit, that commit will be the tip. If
7080 you have just pulled changes from another repository, the tip of
7081 you have just pulled changes from another repository, the tip of
7081 that repository becomes the current tip. The "tip" tag is special
7082 that repository becomes the current tip. The "tip" tag is special
7082 and cannot be renamed or assigned to a different changeset.
7083 and cannot be renamed or assigned to a different changeset.
7083
7084
7084 This command is deprecated, please use :hg:`heads` instead.
7085 This command is deprecated, please use :hg:`heads` instead.
7085
7086
7086 Returns 0 on success.
7087 Returns 0 on success.
7087 """
7088 """
7088 displayer = cmdutil.show_changeset(ui, repo, opts)
7089 displayer = cmdutil.show_changeset(ui, repo, opts)
7089 displayer.show(repo['tip'])
7090 displayer.show(repo['tip'])
7090 displayer.close()
7091 displayer.close()
7091
7092
7092 @command('unbundle',
7093 @command('unbundle',
7093 [('u', 'update', None,
7094 [('u', 'update', None,
7094 _('update to new branch head if changesets were unbundled'))],
7095 _('update to new branch head if changesets were unbundled'))],
7095 _('[-u] FILE...'))
7096 _('[-u] FILE...'))
7096 def unbundle(ui, repo, fname1, *fnames, **opts):
7097 def unbundle(ui, repo, fname1, *fnames, **opts):
7097 """apply one or more changegroup files
7098 """apply one or more changegroup files
7098
7099
7099 Apply one or more compressed changegroup files generated by the
7100 Apply one or more compressed changegroup files generated by the
7100 bundle command.
7101 bundle command.
7101
7102
7102 Returns 0 on success, 1 if an update has unresolved files.
7103 Returns 0 on success, 1 if an update has unresolved files.
7103 """
7104 """
7104 fnames = (fname1,) + fnames
7105 fnames = (fname1,) + fnames
7105
7106
7106 with repo.lock():
7107 with repo.lock():
7107 for fname in fnames:
7108 for fname in fnames:
7108 f = hg.openpath(ui, fname)
7109 f = hg.openpath(ui, fname)
7109 gen = exchange.readbundle(ui, f, fname)
7110 gen = exchange.readbundle(ui, f, fname)
7110 if isinstance(gen, bundle2.unbundle20):
7111 if isinstance(gen, bundle2.unbundle20):
7111 tr = repo.transaction('unbundle')
7112 tr = repo.transaction('unbundle')
7112 try:
7113 try:
7113 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7114 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7114 url='bundle:' + fname)
7115 url='bundle:' + fname)
7115 tr.close()
7116 tr.close()
7116 except error.BundleUnknownFeatureError as exc:
7117 except error.BundleUnknownFeatureError as exc:
7117 raise error.Abort(_('%s: unknown bundle feature, %s')
7118 raise error.Abort(_('%s: unknown bundle feature, %s')
7118 % (fname, exc),
7119 % (fname, exc),
7119 hint=_("see https://mercurial-scm.org/"
7120 hint=_("see https://mercurial-scm.org/"
7120 "wiki/BundleFeature for more "
7121 "wiki/BundleFeature for more "
7121 "information"))
7122 "information"))
7122 finally:
7123 finally:
7123 if tr:
7124 if tr:
7124 tr.release()
7125 tr.release()
7125 changes = [r.get('return', 0)
7126 changes = [r.get('return', 0)
7126 for r in op.records['changegroup']]
7127 for r in op.records['changegroup']]
7127 modheads = changegroup.combineresults(changes)
7128 modheads = changegroup.combineresults(changes)
7128 elif isinstance(gen, streamclone.streamcloneapplier):
7129 elif isinstance(gen, streamclone.streamcloneapplier):
7129 raise error.Abort(
7130 raise error.Abort(
7130 _('packed bundles cannot be applied with '
7131 _('packed bundles cannot be applied with '
7131 '"hg unbundle"'),
7132 '"hg unbundle"'),
7132 hint=_('use "hg debugapplystreamclonebundle"'))
7133 hint=_('use "hg debugapplystreamclonebundle"'))
7133 else:
7134 else:
7134 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7135 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7135
7136
7136 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7137 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7137
7138
7138 @command('^update|up|checkout|co',
7139 @command('^update|up|checkout|co',
7139 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7140 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7140 ('c', 'check', None, _('require clean working directory')),
7141 ('c', 'check', None, _('require clean working directory')),
7141 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7142 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7142 ('r', 'rev', '', _('revision'), _('REV'))
7143 ('r', 'rev', '', _('revision'), _('REV'))
7143 ] + mergetoolopts,
7144 ] + mergetoolopts,
7144 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7145 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7145 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7146 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7146 tool=None):
7147 tool=None):
7147 """update working directory (or switch revisions)
7148 """update working directory (or switch revisions)
7148
7149
7149 Update the repository's working directory to the specified
7150 Update the repository's working directory to the specified
7150 changeset. If no changeset is specified, update to the tip of the
7151 changeset. If no changeset is specified, update to the tip of the
7151 current named branch and move the active bookmark (see :hg:`help
7152 current named branch and move the active bookmark (see :hg:`help
7152 bookmarks`).
7153 bookmarks`).
7153
7154
7154 Update sets the working directory's parent revision to the specified
7155 Update sets the working directory's parent revision to the specified
7155 changeset (see :hg:`help parents`).
7156 changeset (see :hg:`help parents`).
7156
7157
7157 If the changeset is not a descendant or ancestor of the working
7158 If the changeset is not a descendant or ancestor of the working
7158 directory's parent, the update is aborted. With the -c/--check
7159 directory's parent, the update is aborted. With the -c/--check
7159 option, the working directory is checked for uncommitted changes; if
7160 option, the working directory is checked for uncommitted changes; if
7160 none are found, the working directory is updated to the specified
7161 none are found, the working directory is updated to the specified
7161 changeset.
7162 changeset.
7162
7163
7163 .. container:: verbose
7164 .. container:: verbose
7164
7165
7165 The following rules apply when the working directory contains
7166 The following rules apply when the working directory contains
7166 uncommitted changes:
7167 uncommitted changes:
7167
7168
7168 1. If neither -c/--check nor -C/--clean is specified, and if
7169 1. If neither -c/--check nor -C/--clean is specified, and if
7169 the requested changeset is an ancestor or descendant of
7170 the requested changeset is an ancestor or descendant of
7170 the working directory's parent, the uncommitted changes
7171 the working directory's parent, the uncommitted changes
7171 are merged into the requested changeset and the merged
7172 are merged into the requested changeset and the merged
7172 result is left uncommitted. If the requested changeset is
7173 result is left uncommitted. If the requested changeset is
7173 not an ancestor or descendant (that is, it is on another
7174 not an ancestor or descendant (that is, it is on another
7174 branch), the update is aborted and the uncommitted changes
7175 branch), the update is aborted and the uncommitted changes
7175 are preserved.
7176 are preserved.
7176
7177
7177 2. With the -c/--check option, the update is aborted and the
7178 2. With the -c/--check option, the update is aborted and the
7178 uncommitted changes are preserved.
7179 uncommitted changes are preserved.
7179
7180
7180 3. With the -C/--clean option, uncommitted changes are discarded and
7181 3. With the -C/--clean option, uncommitted changes are discarded and
7181 the working directory is updated to the requested changeset.
7182 the working directory is updated to the requested changeset.
7182
7183
7183 To cancel an uncommitted merge (and lose your changes), use
7184 To cancel an uncommitted merge (and lose your changes), use
7184 :hg:`update --clean .`.
7185 :hg:`update --clean .`.
7185
7186
7186 Use null as the changeset to remove the working directory (like
7187 Use null as the changeset to remove the working directory (like
7187 :hg:`clone -U`).
7188 :hg:`clone -U`).
7188
7189
7189 If you want to revert just one file to an older revision, use
7190 If you want to revert just one file to an older revision, use
7190 :hg:`revert [-r REV] NAME`.
7191 :hg:`revert [-r REV] NAME`.
7191
7192
7192 See :hg:`help dates` for a list of formats valid for -d/--date.
7193 See :hg:`help dates` for a list of formats valid for -d/--date.
7193
7194
7194 Returns 0 on success, 1 if there are unresolved files.
7195 Returns 0 on success, 1 if there are unresolved files.
7195 """
7196 """
7196 if rev and node:
7197 if rev and node:
7197 raise error.Abort(_("please specify just one revision"))
7198 raise error.Abort(_("please specify just one revision"))
7198
7199
7199 if rev is None or rev == '':
7200 if rev is None or rev == '':
7200 rev = node
7201 rev = node
7201
7202
7202 if date and rev is not None:
7203 if date and rev is not None:
7203 raise error.Abort(_("you can't specify a revision and a date"))
7204 raise error.Abort(_("you can't specify a revision and a date"))
7204
7205
7205 if check and clean:
7206 if check and clean:
7206 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7207 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7207
7208
7208 with repo.wlock():
7209 with repo.wlock():
7209 cmdutil.clearunfinished(repo)
7210 cmdutil.clearunfinished(repo)
7210
7211
7211 if date:
7212 if date:
7212 rev = cmdutil.finddate(ui, repo, date)
7213 rev = cmdutil.finddate(ui, repo, date)
7213
7214
7214 # if we defined a bookmark, we have to remember the original name
7215 # if we defined a bookmark, we have to remember the original name
7215 brev = rev
7216 brev = rev
7216 rev = scmutil.revsingle(repo, rev, rev).rev()
7217 rev = scmutil.revsingle(repo, rev, rev).rev()
7217
7218
7218 if check:
7219 if check:
7219 cmdutil.bailifchanged(repo, merge=False)
7220 cmdutil.bailifchanged(repo, merge=False)
7220
7221
7221 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7222 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7222
7223
7223 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7224 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7224
7225
7225 @command('verify', [])
7226 @command('verify', [])
7226 def verify(ui, repo):
7227 def verify(ui, repo):
7227 """verify the integrity of the repository
7228 """verify the integrity of the repository
7228
7229
7229 Verify the integrity of the current repository.
7230 Verify the integrity of the current repository.
7230
7231
7231 This will perform an extensive check of the repository's
7232 This will perform an extensive check of the repository's
7232 integrity, validating the hashes and checksums of each entry in
7233 integrity, validating the hashes and checksums of each entry in
7233 the changelog, manifest, and tracked files, as well as the
7234 the changelog, manifest, and tracked files, as well as the
7234 integrity of their crosslinks and indices.
7235 integrity of their crosslinks and indices.
7235
7236
7236 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7237 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7237 for more information about recovery from corruption of the
7238 for more information about recovery from corruption of the
7238 repository.
7239 repository.
7239
7240
7240 Returns 0 on success, 1 if errors are encountered.
7241 Returns 0 on success, 1 if errors are encountered.
7241 """
7242 """
7242 return hg.verify(repo)
7243 return hg.verify(repo)
7243
7244
7244 @command('version', [], norepo=True)
7245 @command('version', [], norepo=True)
7245 def version_(ui):
7246 def version_(ui):
7246 """output version and copyright information"""
7247 """output version and copyright information"""
7247 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7248 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7248 % util.version())
7249 % util.version())
7249 ui.status(_(
7250 ui.status(_(
7250 "(see https://mercurial-scm.org for more information)\n"
7251 "(see https://mercurial-scm.org for more information)\n"
7251 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7252 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7252 "This is free software; see the source for copying conditions. "
7253 "This is free software; see the source for copying conditions. "
7253 "There is NO\nwarranty; "
7254 "There is NO\nwarranty; "
7254 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7255 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7255 ))
7256 ))
7256
7257
7257 ui.note(_("\nEnabled extensions:\n\n"))
7258 ui.note(_("\nEnabled extensions:\n\n"))
7258 if ui.verbose:
7259 if ui.verbose:
7259 # format names and versions into columns
7260 # format names and versions into columns
7260 names = []
7261 names = []
7261 vers = []
7262 vers = []
7262 place = []
7263 place = []
7263 for name, module in extensions.extensions():
7264 for name, module in extensions.extensions():
7264 names.append(name)
7265 names.append(name)
7265 vers.append(extensions.moduleversion(module))
7266 vers.append(extensions.moduleversion(module))
7266 if extensions.ismoduleinternal(module):
7267 if extensions.ismoduleinternal(module):
7267 place.append(_("internal"))
7268 place.append(_("internal"))
7268 else:
7269 else:
7269 place.append(_("external"))
7270 place.append(_("external"))
7270 if names:
7271 if names:
7271 maxnamelen = max(len(n) for n in names)
7272 maxnamelen = max(len(n) for n in names)
7272 for i, name in enumerate(names):
7273 for i, name in enumerate(names):
7273 ui.write(" %-*s %s %s\n" %
7274 ui.write(" %-*s %s %s\n" %
7274 (maxnamelen, name, place[i], vers[i]))
7275 (maxnamelen, name, place[i], vers[i]))
7275
7276
7276 def loadcmdtable(ui, name, cmdtable):
7277 def loadcmdtable(ui, name, cmdtable):
7277 """Load command functions from specified cmdtable
7278 """Load command functions from specified cmdtable
7278 """
7279 """
7279 overrides = [cmd for cmd in cmdtable if cmd in table]
7280 overrides = [cmd for cmd in cmdtable if cmd in table]
7280 if overrides:
7281 if overrides:
7281 ui.warn(_("extension '%s' overrides commands: %s\n")
7282 ui.warn(_("extension '%s' overrides commands: %s\n")
7282 % (name, " ".join(overrides)))
7283 % (name, " ".join(overrides)))
7283 table.update(cmdtable)
7284 table.update(cmdtable)
@@ -1,83 +1,86 b''
1 $ hg debugextensions
1 $ hg debugextensions
2
2
3 $ debugpath=`pwd`/extwithoutinfos.py
3 $ debugpath=`pwd`/extwithoutinfos.py
4
4
5 $ cat > extwithoutinfos.py <<EOF
5 $ cat > extwithoutinfos.py <<EOF
6 > EOF
6 > EOF
7
7
8 $ cat >> $HGRCPATH <<EOF
8 $ cat >> $HGRCPATH <<EOF
9 > [extensions]
9 > [extensions]
10 > color=
10 > color=
11 > histedit=
11 > histedit=
12 > patchbomb=
12 > patchbomb=
13 > rebase=
13 > rebase=
14 > mq=
14 > mq=
15 > ext1 = $debugpath
15 > ext1 = $debugpath
16 > EOF
16 > EOF
17
17
18 $ hg debugextensions
18 $ hg debugextensions
19 color
19 color
20 ext1 (untested!)
20 ext1 (untested!)
21 histedit
21 histedit
22 mq
22 mq
23 patchbomb
23 patchbomb
24 rebase
24 rebase
25
25
26 $ hg debugextensions -v
26 $ hg debugextensions -v
27 color
27 color
28 location: */hgext/color.py* (glob)
28 location: */hgext/color.py* (glob)
29 tested with: internal
29 tested with: internal
30 ext1
30 ext1
31 location: */extwithoutinfos.py* (glob)
31 location: */extwithoutinfos.py* (glob)
32 histedit
32 histedit
33 location: */hgext/histedit.py* (glob)
33 location: */hgext/histedit.py* (glob)
34 tested with: internal
34 tested with: internal
35 mq
35 mq
36 location: */hgext/mq.py* (glob)
36 location: */hgext/mq.py* (glob)
37 tested with: internal
37 tested with: internal
38 patchbomb
38 patchbomb
39 location: */hgext/patchbomb.py* (glob)
39 location: */hgext/patchbomb.py* (glob)
40 tested with: internal
40 tested with: internal
41 rebase
41 rebase
42 location: */hgext/rebase.py* (glob)
42 location: */hgext/rebase.py* (glob)
43 tested with: internal
43 tested with: internal
44
44
45 $ hg debugextensions -Tjson | sed 's|\\\\|/|g'
45 $ hg debugextensions -Tjson | sed 's|\\\\|/|g'
46 [
46 [
47 {
47 {
48 "buglink": "",
48 "buglink": "",
49 "name": "color",
49 "name": "color",
50 "source": "*/hgext/color.py*", (glob)
50 "source": "*/hgext/color.py*", (glob)
51 "testedwith": "internal"
51 "testedwith": ["internal"]
52 },
52 },
53 {
53 {
54 "buglink": "",
54 "buglink": "",
55 "name": "ext1",
55 "name": "ext1",
56 "source": "*/extwithoutinfos.py*", (glob)
56 "source": "*/extwithoutinfos.py*", (glob)
57 "testedwith": ""
57 "testedwith": []
58 },
58 },
59 {
59 {
60 "buglink": "",
60 "buglink": "",
61 "name": "histedit",
61 "name": "histedit",
62 "source": "*/hgext/histedit.py*", (glob)
62 "source": "*/hgext/histedit.py*", (glob)
63 "testedwith": "internal"
63 "testedwith": ["internal"]
64 },
64 },
65 {
65 {
66 "buglink": "",
66 "buglink": "",
67 "name": "mq",
67 "name": "mq",
68 "source": "*/hgext/mq.py*", (glob)
68 "source": "*/hgext/mq.py*", (glob)
69 "testedwith": "internal"
69 "testedwith": ["internal"]
70 },
70 },
71 {
71 {
72 "buglink": "",
72 "buglink": "",
73 "name": "patchbomb",
73 "name": "patchbomb",
74 "source": "*/hgext/patchbomb.py*", (glob)
74 "source": "*/hgext/patchbomb.py*", (glob)
75 "testedwith": "internal"
75 "testedwith": ["internal"]
76 },
76 },
77 {
77 {
78 "buglink": "",
78 "buglink": "",
79 "name": "rebase",
79 "name": "rebase",
80 "source": "*/hgext/rebase.py*", (glob)
80 "source": "*/hgext/rebase.py*", (glob)
81 "testedwith": "internal"
81 "testedwith": ["internal"]
82 }
82 }
83 ]
83 ]
84
85 $ hg debugextensions -T '{ifcontains("internal", testedwith, "", "{name}\n")}'
86 ext1
General Comments 0
You need to be logged in to leave comments. Login now