##// END OF EJS Templates
debugcommands: move 'debugcommands' in the new module...
Gregory Szorc -
r30504:c3bdc271 default
parent child Browse files
Show More
@@ -1,7128 +1,7120
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 string
18 import string
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 import time
21 import time
22
22
23 from .i18n import _
23 from .i18n import _
24 from .node import (
24 from .node import (
25 bin,
25 bin,
26 hex,
26 hex,
27 nullhex,
27 nullhex,
28 nullid,
28 nullid,
29 nullrev,
29 nullrev,
30 short,
30 short,
31 )
31 )
32 from . import (
32 from . import (
33 archival,
33 archival,
34 bookmarks,
34 bookmarks,
35 bundle2,
35 bundle2,
36 changegroup,
36 changegroup,
37 cmdutil,
37 cmdutil,
38 commandserver,
38 commandserver,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 dirstateguard,
43 dirstateguard,
44 discovery,
44 discovery,
45 encoding,
45 encoding,
46 error,
46 error,
47 exchange,
47 exchange,
48 extensions,
48 extensions,
49 fileset,
49 fileset,
50 formatter,
50 formatter,
51 graphmod,
51 graphmod,
52 hbisect,
52 hbisect,
53 help,
53 help,
54 hg,
54 hg,
55 hgweb,
55 hgweb,
56 localrepo,
56 localrepo,
57 lock as lockmod,
57 lock as lockmod,
58 merge as mergemod,
58 merge as mergemod,
59 minirst,
59 minirst,
60 obsolete,
60 obsolete,
61 patch,
61 patch,
62 phases,
62 phases,
63 policy,
63 policy,
64 pvec,
64 pvec,
65 pycompat,
65 pycompat,
66 repair,
66 repair,
67 revlog,
67 revlog,
68 revset,
68 revset,
69 scmutil,
69 scmutil,
70 setdiscovery,
70 setdiscovery,
71 sshserver,
71 sshserver,
72 sslutil,
72 sslutil,
73 streamclone,
73 streamclone,
74 templatekw,
74 templatekw,
75 templater,
75 templater,
76 treediscovery,
76 treediscovery,
77 ui as uimod,
77 ui as uimod,
78 util,
78 util,
79 )
79 )
80
80
81 release = lockmod.release
81 release = lockmod.release
82
82
83 table = {}
83 table = {}
84
84
85 command = cmdutil.command(table)
85 command = cmdutil.command(table)
86
86
87 # label constants
87 # label constants
88 # until 3.5, bookmarks.current was the advertised name, not
88 # until 3.5, bookmarks.current was the advertised name, not
89 # bookmarks.active, so we must use both to avoid breaking old
89 # bookmarks.active, so we must use both to avoid breaking old
90 # custom styles
90 # custom styles
91 activebookmarklabel = 'bookmarks.active bookmarks.current'
91 activebookmarklabel = 'bookmarks.active bookmarks.current'
92
92
93 # common command options
93 # common command options
94
94
95 globalopts = [
95 globalopts = [
96 ('R', 'repository', '',
96 ('R', 'repository', '',
97 _('repository root directory or name of overlay bundle file'),
97 _('repository root directory or name of overlay bundle file'),
98 _('REPO')),
98 _('REPO')),
99 ('', 'cwd', '',
99 ('', 'cwd', '',
100 _('change working directory'), _('DIR')),
100 _('change working directory'), _('DIR')),
101 ('y', 'noninteractive', None,
101 ('y', 'noninteractive', None,
102 _('do not prompt, automatically pick the first choice for all prompts')),
102 _('do not prompt, automatically pick the first choice for all prompts')),
103 ('q', 'quiet', None, _('suppress output')),
103 ('q', 'quiet', None, _('suppress output')),
104 ('v', 'verbose', None, _('enable additional output')),
104 ('v', 'verbose', None, _('enable additional output')),
105 ('', 'config', [],
105 ('', 'config', [],
106 _('set/override config option (use \'section.name=value\')'),
106 _('set/override config option (use \'section.name=value\')'),
107 _('CONFIG')),
107 _('CONFIG')),
108 ('', 'debug', None, _('enable debugging output')),
108 ('', 'debug', None, _('enable debugging output')),
109 ('', 'debugger', None, _('start debugger')),
109 ('', 'debugger', None, _('start debugger')),
110 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
110 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
111 _('ENCODE')),
111 _('ENCODE')),
112 ('', 'encodingmode', encoding.encodingmode,
112 ('', 'encodingmode', encoding.encodingmode,
113 _('set the charset encoding mode'), _('MODE')),
113 _('set the charset encoding mode'), _('MODE')),
114 ('', 'traceback', None, _('always print a traceback on exception')),
114 ('', 'traceback', None, _('always print a traceback on exception')),
115 ('', 'time', None, _('time how long the command takes')),
115 ('', 'time', None, _('time how long the command takes')),
116 ('', 'profile', None, _('print command execution profile')),
116 ('', 'profile', None, _('print command execution profile')),
117 ('', 'version', None, _('output version information and exit')),
117 ('', 'version', None, _('output version information and exit')),
118 ('h', 'help', None, _('display help and exit')),
118 ('h', 'help', None, _('display help and exit')),
119 ('', 'hidden', False, _('consider hidden changesets')),
119 ('', 'hidden', False, _('consider hidden changesets')),
120 ]
120 ]
121
121
122 dryrunopts = [('n', 'dry-run', None,
122 dryrunopts = [('n', 'dry-run', None,
123 _('do not perform actions, just print output'))]
123 _('do not perform actions, just print output'))]
124
124
125 remoteopts = [
125 remoteopts = [
126 ('e', 'ssh', '',
126 ('e', 'ssh', '',
127 _('specify ssh command to use'), _('CMD')),
127 _('specify ssh command to use'), _('CMD')),
128 ('', 'remotecmd', '',
128 ('', 'remotecmd', '',
129 _('specify hg command to run on the remote side'), _('CMD')),
129 _('specify hg command to run on the remote side'), _('CMD')),
130 ('', 'insecure', None,
130 ('', 'insecure', None,
131 _('do not verify server certificate (ignoring web.cacerts config)')),
131 _('do not verify server certificate (ignoring web.cacerts config)')),
132 ]
132 ]
133
133
134 walkopts = [
134 walkopts = [
135 ('I', 'include', [],
135 ('I', 'include', [],
136 _('include names matching the given patterns'), _('PATTERN')),
136 _('include names matching the given patterns'), _('PATTERN')),
137 ('X', 'exclude', [],
137 ('X', 'exclude', [],
138 _('exclude names matching the given patterns'), _('PATTERN')),
138 _('exclude names matching the given patterns'), _('PATTERN')),
139 ]
139 ]
140
140
141 commitopts = [
141 commitopts = [
142 ('m', 'message', '',
142 ('m', 'message', '',
143 _('use text as commit message'), _('TEXT')),
143 _('use text as commit message'), _('TEXT')),
144 ('l', 'logfile', '',
144 ('l', 'logfile', '',
145 _('read commit message from file'), _('FILE')),
145 _('read commit message from file'), _('FILE')),
146 ]
146 ]
147
147
148 commitopts2 = [
148 commitopts2 = [
149 ('d', 'date', '',
149 ('d', 'date', '',
150 _('record the specified date as commit date'), _('DATE')),
150 _('record the specified date as commit date'), _('DATE')),
151 ('u', 'user', '',
151 ('u', 'user', '',
152 _('record the specified user as committer'), _('USER')),
152 _('record the specified user as committer'), _('USER')),
153 ]
153 ]
154
154
155 # hidden for now
155 # hidden for now
156 formatteropts = [
156 formatteropts = [
157 ('T', 'template', '',
157 ('T', 'template', '',
158 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
158 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
159 ]
159 ]
160
160
161 templateopts = [
161 templateopts = [
162 ('', 'style', '',
162 ('', 'style', '',
163 _('display using template map file (DEPRECATED)'), _('STYLE')),
163 _('display using template map file (DEPRECATED)'), _('STYLE')),
164 ('T', 'template', '',
164 ('T', 'template', '',
165 _('display with template'), _('TEMPLATE')),
165 _('display with template'), _('TEMPLATE')),
166 ]
166 ]
167
167
168 logopts = [
168 logopts = [
169 ('p', 'patch', None, _('show patch')),
169 ('p', 'patch', None, _('show patch')),
170 ('g', 'git', None, _('use git extended diff format')),
170 ('g', 'git', None, _('use git extended diff format')),
171 ('l', 'limit', '',
171 ('l', 'limit', '',
172 _('limit number of changes displayed'), _('NUM')),
172 _('limit number of changes displayed'), _('NUM')),
173 ('M', 'no-merges', None, _('do not show merges')),
173 ('M', 'no-merges', None, _('do not show merges')),
174 ('', 'stat', None, _('output diffstat-style summary of changes')),
174 ('', 'stat', None, _('output diffstat-style summary of changes')),
175 ('G', 'graph', None, _("show the revision DAG")),
175 ('G', 'graph', None, _("show the revision DAG")),
176 ] + templateopts
176 ] + templateopts
177
177
178 diffopts = [
178 diffopts = [
179 ('a', 'text', None, _('treat all files as text')),
179 ('a', 'text', None, _('treat all files as text')),
180 ('g', 'git', None, _('use git extended diff format')),
180 ('g', 'git', None, _('use git extended diff format')),
181 ('', 'nodates', None, _('omit dates from diff headers'))
181 ('', 'nodates', None, _('omit dates from diff headers'))
182 ]
182 ]
183
183
184 diffwsopts = [
184 diffwsopts = [
185 ('w', 'ignore-all-space', None,
185 ('w', 'ignore-all-space', None,
186 _('ignore white space when comparing lines')),
186 _('ignore white space when comparing lines')),
187 ('b', 'ignore-space-change', None,
187 ('b', 'ignore-space-change', None,
188 _('ignore changes in the amount of white space')),
188 _('ignore changes in the amount of white space')),
189 ('B', 'ignore-blank-lines', None,
189 ('B', 'ignore-blank-lines', None,
190 _('ignore changes whose lines are all blank')),
190 _('ignore changes whose lines are all blank')),
191 ]
191 ]
192
192
193 diffopts2 = [
193 diffopts2 = [
194 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
194 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
195 ('p', 'show-function', None, _('show which function each change is in')),
195 ('p', 'show-function', None, _('show which function each change is in')),
196 ('', 'reverse', None, _('produce a diff that undoes the changes')),
196 ('', 'reverse', None, _('produce a diff that undoes the changes')),
197 ] + diffwsopts + [
197 ] + diffwsopts + [
198 ('U', 'unified', '',
198 ('U', 'unified', '',
199 _('number of lines of context to show'), _('NUM')),
199 _('number of lines of context to show'), _('NUM')),
200 ('', 'stat', None, _('output diffstat-style summary of changes')),
200 ('', 'stat', None, _('output diffstat-style summary of changes')),
201 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
201 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
202 ]
202 ]
203
203
204 mergetoolopts = [
204 mergetoolopts = [
205 ('t', 'tool', '', _('specify merge tool')),
205 ('t', 'tool', '', _('specify merge tool')),
206 ]
206 ]
207
207
208 similarityopts = [
208 similarityopts = [
209 ('s', 'similarity', '',
209 ('s', 'similarity', '',
210 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
210 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
211 ]
211 ]
212
212
213 subrepoopts = [
213 subrepoopts = [
214 ('S', 'subrepos', None,
214 ('S', 'subrepos', None,
215 _('recurse into subrepositories'))
215 _('recurse into subrepositories'))
216 ]
216 ]
217
217
218 debugrevlogopts = [
218 debugrevlogopts = [
219 ('c', 'changelog', False, _('open changelog')),
219 ('c', 'changelog', False, _('open changelog')),
220 ('m', 'manifest', False, _('open manifest')),
220 ('m', 'manifest', False, _('open manifest')),
221 ('', 'dir', '', _('open directory manifest')),
221 ('', 'dir', '', _('open directory manifest')),
222 ]
222 ]
223
223
224 # Commands start here, listed alphabetically
224 # Commands start here, listed alphabetically
225
225
226 @command('^add',
226 @command('^add',
227 walkopts + subrepoopts + dryrunopts,
227 walkopts + subrepoopts + dryrunopts,
228 _('[OPTION]... [FILE]...'),
228 _('[OPTION]... [FILE]...'),
229 inferrepo=True)
229 inferrepo=True)
230 def add(ui, repo, *pats, **opts):
230 def add(ui, repo, *pats, **opts):
231 """add the specified files on the next commit
231 """add the specified files on the next commit
232
232
233 Schedule files to be version controlled and added to the
233 Schedule files to be version controlled and added to the
234 repository.
234 repository.
235
235
236 The files will be added to the repository at the next commit. To
236 The files will be added to the repository at the next commit. To
237 undo an add before that, see :hg:`forget`.
237 undo an add before that, see :hg:`forget`.
238
238
239 If no names are given, add all files to the repository (except
239 If no names are given, add all files to the repository (except
240 files matching ``.hgignore``).
240 files matching ``.hgignore``).
241
241
242 .. container:: verbose
242 .. container:: verbose
243
243
244 Examples:
244 Examples:
245
245
246 - New (unknown) files are added
246 - New (unknown) files are added
247 automatically by :hg:`add`::
247 automatically by :hg:`add`::
248
248
249 $ ls
249 $ ls
250 foo.c
250 foo.c
251 $ hg status
251 $ hg status
252 ? foo.c
252 ? foo.c
253 $ hg add
253 $ hg add
254 adding foo.c
254 adding foo.c
255 $ hg status
255 $ hg status
256 A foo.c
256 A foo.c
257
257
258 - Specific files to be added can be specified::
258 - Specific files to be added can be specified::
259
259
260 $ ls
260 $ ls
261 bar.c foo.c
261 bar.c foo.c
262 $ hg status
262 $ hg status
263 ? bar.c
263 ? bar.c
264 ? foo.c
264 ? foo.c
265 $ hg add bar.c
265 $ hg add bar.c
266 $ hg status
266 $ hg status
267 A bar.c
267 A bar.c
268 ? foo.c
268 ? foo.c
269
269
270 Returns 0 if all files are successfully added.
270 Returns 0 if all files are successfully added.
271 """
271 """
272
272
273 m = scmutil.match(repo[None], pats, opts)
273 m = scmutil.match(repo[None], pats, opts)
274 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
274 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
275 return rejected and 1 or 0
275 return rejected and 1 or 0
276
276
277 @command('addremove',
277 @command('addremove',
278 similarityopts + subrepoopts + walkopts + dryrunopts,
278 similarityopts + subrepoopts + walkopts + dryrunopts,
279 _('[OPTION]... [FILE]...'),
279 _('[OPTION]... [FILE]...'),
280 inferrepo=True)
280 inferrepo=True)
281 def addremove(ui, repo, *pats, **opts):
281 def addremove(ui, repo, *pats, **opts):
282 """add all new files, delete all missing files
282 """add all new files, delete all missing files
283
283
284 Add all new files and remove all missing files from the
284 Add all new files and remove all missing files from the
285 repository.
285 repository.
286
286
287 Unless names are given, new files are ignored if they match any of
287 Unless names are given, new files are ignored if they match any of
288 the patterns in ``.hgignore``. As with add, these changes take
288 the patterns in ``.hgignore``. As with add, these changes take
289 effect at the next commit.
289 effect at the next commit.
290
290
291 Use the -s/--similarity option to detect renamed files. This
291 Use the -s/--similarity option to detect renamed files. This
292 option takes a percentage between 0 (disabled) and 100 (files must
292 option takes a percentage between 0 (disabled) and 100 (files must
293 be identical) as its parameter. With a parameter greater than 0,
293 be identical) as its parameter. With a parameter greater than 0,
294 this compares every removed file with every added file and records
294 this compares every removed file with every added file and records
295 those similar enough as renames. Detecting renamed files this way
295 those similar enough as renames. Detecting renamed files this way
296 can be expensive. After using this option, :hg:`status -C` can be
296 can be expensive. After using this option, :hg:`status -C` can be
297 used to check which files were identified as moved or renamed. If
297 used to check which files were identified as moved or renamed. If
298 not specified, -s/--similarity defaults to 100 and only renames of
298 not specified, -s/--similarity defaults to 100 and only renames of
299 identical files are detected.
299 identical files are detected.
300
300
301 .. container:: verbose
301 .. container:: verbose
302
302
303 Examples:
303 Examples:
304
304
305 - A number of files (bar.c and foo.c) are new,
305 - A number of files (bar.c and foo.c) are new,
306 while foobar.c has been removed (without using :hg:`remove`)
306 while foobar.c has been removed (without using :hg:`remove`)
307 from the repository::
307 from the repository::
308
308
309 $ ls
309 $ ls
310 bar.c foo.c
310 bar.c foo.c
311 $ hg status
311 $ hg status
312 ! foobar.c
312 ! foobar.c
313 ? bar.c
313 ? bar.c
314 ? foo.c
314 ? foo.c
315 $ hg addremove
315 $ hg addremove
316 adding bar.c
316 adding bar.c
317 adding foo.c
317 adding foo.c
318 removing foobar.c
318 removing foobar.c
319 $ hg status
319 $ hg status
320 A bar.c
320 A bar.c
321 A foo.c
321 A foo.c
322 R foobar.c
322 R foobar.c
323
323
324 - A file foobar.c was moved to foo.c without using :hg:`rename`.
324 - A file foobar.c was moved to foo.c without using :hg:`rename`.
325 Afterwards, it was edited slightly::
325 Afterwards, it was edited slightly::
326
326
327 $ ls
327 $ ls
328 foo.c
328 foo.c
329 $ hg status
329 $ hg status
330 ! foobar.c
330 ! foobar.c
331 ? foo.c
331 ? foo.c
332 $ hg addremove --similarity 90
332 $ hg addremove --similarity 90
333 removing foobar.c
333 removing foobar.c
334 adding foo.c
334 adding foo.c
335 recording removal of foobar.c as rename to foo.c (94% similar)
335 recording removal of foobar.c as rename to foo.c (94% similar)
336 $ hg status -C
336 $ hg status -C
337 A foo.c
337 A foo.c
338 foobar.c
338 foobar.c
339 R foobar.c
339 R foobar.c
340
340
341 Returns 0 if all files are successfully added.
341 Returns 0 if all files are successfully added.
342 """
342 """
343 try:
343 try:
344 sim = float(opts.get('similarity') or 100)
344 sim = float(opts.get('similarity') or 100)
345 except ValueError:
345 except ValueError:
346 raise error.Abort(_('similarity must be a number'))
346 raise error.Abort(_('similarity must be a number'))
347 if sim < 0 or sim > 100:
347 if sim < 0 or sim > 100:
348 raise error.Abort(_('similarity must be between 0 and 100'))
348 raise error.Abort(_('similarity must be between 0 and 100'))
349 matcher = scmutil.match(repo[None], pats, opts)
349 matcher = scmutil.match(repo[None], pats, opts)
350 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
350 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
351
351
352 @command('^annotate|blame',
352 @command('^annotate|blame',
353 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
353 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
354 ('', 'follow', None,
354 ('', 'follow', None,
355 _('follow copies/renames and list the filename (DEPRECATED)')),
355 _('follow copies/renames and list the filename (DEPRECATED)')),
356 ('', 'no-follow', None, _("don't follow copies and renames")),
356 ('', 'no-follow', None, _("don't follow copies and renames")),
357 ('a', 'text', None, _('treat all files as text')),
357 ('a', 'text', None, _('treat all files as text')),
358 ('u', 'user', None, _('list the author (long with -v)')),
358 ('u', 'user', None, _('list the author (long with -v)')),
359 ('f', 'file', None, _('list the filename')),
359 ('f', 'file', None, _('list the filename')),
360 ('d', 'date', None, _('list the date (short with -q)')),
360 ('d', 'date', None, _('list the date (short with -q)')),
361 ('n', 'number', None, _('list the revision number (default)')),
361 ('n', 'number', None, _('list the revision number (default)')),
362 ('c', 'changeset', None, _('list the changeset')),
362 ('c', 'changeset', None, _('list the changeset')),
363 ('l', 'line-number', None, _('show line number at the first appearance'))
363 ('l', 'line-number', None, _('show line number at the first appearance'))
364 ] + diffwsopts + walkopts + formatteropts,
364 ] + diffwsopts + walkopts + formatteropts,
365 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
365 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
366 inferrepo=True)
366 inferrepo=True)
367 def annotate(ui, repo, *pats, **opts):
367 def annotate(ui, repo, *pats, **opts):
368 """show changeset information by line for each file
368 """show changeset information by line for each file
369
369
370 List changes in files, showing the revision id responsible for
370 List changes in files, showing the revision id responsible for
371 each line.
371 each line.
372
372
373 This command is useful for discovering when a change was made and
373 This command is useful for discovering when a change was made and
374 by whom.
374 by whom.
375
375
376 If you include --file, --user, or --date, the revision number is
376 If you include --file, --user, or --date, the revision number is
377 suppressed unless you also include --number.
377 suppressed unless you also include --number.
378
378
379 Without the -a/--text option, annotate will avoid processing files
379 Without the -a/--text option, annotate will avoid processing files
380 it detects as binary. With -a, annotate will annotate the file
380 it detects as binary. With -a, annotate will annotate the file
381 anyway, although the results will probably be neither useful
381 anyway, although the results will probably be neither useful
382 nor desirable.
382 nor desirable.
383
383
384 Returns 0 on success.
384 Returns 0 on success.
385 """
385 """
386 if not pats:
386 if not pats:
387 raise error.Abort(_('at least one filename or pattern is required'))
387 raise error.Abort(_('at least one filename or pattern is required'))
388
388
389 if opts.get('follow'):
389 if opts.get('follow'):
390 # --follow is deprecated and now just an alias for -f/--file
390 # --follow is deprecated and now just an alias for -f/--file
391 # to mimic the behavior of Mercurial before version 1.5
391 # to mimic the behavior of Mercurial before version 1.5
392 opts['file'] = True
392 opts['file'] = True
393
393
394 ctx = scmutil.revsingle(repo, opts.get('rev'))
394 ctx = scmutil.revsingle(repo, opts.get('rev'))
395
395
396 fm = ui.formatter('annotate', opts)
396 fm = ui.formatter('annotate', opts)
397 if ui.quiet:
397 if ui.quiet:
398 datefunc = util.shortdate
398 datefunc = util.shortdate
399 else:
399 else:
400 datefunc = util.datestr
400 datefunc = util.datestr
401 if ctx.rev() is None:
401 if ctx.rev() is None:
402 def hexfn(node):
402 def hexfn(node):
403 if node is None:
403 if node is None:
404 return None
404 return None
405 else:
405 else:
406 return fm.hexfunc(node)
406 return fm.hexfunc(node)
407 if opts.get('changeset'):
407 if opts.get('changeset'):
408 # omit "+" suffix which is appended to node hex
408 # omit "+" suffix which is appended to node hex
409 def formatrev(rev):
409 def formatrev(rev):
410 if rev is None:
410 if rev is None:
411 return '%d' % ctx.p1().rev()
411 return '%d' % ctx.p1().rev()
412 else:
412 else:
413 return '%d' % rev
413 return '%d' % rev
414 else:
414 else:
415 def formatrev(rev):
415 def formatrev(rev):
416 if rev is None:
416 if rev is None:
417 return '%d+' % ctx.p1().rev()
417 return '%d+' % ctx.p1().rev()
418 else:
418 else:
419 return '%d ' % rev
419 return '%d ' % rev
420 def formathex(hex):
420 def formathex(hex):
421 if hex is None:
421 if hex is None:
422 return '%s+' % fm.hexfunc(ctx.p1().node())
422 return '%s+' % fm.hexfunc(ctx.p1().node())
423 else:
423 else:
424 return '%s ' % hex
424 return '%s ' % hex
425 else:
425 else:
426 hexfn = fm.hexfunc
426 hexfn = fm.hexfunc
427 formatrev = formathex = str
427 formatrev = formathex = str
428
428
429 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
429 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
430 ('number', ' ', lambda x: x[0].rev(), formatrev),
430 ('number', ' ', lambda x: x[0].rev(), formatrev),
431 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
431 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
432 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
432 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
433 ('file', ' ', lambda x: x[0].path(), str),
433 ('file', ' ', lambda x: x[0].path(), str),
434 ('line_number', ':', lambda x: x[1], str),
434 ('line_number', ':', lambda x: x[1], str),
435 ]
435 ]
436 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
436 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
437
437
438 if (not opts.get('user') and not opts.get('changeset')
438 if (not opts.get('user') and not opts.get('changeset')
439 and not opts.get('date') and not opts.get('file')):
439 and not opts.get('date') and not opts.get('file')):
440 opts['number'] = True
440 opts['number'] = True
441
441
442 linenumber = opts.get('line_number') is not None
442 linenumber = opts.get('line_number') is not None
443 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
443 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
444 raise error.Abort(_('at least one of -n/-c is required for -l'))
444 raise error.Abort(_('at least one of -n/-c is required for -l'))
445
445
446 if fm.isplain():
446 if fm.isplain():
447 def makefunc(get, fmt):
447 def makefunc(get, fmt):
448 return lambda x: fmt(get(x))
448 return lambda x: fmt(get(x))
449 else:
449 else:
450 def makefunc(get, fmt):
450 def makefunc(get, fmt):
451 return get
451 return get
452 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
452 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
453 if opts.get(op)]
453 if opts.get(op)]
454 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
454 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
455 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
455 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
456 if opts.get(op))
456 if opts.get(op))
457
457
458 def bad(x, y):
458 def bad(x, y):
459 raise error.Abort("%s: %s" % (x, y))
459 raise error.Abort("%s: %s" % (x, y))
460
460
461 m = scmutil.match(ctx, pats, opts, badfn=bad)
461 m = scmutil.match(ctx, pats, opts, badfn=bad)
462
462
463 follow = not opts.get('no_follow')
463 follow = not opts.get('no_follow')
464 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
464 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
465 whitespace=True)
465 whitespace=True)
466 for abs in ctx.walk(m):
466 for abs in ctx.walk(m):
467 fctx = ctx[abs]
467 fctx = ctx[abs]
468 if not opts.get('text') and util.binary(fctx.data()):
468 if not opts.get('text') and util.binary(fctx.data()):
469 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
469 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
470 continue
470 continue
471
471
472 lines = fctx.annotate(follow=follow, linenumber=linenumber,
472 lines = fctx.annotate(follow=follow, linenumber=linenumber,
473 diffopts=diffopts)
473 diffopts=diffopts)
474 if not lines:
474 if not lines:
475 continue
475 continue
476 formats = []
476 formats = []
477 pieces = []
477 pieces = []
478
478
479 for f, sep in funcmap:
479 for f, sep in funcmap:
480 l = [f(n) for n, dummy in lines]
480 l = [f(n) for n, dummy in lines]
481 if fm.isplain():
481 if fm.isplain():
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 else:
485 else:
486 formats.append(['%s' for x in l])
486 formats.append(['%s' for x in l])
487 pieces.append(l)
487 pieces.append(l)
488
488
489 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
489 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
490 fm.startitem()
490 fm.startitem()
491 fm.write(fields, "".join(f), *p)
491 fm.write(fields, "".join(f), *p)
492 fm.write('line', ": %s", l[1])
492 fm.write('line', ": %s", l[1])
493
493
494 if not lines[-1][1].endswith('\n'):
494 if not lines[-1][1].endswith('\n'):
495 fm.plain('\n')
495 fm.plain('\n')
496
496
497 fm.end()
497 fm.end()
498
498
499 @command('archive',
499 @command('archive',
500 [('', 'no-decode', None, _('do not pass files through decoders')),
500 [('', 'no-decode', None, _('do not pass files through decoders')),
501 ('p', 'prefix', '', _('directory prefix for files in archive'),
501 ('p', 'prefix', '', _('directory prefix for files in archive'),
502 _('PREFIX')),
502 _('PREFIX')),
503 ('r', 'rev', '', _('revision to distribute'), _('REV')),
503 ('r', 'rev', '', _('revision to distribute'), _('REV')),
504 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
504 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
505 ] + subrepoopts + walkopts,
505 ] + subrepoopts + walkopts,
506 _('[OPTION]... DEST'))
506 _('[OPTION]... DEST'))
507 def archive(ui, repo, dest, **opts):
507 def archive(ui, repo, dest, **opts):
508 '''create an unversioned archive of a repository revision
508 '''create an unversioned archive of a repository revision
509
509
510 By default, the revision used is the parent of the working
510 By default, the revision used is the parent of the working
511 directory; use -r/--rev to specify a different revision.
511 directory; use -r/--rev to specify a different revision.
512
512
513 The archive type is automatically detected based on file
513 The archive type is automatically detected based on file
514 extension (to override, use -t/--type).
514 extension (to override, use -t/--type).
515
515
516 .. container:: verbose
516 .. container:: verbose
517
517
518 Examples:
518 Examples:
519
519
520 - create a zip file containing the 1.0 release::
520 - create a zip file containing the 1.0 release::
521
521
522 hg archive -r 1.0 project-1.0.zip
522 hg archive -r 1.0 project-1.0.zip
523
523
524 - create a tarball excluding .hg files::
524 - create a tarball excluding .hg files::
525
525
526 hg archive project.tar.gz -X ".hg*"
526 hg archive project.tar.gz -X ".hg*"
527
527
528 Valid types are:
528 Valid types are:
529
529
530 :``files``: a directory full of files (default)
530 :``files``: a directory full of files (default)
531 :``tar``: tar archive, uncompressed
531 :``tar``: tar archive, uncompressed
532 :``tbz2``: tar archive, compressed using bzip2
532 :``tbz2``: tar archive, compressed using bzip2
533 :``tgz``: tar archive, compressed using gzip
533 :``tgz``: tar archive, compressed using gzip
534 :``uzip``: zip archive, uncompressed
534 :``uzip``: zip archive, uncompressed
535 :``zip``: zip archive, compressed using deflate
535 :``zip``: zip archive, compressed using deflate
536
536
537 The exact name of the destination archive or directory is given
537 The exact name of the destination archive or directory is given
538 using a format string; see :hg:`help export` for details.
538 using a format string; see :hg:`help export` for details.
539
539
540 Each member added to an archive file has a directory prefix
540 Each member added to an archive file has a directory prefix
541 prepended. Use -p/--prefix to specify a format string for the
541 prepended. Use -p/--prefix to specify a format string for the
542 prefix. The default is the basename of the archive, with suffixes
542 prefix. The default is the basename of the archive, with suffixes
543 removed.
543 removed.
544
544
545 Returns 0 on success.
545 Returns 0 on success.
546 '''
546 '''
547
547
548 ctx = scmutil.revsingle(repo, opts.get('rev'))
548 ctx = scmutil.revsingle(repo, opts.get('rev'))
549 if not ctx:
549 if not ctx:
550 raise error.Abort(_('no working directory: please specify a revision'))
550 raise error.Abort(_('no working directory: please specify a revision'))
551 node = ctx.node()
551 node = ctx.node()
552 dest = cmdutil.makefilename(repo, dest, node)
552 dest = cmdutil.makefilename(repo, dest, node)
553 if os.path.realpath(dest) == repo.root:
553 if os.path.realpath(dest) == repo.root:
554 raise error.Abort(_('repository root cannot be destination'))
554 raise error.Abort(_('repository root cannot be destination'))
555
555
556 kind = opts.get('type') or archival.guesskind(dest) or 'files'
556 kind = opts.get('type') or archival.guesskind(dest) or 'files'
557 prefix = opts.get('prefix')
557 prefix = opts.get('prefix')
558
558
559 if dest == '-':
559 if dest == '-':
560 if kind == 'files':
560 if kind == 'files':
561 raise error.Abort(_('cannot archive plain files to stdout'))
561 raise error.Abort(_('cannot archive plain files to stdout'))
562 dest = cmdutil.makefileobj(repo, dest)
562 dest = cmdutil.makefileobj(repo, dest)
563 if not prefix:
563 if not prefix:
564 prefix = os.path.basename(repo.root) + '-%h'
564 prefix = os.path.basename(repo.root) + '-%h'
565
565
566 prefix = cmdutil.makefilename(repo, prefix, node)
566 prefix = cmdutil.makefilename(repo, prefix, node)
567 matchfn = scmutil.match(ctx, [], opts)
567 matchfn = scmutil.match(ctx, [], opts)
568 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
568 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
569 matchfn, prefix, subrepos=opts.get('subrepos'))
569 matchfn, prefix, subrepos=opts.get('subrepos'))
570
570
571 @command('backout',
571 @command('backout',
572 [('', 'merge', None, _('merge with old dirstate parent after backout')),
572 [('', 'merge', None, _('merge with old dirstate parent after backout')),
573 ('', 'commit', None,
573 ('', 'commit', None,
574 _('commit if no conflicts were encountered (DEPRECATED)')),
574 _('commit if no conflicts were encountered (DEPRECATED)')),
575 ('', 'no-commit', None, _('do not commit')),
575 ('', 'no-commit', None, _('do not commit')),
576 ('', 'parent', '',
576 ('', 'parent', '',
577 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
577 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
578 ('r', 'rev', '', _('revision to backout'), _('REV')),
578 ('r', 'rev', '', _('revision to backout'), _('REV')),
579 ('e', 'edit', False, _('invoke editor on commit messages')),
579 ('e', 'edit', False, _('invoke editor on commit messages')),
580 ] + mergetoolopts + walkopts + commitopts + commitopts2,
580 ] + mergetoolopts + walkopts + commitopts + commitopts2,
581 _('[OPTION]... [-r] REV'))
581 _('[OPTION]... [-r] REV'))
582 def backout(ui, repo, node=None, rev=None, **opts):
582 def backout(ui, repo, node=None, rev=None, **opts):
583 '''reverse effect of earlier changeset
583 '''reverse effect of earlier changeset
584
584
585 Prepare a new changeset with the effect of REV undone in the
585 Prepare a new changeset with the effect of REV undone in the
586 current working directory. If no conflicts were encountered,
586 current working directory. If no conflicts were encountered,
587 it will be committed immediately.
587 it will be committed immediately.
588
588
589 If REV is the parent of the working directory, then this new changeset
589 If REV is the parent of the working directory, then this new changeset
590 is committed automatically (unless --no-commit is specified).
590 is committed automatically (unless --no-commit is specified).
591
591
592 .. note::
592 .. note::
593
593
594 :hg:`backout` cannot be used to fix either an unwanted or
594 :hg:`backout` cannot be used to fix either an unwanted or
595 incorrect merge.
595 incorrect merge.
596
596
597 .. container:: verbose
597 .. container:: verbose
598
598
599 Examples:
599 Examples:
600
600
601 - Reverse the effect of the parent of the working directory.
601 - Reverse the effect of the parent of the working directory.
602 This backout will be committed immediately::
602 This backout will be committed immediately::
603
603
604 hg backout -r .
604 hg backout -r .
605
605
606 - Reverse the effect of previous bad revision 23::
606 - Reverse the effect of previous bad revision 23::
607
607
608 hg backout -r 23
608 hg backout -r 23
609
609
610 - Reverse the effect of previous bad revision 23 and
610 - Reverse the effect of previous bad revision 23 and
611 leave changes uncommitted::
611 leave changes uncommitted::
612
612
613 hg backout -r 23 --no-commit
613 hg backout -r 23 --no-commit
614 hg commit -m "Backout revision 23"
614 hg commit -m "Backout revision 23"
615
615
616 By default, the pending changeset will have one parent,
616 By default, the pending changeset will have one parent,
617 maintaining a linear history. With --merge, the pending
617 maintaining a linear history. With --merge, the pending
618 changeset will instead have two parents: the old parent of the
618 changeset will instead have two parents: the old parent of the
619 working directory and a new child of REV that simply undoes REV.
619 working directory and a new child of REV that simply undoes REV.
620
620
621 Before version 1.7, the behavior without --merge was equivalent
621 Before version 1.7, the behavior without --merge was equivalent
622 to specifying --merge followed by :hg:`update --clean .` to
622 to specifying --merge followed by :hg:`update --clean .` to
623 cancel the merge and leave the child of REV as a head to be
623 cancel the merge and leave the child of REV as a head to be
624 merged separately.
624 merged separately.
625
625
626 See :hg:`help dates` for a list of formats valid for -d/--date.
626 See :hg:`help dates` for a list of formats valid for -d/--date.
627
627
628 See :hg:`help revert` for a way to restore files to the state
628 See :hg:`help revert` for a way to restore files to the state
629 of another revision.
629 of another revision.
630
630
631 Returns 0 on success, 1 if nothing to backout or there are unresolved
631 Returns 0 on success, 1 if nothing to backout or there are unresolved
632 files.
632 files.
633 '''
633 '''
634 wlock = lock = None
634 wlock = lock = None
635 try:
635 try:
636 wlock = repo.wlock()
636 wlock = repo.wlock()
637 lock = repo.lock()
637 lock = repo.lock()
638 return _dobackout(ui, repo, node, rev, **opts)
638 return _dobackout(ui, repo, node, rev, **opts)
639 finally:
639 finally:
640 release(lock, wlock)
640 release(lock, wlock)
641
641
642 def _dobackout(ui, repo, node=None, rev=None, **opts):
642 def _dobackout(ui, repo, node=None, rev=None, **opts):
643 if opts.get('commit') and opts.get('no_commit'):
643 if opts.get('commit') and opts.get('no_commit'):
644 raise error.Abort(_("cannot use --commit with --no-commit"))
644 raise error.Abort(_("cannot use --commit with --no-commit"))
645 if opts.get('merge') and opts.get('no_commit'):
645 if opts.get('merge') and opts.get('no_commit'):
646 raise error.Abort(_("cannot use --merge with --no-commit"))
646 raise error.Abort(_("cannot use --merge with --no-commit"))
647
647
648 if rev and node:
648 if rev and node:
649 raise error.Abort(_("please specify just one revision"))
649 raise error.Abort(_("please specify just one revision"))
650
650
651 if not rev:
651 if not rev:
652 rev = node
652 rev = node
653
653
654 if not rev:
654 if not rev:
655 raise error.Abort(_("please specify a revision to backout"))
655 raise error.Abort(_("please specify a revision to backout"))
656
656
657 date = opts.get('date')
657 date = opts.get('date')
658 if date:
658 if date:
659 opts['date'] = util.parsedate(date)
659 opts['date'] = util.parsedate(date)
660
660
661 cmdutil.checkunfinished(repo)
661 cmdutil.checkunfinished(repo)
662 cmdutil.bailifchanged(repo)
662 cmdutil.bailifchanged(repo)
663 node = scmutil.revsingle(repo, rev).node()
663 node = scmutil.revsingle(repo, rev).node()
664
664
665 op1, op2 = repo.dirstate.parents()
665 op1, op2 = repo.dirstate.parents()
666 if not repo.changelog.isancestor(node, op1):
666 if not repo.changelog.isancestor(node, op1):
667 raise error.Abort(_('cannot backout change that is not an ancestor'))
667 raise error.Abort(_('cannot backout change that is not an ancestor'))
668
668
669 p1, p2 = repo.changelog.parents(node)
669 p1, p2 = repo.changelog.parents(node)
670 if p1 == nullid:
670 if p1 == nullid:
671 raise error.Abort(_('cannot backout a change with no parents'))
671 raise error.Abort(_('cannot backout a change with no parents'))
672 if p2 != nullid:
672 if p2 != nullid:
673 if not opts.get('parent'):
673 if not opts.get('parent'):
674 raise error.Abort(_('cannot backout a merge changeset'))
674 raise error.Abort(_('cannot backout a merge changeset'))
675 p = repo.lookup(opts['parent'])
675 p = repo.lookup(opts['parent'])
676 if p not in (p1, p2):
676 if p not in (p1, p2):
677 raise error.Abort(_('%s is not a parent of %s') %
677 raise error.Abort(_('%s is not a parent of %s') %
678 (short(p), short(node)))
678 (short(p), short(node)))
679 parent = p
679 parent = p
680 else:
680 else:
681 if opts.get('parent'):
681 if opts.get('parent'):
682 raise error.Abort(_('cannot use --parent on non-merge changeset'))
682 raise error.Abort(_('cannot use --parent on non-merge changeset'))
683 parent = p1
683 parent = p1
684
684
685 # the backout should appear on the same branch
685 # the backout should appear on the same branch
686 branch = repo.dirstate.branch()
686 branch = repo.dirstate.branch()
687 bheads = repo.branchheads(branch)
687 bheads = repo.branchheads(branch)
688 rctx = scmutil.revsingle(repo, hex(parent))
688 rctx = scmutil.revsingle(repo, hex(parent))
689 if not opts.get('merge') and op1 != node:
689 if not opts.get('merge') and op1 != node:
690 dsguard = dirstateguard.dirstateguard(repo, 'backout')
690 dsguard = dirstateguard.dirstateguard(repo, 'backout')
691 try:
691 try:
692 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
692 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
693 'backout')
693 'backout')
694 stats = mergemod.update(repo, parent, True, True, node, False)
694 stats = mergemod.update(repo, parent, True, True, node, False)
695 repo.setparents(op1, op2)
695 repo.setparents(op1, op2)
696 dsguard.close()
696 dsguard.close()
697 hg._showstats(repo, stats)
697 hg._showstats(repo, stats)
698 if stats[3]:
698 if stats[3]:
699 repo.ui.status(_("use 'hg resolve' to retry unresolved "
699 repo.ui.status(_("use 'hg resolve' to retry unresolved "
700 "file merges\n"))
700 "file merges\n"))
701 return 1
701 return 1
702 finally:
702 finally:
703 ui.setconfig('ui', 'forcemerge', '', '')
703 ui.setconfig('ui', 'forcemerge', '', '')
704 lockmod.release(dsguard)
704 lockmod.release(dsguard)
705 else:
705 else:
706 hg.clean(repo, node, show_stats=False)
706 hg.clean(repo, node, show_stats=False)
707 repo.dirstate.setbranch(branch)
707 repo.dirstate.setbranch(branch)
708 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
708 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
709
709
710 if opts.get('no_commit'):
710 if opts.get('no_commit'):
711 msg = _("changeset %s backed out, "
711 msg = _("changeset %s backed out, "
712 "don't forget to commit.\n")
712 "don't forget to commit.\n")
713 ui.status(msg % short(node))
713 ui.status(msg % short(node))
714 return 0
714 return 0
715
715
716 def commitfunc(ui, repo, message, match, opts):
716 def commitfunc(ui, repo, message, match, opts):
717 editform = 'backout'
717 editform = 'backout'
718 e = cmdutil.getcommiteditor(editform=editform, **opts)
718 e = cmdutil.getcommiteditor(editform=editform, **opts)
719 if not message:
719 if not message:
720 # we don't translate commit messages
720 # we don't translate commit messages
721 message = "Backed out changeset %s" % short(node)
721 message = "Backed out changeset %s" % short(node)
722 e = cmdutil.getcommiteditor(edit=True, editform=editform)
722 e = cmdutil.getcommiteditor(edit=True, editform=editform)
723 return repo.commit(message, opts.get('user'), opts.get('date'),
723 return repo.commit(message, opts.get('user'), opts.get('date'),
724 match, editor=e)
724 match, editor=e)
725 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
725 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
726 if not newnode:
726 if not newnode:
727 ui.status(_("nothing changed\n"))
727 ui.status(_("nothing changed\n"))
728 return 1
728 return 1
729 cmdutil.commitstatus(repo, newnode, branch, bheads)
729 cmdutil.commitstatus(repo, newnode, branch, bheads)
730
730
731 def nice(node):
731 def nice(node):
732 return '%d:%s' % (repo.changelog.rev(node), short(node))
732 return '%d:%s' % (repo.changelog.rev(node), short(node))
733 ui.status(_('changeset %s backs out changeset %s\n') %
733 ui.status(_('changeset %s backs out changeset %s\n') %
734 (nice(repo.changelog.tip()), nice(node)))
734 (nice(repo.changelog.tip()), nice(node)))
735 if opts.get('merge') and op1 != node:
735 if opts.get('merge') and op1 != node:
736 hg.clean(repo, op1, show_stats=False)
736 hg.clean(repo, op1, show_stats=False)
737 ui.status(_('merging with changeset %s\n')
737 ui.status(_('merging with changeset %s\n')
738 % nice(repo.changelog.tip()))
738 % nice(repo.changelog.tip()))
739 try:
739 try:
740 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
740 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
741 'backout')
741 'backout')
742 return hg.merge(repo, hex(repo.changelog.tip()))
742 return hg.merge(repo, hex(repo.changelog.tip()))
743 finally:
743 finally:
744 ui.setconfig('ui', 'forcemerge', '', '')
744 ui.setconfig('ui', 'forcemerge', '', '')
745 return 0
745 return 0
746
746
747 @command('bisect',
747 @command('bisect',
748 [('r', 'reset', False, _('reset bisect state')),
748 [('r', 'reset', False, _('reset bisect state')),
749 ('g', 'good', False, _('mark changeset good')),
749 ('g', 'good', False, _('mark changeset good')),
750 ('b', 'bad', False, _('mark changeset bad')),
750 ('b', 'bad', False, _('mark changeset bad')),
751 ('s', 'skip', False, _('skip testing changeset')),
751 ('s', 'skip', False, _('skip testing changeset')),
752 ('e', 'extend', False, _('extend the bisect range')),
752 ('e', 'extend', False, _('extend the bisect range')),
753 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
753 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
754 ('U', 'noupdate', False, _('do not update to target'))],
754 ('U', 'noupdate', False, _('do not update to target'))],
755 _("[-gbsr] [-U] [-c CMD] [REV]"))
755 _("[-gbsr] [-U] [-c CMD] [REV]"))
756 def bisect(ui, repo, rev=None, extra=None, command=None,
756 def bisect(ui, repo, rev=None, extra=None, command=None,
757 reset=None, good=None, bad=None, skip=None, extend=None,
757 reset=None, good=None, bad=None, skip=None, extend=None,
758 noupdate=None):
758 noupdate=None):
759 """subdivision search of changesets
759 """subdivision search of changesets
760
760
761 This command helps to find changesets which introduce problems. To
761 This command helps to find changesets which introduce problems. To
762 use, mark the earliest changeset you know exhibits the problem as
762 use, mark the earliest changeset you know exhibits the problem as
763 bad, then mark the latest changeset which is free from the problem
763 bad, then mark the latest changeset which is free from the problem
764 as good. Bisect will update your working directory to a revision
764 as good. Bisect will update your working directory to a revision
765 for testing (unless the -U/--noupdate option is specified). Once
765 for testing (unless the -U/--noupdate option is specified). Once
766 you have performed tests, mark the working directory as good or
766 you have performed tests, mark the working directory as good or
767 bad, and bisect will either update to another candidate changeset
767 bad, and bisect will either update to another candidate changeset
768 or announce that it has found the bad revision.
768 or announce that it has found the bad revision.
769
769
770 As a shortcut, you can also use the revision argument to mark a
770 As a shortcut, you can also use the revision argument to mark a
771 revision as good or bad without checking it out first.
771 revision as good or bad without checking it out first.
772
772
773 If you supply a command, it will be used for automatic bisection.
773 If you supply a command, it will be used for automatic bisection.
774 The environment variable HG_NODE will contain the ID of the
774 The environment variable HG_NODE will contain the ID of the
775 changeset being tested. The exit status of the command will be
775 changeset being tested. The exit status of the command will be
776 used to mark revisions as good or bad: status 0 means good, 125
776 used to mark revisions as good or bad: status 0 means good, 125
777 means to skip the revision, 127 (command not found) will abort the
777 means to skip the revision, 127 (command not found) will abort the
778 bisection, and any other non-zero exit status means the revision
778 bisection, and any other non-zero exit status means the revision
779 is bad.
779 is bad.
780
780
781 .. container:: verbose
781 .. container:: verbose
782
782
783 Some examples:
783 Some examples:
784
784
785 - start a bisection with known bad revision 34, and good revision 12::
785 - start a bisection with known bad revision 34, and good revision 12::
786
786
787 hg bisect --bad 34
787 hg bisect --bad 34
788 hg bisect --good 12
788 hg bisect --good 12
789
789
790 - advance the current bisection by marking current revision as good or
790 - advance the current bisection by marking current revision as good or
791 bad::
791 bad::
792
792
793 hg bisect --good
793 hg bisect --good
794 hg bisect --bad
794 hg bisect --bad
795
795
796 - mark the current revision, or a known revision, to be skipped (e.g. if
796 - mark the current revision, or a known revision, to be skipped (e.g. if
797 that revision is not usable because of another issue)::
797 that revision is not usable because of another issue)::
798
798
799 hg bisect --skip
799 hg bisect --skip
800 hg bisect --skip 23
800 hg bisect --skip 23
801
801
802 - skip all revisions that do not touch directories ``foo`` or ``bar``::
802 - skip all revisions that do not touch directories ``foo`` or ``bar``::
803
803
804 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
804 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
805
805
806 - forget the current bisection::
806 - forget the current bisection::
807
807
808 hg bisect --reset
808 hg bisect --reset
809
809
810 - use 'make && make tests' to automatically find the first broken
810 - use 'make && make tests' to automatically find the first broken
811 revision::
811 revision::
812
812
813 hg bisect --reset
813 hg bisect --reset
814 hg bisect --bad 34
814 hg bisect --bad 34
815 hg bisect --good 12
815 hg bisect --good 12
816 hg bisect --command "make && make tests"
816 hg bisect --command "make && make tests"
817
817
818 - see all changesets whose states are already known in the current
818 - see all changesets whose states are already known in the current
819 bisection::
819 bisection::
820
820
821 hg log -r "bisect(pruned)"
821 hg log -r "bisect(pruned)"
822
822
823 - see the changeset currently being bisected (especially useful
823 - see the changeset currently being bisected (especially useful
824 if running with -U/--noupdate)::
824 if running with -U/--noupdate)::
825
825
826 hg log -r "bisect(current)"
826 hg log -r "bisect(current)"
827
827
828 - see all changesets that took part in the current bisection::
828 - see all changesets that took part in the current bisection::
829
829
830 hg log -r "bisect(range)"
830 hg log -r "bisect(range)"
831
831
832 - you can even get a nice graph::
832 - you can even get a nice graph::
833
833
834 hg log --graph -r "bisect(range)"
834 hg log --graph -r "bisect(range)"
835
835
836 See :hg:`help revsets` for more about the `bisect()` keyword.
836 See :hg:`help revsets` for more about the `bisect()` keyword.
837
837
838 Returns 0 on success.
838 Returns 0 on success.
839 """
839 """
840 # backward compatibility
840 # backward compatibility
841 if rev in "good bad reset init".split():
841 if rev in "good bad reset init".split():
842 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
842 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
843 cmd, rev, extra = rev, extra, None
843 cmd, rev, extra = rev, extra, None
844 if cmd == "good":
844 if cmd == "good":
845 good = True
845 good = True
846 elif cmd == "bad":
846 elif cmd == "bad":
847 bad = True
847 bad = True
848 else:
848 else:
849 reset = True
849 reset = True
850 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
850 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
851 raise error.Abort(_('incompatible arguments'))
851 raise error.Abort(_('incompatible arguments'))
852
852
853 cmdutil.checkunfinished(repo)
853 cmdutil.checkunfinished(repo)
854
854
855 if reset:
855 if reset:
856 hbisect.resetstate(repo)
856 hbisect.resetstate(repo)
857 return
857 return
858
858
859 state = hbisect.load_state(repo)
859 state = hbisect.load_state(repo)
860
860
861 # update state
861 # update state
862 if good or bad or skip:
862 if good or bad or skip:
863 if rev:
863 if rev:
864 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
864 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
865 else:
865 else:
866 nodes = [repo.lookup('.')]
866 nodes = [repo.lookup('.')]
867 if good:
867 if good:
868 state['good'] += nodes
868 state['good'] += nodes
869 elif bad:
869 elif bad:
870 state['bad'] += nodes
870 state['bad'] += nodes
871 elif skip:
871 elif skip:
872 state['skip'] += nodes
872 state['skip'] += nodes
873 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
874 if not (state['good'] and state['bad']):
874 if not (state['good'] and state['bad']):
875 return
875 return
876
876
877 def mayupdate(repo, node, show_stats=True):
877 def mayupdate(repo, node, show_stats=True):
878 """common used update sequence"""
878 """common used update sequence"""
879 if noupdate:
879 if noupdate:
880 return
880 return
881 cmdutil.bailifchanged(repo)
881 cmdutil.bailifchanged(repo)
882 return hg.clean(repo, node, show_stats=show_stats)
882 return hg.clean(repo, node, show_stats=show_stats)
883
883
884 displayer = cmdutil.show_changeset(ui, repo, {})
884 displayer = cmdutil.show_changeset(ui, repo, {})
885
885
886 if command:
886 if command:
887 changesets = 1
887 changesets = 1
888 if noupdate:
888 if noupdate:
889 try:
889 try:
890 node = state['current'][0]
890 node = state['current'][0]
891 except LookupError:
891 except LookupError:
892 raise error.Abort(_('current bisect revision is unknown - '
892 raise error.Abort(_('current bisect revision is unknown - '
893 'start a new bisect to fix'))
893 'start a new bisect to fix'))
894 else:
894 else:
895 node, p2 = repo.dirstate.parents()
895 node, p2 = repo.dirstate.parents()
896 if p2 != nullid:
896 if p2 != nullid:
897 raise error.Abort(_('current bisect revision is a merge'))
897 raise error.Abort(_('current bisect revision is a merge'))
898 if rev:
898 if rev:
899 node = repo[scmutil.revsingle(repo, rev, node)].node()
899 node = repo[scmutil.revsingle(repo, rev, node)].node()
900 try:
900 try:
901 while changesets:
901 while changesets:
902 # update state
902 # update state
903 state['current'] = [node]
903 state['current'] = [node]
904 hbisect.save_state(repo, state)
904 hbisect.save_state(repo, state)
905 status = ui.system(command, environ={'HG_NODE': hex(node)})
905 status = ui.system(command, environ={'HG_NODE': hex(node)})
906 if status == 125:
906 if status == 125:
907 transition = "skip"
907 transition = "skip"
908 elif status == 0:
908 elif status == 0:
909 transition = "good"
909 transition = "good"
910 # status < 0 means process was killed
910 # status < 0 means process was killed
911 elif status == 127:
911 elif status == 127:
912 raise error.Abort(_("failed to execute %s") % command)
912 raise error.Abort(_("failed to execute %s") % command)
913 elif status < 0:
913 elif status < 0:
914 raise error.Abort(_("%s killed") % command)
914 raise error.Abort(_("%s killed") % command)
915 else:
915 else:
916 transition = "bad"
916 transition = "bad"
917 state[transition].append(node)
917 state[transition].append(node)
918 ctx = repo[node]
918 ctx = repo[node]
919 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
919 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
920 hbisect.checkstate(state)
920 hbisect.checkstate(state)
921 # bisect
921 # bisect
922 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
922 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
923 # update to next check
923 # update to next check
924 node = nodes[0]
924 node = nodes[0]
925 mayupdate(repo, node, show_stats=False)
925 mayupdate(repo, node, show_stats=False)
926 finally:
926 finally:
927 state['current'] = [node]
927 state['current'] = [node]
928 hbisect.save_state(repo, state)
928 hbisect.save_state(repo, state)
929 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
929 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
930 return
930 return
931
931
932 hbisect.checkstate(state)
932 hbisect.checkstate(state)
933
933
934 # actually bisect
934 # actually bisect
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
936 if extend:
936 if extend:
937 if not changesets:
937 if not changesets:
938 extendnode = hbisect.extendrange(repo, state, nodes, good)
938 extendnode = hbisect.extendrange(repo, state, nodes, good)
939 if extendnode is not None:
939 if extendnode is not None:
940 ui.write(_("Extending search to changeset %d:%s\n")
940 ui.write(_("Extending search to changeset %d:%s\n")
941 % (extendnode.rev(), extendnode))
941 % (extendnode.rev(), extendnode))
942 state['current'] = [extendnode.node()]
942 state['current'] = [extendnode.node()]
943 hbisect.save_state(repo, state)
943 hbisect.save_state(repo, state)
944 return mayupdate(repo, extendnode.node())
944 return mayupdate(repo, extendnode.node())
945 raise error.Abort(_("nothing to extend"))
945 raise error.Abort(_("nothing to extend"))
946
946
947 if changesets == 0:
947 if changesets == 0:
948 hbisect.printresult(ui, repo, state, displayer, nodes, good)
948 hbisect.printresult(ui, repo, state, displayer, nodes, good)
949 else:
949 else:
950 assert len(nodes) == 1 # only a single node can be tested next
950 assert len(nodes) == 1 # only a single node can be tested next
951 node = nodes[0]
951 node = nodes[0]
952 # compute the approximate number of remaining tests
952 # compute the approximate number of remaining tests
953 tests, size = 0, 2
953 tests, size = 0, 2
954 while size <= changesets:
954 while size <= changesets:
955 tests, size = tests + 1, size * 2
955 tests, size = tests + 1, size * 2
956 rev = repo.changelog.rev(node)
956 rev = repo.changelog.rev(node)
957 ui.write(_("Testing changeset %d:%s "
957 ui.write(_("Testing changeset %d:%s "
958 "(%d changesets remaining, ~%d tests)\n")
958 "(%d changesets remaining, ~%d tests)\n")
959 % (rev, short(node), changesets, tests))
959 % (rev, short(node), changesets, tests))
960 state['current'] = [node]
960 state['current'] = [node]
961 hbisect.save_state(repo, state)
961 hbisect.save_state(repo, state)
962 return mayupdate(repo, node)
962 return mayupdate(repo, node)
963
963
964 @command('bookmarks|bookmark',
964 @command('bookmarks|bookmark',
965 [('f', 'force', False, _('force')),
965 [('f', 'force', False, _('force')),
966 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
966 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
967 ('d', 'delete', False, _('delete a given bookmark')),
967 ('d', 'delete', False, _('delete a given bookmark')),
968 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
968 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
969 ('i', 'inactive', False, _('mark a bookmark inactive')),
969 ('i', 'inactive', False, _('mark a bookmark inactive')),
970 ] + formatteropts,
970 ] + formatteropts,
971 _('hg bookmarks [OPTIONS]... [NAME]...'))
971 _('hg bookmarks [OPTIONS]... [NAME]...'))
972 def bookmark(ui, repo, *names, **opts):
972 def bookmark(ui, repo, *names, **opts):
973 '''create a new bookmark or list existing bookmarks
973 '''create a new bookmark or list existing bookmarks
974
974
975 Bookmarks are labels on changesets to help track lines of development.
975 Bookmarks are labels on changesets to help track lines of development.
976 Bookmarks are unversioned and can be moved, renamed and deleted.
976 Bookmarks are unversioned and can be moved, renamed and deleted.
977 Deleting or moving a bookmark has no effect on the associated changesets.
977 Deleting or moving a bookmark has no effect on the associated changesets.
978
978
979 Creating or updating to a bookmark causes it to be marked as 'active'.
979 Creating or updating to a bookmark causes it to be marked as 'active'.
980 The active bookmark is indicated with a '*'.
980 The active bookmark is indicated with a '*'.
981 When a commit is made, the active bookmark will advance to the new commit.
981 When a commit is made, the active bookmark will advance to the new commit.
982 A plain :hg:`update` will also advance an active bookmark, if possible.
982 A plain :hg:`update` will also advance an active bookmark, if possible.
983 Updating away from a bookmark will cause it to be deactivated.
983 Updating away from a bookmark will cause it to be deactivated.
984
984
985 Bookmarks can be pushed and pulled between repositories (see
985 Bookmarks can be pushed and pulled between repositories (see
986 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
986 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
987 diverged, a new 'divergent bookmark' of the form 'name@path' will
987 diverged, a new 'divergent bookmark' of the form 'name@path' will
988 be created. Using :hg:`merge` will resolve the divergence.
988 be created. Using :hg:`merge` will resolve the divergence.
989
989
990 A bookmark named '@' has the special property that :hg:`clone` will
990 A bookmark named '@' has the special property that :hg:`clone` will
991 check it out by default if it exists.
991 check it out by default if it exists.
992
992
993 .. container:: verbose
993 .. container:: verbose
994
994
995 Examples:
995 Examples:
996
996
997 - create an active bookmark for a new line of development::
997 - create an active bookmark for a new line of development::
998
998
999 hg book new-feature
999 hg book new-feature
1000
1000
1001 - create an inactive bookmark as a place marker::
1001 - create an inactive bookmark as a place marker::
1002
1002
1003 hg book -i reviewed
1003 hg book -i reviewed
1004
1004
1005 - create an inactive bookmark on another changeset::
1005 - create an inactive bookmark on another changeset::
1006
1006
1007 hg book -r .^ tested
1007 hg book -r .^ tested
1008
1008
1009 - rename bookmark turkey to dinner::
1009 - rename bookmark turkey to dinner::
1010
1010
1011 hg book -m turkey dinner
1011 hg book -m turkey dinner
1012
1012
1013 - move the '@' bookmark from another branch::
1013 - move the '@' bookmark from another branch::
1014
1014
1015 hg book -f @
1015 hg book -f @
1016 '''
1016 '''
1017 force = opts.get('force')
1017 force = opts.get('force')
1018 rev = opts.get('rev')
1018 rev = opts.get('rev')
1019 delete = opts.get('delete')
1019 delete = opts.get('delete')
1020 rename = opts.get('rename')
1020 rename = opts.get('rename')
1021 inactive = opts.get('inactive')
1021 inactive = opts.get('inactive')
1022
1022
1023 def checkformat(mark):
1023 def checkformat(mark):
1024 mark = mark.strip()
1024 mark = mark.strip()
1025 if not mark:
1025 if not mark:
1026 raise error.Abort(_("bookmark names cannot consist entirely of "
1026 raise error.Abort(_("bookmark names cannot consist entirely of "
1027 "whitespace"))
1027 "whitespace"))
1028 scmutil.checknewlabel(repo, mark, 'bookmark')
1028 scmutil.checknewlabel(repo, mark, 'bookmark')
1029 return mark
1029 return mark
1030
1030
1031 def checkconflict(repo, mark, cur, force=False, target=None):
1031 def checkconflict(repo, mark, cur, force=False, target=None):
1032 if mark in marks and not force:
1032 if mark in marks and not force:
1033 if target:
1033 if target:
1034 if marks[mark] == target and target == cur:
1034 if marks[mark] == target and target == cur:
1035 # re-activating a bookmark
1035 # re-activating a bookmark
1036 return
1036 return
1037 anc = repo.changelog.ancestors([repo[target].rev()])
1037 anc = repo.changelog.ancestors([repo[target].rev()])
1038 bmctx = repo[marks[mark]]
1038 bmctx = repo[marks[mark]]
1039 divs = [repo[b].node() for b in marks
1039 divs = [repo[b].node() for b in marks
1040 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1040 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1041
1041
1042 # allow resolving a single divergent bookmark even if moving
1042 # allow resolving a single divergent bookmark even if moving
1043 # the bookmark across branches when a revision is specified
1043 # the bookmark across branches when a revision is specified
1044 # that contains a divergent bookmark
1044 # that contains a divergent bookmark
1045 if bmctx.rev() not in anc and target in divs:
1045 if bmctx.rev() not in anc and target in divs:
1046 bookmarks.deletedivergent(repo, [target], mark)
1046 bookmarks.deletedivergent(repo, [target], mark)
1047 return
1047 return
1048
1048
1049 deletefrom = [b for b in divs
1049 deletefrom = [b for b in divs
1050 if repo[b].rev() in anc or b == target]
1050 if repo[b].rev() in anc or b == target]
1051 bookmarks.deletedivergent(repo, deletefrom, mark)
1051 bookmarks.deletedivergent(repo, deletefrom, mark)
1052 if bookmarks.validdest(repo, bmctx, repo[target]):
1052 if bookmarks.validdest(repo, bmctx, repo[target]):
1053 ui.status(_("moving bookmark '%s' forward from %s\n") %
1053 ui.status(_("moving bookmark '%s' forward from %s\n") %
1054 (mark, short(bmctx.node())))
1054 (mark, short(bmctx.node())))
1055 return
1055 return
1056 raise error.Abort(_("bookmark '%s' already exists "
1056 raise error.Abort(_("bookmark '%s' already exists "
1057 "(use -f to force)") % mark)
1057 "(use -f to force)") % mark)
1058 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1058 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1059 and not force):
1059 and not force):
1060 raise error.Abort(
1060 raise error.Abort(
1061 _("a bookmark cannot have the name of an existing branch"))
1061 _("a bookmark cannot have the name of an existing branch"))
1062
1062
1063 if delete and rename:
1063 if delete and rename:
1064 raise error.Abort(_("--delete and --rename are incompatible"))
1064 raise error.Abort(_("--delete and --rename are incompatible"))
1065 if delete and rev:
1065 if delete and rev:
1066 raise error.Abort(_("--rev is incompatible with --delete"))
1066 raise error.Abort(_("--rev is incompatible with --delete"))
1067 if rename and rev:
1067 if rename and rev:
1068 raise error.Abort(_("--rev is incompatible with --rename"))
1068 raise error.Abort(_("--rev is incompatible with --rename"))
1069 if not names and (delete or rev):
1069 if not names and (delete or rev):
1070 raise error.Abort(_("bookmark name required"))
1070 raise error.Abort(_("bookmark name required"))
1071
1071
1072 if delete or rename or names or inactive:
1072 if delete or rename or names or inactive:
1073 wlock = lock = tr = None
1073 wlock = lock = tr = None
1074 try:
1074 try:
1075 wlock = repo.wlock()
1075 wlock = repo.wlock()
1076 lock = repo.lock()
1076 lock = repo.lock()
1077 cur = repo.changectx('.').node()
1077 cur = repo.changectx('.').node()
1078 marks = repo._bookmarks
1078 marks = repo._bookmarks
1079 if delete:
1079 if delete:
1080 tr = repo.transaction('bookmark')
1080 tr = repo.transaction('bookmark')
1081 for mark in names:
1081 for mark in names:
1082 if mark not in marks:
1082 if mark not in marks:
1083 raise error.Abort(_("bookmark '%s' does not exist") %
1083 raise error.Abort(_("bookmark '%s' does not exist") %
1084 mark)
1084 mark)
1085 if mark == repo._activebookmark:
1085 if mark == repo._activebookmark:
1086 bookmarks.deactivate(repo)
1086 bookmarks.deactivate(repo)
1087 del marks[mark]
1087 del marks[mark]
1088
1088
1089 elif rename:
1089 elif rename:
1090 tr = repo.transaction('bookmark')
1090 tr = repo.transaction('bookmark')
1091 if not names:
1091 if not names:
1092 raise error.Abort(_("new bookmark name required"))
1092 raise error.Abort(_("new bookmark name required"))
1093 elif len(names) > 1:
1093 elif len(names) > 1:
1094 raise error.Abort(_("only one new bookmark name allowed"))
1094 raise error.Abort(_("only one new bookmark name allowed"))
1095 mark = checkformat(names[0])
1095 mark = checkformat(names[0])
1096 if rename not in marks:
1096 if rename not in marks:
1097 raise error.Abort(_("bookmark '%s' does not exist")
1097 raise error.Abort(_("bookmark '%s' does not exist")
1098 % rename)
1098 % rename)
1099 checkconflict(repo, mark, cur, force)
1099 checkconflict(repo, mark, cur, force)
1100 marks[mark] = marks[rename]
1100 marks[mark] = marks[rename]
1101 if repo._activebookmark == rename and not inactive:
1101 if repo._activebookmark == rename and not inactive:
1102 bookmarks.activate(repo, mark)
1102 bookmarks.activate(repo, mark)
1103 del marks[rename]
1103 del marks[rename]
1104 elif names:
1104 elif names:
1105 tr = repo.transaction('bookmark')
1105 tr = repo.transaction('bookmark')
1106 newact = None
1106 newact = None
1107 for mark in names:
1107 for mark in names:
1108 mark = checkformat(mark)
1108 mark = checkformat(mark)
1109 if newact is None:
1109 if newact is None:
1110 newact = mark
1110 newact = mark
1111 if inactive and mark == repo._activebookmark:
1111 if inactive and mark == repo._activebookmark:
1112 bookmarks.deactivate(repo)
1112 bookmarks.deactivate(repo)
1113 return
1113 return
1114 tgt = cur
1114 tgt = cur
1115 if rev:
1115 if rev:
1116 tgt = scmutil.revsingle(repo, rev).node()
1116 tgt = scmutil.revsingle(repo, rev).node()
1117 checkconflict(repo, mark, cur, force, tgt)
1117 checkconflict(repo, mark, cur, force, tgt)
1118 marks[mark] = tgt
1118 marks[mark] = tgt
1119 if not inactive and cur == marks[newact] and not rev:
1119 if not inactive and cur == marks[newact] and not rev:
1120 bookmarks.activate(repo, newact)
1120 bookmarks.activate(repo, newact)
1121 elif cur != tgt and newact == repo._activebookmark:
1121 elif cur != tgt and newact == repo._activebookmark:
1122 bookmarks.deactivate(repo)
1122 bookmarks.deactivate(repo)
1123 elif inactive:
1123 elif inactive:
1124 if len(marks) == 0:
1124 if len(marks) == 0:
1125 ui.status(_("no bookmarks set\n"))
1125 ui.status(_("no bookmarks set\n"))
1126 elif not repo._activebookmark:
1126 elif not repo._activebookmark:
1127 ui.status(_("no active bookmark\n"))
1127 ui.status(_("no active bookmark\n"))
1128 else:
1128 else:
1129 bookmarks.deactivate(repo)
1129 bookmarks.deactivate(repo)
1130 if tr is not None:
1130 if tr is not None:
1131 marks.recordchange(tr)
1131 marks.recordchange(tr)
1132 tr.close()
1132 tr.close()
1133 finally:
1133 finally:
1134 lockmod.release(tr, lock, wlock)
1134 lockmod.release(tr, lock, wlock)
1135 else: # show bookmarks
1135 else: # show bookmarks
1136 fm = ui.formatter('bookmarks', opts)
1136 fm = ui.formatter('bookmarks', opts)
1137 hexfn = fm.hexfunc
1137 hexfn = fm.hexfunc
1138 marks = repo._bookmarks
1138 marks = repo._bookmarks
1139 if len(marks) == 0 and fm.isplain():
1139 if len(marks) == 0 and fm.isplain():
1140 ui.status(_("no bookmarks set\n"))
1140 ui.status(_("no bookmarks set\n"))
1141 for bmark, n in sorted(marks.iteritems()):
1141 for bmark, n in sorted(marks.iteritems()):
1142 active = repo._activebookmark
1142 active = repo._activebookmark
1143 if bmark == active:
1143 if bmark == active:
1144 prefix, label = '*', activebookmarklabel
1144 prefix, label = '*', activebookmarklabel
1145 else:
1145 else:
1146 prefix, label = ' ', ''
1146 prefix, label = ' ', ''
1147
1147
1148 fm.startitem()
1148 fm.startitem()
1149 if not ui.quiet:
1149 if not ui.quiet:
1150 fm.plain(' %s ' % prefix, label=label)
1150 fm.plain(' %s ' % prefix, label=label)
1151 fm.write('bookmark', '%s', bmark, label=label)
1151 fm.write('bookmark', '%s', bmark, label=label)
1152 pad = " " * (25 - encoding.colwidth(bmark))
1152 pad = " " * (25 - encoding.colwidth(bmark))
1153 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1153 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1154 repo.changelog.rev(n), hexfn(n), label=label)
1154 repo.changelog.rev(n), hexfn(n), label=label)
1155 fm.data(active=(bmark == active))
1155 fm.data(active=(bmark == active))
1156 fm.plain('\n')
1156 fm.plain('\n')
1157 fm.end()
1157 fm.end()
1158
1158
1159 @command('branch',
1159 @command('branch',
1160 [('f', 'force', None,
1160 [('f', 'force', None,
1161 _('set branch name even if it shadows an existing branch')),
1161 _('set branch name even if it shadows an existing branch')),
1162 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1162 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1163 _('[-fC] [NAME]'))
1163 _('[-fC] [NAME]'))
1164 def branch(ui, repo, label=None, **opts):
1164 def branch(ui, repo, label=None, **opts):
1165 """set or show the current branch name
1165 """set or show the current branch name
1166
1166
1167 .. note::
1167 .. note::
1168
1168
1169 Branch names are permanent and global. Use :hg:`bookmark` to create a
1169 Branch names are permanent and global. Use :hg:`bookmark` to create a
1170 light-weight bookmark instead. See :hg:`help glossary` for more
1170 light-weight bookmark instead. See :hg:`help glossary` for more
1171 information about named branches and bookmarks.
1171 information about named branches and bookmarks.
1172
1172
1173 With no argument, show the current branch name. With one argument,
1173 With no argument, show the current branch name. With one argument,
1174 set the working directory branch name (the branch will not exist
1174 set the working directory branch name (the branch will not exist
1175 in the repository until the next commit). Standard practice
1175 in the repository until the next commit). Standard practice
1176 recommends that primary development take place on the 'default'
1176 recommends that primary development take place on the 'default'
1177 branch.
1177 branch.
1178
1178
1179 Unless -f/--force is specified, branch will not let you set a
1179 Unless -f/--force is specified, branch will not let you set a
1180 branch name that already exists.
1180 branch name that already exists.
1181
1181
1182 Use -C/--clean to reset the working directory branch to that of
1182 Use -C/--clean to reset the working directory branch to that of
1183 the parent of the working directory, negating a previous branch
1183 the parent of the working directory, negating a previous branch
1184 change.
1184 change.
1185
1185
1186 Use the command :hg:`update` to switch to an existing branch. Use
1186 Use the command :hg:`update` to switch to an existing branch. Use
1187 :hg:`commit --close-branch` to mark this branch head as closed.
1187 :hg:`commit --close-branch` to mark this branch head as closed.
1188 When all heads of a branch are closed, the branch will be
1188 When all heads of a branch are closed, the branch will be
1189 considered closed.
1189 considered closed.
1190
1190
1191 Returns 0 on success.
1191 Returns 0 on success.
1192 """
1192 """
1193 if label:
1193 if label:
1194 label = label.strip()
1194 label = label.strip()
1195
1195
1196 if not opts.get('clean') and not label:
1196 if not opts.get('clean') and not label:
1197 ui.write("%s\n" % repo.dirstate.branch())
1197 ui.write("%s\n" % repo.dirstate.branch())
1198 return
1198 return
1199
1199
1200 with repo.wlock():
1200 with repo.wlock():
1201 if opts.get('clean'):
1201 if opts.get('clean'):
1202 label = repo[None].p1().branch()
1202 label = repo[None].p1().branch()
1203 repo.dirstate.setbranch(label)
1203 repo.dirstate.setbranch(label)
1204 ui.status(_('reset working directory to branch %s\n') % label)
1204 ui.status(_('reset working directory to branch %s\n') % label)
1205 elif label:
1205 elif label:
1206 if not opts.get('force') and label in repo.branchmap():
1206 if not opts.get('force') and label in repo.branchmap():
1207 if label not in [p.branch() for p in repo[None].parents()]:
1207 if label not in [p.branch() for p in repo[None].parents()]:
1208 raise error.Abort(_('a branch of the same name already'
1208 raise error.Abort(_('a branch of the same name already'
1209 ' exists'),
1209 ' exists'),
1210 # i18n: "it" refers to an existing branch
1210 # i18n: "it" refers to an existing branch
1211 hint=_("use 'hg update' to switch to it"))
1211 hint=_("use 'hg update' to switch to it"))
1212 scmutil.checknewlabel(repo, label, 'branch')
1212 scmutil.checknewlabel(repo, label, 'branch')
1213 repo.dirstate.setbranch(label)
1213 repo.dirstate.setbranch(label)
1214 ui.status(_('marked working directory as branch %s\n') % label)
1214 ui.status(_('marked working directory as branch %s\n') % label)
1215
1215
1216 # find any open named branches aside from default
1216 # find any open named branches aside from default
1217 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1217 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1218 if n != "default" and not c]
1218 if n != "default" and not c]
1219 if not others:
1219 if not others:
1220 ui.status(_('(branches are permanent and global, '
1220 ui.status(_('(branches are permanent and global, '
1221 'did you want a bookmark?)\n'))
1221 'did you want a bookmark?)\n'))
1222
1222
1223 @command('branches',
1223 @command('branches',
1224 [('a', 'active', False,
1224 [('a', 'active', False,
1225 _('show only branches that have unmerged heads (DEPRECATED)')),
1225 _('show only branches that have unmerged heads (DEPRECATED)')),
1226 ('c', 'closed', False, _('show normal and closed branches')),
1226 ('c', 'closed', False, _('show normal and closed branches')),
1227 ] + formatteropts,
1227 ] + formatteropts,
1228 _('[-c]'))
1228 _('[-c]'))
1229 def branches(ui, repo, active=False, closed=False, **opts):
1229 def branches(ui, repo, active=False, closed=False, **opts):
1230 """list repository named branches
1230 """list repository named branches
1231
1231
1232 List the repository's named branches, indicating which ones are
1232 List the repository's named branches, indicating which ones are
1233 inactive. If -c/--closed is specified, also list branches which have
1233 inactive. If -c/--closed is specified, also list branches which have
1234 been marked closed (see :hg:`commit --close-branch`).
1234 been marked closed (see :hg:`commit --close-branch`).
1235
1235
1236 Use the command :hg:`update` to switch to an existing branch.
1236 Use the command :hg:`update` to switch to an existing branch.
1237
1237
1238 Returns 0.
1238 Returns 0.
1239 """
1239 """
1240
1240
1241 fm = ui.formatter('branches', opts)
1241 fm = ui.formatter('branches', opts)
1242 hexfunc = fm.hexfunc
1242 hexfunc = fm.hexfunc
1243
1243
1244 allheads = set(repo.heads())
1244 allheads = set(repo.heads())
1245 branches = []
1245 branches = []
1246 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1246 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1247 isactive = not isclosed and bool(set(heads) & allheads)
1247 isactive = not isclosed and bool(set(heads) & allheads)
1248 branches.append((tag, repo[tip], isactive, not isclosed))
1248 branches.append((tag, repo[tip], isactive, not isclosed))
1249 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1249 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1250 reverse=True)
1250 reverse=True)
1251
1251
1252 for tag, ctx, isactive, isopen in branches:
1252 for tag, ctx, isactive, isopen in branches:
1253 if active and not isactive:
1253 if active and not isactive:
1254 continue
1254 continue
1255 if isactive:
1255 if isactive:
1256 label = 'branches.active'
1256 label = 'branches.active'
1257 notice = ''
1257 notice = ''
1258 elif not isopen:
1258 elif not isopen:
1259 if not closed:
1259 if not closed:
1260 continue
1260 continue
1261 label = 'branches.closed'
1261 label = 'branches.closed'
1262 notice = _(' (closed)')
1262 notice = _(' (closed)')
1263 else:
1263 else:
1264 label = 'branches.inactive'
1264 label = 'branches.inactive'
1265 notice = _(' (inactive)')
1265 notice = _(' (inactive)')
1266 current = (tag == repo.dirstate.branch())
1266 current = (tag == repo.dirstate.branch())
1267 if current:
1267 if current:
1268 label = 'branches.current'
1268 label = 'branches.current'
1269
1269
1270 fm.startitem()
1270 fm.startitem()
1271 fm.write('branch', '%s', tag, label=label)
1271 fm.write('branch', '%s', tag, label=label)
1272 rev = ctx.rev()
1272 rev = ctx.rev()
1273 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1273 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1274 fmt = ' ' * padsize + ' %d:%s'
1274 fmt = ' ' * padsize + ' %d:%s'
1275 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1275 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1276 label='log.changeset changeset.%s' % ctx.phasestr())
1276 label='log.changeset changeset.%s' % ctx.phasestr())
1277 fm.data(active=isactive, closed=not isopen, current=current)
1277 fm.data(active=isactive, closed=not isopen, current=current)
1278 if not ui.quiet:
1278 if not ui.quiet:
1279 fm.plain(notice)
1279 fm.plain(notice)
1280 fm.plain('\n')
1280 fm.plain('\n')
1281 fm.end()
1281 fm.end()
1282
1282
1283 @command('bundle',
1283 @command('bundle',
1284 [('f', 'force', None, _('run even when the destination is unrelated')),
1284 [('f', 'force', None, _('run even when the destination is unrelated')),
1285 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1285 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1286 _('REV')),
1286 _('REV')),
1287 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1287 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1288 _('BRANCH')),
1288 _('BRANCH')),
1289 ('', 'base', [],
1289 ('', 'base', [],
1290 _('a base changeset assumed to be available at the destination'),
1290 _('a base changeset assumed to be available at the destination'),
1291 _('REV')),
1291 _('REV')),
1292 ('a', 'all', None, _('bundle all changesets in the repository')),
1292 ('a', 'all', None, _('bundle all changesets in the repository')),
1293 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1293 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1294 ] + remoteopts,
1294 ] + remoteopts,
1295 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1295 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1296 def bundle(ui, repo, fname, dest=None, **opts):
1296 def bundle(ui, repo, fname, dest=None, **opts):
1297 """create a changegroup file
1297 """create a changegroup file
1298
1298
1299 Generate a changegroup file collecting changesets to be added
1299 Generate a changegroup file collecting changesets to be added
1300 to a repository.
1300 to a repository.
1301
1301
1302 To create a bundle containing all changesets, use -a/--all
1302 To create a bundle containing all changesets, use -a/--all
1303 (or --base null). Otherwise, hg assumes the destination will have
1303 (or --base null). Otherwise, hg assumes the destination will have
1304 all the nodes you specify with --base parameters. Otherwise, hg
1304 all the nodes you specify with --base parameters. Otherwise, hg
1305 will assume the repository has all the nodes in destination, or
1305 will assume the repository has all the nodes in destination, or
1306 default-push/default if no destination is specified.
1306 default-push/default if no destination is specified.
1307
1307
1308 You can change bundle format with the -t/--type option. You can
1308 You can change bundle format with the -t/--type option. You can
1309 specify a compression, a bundle version or both using a dash
1309 specify a compression, a bundle version or both using a dash
1310 (comp-version). The available compression methods are: none, bzip2,
1310 (comp-version). The available compression methods are: none, bzip2,
1311 and gzip (by default, bundles are compressed using bzip2). The
1311 and gzip (by default, bundles are compressed using bzip2). The
1312 available formats are: v1, v2 (default to most suitable).
1312 available formats are: v1, v2 (default to most suitable).
1313
1313
1314 The bundle file can then be transferred using conventional means
1314 The bundle file can then be transferred using conventional means
1315 and applied to another repository with the unbundle or pull
1315 and applied to another repository with the unbundle or pull
1316 command. This is useful when direct push and pull are not
1316 command. This is useful when direct push and pull are not
1317 available or when exporting an entire repository is undesirable.
1317 available or when exporting an entire repository is undesirable.
1318
1318
1319 Applying bundles preserves all changeset contents including
1319 Applying bundles preserves all changeset contents including
1320 permissions, copy/rename information, and revision history.
1320 permissions, copy/rename information, and revision history.
1321
1321
1322 Returns 0 on success, 1 if no changes found.
1322 Returns 0 on success, 1 if no changes found.
1323 """
1323 """
1324 revs = None
1324 revs = None
1325 if 'rev' in opts:
1325 if 'rev' in opts:
1326 revstrings = opts['rev']
1326 revstrings = opts['rev']
1327 revs = scmutil.revrange(repo, revstrings)
1327 revs = scmutil.revrange(repo, revstrings)
1328 if revstrings and not revs:
1328 if revstrings and not revs:
1329 raise error.Abort(_('no commits to bundle'))
1329 raise error.Abort(_('no commits to bundle'))
1330
1330
1331 bundletype = opts.get('type', 'bzip2').lower()
1331 bundletype = opts.get('type', 'bzip2').lower()
1332 try:
1332 try:
1333 bcompression, cgversion, params = exchange.parsebundlespec(
1333 bcompression, cgversion, params = exchange.parsebundlespec(
1334 repo, bundletype, strict=False)
1334 repo, bundletype, strict=False)
1335 except error.UnsupportedBundleSpecification as e:
1335 except error.UnsupportedBundleSpecification as e:
1336 raise error.Abort(str(e),
1336 raise error.Abort(str(e),
1337 hint=_("see 'hg help bundle' for supported "
1337 hint=_("see 'hg help bundle' for supported "
1338 "values for --type"))
1338 "values for --type"))
1339
1339
1340 # Packed bundles are a pseudo bundle format for now.
1340 # Packed bundles are a pseudo bundle format for now.
1341 if cgversion == 's1':
1341 if cgversion == 's1':
1342 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1342 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1343 hint=_("use 'hg debugcreatestreamclonebundle'"))
1343 hint=_("use 'hg debugcreatestreamclonebundle'"))
1344
1344
1345 if opts.get('all'):
1345 if opts.get('all'):
1346 if dest:
1346 if dest:
1347 raise error.Abort(_("--all is incompatible with specifying "
1347 raise error.Abort(_("--all is incompatible with specifying "
1348 "a destination"))
1348 "a destination"))
1349 if opts.get('base'):
1349 if opts.get('base'):
1350 ui.warn(_("ignoring --base because --all was specified\n"))
1350 ui.warn(_("ignoring --base because --all was specified\n"))
1351 base = ['null']
1351 base = ['null']
1352 else:
1352 else:
1353 base = scmutil.revrange(repo, opts.get('base'))
1353 base = scmutil.revrange(repo, opts.get('base'))
1354 # TODO: get desired bundlecaps from command line.
1354 # TODO: get desired bundlecaps from command line.
1355 bundlecaps = None
1355 bundlecaps = None
1356 if cgversion not in changegroup.supportedoutgoingversions(repo):
1356 if cgversion not in changegroup.supportedoutgoingversions(repo):
1357 raise error.Abort(_("repository does not support bundle version %s") %
1357 raise error.Abort(_("repository does not support bundle version %s") %
1358 cgversion)
1358 cgversion)
1359
1359
1360 if base:
1360 if base:
1361 if dest:
1361 if dest:
1362 raise error.Abort(_("--base is incompatible with specifying "
1362 raise error.Abort(_("--base is incompatible with specifying "
1363 "a destination"))
1363 "a destination"))
1364 common = [repo.lookup(rev) for rev in base]
1364 common = [repo.lookup(rev) for rev in base]
1365 heads = revs and map(repo.lookup, revs) or None
1365 heads = revs and map(repo.lookup, revs) or None
1366 outgoing = discovery.outgoing(repo, common, heads)
1366 outgoing = discovery.outgoing(repo, common, heads)
1367 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1367 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1368 bundlecaps=bundlecaps,
1368 bundlecaps=bundlecaps,
1369 version=cgversion)
1369 version=cgversion)
1370 outgoing = None
1370 outgoing = None
1371 else:
1371 else:
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1374 other = hg.peer(repo, opts, dest)
1374 other = hg.peer(repo, opts, dest)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1376 heads = revs and map(repo.lookup, revs) or revs
1376 heads = revs and map(repo.lookup, revs) or revs
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1378 onlyheads=heads,
1378 onlyheads=heads,
1379 force=opts.get('force'),
1379 force=opts.get('force'),
1380 portable=True)
1380 portable=True)
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1382 bundlecaps, version=cgversion)
1382 bundlecaps, version=cgversion)
1383 if not cg:
1383 if not cg:
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1385 return 1
1385 return 1
1386
1386
1387 if cgversion == '01': #bundle1
1387 if cgversion == '01': #bundle1
1388 if bcompression is None:
1388 if bcompression is None:
1389 bcompression = 'UN'
1389 bcompression = 'UN'
1390 bversion = 'HG10' + bcompression
1390 bversion = 'HG10' + bcompression
1391 bcompression = None
1391 bcompression = None
1392 else:
1392 else:
1393 assert cgversion == '02'
1393 assert cgversion == '02'
1394 bversion = 'HG20'
1394 bversion = 'HG20'
1395
1395
1396 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1396 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1397
1397
1398 @command('cat',
1398 @command('cat',
1399 [('o', 'output', '',
1399 [('o', 'output', '',
1400 _('print output to file with formatted name'), _('FORMAT')),
1400 _('print output to file with formatted name'), _('FORMAT')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1403 ] + walkopts,
1403 ] + walkopts,
1404 _('[OPTION]... FILE...'),
1404 _('[OPTION]... FILE...'),
1405 inferrepo=True)
1405 inferrepo=True)
1406 def cat(ui, repo, file1, *pats, **opts):
1406 def cat(ui, repo, file1, *pats, **opts):
1407 """output the current or given revision of files
1407 """output the current or given revision of files
1408
1408
1409 Print the specified files as they were at the given revision. If
1409 Print the specified files as they were at the given revision. If
1410 no revision is given, the parent of the working directory is used.
1410 no revision is given, the parent of the working directory is used.
1411
1411
1412 Output may be to a file, in which case the name of the file is
1412 Output may be to a file, in which case the name of the file is
1413 given using a format string. The formatting rules as follows:
1413 given using a format string. The formatting rules as follows:
1414
1414
1415 :``%%``: literal "%" character
1415 :``%%``: literal "%" character
1416 :``%s``: basename of file being printed
1416 :``%s``: basename of file being printed
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%p``: root-relative path name of file being printed
1418 :``%p``: root-relative path name of file being printed
1419 :``%H``: changeset hash (40 hexadecimal digits)
1419 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%R``: changeset revision number
1420 :``%R``: changeset revision number
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%r``: zero-padded changeset revision number
1422 :``%r``: zero-padded changeset revision number
1423 :``%b``: basename of the exporting repository
1423 :``%b``: basename of the exporting repository
1424
1424
1425 Returns 0 on success.
1425 Returns 0 on success.
1426 """
1426 """
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1429
1429
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431
1431
1432 @command('^clone',
1432 @command('^clone',
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 'directory (only a repository)')),
1434 'directory (only a repository)')),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 _('REV')),
1436 _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ] + remoteopts,
1441 ] + remoteopts,
1442 _('[OPTION]... SOURCE [DEST]'),
1442 _('[OPTION]... SOURCE [DEST]'),
1443 norepo=True)
1443 norepo=True)
1444 def clone(ui, source, dest=None, **opts):
1444 def clone(ui, source, dest=None, **opts):
1445 """make a copy of an existing repository
1445 """make a copy of an existing repository
1446
1446
1447 Create a copy of an existing repository in a new directory.
1447 Create a copy of an existing repository in a new directory.
1448
1448
1449 If no destination directory name is specified, it defaults to the
1449 If no destination directory name is specified, it defaults to the
1450 basename of the source.
1450 basename of the source.
1451
1451
1452 The location of the source is added to the new repository's
1452 The location of the source is added to the new repository's
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1454
1454
1455 Only local paths and ``ssh://`` URLs are supported as
1455 Only local paths and ``ssh://`` URLs are supported as
1456 destinations. For ``ssh://`` destinations, no working directory or
1456 destinations. For ``ssh://`` destinations, no working directory or
1457 ``.hg/hgrc`` will be created on the remote side.
1457 ``.hg/hgrc`` will be created on the remote side.
1458
1458
1459 If the source repository has a bookmark called '@' set, that
1459 If the source repository has a bookmark called '@' set, that
1460 revision will be checked out in the new repository by default.
1460 revision will be checked out in the new repository by default.
1461
1461
1462 To check out a particular version, use -u/--update, or
1462 To check out a particular version, use -u/--update, or
1463 -U/--noupdate to create a clone with no working directory.
1463 -U/--noupdate to create a clone with no working directory.
1464
1464
1465 To pull only a subset of changesets, specify one or more revisions
1465 To pull only a subset of changesets, specify one or more revisions
1466 identifiers with -r/--rev or branches with -b/--branch. The
1466 identifiers with -r/--rev or branches with -b/--branch. The
1467 resulting clone will contain only the specified changesets and
1467 resulting clone will contain only the specified changesets and
1468 their ancestors. These options (or 'clone src#rev dest') imply
1468 their ancestors. These options (or 'clone src#rev dest') imply
1469 --pull, even for local source repositories.
1469 --pull, even for local source repositories.
1470
1470
1471 .. note::
1471 .. note::
1472
1472
1473 Specifying a tag will include the tagged changeset but not the
1473 Specifying a tag will include the tagged changeset but not the
1474 changeset containing the tag.
1474 changeset containing the tag.
1475
1475
1476 .. container:: verbose
1476 .. container:: verbose
1477
1477
1478 For efficiency, hardlinks are used for cloning whenever the
1478 For efficiency, hardlinks are used for cloning whenever the
1479 source and destination are on the same filesystem (note this
1479 source and destination are on the same filesystem (note this
1480 applies only to the repository data, not to the working
1480 applies only to the repository data, not to the working
1481 directory). Some filesystems, such as AFS, implement hardlinking
1481 directory). Some filesystems, such as AFS, implement hardlinking
1482 incorrectly, but do not report errors. In these cases, use the
1482 incorrectly, but do not report errors. In these cases, use the
1483 --pull option to avoid hardlinking.
1483 --pull option to avoid hardlinking.
1484
1484
1485 In some cases, you can clone repositories and the working
1485 In some cases, you can clone repositories and the working
1486 directory using full hardlinks with ::
1486 directory using full hardlinks with ::
1487
1487
1488 $ cp -al REPO REPOCLONE
1488 $ cp -al REPO REPOCLONE
1489
1489
1490 This is the fastest way to clone, but it is not always safe. The
1490 This is the fastest way to clone, but it is not always safe. The
1491 operation is not atomic (making sure REPO is not modified during
1491 operation is not atomic (making sure REPO is not modified during
1492 the operation is up to you) and you have to make sure your
1492 the operation is up to you) and you have to make sure your
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 so). Also, this is not compatible with certain extensions that
1494 so). Also, this is not compatible with certain extensions that
1495 place their metadata under the .hg directory, such as mq.
1495 place their metadata under the .hg directory, such as mq.
1496
1496
1497 Mercurial will update the working directory to the first applicable
1497 Mercurial will update the working directory to the first applicable
1498 revision from this list:
1498 revision from this list:
1499
1499
1500 a) null if -U or the source repository has no changesets
1500 a) null if -U or the source repository has no changesets
1501 b) if -u . and the source repository is local, the first parent of
1501 b) if -u . and the source repository is local, the first parent of
1502 the source repository's working directory
1502 the source repository's working directory
1503 c) the changeset specified with -u (if a branch name, this means the
1503 c) the changeset specified with -u (if a branch name, this means the
1504 latest head of that branch)
1504 latest head of that branch)
1505 d) the changeset specified with -r
1505 d) the changeset specified with -r
1506 e) the tipmost head specified with -b
1506 e) the tipmost head specified with -b
1507 f) the tipmost head specified with the url#branch source syntax
1507 f) the tipmost head specified with the url#branch source syntax
1508 g) the revision marked with the '@' bookmark, if present
1508 g) the revision marked with the '@' bookmark, if present
1509 h) the tipmost head of the default branch
1509 h) the tipmost head of the default branch
1510 i) tip
1510 i) tip
1511
1511
1512 When cloning from servers that support it, Mercurial may fetch
1512 When cloning from servers that support it, Mercurial may fetch
1513 pre-generated data from a server-advertised URL. When this is done,
1513 pre-generated data from a server-advertised URL. When this is done,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1515 once for the bundle fetched from the URL and another for any additional
1515 once for the bundle fetched from the URL and another for any additional
1516 data not fetched from this URL. In addition, if an error occurs, the
1516 data not fetched from this URL. In addition, if an error occurs, the
1517 repository may be rolled back to a partial clone. This behavior may
1517 repository may be rolled back to a partial clone. This behavior may
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1519
1519
1520 Examples:
1520 Examples:
1521
1521
1522 - clone a remote repository to a new directory named hg/::
1522 - clone a remote repository to a new directory named hg/::
1523
1523
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1525
1525
1526 - create a lightweight local clone::
1526 - create a lightweight local clone::
1527
1527
1528 hg clone project/ project-feature/
1528 hg clone project/ project-feature/
1529
1529
1530 - clone from an absolute path on an ssh server (note double-slash)::
1530 - clone from an absolute path on an ssh server (note double-slash)::
1531
1531
1532 hg clone ssh://user@server//home/projects/alpha/
1532 hg clone ssh://user@server//home/projects/alpha/
1533
1533
1534 - do a high-speed clone over a LAN while checking out a
1534 - do a high-speed clone over a LAN while checking out a
1535 specified version::
1535 specified version::
1536
1536
1537 hg clone --uncompressed http://server/repo -u 1.5
1537 hg clone --uncompressed http://server/repo -u 1.5
1538
1538
1539 - create a repository without changesets after a particular revision::
1539 - create a repository without changesets after a particular revision::
1540
1540
1541 hg clone -r 04e544 experimental/ good/
1541 hg clone -r 04e544 experimental/ good/
1542
1542
1543 - clone (and track) a particular named branch::
1543 - clone (and track) a particular named branch::
1544
1544
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1546
1546
1547 See :hg:`help urls` for details on specifying URLs.
1547 See :hg:`help urls` for details on specifying URLs.
1548
1548
1549 Returns 0 on success.
1549 Returns 0 on success.
1550 """
1550 """
1551 if opts.get('noupdate') and opts.get('updaterev'):
1551 if opts.get('noupdate') and opts.get('updaterev'):
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1553
1553
1554 r = hg.clone(ui, opts, source, dest,
1554 r = hg.clone(ui, opts, source, dest,
1555 pull=opts.get('pull'),
1555 pull=opts.get('pull'),
1556 stream=opts.get('uncompressed'),
1556 stream=opts.get('uncompressed'),
1557 rev=opts.get('rev'),
1557 rev=opts.get('rev'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1559 branch=opts.get('branch'),
1559 branch=opts.get('branch'),
1560 shareopts=opts.get('shareopts'))
1560 shareopts=opts.get('shareopts'))
1561
1561
1562 return r is None
1562 return r is None
1563
1563
1564 @command('^commit|ci',
1564 @command('^commit|ci',
1565 [('A', 'addremove', None,
1565 [('A', 'addremove', None,
1566 _('mark new/missing files as added/removed before committing')),
1566 _('mark new/missing files as added/removed before committing')),
1567 ('', 'close-branch', None,
1567 ('', 'close-branch', None,
1568 _('mark a branch head as closed')),
1568 _('mark a branch head as closed')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1574 _('[OPTION]... [FILE]...'),
1574 _('[OPTION]... [FILE]...'),
1575 inferrepo=True)
1575 inferrepo=True)
1576 def commit(ui, repo, *pats, **opts):
1576 def commit(ui, repo, *pats, **opts):
1577 """commit the specified files or all outstanding changes
1577 """commit the specified files or all outstanding changes
1578
1578
1579 Commit changes to the given files into the repository. Unlike a
1579 Commit changes to the given files into the repository. Unlike a
1580 centralized SCM, this operation is a local operation. See
1580 centralized SCM, this operation is a local operation. See
1581 :hg:`push` for a way to actively distribute your changes.
1581 :hg:`push` for a way to actively distribute your changes.
1582
1582
1583 If a list of files is omitted, all changes reported by :hg:`status`
1583 If a list of files is omitted, all changes reported by :hg:`status`
1584 will be committed.
1584 will be committed.
1585
1585
1586 If you are committing the result of a merge, do not provide any
1586 If you are committing the result of a merge, do not provide any
1587 filenames or -I/-X filters.
1587 filenames or -I/-X filters.
1588
1588
1589 If no commit message is specified, Mercurial starts your
1589 If no commit message is specified, Mercurial starts your
1590 configured editor where you can enter a message. In case your
1590 configured editor where you can enter a message. In case your
1591 commit fails, you will find a backup of your message in
1591 commit fails, you will find a backup of your message in
1592 ``.hg/last-message.txt``.
1592 ``.hg/last-message.txt``.
1593
1593
1594 The --close-branch flag can be used to mark the current branch
1594 The --close-branch flag can be used to mark the current branch
1595 head closed. When all heads of a branch are closed, the branch
1595 head closed. When all heads of a branch are closed, the branch
1596 will be considered closed and no longer listed.
1596 will be considered closed and no longer listed.
1597
1597
1598 The --amend flag can be used to amend the parent of the
1598 The --amend flag can be used to amend the parent of the
1599 working directory with a new commit that contains the changes
1599 working directory with a new commit that contains the changes
1600 in the parent in addition to those currently reported by :hg:`status`,
1600 in the parent in addition to those currently reported by :hg:`status`,
1601 if there are any. The old commit is stored in a backup bundle in
1601 if there are any. The old commit is stored in a backup bundle in
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 on how to restore it).
1603 on how to restore it).
1604
1604
1605 Message, user and date are taken from the amended commit unless
1605 Message, user and date are taken from the amended commit unless
1606 specified. When a message isn't specified on the command line,
1606 specified. When a message isn't specified on the command line,
1607 the editor will open with the message of the amended commit.
1607 the editor will open with the message of the amended commit.
1608
1608
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1610 or changesets that have children.
1610 or changesets that have children.
1611
1611
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1613
1613
1614 Returns 0 on success, 1 if nothing changed.
1614 Returns 0 on success, 1 if nothing changed.
1615
1615
1616 .. container:: verbose
1616 .. container:: verbose
1617
1617
1618 Examples:
1618 Examples:
1619
1619
1620 - commit all files ending in .py::
1620 - commit all files ending in .py::
1621
1621
1622 hg commit --include "set:**.py"
1622 hg commit --include "set:**.py"
1623
1623
1624 - commit all non-binary files::
1624 - commit all non-binary files::
1625
1625
1626 hg commit --exclude "set:binary()"
1626 hg commit --exclude "set:binary()"
1627
1627
1628 - amend the current commit and set the date to now::
1628 - amend the current commit and set the date to now::
1629
1629
1630 hg commit --amend --date now
1630 hg commit --amend --date now
1631 """
1631 """
1632 wlock = lock = None
1632 wlock = lock = None
1633 try:
1633 try:
1634 wlock = repo.wlock()
1634 wlock = repo.wlock()
1635 lock = repo.lock()
1635 lock = repo.lock()
1636 return _docommit(ui, repo, *pats, **opts)
1636 return _docommit(ui, repo, *pats, **opts)
1637 finally:
1637 finally:
1638 release(lock, wlock)
1638 release(lock, wlock)
1639
1639
1640 def _docommit(ui, repo, *pats, **opts):
1640 def _docommit(ui, repo, *pats, **opts):
1641 if opts.get('interactive'):
1641 if opts.get('interactive'):
1642 opts.pop('interactive')
1642 opts.pop('interactive')
1643 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1643 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1644 cmdutil.recordfilter, *pats, **opts)
1644 cmdutil.recordfilter, *pats, **opts)
1645 # ret can be 0 (no changes to record) or the value returned by
1645 # ret can be 0 (no changes to record) or the value returned by
1646 # commit(), 1 if nothing changed or None on success.
1646 # commit(), 1 if nothing changed or None on success.
1647 return 1 if ret == 0 else ret
1647 return 1 if ret == 0 else ret
1648
1648
1649 if opts.get('subrepos'):
1649 if opts.get('subrepos'):
1650 if opts.get('amend'):
1650 if opts.get('amend'):
1651 raise error.Abort(_('cannot amend with --subrepos'))
1651 raise error.Abort(_('cannot amend with --subrepos'))
1652 # Let --subrepos on the command line override config setting.
1652 # Let --subrepos on the command line override config setting.
1653 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1653 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1654
1654
1655 cmdutil.checkunfinished(repo, commit=True)
1655 cmdutil.checkunfinished(repo, commit=True)
1656
1656
1657 branch = repo[None].branch()
1657 branch = repo[None].branch()
1658 bheads = repo.branchheads(branch)
1658 bheads = repo.branchheads(branch)
1659
1659
1660 extra = {}
1660 extra = {}
1661 if opts.get('close_branch'):
1661 if opts.get('close_branch'):
1662 extra['close'] = 1
1662 extra['close'] = 1
1663
1663
1664 if not bheads:
1664 if not bheads:
1665 raise error.Abort(_('can only close branch heads'))
1665 raise error.Abort(_('can only close branch heads'))
1666 elif opts.get('amend'):
1666 elif opts.get('amend'):
1667 if repo[None].parents()[0].p1().branch() != branch and \
1667 if repo[None].parents()[0].p1().branch() != branch and \
1668 repo[None].parents()[0].p2().branch() != branch:
1668 repo[None].parents()[0].p2().branch() != branch:
1669 raise error.Abort(_('can only close branch heads'))
1669 raise error.Abort(_('can only close branch heads'))
1670
1670
1671 if opts.get('amend'):
1671 if opts.get('amend'):
1672 if ui.configbool('ui', 'commitsubrepos'):
1672 if ui.configbool('ui', 'commitsubrepos'):
1673 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1673 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1674
1674
1675 old = repo['.']
1675 old = repo['.']
1676 if not old.mutable():
1676 if not old.mutable():
1677 raise error.Abort(_('cannot amend public changesets'))
1677 raise error.Abort(_('cannot amend public changesets'))
1678 if len(repo[None].parents()) > 1:
1678 if len(repo[None].parents()) > 1:
1679 raise error.Abort(_('cannot amend while merging'))
1679 raise error.Abort(_('cannot amend while merging'))
1680 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1680 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1681 if not allowunstable and old.children():
1681 if not allowunstable and old.children():
1682 raise error.Abort(_('cannot amend changeset with children'))
1682 raise error.Abort(_('cannot amend changeset with children'))
1683
1683
1684 # Currently histedit gets confused if an amend happens while histedit
1684 # Currently histedit gets confused if an amend happens while histedit
1685 # is in progress. Since we have a checkunfinished command, we are
1685 # is in progress. Since we have a checkunfinished command, we are
1686 # temporarily honoring it.
1686 # temporarily honoring it.
1687 #
1687 #
1688 # Note: eventually this guard will be removed. Please do not expect
1688 # Note: eventually this guard will be removed. Please do not expect
1689 # this behavior to remain.
1689 # this behavior to remain.
1690 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1690 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1691 cmdutil.checkunfinished(repo)
1691 cmdutil.checkunfinished(repo)
1692
1692
1693 # commitfunc is used only for temporary amend commit by cmdutil.amend
1693 # commitfunc is used only for temporary amend commit by cmdutil.amend
1694 def commitfunc(ui, repo, message, match, opts):
1694 def commitfunc(ui, repo, message, match, opts):
1695 return repo.commit(message,
1695 return repo.commit(message,
1696 opts.get('user') or old.user(),
1696 opts.get('user') or old.user(),
1697 opts.get('date') or old.date(),
1697 opts.get('date') or old.date(),
1698 match,
1698 match,
1699 extra=extra)
1699 extra=extra)
1700
1700
1701 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1701 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1702 if node == old.node():
1702 if node == old.node():
1703 ui.status(_("nothing changed\n"))
1703 ui.status(_("nothing changed\n"))
1704 return 1
1704 return 1
1705 else:
1705 else:
1706 def commitfunc(ui, repo, message, match, opts):
1706 def commitfunc(ui, repo, message, match, opts):
1707 backup = ui.backupconfig('phases', 'new-commit')
1707 backup = ui.backupconfig('phases', 'new-commit')
1708 baseui = repo.baseui
1708 baseui = repo.baseui
1709 basebackup = baseui.backupconfig('phases', 'new-commit')
1709 basebackup = baseui.backupconfig('phases', 'new-commit')
1710 try:
1710 try:
1711 if opts.get('secret'):
1711 if opts.get('secret'):
1712 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1712 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1713 # Propagate to subrepos
1713 # Propagate to subrepos
1714 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1714 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1715
1715
1716 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1716 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1717 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1717 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1718 return repo.commit(message, opts.get('user'), opts.get('date'),
1718 return repo.commit(message, opts.get('user'), opts.get('date'),
1719 match,
1719 match,
1720 editor=editor,
1720 editor=editor,
1721 extra=extra)
1721 extra=extra)
1722 finally:
1722 finally:
1723 ui.restoreconfig(backup)
1723 ui.restoreconfig(backup)
1724 repo.baseui.restoreconfig(basebackup)
1724 repo.baseui.restoreconfig(basebackup)
1725
1725
1726
1726
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1728
1728
1729 if not node:
1729 if not node:
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1731 if stat[3]:
1731 if stat[3]:
1732 ui.status(_("nothing changed (%d missing files, see "
1732 ui.status(_("nothing changed (%d missing files, see "
1733 "'hg status')\n") % len(stat[3]))
1733 "'hg status')\n") % len(stat[3]))
1734 else:
1734 else:
1735 ui.status(_("nothing changed\n"))
1735 ui.status(_("nothing changed\n"))
1736 return 1
1736 return 1
1737
1737
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1739
1739
1740 @command('config|showconfig|debugconfig',
1740 @command('config|showconfig|debugconfig',
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1742 ('e', 'edit', None, _('edit user config')),
1742 ('e', 'edit', None, _('edit user config')),
1743 ('l', 'local', None, _('edit repository config')),
1743 ('l', 'local', None, _('edit repository config')),
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1745 _('[-u] [NAME]...'),
1745 _('[-u] [NAME]...'),
1746 optionalrepo=True)
1746 optionalrepo=True)
1747 def config(ui, repo, *values, **opts):
1747 def config(ui, repo, *values, **opts):
1748 """show combined config settings from all hgrc files
1748 """show combined config settings from all hgrc files
1749
1749
1750 With no arguments, print names and values of all config items.
1750 With no arguments, print names and values of all config items.
1751
1751
1752 With one argument of the form section.name, print just the value
1752 With one argument of the form section.name, print just the value
1753 of that config item.
1753 of that config item.
1754
1754
1755 With multiple arguments, print names and values of all config
1755 With multiple arguments, print names and values of all config
1756 items with matching section names.
1756 items with matching section names.
1757
1757
1758 With --edit, start an editor on the user-level config file. With
1758 With --edit, start an editor on the user-level config file. With
1759 --global, edit the system-wide config file. With --local, edit the
1759 --global, edit the system-wide config file. With --local, edit the
1760 repository-level config file.
1760 repository-level config file.
1761
1761
1762 With --debug, the source (filename and line number) is printed
1762 With --debug, the source (filename and line number) is printed
1763 for each config item.
1763 for each config item.
1764
1764
1765 See :hg:`help config` for more information about config files.
1765 See :hg:`help config` for more information about config files.
1766
1766
1767 Returns 0 on success, 1 if NAME does not exist.
1767 Returns 0 on success, 1 if NAME does not exist.
1768
1768
1769 """
1769 """
1770
1770
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1773 raise error.Abort(_("can't use --local and --global together"))
1773 raise error.Abort(_("can't use --local and --global together"))
1774
1774
1775 if opts.get('local'):
1775 if opts.get('local'):
1776 if not repo:
1776 if not repo:
1777 raise error.Abort(_("can't use --local outside a repository"))
1777 raise error.Abort(_("can't use --local outside a repository"))
1778 paths = [repo.join('hgrc')]
1778 paths = [repo.join('hgrc')]
1779 elif opts.get('global'):
1779 elif opts.get('global'):
1780 paths = scmutil.systemrcpath()
1780 paths = scmutil.systemrcpath()
1781 else:
1781 else:
1782 paths = scmutil.userrcpath()
1782 paths = scmutil.userrcpath()
1783
1783
1784 for f in paths:
1784 for f in paths:
1785 if os.path.exists(f):
1785 if os.path.exists(f):
1786 break
1786 break
1787 else:
1787 else:
1788 if opts.get('global'):
1788 if opts.get('global'):
1789 samplehgrc = uimod.samplehgrcs['global']
1789 samplehgrc = uimod.samplehgrcs['global']
1790 elif opts.get('local'):
1790 elif opts.get('local'):
1791 samplehgrc = uimod.samplehgrcs['local']
1791 samplehgrc = uimod.samplehgrcs['local']
1792 else:
1792 else:
1793 samplehgrc = uimod.samplehgrcs['user']
1793 samplehgrc = uimod.samplehgrcs['user']
1794
1794
1795 f = paths[0]
1795 f = paths[0]
1796 fp = open(f, "w")
1796 fp = open(f, "w")
1797 fp.write(samplehgrc)
1797 fp.write(samplehgrc)
1798 fp.close()
1798 fp.close()
1799
1799
1800 editor = ui.geteditor()
1800 editor = ui.geteditor()
1801 ui.system("%s \"%s\"" % (editor, f),
1801 ui.system("%s \"%s\"" % (editor, f),
1802 onerr=error.Abort, errprefix=_("edit failed"))
1802 onerr=error.Abort, errprefix=_("edit failed"))
1803 return
1803 return
1804
1804
1805 fm = ui.formatter('config', opts)
1805 fm = ui.formatter('config', opts)
1806 for f in scmutil.rcpath():
1806 for f in scmutil.rcpath():
1807 ui.debug('read config from: %s\n' % f)
1807 ui.debug('read config from: %s\n' % f)
1808 untrusted = bool(opts.get('untrusted'))
1808 untrusted = bool(opts.get('untrusted'))
1809 if values:
1809 if values:
1810 sections = [v for v in values if '.' not in v]
1810 sections = [v for v in values if '.' not in v]
1811 items = [v for v in values if '.' in v]
1811 items = [v for v in values if '.' in v]
1812 if len(items) > 1 or items and sections:
1812 if len(items) > 1 or items and sections:
1813 raise error.Abort(_('only one config item permitted'))
1813 raise error.Abort(_('only one config item permitted'))
1814 matched = False
1814 matched = False
1815 for section, name, value in ui.walkconfig(untrusted=untrusted):
1815 for section, name, value in ui.walkconfig(untrusted=untrusted):
1816 value = str(value)
1816 value = str(value)
1817 if fm.isplain():
1817 if fm.isplain():
1818 value = value.replace('\n', '\\n')
1818 value = value.replace('\n', '\\n')
1819 entryname = section + '.' + name
1819 entryname = section + '.' + name
1820 if values:
1820 if values:
1821 for v in values:
1821 for v in values:
1822 if v == section:
1822 if v == section:
1823 fm.startitem()
1823 fm.startitem()
1824 fm.condwrite(ui.debugflag, 'source', '%s: ',
1824 fm.condwrite(ui.debugflag, 'source', '%s: ',
1825 ui.configsource(section, name, untrusted))
1825 ui.configsource(section, name, untrusted))
1826 fm.write('name value', '%s=%s\n', entryname, value)
1826 fm.write('name value', '%s=%s\n', entryname, value)
1827 matched = True
1827 matched = True
1828 elif v == entryname:
1828 elif v == entryname:
1829 fm.startitem()
1829 fm.startitem()
1830 fm.condwrite(ui.debugflag, 'source', '%s: ',
1830 fm.condwrite(ui.debugflag, 'source', '%s: ',
1831 ui.configsource(section, name, untrusted))
1831 ui.configsource(section, name, untrusted))
1832 fm.write('value', '%s\n', value)
1832 fm.write('value', '%s\n', value)
1833 fm.data(name=entryname)
1833 fm.data(name=entryname)
1834 matched = True
1834 matched = True
1835 else:
1835 else:
1836 fm.startitem()
1836 fm.startitem()
1837 fm.condwrite(ui.debugflag, 'source', '%s: ',
1837 fm.condwrite(ui.debugflag, 'source', '%s: ',
1838 ui.configsource(section, name, untrusted))
1838 ui.configsource(section, name, untrusted))
1839 fm.write('name value', '%s=%s\n', entryname, value)
1839 fm.write('name value', '%s=%s\n', entryname, value)
1840 matched = True
1840 matched = True
1841 fm.end()
1841 fm.end()
1842 if matched:
1842 if matched:
1843 return 0
1843 return 0
1844 return 1
1844 return 1
1845
1845
1846 @command('copy|cp',
1846 @command('copy|cp',
1847 [('A', 'after', None, _('record a copy that has already occurred')),
1847 [('A', 'after', None, _('record a copy that has already occurred')),
1848 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1848 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1849 ] + walkopts + dryrunopts,
1849 ] + walkopts + dryrunopts,
1850 _('[OPTION]... [SOURCE]... DEST'))
1850 _('[OPTION]... [SOURCE]... DEST'))
1851 def copy(ui, repo, *pats, **opts):
1851 def copy(ui, repo, *pats, **opts):
1852 """mark files as copied for the next commit
1852 """mark files as copied for the next commit
1853
1853
1854 Mark dest as having copies of source files. If dest is a
1854 Mark dest as having copies of source files. If dest is a
1855 directory, copies are put in that directory. If dest is a file,
1855 directory, copies are put in that directory. If dest is a file,
1856 the source must be a single file.
1856 the source must be a single file.
1857
1857
1858 By default, this command copies the contents of files as they
1858 By default, this command copies the contents of files as they
1859 exist in the working directory. If invoked with -A/--after, the
1859 exist in the working directory. If invoked with -A/--after, the
1860 operation is recorded, but no copying is performed.
1860 operation is recorded, but no copying is performed.
1861
1861
1862 This command takes effect with the next commit. To undo a copy
1862 This command takes effect with the next commit. To undo a copy
1863 before that, see :hg:`revert`.
1863 before that, see :hg:`revert`.
1864
1864
1865 Returns 0 on success, 1 if errors are encountered.
1865 Returns 0 on success, 1 if errors are encountered.
1866 """
1866 """
1867 with repo.wlock(False):
1867 with repo.wlock(False):
1868 return cmdutil.copy(ui, repo, pats, opts)
1868 return cmdutil.copy(ui, repo, pats, opts)
1869
1869
1870 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1871 def debugcommands(ui, cmd='', *args):
1872 """list all available commands and options"""
1873 for cmd, vals in sorted(table.iteritems()):
1874 cmd = cmd.split('|')[0].strip('^')
1875 opts = ', '.join([i[1] for i in vals[1]])
1876 ui.write('%s: %s\n' % (cmd, opts))
1877
1878 @command('debugcomplete',
1870 @command('debugcomplete',
1879 [('o', 'options', None, _('show the command options'))],
1871 [('o', 'options', None, _('show the command options'))],
1880 _('[-o] CMD'),
1872 _('[-o] CMD'),
1881 norepo=True)
1873 norepo=True)
1882 def debugcomplete(ui, cmd='', **opts):
1874 def debugcomplete(ui, cmd='', **opts):
1883 """returns the completion list associated with the given command"""
1875 """returns the completion list associated with the given command"""
1884
1876
1885 if opts.get('options'):
1877 if opts.get('options'):
1886 options = []
1878 options = []
1887 otables = [globalopts]
1879 otables = [globalopts]
1888 if cmd:
1880 if cmd:
1889 aliases, entry = cmdutil.findcmd(cmd, table, False)
1881 aliases, entry = cmdutil.findcmd(cmd, table, False)
1890 otables.append(entry[1])
1882 otables.append(entry[1])
1891 for t in otables:
1883 for t in otables:
1892 for o in t:
1884 for o in t:
1893 if "(DEPRECATED)" in o[3]:
1885 if "(DEPRECATED)" in o[3]:
1894 continue
1886 continue
1895 if o[0]:
1887 if o[0]:
1896 options.append('-%s' % o[0])
1888 options.append('-%s' % o[0])
1897 options.append('--%s' % o[1])
1889 options.append('--%s' % o[1])
1898 ui.write("%s\n" % "\n".join(options))
1890 ui.write("%s\n" % "\n".join(options))
1899 return
1891 return
1900
1892
1901 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1893 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1902 if ui.verbose:
1894 if ui.verbose:
1903 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1895 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1904 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1896 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1905
1897
1906 @command('debugdag',
1898 @command('debugdag',
1907 [('t', 'tags', None, _('use tags as labels')),
1899 [('t', 'tags', None, _('use tags as labels')),
1908 ('b', 'branches', None, _('annotate with branch names')),
1900 ('b', 'branches', None, _('annotate with branch names')),
1909 ('', 'dots', None, _('use dots for runs')),
1901 ('', 'dots', None, _('use dots for runs')),
1910 ('s', 'spaces', None, _('separate elements by spaces'))],
1902 ('s', 'spaces', None, _('separate elements by spaces'))],
1911 _('[OPTION]... [FILE [REV]...]'),
1903 _('[OPTION]... [FILE [REV]...]'),
1912 optionalrepo=True)
1904 optionalrepo=True)
1913 def debugdag(ui, repo, file_=None, *revs, **opts):
1905 def debugdag(ui, repo, file_=None, *revs, **opts):
1914 """format the changelog or an index DAG as a concise textual description
1906 """format the changelog or an index DAG as a concise textual description
1915
1907
1916 If you pass a revlog index, the revlog's DAG is emitted. If you list
1908 If you pass a revlog index, the revlog's DAG is emitted. If you list
1917 revision numbers, they get labeled in the output as rN.
1909 revision numbers, they get labeled in the output as rN.
1918
1910
1919 Otherwise, the changelog DAG of the current repo is emitted.
1911 Otherwise, the changelog DAG of the current repo is emitted.
1920 """
1912 """
1921 spaces = opts.get('spaces')
1913 spaces = opts.get('spaces')
1922 dots = opts.get('dots')
1914 dots = opts.get('dots')
1923 if file_:
1915 if file_:
1924 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1916 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1925 revs = set((int(r) for r in revs))
1917 revs = set((int(r) for r in revs))
1926 def events():
1918 def events():
1927 for r in rlog:
1919 for r in rlog:
1928 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1920 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1929 if p != -1))
1921 if p != -1))
1930 if r in revs:
1922 if r in revs:
1931 yield 'l', (r, "r%i" % r)
1923 yield 'l', (r, "r%i" % r)
1932 elif repo:
1924 elif repo:
1933 cl = repo.changelog
1925 cl = repo.changelog
1934 tags = opts.get('tags')
1926 tags = opts.get('tags')
1935 branches = opts.get('branches')
1927 branches = opts.get('branches')
1936 if tags:
1928 if tags:
1937 labels = {}
1929 labels = {}
1938 for l, n in repo.tags().items():
1930 for l, n in repo.tags().items():
1939 labels.setdefault(cl.rev(n), []).append(l)
1931 labels.setdefault(cl.rev(n), []).append(l)
1940 def events():
1932 def events():
1941 b = "default"
1933 b = "default"
1942 for r in cl:
1934 for r in cl:
1943 if branches:
1935 if branches:
1944 newb = cl.read(cl.node(r))[5]['branch']
1936 newb = cl.read(cl.node(r))[5]['branch']
1945 if newb != b:
1937 if newb != b:
1946 yield 'a', newb
1938 yield 'a', newb
1947 b = newb
1939 b = newb
1948 yield 'n', (r, list(p for p in cl.parentrevs(r)
1940 yield 'n', (r, list(p for p in cl.parentrevs(r)
1949 if p != -1))
1941 if p != -1))
1950 if tags:
1942 if tags:
1951 ls = labels.get(r)
1943 ls = labels.get(r)
1952 if ls:
1944 if ls:
1953 for l in ls:
1945 for l in ls:
1954 yield 'l', (r, l)
1946 yield 'l', (r, l)
1955 else:
1947 else:
1956 raise error.Abort(_('need repo for changelog dag'))
1948 raise error.Abort(_('need repo for changelog dag'))
1957
1949
1958 for line in dagparser.dagtextlines(events(),
1950 for line in dagparser.dagtextlines(events(),
1959 addspaces=spaces,
1951 addspaces=spaces,
1960 wraplabels=True,
1952 wraplabels=True,
1961 wrapannotations=True,
1953 wrapannotations=True,
1962 wrapnonlinear=dots,
1954 wrapnonlinear=dots,
1963 usedots=dots,
1955 usedots=dots,
1964 maxlinewidth=70):
1956 maxlinewidth=70):
1965 ui.write(line)
1957 ui.write(line)
1966 ui.write("\n")
1958 ui.write("\n")
1967
1959
1968 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1960 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1969 def debugdata(ui, repo, file_, rev=None, **opts):
1961 def debugdata(ui, repo, file_, rev=None, **opts):
1970 """dump the contents of a data file revision"""
1962 """dump the contents of a data file revision"""
1971 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
1963 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
1972 if rev is not None:
1964 if rev is not None:
1973 raise error.CommandError('debugdata', _('invalid arguments'))
1965 raise error.CommandError('debugdata', _('invalid arguments'))
1974 file_, rev = None, file_
1966 file_, rev = None, file_
1975 elif rev is None:
1967 elif rev is None:
1976 raise error.CommandError('debugdata', _('invalid arguments'))
1968 raise error.CommandError('debugdata', _('invalid arguments'))
1977 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1969 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1978 try:
1970 try:
1979 ui.write(r.revision(r.lookup(rev)))
1971 ui.write(r.revision(r.lookup(rev)))
1980 except KeyError:
1972 except KeyError:
1981 raise error.Abort(_('invalid revision identifier %s') % rev)
1973 raise error.Abort(_('invalid revision identifier %s') % rev)
1982
1974
1983 @command('debugdate',
1975 @command('debugdate',
1984 [('e', 'extended', None, _('try extended date formats'))],
1976 [('e', 'extended', None, _('try extended date formats'))],
1985 _('[-e] DATE [RANGE]'),
1977 _('[-e] DATE [RANGE]'),
1986 norepo=True, optionalrepo=True)
1978 norepo=True, optionalrepo=True)
1987 def debugdate(ui, date, range=None, **opts):
1979 def debugdate(ui, date, range=None, **opts):
1988 """parse and display a date"""
1980 """parse and display a date"""
1989 if opts["extended"]:
1981 if opts["extended"]:
1990 d = util.parsedate(date, util.extendeddateformats)
1982 d = util.parsedate(date, util.extendeddateformats)
1991 else:
1983 else:
1992 d = util.parsedate(date)
1984 d = util.parsedate(date)
1993 ui.write(("internal: %s %s\n") % d)
1985 ui.write(("internal: %s %s\n") % d)
1994 ui.write(("standard: %s\n") % util.datestr(d))
1986 ui.write(("standard: %s\n") % util.datestr(d))
1995 if range:
1987 if range:
1996 m = util.matchdate(range)
1988 m = util.matchdate(range)
1997 ui.write(("match: %s\n") % m(d[0]))
1989 ui.write(("match: %s\n") % m(d[0]))
1998
1990
1999 @command('debugdiscovery',
1991 @command('debugdiscovery',
2000 [('', 'old', None, _('use old-style discovery')),
1992 [('', 'old', None, _('use old-style discovery')),
2001 ('', 'nonheads', None,
1993 ('', 'nonheads', None,
2002 _('use old-style discovery with non-heads included')),
1994 _('use old-style discovery with non-heads included')),
2003 ] + remoteopts,
1995 ] + remoteopts,
2004 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1996 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2005 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1997 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2006 """runs the changeset discovery protocol in isolation"""
1998 """runs the changeset discovery protocol in isolation"""
2007 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1999 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2008 opts.get('branch'))
2000 opts.get('branch'))
2009 remote = hg.peer(repo, opts, remoteurl)
2001 remote = hg.peer(repo, opts, remoteurl)
2010 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2002 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2011
2003
2012 # make sure tests are repeatable
2004 # make sure tests are repeatable
2013 random.seed(12323)
2005 random.seed(12323)
2014
2006
2015 def doit(localheads, remoteheads, remote=remote):
2007 def doit(localheads, remoteheads, remote=remote):
2016 if opts.get('old'):
2008 if opts.get('old'):
2017 if localheads:
2009 if localheads:
2018 raise error.Abort('cannot use localheads with old style '
2010 raise error.Abort('cannot use localheads with old style '
2019 'discovery')
2011 'discovery')
2020 if not util.safehasattr(remote, 'branches'):
2012 if not util.safehasattr(remote, 'branches'):
2021 # enable in-client legacy support
2013 # enable in-client legacy support
2022 remote = localrepo.locallegacypeer(remote.local())
2014 remote = localrepo.locallegacypeer(remote.local())
2023 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2015 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2024 force=True)
2016 force=True)
2025 common = set(common)
2017 common = set(common)
2026 if not opts.get('nonheads'):
2018 if not opts.get('nonheads'):
2027 ui.write(("unpruned common: %s\n") %
2019 ui.write(("unpruned common: %s\n") %
2028 " ".join(sorted(short(n) for n in common)))
2020 " ".join(sorted(short(n) for n in common)))
2029 dag = dagutil.revlogdag(repo.changelog)
2021 dag = dagutil.revlogdag(repo.changelog)
2030 all = dag.ancestorset(dag.internalizeall(common))
2022 all = dag.ancestorset(dag.internalizeall(common))
2031 common = dag.externalizeall(dag.headsetofconnecteds(all))
2023 common = dag.externalizeall(dag.headsetofconnecteds(all))
2032 else:
2024 else:
2033 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2025 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2034 common = set(common)
2026 common = set(common)
2035 rheads = set(hds)
2027 rheads = set(hds)
2036 lheads = set(repo.heads())
2028 lheads = set(repo.heads())
2037 ui.write(("common heads: %s\n") %
2029 ui.write(("common heads: %s\n") %
2038 " ".join(sorted(short(n) for n in common)))
2030 " ".join(sorted(short(n) for n in common)))
2039 if lheads <= common:
2031 if lheads <= common:
2040 ui.write(("local is subset\n"))
2032 ui.write(("local is subset\n"))
2041 elif rheads <= common:
2033 elif rheads <= common:
2042 ui.write(("remote is subset\n"))
2034 ui.write(("remote is subset\n"))
2043
2035
2044 serverlogs = opts.get('serverlog')
2036 serverlogs = opts.get('serverlog')
2045 if serverlogs:
2037 if serverlogs:
2046 for filename in serverlogs:
2038 for filename in serverlogs:
2047 with open(filename, 'r') as logfile:
2039 with open(filename, 'r') as logfile:
2048 line = logfile.readline()
2040 line = logfile.readline()
2049 while line:
2041 while line:
2050 parts = line.strip().split(';')
2042 parts = line.strip().split(';')
2051 op = parts[1]
2043 op = parts[1]
2052 if op == 'cg':
2044 if op == 'cg':
2053 pass
2045 pass
2054 elif op == 'cgss':
2046 elif op == 'cgss':
2055 doit(parts[2].split(' '), parts[3].split(' '))
2047 doit(parts[2].split(' '), parts[3].split(' '))
2056 elif op == 'unb':
2048 elif op == 'unb':
2057 doit(parts[3].split(' '), parts[2].split(' '))
2049 doit(parts[3].split(' '), parts[2].split(' '))
2058 line = logfile.readline()
2050 line = logfile.readline()
2059 else:
2051 else:
2060 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2052 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2061 opts.get('remote_head'))
2053 opts.get('remote_head'))
2062 localrevs = opts.get('local_head')
2054 localrevs = opts.get('local_head')
2063 doit(localrevs, remoterevs)
2055 doit(localrevs, remoterevs)
2064
2056
2065 @command('debugextensions', formatteropts, [], norepo=True)
2057 @command('debugextensions', formatteropts, [], norepo=True)
2066 def debugextensions(ui, **opts):
2058 def debugextensions(ui, **opts):
2067 '''show information about active extensions'''
2059 '''show information about active extensions'''
2068 exts = extensions.extensions(ui)
2060 exts = extensions.extensions(ui)
2069 hgver = util.version()
2061 hgver = util.version()
2070 fm = ui.formatter('debugextensions', opts)
2062 fm = ui.formatter('debugextensions', opts)
2071 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2063 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2072 isinternal = extensions.ismoduleinternal(extmod)
2064 isinternal = extensions.ismoduleinternal(extmod)
2073 extsource = extmod.__file__
2065 extsource = extmod.__file__
2074 if isinternal:
2066 if isinternal:
2075 exttestedwith = [] # never expose magic string to users
2067 exttestedwith = [] # never expose magic string to users
2076 else:
2068 else:
2077 exttestedwith = getattr(extmod, 'testedwith', '').split()
2069 exttestedwith = getattr(extmod, 'testedwith', '').split()
2078 extbuglink = getattr(extmod, 'buglink', None)
2070 extbuglink = getattr(extmod, 'buglink', None)
2079
2071
2080 fm.startitem()
2072 fm.startitem()
2081
2073
2082 if ui.quiet or ui.verbose:
2074 if ui.quiet or ui.verbose:
2083 fm.write('name', '%s\n', extname)
2075 fm.write('name', '%s\n', extname)
2084 else:
2076 else:
2085 fm.write('name', '%s', extname)
2077 fm.write('name', '%s', extname)
2086 if isinternal or hgver in exttestedwith:
2078 if isinternal or hgver in exttestedwith:
2087 fm.plain('\n')
2079 fm.plain('\n')
2088 elif not exttestedwith:
2080 elif not exttestedwith:
2089 fm.plain(_(' (untested!)\n'))
2081 fm.plain(_(' (untested!)\n'))
2090 else:
2082 else:
2091 lasttestedversion = exttestedwith[-1]
2083 lasttestedversion = exttestedwith[-1]
2092 fm.plain(' (%s!)\n' % lasttestedversion)
2084 fm.plain(' (%s!)\n' % lasttestedversion)
2093
2085
2094 fm.condwrite(ui.verbose and extsource, 'source',
2086 fm.condwrite(ui.verbose and extsource, 'source',
2095 _(' location: %s\n'), extsource or "")
2087 _(' location: %s\n'), extsource or "")
2096
2088
2097 if ui.verbose:
2089 if ui.verbose:
2098 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2090 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2099 fm.data(bundled=isinternal)
2091 fm.data(bundled=isinternal)
2100
2092
2101 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2093 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2102 _(' tested with: %s\n'),
2094 _(' tested with: %s\n'),
2103 fm.formatlist(exttestedwith, name='ver'))
2095 fm.formatlist(exttestedwith, name='ver'))
2104
2096
2105 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2097 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2106 _(' bug reporting: %s\n'), extbuglink or "")
2098 _(' bug reporting: %s\n'), extbuglink or "")
2107
2099
2108 fm.end()
2100 fm.end()
2109
2101
2110 @command('debugfileset',
2102 @command('debugfileset',
2111 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2103 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2112 _('[-r REV] FILESPEC'))
2104 _('[-r REV] FILESPEC'))
2113 def debugfileset(ui, repo, expr, **opts):
2105 def debugfileset(ui, repo, expr, **opts):
2114 '''parse and apply a fileset specification'''
2106 '''parse and apply a fileset specification'''
2115 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2107 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2116 if ui.verbose:
2108 if ui.verbose:
2117 tree = fileset.parse(expr)
2109 tree = fileset.parse(expr)
2118 ui.note(fileset.prettyformat(tree), "\n")
2110 ui.note(fileset.prettyformat(tree), "\n")
2119
2111
2120 for f in ctx.getfileset(expr):
2112 for f in ctx.getfileset(expr):
2121 ui.write("%s\n" % f)
2113 ui.write("%s\n" % f)
2122
2114
2123 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2115 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2124 def debugfsinfo(ui, path="."):
2116 def debugfsinfo(ui, path="."):
2125 """show information detected about current filesystem"""
2117 """show information detected about current filesystem"""
2126 util.writefile('.debugfsinfo', '')
2118 util.writefile('.debugfsinfo', '')
2127 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2119 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2128 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2120 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2129 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2121 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2130 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2122 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2131 and 'yes' or 'no'))
2123 and 'yes' or 'no'))
2132 os.unlink('.debugfsinfo')
2124 os.unlink('.debugfsinfo')
2133
2125
2134 @command('debuggetbundle',
2126 @command('debuggetbundle',
2135 [('H', 'head', [], _('id of head node'), _('ID')),
2127 [('H', 'head', [], _('id of head node'), _('ID')),
2136 ('C', 'common', [], _('id of common node'), _('ID')),
2128 ('C', 'common', [], _('id of common node'), _('ID')),
2137 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2129 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2138 _('REPO FILE [-H|-C ID]...'),
2130 _('REPO FILE [-H|-C ID]...'),
2139 norepo=True)
2131 norepo=True)
2140 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2132 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2141 """retrieves a bundle from a repo
2133 """retrieves a bundle from a repo
2142
2134
2143 Every ID must be a full-length hex node id string. Saves the bundle to the
2135 Every ID must be a full-length hex node id string. Saves the bundle to the
2144 given file.
2136 given file.
2145 """
2137 """
2146 repo = hg.peer(ui, opts, repopath)
2138 repo = hg.peer(ui, opts, repopath)
2147 if not repo.capable('getbundle'):
2139 if not repo.capable('getbundle'):
2148 raise error.Abort("getbundle() not supported by target repository")
2140 raise error.Abort("getbundle() not supported by target repository")
2149 args = {}
2141 args = {}
2150 if common:
2142 if common:
2151 args['common'] = [bin(s) for s in common]
2143 args['common'] = [bin(s) for s in common]
2152 if head:
2144 if head:
2153 args['heads'] = [bin(s) for s in head]
2145 args['heads'] = [bin(s) for s in head]
2154 # TODO: get desired bundlecaps from command line.
2146 # TODO: get desired bundlecaps from command line.
2155 args['bundlecaps'] = None
2147 args['bundlecaps'] = None
2156 bundle = repo.getbundle('debug', **args)
2148 bundle = repo.getbundle('debug', **args)
2157
2149
2158 bundletype = opts.get('type', 'bzip2').lower()
2150 bundletype = opts.get('type', 'bzip2').lower()
2159 btypes = {'none': 'HG10UN',
2151 btypes = {'none': 'HG10UN',
2160 'bzip2': 'HG10BZ',
2152 'bzip2': 'HG10BZ',
2161 'gzip': 'HG10GZ',
2153 'gzip': 'HG10GZ',
2162 'bundle2': 'HG20'}
2154 'bundle2': 'HG20'}
2163 bundletype = btypes.get(bundletype)
2155 bundletype = btypes.get(bundletype)
2164 if bundletype not in bundle2.bundletypes:
2156 if bundletype not in bundle2.bundletypes:
2165 raise error.Abort(_('unknown bundle type specified with --type'))
2157 raise error.Abort(_('unknown bundle type specified with --type'))
2166 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2158 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2167
2159
2168 @command('debugignore', [], '[FILE]')
2160 @command('debugignore', [], '[FILE]')
2169 def debugignore(ui, repo, *files, **opts):
2161 def debugignore(ui, repo, *files, **opts):
2170 """display the combined ignore pattern and information about ignored files
2162 """display the combined ignore pattern and information about ignored files
2171
2163
2172 With no argument display the combined ignore pattern.
2164 With no argument display the combined ignore pattern.
2173
2165
2174 Given space separated file names, shows if the given file is ignored and
2166 Given space separated file names, shows if the given file is ignored and
2175 if so, show the ignore rule (file and line number) that matched it.
2167 if so, show the ignore rule (file and line number) that matched it.
2176 """
2168 """
2177 ignore = repo.dirstate._ignore
2169 ignore = repo.dirstate._ignore
2178 if not files:
2170 if not files:
2179 # Show all the patterns
2171 # Show all the patterns
2180 includepat = getattr(ignore, 'includepat', None)
2172 includepat = getattr(ignore, 'includepat', None)
2181 if includepat is not None:
2173 if includepat is not None:
2182 ui.write("%s\n" % includepat)
2174 ui.write("%s\n" % includepat)
2183 else:
2175 else:
2184 raise error.Abort(_("no ignore patterns found"))
2176 raise error.Abort(_("no ignore patterns found"))
2185 else:
2177 else:
2186 for f in files:
2178 for f in files:
2187 nf = util.normpath(f)
2179 nf = util.normpath(f)
2188 ignored = None
2180 ignored = None
2189 ignoredata = None
2181 ignoredata = None
2190 if nf != '.':
2182 if nf != '.':
2191 if ignore(nf):
2183 if ignore(nf):
2192 ignored = nf
2184 ignored = nf
2193 ignoredata = repo.dirstate._ignorefileandline(nf)
2185 ignoredata = repo.dirstate._ignorefileandline(nf)
2194 else:
2186 else:
2195 for p in util.finddirs(nf):
2187 for p in util.finddirs(nf):
2196 if ignore(p):
2188 if ignore(p):
2197 ignored = p
2189 ignored = p
2198 ignoredata = repo.dirstate._ignorefileandline(p)
2190 ignoredata = repo.dirstate._ignorefileandline(p)
2199 break
2191 break
2200 if ignored:
2192 if ignored:
2201 if ignored == nf:
2193 if ignored == nf:
2202 ui.write(_("%s is ignored\n") % f)
2194 ui.write(_("%s is ignored\n") % f)
2203 else:
2195 else:
2204 ui.write(_("%s is ignored because of "
2196 ui.write(_("%s is ignored because of "
2205 "containing folder %s\n")
2197 "containing folder %s\n")
2206 % (f, ignored))
2198 % (f, ignored))
2207 ignorefile, lineno, line = ignoredata
2199 ignorefile, lineno, line = ignoredata
2208 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2200 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2209 % (ignorefile, lineno, line))
2201 % (ignorefile, lineno, line))
2210 else:
2202 else:
2211 ui.write(_("%s is not ignored\n") % f)
2203 ui.write(_("%s is not ignored\n") % f)
2212
2204
2213 @command('debugindex', debugrevlogopts +
2205 @command('debugindex', debugrevlogopts +
2214 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2206 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2215 _('[-f FORMAT] -c|-m|FILE'),
2207 _('[-f FORMAT] -c|-m|FILE'),
2216 optionalrepo=True)
2208 optionalrepo=True)
2217 def debugindex(ui, repo, file_=None, **opts):
2209 def debugindex(ui, repo, file_=None, **opts):
2218 """dump the contents of an index file"""
2210 """dump the contents of an index file"""
2219 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2211 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2220 format = opts.get('format', 0)
2212 format = opts.get('format', 0)
2221 if format not in (0, 1):
2213 if format not in (0, 1):
2222 raise error.Abort(_("unknown format %d") % format)
2214 raise error.Abort(_("unknown format %d") % format)
2223
2215
2224 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2216 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2225 if generaldelta:
2217 if generaldelta:
2226 basehdr = ' delta'
2218 basehdr = ' delta'
2227 else:
2219 else:
2228 basehdr = ' base'
2220 basehdr = ' base'
2229
2221
2230 if ui.debugflag:
2222 if ui.debugflag:
2231 shortfn = hex
2223 shortfn = hex
2232 else:
2224 else:
2233 shortfn = short
2225 shortfn = short
2234
2226
2235 # There might not be anything in r, so have a sane default
2227 # There might not be anything in r, so have a sane default
2236 idlen = 12
2228 idlen = 12
2237 for i in r:
2229 for i in r:
2238 idlen = len(shortfn(r.node(i)))
2230 idlen = len(shortfn(r.node(i)))
2239 break
2231 break
2240
2232
2241 if format == 0:
2233 if format == 0:
2242 ui.write((" rev offset length " + basehdr + " linkrev"
2234 ui.write((" rev offset length " + basehdr + " linkrev"
2243 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2235 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2244 elif format == 1:
2236 elif format == 1:
2245 ui.write((" rev flag offset length"
2237 ui.write((" rev flag offset length"
2246 " size " + basehdr + " link p1 p2"
2238 " size " + basehdr + " link p1 p2"
2247 " %s\n") % "nodeid".rjust(idlen))
2239 " %s\n") % "nodeid".rjust(idlen))
2248
2240
2249 for i in r:
2241 for i in r:
2250 node = r.node(i)
2242 node = r.node(i)
2251 if generaldelta:
2243 if generaldelta:
2252 base = r.deltaparent(i)
2244 base = r.deltaparent(i)
2253 else:
2245 else:
2254 base = r.chainbase(i)
2246 base = r.chainbase(i)
2255 if format == 0:
2247 if format == 0:
2256 try:
2248 try:
2257 pp = r.parents(node)
2249 pp = r.parents(node)
2258 except Exception:
2250 except Exception:
2259 pp = [nullid, nullid]
2251 pp = [nullid, nullid]
2260 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2252 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2261 i, r.start(i), r.length(i), base, r.linkrev(i),
2253 i, r.start(i), r.length(i), base, r.linkrev(i),
2262 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2254 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2263 elif format == 1:
2255 elif format == 1:
2264 pr = r.parentrevs(i)
2256 pr = r.parentrevs(i)
2265 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2257 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2266 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2258 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2267 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2259 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2268
2260
2269 @command('debugindexdot', debugrevlogopts,
2261 @command('debugindexdot', debugrevlogopts,
2270 _('-c|-m|FILE'), optionalrepo=True)
2262 _('-c|-m|FILE'), optionalrepo=True)
2271 def debugindexdot(ui, repo, file_=None, **opts):
2263 def debugindexdot(ui, repo, file_=None, **opts):
2272 """dump an index DAG as a graphviz dot file"""
2264 """dump an index DAG as a graphviz dot file"""
2273 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2265 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2274 ui.write(("digraph G {\n"))
2266 ui.write(("digraph G {\n"))
2275 for i in r:
2267 for i in r:
2276 node = r.node(i)
2268 node = r.node(i)
2277 pp = r.parents(node)
2269 pp = r.parents(node)
2278 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2270 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2279 if pp[1] != nullid:
2271 if pp[1] != nullid:
2280 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2272 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2281 ui.write("}\n")
2273 ui.write("}\n")
2282
2274
2283 @command('debugdeltachain',
2275 @command('debugdeltachain',
2284 debugrevlogopts + formatteropts,
2276 debugrevlogopts + formatteropts,
2285 _('-c|-m|FILE'),
2277 _('-c|-m|FILE'),
2286 optionalrepo=True)
2278 optionalrepo=True)
2287 def debugdeltachain(ui, repo, file_=None, **opts):
2279 def debugdeltachain(ui, repo, file_=None, **opts):
2288 """dump information about delta chains in a revlog
2280 """dump information about delta chains in a revlog
2289
2281
2290 Output can be templatized. Available template keywords are:
2282 Output can be templatized. Available template keywords are:
2291
2283
2292 :``rev``: revision number
2284 :``rev``: revision number
2293 :``chainid``: delta chain identifier (numbered by unique base)
2285 :``chainid``: delta chain identifier (numbered by unique base)
2294 :``chainlen``: delta chain length to this revision
2286 :``chainlen``: delta chain length to this revision
2295 :``prevrev``: previous revision in delta chain
2287 :``prevrev``: previous revision in delta chain
2296 :``deltatype``: role of delta / how it was computed
2288 :``deltatype``: role of delta / how it was computed
2297 :``compsize``: compressed size of revision
2289 :``compsize``: compressed size of revision
2298 :``uncompsize``: uncompressed size of revision
2290 :``uncompsize``: uncompressed size of revision
2299 :``chainsize``: total size of compressed revisions in chain
2291 :``chainsize``: total size of compressed revisions in chain
2300 :``chainratio``: total chain size divided by uncompressed revision size
2292 :``chainratio``: total chain size divided by uncompressed revision size
2301 (new delta chains typically start at ratio 2.00)
2293 (new delta chains typically start at ratio 2.00)
2302 :``lindist``: linear distance from base revision in delta chain to end
2294 :``lindist``: linear distance from base revision in delta chain to end
2303 of this revision
2295 of this revision
2304 :``extradist``: total size of revisions not part of this delta chain from
2296 :``extradist``: total size of revisions not part of this delta chain from
2305 base of delta chain to end of this revision; a measurement
2297 base of delta chain to end of this revision; a measurement
2306 of how much extra data we need to read/seek across to read
2298 of how much extra data we need to read/seek across to read
2307 the delta chain for this revision
2299 the delta chain for this revision
2308 :``extraratio``: extradist divided by chainsize; another representation of
2300 :``extraratio``: extradist divided by chainsize; another representation of
2309 how much unrelated data is needed to load this delta chain
2301 how much unrelated data is needed to load this delta chain
2310 """
2302 """
2311 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2303 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2312 index = r.index
2304 index = r.index
2313 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2305 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2314
2306
2315 def revinfo(rev):
2307 def revinfo(rev):
2316 e = index[rev]
2308 e = index[rev]
2317 compsize = e[1]
2309 compsize = e[1]
2318 uncompsize = e[2]
2310 uncompsize = e[2]
2319 chainsize = 0
2311 chainsize = 0
2320
2312
2321 if generaldelta:
2313 if generaldelta:
2322 if e[3] == e[5]:
2314 if e[3] == e[5]:
2323 deltatype = 'p1'
2315 deltatype = 'p1'
2324 elif e[3] == e[6]:
2316 elif e[3] == e[6]:
2325 deltatype = 'p2'
2317 deltatype = 'p2'
2326 elif e[3] == rev - 1:
2318 elif e[3] == rev - 1:
2327 deltatype = 'prev'
2319 deltatype = 'prev'
2328 elif e[3] == rev:
2320 elif e[3] == rev:
2329 deltatype = 'base'
2321 deltatype = 'base'
2330 else:
2322 else:
2331 deltatype = 'other'
2323 deltatype = 'other'
2332 else:
2324 else:
2333 if e[3] == rev:
2325 if e[3] == rev:
2334 deltatype = 'base'
2326 deltatype = 'base'
2335 else:
2327 else:
2336 deltatype = 'prev'
2328 deltatype = 'prev'
2337
2329
2338 chain = r._deltachain(rev)[0]
2330 chain = r._deltachain(rev)[0]
2339 for iterrev in chain:
2331 for iterrev in chain:
2340 e = index[iterrev]
2332 e = index[iterrev]
2341 chainsize += e[1]
2333 chainsize += e[1]
2342
2334
2343 return compsize, uncompsize, deltatype, chain, chainsize
2335 return compsize, uncompsize, deltatype, chain, chainsize
2344
2336
2345 fm = ui.formatter('debugdeltachain', opts)
2337 fm = ui.formatter('debugdeltachain', opts)
2346
2338
2347 fm.plain(' rev chain# chainlen prev delta '
2339 fm.plain(' rev chain# chainlen prev delta '
2348 'size rawsize chainsize ratio lindist extradist '
2340 'size rawsize chainsize ratio lindist extradist '
2349 'extraratio\n')
2341 'extraratio\n')
2350
2342
2351 chainbases = {}
2343 chainbases = {}
2352 for rev in r:
2344 for rev in r:
2353 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2345 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2354 chainbase = chain[0]
2346 chainbase = chain[0]
2355 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2347 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2356 basestart = r.start(chainbase)
2348 basestart = r.start(chainbase)
2357 revstart = r.start(rev)
2349 revstart = r.start(rev)
2358 lineardist = revstart + comp - basestart
2350 lineardist = revstart + comp - basestart
2359 extradist = lineardist - chainsize
2351 extradist = lineardist - chainsize
2360 try:
2352 try:
2361 prevrev = chain[-2]
2353 prevrev = chain[-2]
2362 except IndexError:
2354 except IndexError:
2363 prevrev = -1
2355 prevrev = -1
2364
2356
2365 chainratio = float(chainsize) / float(uncomp)
2357 chainratio = float(chainsize) / float(uncomp)
2366 extraratio = float(extradist) / float(chainsize)
2358 extraratio = float(extradist) / float(chainsize)
2367
2359
2368 fm.startitem()
2360 fm.startitem()
2369 fm.write('rev chainid chainlen prevrev deltatype compsize '
2361 fm.write('rev chainid chainlen prevrev deltatype compsize '
2370 'uncompsize chainsize chainratio lindist extradist '
2362 'uncompsize chainsize chainratio lindist extradist '
2371 'extraratio',
2363 'extraratio',
2372 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2364 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2373 rev, chainid, len(chain), prevrev, deltatype, comp,
2365 rev, chainid, len(chain), prevrev, deltatype, comp,
2374 uncomp, chainsize, chainratio, lineardist, extradist,
2366 uncomp, chainsize, chainratio, lineardist, extradist,
2375 extraratio,
2367 extraratio,
2376 rev=rev, chainid=chainid, chainlen=len(chain),
2368 rev=rev, chainid=chainid, chainlen=len(chain),
2377 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2369 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2378 uncompsize=uncomp, chainsize=chainsize,
2370 uncompsize=uncomp, chainsize=chainsize,
2379 chainratio=chainratio, lindist=lineardist,
2371 chainratio=chainratio, lindist=lineardist,
2380 extradist=extradist, extraratio=extraratio)
2372 extradist=extradist, extraratio=extraratio)
2381
2373
2382 fm.end()
2374 fm.end()
2383
2375
2384 @command('debuginstall', [] + formatteropts, '', norepo=True)
2376 @command('debuginstall', [] + formatteropts, '', norepo=True)
2385 def debuginstall(ui, **opts):
2377 def debuginstall(ui, **opts):
2386 '''test Mercurial installation
2378 '''test Mercurial installation
2387
2379
2388 Returns 0 on success.
2380 Returns 0 on success.
2389 '''
2381 '''
2390
2382
2391 def writetemp(contents):
2383 def writetemp(contents):
2392 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2384 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2393 f = os.fdopen(fd, "wb")
2385 f = os.fdopen(fd, "wb")
2394 f.write(contents)
2386 f.write(contents)
2395 f.close()
2387 f.close()
2396 return name
2388 return name
2397
2389
2398 problems = 0
2390 problems = 0
2399
2391
2400 fm = ui.formatter('debuginstall', opts)
2392 fm = ui.formatter('debuginstall', opts)
2401 fm.startitem()
2393 fm.startitem()
2402
2394
2403 # encoding
2395 # encoding
2404 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2396 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2405 err = None
2397 err = None
2406 try:
2398 try:
2407 encoding.fromlocal("test")
2399 encoding.fromlocal("test")
2408 except error.Abort as inst:
2400 except error.Abort as inst:
2409 err = inst
2401 err = inst
2410 problems += 1
2402 problems += 1
2411 fm.condwrite(err, 'encodingerror', _(" %s\n"
2403 fm.condwrite(err, 'encodingerror', _(" %s\n"
2412 " (check that your locale is properly set)\n"), err)
2404 " (check that your locale is properly set)\n"), err)
2413
2405
2414 # Python
2406 # Python
2415 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2407 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2416 sys.executable)
2408 sys.executable)
2417 fm.write('pythonver', _("checking Python version (%s)\n"),
2409 fm.write('pythonver', _("checking Python version (%s)\n"),
2418 ("%s.%s.%s" % sys.version_info[:3]))
2410 ("%s.%s.%s" % sys.version_info[:3]))
2419 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2411 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2420 os.path.dirname(os.__file__))
2412 os.path.dirname(os.__file__))
2421
2413
2422 security = set(sslutil.supportedprotocols)
2414 security = set(sslutil.supportedprotocols)
2423 if sslutil.hassni:
2415 if sslutil.hassni:
2424 security.add('sni')
2416 security.add('sni')
2425
2417
2426 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2418 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2427 fm.formatlist(sorted(security), name='protocol',
2419 fm.formatlist(sorted(security), name='protocol',
2428 fmt='%s', sep=','))
2420 fmt='%s', sep=','))
2429
2421
2430 # These are warnings, not errors. So don't increment problem count. This
2422 # These are warnings, not errors. So don't increment problem count. This
2431 # may change in the future.
2423 # may change in the future.
2432 if 'tls1.2' not in security:
2424 if 'tls1.2' not in security:
2433 fm.plain(_(' TLS 1.2 not supported by Python install; '
2425 fm.plain(_(' TLS 1.2 not supported by Python install; '
2434 'network connections lack modern security\n'))
2426 'network connections lack modern security\n'))
2435 if 'sni' not in security:
2427 if 'sni' not in security:
2436 fm.plain(_(' SNI not supported by Python install; may have '
2428 fm.plain(_(' SNI not supported by Python install; may have '
2437 'connectivity issues with some servers\n'))
2429 'connectivity issues with some servers\n'))
2438
2430
2439 # TODO print CA cert info
2431 # TODO print CA cert info
2440
2432
2441 # hg version
2433 # hg version
2442 hgver = util.version()
2434 hgver = util.version()
2443 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2435 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2444 hgver.split('+')[0])
2436 hgver.split('+')[0])
2445 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2437 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2446 '+'.join(hgver.split('+')[1:]))
2438 '+'.join(hgver.split('+')[1:]))
2447
2439
2448 # compiled modules
2440 # compiled modules
2449 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2441 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2450 policy.policy)
2442 policy.policy)
2451 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2443 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2452 os.path.dirname(__file__))
2444 os.path.dirname(__file__))
2453
2445
2454 err = None
2446 err = None
2455 try:
2447 try:
2456 from . import (
2448 from . import (
2457 base85,
2449 base85,
2458 bdiff,
2450 bdiff,
2459 mpatch,
2451 mpatch,
2460 osutil,
2452 osutil,
2461 )
2453 )
2462 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2454 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2463 except Exception as inst:
2455 except Exception as inst:
2464 err = inst
2456 err = inst
2465 problems += 1
2457 problems += 1
2466 fm.condwrite(err, 'extensionserror', " %s\n", err)
2458 fm.condwrite(err, 'extensionserror', " %s\n", err)
2467
2459
2468 compengines = util.compengines._engines.values()
2460 compengines = util.compengines._engines.values()
2469 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2461 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2470 fm.formatlist(sorted(e.name() for e in compengines),
2462 fm.formatlist(sorted(e.name() for e in compengines),
2471 name='compengine', fmt='%s', sep=', '))
2463 name='compengine', fmt='%s', sep=', '))
2472 fm.write('compenginesavail', _('checking available compression engines '
2464 fm.write('compenginesavail', _('checking available compression engines '
2473 '(%s)\n'),
2465 '(%s)\n'),
2474 fm.formatlist(sorted(e.name() for e in compengines
2466 fm.formatlist(sorted(e.name() for e in compengines
2475 if e.available()),
2467 if e.available()),
2476 name='compengine', fmt='%s', sep=', '))
2468 name='compengine', fmt='%s', sep=', '))
2477
2469
2478 # templates
2470 # templates
2479 p = templater.templatepaths()
2471 p = templater.templatepaths()
2480 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2472 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2481 fm.condwrite(not p, '', _(" no template directories found\n"))
2473 fm.condwrite(not p, '', _(" no template directories found\n"))
2482 if p:
2474 if p:
2483 m = templater.templatepath("map-cmdline.default")
2475 m = templater.templatepath("map-cmdline.default")
2484 if m:
2476 if m:
2485 # template found, check if it is working
2477 # template found, check if it is working
2486 err = None
2478 err = None
2487 try:
2479 try:
2488 templater.templater.frommapfile(m)
2480 templater.templater.frommapfile(m)
2489 except Exception as inst:
2481 except Exception as inst:
2490 err = inst
2482 err = inst
2491 p = None
2483 p = None
2492 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2484 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2493 else:
2485 else:
2494 p = None
2486 p = None
2495 fm.condwrite(p, 'defaulttemplate',
2487 fm.condwrite(p, 'defaulttemplate',
2496 _("checking default template (%s)\n"), m)
2488 _("checking default template (%s)\n"), m)
2497 fm.condwrite(not m, 'defaulttemplatenotfound',
2489 fm.condwrite(not m, 'defaulttemplatenotfound',
2498 _(" template '%s' not found\n"), "default")
2490 _(" template '%s' not found\n"), "default")
2499 if not p:
2491 if not p:
2500 problems += 1
2492 problems += 1
2501 fm.condwrite(not p, '',
2493 fm.condwrite(not p, '',
2502 _(" (templates seem to have been installed incorrectly)\n"))
2494 _(" (templates seem to have been installed incorrectly)\n"))
2503
2495
2504 # editor
2496 # editor
2505 editor = ui.geteditor()
2497 editor = ui.geteditor()
2506 editor = util.expandpath(editor)
2498 editor = util.expandpath(editor)
2507 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2499 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2508 cmdpath = util.findexe(shlex.split(editor)[0])
2500 cmdpath = util.findexe(shlex.split(editor)[0])
2509 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2501 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2510 _(" No commit editor set and can't find %s in PATH\n"
2502 _(" No commit editor set and can't find %s in PATH\n"
2511 " (specify a commit editor in your configuration"
2503 " (specify a commit editor in your configuration"
2512 " file)\n"), not cmdpath and editor == 'vi' and editor)
2504 " file)\n"), not cmdpath and editor == 'vi' and editor)
2513 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2505 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2514 _(" Can't find editor '%s' in PATH\n"
2506 _(" Can't find editor '%s' in PATH\n"
2515 " (specify a commit editor in your configuration"
2507 " (specify a commit editor in your configuration"
2516 " file)\n"), not cmdpath and editor)
2508 " file)\n"), not cmdpath and editor)
2517 if not cmdpath and editor != 'vi':
2509 if not cmdpath and editor != 'vi':
2518 problems += 1
2510 problems += 1
2519
2511
2520 # check username
2512 # check username
2521 username = None
2513 username = None
2522 err = None
2514 err = None
2523 try:
2515 try:
2524 username = ui.username()
2516 username = ui.username()
2525 except error.Abort as e:
2517 except error.Abort as e:
2526 err = e
2518 err = e
2527 problems += 1
2519 problems += 1
2528
2520
2529 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2521 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2530 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2522 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2531 " (specify a username in your configuration file)\n"), err)
2523 " (specify a username in your configuration file)\n"), err)
2532
2524
2533 fm.condwrite(not problems, '',
2525 fm.condwrite(not problems, '',
2534 _("no problems detected\n"))
2526 _("no problems detected\n"))
2535 if not problems:
2527 if not problems:
2536 fm.data(problems=problems)
2528 fm.data(problems=problems)
2537 fm.condwrite(problems, 'problems',
2529 fm.condwrite(problems, 'problems',
2538 _("%d problems detected,"
2530 _("%d problems detected,"
2539 " please check your install!\n"), problems)
2531 " please check your install!\n"), problems)
2540 fm.end()
2532 fm.end()
2541
2533
2542 return problems
2534 return problems
2543
2535
2544 @command('debugknown', [], _('REPO ID...'), norepo=True)
2536 @command('debugknown', [], _('REPO ID...'), norepo=True)
2545 def debugknown(ui, repopath, *ids, **opts):
2537 def debugknown(ui, repopath, *ids, **opts):
2546 """test whether node ids are known to a repo
2538 """test whether node ids are known to a repo
2547
2539
2548 Every ID must be a full-length hex node id string. Returns a list of 0s
2540 Every ID must be a full-length hex node id string. Returns a list of 0s
2549 and 1s indicating unknown/known.
2541 and 1s indicating unknown/known.
2550 """
2542 """
2551 repo = hg.peer(ui, opts, repopath)
2543 repo = hg.peer(ui, opts, repopath)
2552 if not repo.capable('known'):
2544 if not repo.capable('known'):
2553 raise error.Abort("known() not supported by target repository")
2545 raise error.Abort("known() not supported by target repository")
2554 flags = repo.known([bin(s) for s in ids])
2546 flags = repo.known([bin(s) for s in ids])
2555 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2547 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2556
2548
2557 @command('debuglabelcomplete', [], _('LABEL...'))
2549 @command('debuglabelcomplete', [], _('LABEL...'))
2558 def debuglabelcomplete(ui, repo, *args):
2550 def debuglabelcomplete(ui, repo, *args):
2559 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2551 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2560 debugnamecomplete(ui, repo, *args)
2552 debugnamecomplete(ui, repo, *args)
2561
2553
2562 @command('debugmergestate', [], '')
2554 @command('debugmergestate', [], '')
2563 def debugmergestate(ui, repo, *args):
2555 def debugmergestate(ui, repo, *args):
2564 """print merge state
2556 """print merge state
2565
2557
2566 Use --verbose to print out information about whether v1 or v2 merge state
2558 Use --verbose to print out information about whether v1 or v2 merge state
2567 was chosen."""
2559 was chosen."""
2568 def _hashornull(h):
2560 def _hashornull(h):
2569 if h == nullhex:
2561 if h == nullhex:
2570 return 'null'
2562 return 'null'
2571 else:
2563 else:
2572 return h
2564 return h
2573
2565
2574 def printrecords(version):
2566 def printrecords(version):
2575 ui.write(('* version %s records\n') % version)
2567 ui.write(('* version %s records\n') % version)
2576 if version == 1:
2568 if version == 1:
2577 records = v1records
2569 records = v1records
2578 else:
2570 else:
2579 records = v2records
2571 records = v2records
2580
2572
2581 for rtype, record in records:
2573 for rtype, record in records:
2582 # pretty print some record types
2574 # pretty print some record types
2583 if rtype == 'L':
2575 if rtype == 'L':
2584 ui.write(('local: %s\n') % record)
2576 ui.write(('local: %s\n') % record)
2585 elif rtype == 'O':
2577 elif rtype == 'O':
2586 ui.write(('other: %s\n') % record)
2578 ui.write(('other: %s\n') % record)
2587 elif rtype == 'm':
2579 elif rtype == 'm':
2588 driver, mdstate = record.split('\0', 1)
2580 driver, mdstate = record.split('\0', 1)
2589 ui.write(('merge driver: %s (state "%s")\n')
2581 ui.write(('merge driver: %s (state "%s")\n')
2590 % (driver, mdstate))
2582 % (driver, mdstate))
2591 elif rtype in 'FDC':
2583 elif rtype in 'FDC':
2592 r = record.split('\0')
2584 r = record.split('\0')
2593 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2585 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2594 if version == 1:
2586 if version == 1:
2595 onode = 'not stored in v1 format'
2587 onode = 'not stored in v1 format'
2596 flags = r[7]
2588 flags = r[7]
2597 else:
2589 else:
2598 onode, flags = r[7:9]
2590 onode, flags = r[7:9]
2599 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2591 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2600 % (f, rtype, state, _hashornull(hash)))
2592 % (f, rtype, state, _hashornull(hash)))
2601 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2593 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2602 ui.write((' ancestor path: %s (node %s)\n')
2594 ui.write((' ancestor path: %s (node %s)\n')
2603 % (afile, _hashornull(anode)))
2595 % (afile, _hashornull(anode)))
2604 ui.write((' other path: %s (node %s)\n')
2596 ui.write((' other path: %s (node %s)\n')
2605 % (ofile, _hashornull(onode)))
2597 % (ofile, _hashornull(onode)))
2606 elif rtype == 'f':
2598 elif rtype == 'f':
2607 filename, rawextras = record.split('\0', 1)
2599 filename, rawextras = record.split('\0', 1)
2608 extras = rawextras.split('\0')
2600 extras = rawextras.split('\0')
2609 i = 0
2601 i = 0
2610 extrastrings = []
2602 extrastrings = []
2611 while i < len(extras):
2603 while i < len(extras):
2612 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2604 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2613 i += 2
2605 i += 2
2614
2606
2615 ui.write(('file extras: %s (%s)\n')
2607 ui.write(('file extras: %s (%s)\n')
2616 % (filename, ', '.join(extrastrings)))
2608 % (filename, ', '.join(extrastrings)))
2617 elif rtype == 'l':
2609 elif rtype == 'l':
2618 labels = record.split('\0', 2)
2610 labels = record.split('\0', 2)
2619 labels = [l for l in labels if len(l) > 0]
2611 labels = [l for l in labels if len(l) > 0]
2620 ui.write(('labels:\n'))
2612 ui.write(('labels:\n'))
2621 ui.write((' local: %s\n' % labels[0]))
2613 ui.write((' local: %s\n' % labels[0]))
2622 ui.write((' other: %s\n' % labels[1]))
2614 ui.write((' other: %s\n' % labels[1]))
2623 if len(labels) > 2:
2615 if len(labels) > 2:
2624 ui.write((' base: %s\n' % labels[2]))
2616 ui.write((' base: %s\n' % labels[2]))
2625 else:
2617 else:
2626 ui.write(('unrecognized entry: %s\t%s\n')
2618 ui.write(('unrecognized entry: %s\t%s\n')
2627 % (rtype, record.replace('\0', '\t')))
2619 % (rtype, record.replace('\0', '\t')))
2628
2620
2629 # Avoid mergestate.read() since it may raise an exception for unsupported
2621 # Avoid mergestate.read() since it may raise an exception for unsupported
2630 # merge state records. We shouldn't be doing this, but this is OK since this
2622 # merge state records. We shouldn't be doing this, but this is OK since this
2631 # command is pretty low-level.
2623 # command is pretty low-level.
2632 ms = mergemod.mergestate(repo)
2624 ms = mergemod.mergestate(repo)
2633
2625
2634 # sort so that reasonable information is on top
2626 # sort so that reasonable information is on top
2635 v1records = ms._readrecordsv1()
2627 v1records = ms._readrecordsv1()
2636 v2records = ms._readrecordsv2()
2628 v2records = ms._readrecordsv2()
2637 order = 'LOml'
2629 order = 'LOml'
2638 def key(r):
2630 def key(r):
2639 idx = order.find(r[0])
2631 idx = order.find(r[0])
2640 if idx == -1:
2632 if idx == -1:
2641 return (1, r[1])
2633 return (1, r[1])
2642 else:
2634 else:
2643 return (0, idx)
2635 return (0, idx)
2644 v1records.sort(key=key)
2636 v1records.sort(key=key)
2645 v2records.sort(key=key)
2637 v2records.sort(key=key)
2646
2638
2647 if not v1records and not v2records:
2639 if not v1records and not v2records:
2648 ui.write(('no merge state found\n'))
2640 ui.write(('no merge state found\n'))
2649 elif not v2records:
2641 elif not v2records:
2650 ui.note(('no version 2 merge state\n'))
2642 ui.note(('no version 2 merge state\n'))
2651 printrecords(1)
2643 printrecords(1)
2652 elif ms._v1v2match(v1records, v2records):
2644 elif ms._v1v2match(v1records, v2records):
2653 ui.note(('v1 and v2 states match: using v2\n'))
2645 ui.note(('v1 and v2 states match: using v2\n'))
2654 printrecords(2)
2646 printrecords(2)
2655 else:
2647 else:
2656 ui.note(('v1 and v2 states mismatch: using v1\n'))
2648 ui.note(('v1 and v2 states mismatch: using v1\n'))
2657 printrecords(1)
2649 printrecords(1)
2658 if ui.verbose:
2650 if ui.verbose:
2659 printrecords(2)
2651 printrecords(2)
2660
2652
2661 @command('debugnamecomplete', [], _('NAME...'))
2653 @command('debugnamecomplete', [], _('NAME...'))
2662 def debugnamecomplete(ui, repo, *args):
2654 def debugnamecomplete(ui, repo, *args):
2663 '''complete "names" - tags, open branch names, bookmark names'''
2655 '''complete "names" - tags, open branch names, bookmark names'''
2664
2656
2665 names = set()
2657 names = set()
2666 # since we previously only listed open branches, we will handle that
2658 # since we previously only listed open branches, we will handle that
2667 # specially (after this for loop)
2659 # specially (after this for loop)
2668 for name, ns in repo.names.iteritems():
2660 for name, ns in repo.names.iteritems():
2669 if name != 'branches':
2661 if name != 'branches':
2670 names.update(ns.listnames(repo))
2662 names.update(ns.listnames(repo))
2671 names.update(tag for (tag, heads, tip, closed)
2663 names.update(tag for (tag, heads, tip, closed)
2672 in repo.branchmap().iterbranches() if not closed)
2664 in repo.branchmap().iterbranches() if not closed)
2673 completions = set()
2665 completions = set()
2674 if not args:
2666 if not args:
2675 args = ['']
2667 args = ['']
2676 for a in args:
2668 for a in args:
2677 completions.update(n for n in names if n.startswith(a))
2669 completions.update(n for n in names if n.startswith(a))
2678 ui.write('\n'.join(sorted(completions)))
2670 ui.write('\n'.join(sorted(completions)))
2679 ui.write('\n')
2671 ui.write('\n')
2680
2672
2681 @command('debuglocks',
2673 @command('debuglocks',
2682 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2674 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2683 ('W', 'force-wlock', None,
2675 ('W', 'force-wlock', None,
2684 _('free the working state lock (DANGEROUS)'))],
2676 _('free the working state lock (DANGEROUS)'))],
2685 _('[OPTION]...'))
2677 _('[OPTION]...'))
2686 def debuglocks(ui, repo, **opts):
2678 def debuglocks(ui, repo, **opts):
2687 """show or modify state of locks
2679 """show or modify state of locks
2688
2680
2689 By default, this command will show which locks are held. This
2681 By default, this command will show which locks are held. This
2690 includes the user and process holding the lock, the amount of time
2682 includes the user and process holding the lock, the amount of time
2691 the lock has been held, and the machine name where the process is
2683 the lock has been held, and the machine name where the process is
2692 running if it's not local.
2684 running if it's not local.
2693
2685
2694 Locks protect the integrity of Mercurial's data, so should be
2686 Locks protect the integrity of Mercurial's data, so should be
2695 treated with care. System crashes or other interruptions may cause
2687 treated with care. System crashes or other interruptions may cause
2696 locks to not be properly released, though Mercurial will usually
2688 locks to not be properly released, though Mercurial will usually
2697 detect and remove such stale locks automatically.
2689 detect and remove such stale locks automatically.
2698
2690
2699 However, detecting stale locks may not always be possible (for
2691 However, detecting stale locks may not always be possible (for
2700 instance, on a shared filesystem). Removing locks may also be
2692 instance, on a shared filesystem). Removing locks may also be
2701 blocked by filesystem permissions.
2693 blocked by filesystem permissions.
2702
2694
2703 Returns 0 if no locks are held.
2695 Returns 0 if no locks are held.
2704
2696
2705 """
2697 """
2706
2698
2707 if opts.get('force_lock'):
2699 if opts.get('force_lock'):
2708 repo.svfs.unlink('lock')
2700 repo.svfs.unlink('lock')
2709 if opts.get('force_wlock'):
2701 if opts.get('force_wlock'):
2710 repo.vfs.unlink('wlock')
2702 repo.vfs.unlink('wlock')
2711 if opts.get('force_lock') or opts.get('force_lock'):
2703 if opts.get('force_lock') or opts.get('force_lock'):
2712 return 0
2704 return 0
2713
2705
2714 now = time.time()
2706 now = time.time()
2715 held = 0
2707 held = 0
2716
2708
2717 def report(vfs, name, method):
2709 def report(vfs, name, method):
2718 # this causes stale locks to get reaped for more accurate reporting
2710 # this causes stale locks to get reaped for more accurate reporting
2719 try:
2711 try:
2720 l = method(False)
2712 l = method(False)
2721 except error.LockHeld:
2713 except error.LockHeld:
2722 l = None
2714 l = None
2723
2715
2724 if l:
2716 if l:
2725 l.release()
2717 l.release()
2726 else:
2718 else:
2727 try:
2719 try:
2728 stat = vfs.lstat(name)
2720 stat = vfs.lstat(name)
2729 age = now - stat.st_mtime
2721 age = now - stat.st_mtime
2730 user = util.username(stat.st_uid)
2722 user = util.username(stat.st_uid)
2731 locker = vfs.readlock(name)
2723 locker = vfs.readlock(name)
2732 if ":" in locker:
2724 if ":" in locker:
2733 host, pid = locker.split(':')
2725 host, pid = locker.split(':')
2734 if host == socket.gethostname():
2726 if host == socket.gethostname():
2735 locker = 'user %s, process %s' % (user, pid)
2727 locker = 'user %s, process %s' % (user, pid)
2736 else:
2728 else:
2737 locker = 'user %s, process %s, host %s' \
2729 locker = 'user %s, process %s, host %s' \
2738 % (user, pid, host)
2730 % (user, pid, host)
2739 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2731 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2740 return 1
2732 return 1
2741 except OSError as e:
2733 except OSError as e:
2742 if e.errno != errno.ENOENT:
2734 if e.errno != errno.ENOENT:
2743 raise
2735 raise
2744
2736
2745 ui.write(("%-6s free\n") % (name + ":"))
2737 ui.write(("%-6s free\n") % (name + ":"))
2746 return 0
2738 return 0
2747
2739
2748 held += report(repo.svfs, "lock", repo.lock)
2740 held += report(repo.svfs, "lock", repo.lock)
2749 held += report(repo.vfs, "wlock", repo.wlock)
2741 held += report(repo.vfs, "wlock", repo.wlock)
2750
2742
2751 return held
2743 return held
2752
2744
2753 @command('debugobsolete',
2745 @command('debugobsolete',
2754 [('', 'flags', 0, _('markers flag')),
2746 [('', 'flags', 0, _('markers flag')),
2755 ('', 'record-parents', False,
2747 ('', 'record-parents', False,
2756 _('record parent information for the precursor')),
2748 _('record parent information for the precursor')),
2757 ('r', 'rev', [], _('display markers relevant to REV')),
2749 ('r', 'rev', [], _('display markers relevant to REV')),
2758 ('', 'index', False, _('display index of the marker')),
2750 ('', 'index', False, _('display index of the marker')),
2759 ('', 'delete', [], _('delete markers specified by indices')),
2751 ('', 'delete', [], _('delete markers specified by indices')),
2760 ] + commitopts2 + formatteropts,
2752 ] + commitopts2 + formatteropts,
2761 _('[OBSOLETED [REPLACEMENT ...]]'))
2753 _('[OBSOLETED [REPLACEMENT ...]]'))
2762 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2754 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2763 """create arbitrary obsolete marker
2755 """create arbitrary obsolete marker
2764
2756
2765 With no arguments, displays the list of obsolescence markers."""
2757 With no arguments, displays the list of obsolescence markers."""
2766
2758
2767 def parsenodeid(s):
2759 def parsenodeid(s):
2768 try:
2760 try:
2769 # We do not use revsingle/revrange functions here to accept
2761 # We do not use revsingle/revrange functions here to accept
2770 # arbitrary node identifiers, possibly not present in the
2762 # arbitrary node identifiers, possibly not present in the
2771 # local repository.
2763 # local repository.
2772 n = bin(s)
2764 n = bin(s)
2773 if len(n) != len(nullid):
2765 if len(n) != len(nullid):
2774 raise TypeError()
2766 raise TypeError()
2775 return n
2767 return n
2776 except TypeError:
2768 except TypeError:
2777 raise error.Abort('changeset references must be full hexadecimal '
2769 raise error.Abort('changeset references must be full hexadecimal '
2778 'node identifiers')
2770 'node identifiers')
2779
2771
2780 if opts.get('delete'):
2772 if opts.get('delete'):
2781 indices = []
2773 indices = []
2782 for v in opts.get('delete'):
2774 for v in opts.get('delete'):
2783 try:
2775 try:
2784 indices.append(int(v))
2776 indices.append(int(v))
2785 except ValueError:
2777 except ValueError:
2786 raise error.Abort(_('invalid index value: %r') % v,
2778 raise error.Abort(_('invalid index value: %r') % v,
2787 hint=_('use integers for indices'))
2779 hint=_('use integers for indices'))
2788
2780
2789 if repo.currenttransaction():
2781 if repo.currenttransaction():
2790 raise error.Abort(_('cannot delete obsmarkers in the middle '
2782 raise error.Abort(_('cannot delete obsmarkers in the middle '
2791 'of transaction.'))
2783 'of transaction.'))
2792
2784
2793 with repo.lock():
2785 with repo.lock():
2794 n = repair.deleteobsmarkers(repo.obsstore, indices)
2786 n = repair.deleteobsmarkers(repo.obsstore, indices)
2795 ui.write(_('deleted %i obsolescence markers\n') % n)
2787 ui.write(_('deleted %i obsolescence markers\n') % n)
2796
2788
2797 return
2789 return
2798
2790
2799 if precursor is not None:
2791 if precursor is not None:
2800 if opts['rev']:
2792 if opts['rev']:
2801 raise error.Abort('cannot select revision when creating marker')
2793 raise error.Abort('cannot select revision when creating marker')
2802 metadata = {}
2794 metadata = {}
2803 metadata['user'] = opts['user'] or ui.username()
2795 metadata['user'] = opts['user'] or ui.username()
2804 succs = tuple(parsenodeid(succ) for succ in successors)
2796 succs = tuple(parsenodeid(succ) for succ in successors)
2805 l = repo.lock()
2797 l = repo.lock()
2806 try:
2798 try:
2807 tr = repo.transaction('debugobsolete')
2799 tr = repo.transaction('debugobsolete')
2808 try:
2800 try:
2809 date = opts.get('date')
2801 date = opts.get('date')
2810 if date:
2802 if date:
2811 date = util.parsedate(date)
2803 date = util.parsedate(date)
2812 else:
2804 else:
2813 date = None
2805 date = None
2814 prec = parsenodeid(precursor)
2806 prec = parsenodeid(precursor)
2815 parents = None
2807 parents = None
2816 if opts['record_parents']:
2808 if opts['record_parents']:
2817 if prec not in repo.unfiltered():
2809 if prec not in repo.unfiltered():
2818 raise error.Abort('cannot used --record-parents on '
2810 raise error.Abort('cannot used --record-parents on '
2819 'unknown changesets')
2811 'unknown changesets')
2820 parents = repo.unfiltered()[prec].parents()
2812 parents = repo.unfiltered()[prec].parents()
2821 parents = tuple(p.node() for p in parents)
2813 parents = tuple(p.node() for p in parents)
2822 repo.obsstore.create(tr, prec, succs, opts['flags'],
2814 repo.obsstore.create(tr, prec, succs, opts['flags'],
2823 parents=parents, date=date,
2815 parents=parents, date=date,
2824 metadata=metadata)
2816 metadata=metadata)
2825 tr.close()
2817 tr.close()
2826 except ValueError as exc:
2818 except ValueError as exc:
2827 raise error.Abort(_('bad obsmarker input: %s') % exc)
2819 raise error.Abort(_('bad obsmarker input: %s') % exc)
2828 finally:
2820 finally:
2829 tr.release()
2821 tr.release()
2830 finally:
2822 finally:
2831 l.release()
2823 l.release()
2832 else:
2824 else:
2833 if opts['rev']:
2825 if opts['rev']:
2834 revs = scmutil.revrange(repo, opts['rev'])
2826 revs = scmutil.revrange(repo, opts['rev'])
2835 nodes = [repo[r].node() for r in revs]
2827 nodes = [repo[r].node() for r in revs]
2836 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2828 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2837 markers.sort(key=lambda x: x._data)
2829 markers.sort(key=lambda x: x._data)
2838 else:
2830 else:
2839 markers = obsolete.getmarkers(repo)
2831 markers = obsolete.getmarkers(repo)
2840
2832
2841 markerstoiter = markers
2833 markerstoiter = markers
2842 isrelevant = lambda m: True
2834 isrelevant = lambda m: True
2843 if opts.get('rev') and opts.get('index'):
2835 if opts.get('rev') and opts.get('index'):
2844 markerstoiter = obsolete.getmarkers(repo)
2836 markerstoiter = obsolete.getmarkers(repo)
2845 markerset = set(markers)
2837 markerset = set(markers)
2846 isrelevant = lambda m: m in markerset
2838 isrelevant = lambda m: m in markerset
2847
2839
2848 fm = ui.formatter('debugobsolete', opts)
2840 fm = ui.formatter('debugobsolete', opts)
2849 for i, m in enumerate(markerstoiter):
2841 for i, m in enumerate(markerstoiter):
2850 if not isrelevant(m):
2842 if not isrelevant(m):
2851 # marker can be irrelevant when we're iterating over a set
2843 # marker can be irrelevant when we're iterating over a set
2852 # of markers (markerstoiter) which is bigger than the set
2844 # of markers (markerstoiter) which is bigger than the set
2853 # of markers we want to display (markers)
2845 # of markers we want to display (markers)
2854 # this can happen if both --index and --rev options are
2846 # this can happen if both --index and --rev options are
2855 # provided and thus we need to iterate over all of the markers
2847 # provided and thus we need to iterate over all of the markers
2856 # to get the correct indices, but only display the ones that
2848 # to get the correct indices, but only display the ones that
2857 # are relevant to --rev value
2849 # are relevant to --rev value
2858 continue
2850 continue
2859 fm.startitem()
2851 fm.startitem()
2860 ind = i if opts.get('index') else None
2852 ind = i if opts.get('index') else None
2861 cmdutil.showmarker(fm, m, index=ind)
2853 cmdutil.showmarker(fm, m, index=ind)
2862 fm.end()
2854 fm.end()
2863
2855
2864 @command('debugpathcomplete',
2856 @command('debugpathcomplete',
2865 [('f', 'full', None, _('complete an entire path')),
2857 [('f', 'full', None, _('complete an entire path')),
2866 ('n', 'normal', None, _('show only normal files')),
2858 ('n', 'normal', None, _('show only normal files')),
2867 ('a', 'added', None, _('show only added files')),
2859 ('a', 'added', None, _('show only added files')),
2868 ('r', 'removed', None, _('show only removed files'))],
2860 ('r', 'removed', None, _('show only removed files'))],
2869 _('FILESPEC...'))
2861 _('FILESPEC...'))
2870 def debugpathcomplete(ui, repo, *specs, **opts):
2862 def debugpathcomplete(ui, repo, *specs, **opts):
2871 '''complete part or all of a tracked path
2863 '''complete part or all of a tracked path
2872
2864
2873 This command supports shells that offer path name completion. It
2865 This command supports shells that offer path name completion. It
2874 currently completes only files already known to the dirstate.
2866 currently completes only files already known to the dirstate.
2875
2867
2876 Completion extends only to the next path segment unless
2868 Completion extends only to the next path segment unless
2877 --full is specified, in which case entire paths are used.'''
2869 --full is specified, in which case entire paths are used.'''
2878
2870
2879 def complete(path, acceptable):
2871 def complete(path, acceptable):
2880 dirstate = repo.dirstate
2872 dirstate = repo.dirstate
2881 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2873 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2882 rootdir = repo.root + os.sep
2874 rootdir = repo.root + os.sep
2883 if spec != repo.root and not spec.startswith(rootdir):
2875 if spec != repo.root and not spec.startswith(rootdir):
2884 return [], []
2876 return [], []
2885 if os.path.isdir(spec):
2877 if os.path.isdir(spec):
2886 spec += '/'
2878 spec += '/'
2887 spec = spec[len(rootdir):]
2879 spec = spec[len(rootdir):]
2888 fixpaths = pycompat.ossep != '/'
2880 fixpaths = pycompat.ossep != '/'
2889 if fixpaths:
2881 if fixpaths:
2890 spec = spec.replace(os.sep, '/')
2882 spec = spec.replace(os.sep, '/')
2891 speclen = len(spec)
2883 speclen = len(spec)
2892 fullpaths = opts['full']
2884 fullpaths = opts['full']
2893 files, dirs = set(), set()
2885 files, dirs = set(), set()
2894 adddir, addfile = dirs.add, files.add
2886 adddir, addfile = dirs.add, files.add
2895 for f, st in dirstate.iteritems():
2887 for f, st in dirstate.iteritems():
2896 if f.startswith(spec) and st[0] in acceptable:
2888 if f.startswith(spec) and st[0] in acceptable:
2897 if fixpaths:
2889 if fixpaths:
2898 f = f.replace('/', os.sep)
2890 f = f.replace('/', os.sep)
2899 if fullpaths:
2891 if fullpaths:
2900 addfile(f)
2892 addfile(f)
2901 continue
2893 continue
2902 s = f.find(os.sep, speclen)
2894 s = f.find(os.sep, speclen)
2903 if s >= 0:
2895 if s >= 0:
2904 adddir(f[:s])
2896 adddir(f[:s])
2905 else:
2897 else:
2906 addfile(f)
2898 addfile(f)
2907 return files, dirs
2899 return files, dirs
2908
2900
2909 acceptable = ''
2901 acceptable = ''
2910 if opts['normal']:
2902 if opts['normal']:
2911 acceptable += 'nm'
2903 acceptable += 'nm'
2912 if opts['added']:
2904 if opts['added']:
2913 acceptable += 'a'
2905 acceptable += 'a'
2914 if opts['removed']:
2906 if opts['removed']:
2915 acceptable += 'r'
2907 acceptable += 'r'
2916 cwd = repo.getcwd()
2908 cwd = repo.getcwd()
2917 if not specs:
2909 if not specs:
2918 specs = ['.']
2910 specs = ['.']
2919
2911
2920 files, dirs = set(), set()
2912 files, dirs = set(), set()
2921 for spec in specs:
2913 for spec in specs:
2922 f, d = complete(spec, acceptable or 'nmar')
2914 f, d = complete(spec, acceptable or 'nmar')
2923 files.update(f)
2915 files.update(f)
2924 dirs.update(d)
2916 dirs.update(d)
2925 files.update(dirs)
2917 files.update(dirs)
2926 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2918 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2927 ui.write('\n')
2919 ui.write('\n')
2928
2920
2929 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2921 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2930 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2922 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2931 '''access the pushkey key/value protocol
2923 '''access the pushkey key/value protocol
2932
2924
2933 With two args, list the keys in the given namespace.
2925 With two args, list the keys in the given namespace.
2934
2926
2935 With five args, set a key to new if it currently is set to old.
2927 With five args, set a key to new if it currently is set to old.
2936 Reports success or failure.
2928 Reports success or failure.
2937 '''
2929 '''
2938
2930
2939 target = hg.peer(ui, {}, repopath)
2931 target = hg.peer(ui, {}, repopath)
2940 if keyinfo:
2932 if keyinfo:
2941 key, old, new = keyinfo
2933 key, old, new = keyinfo
2942 r = target.pushkey(namespace, key, old, new)
2934 r = target.pushkey(namespace, key, old, new)
2943 ui.status(str(r) + '\n')
2935 ui.status(str(r) + '\n')
2944 return not r
2936 return not r
2945 else:
2937 else:
2946 for k, v in sorted(target.listkeys(namespace).iteritems()):
2938 for k, v in sorted(target.listkeys(namespace).iteritems()):
2947 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2939 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2948 v.encode('string-escape')))
2940 v.encode('string-escape')))
2949
2941
2950 @command('debugpvec', [], _('A B'))
2942 @command('debugpvec', [], _('A B'))
2951 def debugpvec(ui, repo, a, b=None):
2943 def debugpvec(ui, repo, a, b=None):
2952 ca = scmutil.revsingle(repo, a)
2944 ca = scmutil.revsingle(repo, a)
2953 cb = scmutil.revsingle(repo, b)
2945 cb = scmutil.revsingle(repo, b)
2954 pa = pvec.ctxpvec(ca)
2946 pa = pvec.ctxpvec(ca)
2955 pb = pvec.ctxpvec(cb)
2947 pb = pvec.ctxpvec(cb)
2956 if pa == pb:
2948 if pa == pb:
2957 rel = "="
2949 rel = "="
2958 elif pa > pb:
2950 elif pa > pb:
2959 rel = ">"
2951 rel = ">"
2960 elif pa < pb:
2952 elif pa < pb:
2961 rel = "<"
2953 rel = "<"
2962 elif pa | pb:
2954 elif pa | pb:
2963 rel = "|"
2955 rel = "|"
2964 ui.write(_("a: %s\n") % pa)
2956 ui.write(_("a: %s\n") % pa)
2965 ui.write(_("b: %s\n") % pb)
2957 ui.write(_("b: %s\n") % pb)
2966 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2958 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2967 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2959 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2968 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2960 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2969 pa.distance(pb), rel))
2961 pa.distance(pb), rel))
2970
2962
2971 @command('debugrebuilddirstate|debugrebuildstate',
2963 @command('debugrebuilddirstate|debugrebuildstate',
2972 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2964 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2973 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2965 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2974 'the working copy parent')),
2966 'the working copy parent')),
2975 ],
2967 ],
2976 _('[-r REV]'))
2968 _('[-r REV]'))
2977 def debugrebuilddirstate(ui, repo, rev, **opts):
2969 def debugrebuilddirstate(ui, repo, rev, **opts):
2978 """rebuild the dirstate as it would look like for the given revision
2970 """rebuild the dirstate as it would look like for the given revision
2979
2971
2980 If no revision is specified the first current parent will be used.
2972 If no revision is specified the first current parent will be used.
2981
2973
2982 The dirstate will be set to the files of the given revision.
2974 The dirstate will be set to the files of the given revision.
2983 The actual working directory content or existing dirstate
2975 The actual working directory content or existing dirstate
2984 information such as adds or removes is not considered.
2976 information such as adds or removes is not considered.
2985
2977
2986 ``minimal`` will only rebuild the dirstate status for files that claim to be
2978 ``minimal`` will only rebuild the dirstate status for files that claim to be
2987 tracked but are not in the parent manifest, or that exist in the parent
2979 tracked but are not in the parent manifest, or that exist in the parent
2988 manifest but are not in the dirstate. It will not change adds, removes, or
2980 manifest but are not in the dirstate. It will not change adds, removes, or
2989 modified files that are in the working copy parent.
2981 modified files that are in the working copy parent.
2990
2982
2991 One use of this command is to make the next :hg:`status` invocation
2983 One use of this command is to make the next :hg:`status` invocation
2992 check the actual file content.
2984 check the actual file content.
2993 """
2985 """
2994 ctx = scmutil.revsingle(repo, rev)
2986 ctx = scmutil.revsingle(repo, rev)
2995 with repo.wlock():
2987 with repo.wlock():
2996 dirstate = repo.dirstate
2988 dirstate = repo.dirstate
2997 changedfiles = None
2989 changedfiles = None
2998 # See command doc for what minimal does.
2990 # See command doc for what minimal does.
2999 if opts.get('minimal'):
2991 if opts.get('minimal'):
3000 manifestfiles = set(ctx.manifest().keys())
2992 manifestfiles = set(ctx.manifest().keys())
3001 dirstatefiles = set(dirstate)
2993 dirstatefiles = set(dirstate)
3002 manifestonly = manifestfiles - dirstatefiles
2994 manifestonly = manifestfiles - dirstatefiles
3003 dsonly = dirstatefiles - manifestfiles
2995 dsonly = dirstatefiles - manifestfiles
3004 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2996 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3005 changedfiles = manifestonly | dsnotadded
2997 changedfiles = manifestonly | dsnotadded
3006
2998
3007 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2999 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3008
3000
3009 @command('debugrebuildfncache', [], '')
3001 @command('debugrebuildfncache', [], '')
3010 def debugrebuildfncache(ui, repo):
3002 def debugrebuildfncache(ui, repo):
3011 """rebuild the fncache file"""
3003 """rebuild the fncache file"""
3012 repair.rebuildfncache(ui, repo)
3004 repair.rebuildfncache(ui, repo)
3013
3005
3014 @command('debugrename',
3006 @command('debugrename',
3015 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3007 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3016 _('[-r REV] FILE'))
3008 _('[-r REV] FILE'))
3017 def debugrename(ui, repo, file1, *pats, **opts):
3009 def debugrename(ui, repo, file1, *pats, **opts):
3018 """dump rename information"""
3010 """dump rename information"""
3019
3011
3020 ctx = scmutil.revsingle(repo, opts.get('rev'))
3012 ctx = scmutil.revsingle(repo, opts.get('rev'))
3021 m = scmutil.match(ctx, (file1,) + pats, opts)
3013 m = scmutil.match(ctx, (file1,) + pats, opts)
3022 for abs in ctx.walk(m):
3014 for abs in ctx.walk(m):
3023 fctx = ctx[abs]
3015 fctx = ctx[abs]
3024 o = fctx.filelog().renamed(fctx.filenode())
3016 o = fctx.filelog().renamed(fctx.filenode())
3025 rel = m.rel(abs)
3017 rel = m.rel(abs)
3026 if o:
3018 if o:
3027 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3019 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3028 else:
3020 else:
3029 ui.write(_("%s not renamed\n") % rel)
3021 ui.write(_("%s not renamed\n") % rel)
3030
3022
3031 @command('debugrevlog', debugrevlogopts +
3023 @command('debugrevlog', debugrevlogopts +
3032 [('d', 'dump', False, _('dump index data'))],
3024 [('d', 'dump', False, _('dump index data'))],
3033 _('-c|-m|FILE'),
3025 _('-c|-m|FILE'),
3034 optionalrepo=True)
3026 optionalrepo=True)
3035 def debugrevlog(ui, repo, file_=None, **opts):
3027 def debugrevlog(ui, repo, file_=None, **opts):
3036 """show data and statistics about a revlog"""
3028 """show data and statistics about a revlog"""
3037 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3029 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3038
3030
3039 if opts.get("dump"):
3031 if opts.get("dump"):
3040 numrevs = len(r)
3032 numrevs = len(r)
3041 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3033 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3042 " rawsize totalsize compression heads chainlen\n"))
3034 " rawsize totalsize compression heads chainlen\n"))
3043 ts = 0
3035 ts = 0
3044 heads = set()
3036 heads = set()
3045
3037
3046 for rev in xrange(numrevs):
3038 for rev in xrange(numrevs):
3047 dbase = r.deltaparent(rev)
3039 dbase = r.deltaparent(rev)
3048 if dbase == -1:
3040 if dbase == -1:
3049 dbase = rev
3041 dbase = rev
3050 cbase = r.chainbase(rev)
3042 cbase = r.chainbase(rev)
3051 clen = r.chainlen(rev)
3043 clen = r.chainlen(rev)
3052 p1, p2 = r.parentrevs(rev)
3044 p1, p2 = r.parentrevs(rev)
3053 rs = r.rawsize(rev)
3045 rs = r.rawsize(rev)
3054 ts = ts + rs
3046 ts = ts + rs
3055 heads -= set(r.parentrevs(rev))
3047 heads -= set(r.parentrevs(rev))
3056 heads.add(rev)
3048 heads.add(rev)
3057 try:
3049 try:
3058 compression = ts / r.end(rev)
3050 compression = ts / r.end(rev)
3059 except ZeroDivisionError:
3051 except ZeroDivisionError:
3060 compression = 0
3052 compression = 0
3061 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3053 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3062 "%11d %5d %8d\n" %
3054 "%11d %5d %8d\n" %
3063 (rev, p1, p2, r.start(rev), r.end(rev),
3055 (rev, p1, p2, r.start(rev), r.end(rev),
3064 r.start(dbase), r.start(cbase),
3056 r.start(dbase), r.start(cbase),
3065 r.start(p1), r.start(p2),
3057 r.start(p1), r.start(p2),
3066 rs, ts, compression, len(heads), clen))
3058 rs, ts, compression, len(heads), clen))
3067 return 0
3059 return 0
3068
3060
3069 v = r.version
3061 v = r.version
3070 format = v & 0xFFFF
3062 format = v & 0xFFFF
3071 flags = []
3063 flags = []
3072 gdelta = False
3064 gdelta = False
3073 if v & revlog.REVLOGNGINLINEDATA:
3065 if v & revlog.REVLOGNGINLINEDATA:
3074 flags.append('inline')
3066 flags.append('inline')
3075 if v & revlog.REVLOGGENERALDELTA:
3067 if v & revlog.REVLOGGENERALDELTA:
3076 gdelta = True
3068 gdelta = True
3077 flags.append('generaldelta')
3069 flags.append('generaldelta')
3078 if not flags:
3070 if not flags:
3079 flags = ['(none)']
3071 flags = ['(none)']
3080
3072
3081 nummerges = 0
3073 nummerges = 0
3082 numfull = 0
3074 numfull = 0
3083 numprev = 0
3075 numprev = 0
3084 nump1 = 0
3076 nump1 = 0
3085 nump2 = 0
3077 nump2 = 0
3086 numother = 0
3078 numother = 0
3087 nump1prev = 0
3079 nump1prev = 0
3088 nump2prev = 0
3080 nump2prev = 0
3089 chainlengths = []
3081 chainlengths = []
3090
3082
3091 datasize = [None, 0, 0]
3083 datasize = [None, 0, 0]
3092 fullsize = [None, 0, 0]
3084 fullsize = [None, 0, 0]
3093 deltasize = [None, 0, 0]
3085 deltasize = [None, 0, 0]
3094 chunktypecounts = {}
3086 chunktypecounts = {}
3095 chunktypesizes = {}
3087 chunktypesizes = {}
3096
3088
3097 def addsize(size, l):
3089 def addsize(size, l):
3098 if l[0] is None or size < l[0]:
3090 if l[0] is None or size < l[0]:
3099 l[0] = size
3091 l[0] = size
3100 if size > l[1]:
3092 if size > l[1]:
3101 l[1] = size
3093 l[1] = size
3102 l[2] += size
3094 l[2] += size
3103
3095
3104 numrevs = len(r)
3096 numrevs = len(r)
3105 for rev in xrange(numrevs):
3097 for rev in xrange(numrevs):
3106 p1, p2 = r.parentrevs(rev)
3098 p1, p2 = r.parentrevs(rev)
3107 delta = r.deltaparent(rev)
3099 delta = r.deltaparent(rev)
3108 if format > 0:
3100 if format > 0:
3109 addsize(r.rawsize(rev), datasize)
3101 addsize(r.rawsize(rev), datasize)
3110 if p2 != nullrev:
3102 if p2 != nullrev:
3111 nummerges += 1
3103 nummerges += 1
3112 size = r.length(rev)
3104 size = r.length(rev)
3113 if delta == nullrev:
3105 if delta == nullrev:
3114 chainlengths.append(0)
3106 chainlengths.append(0)
3115 numfull += 1
3107 numfull += 1
3116 addsize(size, fullsize)
3108 addsize(size, fullsize)
3117 else:
3109 else:
3118 chainlengths.append(chainlengths[delta] + 1)
3110 chainlengths.append(chainlengths[delta] + 1)
3119 addsize(size, deltasize)
3111 addsize(size, deltasize)
3120 if delta == rev - 1:
3112 if delta == rev - 1:
3121 numprev += 1
3113 numprev += 1
3122 if delta == p1:
3114 if delta == p1:
3123 nump1prev += 1
3115 nump1prev += 1
3124 elif delta == p2:
3116 elif delta == p2:
3125 nump2prev += 1
3117 nump2prev += 1
3126 elif delta == p1:
3118 elif delta == p1:
3127 nump1 += 1
3119 nump1 += 1
3128 elif delta == p2:
3120 elif delta == p2:
3129 nump2 += 1
3121 nump2 += 1
3130 elif delta != nullrev:
3122 elif delta != nullrev:
3131 numother += 1
3123 numother += 1
3132
3124
3133 # Obtain data on the raw chunks in the revlog.
3125 # Obtain data on the raw chunks in the revlog.
3134 chunk = r._chunkraw(rev, rev)[1]
3126 chunk = r._chunkraw(rev, rev)[1]
3135 if chunk:
3127 if chunk:
3136 chunktype = chunk[0]
3128 chunktype = chunk[0]
3137 else:
3129 else:
3138 chunktype = 'empty'
3130 chunktype = 'empty'
3139
3131
3140 if chunktype not in chunktypecounts:
3132 if chunktype not in chunktypecounts:
3141 chunktypecounts[chunktype] = 0
3133 chunktypecounts[chunktype] = 0
3142 chunktypesizes[chunktype] = 0
3134 chunktypesizes[chunktype] = 0
3143
3135
3144 chunktypecounts[chunktype] += 1
3136 chunktypecounts[chunktype] += 1
3145 chunktypesizes[chunktype] += size
3137 chunktypesizes[chunktype] += size
3146
3138
3147 # Adjust size min value for empty cases
3139 # Adjust size min value for empty cases
3148 for size in (datasize, fullsize, deltasize):
3140 for size in (datasize, fullsize, deltasize):
3149 if size[0] is None:
3141 if size[0] is None:
3150 size[0] = 0
3142 size[0] = 0
3151
3143
3152 numdeltas = numrevs - numfull
3144 numdeltas = numrevs - numfull
3153 numoprev = numprev - nump1prev - nump2prev
3145 numoprev = numprev - nump1prev - nump2prev
3154 totalrawsize = datasize[2]
3146 totalrawsize = datasize[2]
3155 datasize[2] /= numrevs
3147 datasize[2] /= numrevs
3156 fulltotal = fullsize[2]
3148 fulltotal = fullsize[2]
3157 fullsize[2] /= numfull
3149 fullsize[2] /= numfull
3158 deltatotal = deltasize[2]
3150 deltatotal = deltasize[2]
3159 if numrevs - numfull > 0:
3151 if numrevs - numfull > 0:
3160 deltasize[2] /= numrevs - numfull
3152 deltasize[2] /= numrevs - numfull
3161 totalsize = fulltotal + deltatotal
3153 totalsize = fulltotal + deltatotal
3162 avgchainlen = sum(chainlengths) / numrevs
3154 avgchainlen = sum(chainlengths) / numrevs
3163 maxchainlen = max(chainlengths)
3155 maxchainlen = max(chainlengths)
3164 compratio = 1
3156 compratio = 1
3165 if totalsize:
3157 if totalsize:
3166 compratio = totalrawsize / totalsize
3158 compratio = totalrawsize / totalsize
3167
3159
3168 basedfmtstr = '%%%dd\n'
3160 basedfmtstr = '%%%dd\n'
3169 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3161 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3170
3162
3171 def dfmtstr(max):
3163 def dfmtstr(max):
3172 return basedfmtstr % len(str(max))
3164 return basedfmtstr % len(str(max))
3173 def pcfmtstr(max, padding=0):
3165 def pcfmtstr(max, padding=0):
3174 return basepcfmtstr % (len(str(max)), ' ' * padding)
3166 return basepcfmtstr % (len(str(max)), ' ' * padding)
3175
3167
3176 def pcfmt(value, total):
3168 def pcfmt(value, total):
3177 if total:
3169 if total:
3178 return (value, 100 * float(value) / total)
3170 return (value, 100 * float(value) / total)
3179 else:
3171 else:
3180 return value, 100.0
3172 return value, 100.0
3181
3173
3182 ui.write(('format : %d\n') % format)
3174 ui.write(('format : %d\n') % format)
3183 ui.write(('flags : %s\n') % ', '.join(flags))
3175 ui.write(('flags : %s\n') % ', '.join(flags))
3184
3176
3185 ui.write('\n')
3177 ui.write('\n')
3186 fmt = pcfmtstr(totalsize)
3178 fmt = pcfmtstr(totalsize)
3187 fmt2 = dfmtstr(totalsize)
3179 fmt2 = dfmtstr(totalsize)
3188 ui.write(('revisions : ') + fmt2 % numrevs)
3180 ui.write(('revisions : ') + fmt2 % numrevs)
3189 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3181 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3190 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3182 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3191 ui.write(('revisions : ') + fmt2 % numrevs)
3183 ui.write(('revisions : ') + fmt2 % numrevs)
3192 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3184 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3193 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3185 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3194 ui.write(('revision size : ') + fmt2 % totalsize)
3186 ui.write(('revision size : ') + fmt2 % totalsize)
3195 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3187 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3196 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3188 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3197
3189
3198 def fmtchunktype(chunktype):
3190 def fmtchunktype(chunktype):
3199 if chunktype == 'empty':
3191 if chunktype == 'empty':
3200 return ' %s : ' % chunktype
3192 return ' %s : ' % chunktype
3201 elif chunktype in string.ascii_letters:
3193 elif chunktype in string.ascii_letters:
3202 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3194 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3203 else:
3195 else:
3204 return ' 0x%s : ' % hex(chunktype)
3196 return ' 0x%s : ' % hex(chunktype)
3205
3197
3206 ui.write('\n')
3198 ui.write('\n')
3207 ui.write(('chunks : ') + fmt2 % numrevs)
3199 ui.write(('chunks : ') + fmt2 % numrevs)
3208 for chunktype in sorted(chunktypecounts):
3200 for chunktype in sorted(chunktypecounts):
3209 ui.write(fmtchunktype(chunktype))
3201 ui.write(fmtchunktype(chunktype))
3210 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3202 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3211 ui.write(('chunks size : ') + fmt2 % totalsize)
3203 ui.write(('chunks size : ') + fmt2 % totalsize)
3212 for chunktype in sorted(chunktypecounts):
3204 for chunktype in sorted(chunktypecounts):
3213 ui.write(fmtchunktype(chunktype))
3205 ui.write(fmtchunktype(chunktype))
3214 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3206 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3215
3207
3216 ui.write('\n')
3208 ui.write('\n')
3217 fmt = dfmtstr(max(avgchainlen, compratio))
3209 fmt = dfmtstr(max(avgchainlen, compratio))
3218 ui.write(('avg chain length : ') + fmt % avgchainlen)
3210 ui.write(('avg chain length : ') + fmt % avgchainlen)
3219 ui.write(('max chain length : ') + fmt % maxchainlen)
3211 ui.write(('max chain length : ') + fmt % maxchainlen)
3220 ui.write(('compression ratio : ') + fmt % compratio)
3212 ui.write(('compression ratio : ') + fmt % compratio)
3221
3213
3222 if format > 0:
3214 if format > 0:
3223 ui.write('\n')
3215 ui.write('\n')
3224 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3216 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3225 % tuple(datasize))
3217 % tuple(datasize))
3226 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3218 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3227 % tuple(fullsize))
3219 % tuple(fullsize))
3228 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3220 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3229 % tuple(deltasize))
3221 % tuple(deltasize))
3230
3222
3231 if numdeltas > 0:
3223 if numdeltas > 0:
3232 ui.write('\n')
3224 ui.write('\n')
3233 fmt = pcfmtstr(numdeltas)
3225 fmt = pcfmtstr(numdeltas)
3234 fmt2 = pcfmtstr(numdeltas, 4)
3226 fmt2 = pcfmtstr(numdeltas, 4)
3235 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3227 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3236 if numprev > 0:
3228 if numprev > 0:
3237 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3229 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3238 numprev))
3230 numprev))
3239 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3231 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3240 numprev))
3232 numprev))
3241 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3233 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3242 numprev))
3234 numprev))
3243 if gdelta:
3235 if gdelta:
3244 ui.write(('deltas against p1 : ')
3236 ui.write(('deltas against p1 : ')
3245 + fmt % pcfmt(nump1, numdeltas))
3237 + fmt % pcfmt(nump1, numdeltas))
3246 ui.write(('deltas against p2 : ')
3238 ui.write(('deltas against p2 : ')
3247 + fmt % pcfmt(nump2, numdeltas))
3239 + fmt % pcfmt(nump2, numdeltas))
3248 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3240 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3249 numdeltas))
3241 numdeltas))
3250
3242
3251 @command('debugrevspec',
3243 @command('debugrevspec',
3252 [('', 'optimize', None,
3244 [('', 'optimize', None,
3253 _('print parsed tree after optimizing (DEPRECATED)')),
3245 _('print parsed tree after optimizing (DEPRECATED)')),
3254 ('p', 'show-stage', [],
3246 ('p', 'show-stage', [],
3255 _('print parsed tree at the given stage'), _('NAME')),
3247 _('print parsed tree at the given stage'), _('NAME')),
3256 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3248 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3257 ('', 'verify-optimized', False, _('verify optimized result')),
3249 ('', 'verify-optimized', False, _('verify optimized result')),
3258 ],
3250 ],
3259 ('REVSPEC'))
3251 ('REVSPEC'))
3260 def debugrevspec(ui, repo, expr, **opts):
3252 def debugrevspec(ui, repo, expr, **opts):
3261 """parse and apply a revision specification
3253 """parse and apply a revision specification
3262
3254
3263 Use -p/--show-stage option to print the parsed tree at the given stages.
3255 Use -p/--show-stage option to print the parsed tree at the given stages.
3264 Use -p all to print tree at every stage.
3256 Use -p all to print tree at every stage.
3265
3257
3266 Use --verify-optimized to compare the optimized result with the unoptimized
3258 Use --verify-optimized to compare the optimized result with the unoptimized
3267 one. Returns 1 if the optimized result differs.
3259 one. Returns 1 if the optimized result differs.
3268 """
3260 """
3269 stages = [
3261 stages = [
3270 ('parsed', lambda tree: tree),
3262 ('parsed', lambda tree: tree),
3271 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3263 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3272 ('concatenated', revset.foldconcat),
3264 ('concatenated', revset.foldconcat),
3273 ('analyzed', revset.analyze),
3265 ('analyzed', revset.analyze),
3274 ('optimized', revset.optimize),
3266 ('optimized', revset.optimize),
3275 ]
3267 ]
3276 if opts['no_optimized']:
3268 if opts['no_optimized']:
3277 stages = stages[:-1]
3269 stages = stages[:-1]
3278 if opts['verify_optimized'] and opts['no_optimized']:
3270 if opts['verify_optimized'] and opts['no_optimized']:
3279 raise error.Abort(_('cannot use --verify-optimized with '
3271 raise error.Abort(_('cannot use --verify-optimized with '
3280 '--no-optimized'))
3272 '--no-optimized'))
3281 stagenames = set(n for n, f in stages)
3273 stagenames = set(n for n, f in stages)
3282
3274
3283 showalways = set()
3275 showalways = set()
3284 showchanged = set()
3276 showchanged = set()
3285 if ui.verbose and not opts['show_stage']:
3277 if ui.verbose and not opts['show_stage']:
3286 # show parsed tree by --verbose (deprecated)
3278 # show parsed tree by --verbose (deprecated)
3287 showalways.add('parsed')
3279 showalways.add('parsed')
3288 showchanged.update(['expanded', 'concatenated'])
3280 showchanged.update(['expanded', 'concatenated'])
3289 if opts['optimize']:
3281 if opts['optimize']:
3290 showalways.add('optimized')
3282 showalways.add('optimized')
3291 if opts['show_stage'] and opts['optimize']:
3283 if opts['show_stage'] and opts['optimize']:
3292 raise error.Abort(_('cannot use --optimize with --show-stage'))
3284 raise error.Abort(_('cannot use --optimize with --show-stage'))
3293 if opts['show_stage'] == ['all']:
3285 if opts['show_stage'] == ['all']:
3294 showalways.update(stagenames)
3286 showalways.update(stagenames)
3295 else:
3287 else:
3296 for n in opts['show_stage']:
3288 for n in opts['show_stage']:
3297 if n not in stagenames:
3289 if n not in stagenames:
3298 raise error.Abort(_('invalid stage name: %s') % n)
3290 raise error.Abort(_('invalid stage name: %s') % n)
3299 showalways.update(opts['show_stage'])
3291 showalways.update(opts['show_stage'])
3300
3292
3301 treebystage = {}
3293 treebystage = {}
3302 printedtree = None
3294 printedtree = None
3303 tree = revset.parse(expr, lookup=repo.__contains__)
3295 tree = revset.parse(expr, lookup=repo.__contains__)
3304 for n, f in stages:
3296 for n, f in stages:
3305 treebystage[n] = tree = f(tree)
3297 treebystage[n] = tree = f(tree)
3306 if n in showalways or (n in showchanged and tree != printedtree):
3298 if n in showalways or (n in showchanged and tree != printedtree):
3307 if opts['show_stage'] or n != 'parsed':
3299 if opts['show_stage'] or n != 'parsed':
3308 ui.write(("* %s:\n") % n)
3300 ui.write(("* %s:\n") % n)
3309 ui.write(revset.prettyformat(tree), "\n")
3301 ui.write(revset.prettyformat(tree), "\n")
3310 printedtree = tree
3302 printedtree = tree
3311
3303
3312 if opts['verify_optimized']:
3304 if opts['verify_optimized']:
3313 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3305 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3314 brevs = revset.makematcher(treebystage['optimized'])(repo)
3306 brevs = revset.makematcher(treebystage['optimized'])(repo)
3315 if ui.verbose:
3307 if ui.verbose:
3316 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3308 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3317 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3309 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3318 arevs = list(arevs)
3310 arevs = list(arevs)
3319 brevs = list(brevs)
3311 brevs = list(brevs)
3320 if arevs == brevs:
3312 if arevs == brevs:
3321 return 0
3313 return 0
3322 ui.write(('--- analyzed\n'), label='diff.file_a')
3314 ui.write(('--- analyzed\n'), label='diff.file_a')
3323 ui.write(('+++ optimized\n'), label='diff.file_b')
3315 ui.write(('+++ optimized\n'), label='diff.file_b')
3324 sm = difflib.SequenceMatcher(None, arevs, brevs)
3316 sm = difflib.SequenceMatcher(None, arevs, brevs)
3325 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3317 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3326 if tag in ('delete', 'replace'):
3318 if tag in ('delete', 'replace'):
3327 for c in arevs[alo:ahi]:
3319 for c in arevs[alo:ahi]:
3328 ui.write('-%s\n' % c, label='diff.deleted')
3320 ui.write('-%s\n' % c, label='diff.deleted')
3329 if tag in ('insert', 'replace'):
3321 if tag in ('insert', 'replace'):
3330 for c in brevs[blo:bhi]:
3322 for c in brevs[blo:bhi]:
3331 ui.write('+%s\n' % c, label='diff.inserted')
3323 ui.write('+%s\n' % c, label='diff.inserted')
3332 if tag == 'equal':
3324 if tag == 'equal':
3333 for c in arevs[alo:ahi]:
3325 for c in arevs[alo:ahi]:
3334 ui.write(' %s\n' % c)
3326 ui.write(' %s\n' % c)
3335 return 1
3327 return 1
3336
3328
3337 func = revset.makematcher(tree)
3329 func = revset.makematcher(tree)
3338 revs = func(repo)
3330 revs = func(repo)
3339 if ui.verbose:
3331 if ui.verbose:
3340 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3332 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3341 for c in revs:
3333 for c in revs:
3342 ui.write("%s\n" % c)
3334 ui.write("%s\n" % c)
3343
3335
3344 @command('debugsetparents', [], _('REV1 [REV2]'))
3336 @command('debugsetparents', [], _('REV1 [REV2]'))
3345 def debugsetparents(ui, repo, rev1, rev2=None):
3337 def debugsetparents(ui, repo, rev1, rev2=None):
3346 """manually set the parents of the current working directory
3338 """manually set the parents of the current working directory
3347
3339
3348 This is useful for writing repository conversion tools, but should
3340 This is useful for writing repository conversion tools, but should
3349 be used with care. For example, neither the working directory nor the
3341 be used with care. For example, neither the working directory nor the
3350 dirstate is updated, so file status may be incorrect after running this
3342 dirstate is updated, so file status may be incorrect after running this
3351 command.
3343 command.
3352
3344
3353 Returns 0 on success.
3345 Returns 0 on success.
3354 """
3346 """
3355
3347
3356 r1 = scmutil.revsingle(repo, rev1).node()
3348 r1 = scmutil.revsingle(repo, rev1).node()
3357 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3349 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3358
3350
3359 with repo.wlock():
3351 with repo.wlock():
3360 repo.setparents(r1, r2)
3352 repo.setparents(r1, r2)
3361
3353
3362 @command('debugdirstate|debugstate',
3354 @command('debugdirstate|debugstate',
3363 [('', 'nodates', None, _('do not display the saved mtime')),
3355 [('', 'nodates', None, _('do not display the saved mtime')),
3364 ('', 'datesort', None, _('sort by saved mtime'))],
3356 ('', 'datesort', None, _('sort by saved mtime'))],
3365 _('[OPTION]...'))
3357 _('[OPTION]...'))
3366 def debugstate(ui, repo, **opts):
3358 def debugstate(ui, repo, **opts):
3367 """show the contents of the current dirstate"""
3359 """show the contents of the current dirstate"""
3368
3360
3369 nodates = opts.get('nodates')
3361 nodates = opts.get('nodates')
3370 datesort = opts.get('datesort')
3362 datesort = opts.get('datesort')
3371
3363
3372 timestr = ""
3364 timestr = ""
3373 if datesort:
3365 if datesort:
3374 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3366 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3375 else:
3367 else:
3376 keyfunc = None # sort by filename
3368 keyfunc = None # sort by filename
3377 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3369 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3378 if ent[3] == -1:
3370 if ent[3] == -1:
3379 timestr = 'unset '
3371 timestr = 'unset '
3380 elif nodates:
3372 elif nodates:
3381 timestr = 'set '
3373 timestr = 'set '
3382 else:
3374 else:
3383 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3375 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3384 time.localtime(ent[3]))
3376 time.localtime(ent[3]))
3385 if ent[1] & 0o20000:
3377 if ent[1] & 0o20000:
3386 mode = 'lnk'
3378 mode = 'lnk'
3387 else:
3379 else:
3388 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3380 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3389 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3381 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3390 for f in repo.dirstate.copies():
3382 for f in repo.dirstate.copies():
3391 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3383 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3392
3384
3393 @command('debugsub',
3385 @command('debugsub',
3394 [('r', 'rev', '',
3386 [('r', 'rev', '',
3395 _('revision to check'), _('REV'))],
3387 _('revision to check'), _('REV'))],
3396 _('[-r REV] [REV]'))
3388 _('[-r REV] [REV]'))
3397 def debugsub(ui, repo, rev=None):
3389 def debugsub(ui, repo, rev=None):
3398 ctx = scmutil.revsingle(repo, rev, None)
3390 ctx = scmutil.revsingle(repo, rev, None)
3399 for k, v in sorted(ctx.substate.items()):
3391 for k, v in sorted(ctx.substate.items()):
3400 ui.write(('path %s\n') % k)
3392 ui.write(('path %s\n') % k)
3401 ui.write((' source %s\n') % v[0])
3393 ui.write((' source %s\n') % v[0])
3402 ui.write((' revision %s\n') % v[1])
3394 ui.write((' revision %s\n') % v[1])
3403
3395
3404 @command('debugsuccessorssets',
3396 @command('debugsuccessorssets',
3405 [],
3397 [],
3406 _('[REV]'))
3398 _('[REV]'))
3407 def debugsuccessorssets(ui, repo, *revs):
3399 def debugsuccessorssets(ui, repo, *revs):
3408 """show set of successors for revision
3400 """show set of successors for revision
3409
3401
3410 A successors set of changeset A is a consistent group of revisions that
3402 A successors set of changeset A is a consistent group of revisions that
3411 succeed A. It contains non-obsolete changesets only.
3403 succeed A. It contains non-obsolete changesets only.
3412
3404
3413 In most cases a changeset A has a single successors set containing a single
3405 In most cases a changeset A has a single successors set containing a single
3414 successor (changeset A replaced by A').
3406 successor (changeset A replaced by A').
3415
3407
3416 A changeset that is made obsolete with no successors are called "pruned".
3408 A changeset that is made obsolete with no successors are called "pruned".
3417 Such changesets have no successors sets at all.
3409 Such changesets have no successors sets at all.
3418
3410
3419 A changeset that has been "split" will have a successors set containing
3411 A changeset that has been "split" will have a successors set containing
3420 more than one successor.
3412 more than one successor.
3421
3413
3422 A changeset that has been rewritten in multiple different ways is called
3414 A changeset that has been rewritten in multiple different ways is called
3423 "divergent". Such changesets have multiple successor sets (each of which
3415 "divergent". Such changesets have multiple successor sets (each of which
3424 may also be split, i.e. have multiple successors).
3416 may also be split, i.e. have multiple successors).
3425
3417
3426 Results are displayed as follows::
3418 Results are displayed as follows::
3427
3419
3428 <rev1>
3420 <rev1>
3429 <successors-1A>
3421 <successors-1A>
3430 <rev2>
3422 <rev2>
3431 <successors-2A>
3423 <successors-2A>
3432 <successors-2B1> <successors-2B2> <successors-2B3>
3424 <successors-2B1> <successors-2B2> <successors-2B3>
3433
3425
3434 Here rev2 has two possible (i.e. divergent) successors sets. The first
3426 Here rev2 has two possible (i.e. divergent) successors sets. The first
3435 holds one element, whereas the second holds three (i.e. the changeset has
3427 holds one element, whereas the second holds three (i.e. the changeset has
3436 been split).
3428 been split).
3437 """
3429 """
3438 # passed to successorssets caching computation from one call to another
3430 # passed to successorssets caching computation from one call to another
3439 cache = {}
3431 cache = {}
3440 ctx2str = str
3432 ctx2str = str
3441 node2str = short
3433 node2str = short
3442 if ui.debug():
3434 if ui.debug():
3443 def ctx2str(ctx):
3435 def ctx2str(ctx):
3444 return ctx.hex()
3436 return ctx.hex()
3445 node2str = hex
3437 node2str = hex
3446 for rev in scmutil.revrange(repo, revs):
3438 for rev in scmutil.revrange(repo, revs):
3447 ctx = repo[rev]
3439 ctx = repo[rev]
3448 ui.write('%s\n'% ctx2str(ctx))
3440 ui.write('%s\n'% ctx2str(ctx))
3449 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3441 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3450 if succsset:
3442 if succsset:
3451 ui.write(' ')
3443 ui.write(' ')
3452 ui.write(node2str(succsset[0]))
3444 ui.write(node2str(succsset[0]))
3453 for node in succsset[1:]:
3445 for node in succsset[1:]:
3454 ui.write(' ')
3446 ui.write(' ')
3455 ui.write(node2str(node))
3447 ui.write(node2str(node))
3456 ui.write('\n')
3448 ui.write('\n')
3457
3449
3458 @command('debugtemplate',
3450 @command('debugtemplate',
3459 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3451 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3460 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3452 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3461 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3453 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3462 optionalrepo=True)
3454 optionalrepo=True)
3463 def debugtemplate(ui, repo, tmpl, **opts):
3455 def debugtemplate(ui, repo, tmpl, **opts):
3464 """parse and apply a template
3456 """parse and apply a template
3465
3457
3466 If -r/--rev is given, the template is processed as a log template and
3458 If -r/--rev is given, the template is processed as a log template and
3467 applied to the given changesets. Otherwise, it is processed as a generic
3459 applied to the given changesets. Otherwise, it is processed as a generic
3468 template.
3460 template.
3469
3461
3470 Use --verbose to print the parsed tree.
3462 Use --verbose to print the parsed tree.
3471 """
3463 """
3472 revs = None
3464 revs = None
3473 if opts['rev']:
3465 if opts['rev']:
3474 if repo is None:
3466 if repo is None:
3475 raise error.RepoError(_('there is no Mercurial repository here '
3467 raise error.RepoError(_('there is no Mercurial repository here '
3476 '(.hg not found)'))
3468 '(.hg not found)'))
3477 revs = scmutil.revrange(repo, opts['rev'])
3469 revs = scmutil.revrange(repo, opts['rev'])
3478
3470
3479 props = {}
3471 props = {}
3480 for d in opts['define']:
3472 for d in opts['define']:
3481 try:
3473 try:
3482 k, v = (e.strip() for e in d.split('=', 1))
3474 k, v = (e.strip() for e in d.split('=', 1))
3483 if not k:
3475 if not k:
3484 raise ValueError
3476 raise ValueError
3485 props[k] = v
3477 props[k] = v
3486 except ValueError:
3478 except ValueError:
3487 raise error.Abort(_('malformed keyword definition: %s') % d)
3479 raise error.Abort(_('malformed keyword definition: %s') % d)
3488
3480
3489 if ui.verbose:
3481 if ui.verbose:
3490 aliases = ui.configitems('templatealias')
3482 aliases = ui.configitems('templatealias')
3491 tree = templater.parse(tmpl)
3483 tree = templater.parse(tmpl)
3492 ui.note(templater.prettyformat(tree), '\n')
3484 ui.note(templater.prettyformat(tree), '\n')
3493 newtree = templater.expandaliases(tree, aliases)
3485 newtree = templater.expandaliases(tree, aliases)
3494 if newtree != tree:
3486 if newtree != tree:
3495 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3487 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3496
3488
3497 mapfile = None
3489 mapfile = None
3498 if revs is None:
3490 if revs is None:
3499 k = 'debugtemplate'
3491 k = 'debugtemplate'
3500 t = formatter.maketemplater(ui, k, tmpl)
3492 t = formatter.maketemplater(ui, k, tmpl)
3501 ui.write(templater.stringify(t(k, **props)))
3493 ui.write(templater.stringify(t(k, **props)))
3502 else:
3494 else:
3503 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3495 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3504 mapfile, buffered=False)
3496 mapfile, buffered=False)
3505 for r in revs:
3497 for r in revs:
3506 displayer.show(repo[r], **props)
3498 displayer.show(repo[r], **props)
3507 displayer.close()
3499 displayer.close()
3508
3500
3509 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3501 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3510 def debugwalk(ui, repo, *pats, **opts):
3502 def debugwalk(ui, repo, *pats, **opts):
3511 """show how files match on given patterns"""
3503 """show how files match on given patterns"""
3512 m = scmutil.match(repo[None], pats, opts)
3504 m = scmutil.match(repo[None], pats, opts)
3513 items = list(repo.walk(m))
3505 items = list(repo.walk(m))
3514 if not items:
3506 if not items:
3515 return
3507 return
3516 f = lambda fn: fn
3508 f = lambda fn: fn
3517 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3509 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3518 f = lambda fn: util.normpath(fn)
3510 f = lambda fn: util.normpath(fn)
3519 fmt = 'f %%-%ds %%-%ds %%s' % (
3511 fmt = 'f %%-%ds %%-%ds %%s' % (
3520 max([len(abs) for abs in items]),
3512 max([len(abs) for abs in items]),
3521 max([len(m.rel(abs)) for abs in items]))
3513 max([len(m.rel(abs)) for abs in items]))
3522 for abs in items:
3514 for abs in items:
3523 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3515 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3524 ui.write("%s\n" % line.rstrip())
3516 ui.write("%s\n" % line.rstrip())
3525
3517
3526 @command('debugwireargs',
3518 @command('debugwireargs',
3527 [('', 'three', '', 'three'),
3519 [('', 'three', '', 'three'),
3528 ('', 'four', '', 'four'),
3520 ('', 'four', '', 'four'),
3529 ('', 'five', '', 'five'),
3521 ('', 'five', '', 'five'),
3530 ] + remoteopts,
3522 ] + remoteopts,
3531 _('REPO [OPTIONS]... [ONE [TWO]]'),
3523 _('REPO [OPTIONS]... [ONE [TWO]]'),
3532 norepo=True)
3524 norepo=True)
3533 def debugwireargs(ui, repopath, *vals, **opts):
3525 def debugwireargs(ui, repopath, *vals, **opts):
3534 repo = hg.peer(ui, opts, repopath)
3526 repo = hg.peer(ui, opts, repopath)
3535 for opt in remoteopts:
3527 for opt in remoteopts:
3536 del opts[opt[1]]
3528 del opts[opt[1]]
3537 args = {}
3529 args = {}
3538 for k, v in opts.iteritems():
3530 for k, v in opts.iteritems():
3539 if v:
3531 if v:
3540 args[k] = v
3532 args[k] = v
3541 # run twice to check that we don't mess up the stream for the next command
3533 # run twice to check that we don't mess up the stream for the next command
3542 res1 = repo.debugwireargs(*vals, **args)
3534 res1 = repo.debugwireargs(*vals, **args)
3543 res2 = repo.debugwireargs(*vals, **args)
3535 res2 = repo.debugwireargs(*vals, **args)
3544 ui.write("%s\n" % res1)
3536 ui.write("%s\n" % res1)
3545 if res1 != res2:
3537 if res1 != res2:
3546 ui.warn("%s\n" % res2)
3538 ui.warn("%s\n" % res2)
3547
3539
3548 @command('^diff',
3540 @command('^diff',
3549 [('r', 'rev', [], _('revision'), _('REV')),
3541 [('r', 'rev', [], _('revision'), _('REV')),
3550 ('c', 'change', '', _('change made by revision'), _('REV'))
3542 ('c', 'change', '', _('change made by revision'), _('REV'))
3551 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3543 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3552 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3544 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3553 inferrepo=True)
3545 inferrepo=True)
3554 def diff(ui, repo, *pats, **opts):
3546 def diff(ui, repo, *pats, **opts):
3555 """diff repository (or selected files)
3547 """diff repository (or selected files)
3556
3548
3557 Show differences between revisions for the specified files.
3549 Show differences between revisions for the specified files.
3558
3550
3559 Differences between files are shown using the unified diff format.
3551 Differences between files are shown using the unified diff format.
3560
3552
3561 .. note::
3553 .. note::
3562
3554
3563 :hg:`diff` may generate unexpected results for merges, as it will
3555 :hg:`diff` may generate unexpected results for merges, as it will
3564 default to comparing against the working directory's first
3556 default to comparing against the working directory's first
3565 parent changeset if no revisions are specified.
3557 parent changeset if no revisions are specified.
3566
3558
3567 When two revision arguments are given, then changes are shown
3559 When two revision arguments are given, then changes are shown
3568 between those revisions. If only one revision is specified then
3560 between those revisions. If only one revision is specified then
3569 that revision is compared to the working directory, and, when no
3561 that revision is compared to the working directory, and, when no
3570 revisions are specified, the working directory files are compared
3562 revisions are specified, the working directory files are compared
3571 to its first parent.
3563 to its first parent.
3572
3564
3573 Alternatively you can specify -c/--change with a revision to see
3565 Alternatively you can specify -c/--change with a revision to see
3574 the changes in that changeset relative to its first parent.
3566 the changes in that changeset relative to its first parent.
3575
3567
3576 Without the -a/--text option, diff will avoid generating diffs of
3568 Without the -a/--text option, diff will avoid generating diffs of
3577 files it detects as binary. With -a, diff will generate a diff
3569 files it detects as binary. With -a, diff will generate a diff
3578 anyway, probably with undesirable results.
3570 anyway, probably with undesirable results.
3579
3571
3580 Use the -g/--git option to generate diffs in the git extended diff
3572 Use the -g/--git option to generate diffs in the git extended diff
3581 format. For more information, read :hg:`help diffs`.
3573 format. For more information, read :hg:`help diffs`.
3582
3574
3583 .. container:: verbose
3575 .. container:: verbose
3584
3576
3585 Examples:
3577 Examples:
3586
3578
3587 - compare a file in the current working directory to its parent::
3579 - compare a file in the current working directory to its parent::
3588
3580
3589 hg diff foo.c
3581 hg diff foo.c
3590
3582
3591 - compare two historical versions of a directory, with rename info::
3583 - compare two historical versions of a directory, with rename info::
3592
3584
3593 hg diff --git -r 1.0:1.2 lib/
3585 hg diff --git -r 1.0:1.2 lib/
3594
3586
3595 - get change stats relative to the last change on some date::
3587 - get change stats relative to the last change on some date::
3596
3588
3597 hg diff --stat -r "date('may 2')"
3589 hg diff --stat -r "date('may 2')"
3598
3590
3599 - diff all newly-added files that contain a keyword::
3591 - diff all newly-added files that contain a keyword::
3600
3592
3601 hg diff "set:added() and grep(GNU)"
3593 hg diff "set:added() and grep(GNU)"
3602
3594
3603 - compare a revision and its parents::
3595 - compare a revision and its parents::
3604
3596
3605 hg diff -c 9353 # compare against first parent
3597 hg diff -c 9353 # compare against first parent
3606 hg diff -r 9353^:9353 # same using revset syntax
3598 hg diff -r 9353^:9353 # same using revset syntax
3607 hg diff -r 9353^2:9353 # compare against the second parent
3599 hg diff -r 9353^2:9353 # compare against the second parent
3608
3600
3609 Returns 0 on success.
3601 Returns 0 on success.
3610 """
3602 """
3611
3603
3612 revs = opts.get('rev')
3604 revs = opts.get('rev')
3613 change = opts.get('change')
3605 change = opts.get('change')
3614 stat = opts.get('stat')
3606 stat = opts.get('stat')
3615 reverse = opts.get('reverse')
3607 reverse = opts.get('reverse')
3616
3608
3617 if revs and change:
3609 if revs and change:
3618 msg = _('cannot specify --rev and --change at the same time')
3610 msg = _('cannot specify --rev and --change at the same time')
3619 raise error.Abort(msg)
3611 raise error.Abort(msg)
3620 elif change:
3612 elif change:
3621 node2 = scmutil.revsingle(repo, change, None).node()
3613 node2 = scmutil.revsingle(repo, change, None).node()
3622 node1 = repo[node2].p1().node()
3614 node1 = repo[node2].p1().node()
3623 else:
3615 else:
3624 node1, node2 = scmutil.revpair(repo, revs)
3616 node1, node2 = scmutil.revpair(repo, revs)
3625
3617
3626 if reverse:
3618 if reverse:
3627 node1, node2 = node2, node1
3619 node1, node2 = node2, node1
3628
3620
3629 diffopts = patch.diffallopts(ui, opts)
3621 diffopts = patch.diffallopts(ui, opts)
3630 m = scmutil.match(repo[node2], pats, opts)
3622 m = scmutil.match(repo[node2], pats, opts)
3631 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3623 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3632 listsubrepos=opts.get('subrepos'),
3624 listsubrepos=opts.get('subrepos'),
3633 root=opts.get('root'))
3625 root=opts.get('root'))
3634
3626
3635 @command('^export',
3627 @command('^export',
3636 [('o', 'output', '',
3628 [('o', 'output', '',
3637 _('print output to file with formatted name'), _('FORMAT')),
3629 _('print output to file with formatted name'), _('FORMAT')),
3638 ('', 'switch-parent', None, _('diff against the second parent')),
3630 ('', 'switch-parent', None, _('diff against the second parent')),
3639 ('r', 'rev', [], _('revisions to export'), _('REV')),
3631 ('r', 'rev', [], _('revisions to export'), _('REV')),
3640 ] + diffopts,
3632 ] + diffopts,
3641 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3633 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3642 def export(ui, repo, *changesets, **opts):
3634 def export(ui, repo, *changesets, **opts):
3643 """dump the header and diffs for one or more changesets
3635 """dump the header and diffs for one or more changesets
3644
3636
3645 Print the changeset header and diffs for one or more revisions.
3637 Print the changeset header and diffs for one or more revisions.
3646 If no revision is given, the parent of the working directory is used.
3638 If no revision is given, the parent of the working directory is used.
3647
3639
3648 The information shown in the changeset header is: author, date,
3640 The information shown in the changeset header is: author, date,
3649 branch name (if non-default), changeset hash, parent(s) and commit
3641 branch name (if non-default), changeset hash, parent(s) and commit
3650 comment.
3642 comment.
3651
3643
3652 .. note::
3644 .. note::
3653
3645
3654 :hg:`export` may generate unexpected diff output for merge
3646 :hg:`export` may generate unexpected diff output for merge
3655 changesets, as it will compare the merge changeset against its
3647 changesets, as it will compare the merge changeset against its
3656 first parent only.
3648 first parent only.
3657
3649
3658 Output may be to a file, in which case the name of the file is
3650 Output may be to a file, in which case the name of the file is
3659 given using a format string. The formatting rules are as follows:
3651 given using a format string. The formatting rules are as follows:
3660
3652
3661 :``%%``: literal "%" character
3653 :``%%``: literal "%" character
3662 :``%H``: changeset hash (40 hexadecimal digits)
3654 :``%H``: changeset hash (40 hexadecimal digits)
3663 :``%N``: number of patches being generated
3655 :``%N``: number of patches being generated
3664 :``%R``: changeset revision number
3656 :``%R``: changeset revision number
3665 :``%b``: basename of the exporting repository
3657 :``%b``: basename of the exporting repository
3666 :``%h``: short-form changeset hash (12 hexadecimal digits)
3658 :``%h``: short-form changeset hash (12 hexadecimal digits)
3667 :``%m``: first line of the commit message (only alphanumeric characters)
3659 :``%m``: first line of the commit message (only alphanumeric characters)
3668 :``%n``: zero-padded sequence number, starting at 1
3660 :``%n``: zero-padded sequence number, starting at 1
3669 :``%r``: zero-padded changeset revision number
3661 :``%r``: zero-padded changeset revision number
3670
3662
3671 Without the -a/--text option, export will avoid generating diffs
3663 Without the -a/--text option, export will avoid generating diffs
3672 of files it detects as binary. With -a, export will generate a
3664 of files it detects as binary. With -a, export will generate a
3673 diff anyway, probably with undesirable results.
3665 diff anyway, probably with undesirable results.
3674
3666
3675 Use the -g/--git option to generate diffs in the git extended diff
3667 Use the -g/--git option to generate diffs in the git extended diff
3676 format. See :hg:`help diffs` for more information.
3668 format. See :hg:`help diffs` for more information.
3677
3669
3678 With the --switch-parent option, the diff will be against the
3670 With the --switch-parent option, the diff will be against the
3679 second parent. It can be useful to review a merge.
3671 second parent. It can be useful to review a merge.
3680
3672
3681 .. container:: verbose
3673 .. container:: verbose
3682
3674
3683 Examples:
3675 Examples:
3684
3676
3685 - use export and import to transplant a bugfix to the current
3677 - use export and import to transplant a bugfix to the current
3686 branch::
3678 branch::
3687
3679
3688 hg export -r 9353 | hg import -
3680 hg export -r 9353 | hg import -
3689
3681
3690 - export all the changesets between two revisions to a file with
3682 - export all the changesets between two revisions to a file with
3691 rename information::
3683 rename information::
3692
3684
3693 hg export --git -r 123:150 > changes.txt
3685 hg export --git -r 123:150 > changes.txt
3694
3686
3695 - split outgoing changes into a series of patches with
3687 - split outgoing changes into a series of patches with
3696 descriptive names::
3688 descriptive names::
3697
3689
3698 hg export -r "outgoing()" -o "%n-%m.patch"
3690 hg export -r "outgoing()" -o "%n-%m.patch"
3699
3691
3700 Returns 0 on success.
3692 Returns 0 on success.
3701 """
3693 """
3702 changesets += tuple(opts.get('rev', []))
3694 changesets += tuple(opts.get('rev', []))
3703 if not changesets:
3695 if not changesets:
3704 changesets = ['.']
3696 changesets = ['.']
3705 revs = scmutil.revrange(repo, changesets)
3697 revs = scmutil.revrange(repo, changesets)
3706 if not revs:
3698 if not revs:
3707 raise error.Abort(_("export requires at least one changeset"))
3699 raise error.Abort(_("export requires at least one changeset"))
3708 if len(revs) > 1:
3700 if len(revs) > 1:
3709 ui.note(_('exporting patches:\n'))
3701 ui.note(_('exporting patches:\n'))
3710 else:
3702 else:
3711 ui.note(_('exporting patch:\n'))
3703 ui.note(_('exporting patch:\n'))
3712 cmdutil.export(repo, revs, template=opts.get('output'),
3704 cmdutil.export(repo, revs, template=opts.get('output'),
3713 switch_parent=opts.get('switch_parent'),
3705 switch_parent=opts.get('switch_parent'),
3714 opts=patch.diffallopts(ui, opts))
3706 opts=patch.diffallopts(ui, opts))
3715
3707
3716 @command('files',
3708 @command('files',
3717 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3709 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3718 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3710 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3719 ] + walkopts + formatteropts + subrepoopts,
3711 ] + walkopts + formatteropts + subrepoopts,
3720 _('[OPTION]... [FILE]...'))
3712 _('[OPTION]... [FILE]...'))
3721 def files(ui, repo, *pats, **opts):
3713 def files(ui, repo, *pats, **opts):
3722 """list tracked files
3714 """list tracked files
3723
3715
3724 Print files under Mercurial control in the working directory or
3716 Print files under Mercurial control in the working directory or
3725 specified revision for given files (excluding removed files).
3717 specified revision for given files (excluding removed files).
3726 Files can be specified as filenames or filesets.
3718 Files can be specified as filenames or filesets.
3727
3719
3728 If no files are given to match, this command prints the names
3720 If no files are given to match, this command prints the names
3729 of all files under Mercurial control.
3721 of all files under Mercurial control.
3730
3722
3731 .. container:: verbose
3723 .. container:: verbose
3732
3724
3733 Examples:
3725 Examples:
3734
3726
3735 - list all files under the current directory::
3727 - list all files under the current directory::
3736
3728
3737 hg files .
3729 hg files .
3738
3730
3739 - shows sizes and flags for current revision::
3731 - shows sizes and flags for current revision::
3740
3732
3741 hg files -vr .
3733 hg files -vr .
3742
3734
3743 - list all files named README::
3735 - list all files named README::
3744
3736
3745 hg files -I "**/README"
3737 hg files -I "**/README"
3746
3738
3747 - list all binary files::
3739 - list all binary files::
3748
3740
3749 hg files "set:binary()"
3741 hg files "set:binary()"
3750
3742
3751 - find files containing a regular expression::
3743 - find files containing a regular expression::
3752
3744
3753 hg files "set:grep('bob')"
3745 hg files "set:grep('bob')"
3754
3746
3755 - search tracked file contents with xargs and grep::
3747 - search tracked file contents with xargs and grep::
3756
3748
3757 hg files -0 | xargs -0 grep foo
3749 hg files -0 | xargs -0 grep foo
3758
3750
3759 See :hg:`help patterns` and :hg:`help filesets` for more information
3751 See :hg:`help patterns` and :hg:`help filesets` for more information
3760 on specifying file patterns.
3752 on specifying file patterns.
3761
3753
3762 Returns 0 if a match is found, 1 otherwise.
3754 Returns 0 if a match is found, 1 otherwise.
3763
3755
3764 """
3756 """
3765 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3757 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3766
3758
3767 end = '\n'
3759 end = '\n'
3768 if opts.get('print0'):
3760 if opts.get('print0'):
3769 end = '\0'
3761 end = '\0'
3770 fmt = '%s' + end
3762 fmt = '%s' + end
3771
3763
3772 m = scmutil.match(ctx, pats, opts)
3764 m = scmutil.match(ctx, pats, opts)
3773 with ui.formatter('files', opts) as fm:
3765 with ui.formatter('files', opts) as fm:
3774 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3766 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3775
3767
3776 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3768 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3777 def forget(ui, repo, *pats, **opts):
3769 def forget(ui, repo, *pats, **opts):
3778 """forget the specified files on the next commit
3770 """forget the specified files on the next commit
3779
3771
3780 Mark the specified files so they will no longer be tracked
3772 Mark the specified files so they will no longer be tracked
3781 after the next commit.
3773 after the next commit.
3782
3774
3783 This only removes files from the current branch, not from the
3775 This only removes files from the current branch, not from the
3784 entire project history, and it does not delete them from the
3776 entire project history, and it does not delete them from the
3785 working directory.
3777 working directory.
3786
3778
3787 To delete the file from the working directory, see :hg:`remove`.
3779 To delete the file from the working directory, see :hg:`remove`.
3788
3780
3789 To undo a forget before the next commit, see :hg:`add`.
3781 To undo a forget before the next commit, see :hg:`add`.
3790
3782
3791 .. container:: verbose
3783 .. container:: verbose
3792
3784
3793 Examples:
3785 Examples:
3794
3786
3795 - forget newly-added binary files::
3787 - forget newly-added binary files::
3796
3788
3797 hg forget "set:added() and binary()"
3789 hg forget "set:added() and binary()"
3798
3790
3799 - forget files that would be excluded by .hgignore::
3791 - forget files that would be excluded by .hgignore::
3800
3792
3801 hg forget "set:hgignore()"
3793 hg forget "set:hgignore()"
3802
3794
3803 Returns 0 on success.
3795 Returns 0 on success.
3804 """
3796 """
3805
3797
3806 if not pats:
3798 if not pats:
3807 raise error.Abort(_('no files specified'))
3799 raise error.Abort(_('no files specified'))
3808
3800
3809 m = scmutil.match(repo[None], pats, opts)
3801 m = scmutil.match(repo[None], pats, opts)
3810 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3802 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3811 return rejected and 1 or 0
3803 return rejected and 1 or 0
3812
3804
3813 @command(
3805 @command(
3814 'graft',
3806 'graft',
3815 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3807 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3816 ('c', 'continue', False, _('resume interrupted graft')),
3808 ('c', 'continue', False, _('resume interrupted graft')),
3817 ('e', 'edit', False, _('invoke editor on commit messages')),
3809 ('e', 'edit', False, _('invoke editor on commit messages')),
3818 ('', 'log', None, _('append graft info to log message')),
3810 ('', 'log', None, _('append graft info to log message')),
3819 ('f', 'force', False, _('force graft')),
3811 ('f', 'force', False, _('force graft')),
3820 ('D', 'currentdate', False,
3812 ('D', 'currentdate', False,
3821 _('record the current date as commit date')),
3813 _('record the current date as commit date')),
3822 ('U', 'currentuser', False,
3814 ('U', 'currentuser', False,
3823 _('record the current user as committer'), _('DATE'))]
3815 _('record the current user as committer'), _('DATE'))]
3824 + commitopts2 + mergetoolopts + dryrunopts,
3816 + commitopts2 + mergetoolopts + dryrunopts,
3825 _('[OPTION]... [-r REV]... REV...'))
3817 _('[OPTION]... [-r REV]... REV...'))
3826 def graft(ui, repo, *revs, **opts):
3818 def graft(ui, repo, *revs, **opts):
3827 '''copy changes from other branches onto the current branch
3819 '''copy changes from other branches onto the current branch
3828
3820
3829 This command uses Mercurial's merge logic to copy individual
3821 This command uses Mercurial's merge logic to copy individual
3830 changes from other branches without merging branches in the
3822 changes from other branches without merging branches in the
3831 history graph. This is sometimes known as 'backporting' or
3823 history graph. This is sometimes known as 'backporting' or
3832 'cherry-picking'. By default, graft will copy user, date, and
3824 'cherry-picking'. By default, graft will copy user, date, and
3833 description from the source changesets.
3825 description from the source changesets.
3834
3826
3835 Changesets that are ancestors of the current revision, that have
3827 Changesets that are ancestors of the current revision, that have
3836 already been grafted, or that are merges will be skipped.
3828 already been grafted, or that are merges will be skipped.
3837
3829
3838 If --log is specified, log messages will have a comment appended
3830 If --log is specified, log messages will have a comment appended
3839 of the form::
3831 of the form::
3840
3832
3841 (grafted from CHANGESETHASH)
3833 (grafted from CHANGESETHASH)
3842
3834
3843 If --force is specified, revisions will be grafted even if they
3835 If --force is specified, revisions will be grafted even if they
3844 are already ancestors of or have been grafted to the destination.
3836 are already ancestors of or have been grafted to the destination.
3845 This is useful when the revisions have since been backed out.
3837 This is useful when the revisions have since been backed out.
3846
3838
3847 If a graft merge results in conflicts, the graft process is
3839 If a graft merge results in conflicts, the graft process is
3848 interrupted so that the current merge can be manually resolved.
3840 interrupted so that the current merge can be manually resolved.
3849 Once all conflicts are addressed, the graft process can be
3841 Once all conflicts are addressed, the graft process can be
3850 continued with the -c/--continue option.
3842 continued with the -c/--continue option.
3851
3843
3852 .. note::
3844 .. note::
3853
3845
3854 The -c/--continue option does not reapply earlier options, except
3846 The -c/--continue option does not reapply earlier options, except
3855 for --force.
3847 for --force.
3856
3848
3857 .. container:: verbose
3849 .. container:: verbose
3858
3850
3859 Examples:
3851 Examples:
3860
3852
3861 - copy a single change to the stable branch and edit its description::
3853 - copy a single change to the stable branch and edit its description::
3862
3854
3863 hg update stable
3855 hg update stable
3864 hg graft --edit 9393
3856 hg graft --edit 9393
3865
3857
3866 - graft a range of changesets with one exception, updating dates::
3858 - graft a range of changesets with one exception, updating dates::
3867
3859
3868 hg graft -D "2085::2093 and not 2091"
3860 hg graft -D "2085::2093 and not 2091"
3869
3861
3870 - continue a graft after resolving conflicts::
3862 - continue a graft after resolving conflicts::
3871
3863
3872 hg graft -c
3864 hg graft -c
3873
3865
3874 - show the source of a grafted changeset::
3866 - show the source of a grafted changeset::
3875
3867
3876 hg log --debug -r .
3868 hg log --debug -r .
3877
3869
3878 - show revisions sorted by date::
3870 - show revisions sorted by date::
3879
3871
3880 hg log -r "sort(all(), date)"
3872 hg log -r "sort(all(), date)"
3881
3873
3882 See :hg:`help revisions` and :hg:`help revsets` for more about
3874 See :hg:`help revisions` and :hg:`help revsets` for more about
3883 specifying revisions.
3875 specifying revisions.
3884
3876
3885 Returns 0 on successful completion.
3877 Returns 0 on successful completion.
3886 '''
3878 '''
3887 with repo.wlock():
3879 with repo.wlock():
3888 return _dograft(ui, repo, *revs, **opts)
3880 return _dograft(ui, repo, *revs, **opts)
3889
3881
3890 def _dograft(ui, repo, *revs, **opts):
3882 def _dograft(ui, repo, *revs, **opts):
3891 if revs and opts.get('rev'):
3883 if revs and opts.get('rev'):
3892 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3884 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3893 'revision ordering!\n'))
3885 'revision ordering!\n'))
3894
3886
3895 revs = list(revs)
3887 revs = list(revs)
3896 revs.extend(opts.get('rev'))
3888 revs.extend(opts.get('rev'))
3897
3889
3898 if not opts.get('user') and opts.get('currentuser'):
3890 if not opts.get('user') and opts.get('currentuser'):
3899 opts['user'] = ui.username()
3891 opts['user'] = ui.username()
3900 if not opts.get('date') and opts.get('currentdate'):
3892 if not opts.get('date') and opts.get('currentdate'):
3901 opts['date'] = "%d %d" % util.makedate()
3893 opts['date'] = "%d %d" % util.makedate()
3902
3894
3903 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3895 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3904
3896
3905 cont = False
3897 cont = False
3906 if opts.get('continue'):
3898 if opts.get('continue'):
3907 cont = True
3899 cont = True
3908 if revs:
3900 if revs:
3909 raise error.Abort(_("can't specify --continue and revisions"))
3901 raise error.Abort(_("can't specify --continue and revisions"))
3910 # read in unfinished revisions
3902 # read in unfinished revisions
3911 try:
3903 try:
3912 nodes = repo.vfs.read('graftstate').splitlines()
3904 nodes = repo.vfs.read('graftstate').splitlines()
3913 revs = [repo[node].rev() for node in nodes]
3905 revs = [repo[node].rev() for node in nodes]
3914 except IOError as inst:
3906 except IOError as inst:
3915 if inst.errno != errno.ENOENT:
3907 if inst.errno != errno.ENOENT:
3916 raise
3908 raise
3917 cmdutil.wrongtooltocontinue(repo, _('graft'))
3909 cmdutil.wrongtooltocontinue(repo, _('graft'))
3918 else:
3910 else:
3919 cmdutil.checkunfinished(repo)
3911 cmdutil.checkunfinished(repo)
3920 cmdutil.bailifchanged(repo)
3912 cmdutil.bailifchanged(repo)
3921 if not revs:
3913 if not revs:
3922 raise error.Abort(_('no revisions specified'))
3914 raise error.Abort(_('no revisions specified'))
3923 revs = scmutil.revrange(repo, revs)
3915 revs = scmutil.revrange(repo, revs)
3924
3916
3925 skipped = set()
3917 skipped = set()
3926 # check for merges
3918 # check for merges
3927 for rev in repo.revs('%ld and merge()', revs):
3919 for rev in repo.revs('%ld and merge()', revs):
3928 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3920 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3929 skipped.add(rev)
3921 skipped.add(rev)
3930 revs = [r for r in revs if r not in skipped]
3922 revs = [r for r in revs if r not in skipped]
3931 if not revs:
3923 if not revs:
3932 return -1
3924 return -1
3933
3925
3934 # Don't check in the --continue case, in effect retaining --force across
3926 # Don't check in the --continue case, in effect retaining --force across
3935 # --continues. That's because without --force, any revisions we decided to
3927 # --continues. That's because without --force, any revisions we decided to
3936 # skip would have been filtered out here, so they wouldn't have made their
3928 # skip would have been filtered out here, so they wouldn't have made their
3937 # way to the graftstate. With --force, any revisions we would have otherwise
3929 # way to the graftstate. With --force, any revisions we would have otherwise
3938 # skipped would not have been filtered out, and if they hadn't been applied
3930 # skipped would not have been filtered out, and if they hadn't been applied
3939 # already, they'd have been in the graftstate.
3931 # already, they'd have been in the graftstate.
3940 if not (cont or opts.get('force')):
3932 if not (cont or opts.get('force')):
3941 # check for ancestors of dest branch
3933 # check for ancestors of dest branch
3942 crev = repo['.'].rev()
3934 crev = repo['.'].rev()
3943 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3935 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3944 # XXX make this lazy in the future
3936 # XXX make this lazy in the future
3945 # don't mutate while iterating, create a copy
3937 # don't mutate while iterating, create a copy
3946 for rev in list(revs):
3938 for rev in list(revs):
3947 if rev in ancestors:
3939 if rev in ancestors:
3948 ui.warn(_('skipping ancestor revision %d:%s\n') %
3940 ui.warn(_('skipping ancestor revision %d:%s\n') %
3949 (rev, repo[rev]))
3941 (rev, repo[rev]))
3950 # XXX remove on list is slow
3942 # XXX remove on list is slow
3951 revs.remove(rev)
3943 revs.remove(rev)
3952 if not revs:
3944 if not revs:
3953 return -1
3945 return -1
3954
3946
3955 # analyze revs for earlier grafts
3947 # analyze revs for earlier grafts
3956 ids = {}
3948 ids = {}
3957 for ctx in repo.set("%ld", revs):
3949 for ctx in repo.set("%ld", revs):
3958 ids[ctx.hex()] = ctx.rev()
3950 ids[ctx.hex()] = ctx.rev()
3959 n = ctx.extra().get('source')
3951 n = ctx.extra().get('source')
3960 if n:
3952 if n:
3961 ids[n] = ctx.rev()
3953 ids[n] = ctx.rev()
3962
3954
3963 # check ancestors for earlier grafts
3955 # check ancestors for earlier grafts
3964 ui.debug('scanning for duplicate grafts\n')
3956 ui.debug('scanning for duplicate grafts\n')
3965
3957
3966 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3958 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3967 ctx = repo[rev]
3959 ctx = repo[rev]
3968 n = ctx.extra().get('source')
3960 n = ctx.extra().get('source')
3969 if n in ids:
3961 if n in ids:
3970 try:
3962 try:
3971 r = repo[n].rev()
3963 r = repo[n].rev()
3972 except error.RepoLookupError:
3964 except error.RepoLookupError:
3973 r = None
3965 r = None
3974 if r in revs:
3966 if r in revs:
3975 ui.warn(_('skipping revision %d:%s '
3967 ui.warn(_('skipping revision %d:%s '
3976 '(already grafted to %d:%s)\n')
3968 '(already grafted to %d:%s)\n')
3977 % (r, repo[r], rev, ctx))
3969 % (r, repo[r], rev, ctx))
3978 revs.remove(r)
3970 revs.remove(r)
3979 elif ids[n] in revs:
3971 elif ids[n] in revs:
3980 if r is None:
3972 if r is None:
3981 ui.warn(_('skipping already grafted revision %d:%s '
3973 ui.warn(_('skipping already grafted revision %d:%s '
3982 '(%d:%s also has unknown origin %s)\n')
3974 '(%d:%s also has unknown origin %s)\n')
3983 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3975 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3984 else:
3976 else:
3985 ui.warn(_('skipping already grafted revision %d:%s '
3977 ui.warn(_('skipping already grafted revision %d:%s '
3986 '(%d:%s also has origin %d:%s)\n')
3978 '(%d:%s also has origin %d:%s)\n')
3987 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3979 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3988 revs.remove(ids[n])
3980 revs.remove(ids[n])
3989 elif ctx.hex() in ids:
3981 elif ctx.hex() in ids:
3990 r = ids[ctx.hex()]
3982 r = ids[ctx.hex()]
3991 ui.warn(_('skipping already grafted revision %d:%s '
3983 ui.warn(_('skipping already grafted revision %d:%s '
3992 '(was grafted from %d:%s)\n') %
3984 '(was grafted from %d:%s)\n') %
3993 (r, repo[r], rev, ctx))
3985 (r, repo[r], rev, ctx))
3994 revs.remove(r)
3986 revs.remove(r)
3995 if not revs:
3987 if not revs:
3996 return -1
3988 return -1
3997
3989
3998 for pos, ctx in enumerate(repo.set("%ld", revs)):
3990 for pos, ctx in enumerate(repo.set("%ld", revs)):
3999 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3991 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4000 ctx.description().split('\n', 1)[0])
3992 ctx.description().split('\n', 1)[0])
4001 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3993 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4002 if names:
3994 if names:
4003 desc += ' (%s)' % ' '.join(names)
3995 desc += ' (%s)' % ' '.join(names)
4004 ui.status(_('grafting %s\n') % desc)
3996 ui.status(_('grafting %s\n') % desc)
4005 if opts.get('dry_run'):
3997 if opts.get('dry_run'):
4006 continue
3998 continue
4007
3999
4008 source = ctx.extra().get('source')
4000 source = ctx.extra().get('source')
4009 extra = {}
4001 extra = {}
4010 if source:
4002 if source:
4011 extra['source'] = source
4003 extra['source'] = source
4012 extra['intermediate-source'] = ctx.hex()
4004 extra['intermediate-source'] = ctx.hex()
4013 else:
4005 else:
4014 extra['source'] = ctx.hex()
4006 extra['source'] = ctx.hex()
4015 user = ctx.user()
4007 user = ctx.user()
4016 if opts.get('user'):
4008 if opts.get('user'):
4017 user = opts['user']
4009 user = opts['user']
4018 date = ctx.date()
4010 date = ctx.date()
4019 if opts.get('date'):
4011 if opts.get('date'):
4020 date = opts['date']
4012 date = opts['date']
4021 message = ctx.description()
4013 message = ctx.description()
4022 if opts.get('log'):
4014 if opts.get('log'):
4023 message += '\n(grafted from %s)' % ctx.hex()
4015 message += '\n(grafted from %s)' % ctx.hex()
4024
4016
4025 # we don't merge the first commit when continuing
4017 # we don't merge the first commit when continuing
4026 if not cont:
4018 if not cont:
4027 # perform the graft merge with p1(rev) as 'ancestor'
4019 # perform the graft merge with p1(rev) as 'ancestor'
4028 try:
4020 try:
4029 # ui.forcemerge is an internal variable, do not document
4021 # ui.forcemerge is an internal variable, do not document
4030 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4022 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4031 'graft')
4023 'graft')
4032 stats = mergemod.graft(repo, ctx, ctx.p1(),
4024 stats = mergemod.graft(repo, ctx, ctx.p1(),
4033 ['local', 'graft'])
4025 ['local', 'graft'])
4034 finally:
4026 finally:
4035 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4027 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4036 # report any conflicts
4028 # report any conflicts
4037 if stats and stats[3] > 0:
4029 if stats and stats[3] > 0:
4038 # write out state for --continue
4030 # write out state for --continue
4039 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4031 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4040 repo.vfs.write('graftstate', ''.join(nodelines))
4032 repo.vfs.write('graftstate', ''.join(nodelines))
4041 extra = ''
4033 extra = ''
4042 if opts.get('user'):
4034 if opts.get('user'):
4043 extra += ' --user %s' % util.shellquote(opts['user'])
4035 extra += ' --user %s' % util.shellquote(opts['user'])
4044 if opts.get('date'):
4036 if opts.get('date'):
4045 extra += ' --date %s' % util.shellquote(opts['date'])
4037 extra += ' --date %s' % util.shellquote(opts['date'])
4046 if opts.get('log'):
4038 if opts.get('log'):
4047 extra += ' --log'
4039 extra += ' --log'
4048 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4040 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4049 raise error.Abort(
4041 raise error.Abort(
4050 _("unresolved conflicts, can't continue"),
4042 _("unresolved conflicts, can't continue"),
4051 hint=hint)
4043 hint=hint)
4052 else:
4044 else:
4053 cont = False
4045 cont = False
4054
4046
4055 # commit
4047 # commit
4056 node = repo.commit(text=message, user=user,
4048 node = repo.commit(text=message, user=user,
4057 date=date, extra=extra, editor=editor)
4049 date=date, extra=extra, editor=editor)
4058 if node is None:
4050 if node is None:
4059 ui.warn(
4051 ui.warn(
4060 _('note: graft of %d:%s created no changes to commit\n') %
4052 _('note: graft of %d:%s created no changes to commit\n') %
4061 (ctx.rev(), ctx))
4053 (ctx.rev(), ctx))
4062
4054
4063 # remove state when we complete successfully
4055 # remove state when we complete successfully
4064 if not opts.get('dry_run'):
4056 if not opts.get('dry_run'):
4065 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4057 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4066
4058
4067 return 0
4059 return 0
4068
4060
4069 @command('grep',
4061 @command('grep',
4070 [('0', 'print0', None, _('end fields with NUL')),
4062 [('0', 'print0', None, _('end fields with NUL')),
4071 ('', 'all', None, _('print all revisions that match')),
4063 ('', 'all', None, _('print all revisions that match')),
4072 ('a', 'text', None, _('treat all files as text')),
4064 ('a', 'text', None, _('treat all files as text')),
4073 ('f', 'follow', None,
4065 ('f', 'follow', None,
4074 _('follow changeset history,'
4066 _('follow changeset history,'
4075 ' or file history across copies and renames')),
4067 ' or file history across copies and renames')),
4076 ('i', 'ignore-case', None, _('ignore case when matching')),
4068 ('i', 'ignore-case', None, _('ignore case when matching')),
4077 ('l', 'files-with-matches', None,
4069 ('l', 'files-with-matches', None,
4078 _('print only filenames and revisions that match')),
4070 _('print only filenames and revisions that match')),
4079 ('n', 'line-number', None, _('print matching line numbers')),
4071 ('n', 'line-number', None, _('print matching line numbers')),
4080 ('r', 'rev', [],
4072 ('r', 'rev', [],
4081 _('only search files changed within revision range'), _('REV')),
4073 _('only search files changed within revision range'), _('REV')),
4082 ('u', 'user', None, _('list the author (long with -v)')),
4074 ('u', 'user', None, _('list the author (long with -v)')),
4083 ('d', 'date', None, _('list the date (short with -q)')),
4075 ('d', 'date', None, _('list the date (short with -q)')),
4084 ] + formatteropts + walkopts,
4076 ] + formatteropts + walkopts,
4085 _('[OPTION]... PATTERN [FILE]...'),
4077 _('[OPTION]... PATTERN [FILE]...'),
4086 inferrepo=True)
4078 inferrepo=True)
4087 def grep(ui, repo, pattern, *pats, **opts):
4079 def grep(ui, repo, pattern, *pats, **opts):
4088 """search revision history for a pattern in specified files
4080 """search revision history for a pattern in specified files
4089
4081
4090 Search revision history for a regular expression in the specified
4082 Search revision history for a regular expression in the specified
4091 files or the entire project.
4083 files or the entire project.
4092
4084
4093 By default, grep prints the most recent revision number for each
4085 By default, grep prints the most recent revision number for each
4094 file in which it finds a match. To get it to print every revision
4086 file in which it finds a match. To get it to print every revision
4095 that contains a change in match status ("-" for a match that becomes
4087 that contains a change in match status ("-" for a match that becomes
4096 a non-match, or "+" for a non-match that becomes a match), use the
4088 a non-match, or "+" for a non-match that becomes a match), use the
4097 --all flag.
4089 --all flag.
4098
4090
4099 PATTERN can be any Python (roughly Perl-compatible) regular
4091 PATTERN can be any Python (roughly Perl-compatible) regular
4100 expression.
4092 expression.
4101
4093
4102 If no FILEs are specified (and -f/--follow isn't set), all files in
4094 If no FILEs are specified (and -f/--follow isn't set), all files in
4103 the repository are searched, including those that don't exist in the
4095 the repository are searched, including those that don't exist in the
4104 current branch or have been deleted in a prior changeset.
4096 current branch or have been deleted in a prior changeset.
4105
4097
4106 Returns 0 if a match is found, 1 otherwise.
4098 Returns 0 if a match is found, 1 otherwise.
4107 """
4099 """
4108 reflags = re.M
4100 reflags = re.M
4109 if opts.get('ignore_case'):
4101 if opts.get('ignore_case'):
4110 reflags |= re.I
4102 reflags |= re.I
4111 try:
4103 try:
4112 regexp = util.re.compile(pattern, reflags)
4104 regexp = util.re.compile(pattern, reflags)
4113 except re.error as inst:
4105 except re.error as inst:
4114 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4106 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4115 return 1
4107 return 1
4116 sep, eol = ':', '\n'
4108 sep, eol = ':', '\n'
4117 if opts.get('print0'):
4109 if opts.get('print0'):
4118 sep = eol = '\0'
4110 sep = eol = '\0'
4119
4111
4120 getfile = util.lrucachefunc(repo.file)
4112 getfile = util.lrucachefunc(repo.file)
4121
4113
4122 def matchlines(body):
4114 def matchlines(body):
4123 begin = 0
4115 begin = 0
4124 linenum = 0
4116 linenum = 0
4125 while begin < len(body):
4117 while begin < len(body):
4126 match = regexp.search(body, begin)
4118 match = regexp.search(body, begin)
4127 if not match:
4119 if not match:
4128 break
4120 break
4129 mstart, mend = match.span()
4121 mstart, mend = match.span()
4130 linenum += body.count('\n', begin, mstart) + 1
4122 linenum += body.count('\n', begin, mstart) + 1
4131 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4123 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4132 begin = body.find('\n', mend) + 1 or len(body) + 1
4124 begin = body.find('\n', mend) + 1 or len(body) + 1
4133 lend = begin - 1
4125 lend = begin - 1
4134 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4126 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4135
4127
4136 class linestate(object):
4128 class linestate(object):
4137 def __init__(self, line, linenum, colstart, colend):
4129 def __init__(self, line, linenum, colstart, colend):
4138 self.line = line
4130 self.line = line
4139 self.linenum = linenum
4131 self.linenum = linenum
4140 self.colstart = colstart
4132 self.colstart = colstart
4141 self.colend = colend
4133 self.colend = colend
4142
4134
4143 def __hash__(self):
4135 def __hash__(self):
4144 return hash((self.linenum, self.line))
4136 return hash((self.linenum, self.line))
4145
4137
4146 def __eq__(self, other):
4138 def __eq__(self, other):
4147 return self.line == other.line
4139 return self.line == other.line
4148
4140
4149 def findpos(self):
4141 def findpos(self):
4150 """Iterate all (start, end) indices of matches"""
4142 """Iterate all (start, end) indices of matches"""
4151 yield self.colstart, self.colend
4143 yield self.colstart, self.colend
4152 p = self.colend
4144 p = self.colend
4153 while p < len(self.line):
4145 while p < len(self.line):
4154 m = regexp.search(self.line, p)
4146 m = regexp.search(self.line, p)
4155 if not m:
4147 if not m:
4156 break
4148 break
4157 yield m.span()
4149 yield m.span()
4158 p = m.end()
4150 p = m.end()
4159
4151
4160 matches = {}
4152 matches = {}
4161 copies = {}
4153 copies = {}
4162 def grepbody(fn, rev, body):
4154 def grepbody(fn, rev, body):
4163 matches[rev].setdefault(fn, [])
4155 matches[rev].setdefault(fn, [])
4164 m = matches[rev][fn]
4156 m = matches[rev][fn]
4165 for lnum, cstart, cend, line in matchlines(body):
4157 for lnum, cstart, cend, line in matchlines(body):
4166 s = linestate(line, lnum, cstart, cend)
4158 s = linestate(line, lnum, cstart, cend)
4167 m.append(s)
4159 m.append(s)
4168
4160
4169 def difflinestates(a, b):
4161 def difflinestates(a, b):
4170 sm = difflib.SequenceMatcher(None, a, b)
4162 sm = difflib.SequenceMatcher(None, a, b)
4171 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4163 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4172 if tag == 'insert':
4164 if tag == 'insert':
4173 for i in xrange(blo, bhi):
4165 for i in xrange(blo, bhi):
4174 yield ('+', b[i])
4166 yield ('+', b[i])
4175 elif tag == 'delete':
4167 elif tag == 'delete':
4176 for i in xrange(alo, ahi):
4168 for i in xrange(alo, ahi):
4177 yield ('-', a[i])
4169 yield ('-', a[i])
4178 elif tag == 'replace':
4170 elif tag == 'replace':
4179 for i in xrange(alo, ahi):
4171 for i in xrange(alo, ahi):
4180 yield ('-', a[i])
4172 yield ('-', a[i])
4181 for i in xrange(blo, bhi):
4173 for i in xrange(blo, bhi):
4182 yield ('+', b[i])
4174 yield ('+', b[i])
4183
4175
4184 def display(fm, fn, ctx, pstates, states):
4176 def display(fm, fn, ctx, pstates, states):
4185 rev = ctx.rev()
4177 rev = ctx.rev()
4186 if fm.isplain():
4178 if fm.isplain():
4187 formatuser = ui.shortuser
4179 formatuser = ui.shortuser
4188 else:
4180 else:
4189 formatuser = str
4181 formatuser = str
4190 if ui.quiet:
4182 if ui.quiet:
4191 datefmt = '%Y-%m-%d'
4183 datefmt = '%Y-%m-%d'
4192 else:
4184 else:
4193 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4185 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4194 found = False
4186 found = False
4195 @util.cachefunc
4187 @util.cachefunc
4196 def binary():
4188 def binary():
4197 flog = getfile(fn)
4189 flog = getfile(fn)
4198 return util.binary(flog.read(ctx.filenode(fn)))
4190 return util.binary(flog.read(ctx.filenode(fn)))
4199
4191
4200 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4192 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4201 if opts.get('all'):
4193 if opts.get('all'):
4202 iter = difflinestates(pstates, states)
4194 iter = difflinestates(pstates, states)
4203 else:
4195 else:
4204 iter = [('', l) for l in states]
4196 iter = [('', l) for l in states]
4205 for change, l in iter:
4197 for change, l in iter:
4206 fm.startitem()
4198 fm.startitem()
4207 fm.data(node=fm.hexfunc(ctx.node()))
4199 fm.data(node=fm.hexfunc(ctx.node()))
4208 cols = [
4200 cols = [
4209 ('filename', fn, True),
4201 ('filename', fn, True),
4210 ('rev', rev, True),
4202 ('rev', rev, True),
4211 ('linenumber', l.linenum, opts.get('line_number')),
4203 ('linenumber', l.linenum, opts.get('line_number')),
4212 ]
4204 ]
4213 if opts.get('all'):
4205 if opts.get('all'):
4214 cols.append(('change', change, True))
4206 cols.append(('change', change, True))
4215 cols.extend([
4207 cols.extend([
4216 ('user', formatuser(ctx.user()), opts.get('user')),
4208 ('user', formatuser(ctx.user()), opts.get('user')),
4217 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4209 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4218 ])
4210 ])
4219 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4211 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4220 for name, data, cond in cols:
4212 for name, data, cond in cols:
4221 field = fieldnamemap.get(name, name)
4213 field = fieldnamemap.get(name, name)
4222 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4214 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4223 if cond and name != lastcol:
4215 if cond and name != lastcol:
4224 fm.plain(sep, label='grep.sep')
4216 fm.plain(sep, label='grep.sep')
4225 if not opts.get('files_with_matches'):
4217 if not opts.get('files_with_matches'):
4226 fm.plain(sep, label='grep.sep')
4218 fm.plain(sep, label='grep.sep')
4227 if not opts.get('text') and binary():
4219 if not opts.get('text') and binary():
4228 fm.plain(_(" Binary file matches"))
4220 fm.plain(_(" Binary file matches"))
4229 else:
4221 else:
4230 displaymatches(fm.nested('texts'), l)
4222 displaymatches(fm.nested('texts'), l)
4231 fm.plain(eol)
4223 fm.plain(eol)
4232 found = True
4224 found = True
4233 if opts.get('files_with_matches'):
4225 if opts.get('files_with_matches'):
4234 break
4226 break
4235 return found
4227 return found
4236
4228
4237 def displaymatches(fm, l):
4229 def displaymatches(fm, l):
4238 p = 0
4230 p = 0
4239 for s, e in l.findpos():
4231 for s, e in l.findpos():
4240 if p < s:
4232 if p < s:
4241 fm.startitem()
4233 fm.startitem()
4242 fm.write('text', '%s', l.line[p:s])
4234 fm.write('text', '%s', l.line[p:s])
4243 fm.data(matched=False)
4235 fm.data(matched=False)
4244 fm.startitem()
4236 fm.startitem()
4245 fm.write('text', '%s', l.line[s:e], label='grep.match')
4237 fm.write('text', '%s', l.line[s:e], label='grep.match')
4246 fm.data(matched=True)
4238 fm.data(matched=True)
4247 p = e
4239 p = e
4248 if p < len(l.line):
4240 if p < len(l.line):
4249 fm.startitem()
4241 fm.startitem()
4250 fm.write('text', '%s', l.line[p:])
4242 fm.write('text', '%s', l.line[p:])
4251 fm.data(matched=False)
4243 fm.data(matched=False)
4252 fm.end()
4244 fm.end()
4253
4245
4254 skip = {}
4246 skip = {}
4255 revfiles = {}
4247 revfiles = {}
4256 matchfn = scmutil.match(repo[None], pats, opts)
4248 matchfn = scmutil.match(repo[None], pats, opts)
4257 found = False
4249 found = False
4258 follow = opts.get('follow')
4250 follow = opts.get('follow')
4259
4251
4260 def prep(ctx, fns):
4252 def prep(ctx, fns):
4261 rev = ctx.rev()
4253 rev = ctx.rev()
4262 pctx = ctx.p1()
4254 pctx = ctx.p1()
4263 parent = pctx.rev()
4255 parent = pctx.rev()
4264 matches.setdefault(rev, {})
4256 matches.setdefault(rev, {})
4265 matches.setdefault(parent, {})
4257 matches.setdefault(parent, {})
4266 files = revfiles.setdefault(rev, [])
4258 files = revfiles.setdefault(rev, [])
4267 for fn in fns:
4259 for fn in fns:
4268 flog = getfile(fn)
4260 flog = getfile(fn)
4269 try:
4261 try:
4270 fnode = ctx.filenode(fn)
4262 fnode = ctx.filenode(fn)
4271 except error.LookupError:
4263 except error.LookupError:
4272 continue
4264 continue
4273
4265
4274 copied = flog.renamed(fnode)
4266 copied = flog.renamed(fnode)
4275 copy = follow and copied and copied[0]
4267 copy = follow and copied and copied[0]
4276 if copy:
4268 if copy:
4277 copies.setdefault(rev, {})[fn] = copy
4269 copies.setdefault(rev, {})[fn] = copy
4278 if fn in skip:
4270 if fn in skip:
4279 if copy:
4271 if copy:
4280 skip[copy] = True
4272 skip[copy] = True
4281 continue
4273 continue
4282 files.append(fn)
4274 files.append(fn)
4283
4275
4284 if fn not in matches[rev]:
4276 if fn not in matches[rev]:
4285 grepbody(fn, rev, flog.read(fnode))
4277 grepbody(fn, rev, flog.read(fnode))
4286
4278
4287 pfn = copy or fn
4279 pfn = copy or fn
4288 if pfn not in matches[parent]:
4280 if pfn not in matches[parent]:
4289 try:
4281 try:
4290 fnode = pctx.filenode(pfn)
4282 fnode = pctx.filenode(pfn)
4291 grepbody(pfn, parent, flog.read(fnode))
4283 grepbody(pfn, parent, flog.read(fnode))
4292 except error.LookupError:
4284 except error.LookupError:
4293 pass
4285 pass
4294
4286
4295 fm = ui.formatter('grep', opts)
4287 fm = ui.formatter('grep', opts)
4296 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4288 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4297 rev = ctx.rev()
4289 rev = ctx.rev()
4298 parent = ctx.p1().rev()
4290 parent = ctx.p1().rev()
4299 for fn in sorted(revfiles.get(rev, [])):
4291 for fn in sorted(revfiles.get(rev, [])):
4300 states = matches[rev][fn]
4292 states = matches[rev][fn]
4301 copy = copies.get(rev, {}).get(fn)
4293 copy = copies.get(rev, {}).get(fn)
4302 if fn in skip:
4294 if fn in skip:
4303 if copy:
4295 if copy:
4304 skip[copy] = True
4296 skip[copy] = True
4305 continue
4297 continue
4306 pstates = matches.get(parent, {}).get(copy or fn, [])
4298 pstates = matches.get(parent, {}).get(copy or fn, [])
4307 if pstates or states:
4299 if pstates or states:
4308 r = display(fm, fn, ctx, pstates, states)
4300 r = display(fm, fn, ctx, pstates, states)
4309 found = found or r
4301 found = found or r
4310 if r and not opts.get('all'):
4302 if r and not opts.get('all'):
4311 skip[fn] = True
4303 skip[fn] = True
4312 if copy:
4304 if copy:
4313 skip[copy] = True
4305 skip[copy] = True
4314 del matches[rev]
4306 del matches[rev]
4315 del revfiles[rev]
4307 del revfiles[rev]
4316 fm.end()
4308 fm.end()
4317
4309
4318 return not found
4310 return not found
4319
4311
4320 @command('heads',
4312 @command('heads',
4321 [('r', 'rev', '',
4313 [('r', 'rev', '',
4322 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4314 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4323 ('t', 'topo', False, _('show topological heads only')),
4315 ('t', 'topo', False, _('show topological heads only')),
4324 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4316 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4325 ('c', 'closed', False, _('show normal and closed branch heads')),
4317 ('c', 'closed', False, _('show normal and closed branch heads')),
4326 ] + templateopts,
4318 ] + templateopts,
4327 _('[-ct] [-r STARTREV] [REV]...'))
4319 _('[-ct] [-r STARTREV] [REV]...'))
4328 def heads(ui, repo, *branchrevs, **opts):
4320 def heads(ui, repo, *branchrevs, **opts):
4329 """show branch heads
4321 """show branch heads
4330
4322
4331 With no arguments, show all open branch heads in the repository.
4323 With no arguments, show all open branch heads in the repository.
4332 Branch heads are changesets that have no descendants on the
4324 Branch heads are changesets that have no descendants on the
4333 same branch. They are where development generally takes place and
4325 same branch. They are where development generally takes place and
4334 are the usual targets for update and merge operations.
4326 are the usual targets for update and merge operations.
4335
4327
4336 If one or more REVs are given, only open branch heads on the
4328 If one or more REVs are given, only open branch heads on the
4337 branches associated with the specified changesets are shown. This
4329 branches associated with the specified changesets are shown. This
4338 means that you can use :hg:`heads .` to see the heads on the
4330 means that you can use :hg:`heads .` to see the heads on the
4339 currently checked-out branch.
4331 currently checked-out branch.
4340
4332
4341 If -c/--closed is specified, also show branch heads marked closed
4333 If -c/--closed is specified, also show branch heads marked closed
4342 (see :hg:`commit --close-branch`).
4334 (see :hg:`commit --close-branch`).
4343
4335
4344 If STARTREV is specified, only those heads that are descendants of
4336 If STARTREV is specified, only those heads that are descendants of
4345 STARTREV will be displayed.
4337 STARTREV will be displayed.
4346
4338
4347 If -t/--topo is specified, named branch mechanics will be ignored and only
4339 If -t/--topo is specified, named branch mechanics will be ignored and only
4348 topological heads (changesets with no children) will be shown.
4340 topological heads (changesets with no children) will be shown.
4349
4341
4350 Returns 0 if matching heads are found, 1 if not.
4342 Returns 0 if matching heads are found, 1 if not.
4351 """
4343 """
4352
4344
4353 start = None
4345 start = None
4354 if 'rev' in opts:
4346 if 'rev' in opts:
4355 start = scmutil.revsingle(repo, opts['rev'], None).node()
4347 start = scmutil.revsingle(repo, opts['rev'], None).node()
4356
4348
4357 if opts.get('topo'):
4349 if opts.get('topo'):
4358 heads = [repo[h] for h in repo.heads(start)]
4350 heads = [repo[h] for h in repo.heads(start)]
4359 else:
4351 else:
4360 heads = []
4352 heads = []
4361 for branch in repo.branchmap():
4353 for branch in repo.branchmap():
4362 heads += repo.branchheads(branch, start, opts.get('closed'))
4354 heads += repo.branchheads(branch, start, opts.get('closed'))
4363 heads = [repo[h] for h in heads]
4355 heads = [repo[h] for h in heads]
4364
4356
4365 if branchrevs:
4357 if branchrevs:
4366 branches = set(repo[br].branch() for br in branchrevs)
4358 branches = set(repo[br].branch() for br in branchrevs)
4367 heads = [h for h in heads if h.branch() in branches]
4359 heads = [h for h in heads if h.branch() in branches]
4368
4360
4369 if opts.get('active') and branchrevs:
4361 if opts.get('active') and branchrevs:
4370 dagheads = repo.heads(start)
4362 dagheads = repo.heads(start)
4371 heads = [h for h in heads if h.node() in dagheads]
4363 heads = [h for h in heads if h.node() in dagheads]
4372
4364
4373 if branchrevs:
4365 if branchrevs:
4374 haveheads = set(h.branch() for h in heads)
4366 haveheads = set(h.branch() for h in heads)
4375 if branches - haveheads:
4367 if branches - haveheads:
4376 headless = ', '.join(b for b in branches - haveheads)
4368 headless = ', '.join(b for b in branches - haveheads)
4377 msg = _('no open branch heads found on branches %s')
4369 msg = _('no open branch heads found on branches %s')
4378 if opts.get('rev'):
4370 if opts.get('rev'):
4379 msg += _(' (started at %s)') % opts['rev']
4371 msg += _(' (started at %s)') % opts['rev']
4380 ui.warn((msg + '\n') % headless)
4372 ui.warn((msg + '\n') % headless)
4381
4373
4382 if not heads:
4374 if not heads:
4383 return 1
4375 return 1
4384
4376
4385 heads = sorted(heads, key=lambda x: -x.rev())
4377 heads = sorted(heads, key=lambda x: -x.rev())
4386 displayer = cmdutil.show_changeset(ui, repo, opts)
4378 displayer = cmdutil.show_changeset(ui, repo, opts)
4387 for ctx in heads:
4379 for ctx in heads:
4388 displayer.show(ctx)
4380 displayer.show(ctx)
4389 displayer.close()
4381 displayer.close()
4390
4382
4391 @command('help',
4383 @command('help',
4392 [('e', 'extension', None, _('show only help for extensions')),
4384 [('e', 'extension', None, _('show only help for extensions')),
4393 ('c', 'command', None, _('show only help for commands')),
4385 ('c', 'command', None, _('show only help for commands')),
4394 ('k', 'keyword', None, _('show topics matching keyword')),
4386 ('k', 'keyword', None, _('show topics matching keyword')),
4395 ('s', 'system', [], _('show help for specific platform(s)')),
4387 ('s', 'system', [], _('show help for specific platform(s)')),
4396 ],
4388 ],
4397 _('[-ecks] [TOPIC]'),
4389 _('[-ecks] [TOPIC]'),
4398 norepo=True)
4390 norepo=True)
4399 def help_(ui, name=None, **opts):
4391 def help_(ui, name=None, **opts):
4400 """show help for a given topic or a help overview
4392 """show help for a given topic or a help overview
4401
4393
4402 With no arguments, print a list of commands with short help messages.
4394 With no arguments, print a list of commands with short help messages.
4403
4395
4404 Given a topic, extension, or command name, print help for that
4396 Given a topic, extension, or command name, print help for that
4405 topic.
4397 topic.
4406
4398
4407 Returns 0 if successful.
4399 Returns 0 if successful.
4408 """
4400 """
4409
4401
4410 textwidth = ui.configint('ui', 'textwidth', 78)
4402 textwidth = ui.configint('ui', 'textwidth', 78)
4411 termwidth = ui.termwidth() - 2
4403 termwidth = ui.termwidth() - 2
4412 if textwidth <= 0 or termwidth < textwidth:
4404 if textwidth <= 0 or termwidth < textwidth:
4413 textwidth = termwidth
4405 textwidth = termwidth
4414
4406
4415 keep = opts.get('system') or []
4407 keep = opts.get('system') or []
4416 if len(keep) == 0:
4408 if len(keep) == 0:
4417 if sys.platform.startswith('win'):
4409 if sys.platform.startswith('win'):
4418 keep.append('windows')
4410 keep.append('windows')
4419 elif sys.platform == 'OpenVMS':
4411 elif sys.platform == 'OpenVMS':
4420 keep.append('vms')
4412 keep.append('vms')
4421 elif sys.platform == 'plan9':
4413 elif sys.platform == 'plan9':
4422 keep.append('plan9')
4414 keep.append('plan9')
4423 else:
4415 else:
4424 keep.append('unix')
4416 keep.append('unix')
4425 keep.append(sys.platform.lower())
4417 keep.append(sys.platform.lower())
4426 if ui.verbose:
4418 if ui.verbose:
4427 keep.append('verbose')
4419 keep.append('verbose')
4428
4420
4429 section = None
4421 section = None
4430 subtopic = None
4422 subtopic = None
4431 if name and '.' in name:
4423 if name and '.' in name:
4432 name, remaining = name.split('.', 1)
4424 name, remaining = name.split('.', 1)
4433 remaining = encoding.lower(remaining)
4425 remaining = encoding.lower(remaining)
4434 if '.' in remaining:
4426 if '.' in remaining:
4435 subtopic, section = remaining.split('.', 1)
4427 subtopic, section = remaining.split('.', 1)
4436 else:
4428 else:
4437 if name in help.subtopics:
4429 if name in help.subtopics:
4438 subtopic = remaining
4430 subtopic = remaining
4439 else:
4431 else:
4440 section = remaining
4432 section = remaining
4441
4433
4442 text = help.help_(ui, name, subtopic=subtopic, **opts)
4434 text = help.help_(ui, name, subtopic=subtopic, **opts)
4443
4435
4444 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4436 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4445 section=section)
4437 section=section)
4446
4438
4447 # We could have been given a weird ".foo" section without a name
4439 # We could have been given a weird ".foo" section without a name
4448 # to look for, or we could have simply failed to found "foo.bar"
4440 # to look for, or we could have simply failed to found "foo.bar"
4449 # because bar isn't a section of foo
4441 # because bar isn't a section of foo
4450 if section and not (formatted and name):
4442 if section and not (formatted and name):
4451 raise error.Abort(_("help section not found"))
4443 raise error.Abort(_("help section not found"))
4452
4444
4453 if 'verbose' in pruned:
4445 if 'verbose' in pruned:
4454 keep.append('omitted')
4446 keep.append('omitted')
4455 else:
4447 else:
4456 keep.append('notomitted')
4448 keep.append('notomitted')
4457 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4449 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4458 section=section)
4450 section=section)
4459 ui.write(formatted)
4451 ui.write(formatted)
4460
4452
4461
4453
4462 @command('identify|id',
4454 @command('identify|id',
4463 [('r', 'rev', '',
4455 [('r', 'rev', '',
4464 _('identify the specified revision'), _('REV')),
4456 _('identify the specified revision'), _('REV')),
4465 ('n', 'num', None, _('show local revision number')),
4457 ('n', 'num', None, _('show local revision number')),
4466 ('i', 'id', None, _('show global revision id')),
4458 ('i', 'id', None, _('show global revision id')),
4467 ('b', 'branch', None, _('show branch')),
4459 ('b', 'branch', None, _('show branch')),
4468 ('t', 'tags', None, _('show tags')),
4460 ('t', 'tags', None, _('show tags')),
4469 ('B', 'bookmarks', None, _('show bookmarks')),
4461 ('B', 'bookmarks', None, _('show bookmarks')),
4470 ] + remoteopts,
4462 ] + remoteopts,
4471 _('[-nibtB] [-r REV] [SOURCE]'),
4463 _('[-nibtB] [-r REV] [SOURCE]'),
4472 optionalrepo=True)
4464 optionalrepo=True)
4473 def identify(ui, repo, source=None, rev=None,
4465 def identify(ui, repo, source=None, rev=None,
4474 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4466 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4475 """identify the working directory or specified revision
4467 """identify the working directory or specified revision
4476
4468
4477 Print a summary identifying the repository state at REV using one or
4469 Print a summary identifying the repository state at REV using one or
4478 two parent hash identifiers, followed by a "+" if the working
4470 two parent hash identifiers, followed by a "+" if the working
4479 directory has uncommitted changes, the branch name (if not default),
4471 directory has uncommitted changes, the branch name (if not default),
4480 a list of tags, and a list of bookmarks.
4472 a list of tags, and a list of bookmarks.
4481
4473
4482 When REV is not given, print a summary of the current state of the
4474 When REV is not given, print a summary of the current state of the
4483 repository.
4475 repository.
4484
4476
4485 Specifying a path to a repository root or Mercurial bundle will
4477 Specifying a path to a repository root or Mercurial bundle will
4486 cause lookup to operate on that repository/bundle.
4478 cause lookup to operate on that repository/bundle.
4487
4479
4488 .. container:: verbose
4480 .. container:: verbose
4489
4481
4490 Examples:
4482 Examples:
4491
4483
4492 - generate a build identifier for the working directory::
4484 - generate a build identifier for the working directory::
4493
4485
4494 hg id --id > build-id.dat
4486 hg id --id > build-id.dat
4495
4487
4496 - find the revision corresponding to a tag::
4488 - find the revision corresponding to a tag::
4497
4489
4498 hg id -n -r 1.3
4490 hg id -n -r 1.3
4499
4491
4500 - check the most recent revision of a remote repository::
4492 - check the most recent revision of a remote repository::
4501
4493
4502 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4494 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4503
4495
4504 See :hg:`log` for generating more information about specific revisions,
4496 See :hg:`log` for generating more information about specific revisions,
4505 including full hash identifiers.
4497 including full hash identifiers.
4506
4498
4507 Returns 0 if successful.
4499 Returns 0 if successful.
4508 """
4500 """
4509
4501
4510 if not repo and not source:
4502 if not repo and not source:
4511 raise error.Abort(_("there is no Mercurial repository here "
4503 raise error.Abort(_("there is no Mercurial repository here "
4512 "(.hg not found)"))
4504 "(.hg not found)"))
4513
4505
4514 if ui.debugflag:
4506 if ui.debugflag:
4515 hexfunc = hex
4507 hexfunc = hex
4516 else:
4508 else:
4517 hexfunc = short
4509 hexfunc = short
4518 default = not (num or id or branch or tags or bookmarks)
4510 default = not (num or id or branch or tags or bookmarks)
4519 output = []
4511 output = []
4520 revs = []
4512 revs = []
4521
4513
4522 if source:
4514 if source:
4523 source, branches = hg.parseurl(ui.expandpath(source))
4515 source, branches = hg.parseurl(ui.expandpath(source))
4524 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4516 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4525 repo = peer.local()
4517 repo = peer.local()
4526 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4518 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4527
4519
4528 if not repo:
4520 if not repo:
4529 if num or branch or tags:
4521 if num or branch or tags:
4530 raise error.Abort(
4522 raise error.Abort(
4531 _("can't query remote revision number, branch, or tags"))
4523 _("can't query remote revision number, branch, or tags"))
4532 if not rev and revs:
4524 if not rev and revs:
4533 rev = revs[0]
4525 rev = revs[0]
4534 if not rev:
4526 if not rev:
4535 rev = "tip"
4527 rev = "tip"
4536
4528
4537 remoterev = peer.lookup(rev)
4529 remoterev = peer.lookup(rev)
4538 if default or id:
4530 if default or id:
4539 output = [hexfunc(remoterev)]
4531 output = [hexfunc(remoterev)]
4540
4532
4541 def getbms():
4533 def getbms():
4542 bms = []
4534 bms = []
4543
4535
4544 if 'bookmarks' in peer.listkeys('namespaces'):
4536 if 'bookmarks' in peer.listkeys('namespaces'):
4545 hexremoterev = hex(remoterev)
4537 hexremoterev = hex(remoterev)
4546 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4538 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4547 if bmr == hexremoterev]
4539 if bmr == hexremoterev]
4548
4540
4549 return sorted(bms)
4541 return sorted(bms)
4550
4542
4551 if bookmarks:
4543 if bookmarks:
4552 output.extend(getbms())
4544 output.extend(getbms())
4553 elif default and not ui.quiet:
4545 elif default and not ui.quiet:
4554 # multiple bookmarks for a single parent separated by '/'
4546 # multiple bookmarks for a single parent separated by '/'
4555 bm = '/'.join(getbms())
4547 bm = '/'.join(getbms())
4556 if bm:
4548 if bm:
4557 output.append(bm)
4549 output.append(bm)
4558 else:
4550 else:
4559 ctx = scmutil.revsingle(repo, rev, None)
4551 ctx = scmutil.revsingle(repo, rev, None)
4560
4552
4561 if ctx.rev() is None:
4553 if ctx.rev() is None:
4562 ctx = repo[None]
4554 ctx = repo[None]
4563 parents = ctx.parents()
4555 parents = ctx.parents()
4564 taglist = []
4556 taglist = []
4565 for p in parents:
4557 for p in parents:
4566 taglist.extend(p.tags())
4558 taglist.extend(p.tags())
4567
4559
4568 changed = ""
4560 changed = ""
4569 if default or id or num:
4561 if default or id or num:
4570 if (any(repo.status())
4562 if (any(repo.status())
4571 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4563 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4572 changed = '+'
4564 changed = '+'
4573 if default or id:
4565 if default or id:
4574 output = ["%s%s" %
4566 output = ["%s%s" %
4575 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4567 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4576 if num:
4568 if num:
4577 output.append("%s%s" %
4569 output.append("%s%s" %
4578 ('+'.join([str(p.rev()) for p in parents]), changed))
4570 ('+'.join([str(p.rev()) for p in parents]), changed))
4579 else:
4571 else:
4580 if default or id:
4572 if default or id:
4581 output = [hexfunc(ctx.node())]
4573 output = [hexfunc(ctx.node())]
4582 if num:
4574 if num:
4583 output.append(str(ctx.rev()))
4575 output.append(str(ctx.rev()))
4584 taglist = ctx.tags()
4576 taglist = ctx.tags()
4585
4577
4586 if default and not ui.quiet:
4578 if default and not ui.quiet:
4587 b = ctx.branch()
4579 b = ctx.branch()
4588 if b != 'default':
4580 if b != 'default':
4589 output.append("(%s)" % b)
4581 output.append("(%s)" % b)
4590
4582
4591 # multiple tags for a single parent separated by '/'
4583 # multiple tags for a single parent separated by '/'
4592 t = '/'.join(taglist)
4584 t = '/'.join(taglist)
4593 if t:
4585 if t:
4594 output.append(t)
4586 output.append(t)
4595
4587
4596 # multiple bookmarks for a single parent separated by '/'
4588 # multiple bookmarks for a single parent separated by '/'
4597 bm = '/'.join(ctx.bookmarks())
4589 bm = '/'.join(ctx.bookmarks())
4598 if bm:
4590 if bm:
4599 output.append(bm)
4591 output.append(bm)
4600 else:
4592 else:
4601 if branch:
4593 if branch:
4602 output.append(ctx.branch())
4594 output.append(ctx.branch())
4603
4595
4604 if tags:
4596 if tags:
4605 output.extend(taglist)
4597 output.extend(taglist)
4606
4598
4607 if bookmarks:
4599 if bookmarks:
4608 output.extend(ctx.bookmarks())
4600 output.extend(ctx.bookmarks())
4609
4601
4610 ui.write("%s\n" % ' '.join(output))
4602 ui.write("%s\n" % ' '.join(output))
4611
4603
4612 @command('import|patch',
4604 @command('import|patch',
4613 [('p', 'strip', 1,
4605 [('p', 'strip', 1,
4614 _('directory strip option for patch. This has the same '
4606 _('directory strip option for patch. This has the same '
4615 'meaning as the corresponding patch option'), _('NUM')),
4607 'meaning as the corresponding patch option'), _('NUM')),
4616 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4608 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4617 ('e', 'edit', False, _('invoke editor on commit messages')),
4609 ('e', 'edit', False, _('invoke editor on commit messages')),
4618 ('f', 'force', None,
4610 ('f', 'force', None,
4619 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4611 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4620 ('', 'no-commit', None,
4612 ('', 'no-commit', None,
4621 _("don't commit, just update the working directory")),
4613 _("don't commit, just update the working directory")),
4622 ('', 'bypass', None,
4614 ('', 'bypass', None,
4623 _("apply patch without touching the working directory")),
4615 _("apply patch without touching the working directory")),
4624 ('', 'partial', None,
4616 ('', 'partial', None,
4625 _('commit even if some hunks fail')),
4617 _('commit even if some hunks fail')),
4626 ('', 'exact', None,
4618 ('', 'exact', None,
4627 _('abort if patch would apply lossily')),
4619 _('abort if patch would apply lossily')),
4628 ('', 'prefix', '',
4620 ('', 'prefix', '',
4629 _('apply patch to subdirectory'), _('DIR')),
4621 _('apply patch to subdirectory'), _('DIR')),
4630 ('', 'import-branch', None,
4622 ('', 'import-branch', None,
4631 _('use any branch information in patch (implied by --exact)'))] +
4623 _('use any branch information in patch (implied by --exact)'))] +
4632 commitopts + commitopts2 + similarityopts,
4624 commitopts + commitopts2 + similarityopts,
4633 _('[OPTION]... PATCH...'))
4625 _('[OPTION]... PATCH...'))
4634 def import_(ui, repo, patch1=None, *patches, **opts):
4626 def import_(ui, repo, patch1=None, *patches, **opts):
4635 """import an ordered set of patches
4627 """import an ordered set of patches
4636
4628
4637 Import a list of patches and commit them individually (unless
4629 Import a list of patches and commit them individually (unless
4638 --no-commit is specified).
4630 --no-commit is specified).
4639
4631
4640 To read a patch from standard input, use "-" as the patch name. If
4632 To read a patch from standard input, use "-" as the patch name. If
4641 a URL is specified, the patch will be downloaded from there.
4633 a URL is specified, the patch will be downloaded from there.
4642
4634
4643 Import first applies changes to the working directory (unless
4635 Import first applies changes to the working directory (unless
4644 --bypass is specified), import will abort if there are outstanding
4636 --bypass is specified), import will abort if there are outstanding
4645 changes.
4637 changes.
4646
4638
4647 Use --bypass to apply and commit patches directly to the
4639 Use --bypass to apply and commit patches directly to the
4648 repository, without affecting the working directory. Without
4640 repository, without affecting the working directory. Without
4649 --exact, patches will be applied on top of the working directory
4641 --exact, patches will be applied on top of the working directory
4650 parent revision.
4642 parent revision.
4651
4643
4652 You can import a patch straight from a mail message. Even patches
4644 You can import a patch straight from a mail message. Even patches
4653 as attachments work (to use the body part, it must have type
4645 as attachments work (to use the body part, it must have type
4654 text/plain or text/x-patch). From and Subject headers of email
4646 text/plain or text/x-patch). From and Subject headers of email
4655 message are used as default committer and commit message. All
4647 message are used as default committer and commit message. All
4656 text/plain body parts before first diff are added to the commit
4648 text/plain body parts before first diff are added to the commit
4657 message.
4649 message.
4658
4650
4659 If the imported patch was generated by :hg:`export`, user and
4651 If the imported patch was generated by :hg:`export`, user and
4660 description from patch override values from message headers and
4652 description from patch override values from message headers and
4661 body. Values given on command line with -m/--message and -u/--user
4653 body. Values given on command line with -m/--message and -u/--user
4662 override these.
4654 override these.
4663
4655
4664 If --exact is specified, import will set the working directory to
4656 If --exact is specified, import will set the working directory to
4665 the parent of each patch before applying it, and will abort if the
4657 the parent of each patch before applying it, and will abort if the
4666 resulting changeset has a different ID than the one recorded in
4658 resulting changeset has a different ID than the one recorded in
4667 the patch. This will guard against various ways that portable
4659 the patch. This will guard against various ways that portable
4668 patch formats and mail systems might fail to transfer Mercurial
4660 patch formats and mail systems might fail to transfer Mercurial
4669 data or metadata. See :hg:`bundle` for lossless transmission.
4661 data or metadata. See :hg:`bundle` for lossless transmission.
4670
4662
4671 Use --partial to ensure a changeset will be created from the patch
4663 Use --partial to ensure a changeset will be created from the patch
4672 even if some hunks fail to apply. Hunks that fail to apply will be
4664 even if some hunks fail to apply. Hunks that fail to apply will be
4673 written to a <target-file>.rej file. Conflicts can then be resolved
4665 written to a <target-file>.rej file. Conflicts can then be resolved
4674 by hand before :hg:`commit --amend` is run to update the created
4666 by hand before :hg:`commit --amend` is run to update the created
4675 changeset. This flag exists to let people import patches that
4667 changeset. This flag exists to let people import patches that
4676 partially apply without losing the associated metadata (author,
4668 partially apply without losing the associated metadata (author,
4677 date, description, ...).
4669 date, description, ...).
4678
4670
4679 .. note::
4671 .. note::
4680
4672
4681 When no hunks apply cleanly, :hg:`import --partial` will create
4673 When no hunks apply cleanly, :hg:`import --partial` will create
4682 an empty changeset, importing only the patch metadata.
4674 an empty changeset, importing only the patch metadata.
4683
4675
4684 With -s/--similarity, hg will attempt to discover renames and
4676 With -s/--similarity, hg will attempt to discover renames and
4685 copies in the patch in the same way as :hg:`addremove`.
4677 copies in the patch in the same way as :hg:`addremove`.
4686
4678
4687 It is possible to use external patch programs to perform the patch
4679 It is possible to use external patch programs to perform the patch
4688 by setting the ``ui.patch`` configuration option. For the default
4680 by setting the ``ui.patch`` configuration option. For the default
4689 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4681 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4690 See :hg:`help config` for more information about configuration
4682 See :hg:`help config` for more information about configuration
4691 files and how to use these options.
4683 files and how to use these options.
4692
4684
4693 See :hg:`help dates` for a list of formats valid for -d/--date.
4685 See :hg:`help dates` for a list of formats valid for -d/--date.
4694
4686
4695 .. container:: verbose
4687 .. container:: verbose
4696
4688
4697 Examples:
4689 Examples:
4698
4690
4699 - import a traditional patch from a website and detect renames::
4691 - import a traditional patch from a website and detect renames::
4700
4692
4701 hg import -s 80 http://example.com/bugfix.patch
4693 hg import -s 80 http://example.com/bugfix.patch
4702
4694
4703 - import a changeset from an hgweb server::
4695 - import a changeset from an hgweb server::
4704
4696
4705 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4697 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4706
4698
4707 - import all the patches in an Unix-style mbox::
4699 - import all the patches in an Unix-style mbox::
4708
4700
4709 hg import incoming-patches.mbox
4701 hg import incoming-patches.mbox
4710
4702
4711 - attempt to exactly restore an exported changeset (not always
4703 - attempt to exactly restore an exported changeset (not always
4712 possible)::
4704 possible)::
4713
4705
4714 hg import --exact proposed-fix.patch
4706 hg import --exact proposed-fix.patch
4715
4707
4716 - use an external tool to apply a patch which is too fuzzy for
4708 - use an external tool to apply a patch which is too fuzzy for
4717 the default internal tool.
4709 the default internal tool.
4718
4710
4719 hg import --config ui.patch="patch --merge" fuzzy.patch
4711 hg import --config ui.patch="patch --merge" fuzzy.patch
4720
4712
4721 - change the default fuzzing from 2 to a less strict 7
4713 - change the default fuzzing from 2 to a less strict 7
4722
4714
4723 hg import --config ui.fuzz=7 fuzz.patch
4715 hg import --config ui.fuzz=7 fuzz.patch
4724
4716
4725 Returns 0 on success, 1 on partial success (see --partial).
4717 Returns 0 on success, 1 on partial success (see --partial).
4726 """
4718 """
4727
4719
4728 if not patch1:
4720 if not patch1:
4729 raise error.Abort(_('need at least one patch to import'))
4721 raise error.Abort(_('need at least one patch to import'))
4730
4722
4731 patches = (patch1,) + patches
4723 patches = (patch1,) + patches
4732
4724
4733 date = opts.get('date')
4725 date = opts.get('date')
4734 if date:
4726 if date:
4735 opts['date'] = util.parsedate(date)
4727 opts['date'] = util.parsedate(date)
4736
4728
4737 exact = opts.get('exact')
4729 exact = opts.get('exact')
4738 update = not opts.get('bypass')
4730 update = not opts.get('bypass')
4739 if not update and opts.get('no_commit'):
4731 if not update and opts.get('no_commit'):
4740 raise error.Abort(_('cannot use --no-commit with --bypass'))
4732 raise error.Abort(_('cannot use --no-commit with --bypass'))
4741 try:
4733 try:
4742 sim = float(opts.get('similarity') or 0)
4734 sim = float(opts.get('similarity') or 0)
4743 except ValueError:
4735 except ValueError:
4744 raise error.Abort(_('similarity must be a number'))
4736 raise error.Abort(_('similarity must be a number'))
4745 if sim < 0 or sim > 100:
4737 if sim < 0 or sim > 100:
4746 raise error.Abort(_('similarity must be between 0 and 100'))
4738 raise error.Abort(_('similarity must be between 0 and 100'))
4747 if sim and not update:
4739 if sim and not update:
4748 raise error.Abort(_('cannot use --similarity with --bypass'))
4740 raise error.Abort(_('cannot use --similarity with --bypass'))
4749 if exact:
4741 if exact:
4750 if opts.get('edit'):
4742 if opts.get('edit'):
4751 raise error.Abort(_('cannot use --exact with --edit'))
4743 raise error.Abort(_('cannot use --exact with --edit'))
4752 if opts.get('prefix'):
4744 if opts.get('prefix'):
4753 raise error.Abort(_('cannot use --exact with --prefix'))
4745 raise error.Abort(_('cannot use --exact with --prefix'))
4754
4746
4755 base = opts["base"]
4747 base = opts["base"]
4756 wlock = dsguard = lock = tr = None
4748 wlock = dsguard = lock = tr = None
4757 msgs = []
4749 msgs = []
4758 ret = 0
4750 ret = 0
4759
4751
4760
4752
4761 try:
4753 try:
4762 wlock = repo.wlock()
4754 wlock = repo.wlock()
4763
4755
4764 if update:
4756 if update:
4765 cmdutil.checkunfinished(repo)
4757 cmdutil.checkunfinished(repo)
4766 if (exact or not opts.get('force')):
4758 if (exact or not opts.get('force')):
4767 cmdutil.bailifchanged(repo)
4759 cmdutil.bailifchanged(repo)
4768
4760
4769 if not opts.get('no_commit'):
4761 if not opts.get('no_commit'):
4770 lock = repo.lock()
4762 lock = repo.lock()
4771 tr = repo.transaction('import')
4763 tr = repo.transaction('import')
4772 else:
4764 else:
4773 dsguard = dirstateguard.dirstateguard(repo, 'import')
4765 dsguard = dirstateguard.dirstateguard(repo, 'import')
4774 parents = repo[None].parents()
4766 parents = repo[None].parents()
4775 for patchurl in patches:
4767 for patchurl in patches:
4776 if patchurl == '-':
4768 if patchurl == '-':
4777 ui.status(_('applying patch from stdin\n'))
4769 ui.status(_('applying patch from stdin\n'))
4778 patchfile = ui.fin
4770 patchfile = ui.fin
4779 patchurl = 'stdin' # for error message
4771 patchurl = 'stdin' # for error message
4780 else:
4772 else:
4781 patchurl = os.path.join(base, patchurl)
4773 patchurl = os.path.join(base, patchurl)
4782 ui.status(_('applying %s\n') % patchurl)
4774 ui.status(_('applying %s\n') % patchurl)
4783 patchfile = hg.openpath(ui, patchurl)
4775 patchfile = hg.openpath(ui, patchurl)
4784
4776
4785 haspatch = False
4777 haspatch = False
4786 for hunk in patch.split(patchfile):
4778 for hunk in patch.split(patchfile):
4787 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4779 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4788 parents, opts,
4780 parents, opts,
4789 msgs, hg.clean)
4781 msgs, hg.clean)
4790 if msg:
4782 if msg:
4791 haspatch = True
4783 haspatch = True
4792 ui.note(msg + '\n')
4784 ui.note(msg + '\n')
4793 if update or exact:
4785 if update or exact:
4794 parents = repo[None].parents()
4786 parents = repo[None].parents()
4795 else:
4787 else:
4796 parents = [repo[node]]
4788 parents = [repo[node]]
4797 if rej:
4789 if rej:
4798 ui.write_err(_("patch applied partially\n"))
4790 ui.write_err(_("patch applied partially\n"))
4799 ui.write_err(_("(fix the .rej files and run "
4791 ui.write_err(_("(fix the .rej files and run "
4800 "`hg commit --amend`)\n"))
4792 "`hg commit --amend`)\n"))
4801 ret = 1
4793 ret = 1
4802 break
4794 break
4803
4795
4804 if not haspatch:
4796 if not haspatch:
4805 raise error.Abort(_('%s: no diffs found') % patchurl)
4797 raise error.Abort(_('%s: no diffs found') % patchurl)
4806
4798
4807 if tr:
4799 if tr:
4808 tr.close()
4800 tr.close()
4809 if msgs:
4801 if msgs:
4810 repo.savecommitmessage('\n* * *\n'.join(msgs))
4802 repo.savecommitmessage('\n* * *\n'.join(msgs))
4811 if dsguard:
4803 if dsguard:
4812 dsguard.close()
4804 dsguard.close()
4813 return ret
4805 return ret
4814 finally:
4806 finally:
4815 if tr:
4807 if tr:
4816 tr.release()
4808 tr.release()
4817 release(lock, dsguard, wlock)
4809 release(lock, dsguard, wlock)
4818
4810
4819 @command('incoming|in',
4811 @command('incoming|in',
4820 [('f', 'force', None,
4812 [('f', 'force', None,
4821 _('run even if remote repository is unrelated')),
4813 _('run even if remote repository is unrelated')),
4822 ('n', 'newest-first', None, _('show newest record first')),
4814 ('n', 'newest-first', None, _('show newest record first')),
4823 ('', 'bundle', '',
4815 ('', 'bundle', '',
4824 _('file to store the bundles into'), _('FILE')),
4816 _('file to store the bundles into'), _('FILE')),
4825 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4817 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4826 ('B', 'bookmarks', False, _("compare bookmarks")),
4818 ('B', 'bookmarks', False, _("compare bookmarks")),
4827 ('b', 'branch', [],
4819 ('b', 'branch', [],
4828 _('a specific branch you would like to pull'), _('BRANCH')),
4820 _('a specific branch you would like to pull'), _('BRANCH')),
4829 ] + logopts + remoteopts + subrepoopts,
4821 ] + logopts + remoteopts + subrepoopts,
4830 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4822 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4831 def incoming(ui, repo, source="default", **opts):
4823 def incoming(ui, repo, source="default", **opts):
4832 """show new changesets found in source
4824 """show new changesets found in source
4833
4825
4834 Show new changesets found in the specified path/URL or the default
4826 Show new changesets found in the specified path/URL or the default
4835 pull location. These are the changesets that would have been pulled
4827 pull location. These are the changesets that would have been pulled
4836 if a pull at the time you issued this command.
4828 if a pull at the time you issued this command.
4837
4829
4838 See pull for valid source format details.
4830 See pull for valid source format details.
4839
4831
4840 .. container:: verbose
4832 .. container:: verbose
4841
4833
4842 With -B/--bookmarks, the result of bookmark comparison between
4834 With -B/--bookmarks, the result of bookmark comparison between
4843 local and remote repositories is displayed. With -v/--verbose,
4835 local and remote repositories is displayed. With -v/--verbose,
4844 status is also displayed for each bookmark like below::
4836 status is also displayed for each bookmark like below::
4845
4837
4846 BM1 01234567890a added
4838 BM1 01234567890a added
4847 BM2 1234567890ab advanced
4839 BM2 1234567890ab advanced
4848 BM3 234567890abc diverged
4840 BM3 234567890abc diverged
4849 BM4 34567890abcd changed
4841 BM4 34567890abcd changed
4850
4842
4851 The action taken locally when pulling depends on the
4843 The action taken locally when pulling depends on the
4852 status of each bookmark:
4844 status of each bookmark:
4853
4845
4854 :``added``: pull will create it
4846 :``added``: pull will create it
4855 :``advanced``: pull will update it
4847 :``advanced``: pull will update it
4856 :``diverged``: pull will create a divergent bookmark
4848 :``diverged``: pull will create a divergent bookmark
4857 :``changed``: result depends on remote changesets
4849 :``changed``: result depends on remote changesets
4858
4850
4859 From the point of view of pulling behavior, bookmark
4851 From the point of view of pulling behavior, bookmark
4860 existing only in the remote repository are treated as ``added``,
4852 existing only in the remote repository are treated as ``added``,
4861 even if it is in fact locally deleted.
4853 even if it is in fact locally deleted.
4862
4854
4863 .. container:: verbose
4855 .. container:: verbose
4864
4856
4865 For remote repository, using --bundle avoids downloading the
4857 For remote repository, using --bundle avoids downloading the
4866 changesets twice if the incoming is followed by a pull.
4858 changesets twice if the incoming is followed by a pull.
4867
4859
4868 Examples:
4860 Examples:
4869
4861
4870 - show incoming changes with patches and full description::
4862 - show incoming changes with patches and full description::
4871
4863
4872 hg incoming -vp
4864 hg incoming -vp
4873
4865
4874 - show incoming changes excluding merges, store a bundle::
4866 - show incoming changes excluding merges, store a bundle::
4875
4867
4876 hg in -vpM --bundle incoming.hg
4868 hg in -vpM --bundle incoming.hg
4877 hg pull incoming.hg
4869 hg pull incoming.hg
4878
4870
4879 - briefly list changes inside a bundle::
4871 - briefly list changes inside a bundle::
4880
4872
4881 hg in changes.hg -T "{desc|firstline}\\n"
4873 hg in changes.hg -T "{desc|firstline}\\n"
4882
4874
4883 Returns 0 if there are incoming changes, 1 otherwise.
4875 Returns 0 if there are incoming changes, 1 otherwise.
4884 """
4876 """
4885 if opts.get('graph'):
4877 if opts.get('graph'):
4886 cmdutil.checkunsupportedgraphflags([], opts)
4878 cmdutil.checkunsupportedgraphflags([], opts)
4887 def display(other, chlist, displayer):
4879 def display(other, chlist, displayer):
4888 revdag = cmdutil.graphrevs(other, chlist, opts)
4880 revdag = cmdutil.graphrevs(other, chlist, opts)
4889 cmdutil.displaygraph(ui, repo, revdag, displayer,
4881 cmdutil.displaygraph(ui, repo, revdag, displayer,
4890 graphmod.asciiedges)
4882 graphmod.asciiedges)
4891
4883
4892 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4884 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4893 return 0
4885 return 0
4894
4886
4895 if opts.get('bundle') and opts.get('subrepos'):
4887 if opts.get('bundle') and opts.get('subrepos'):
4896 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4888 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4897
4889
4898 if opts.get('bookmarks'):
4890 if opts.get('bookmarks'):
4899 source, branches = hg.parseurl(ui.expandpath(source),
4891 source, branches = hg.parseurl(ui.expandpath(source),
4900 opts.get('branch'))
4892 opts.get('branch'))
4901 other = hg.peer(repo, opts, source)
4893 other = hg.peer(repo, opts, source)
4902 if 'bookmarks' not in other.listkeys('namespaces'):
4894 if 'bookmarks' not in other.listkeys('namespaces'):
4903 ui.warn(_("remote doesn't support bookmarks\n"))
4895 ui.warn(_("remote doesn't support bookmarks\n"))
4904 return 0
4896 return 0
4905 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4897 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4906 return bookmarks.incoming(ui, repo, other)
4898 return bookmarks.incoming(ui, repo, other)
4907
4899
4908 repo._subtoppath = ui.expandpath(source)
4900 repo._subtoppath = ui.expandpath(source)
4909 try:
4901 try:
4910 return hg.incoming(ui, repo, source, opts)
4902 return hg.incoming(ui, repo, source, opts)
4911 finally:
4903 finally:
4912 del repo._subtoppath
4904 del repo._subtoppath
4913
4905
4914
4906
4915 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4907 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4916 norepo=True)
4908 norepo=True)
4917 def init(ui, dest=".", **opts):
4909 def init(ui, dest=".", **opts):
4918 """create a new repository in the given directory
4910 """create a new repository in the given directory
4919
4911
4920 Initialize a new repository in the given directory. If the given
4912 Initialize a new repository in the given directory. If the given
4921 directory does not exist, it will be created.
4913 directory does not exist, it will be created.
4922
4914
4923 If no directory is given, the current directory is used.
4915 If no directory is given, the current directory is used.
4924
4916
4925 It is possible to specify an ``ssh://`` URL as the destination.
4917 It is possible to specify an ``ssh://`` URL as the destination.
4926 See :hg:`help urls` for more information.
4918 See :hg:`help urls` for more information.
4927
4919
4928 Returns 0 on success.
4920 Returns 0 on success.
4929 """
4921 """
4930 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4922 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4931
4923
4932 @command('locate',
4924 @command('locate',
4933 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4925 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4934 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4926 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4935 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4927 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4936 ] + walkopts,
4928 ] + walkopts,
4937 _('[OPTION]... [PATTERN]...'))
4929 _('[OPTION]... [PATTERN]...'))
4938 def locate(ui, repo, *pats, **opts):
4930 def locate(ui, repo, *pats, **opts):
4939 """locate files matching specific patterns (DEPRECATED)
4931 """locate files matching specific patterns (DEPRECATED)
4940
4932
4941 Print files under Mercurial control in the working directory whose
4933 Print files under Mercurial control in the working directory whose
4942 names match the given patterns.
4934 names match the given patterns.
4943
4935
4944 By default, this command searches all directories in the working
4936 By default, this command searches all directories in the working
4945 directory. To search just the current directory and its
4937 directory. To search just the current directory and its
4946 subdirectories, use "--include .".
4938 subdirectories, use "--include .".
4947
4939
4948 If no patterns are given to match, this command prints the names
4940 If no patterns are given to match, this command prints the names
4949 of all files under Mercurial control in the working directory.
4941 of all files under Mercurial control in the working directory.
4950
4942
4951 If you want to feed the output of this command into the "xargs"
4943 If you want to feed the output of this command into the "xargs"
4952 command, use the -0 option to both this command and "xargs". This
4944 command, use the -0 option to both this command and "xargs". This
4953 will avoid the problem of "xargs" treating single filenames that
4945 will avoid the problem of "xargs" treating single filenames that
4954 contain whitespace as multiple filenames.
4946 contain whitespace as multiple filenames.
4955
4947
4956 See :hg:`help files` for a more versatile command.
4948 See :hg:`help files` for a more versatile command.
4957
4949
4958 Returns 0 if a match is found, 1 otherwise.
4950 Returns 0 if a match is found, 1 otherwise.
4959 """
4951 """
4960 if opts.get('print0'):
4952 if opts.get('print0'):
4961 end = '\0'
4953 end = '\0'
4962 else:
4954 else:
4963 end = '\n'
4955 end = '\n'
4964 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4956 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4965
4957
4966 ret = 1
4958 ret = 1
4967 ctx = repo[rev]
4959 ctx = repo[rev]
4968 m = scmutil.match(ctx, pats, opts, default='relglob',
4960 m = scmutil.match(ctx, pats, opts, default='relglob',
4969 badfn=lambda x, y: False)
4961 badfn=lambda x, y: False)
4970
4962
4971 for abs in ctx.matches(m):
4963 for abs in ctx.matches(m):
4972 if opts.get('fullpath'):
4964 if opts.get('fullpath'):
4973 ui.write(repo.wjoin(abs), end)
4965 ui.write(repo.wjoin(abs), end)
4974 else:
4966 else:
4975 ui.write(((pats and m.rel(abs)) or abs), end)
4967 ui.write(((pats and m.rel(abs)) or abs), end)
4976 ret = 0
4968 ret = 0
4977
4969
4978 return ret
4970 return ret
4979
4971
4980 @command('^log|history',
4972 @command('^log|history',
4981 [('f', 'follow', None,
4973 [('f', 'follow', None,
4982 _('follow changeset history, or file history across copies and renames')),
4974 _('follow changeset history, or file history across copies and renames')),
4983 ('', 'follow-first', None,
4975 ('', 'follow-first', None,
4984 _('only follow the first parent of merge changesets (DEPRECATED)')),
4976 _('only follow the first parent of merge changesets (DEPRECATED)')),
4985 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4977 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4986 ('C', 'copies', None, _('show copied files')),
4978 ('C', 'copies', None, _('show copied files')),
4987 ('k', 'keyword', [],
4979 ('k', 'keyword', [],
4988 _('do case-insensitive search for a given text'), _('TEXT')),
4980 _('do case-insensitive search for a given text'), _('TEXT')),
4989 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4981 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4990 ('', 'removed', None, _('include revisions where files were removed')),
4982 ('', 'removed', None, _('include revisions where files were removed')),
4991 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4983 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4992 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4984 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4993 ('', 'only-branch', [],
4985 ('', 'only-branch', [],
4994 _('show only changesets within the given named branch (DEPRECATED)'),
4986 _('show only changesets within the given named branch (DEPRECATED)'),
4995 _('BRANCH')),
4987 _('BRANCH')),
4996 ('b', 'branch', [],
4988 ('b', 'branch', [],
4997 _('show changesets within the given named branch'), _('BRANCH')),
4989 _('show changesets within the given named branch'), _('BRANCH')),
4998 ('P', 'prune', [],
4990 ('P', 'prune', [],
4999 _('do not display revision or any of its ancestors'), _('REV')),
4991 _('do not display revision or any of its ancestors'), _('REV')),
5000 ] + logopts + walkopts,
4992 ] + logopts + walkopts,
5001 _('[OPTION]... [FILE]'),
4993 _('[OPTION]... [FILE]'),
5002 inferrepo=True)
4994 inferrepo=True)
5003 def log(ui, repo, *pats, **opts):
4995 def log(ui, repo, *pats, **opts):
5004 """show revision history of entire repository or files
4996 """show revision history of entire repository or files
5005
4997
5006 Print the revision history of the specified files or the entire
4998 Print the revision history of the specified files or the entire
5007 project.
4999 project.
5008
5000
5009 If no revision range is specified, the default is ``tip:0`` unless
5001 If no revision range is specified, the default is ``tip:0`` unless
5010 --follow is set, in which case the working directory parent is
5002 --follow is set, in which case the working directory parent is
5011 used as the starting revision.
5003 used as the starting revision.
5012
5004
5013 File history is shown without following rename or copy history of
5005 File history is shown without following rename or copy history of
5014 files. Use -f/--follow with a filename to follow history across
5006 files. Use -f/--follow with a filename to follow history across
5015 renames and copies. --follow without a filename will only show
5007 renames and copies. --follow without a filename will only show
5016 ancestors or descendants of the starting revision.
5008 ancestors or descendants of the starting revision.
5017
5009
5018 By default this command prints revision number and changeset id,
5010 By default this command prints revision number and changeset id,
5019 tags, non-trivial parents, user, date and time, and a summary for
5011 tags, non-trivial parents, user, date and time, and a summary for
5020 each commit. When the -v/--verbose switch is used, the list of
5012 each commit. When the -v/--verbose switch is used, the list of
5021 changed files and full commit message are shown.
5013 changed files and full commit message are shown.
5022
5014
5023 With --graph the revisions are shown as an ASCII art DAG with the most
5015 With --graph the revisions are shown as an ASCII art DAG with the most
5024 recent changeset at the top.
5016 recent changeset at the top.
5025 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5017 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5026 and '+' represents a fork where the changeset from the lines below is a
5018 and '+' represents a fork where the changeset from the lines below is a
5027 parent of the 'o' merge on the same line.
5019 parent of the 'o' merge on the same line.
5028
5020
5029 .. note::
5021 .. note::
5030
5022
5031 :hg:`log --patch` may generate unexpected diff output for merge
5023 :hg:`log --patch` may generate unexpected diff output for merge
5032 changesets, as it will only compare the merge changeset against
5024 changesets, as it will only compare the merge changeset against
5033 its first parent. Also, only files different from BOTH parents
5025 its first parent. Also, only files different from BOTH parents
5034 will appear in files:.
5026 will appear in files:.
5035
5027
5036 .. note::
5028 .. note::
5037
5029
5038 For performance reasons, :hg:`log FILE` may omit duplicate changes
5030 For performance reasons, :hg:`log FILE` may omit duplicate changes
5039 made on branches and will not show removals or mode changes. To
5031 made on branches and will not show removals or mode changes. To
5040 see all such changes, use the --removed switch.
5032 see all such changes, use the --removed switch.
5041
5033
5042 .. container:: verbose
5034 .. container:: verbose
5043
5035
5044 Some examples:
5036 Some examples:
5045
5037
5046 - changesets with full descriptions and file lists::
5038 - changesets with full descriptions and file lists::
5047
5039
5048 hg log -v
5040 hg log -v
5049
5041
5050 - changesets ancestral to the working directory::
5042 - changesets ancestral to the working directory::
5051
5043
5052 hg log -f
5044 hg log -f
5053
5045
5054 - last 10 commits on the current branch::
5046 - last 10 commits on the current branch::
5055
5047
5056 hg log -l 10 -b .
5048 hg log -l 10 -b .
5057
5049
5058 - changesets showing all modifications of a file, including removals::
5050 - changesets showing all modifications of a file, including removals::
5059
5051
5060 hg log --removed file.c
5052 hg log --removed file.c
5061
5053
5062 - all changesets that touch a directory, with diffs, excluding merges::
5054 - all changesets that touch a directory, with diffs, excluding merges::
5063
5055
5064 hg log -Mp lib/
5056 hg log -Mp lib/
5065
5057
5066 - all revision numbers that match a keyword::
5058 - all revision numbers that match a keyword::
5067
5059
5068 hg log -k bug --template "{rev}\\n"
5060 hg log -k bug --template "{rev}\\n"
5069
5061
5070 - the full hash identifier of the working directory parent::
5062 - the full hash identifier of the working directory parent::
5071
5063
5072 hg log -r . --template "{node}\\n"
5064 hg log -r . --template "{node}\\n"
5073
5065
5074 - list available log templates::
5066 - list available log templates::
5075
5067
5076 hg log -T list
5068 hg log -T list
5077
5069
5078 - check if a given changeset is included in a tagged release::
5070 - check if a given changeset is included in a tagged release::
5079
5071
5080 hg log -r "a21ccf and ancestor(1.9)"
5072 hg log -r "a21ccf and ancestor(1.9)"
5081
5073
5082 - find all changesets by some user in a date range::
5074 - find all changesets by some user in a date range::
5083
5075
5084 hg log -k alice -d "may 2008 to jul 2008"
5076 hg log -k alice -d "may 2008 to jul 2008"
5085
5077
5086 - summary of all changesets after the last tag::
5078 - summary of all changesets after the last tag::
5087
5079
5088 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5080 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5089
5081
5090 See :hg:`help dates` for a list of formats valid for -d/--date.
5082 See :hg:`help dates` for a list of formats valid for -d/--date.
5091
5083
5092 See :hg:`help revisions` and :hg:`help revsets` for more about
5084 See :hg:`help revisions` and :hg:`help revsets` for more about
5093 specifying and ordering revisions.
5085 specifying and ordering revisions.
5094
5086
5095 See :hg:`help templates` for more about pre-packaged styles and
5087 See :hg:`help templates` for more about pre-packaged styles and
5096 specifying custom templates.
5088 specifying custom templates.
5097
5089
5098 Returns 0 on success.
5090 Returns 0 on success.
5099
5091
5100 """
5092 """
5101 if opts.get('follow') and opts.get('rev'):
5093 if opts.get('follow') and opts.get('rev'):
5102 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5094 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5103 del opts['follow']
5095 del opts['follow']
5104
5096
5105 if opts.get('graph'):
5097 if opts.get('graph'):
5106 return cmdutil.graphlog(ui, repo, *pats, **opts)
5098 return cmdutil.graphlog(ui, repo, *pats, **opts)
5107
5099
5108 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5100 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5109 limit = cmdutil.loglimit(opts)
5101 limit = cmdutil.loglimit(opts)
5110 count = 0
5102 count = 0
5111
5103
5112 getrenamed = None
5104 getrenamed = None
5113 if opts.get('copies'):
5105 if opts.get('copies'):
5114 endrev = None
5106 endrev = None
5115 if opts.get('rev'):
5107 if opts.get('rev'):
5116 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5108 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5117 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5109 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5118
5110
5119 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5111 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5120 for rev in revs:
5112 for rev in revs:
5121 if count == limit:
5113 if count == limit:
5122 break
5114 break
5123 ctx = repo[rev]
5115 ctx = repo[rev]
5124 copies = None
5116 copies = None
5125 if getrenamed is not None and rev:
5117 if getrenamed is not None and rev:
5126 copies = []
5118 copies = []
5127 for fn in ctx.files():
5119 for fn in ctx.files():
5128 rename = getrenamed(fn, rev)
5120 rename = getrenamed(fn, rev)
5129 if rename:
5121 if rename:
5130 copies.append((fn, rename[0]))
5122 copies.append((fn, rename[0]))
5131 if filematcher:
5123 if filematcher:
5132 revmatchfn = filematcher(ctx.rev())
5124 revmatchfn = filematcher(ctx.rev())
5133 else:
5125 else:
5134 revmatchfn = None
5126 revmatchfn = None
5135 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5127 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5136 if displayer.flush(ctx):
5128 if displayer.flush(ctx):
5137 count += 1
5129 count += 1
5138
5130
5139 displayer.close()
5131 displayer.close()
5140
5132
5141 @command('manifest',
5133 @command('manifest',
5142 [('r', 'rev', '', _('revision to display'), _('REV')),
5134 [('r', 'rev', '', _('revision to display'), _('REV')),
5143 ('', 'all', False, _("list files from all revisions"))]
5135 ('', 'all', False, _("list files from all revisions"))]
5144 + formatteropts,
5136 + formatteropts,
5145 _('[-r REV]'))
5137 _('[-r REV]'))
5146 def manifest(ui, repo, node=None, rev=None, **opts):
5138 def manifest(ui, repo, node=None, rev=None, **opts):
5147 """output the current or given revision of the project manifest
5139 """output the current or given revision of the project manifest
5148
5140
5149 Print a list of version controlled files for the given revision.
5141 Print a list of version controlled files for the given revision.
5150 If no revision is given, the first parent of the working directory
5142 If no revision is given, the first parent of the working directory
5151 is used, or the null revision if no revision is checked out.
5143 is used, or the null revision if no revision is checked out.
5152
5144
5153 With -v, print file permissions, symlink and executable bits.
5145 With -v, print file permissions, symlink and executable bits.
5154 With --debug, print file revision hashes.
5146 With --debug, print file revision hashes.
5155
5147
5156 If option --all is specified, the list of all files from all revisions
5148 If option --all is specified, the list of all files from all revisions
5157 is printed. This includes deleted and renamed files.
5149 is printed. This includes deleted and renamed files.
5158
5150
5159 Returns 0 on success.
5151 Returns 0 on success.
5160 """
5152 """
5161
5153
5162 fm = ui.formatter('manifest', opts)
5154 fm = ui.formatter('manifest', opts)
5163
5155
5164 if opts.get('all'):
5156 if opts.get('all'):
5165 if rev or node:
5157 if rev or node:
5166 raise error.Abort(_("can't specify a revision with --all"))
5158 raise error.Abort(_("can't specify a revision with --all"))
5167
5159
5168 res = []
5160 res = []
5169 prefix = "data/"
5161 prefix = "data/"
5170 suffix = ".i"
5162 suffix = ".i"
5171 plen = len(prefix)
5163 plen = len(prefix)
5172 slen = len(suffix)
5164 slen = len(suffix)
5173 with repo.lock():
5165 with repo.lock():
5174 for fn, b, size in repo.store.datafiles():
5166 for fn, b, size in repo.store.datafiles():
5175 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5167 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5176 res.append(fn[plen:-slen])
5168 res.append(fn[plen:-slen])
5177 for f in res:
5169 for f in res:
5178 fm.startitem()
5170 fm.startitem()
5179 fm.write("path", '%s\n', f)
5171 fm.write("path", '%s\n', f)
5180 fm.end()
5172 fm.end()
5181 return
5173 return
5182
5174
5183 if rev and node:
5175 if rev and node:
5184 raise error.Abort(_("please specify just one revision"))
5176 raise error.Abort(_("please specify just one revision"))
5185
5177
5186 if not node:
5178 if not node:
5187 node = rev
5179 node = rev
5188
5180
5189 char = {'l': '@', 'x': '*', '': ''}
5181 char = {'l': '@', 'x': '*', '': ''}
5190 mode = {'l': '644', 'x': '755', '': '644'}
5182 mode = {'l': '644', 'x': '755', '': '644'}
5191 ctx = scmutil.revsingle(repo, node)
5183 ctx = scmutil.revsingle(repo, node)
5192 mf = ctx.manifest()
5184 mf = ctx.manifest()
5193 for f in ctx:
5185 for f in ctx:
5194 fm.startitem()
5186 fm.startitem()
5195 fl = ctx[f].flags()
5187 fl = ctx[f].flags()
5196 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5188 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5197 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5189 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5198 fm.write('path', '%s\n', f)
5190 fm.write('path', '%s\n', f)
5199 fm.end()
5191 fm.end()
5200
5192
5201 @command('^merge',
5193 @command('^merge',
5202 [('f', 'force', None,
5194 [('f', 'force', None,
5203 _('force a merge including outstanding changes (DEPRECATED)')),
5195 _('force a merge including outstanding changes (DEPRECATED)')),
5204 ('r', 'rev', '', _('revision to merge'), _('REV')),
5196 ('r', 'rev', '', _('revision to merge'), _('REV')),
5205 ('P', 'preview', None,
5197 ('P', 'preview', None,
5206 _('review revisions to merge (no merge is performed)'))
5198 _('review revisions to merge (no merge is performed)'))
5207 ] + mergetoolopts,
5199 ] + mergetoolopts,
5208 _('[-P] [[-r] REV]'))
5200 _('[-P] [[-r] REV]'))
5209 def merge(ui, repo, node=None, **opts):
5201 def merge(ui, repo, node=None, **opts):
5210 """merge another revision into working directory
5202 """merge another revision into working directory
5211
5203
5212 The current working directory is updated with all changes made in
5204 The current working directory is updated with all changes made in
5213 the requested revision since the last common predecessor revision.
5205 the requested revision since the last common predecessor revision.
5214
5206
5215 Files that changed between either parent are marked as changed for
5207 Files that changed between either parent are marked as changed for
5216 the next commit and a commit must be performed before any further
5208 the next commit and a commit must be performed before any further
5217 updates to the repository are allowed. The next commit will have
5209 updates to the repository are allowed. The next commit will have
5218 two parents.
5210 two parents.
5219
5211
5220 ``--tool`` can be used to specify the merge tool used for file
5212 ``--tool`` can be used to specify the merge tool used for file
5221 merges. It overrides the HGMERGE environment variable and your
5213 merges. It overrides the HGMERGE environment variable and your
5222 configuration files. See :hg:`help merge-tools` for options.
5214 configuration files. See :hg:`help merge-tools` for options.
5223
5215
5224 If no revision is specified, the working directory's parent is a
5216 If no revision is specified, the working directory's parent is a
5225 head revision, and the current branch contains exactly one other
5217 head revision, and the current branch contains exactly one other
5226 head, the other head is merged with by default. Otherwise, an
5218 head, the other head is merged with by default. Otherwise, an
5227 explicit revision with which to merge with must be provided.
5219 explicit revision with which to merge with must be provided.
5228
5220
5229 See :hg:`help resolve` for information on handling file conflicts.
5221 See :hg:`help resolve` for information on handling file conflicts.
5230
5222
5231 To undo an uncommitted merge, use :hg:`update --clean .` which
5223 To undo an uncommitted merge, use :hg:`update --clean .` which
5232 will check out a clean copy of the original merge parent, losing
5224 will check out a clean copy of the original merge parent, losing
5233 all changes.
5225 all changes.
5234
5226
5235 Returns 0 on success, 1 if there are unresolved files.
5227 Returns 0 on success, 1 if there are unresolved files.
5236 """
5228 """
5237
5229
5238 if opts.get('rev') and node:
5230 if opts.get('rev') and node:
5239 raise error.Abort(_("please specify just one revision"))
5231 raise error.Abort(_("please specify just one revision"))
5240 if not node:
5232 if not node:
5241 node = opts.get('rev')
5233 node = opts.get('rev')
5242
5234
5243 if node:
5235 if node:
5244 node = scmutil.revsingle(repo, node).node()
5236 node = scmutil.revsingle(repo, node).node()
5245
5237
5246 if not node:
5238 if not node:
5247 node = repo[destutil.destmerge(repo)].node()
5239 node = repo[destutil.destmerge(repo)].node()
5248
5240
5249 if opts.get('preview'):
5241 if opts.get('preview'):
5250 # find nodes that are ancestors of p2 but not of p1
5242 # find nodes that are ancestors of p2 but not of p1
5251 p1 = repo.lookup('.')
5243 p1 = repo.lookup('.')
5252 p2 = repo.lookup(node)
5244 p2 = repo.lookup(node)
5253 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5245 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5254
5246
5255 displayer = cmdutil.show_changeset(ui, repo, opts)
5247 displayer = cmdutil.show_changeset(ui, repo, opts)
5256 for node in nodes:
5248 for node in nodes:
5257 displayer.show(repo[node])
5249 displayer.show(repo[node])
5258 displayer.close()
5250 displayer.close()
5259 return 0
5251 return 0
5260
5252
5261 try:
5253 try:
5262 # ui.forcemerge is an internal variable, do not document
5254 # ui.forcemerge is an internal variable, do not document
5263 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5255 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5264 force = opts.get('force')
5256 force = opts.get('force')
5265 labels = ['working copy', 'merge rev']
5257 labels = ['working copy', 'merge rev']
5266 return hg.merge(repo, node, force=force, mergeforce=force,
5258 return hg.merge(repo, node, force=force, mergeforce=force,
5267 labels=labels)
5259 labels=labels)
5268 finally:
5260 finally:
5269 ui.setconfig('ui', 'forcemerge', '', 'merge')
5261 ui.setconfig('ui', 'forcemerge', '', 'merge')
5270
5262
5271 @command('outgoing|out',
5263 @command('outgoing|out',
5272 [('f', 'force', None, _('run even when the destination is unrelated')),
5264 [('f', 'force', None, _('run even when the destination is unrelated')),
5273 ('r', 'rev', [],
5265 ('r', 'rev', [],
5274 _('a changeset intended to be included in the destination'), _('REV')),
5266 _('a changeset intended to be included in the destination'), _('REV')),
5275 ('n', 'newest-first', None, _('show newest record first')),
5267 ('n', 'newest-first', None, _('show newest record first')),
5276 ('B', 'bookmarks', False, _('compare bookmarks')),
5268 ('B', 'bookmarks', False, _('compare bookmarks')),
5277 ('b', 'branch', [], _('a specific branch you would like to push'),
5269 ('b', 'branch', [], _('a specific branch you would like to push'),
5278 _('BRANCH')),
5270 _('BRANCH')),
5279 ] + logopts + remoteopts + subrepoopts,
5271 ] + logopts + remoteopts + subrepoopts,
5280 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5272 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5281 def outgoing(ui, repo, dest=None, **opts):
5273 def outgoing(ui, repo, dest=None, **opts):
5282 """show changesets not found in the destination
5274 """show changesets not found in the destination
5283
5275
5284 Show changesets not found in the specified destination repository
5276 Show changesets not found in the specified destination repository
5285 or the default push location. These are the changesets that would
5277 or the default push location. These are the changesets that would
5286 be pushed if a push was requested.
5278 be pushed if a push was requested.
5287
5279
5288 See pull for details of valid destination formats.
5280 See pull for details of valid destination formats.
5289
5281
5290 .. container:: verbose
5282 .. container:: verbose
5291
5283
5292 With -B/--bookmarks, the result of bookmark comparison between
5284 With -B/--bookmarks, the result of bookmark comparison between
5293 local and remote repositories is displayed. With -v/--verbose,
5285 local and remote repositories is displayed. With -v/--verbose,
5294 status is also displayed for each bookmark like below::
5286 status is also displayed for each bookmark like below::
5295
5287
5296 BM1 01234567890a added
5288 BM1 01234567890a added
5297 BM2 deleted
5289 BM2 deleted
5298 BM3 234567890abc advanced
5290 BM3 234567890abc advanced
5299 BM4 34567890abcd diverged
5291 BM4 34567890abcd diverged
5300 BM5 4567890abcde changed
5292 BM5 4567890abcde changed
5301
5293
5302 The action taken when pushing depends on the
5294 The action taken when pushing depends on the
5303 status of each bookmark:
5295 status of each bookmark:
5304
5296
5305 :``added``: push with ``-B`` will create it
5297 :``added``: push with ``-B`` will create it
5306 :``deleted``: push with ``-B`` will delete it
5298 :``deleted``: push with ``-B`` will delete it
5307 :``advanced``: push will update it
5299 :``advanced``: push will update it
5308 :``diverged``: push with ``-B`` will update it
5300 :``diverged``: push with ``-B`` will update it
5309 :``changed``: push with ``-B`` will update it
5301 :``changed``: push with ``-B`` will update it
5310
5302
5311 From the point of view of pushing behavior, bookmarks
5303 From the point of view of pushing behavior, bookmarks
5312 existing only in the remote repository are treated as
5304 existing only in the remote repository are treated as
5313 ``deleted``, even if it is in fact added remotely.
5305 ``deleted``, even if it is in fact added remotely.
5314
5306
5315 Returns 0 if there are outgoing changes, 1 otherwise.
5307 Returns 0 if there are outgoing changes, 1 otherwise.
5316 """
5308 """
5317 if opts.get('graph'):
5309 if opts.get('graph'):
5318 cmdutil.checkunsupportedgraphflags([], opts)
5310 cmdutil.checkunsupportedgraphflags([], opts)
5319 o, other = hg._outgoing(ui, repo, dest, opts)
5311 o, other = hg._outgoing(ui, repo, dest, opts)
5320 if not o:
5312 if not o:
5321 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5313 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5322 return
5314 return
5323
5315
5324 revdag = cmdutil.graphrevs(repo, o, opts)
5316 revdag = cmdutil.graphrevs(repo, o, opts)
5325 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5317 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5326 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5318 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5327 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5319 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5328 return 0
5320 return 0
5329
5321
5330 if opts.get('bookmarks'):
5322 if opts.get('bookmarks'):
5331 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5323 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5332 dest, branches = hg.parseurl(dest, opts.get('branch'))
5324 dest, branches = hg.parseurl(dest, opts.get('branch'))
5333 other = hg.peer(repo, opts, dest)
5325 other = hg.peer(repo, opts, dest)
5334 if 'bookmarks' not in other.listkeys('namespaces'):
5326 if 'bookmarks' not in other.listkeys('namespaces'):
5335 ui.warn(_("remote doesn't support bookmarks\n"))
5327 ui.warn(_("remote doesn't support bookmarks\n"))
5336 return 0
5328 return 0
5337 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5329 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5338 return bookmarks.outgoing(ui, repo, other)
5330 return bookmarks.outgoing(ui, repo, other)
5339
5331
5340 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5332 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5341 try:
5333 try:
5342 return hg.outgoing(ui, repo, dest, opts)
5334 return hg.outgoing(ui, repo, dest, opts)
5343 finally:
5335 finally:
5344 del repo._subtoppath
5336 del repo._subtoppath
5345
5337
5346 @command('parents',
5338 @command('parents',
5347 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5339 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5348 ] + templateopts,
5340 ] + templateopts,
5349 _('[-r REV] [FILE]'),
5341 _('[-r REV] [FILE]'),
5350 inferrepo=True)
5342 inferrepo=True)
5351 def parents(ui, repo, file_=None, **opts):
5343 def parents(ui, repo, file_=None, **opts):
5352 """show the parents of the working directory or revision (DEPRECATED)
5344 """show the parents of the working directory or revision (DEPRECATED)
5353
5345
5354 Print the working directory's parent revisions. If a revision is
5346 Print the working directory's parent revisions. If a revision is
5355 given via -r/--rev, the parent of that revision will be printed.
5347 given via -r/--rev, the parent of that revision will be printed.
5356 If a file argument is given, the revision in which the file was
5348 If a file argument is given, the revision in which the file was
5357 last changed (before the working directory revision or the
5349 last changed (before the working directory revision or the
5358 argument to --rev if given) is printed.
5350 argument to --rev if given) is printed.
5359
5351
5360 This command is equivalent to::
5352 This command is equivalent to::
5361
5353
5362 hg log -r "p1()+p2()" or
5354 hg log -r "p1()+p2()" or
5363 hg log -r "p1(REV)+p2(REV)" or
5355 hg log -r "p1(REV)+p2(REV)" or
5364 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5356 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5365 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5357 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5366
5358
5367 See :hg:`summary` and :hg:`help revsets` for related information.
5359 See :hg:`summary` and :hg:`help revsets` for related information.
5368
5360
5369 Returns 0 on success.
5361 Returns 0 on success.
5370 """
5362 """
5371
5363
5372 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5364 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5373
5365
5374 if file_:
5366 if file_:
5375 m = scmutil.match(ctx, (file_,), opts)
5367 m = scmutil.match(ctx, (file_,), opts)
5376 if m.anypats() or len(m.files()) != 1:
5368 if m.anypats() or len(m.files()) != 1:
5377 raise error.Abort(_('can only specify an explicit filename'))
5369 raise error.Abort(_('can only specify an explicit filename'))
5378 file_ = m.files()[0]
5370 file_ = m.files()[0]
5379 filenodes = []
5371 filenodes = []
5380 for cp in ctx.parents():
5372 for cp in ctx.parents():
5381 if not cp:
5373 if not cp:
5382 continue
5374 continue
5383 try:
5375 try:
5384 filenodes.append(cp.filenode(file_))
5376 filenodes.append(cp.filenode(file_))
5385 except error.LookupError:
5377 except error.LookupError:
5386 pass
5378 pass
5387 if not filenodes:
5379 if not filenodes:
5388 raise error.Abort(_("'%s' not found in manifest!") % file_)
5380 raise error.Abort(_("'%s' not found in manifest!") % file_)
5389 p = []
5381 p = []
5390 for fn in filenodes:
5382 for fn in filenodes:
5391 fctx = repo.filectx(file_, fileid=fn)
5383 fctx = repo.filectx(file_, fileid=fn)
5392 p.append(fctx.node())
5384 p.append(fctx.node())
5393 else:
5385 else:
5394 p = [cp.node() for cp in ctx.parents()]
5386 p = [cp.node() for cp in ctx.parents()]
5395
5387
5396 displayer = cmdutil.show_changeset(ui, repo, opts)
5388 displayer = cmdutil.show_changeset(ui, repo, opts)
5397 for n in p:
5389 for n in p:
5398 if n != nullid:
5390 if n != nullid:
5399 displayer.show(repo[n])
5391 displayer.show(repo[n])
5400 displayer.close()
5392 displayer.close()
5401
5393
5402 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5394 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5403 def paths(ui, repo, search=None, **opts):
5395 def paths(ui, repo, search=None, **opts):
5404 """show aliases for remote repositories
5396 """show aliases for remote repositories
5405
5397
5406 Show definition of symbolic path name NAME. If no name is given,
5398 Show definition of symbolic path name NAME. If no name is given,
5407 show definition of all available names.
5399 show definition of all available names.
5408
5400
5409 Option -q/--quiet suppresses all output when searching for NAME
5401 Option -q/--quiet suppresses all output when searching for NAME
5410 and shows only the path names when listing all definitions.
5402 and shows only the path names when listing all definitions.
5411
5403
5412 Path names are defined in the [paths] section of your
5404 Path names are defined in the [paths] section of your
5413 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5405 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5414 repository, ``.hg/hgrc`` is used, too.
5406 repository, ``.hg/hgrc`` is used, too.
5415
5407
5416 The path names ``default`` and ``default-push`` have a special
5408 The path names ``default`` and ``default-push`` have a special
5417 meaning. When performing a push or pull operation, they are used
5409 meaning. When performing a push or pull operation, they are used
5418 as fallbacks if no location is specified on the command-line.
5410 as fallbacks if no location is specified on the command-line.
5419 When ``default-push`` is set, it will be used for push and
5411 When ``default-push`` is set, it will be used for push and
5420 ``default`` will be used for pull; otherwise ``default`` is used
5412 ``default`` will be used for pull; otherwise ``default`` is used
5421 as the fallback for both. When cloning a repository, the clone
5413 as the fallback for both. When cloning a repository, the clone
5422 source is written as ``default`` in ``.hg/hgrc``.
5414 source is written as ``default`` in ``.hg/hgrc``.
5423
5415
5424 .. note::
5416 .. note::
5425
5417
5426 ``default`` and ``default-push`` apply to all inbound (e.g.
5418 ``default`` and ``default-push`` apply to all inbound (e.g.
5427 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5419 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5428 and :hg:`bundle`) operations.
5420 and :hg:`bundle`) operations.
5429
5421
5430 See :hg:`help urls` for more information.
5422 See :hg:`help urls` for more information.
5431
5423
5432 Returns 0 on success.
5424 Returns 0 on success.
5433 """
5425 """
5434 if search:
5426 if search:
5435 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5427 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5436 if name == search]
5428 if name == search]
5437 else:
5429 else:
5438 pathitems = sorted(ui.paths.iteritems())
5430 pathitems = sorted(ui.paths.iteritems())
5439
5431
5440 fm = ui.formatter('paths', opts)
5432 fm = ui.formatter('paths', opts)
5441 if fm.isplain():
5433 if fm.isplain():
5442 hidepassword = util.hidepassword
5434 hidepassword = util.hidepassword
5443 else:
5435 else:
5444 hidepassword = str
5436 hidepassword = str
5445 if ui.quiet:
5437 if ui.quiet:
5446 namefmt = '%s\n'
5438 namefmt = '%s\n'
5447 else:
5439 else:
5448 namefmt = '%s = '
5440 namefmt = '%s = '
5449 showsubopts = not search and not ui.quiet
5441 showsubopts = not search and not ui.quiet
5450
5442
5451 for name, path in pathitems:
5443 for name, path in pathitems:
5452 fm.startitem()
5444 fm.startitem()
5453 fm.condwrite(not search, 'name', namefmt, name)
5445 fm.condwrite(not search, 'name', namefmt, name)
5454 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5446 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5455 for subopt, value in sorted(path.suboptions.items()):
5447 for subopt, value in sorted(path.suboptions.items()):
5456 assert subopt not in ('name', 'url')
5448 assert subopt not in ('name', 'url')
5457 if showsubopts:
5449 if showsubopts:
5458 fm.plain('%s:%s = ' % (name, subopt))
5450 fm.plain('%s:%s = ' % (name, subopt))
5459 fm.condwrite(showsubopts, subopt, '%s\n', value)
5451 fm.condwrite(showsubopts, subopt, '%s\n', value)
5460
5452
5461 fm.end()
5453 fm.end()
5462
5454
5463 if search and not pathitems:
5455 if search and not pathitems:
5464 if not ui.quiet:
5456 if not ui.quiet:
5465 ui.warn(_("not found!\n"))
5457 ui.warn(_("not found!\n"))
5466 return 1
5458 return 1
5467 else:
5459 else:
5468 return 0
5460 return 0
5469
5461
5470 @command('phase',
5462 @command('phase',
5471 [('p', 'public', False, _('set changeset phase to public')),
5463 [('p', 'public', False, _('set changeset phase to public')),
5472 ('d', 'draft', False, _('set changeset phase to draft')),
5464 ('d', 'draft', False, _('set changeset phase to draft')),
5473 ('s', 'secret', False, _('set changeset phase to secret')),
5465 ('s', 'secret', False, _('set changeset phase to secret')),
5474 ('f', 'force', False, _('allow to move boundary backward')),
5466 ('f', 'force', False, _('allow to move boundary backward')),
5475 ('r', 'rev', [], _('target revision'), _('REV')),
5467 ('r', 'rev', [], _('target revision'), _('REV')),
5476 ],
5468 ],
5477 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5469 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5478 def phase(ui, repo, *revs, **opts):
5470 def phase(ui, repo, *revs, **opts):
5479 """set or show the current phase name
5471 """set or show the current phase name
5480
5472
5481 With no argument, show the phase name of the current revision(s).
5473 With no argument, show the phase name of the current revision(s).
5482
5474
5483 With one of -p/--public, -d/--draft or -s/--secret, change the
5475 With one of -p/--public, -d/--draft or -s/--secret, change the
5484 phase value of the specified revisions.
5476 phase value of the specified revisions.
5485
5477
5486 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5478 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5487 lower phase to an higher phase. Phases are ordered as follows::
5479 lower phase to an higher phase. Phases are ordered as follows::
5488
5480
5489 public < draft < secret
5481 public < draft < secret
5490
5482
5491 Returns 0 on success, 1 if some phases could not be changed.
5483 Returns 0 on success, 1 if some phases could not be changed.
5492
5484
5493 (For more information about the phases concept, see :hg:`help phases`.)
5485 (For more information about the phases concept, see :hg:`help phases`.)
5494 """
5486 """
5495 # search for a unique phase argument
5487 # search for a unique phase argument
5496 targetphase = None
5488 targetphase = None
5497 for idx, name in enumerate(phases.phasenames):
5489 for idx, name in enumerate(phases.phasenames):
5498 if opts[name]:
5490 if opts[name]:
5499 if targetphase is not None:
5491 if targetphase is not None:
5500 raise error.Abort(_('only one phase can be specified'))
5492 raise error.Abort(_('only one phase can be specified'))
5501 targetphase = idx
5493 targetphase = idx
5502
5494
5503 # look for specified revision
5495 # look for specified revision
5504 revs = list(revs)
5496 revs = list(revs)
5505 revs.extend(opts['rev'])
5497 revs.extend(opts['rev'])
5506 if not revs:
5498 if not revs:
5507 # display both parents as the second parent phase can influence
5499 # display both parents as the second parent phase can influence
5508 # the phase of a merge commit
5500 # the phase of a merge commit
5509 revs = [c.rev() for c in repo[None].parents()]
5501 revs = [c.rev() for c in repo[None].parents()]
5510
5502
5511 revs = scmutil.revrange(repo, revs)
5503 revs = scmutil.revrange(repo, revs)
5512
5504
5513 lock = None
5505 lock = None
5514 ret = 0
5506 ret = 0
5515 if targetphase is None:
5507 if targetphase is None:
5516 # display
5508 # display
5517 for r in revs:
5509 for r in revs:
5518 ctx = repo[r]
5510 ctx = repo[r]
5519 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5511 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5520 else:
5512 else:
5521 tr = None
5513 tr = None
5522 lock = repo.lock()
5514 lock = repo.lock()
5523 try:
5515 try:
5524 tr = repo.transaction("phase")
5516 tr = repo.transaction("phase")
5525 # set phase
5517 # set phase
5526 if not revs:
5518 if not revs:
5527 raise error.Abort(_('empty revision set'))
5519 raise error.Abort(_('empty revision set'))
5528 nodes = [repo[r].node() for r in revs]
5520 nodes = [repo[r].node() for r in revs]
5529 # moving revision from public to draft may hide them
5521 # moving revision from public to draft may hide them
5530 # We have to check result on an unfiltered repository
5522 # We have to check result on an unfiltered repository
5531 unfi = repo.unfiltered()
5523 unfi = repo.unfiltered()
5532 getphase = unfi._phasecache.phase
5524 getphase = unfi._phasecache.phase
5533 olddata = [getphase(unfi, r) for r in unfi]
5525 olddata = [getphase(unfi, r) for r in unfi]
5534 phases.advanceboundary(repo, tr, targetphase, nodes)
5526 phases.advanceboundary(repo, tr, targetphase, nodes)
5535 if opts['force']:
5527 if opts['force']:
5536 phases.retractboundary(repo, tr, targetphase, nodes)
5528 phases.retractboundary(repo, tr, targetphase, nodes)
5537 tr.close()
5529 tr.close()
5538 finally:
5530 finally:
5539 if tr is not None:
5531 if tr is not None:
5540 tr.release()
5532 tr.release()
5541 lock.release()
5533 lock.release()
5542 getphase = unfi._phasecache.phase
5534 getphase = unfi._phasecache.phase
5543 newdata = [getphase(unfi, r) for r in unfi]
5535 newdata = [getphase(unfi, r) for r in unfi]
5544 changes = sum(newdata[r] != olddata[r] for r in unfi)
5536 changes = sum(newdata[r] != olddata[r] for r in unfi)
5545 cl = unfi.changelog
5537 cl = unfi.changelog
5546 rejected = [n for n in nodes
5538 rejected = [n for n in nodes
5547 if newdata[cl.rev(n)] < targetphase]
5539 if newdata[cl.rev(n)] < targetphase]
5548 if rejected:
5540 if rejected:
5549 ui.warn(_('cannot move %i changesets to a higher '
5541 ui.warn(_('cannot move %i changesets to a higher '
5550 'phase, use --force\n') % len(rejected))
5542 'phase, use --force\n') % len(rejected))
5551 ret = 1
5543 ret = 1
5552 if changes:
5544 if changes:
5553 msg = _('phase changed for %i changesets\n') % changes
5545 msg = _('phase changed for %i changesets\n') % changes
5554 if ret:
5546 if ret:
5555 ui.status(msg)
5547 ui.status(msg)
5556 else:
5548 else:
5557 ui.note(msg)
5549 ui.note(msg)
5558 else:
5550 else:
5559 ui.warn(_('no phases changed\n'))
5551 ui.warn(_('no phases changed\n'))
5560 return ret
5552 return ret
5561
5553
5562 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5554 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5563 """Run after a changegroup has been added via pull/unbundle
5555 """Run after a changegroup has been added via pull/unbundle
5564
5556
5565 This takes arguments below:
5557 This takes arguments below:
5566
5558
5567 :modheads: change of heads by pull/unbundle
5559 :modheads: change of heads by pull/unbundle
5568 :optupdate: updating working directory is needed or not
5560 :optupdate: updating working directory is needed or not
5569 :checkout: update destination revision (or None to default destination)
5561 :checkout: update destination revision (or None to default destination)
5570 :brev: a name, which might be a bookmark to be activated after updating
5562 :brev: a name, which might be a bookmark to be activated after updating
5571 """
5563 """
5572 if modheads == 0:
5564 if modheads == 0:
5573 return
5565 return
5574 if optupdate:
5566 if optupdate:
5575 try:
5567 try:
5576 return hg.updatetotally(ui, repo, checkout, brev)
5568 return hg.updatetotally(ui, repo, checkout, brev)
5577 except error.UpdateAbort as inst:
5569 except error.UpdateAbort as inst:
5578 msg = _("not updating: %s") % str(inst)
5570 msg = _("not updating: %s") % str(inst)
5579 hint = inst.hint
5571 hint = inst.hint
5580 raise error.UpdateAbort(msg, hint=hint)
5572 raise error.UpdateAbort(msg, hint=hint)
5581 if modheads > 1:
5573 if modheads > 1:
5582 currentbranchheads = len(repo.branchheads())
5574 currentbranchheads = len(repo.branchheads())
5583 if currentbranchheads == modheads:
5575 if currentbranchheads == modheads:
5584 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5576 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5585 elif currentbranchheads > 1:
5577 elif currentbranchheads > 1:
5586 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5578 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5587 "merge)\n"))
5579 "merge)\n"))
5588 else:
5580 else:
5589 ui.status(_("(run 'hg heads' to see heads)\n"))
5581 ui.status(_("(run 'hg heads' to see heads)\n"))
5590 else:
5582 else:
5591 ui.status(_("(run 'hg update' to get a working copy)\n"))
5583 ui.status(_("(run 'hg update' to get a working copy)\n"))
5592
5584
5593 @command('^pull',
5585 @command('^pull',
5594 [('u', 'update', None,
5586 [('u', 'update', None,
5595 _('update to new branch head if changesets were pulled')),
5587 _('update to new branch head if changesets were pulled')),
5596 ('f', 'force', None, _('run even when remote repository is unrelated')),
5588 ('f', 'force', None, _('run even when remote repository is unrelated')),
5597 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5589 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5598 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5590 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5599 ('b', 'branch', [], _('a specific branch you would like to pull'),
5591 ('b', 'branch', [], _('a specific branch you would like to pull'),
5600 _('BRANCH')),
5592 _('BRANCH')),
5601 ] + remoteopts,
5593 ] + remoteopts,
5602 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5594 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5603 def pull(ui, repo, source="default", **opts):
5595 def pull(ui, repo, source="default", **opts):
5604 """pull changes from the specified source
5596 """pull changes from the specified source
5605
5597
5606 Pull changes from a remote repository to a local one.
5598 Pull changes from a remote repository to a local one.
5607
5599
5608 This finds all changes from the repository at the specified path
5600 This finds all changes from the repository at the specified path
5609 or URL and adds them to a local repository (the current one unless
5601 or URL and adds them to a local repository (the current one unless
5610 -R is specified). By default, this does not update the copy of the
5602 -R is specified). By default, this does not update the copy of the
5611 project in the working directory.
5603 project in the working directory.
5612
5604
5613 Use :hg:`incoming` if you want to see what would have been added
5605 Use :hg:`incoming` if you want to see what would have been added
5614 by a pull at the time you issued this command. If you then decide
5606 by a pull at the time you issued this command. If you then decide
5615 to add those changes to the repository, you should use :hg:`pull
5607 to add those changes to the repository, you should use :hg:`pull
5616 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5608 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5617
5609
5618 If SOURCE is omitted, the 'default' path will be used.
5610 If SOURCE is omitted, the 'default' path will be used.
5619 See :hg:`help urls` for more information.
5611 See :hg:`help urls` for more information.
5620
5612
5621 Specifying bookmark as ``.`` is equivalent to specifying the active
5613 Specifying bookmark as ``.`` is equivalent to specifying the active
5622 bookmark's name.
5614 bookmark's name.
5623
5615
5624 Returns 0 on success, 1 if an update had unresolved files.
5616 Returns 0 on success, 1 if an update had unresolved files.
5625 """
5617 """
5626 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5618 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5627 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5619 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5628 other = hg.peer(repo, opts, source)
5620 other = hg.peer(repo, opts, source)
5629 try:
5621 try:
5630 revs, checkout = hg.addbranchrevs(repo, other, branches,
5622 revs, checkout = hg.addbranchrevs(repo, other, branches,
5631 opts.get('rev'))
5623 opts.get('rev'))
5632
5624
5633
5625
5634 pullopargs = {}
5626 pullopargs = {}
5635 if opts.get('bookmark'):
5627 if opts.get('bookmark'):
5636 if not revs:
5628 if not revs:
5637 revs = []
5629 revs = []
5638 # The list of bookmark used here is not the one used to actually
5630 # The list of bookmark used here is not the one used to actually
5639 # update the bookmark name. This can result in the revision pulled
5631 # update the bookmark name. This can result in the revision pulled
5640 # not ending up with the name of the bookmark because of a race
5632 # not ending up with the name of the bookmark because of a race
5641 # condition on the server. (See issue 4689 for details)
5633 # condition on the server. (See issue 4689 for details)
5642 remotebookmarks = other.listkeys('bookmarks')
5634 remotebookmarks = other.listkeys('bookmarks')
5643 pullopargs['remotebookmarks'] = remotebookmarks
5635 pullopargs['remotebookmarks'] = remotebookmarks
5644 for b in opts['bookmark']:
5636 for b in opts['bookmark']:
5645 b = repo._bookmarks.expandname(b)
5637 b = repo._bookmarks.expandname(b)
5646 if b not in remotebookmarks:
5638 if b not in remotebookmarks:
5647 raise error.Abort(_('remote bookmark %s not found!') % b)
5639 raise error.Abort(_('remote bookmark %s not found!') % b)
5648 revs.append(remotebookmarks[b])
5640 revs.append(remotebookmarks[b])
5649
5641
5650 if revs:
5642 if revs:
5651 try:
5643 try:
5652 # When 'rev' is a bookmark name, we cannot guarantee that it
5644 # When 'rev' is a bookmark name, we cannot guarantee that it
5653 # will be updated with that name because of a race condition
5645 # will be updated with that name because of a race condition
5654 # server side. (See issue 4689 for details)
5646 # server side. (See issue 4689 for details)
5655 oldrevs = revs
5647 oldrevs = revs
5656 revs = [] # actually, nodes
5648 revs = [] # actually, nodes
5657 for r in oldrevs:
5649 for r in oldrevs:
5658 node = other.lookup(r)
5650 node = other.lookup(r)
5659 revs.append(node)
5651 revs.append(node)
5660 if r == checkout:
5652 if r == checkout:
5661 checkout = node
5653 checkout = node
5662 except error.CapabilityError:
5654 except error.CapabilityError:
5663 err = _("other repository doesn't support revision lookup, "
5655 err = _("other repository doesn't support revision lookup, "
5664 "so a rev cannot be specified.")
5656 "so a rev cannot be specified.")
5665 raise error.Abort(err)
5657 raise error.Abort(err)
5666
5658
5667 pullopargs.update(opts.get('opargs', {}))
5659 pullopargs.update(opts.get('opargs', {}))
5668 modheads = exchange.pull(repo, other, heads=revs,
5660 modheads = exchange.pull(repo, other, heads=revs,
5669 force=opts.get('force'),
5661 force=opts.get('force'),
5670 bookmarks=opts.get('bookmark', ()),
5662 bookmarks=opts.get('bookmark', ()),
5671 opargs=pullopargs).cgresult
5663 opargs=pullopargs).cgresult
5672
5664
5673 # brev is a name, which might be a bookmark to be activated at
5665 # brev is a name, which might be a bookmark to be activated at
5674 # the end of the update. In other words, it is an explicit
5666 # the end of the update. In other words, it is an explicit
5675 # destination of the update
5667 # destination of the update
5676 brev = None
5668 brev = None
5677
5669
5678 if checkout:
5670 if checkout:
5679 checkout = str(repo.changelog.rev(checkout))
5671 checkout = str(repo.changelog.rev(checkout))
5680
5672
5681 # order below depends on implementation of
5673 # order below depends on implementation of
5682 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5674 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5683 # because 'checkout' is determined without it.
5675 # because 'checkout' is determined without it.
5684 if opts.get('rev'):
5676 if opts.get('rev'):
5685 brev = opts['rev'][0]
5677 brev = opts['rev'][0]
5686 elif opts.get('branch'):
5678 elif opts.get('branch'):
5687 brev = opts['branch'][0]
5679 brev = opts['branch'][0]
5688 else:
5680 else:
5689 brev = branches[0]
5681 brev = branches[0]
5690 repo._subtoppath = source
5682 repo._subtoppath = source
5691 try:
5683 try:
5692 ret = postincoming(ui, repo, modheads, opts.get('update'),
5684 ret = postincoming(ui, repo, modheads, opts.get('update'),
5693 checkout, brev)
5685 checkout, brev)
5694
5686
5695 finally:
5687 finally:
5696 del repo._subtoppath
5688 del repo._subtoppath
5697
5689
5698 finally:
5690 finally:
5699 other.close()
5691 other.close()
5700 return ret
5692 return ret
5701
5693
5702 @command('^push',
5694 @command('^push',
5703 [('f', 'force', None, _('force push')),
5695 [('f', 'force', None, _('force push')),
5704 ('r', 'rev', [],
5696 ('r', 'rev', [],
5705 _('a changeset intended to be included in the destination'),
5697 _('a changeset intended to be included in the destination'),
5706 _('REV')),
5698 _('REV')),
5707 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5699 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5708 ('b', 'branch', [],
5700 ('b', 'branch', [],
5709 _('a specific branch you would like to push'), _('BRANCH')),
5701 _('a specific branch you would like to push'), _('BRANCH')),
5710 ('', 'new-branch', False, _('allow pushing a new branch')),
5702 ('', 'new-branch', False, _('allow pushing a new branch')),
5711 ] + remoteopts,
5703 ] + remoteopts,
5712 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5704 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5713 def push(ui, repo, dest=None, **opts):
5705 def push(ui, repo, dest=None, **opts):
5714 """push changes to the specified destination
5706 """push changes to the specified destination
5715
5707
5716 Push changesets from the local repository to the specified
5708 Push changesets from the local repository to the specified
5717 destination.
5709 destination.
5718
5710
5719 This operation is symmetrical to pull: it is identical to a pull
5711 This operation is symmetrical to pull: it is identical to a pull
5720 in the destination repository from the current one.
5712 in the destination repository from the current one.
5721
5713
5722 By default, push will not allow creation of new heads at the
5714 By default, push will not allow creation of new heads at the
5723 destination, since multiple heads would make it unclear which head
5715 destination, since multiple heads would make it unclear which head
5724 to use. In this situation, it is recommended to pull and merge
5716 to use. In this situation, it is recommended to pull and merge
5725 before pushing.
5717 before pushing.
5726
5718
5727 Use --new-branch if you want to allow push to create a new named
5719 Use --new-branch if you want to allow push to create a new named
5728 branch that is not present at the destination. This allows you to
5720 branch that is not present at the destination. This allows you to
5729 only create a new branch without forcing other changes.
5721 only create a new branch without forcing other changes.
5730
5722
5731 .. note::
5723 .. note::
5732
5724
5733 Extra care should be taken with the -f/--force option,
5725 Extra care should be taken with the -f/--force option,
5734 which will push all new heads on all branches, an action which will
5726 which will push all new heads on all branches, an action which will
5735 almost always cause confusion for collaborators.
5727 almost always cause confusion for collaborators.
5736
5728
5737 If -r/--rev is used, the specified revision and all its ancestors
5729 If -r/--rev is used, the specified revision and all its ancestors
5738 will be pushed to the remote repository.
5730 will be pushed to the remote repository.
5739
5731
5740 If -B/--bookmark is used, the specified bookmarked revision, its
5732 If -B/--bookmark is used, the specified bookmarked revision, its
5741 ancestors, and the bookmark will be pushed to the remote
5733 ancestors, and the bookmark will be pushed to the remote
5742 repository. Specifying ``.`` is equivalent to specifying the active
5734 repository. Specifying ``.`` is equivalent to specifying the active
5743 bookmark's name.
5735 bookmark's name.
5744
5736
5745 Please see :hg:`help urls` for important details about ``ssh://``
5737 Please see :hg:`help urls` for important details about ``ssh://``
5746 URLs. If DESTINATION is omitted, a default path will be used.
5738 URLs. If DESTINATION is omitted, a default path will be used.
5747
5739
5748 Returns 0 if push was successful, 1 if nothing to push.
5740 Returns 0 if push was successful, 1 if nothing to push.
5749 """
5741 """
5750
5742
5751 if opts.get('bookmark'):
5743 if opts.get('bookmark'):
5752 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5744 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5753 for b in opts['bookmark']:
5745 for b in opts['bookmark']:
5754 # translate -B options to -r so changesets get pushed
5746 # translate -B options to -r so changesets get pushed
5755 b = repo._bookmarks.expandname(b)
5747 b = repo._bookmarks.expandname(b)
5756 if b in repo._bookmarks:
5748 if b in repo._bookmarks:
5757 opts.setdefault('rev', []).append(b)
5749 opts.setdefault('rev', []).append(b)
5758 else:
5750 else:
5759 # if we try to push a deleted bookmark, translate it to null
5751 # if we try to push a deleted bookmark, translate it to null
5760 # this lets simultaneous -r, -b options continue working
5752 # this lets simultaneous -r, -b options continue working
5761 opts.setdefault('rev', []).append("null")
5753 opts.setdefault('rev', []).append("null")
5762
5754
5763 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5755 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5764 if not path:
5756 if not path:
5765 raise error.Abort(_('default repository not configured!'),
5757 raise error.Abort(_('default repository not configured!'),
5766 hint=_("see 'hg help config.paths'"))
5758 hint=_("see 'hg help config.paths'"))
5767 dest = path.pushloc or path.loc
5759 dest = path.pushloc or path.loc
5768 branches = (path.branch, opts.get('branch') or [])
5760 branches = (path.branch, opts.get('branch') or [])
5769 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5761 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5770 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5762 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5771 other = hg.peer(repo, opts, dest)
5763 other = hg.peer(repo, opts, dest)
5772
5764
5773 if revs:
5765 if revs:
5774 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5766 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5775 if not revs:
5767 if not revs:
5776 raise error.Abort(_("specified revisions evaluate to an empty set"),
5768 raise error.Abort(_("specified revisions evaluate to an empty set"),
5777 hint=_("use different revision arguments"))
5769 hint=_("use different revision arguments"))
5778 elif path.pushrev:
5770 elif path.pushrev:
5779 # It doesn't make any sense to specify ancestor revisions. So limit
5771 # It doesn't make any sense to specify ancestor revisions. So limit
5780 # to DAG heads to make discovery simpler.
5772 # to DAG heads to make discovery simpler.
5781 expr = revset.formatspec('heads(%r)', path.pushrev)
5773 expr = revset.formatspec('heads(%r)', path.pushrev)
5782 revs = scmutil.revrange(repo, [expr])
5774 revs = scmutil.revrange(repo, [expr])
5783 revs = [repo[rev].node() for rev in revs]
5775 revs = [repo[rev].node() for rev in revs]
5784 if not revs:
5776 if not revs:
5785 raise error.Abort(_('default push revset for path evaluates to an '
5777 raise error.Abort(_('default push revset for path evaluates to an '
5786 'empty set'))
5778 'empty set'))
5787
5779
5788 repo._subtoppath = dest
5780 repo._subtoppath = dest
5789 try:
5781 try:
5790 # push subrepos depth-first for coherent ordering
5782 # push subrepos depth-first for coherent ordering
5791 c = repo['']
5783 c = repo['']
5792 subs = c.substate # only repos that are committed
5784 subs = c.substate # only repos that are committed
5793 for s in sorted(subs):
5785 for s in sorted(subs):
5794 result = c.sub(s).push(opts)
5786 result = c.sub(s).push(opts)
5795 if result == 0:
5787 if result == 0:
5796 return not result
5788 return not result
5797 finally:
5789 finally:
5798 del repo._subtoppath
5790 del repo._subtoppath
5799 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5791 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5800 newbranch=opts.get('new_branch'),
5792 newbranch=opts.get('new_branch'),
5801 bookmarks=opts.get('bookmark', ()),
5793 bookmarks=opts.get('bookmark', ()),
5802 opargs=opts.get('opargs'))
5794 opargs=opts.get('opargs'))
5803
5795
5804 result = not pushop.cgresult
5796 result = not pushop.cgresult
5805
5797
5806 if pushop.bkresult is not None:
5798 if pushop.bkresult is not None:
5807 if pushop.bkresult == 2:
5799 if pushop.bkresult == 2:
5808 result = 2
5800 result = 2
5809 elif not result and pushop.bkresult:
5801 elif not result and pushop.bkresult:
5810 result = 2
5802 result = 2
5811
5803
5812 return result
5804 return result
5813
5805
5814 @command('recover', [])
5806 @command('recover', [])
5815 def recover(ui, repo):
5807 def recover(ui, repo):
5816 """roll back an interrupted transaction
5808 """roll back an interrupted transaction
5817
5809
5818 Recover from an interrupted commit or pull.
5810 Recover from an interrupted commit or pull.
5819
5811
5820 This command tries to fix the repository status after an
5812 This command tries to fix the repository status after an
5821 interrupted operation. It should only be necessary when Mercurial
5813 interrupted operation. It should only be necessary when Mercurial
5822 suggests it.
5814 suggests it.
5823
5815
5824 Returns 0 if successful, 1 if nothing to recover or verify fails.
5816 Returns 0 if successful, 1 if nothing to recover or verify fails.
5825 """
5817 """
5826 if repo.recover():
5818 if repo.recover():
5827 return hg.verify(repo)
5819 return hg.verify(repo)
5828 return 1
5820 return 1
5829
5821
5830 @command('^remove|rm',
5822 @command('^remove|rm',
5831 [('A', 'after', None, _('record delete for missing files')),
5823 [('A', 'after', None, _('record delete for missing files')),
5832 ('f', 'force', None,
5824 ('f', 'force', None,
5833 _('forget added files, delete modified files')),
5825 _('forget added files, delete modified files')),
5834 ] + subrepoopts + walkopts,
5826 ] + subrepoopts + walkopts,
5835 _('[OPTION]... FILE...'),
5827 _('[OPTION]... FILE...'),
5836 inferrepo=True)
5828 inferrepo=True)
5837 def remove(ui, repo, *pats, **opts):
5829 def remove(ui, repo, *pats, **opts):
5838 """remove the specified files on the next commit
5830 """remove the specified files on the next commit
5839
5831
5840 Schedule the indicated files for removal from the current branch.
5832 Schedule the indicated files for removal from the current branch.
5841
5833
5842 This command schedules the files to be removed at the next commit.
5834 This command schedules the files to be removed at the next commit.
5843 To undo a remove before that, see :hg:`revert`. To undo added
5835 To undo a remove before that, see :hg:`revert`. To undo added
5844 files, see :hg:`forget`.
5836 files, see :hg:`forget`.
5845
5837
5846 .. container:: verbose
5838 .. container:: verbose
5847
5839
5848 -A/--after can be used to remove only files that have already
5840 -A/--after can be used to remove only files that have already
5849 been deleted, -f/--force can be used to force deletion, and -Af
5841 been deleted, -f/--force can be used to force deletion, and -Af
5850 can be used to remove files from the next revision without
5842 can be used to remove files from the next revision without
5851 deleting them from the working directory.
5843 deleting them from the working directory.
5852
5844
5853 The following table details the behavior of remove for different
5845 The following table details the behavior of remove for different
5854 file states (columns) and option combinations (rows). The file
5846 file states (columns) and option combinations (rows). The file
5855 states are Added [A], Clean [C], Modified [M] and Missing [!]
5847 states are Added [A], Clean [C], Modified [M] and Missing [!]
5856 (as reported by :hg:`status`). The actions are Warn, Remove
5848 (as reported by :hg:`status`). The actions are Warn, Remove
5857 (from branch) and Delete (from disk):
5849 (from branch) and Delete (from disk):
5858
5850
5859 ========= == == == ==
5851 ========= == == == ==
5860 opt/state A C M !
5852 opt/state A C M !
5861 ========= == == == ==
5853 ========= == == == ==
5862 none W RD W R
5854 none W RD W R
5863 -f R RD RD R
5855 -f R RD RD R
5864 -A W W W R
5856 -A W W W R
5865 -Af R R R R
5857 -Af R R R R
5866 ========= == == == ==
5858 ========= == == == ==
5867
5859
5868 .. note::
5860 .. note::
5869
5861
5870 :hg:`remove` never deletes files in Added [A] state from the
5862 :hg:`remove` never deletes files in Added [A] state from the
5871 working directory, not even if ``--force`` is specified.
5863 working directory, not even if ``--force`` is specified.
5872
5864
5873 Returns 0 on success, 1 if any warnings encountered.
5865 Returns 0 on success, 1 if any warnings encountered.
5874 """
5866 """
5875
5867
5876 after, force = opts.get('after'), opts.get('force')
5868 after, force = opts.get('after'), opts.get('force')
5877 if not pats and not after:
5869 if not pats and not after:
5878 raise error.Abort(_('no files specified'))
5870 raise error.Abort(_('no files specified'))
5879
5871
5880 m = scmutil.match(repo[None], pats, opts)
5872 m = scmutil.match(repo[None], pats, opts)
5881 subrepos = opts.get('subrepos')
5873 subrepos = opts.get('subrepos')
5882 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5874 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5883
5875
5884 @command('rename|move|mv',
5876 @command('rename|move|mv',
5885 [('A', 'after', None, _('record a rename that has already occurred')),
5877 [('A', 'after', None, _('record a rename that has already occurred')),
5886 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5878 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5887 ] + walkopts + dryrunopts,
5879 ] + walkopts + dryrunopts,
5888 _('[OPTION]... SOURCE... DEST'))
5880 _('[OPTION]... SOURCE... DEST'))
5889 def rename(ui, repo, *pats, **opts):
5881 def rename(ui, repo, *pats, **opts):
5890 """rename files; equivalent of copy + remove
5882 """rename files; equivalent of copy + remove
5891
5883
5892 Mark dest as copies of sources; mark sources for deletion. If dest
5884 Mark dest as copies of sources; mark sources for deletion. If dest
5893 is a directory, copies are put in that directory. If dest is a
5885 is a directory, copies are put in that directory. If dest is a
5894 file, there can only be one source.
5886 file, there can only be one source.
5895
5887
5896 By default, this command copies the contents of files as they
5888 By default, this command copies the contents of files as they
5897 exist in the working directory. If invoked with -A/--after, the
5889 exist in the working directory. If invoked with -A/--after, the
5898 operation is recorded, but no copying is performed.
5890 operation is recorded, but no copying is performed.
5899
5891
5900 This command takes effect at the next commit. To undo a rename
5892 This command takes effect at the next commit. To undo a rename
5901 before that, see :hg:`revert`.
5893 before that, see :hg:`revert`.
5902
5894
5903 Returns 0 on success, 1 if errors are encountered.
5895 Returns 0 on success, 1 if errors are encountered.
5904 """
5896 """
5905 with repo.wlock(False):
5897 with repo.wlock(False):
5906 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5898 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5907
5899
5908 @command('resolve',
5900 @command('resolve',
5909 [('a', 'all', None, _('select all unresolved files')),
5901 [('a', 'all', None, _('select all unresolved files')),
5910 ('l', 'list', None, _('list state of files needing merge')),
5902 ('l', 'list', None, _('list state of files needing merge')),
5911 ('m', 'mark', None, _('mark files as resolved')),
5903 ('m', 'mark', None, _('mark files as resolved')),
5912 ('u', 'unmark', None, _('mark files as unresolved')),
5904 ('u', 'unmark', None, _('mark files as unresolved')),
5913 ('n', 'no-status', None, _('hide status prefix'))]
5905 ('n', 'no-status', None, _('hide status prefix'))]
5914 + mergetoolopts + walkopts + formatteropts,
5906 + mergetoolopts + walkopts + formatteropts,
5915 _('[OPTION]... [FILE]...'),
5907 _('[OPTION]... [FILE]...'),
5916 inferrepo=True)
5908 inferrepo=True)
5917 def resolve(ui, repo, *pats, **opts):
5909 def resolve(ui, repo, *pats, **opts):
5918 """redo merges or set/view the merge status of files
5910 """redo merges or set/view the merge status of files
5919
5911
5920 Merges with unresolved conflicts are often the result of
5912 Merges with unresolved conflicts are often the result of
5921 non-interactive merging using the ``internal:merge`` configuration
5913 non-interactive merging using the ``internal:merge`` configuration
5922 setting, or a command-line merge tool like ``diff3``. The resolve
5914 setting, or a command-line merge tool like ``diff3``. The resolve
5923 command is used to manage the files involved in a merge, after
5915 command is used to manage the files involved in a merge, after
5924 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5916 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5925 working directory must have two parents). See :hg:`help
5917 working directory must have two parents). See :hg:`help
5926 merge-tools` for information on configuring merge tools.
5918 merge-tools` for information on configuring merge tools.
5927
5919
5928 The resolve command can be used in the following ways:
5920 The resolve command can be used in the following ways:
5929
5921
5930 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5922 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5931 files, discarding any previous merge attempts. Re-merging is not
5923 files, discarding any previous merge attempts. Re-merging is not
5932 performed for files already marked as resolved. Use ``--all/-a``
5924 performed for files already marked as resolved. Use ``--all/-a``
5933 to select all unresolved files. ``--tool`` can be used to specify
5925 to select all unresolved files. ``--tool`` can be used to specify
5934 the merge tool used for the given files. It overrides the HGMERGE
5926 the merge tool used for the given files. It overrides the HGMERGE
5935 environment variable and your configuration files. Previous file
5927 environment variable and your configuration files. Previous file
5936 contents are saved with a ``.orig`` suffix.
5928 contents are saved with a ``.orig`` suffix.
5937
5929
5938 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5930 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5939 (e.g. after having manually fixed-up the files). The default is
5931 (e.g. after having manually fixed-up the files). The default is
5940 to mark all unresolved files.
5932 to mark all unresolved files.
5941
5933
5942 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5934 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5943 default is to mark all resolved files.
5935 default is to mark all resolved files.
5944
5936
5945 - :hg:`resolve -l`: list files which had or still have conflicts.
5937 - :hg:`resolve -l`: list files which had or still have conflicts.
5946 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5938 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5947
5939
5948 .. note::
5940 .. note::
5949
5941
5950 Mercurial will not let you commit files with unresolved merge
5942 Mercurial will not let you commit files with unresolved merge
5951 conflicts. You must use :hg:`resolve -m ...` before you can
5943 conflicts. You must use :hg:`resolve -m ...` before you can
5952 commit after a conflicting merge.
5944 commit after a conflicting merge.
5953
5945
5954 Returns 0 on success, 1 if any files fail a resolve attempt.
5946 Returns 0 on success, 1 if any files fail a resolve attempt.
5955 """
5947 """
5956
5948
5957 flaglist = 'all mark unmark list no_status'.split()
5949 flaglist = 'all mark unmark list no_status'.split()
5958 all, mark, unmark, show, nostatus = \
5950 all, mark, unmark, show, nostatus = \
5959 [opts.get(o) for o in flaglist]
5951 [opts.get(o) for o in flaglist]
5960
5952
5961 if (show and (mark or unmark)) or (mark and unmark):
5953 if (show and (mark or unmark)) or (mark and unmark):
5962 raise error.Abort(_("too many options specified"))
5954 raise error.Abort(_("too many options specified"))
5963 if pats and all:
5955 if pats and all:
5964 raise error.Abort(_("can't specify --all and patterns"))
5956 raise error.Abort(_("can't specify --all and patterns"))
5965 if not (all or pats or show or mark or unmark):
5957 if not (all or pats or show or mark or unmark):
5966 raise error.Abort(_('no files or directories specified'),
5958 raise error.Abort(_('no files or directories specified'),
5967 hint=('use --all to re-merge all unresolved files'))
5959 hint=('use --all to re-merge all unresolved files'))
5968
5960
5969 if show:
5961 if show:
5970 fm = ui.formatter('resolve', opts)
5962 fm = ui.formatter('resolve', opts)
5971 ms = mergemod.mergestate.read(repo)
5963 ms = mergemod.mergestate.read(repo)
5972 m = scmutil.match(repo[None], pats, opts)
5964 m = scmutil.match(repo[None], pats, opts)
5973 for f in ms:
5965 for f in ms:
5974 if not m(f):
5966 if not m(f):
5975 continue
5967 continue
5976 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5968 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5977 'd': 'driverresolved'}[ms[f]]
5969 'd': 'driverresolved'}[ms[f]]
5978 fm.startitem()
5970 fm.startitem()
5979 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5971 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5980 fm.write('path', '%s\n', f, label=l)
5972 fm.write('path', '%s\n', f, label=l)
5981 fm.end()
5973 fm.end()
5982 return 0
5974 return 0
5983
5975
5984 with repo.wlock():
5976 with repo.wlock():
5985 ms = mergemod.mergestate.read(repo)
5977 ms = mergemod.mergestate.read(repo)
5986
5978
5987 if not (ms.active() or repo.dirstate.p2() != nullid):
5979 if not (ms.active() or repo.dirstate.p2() != nullid):
5988 raise error.Abort(
5980 raise error.Abort(
5989 _('resolve command not applicable when not merging'))
5981 _('resolve command not applicable when not merging'))
5990
5982
5991 wctx = repo[None]
5983 wctx = repo[None]
5992
5984
5993 if ms.mergedriver and ms.mdstate() == 'u':
5985 if ms.mergedriver and ms.mdstate() == 'u':
5994 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5986 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5995 ms.commit()
5987 ms.commit()
5996 # allow mark and unmark to go through
5988 # allow mark and unmark to go through
5997 if not mark and not unmark and not proceed:
5989 if not mark and not unmark and not proceed:
5998 return 1
5990 return 1
5999
5991
6000 m = scmutil.match(wctx, pats, opts)
5992 m = scmutil.match(wctx, pats, opts)
6001 ret = 0
5993 ret = 0
6002 didwork = False
5994 didwork = False
6003 runconclude = False
5995 runconclude = False
6004
5996
6005 tocomplete = []
5997 tocomplete = []
6006 for f in ms:
5998 for f in ms:
6007 if not m(f):
5999 if not m(f):
6008 continue
6000 continue
6009
6001
6010 didwork = True
6002 didwork = True
6011
6003
6012 # don't let driver-resolved files be marked, and run the conclude
6004 # don't let driver-resolved files be marked, and run the conclude
6013 # step if asked to resolve
6005 # step if asked to resolve
6014 if ms[f] == "d":
6006 if ms[f] == "d":
6015 exact = m.exact(f)
6007 exact = m.exact(f)
6016 if mark:
6008 if mark:
6017 if exact:
6009 if exact:
6018 ui.warn(_('not marking %s as it is driver-resolved\n')
6010 ui.warn(_('not marking %s as it is driver-resolved\n')
6019 % f)
6011 % f)
6020 elif unmark:
6012 elif unmark:
6021 if exact:
6013 if exact:
6022 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6014 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6023 % f)
6015 % f)
6024 else:
6016 else:
6025 runconclude = True
6017 runconclude = True
6026 continue
6018 continue
6027
6019
6028 if mark:
6020 if mark:
6029 ms.mark(f, "r")
6021 ms.mark(f, "r")
6030 elif unmark:
6022 elif unmark:
6031 ms.mark(f, "u")
6023 ms.mark(f, "u")
6032 else:
6024 else:
6033 # backup pre-resolve (merge uses .orig for its own purposes)
6025 # backup pre-resolve (merge uses .orig for its own purposes)
6034 a = repo.wjoin(f)
6026 a = repo.wjoin(f)
6035 try:
6027 try:
6036 util.copyfile(a, a + ".resolve")
6028 util.copyfile(a, a + ".resolve")
6037 except (IOError, OSError) as inst:
6029 except (IOError, OSError) as inst:
6038 if inst.errno != errno.ENOENT:
6030 if inst.errno != errno.ENOENT:
6039 raise
6031 raise
6040
6032
6041 try:
6033 try:
6042 # preresolve file
6034 # preresolve file
6043 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6035 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6044 'resolve')
6036 'resolve')
6045 complete, r = ms.preresolve(f, wctx)
6037 complete, r = ms.preresolve(f, wctx)
6046 if not complete:
6038 if not complete:
6047 tocomplete.append(f)
6039 tocomplete.append(f)
6048 elif r:
6040 elif r:
6049 ret = 1
6041 ret = 1
6050 finally:
6042 finally:
6051 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6043 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6052 ms.commit()
6044 ms.commit()
6053
6045
6054 # replace filemerge's .orig file with our resolve file, but only
6046 # replace filemerge's .orig file with our resolve file, but only
6055 # for merges that are complete
6047 # for merges that are complete
6056 if complete:
6048 if complete:
6057 try:
6049 try:
6058 util.rename(a + ".resolve",
6050 util.rename(a + ".resolve",
6059 scmutil.origpath(ui, repo, a))
6051 scmutil.origpath(ui, repo, a))
6060 except OSError as inst:
6052 except OSError as inst:
6061 if inst.errno != errno.ENOENT:
6053 if inst.errno != errno.ENOENT:
6062 raise
6054 raise
6063
6055
6064 for f in tocomplete:
6056 for f in tocomplete:
6065 try:
6057 try:
6066 # resolve file
6058 # resolve file
6067 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6059 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6068 'resolve')
6060 'resolve')
6069 r = ms.resolve(f, wctx)
6061 r = ms.resolve(f, wctx)
6070 if r:
6062 if r:
6071 ret = 1
6063 ret = 1
6072 finally:
6064 finally:
6073 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6065 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6074 ms.commit()
6066 ms.commit()
6075
6067
6076 # replace filemerge's .orig file with our resolve file
6068 # replace filemerge's .orig file with our resolve file
6077 a = repo.wjoin(f)
6069 a = repo.wjoin(f)
6078 try:
6070 try:
6079 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6071 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6080 except OSError as inst:
6072 except OSError as inst:
6081 if inst.errno != errno.ENOENT:
6073 if inst.errno != errno.ENOENT:
6082 raise
6074 raise
6083
6075
6084 ms.commit()
6076 ms.commit()
6085 ms.recordactions()
6077 ms.recordactions()
6086
6078
6087 if not didwork and pats:
6079 if not didwork and pats:
6088 hint = None
6080 hint = None
6089 if not any([p for p in pats if p.find(':') >= 0]):
6081 if not any([p for p in pats if p.find(':') >= 0]):
6090 pats = ['path:%s' % p for p in pats]
6082 pats = ['path:%s' % p for p in pats]
6091 m = scmutil.match(wctx, pats, opts)
6083 m = scmutil.match(wctx, pats, opts)
6092 for f in ms:
6084 for f in ms:
6093 if not m(f):
6085 if not m(f):
6094 continue
6086 continue
6095 flags = ''.join(['-%s ' % o[0] for o in flaglist
6087 flags = ''.join(['-%s ' % o[0] for o in flaglist
6096 if opts.get(o)])
6088 if opts.get(o)])
6097 hint = _("(try: hg resolve %s%s)\n") % (
6089 hint = _("(try: hg resolve %s%s)\n") % (
6098 flags,
6090 flags,
6099 ' '.join(pats))
6091 ' '.join(pats))
6100 break
6092 break
6101 ui.warn(_("arguments do not match paths that need resolving\n"))
6093 ui.warn(_("arguments do not match paths that need resolving\n"))
6102 if hint:
6094 if hint:
6103 ui.warn(hint)
6095 ui.warn(hint)
6104 elif ms.mergedriver and ms.mdstate() != 's':
6096 elif ms.mergedriver and ms.mdstate() != 's':
6105 # run conclude step when either a driver-resolved file is requested
6097 # run conclude step when either a driver-resolved file is requested
6106 # or there are no driver-resolved files
6098 # or there are no driver-resolved files
6107 # we can't use 'ret' to determine whether any files are unresolved
6099 # we can't use 'ret' to determine whether any files are unresolved
6108 # because we might not have tried to resolve some
6100 # because we might not have tried to resolve some
6109 if ((runconclude or not list(ms.driverresolved()))
6101 if ((runconclude or not list(ms.driverresolved()))
6110 and not list(ms.unresolved())):
6102 and not list(ms.unresolved())):
6111 proceed = mergemod.driverconclude(repo, ms, wctx)
6103 proceed = mergemod.driverconclude(repo, ms, wctx)
6112 ms.commit()
6104 ms.commit()
6113 if not proceed:
6105 if not proceed:
6114 return 1
6106 return 1
6115
6107
6116 # Nudge users into finishing an unfinished operation
6108 # Nudge users into finishing an unfinished operation
6117 unresolvedf = list(ms.unresolved())
6109 unresolvedf = list(ms.unresolved())
6118 driverresolvedf = list(ms.driverresolved())
6110 driverresolvedf = list(ms.driverresolved())
6119 if not unresolvedf and not driverresolvedf:
6111 if not unresolvedf and not driverresolvedf:
6120 ui.status(_('(no more unresolved files)\n'))
6112 ui.status(_('(no more unresolved files)\n'))
6121 cmdutil.checkafterresolved(repo)
6113 cmdutil.checkafterresolved(repo)
6122 elif not unresolvedf:
6114 elif not unresolvedf:
6123 ui.status(_('(no more unresolved files -- '
6115 ui.status(_('(no more unresolved files -- '
6124 'run "hg resolve --all" to conclude)\n'))
6116 'run "hg resolve --all" to conclude)\n'))
6125
6117
6126 return ret
6118 return ret
6127
6119
6128 @command('revert',
6120 @command('revert',
6129 [('a', 'all', None, _('revert all changes when no arguments given')),
6121 [('a', 'all', None, _('revert all changes when no arguments given')),
6130 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6122 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6131 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6123 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6132 ('C', 'no-backup', None, _('do not save backup copies of files')),
6124 ('C', 'no-backup', None, _('do not save backup copies of files')),
6133 ('i', 'interactive', None,
6125 ('i', 'interactive', None,
6134 _('interactively select the changes (EXPERIMENTAL)')),
6126 _('interactively select the changes (EXPERIMENTAL)')),
6135 ] + walkopts + dryrunopts,
6127 ] + walkopts + dryrunopts,
6136 _('[OPTION]... [-r REV] [NAME]...'))
6128 _('[OPTION]... [-r REV] [NAME]...'))
6137 def revert(ui, repo, *pats, **opts):
6129 def revert(ui, repo, *pats, **opts):
6138 """restore files to their checkout state
6130 """restore files to their checkout state
6139
6131
6140 .. note::
6132 .. note::
6141
6133
6142 To check out earlier revisions, you should use :hg:`update REV`.
6134 To check out earlier revisions, you should use :hg:`update REV`.
6143 To cancel an uncommitted merge (and lose your changes),
6135 To cancel an uncommitted merge (and lose your changes),
6144 use :hg:`update --clean .`.
6136 use :hg:`update --clean .`.
6145
6137
6146 With no revision specified, revert the specified files or directories
6138 With no revision specified, revert the specified files or directories
6147 to the contents they had in the parent of the working directory.
6139 to the contents they had in the parent of the working directory.
6148 This restores the contents of files to an unmodified
6140 This restores the contents of files to an unmodified
6149 state and unschedules adds, removes, copies, and renames. If the
6141 state and unschedules adds, removes, copies, and renames. If the
6150 working directory has two parents, you must explicitly specify a
6142 working directory has two parents, you must explicitly specify a
6151 revision.
6143 revision.
6152
6144
6153 Using the -r/--rev or -d/--date options, revert the given files or
6145 Using the -r/--rev or -d/--date options, revert the given files or
6154 directories to their states as of a specific revision. Because
6146 directories to their states as of a specific revision. Because
6155 revert does not change the working directory parents, this will
6147 revert does not change the working directory parents, this will
6156 cause these files to appear modified. This can be helpful to "back
6148 cause these files to appear modified. This can be helpful to "back
6157 out" some or all of an earlier change. See :hg:`backout` for a
6149 out" some or all of an earlier change. See :hg:`backout` for a
6158 related method.
6150 related method.
6159
6151
6160 Modified files are saved with a .orig suffix before reverting.
6152 Modified files are saved with a .orig suffix before reverting.
6161 To disable these backups, use --no-backup. It is possible to store
6153 To disable these backups, use --no-backup. It is possible to store
6162 the backup files in a custom directory relative to the root of the
6154 the backup files in a custom directory relative to the root of the
6163 repository by setting the ``ui.origbackuppath`` configuration
6155 repository by setting the ``ui.origbackuppath`` configuration
6164 option.
6156 option.
6165
6157
6166 See :hg:`help dates` for a list of formats valid for -d/--date.
6158 See :hg:`help dates` for a list of formats valid for -d/--date.
6167
6159
6168 See :hg:`help backout` for a way to reverse the effect of an
6160 See :hg:`help backout` for a way to reverse the effect of an
6169 earlier changeset.
6161 earlier changeset.
6170
6162
6171 Returns 0 on success.
6163 Returns 0 on success.
6172 """
6164 """
6173
6165
6174 if opts.get("date"):
6166 if opts.get("date"):
6175 if opts.get("rev"):
6167 if opts.get("rev"):
6176 raise error.Abort(_("you can't specify a revision and a date"))
6168 raise error.Abort(_("you can't specify a revision and a date"))
6177 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6169 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6178
6170
6179 parent, p2 = repo.dirstate.parents()
6171 parent, p2 = repo.dirstate.parents()
6180 if not opts.get('rev') and p2 != nullid:
6172 if not opts.get('rev') and p2 != nullid:
6181 # revert after merge is a trap for new users (issue2915)
6173 # revert after merge is a trap for new users (issue2915)
6182 raise error.Abort(_('uncommitted merge with no revision specified'),
6174 raise error.Abort(_('uncommitted merge with no revision specified'),
6183 hint=_("use 'hg update' or see 'hg help revert'"))
6175 hint=_("use 'hg update' or see 'hg help revert'"))
6184
6176
6185 ctx = scmutil.revsingle(repo, opts.get('rev'))
6177 ctx = scmutil.revsingle(repo, opts.get('rev'))
6186
6178
6187 if (not (pats or opts.get('include') or opts.get('exclude') or
6179 if (not (pats or opts.get('include') or opts.get('exclude') or
6188 opts.get('all') or opts.get('interactive'))):
6180 opts.get('all') or opts.get('interactive'))):
6189 msg = _("no files or directories specified")
6181 msg = _("no files or directories specified")
6190 if p2 != nullid:
6182 if p2 != nullid:
6191 hint = _("uncommitted merge, use --all to discard all changes,"
6183 hint = _("uncommitted merge, use --all to discard all changes,"
6192 " or 'hg update -C .' to abort the merge")
6184 " or 'hg update -C .' to abort the merge")
6193 raise error.Abort(msg, hint=hint)
6185 raise error.Abort(msg, hint=hint)
6194 dirty = any(repo.status())
6186 dirty = any(repo.status())
6195 node = ctx.node()
6187 node = ctx.node()
6196 if node != parent:
6188 if node != parent:
6197 if dirty:
6189 if dirty:
6198 hint = _("uncommitted changes, use --all to discard all"
6190 hint = _("uncommitted changes, use --all to discard all"
6199 " changes, or 'hg update %s' to update") % ctx.rev()
6191 " changes, or 'hg update %s' to update") % ctx.rev()
6200 else:
6192 else:
6201 hint = _("use --all to revert all files,"
6193 hint = _("use --all to revert all files,"
6202 " or 'hg update %s' to update") % ctx.rev()
6194 " or 'hg update %s' to update") % ctx.rev()
6203 elif dirty:
6195 elif dirty:
6204 hint = _("uncommitted changes, use --all to discard all changes")
6196 hint = _("uncommitted changes, use --all to discard all changes")
6205 else:
6197 else:
6206 hint = _("use --all to revert all files")
6198 hint = _("use --all to revert all files")
6207 raise error.Abort(msg, hint=hint)
6199 raise error.Abort(msg, hint=hint)
6208
6200
6209 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6201 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6210
6202
6211 @command('rollback', dryrunopts +
6203 @command('rollback', dryrunopts +
6212 [('f', 'force', False, _('ignore safety measures'))])
6204 [('f', 'force', False, _('ignore safety measures'))])
6213 def rollback(ui, repo, **opts):
6205 def rollback(ui, repo, **opts):
6214 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6206 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6215
6207
6216 Please use :hg:`commit --amend` instead of rollback to correct
6208 Please use :hg:`commit --amend` instead of rollback to correct
6217 mistakes in the last commit.
6209 mistakes in the last commit.
6218
6210
6219 This command should be used with care. There is only one level of
6211 This command should be used with care. There is only one level of
6220 rollback, and there is no way to undo a rollback. It will also
6212 rollback, and there is no way to undo a rollback. It will also
6221 restore the dirstate at the time of the last transaction, losing
6213 restore the dirstate at the time of the last transaction, losing
6222 any dirstate changes since that time. This command does not alter
6214 any dirstate changes since that time. This command does not alter
6223 the working directory.
6215 the working directory.
6224
6216
6225 Transactions are used to encapsulate the effects of all commands
6217 Transactions are used to encapsulate the effects of all commands
6226 that create new changesets or propagate existing changesets into a
6218 that create new changesets or propagate existing changesets into a
6227 repository.
6219 repository.
6228
6220
6229 .. container:: verbose
6221 .. container:: verbose
6230
6222
6231 For example, the following commands are transactional, and their
6223 For example, the following commands are transactional, and their
6232 effects can be rolled back:
6224 effects can be rolled back:
6233
6225
6234 - commit
6226 - commit
6235 - import
6227 - import
6236 - pull
6228 - pull
6237 - push (with this repository as the destination)
6229 - push (with this repository as the destination)
6238 - unbundle
6230 - unbundle
6239
6231
6240 To avoid permanent data loss, rollback will refuse to rollback a
6232 To avoid permanent data loss, rollback will refuse to rollback a
6241 commit transaction if it isn't checked out. Use --force to
6233 commit transaction if it isn't checked out. Use --force to
6242 override this protection.
6234 override this protection.
6243
6235
6244 The rollback command can be entirely disabled by setting the
6236 The rollback command can be entirely disabled by setting the
6245 ``ui.rollback`` configuration setting to false. If you're here
6237 ``ui.rollback`` configuration setting to false. If you're here
6246 because you want to use rollback and it's disabled, you can
6238 because you want to use rollback and it's disabled, you can
6247 re-enable the command by setting ``ui.rollback`` to true.
6239 re-enable the command by setting ``ui.rollback`` to true.
6248
6240
6249 This command is not intended for use on public repositories. Once
6241 This command is not intended for use on public repositories. Once
6250 changes are visible for pull by other users, rolling a transaction
6242 changes are visible for pull by other users, rolling a transaction
6251 back locally is ineffective (someone else may already have pulled
6243 back locally is ineffective (someone else may already have pulled
6252 the changes). Furthermore, a race is possible with readers of the
6244 the changes). Furthermore, a race is possible with readers of the
6253 repository; for example an in-progress pull from the repository
6245 repository; for example an in-progress pull from the repository
6254 may fail if a rollback is performed.
6246 may fail if a rollback is performed.
6255
6247
6256 Returns 0 on success, 1 if no rollback data is available.
6248 Returns 0 on success, 1 if no rollback data is available.
6257 """
6249 """
6258 if not ui.configbool('ui', 'rollback', True):
6250 if not ui.configbool('ui', 'rollback', True):
6259 raise error.Abort(_('rollback is disabled because it is unsafe'),
6251 raise error.Abort(_('rollback is disabled because it is unsafe'),
6260 hint=('see `hg help -v rollback` for information'))
6252 hint=('see `hg help -v rollback` for information'))
6261 return repo.rollback(dryrun=opts.get('dry_run'),
6253 return repo.rollback(dryrun=opts.get('dry_run'),
6262 force=opts.get('force'))
6254 force=opts.get('force'))
6263
6255
6264 @command('root', [])
6256 @command('root', [])
6265 def root(ui, repo):
6257 def root(ui, repo):
6266 """print the root (top) of the current working directory
6258 """print the root (top) of the current working directory
6267
6259
6268 Print the root directory of the current repository.
6260 Print the root directory of the current repository.
6269
6261
6270 Returns 0 on success.
6262 Returns 0 on success.
6271 """
6263 """
6272 ui.write(repo.root + "\n")
6264 ui.write(repo.root + "\n")
6273
6265
6274 @command('^serve',
6266 @command('^serve',
6275 [('A', 'accesslog', '', _('name of access log file to write to'),
6267 [('A', 'accesslog', '', _('name of access log file to write to'),
6276 _('FILE')),
6268 _('FILE')),
6277 ('d', 'daemon', None, _('run server in background')),
6269 ('d', 'daemon', None, _('run server in background')),
6278 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6270 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6279 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6271 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6280 # use string type, then we can check if something was passed
6272 # use string type, then we can check if something was passed
6281 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6273 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6282 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6274 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6283 _('ADDR')),
6275 _('ADDR')),
6284 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6276 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6285 _('PREFIX')),
6277 _('PREFIX')),
6286 ('n', 'name', '',
6278 ('n', 'name', '',
6287 _('name to show in web pages (default: working directory)'), _('NAME')),
6279 _('name to show in web pages (default: working directory)'), _('NAME')),
6288 ('', 'web-conf', '',
6280 ('', 'web-conf', '',
6289 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6281 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6290 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6282 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6291 _('FILE')),
6283 _('FILE')),
6292 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6284 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6293 ('', 'stdio', None, _('for remote clients')),
6285 ('', 'stdio', None, _('for remote clients')),
6294 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6286 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6295 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6287 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6296 ('', 'style', '', _('template style to use'), _('STYLE')),
6288 ('', 'style', '', _('template style to use'), _('STYLE')),
6297 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6289 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6298 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6290 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6299 _('[OPTION]...'),
6291 _('[OPTION]...'),
6300 optionalrepo=True)
6292 optionalrepo=True)
6301 def serve(ui, repo, **opts):
6293 def serve(ui, repo, **opts):
6302 """start stand-alone webserver
6294 """start stand-alone webserver
6303
6295
6304 Start a local HTTP repository browser and pull server. You can use
6296 Start a local HTTP repository browser and pull server. You can use
6305 this for ad-hoc sharing and browsing of repositories. It is
6297 this for ad-hoc sharing and browsing of repositories. It is
6306 recommended to use a real web server to serve a repository for
6298 recommended to use a real web server to serve a repository for
6307 longer periods of time.
6299 longer periods of time.
6308
6300
6309 Please note that the server does not implement access control.
6301 Please note that the server does not implement access control.
6310 This means that, by default, anybody can read from the server and
6302 This means that, by default, anybody can read from the server and
6311 nobody can write to it by default. Set the ``web.allow_push``
6303 nobody can write to it by default. Set the ``web.allow_push``
6312 option to ``*`` to allow everybody to push to the server. You
6304 option to ``*`` to allow everybody to push to the server. You
6313 should use a real web server if you need to authenticate users.
6305 should use a real web server if you need to authenticate users.
6314
6306
6315 By default, the server logs accesses to stdout and errors to
6307 By default, the server logs accesses to stdout and errors to
6316 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6308 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6317 files.
6309 files.
6318
6310
6319 To have the server choose a free port number to listen on, specify
6311 To have the server choose a free port number to listen on, specify
6320 a port number of 0; in this case, the server will print the port
6312 a port number of 0; in this case, the server will print the port
6321 number it uses.
6313 number it uses.
6322
6314
6323 Returns 0 on success.
6315 Returns 0 on success.
6324 """
6316 """
6325
6317
6326 if opts["stdio"] and opts["cmdserver"]:
6318 if opts["stdio"] and opts["cmdserver"]:
6327 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6319 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6328
6320
6329 if opts["stdio"]:
6321 if opts["stdio"]:
6330 if repo is None:
6322 if repo is None:
6331 raise error.RepoError(_("there is no Mercurial repository here"
6323 raise error.RepoError(_("there is no Mercurial repository here"
6332 " (.hg not found)"))
6324 " (.hg not found)"))
6333 s = sshserver.sshserver(ui, repo)
6325 s = sshserver.sshserver(ui, repo)
6334 s.serve_forever()
6326 s.serve_forever()
6335
6327
6336 if opts["cmdserver"]:
6328 if opts["cmdserver"]:
6337 service = commandserver.createservice(ui, repo, opts)
6329 service = commandserver.createservice(ui, repo, opts)
6338 else:
6330 else:
6339 service = hgweb.createservice(ui, repo, opts)
6331 service = hgweb.createservice(ui, repo, opts)
6340 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6332 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6341
6333
6342 @command('^status|st',
6334 @command('^status|st',
6343 [('A', 'all', None, _('show status of all files')),
6335 [('A', 'all', None, _('show status of all files')),
6344 ('m', 'modified', None, _('show only modified files')),
6336 ('m', 'modified', None, _('show only modified files')),
6345 ('a', 'added', None, _('show only added files')),
6337 ('a', 'added', None, _('show only added files')),
6346 ('r', 'removed', None, _('show only removed files')),
6338 ('r', 'removed', None, _('show only removed files')),
6347 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6339 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6348 ('c', 'clean', None, _('show only files without changes')),
6340 ('c', 'clean', None, _('show only files without changes')),
6349 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6341 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6350 ('i', 'ignored', None, _('show only ignored files')),
6342 ('i', 'ignored', None, _('show only ignored files')),
6351 ('n', 'no-status', None, _('hide status prefix')),
6343 ('n', 'no-status', None, _('hide status prefix')),
6352 ('C', 'copies', None, _('show source of copied files')),
6344 ('C', 'copies', None, _('show source of copied files')),
6353 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6345 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6354 ('', 'rev', [], _('show difference from revision'), _('REV')),
6346 ('', 'rev', [], _('show difference from revision'), _('REV')),
6355 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6347 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6356 ] + walkopts + subrepoopts + formatteropts,
6348 ] + walkopts + subrepoopts + formatteropts,
6357 _('[OPTION]... [FILE]...'),
6349 _('[OPTION]... [FILE]...'),
6358 inferrepo=True)
6350 inferrepo=True)
6359 def status(ui, repo, *pats, **opts):
6351 def status(ui, repo, *pats, **opts):
6360 """show changed files in the working directory
6352 """show changed files in the working directory
6361
6353
6362 Show status of files in the repository. If names are given, only
6354 Show status of files in the repository. If names are given, only
6363 files that match are shown. Files that are clean or ignored or
6355 files that match are shown. Files that are clean or ignored or
6364 the source of a copy/move operation, are not listed unless
6356 the source of a copy/move operation, are not listed unless
6365 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6357 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6366 Unless options described with "show only ..." are given, the
6358 Unless options described with "show only ..." are given, the
6367 options -mardu are used.
6359 options -mardu are used.
6368
6360
6369 Option -q/--quiet hides untracked (unknown and ignored) files
6361 Option -q/--quiet hides untracked (unknown and ignored) files
6370 unless explicitly requested with -u/--unknown or -i/--ignored.
6362 unless explicitly requested with -u/--unknown or -i/--ignored.
6371
6363
6372 .. note::
6364 .. note::
6373
6365
6374 :hg:`status` may appear to disagree with diff if permissions have
6366 :hg:`status` may appear to disagree with diff if permissions have
6375 changed or a merge has occurred. The standard diff format does
6367 changed or a merge has occurred. The standard diff format does
6376 not report permission changes and diff only reports changes
6368 not report permission changes and diff only reports changes
6377 relative to one merge parent.
6369 relative to one merge parent.
6378
6370
6379 If one revision is given, it is used as the base revision.
6371 If one revision is given, it is used as the base revision.
6380 If two revisions are given, the differences between them are
6372 If two revisions are given, the differences between them are
6381 shown. The --change option can also be used as a shortcut to list
6373 shown. The --change option can also be used as a shortcut to list
6382 the changed files of a revision from its first parent.
6374 the changed files of a revision from its first parent.
6383
6375
6384 The codes used to show the status of files are::
6376 The codes used to show the status of files are::
6385
6377
6386 M = modified
6378 M = modified
6387 A = added
6379 A = added
6388 R = removed
6380 R = removed
6389 C = clean
6381 C = clean
6390 ! = missing (deleted by non-hg command, but still tracked)
6382 ! = missing (deleted by non-hg command, but still tracked)
6391 ? = not tracked
6383 ? = not tracked
6392 I = ignored
6384 I = ignored
6393 = origin of the previous file (with --copies)
6385 = origin of the previous file (with --copies)
6394
6386
6395 .. container:: verbose
6387 .. container:: verbose
6396
6388
6397 Examples:
6389 Examples:
6398
6390
6399 - show changes in the working directory relative to a
6391 - show changes in the working directory relative to a
6400 changeset::
6392 changeset::
6401
6393
6402 hg status --rev 9353
6394 hg status --rev 9353
6403
6395
6404 - show changes in the working directory relative to the
6396 - show changes in the working directory relative to the
6405 current directory (see :hg:`help patterns` for more information)::
6397 current directory (see :hg:`help patterns` for more information)::
6406
6398
6407 hg status re:
6399 hg status re:
6408
6400
6409 - show all changes including copies in an existing changeset::
6401 - show all changes including copies in an existing changeset::
6410
6402
6411 hg status --copies --change 9353
6403 hg status --copies --change 9353
6412
6404
6413 - get a NUL separated list of added files, suitable for xargs::
6405 - get a NUL separated list of added files, suitable for xargs::
6414
6406
6415 hg status -an0
6407 hg status -an0
6416
6408
6417 Returns 0 on success.
6409 Returns 0 on success.
6418 """
6410 """
6419
6411
6420 revs = opts.get('rev')
6412 revs = opts.get('rev')
6421 change = opts.get('change')
6413 change = opts.get('change')
6422
6414
6423 if revs and change:
6415 if revs and change:
6424 msg = _('cannot specify --rev and --change at the same time')
6416 msg = _('cannot specify --rev and --change at the same time')
6425 raise error.Abort(msg)
6417 raise error.Abort(msg)
6426 elif change:
6418 elif change:
6427 node2 = scmutil.revsingle(repo, change, None).node()
6419 node2 = scmutil.revsingle(repo, change, None).node()
6428 node1 = repo[node2].p1().node()
6420 node1 = repo[node2].p1().node()
6429 else:
6421 else:
6430 node1, node2 = scmutil.revpair(repo, revs)
6422 node1, node2 = scmutil.revpair(repo, revs)
6431
6423
6432 if pats:
6424 if pats:
6433 cwd = repo.getcwd()
6425 cwd = repo.getcwd()
6434 else:
6426 else:
6435 cwd = ''
6427 cwd = ''
6436
6428
6437 if opts.get('print0'):
6429 if opts.get('print0'):
6438 end = '\0'
6430 end = '\0'
6439 else:
6431 else:
6440 end = '\n'
6432 end = '\n'
6441 copy = {}
6433 copy = {}
6442 states = 'modified added removed deleted unknown ignored clean'.split()
6434 states = 'modified added removed deleted unknown ignored clean'.split()
6443 show = [k for k in states if opts.get(k)]
6435 show = [k for k in states if opts.get(k)]
6444 if opts.get('all'):
6436 if opts.get('all'):
6445 show += ui.quiet and (states[:4] + ['clean']) or states
6437 show += ui.quiet and (states[:4] + ['clean']) or states
6446 if not show:
6438 if not show:
6447 if ui.quiet:
6439 if ui.quiet:
6448 show = states[:4]
6440 show = states[:4]
6449 else:
6441 else:
6450 show = states[:5]
6442 show = states[:5]
6451
6443
6452 m = scmutil.match(repo[node2], pats, opts)
6444 m = scmutil.match(repo[node2], pats, opts)
6453 stat = repo.status(node1, node2, m,
6445 stat = repo.status(node1, node2, m,
6454 'ignored' in show, 'clean' in show, 'unknown' in show,
6446 'ignored' in show, 'clean' in show, 'unknown' in show,
6455 opts.get('subrepos'))
6447 opts.get('subrepos'))
6456 changestates = zip(states, 'MAR!?IC', stat)
6448 changestates = zip(states, 'MAR!?IC', stat)
6457
6449
6458 if (opts.get('all') or opts.get('copies')
6450 if (opts.get('all') or opts.get('copies')
6459 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6451 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6460 copy = copies.pathcopies(repo[node1], repo[node2], m)
6452 copy = copies.pathcopies(repo[node1], repo[node2], m)
6461
6453
6462 fm = ui.formatter('status', opts)
6454 fm = ui.formatter('status', opts)
6463 fmt = '%s' + end
6455 fmt = '%s' + end
6464 showchar = not opts.get('no_status')
6456 showchar = not opts.get('no_status')
6465
6457
6466 for state, char, files in changestates:
6458 for state, char, files in changestates:
6467 if state in show:
6459 if state in show:
6468 label = 'status.' + state
6460 label = 'status.' + state
6469 for f in files:
6461 for f in files:
6470 fm.startitem()
6462 fm.startitem()
6471 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6463 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6472 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6464 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6473 if f in copy:
6465 if f in copy:
6474 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6466 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6475 label='status.copied')
6467 label='status.copied')
6476 fm.end()
6468 fm.end()
6477
6469
6478 @command('^summary|sum',
6470 @command('^summary|sum',
6479 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6471 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6480 def summary(ui, repo, **opts):
6472 def summary(ui, repo, **opts):
6481 """summarize working directory state
6473 """summarize working directory state
6482
6474
6483 This generates a brief summary of the working directory state,
6475 This generates a brief summary of the working directory state,
6484 including parents, branch, commit status, phase and available updates.
6476 including parents, branch, commit status, phase and available updates.
6485
6477
6486 With the --remote option, this will check the default paths for
6478 With the --remote option, this will check the default paths for
6487 incoming and outgoing changes. This can be time-consuming.
6479 incoming and outgoing changes. This can be time-consuming.
6488
6480
6489 Returns 0 on success.
6481 Returns 0 on success.
6490 """
6482 """
6491
6483
6492 ctx = repo[None]
6484 ctx = repo[None]
6493 parents = ctx.parents()
6485 parents = ctx.parents()
6494 pnode = parents[0].node()
6486 pnode = parents[0].node()
6495 marks = []
6487 marks = []
6496
6488
6497 ms = None
6489 ms = None
6498 try:
6490 try:
6499 ms = mergemod.mergestate.read(repo)
6491 ms = mergemod.mergestate.read(repo)
6500 except error.UnsupportedMergeRecords as e:
6492 except error.UnsupportedMergeRecords as e:
6501 s = ' '.join(e.recordtypes)
6493 s = ' '.join(e.recordtypes)
6502 ui.warn(
6494 ui.warn(
6503 _('warning: merge state has unsupported record types: %s\n') % s)
6495 _('warning: merge state has unsupported record types: %s\n') % s)
6504 unresolved = 0
6496 unresolved = 0
6505 else:
6497 else:
6506 unresolved = [f for f in ms if ms[f] == 'u']
6498 unresolved = [f for f in ms if ms[f] == 'u']
6507
6499
6508 for p in parents:
6500 for p in parents:
6509 # label with log.changeset (instead of log.parent) since this
6501 # label with log.changeset (instead of log.parent) since this
6510 # shows a working directory parent *changeset*:
6502 # shows a working directory parent *changeset*:
6511 # i18n: column positioning for "hg summary"
6503 # i18n: column positioning for "hg summary"
6512 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6504 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6513 label='log.changeset changeset.%s' % p.phasestr())
6505 label='log.changeset changeset.%s' % p.phasestr())
6514 ui.write(' '.join(p.tags()), label='log.tag')
6506 ui.write(' '.join(p.tags()), label='log.tag')
6515 if p.bookmarks():
6507 if p.bookmarks():
6516 marks.extend(p.bookmarks())
6508 marks.extend(p.bookmarks())
6517 if p.rev() == -1:
6509 if p.rev() == -1:
6518 if not len(repo):
6510 if not len(repo):
6519 ui.write(_(' (empty repository)'))
6511 ui.write(_(' (empty repository)'))
6520 else:
6512 else:
6521 ui.write(_(' (no revision checked out)'))
6513 ui.write(_(' (no revision checked out)'))
6522 ui.write('\n')
6514 ui.write('\n')
6523 if p.description():
6515 if p.description():
6524 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6516 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6525 label='log.summary')
6517 label='log.summary')
6526
6518
6527 branch = ctx.branch()
6519 branch = ctx.branch()
6528 bheads = repo.branchheads(branch)
6520 bheads = repo.branchheads(branch)
6529 # i18n: column positioning for "hg summary"
6521 # i18n: column positioning for "hg summary"
6530 m = _('branch: %s\n') % branch
6522 m = _('branch: %s\n') % branch
6531 if branch != 'default':
6523 if branch != 'default':
6532 ui.write(m, label='log.branch')
6524 ui.write(m, label='log.branch')
6533 else:
6525 else:
6534 ui.status(m, label='log.branch')
6526 ui.status(m, label='log.branch')
6535
6527
6536 if marks:
6528 if marks:
6537 active = repo._activebookmark
6529 active = repo._activebookmark
6538 # i18n: column positioning for "hg summary"
6530 # i18n: column positioning for "hg summary"
6539 ui.write(_('bookmarks:'), label='log.bookmark')
6531 ui.write(_('bookmarks:'), label='log.bookmark')
6540 if active is not None:
6532 if active is not None:
6541 if active in marks:
6533 if active in marks:
6542 ui.write(' *' + active, label=activebookmarklabel)
6534 ui.write(' *' + active, label=activebookmarklabel)
6543 marks.remove(active)
6535 marks.remove(active)
6544 else:
6536 else:
6545 ui.write(' [%s]' % active, label=activebookmarklabel)
6537 ui.write(' [%s]' % active, label=activebookmarklabel)
6546 for m in marks:
6538 for m in marks:
6547 ui.write(' ' + m, label='log.bookmark')
6539 ui.write(' ' + m, label='log.bookmark')
6548 ui.write('\n', label='log.bookmark')
6540 ui.write('\n', label='log.bookmark')
6549
6541
6550 status = repo.status(unknown=True)
6542 status = repo.status(unknown=True)
6551
6543
6552 c = repo.dirstate.copies()
6544 c = repo.dirstate.copies()
6553 copied, renamed = [], []
6545 copied, renamed = [], []
6554 for d, s in c.iteritems():
6546 for d, s in c.iteritems():
6555 if s in status.removed:
6547 if s in status.removed:
6556 status.removed.remove(s)
6548 status.removed.remove(s)
6557 renamed.append(d)
6549 renamed.append(d)
6558 else:
6550 else:
6559 copied.append(d)
6551 copied.append(d)
6560 if d in status.added:
6552 if d in status.added:
6561 status.added.remove(d)
6553 status.added.remove(d)
6562
6554
6563 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6555 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6564
6556
6565 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6557 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6566 (ui.label(_('%d added'), 'status.added'), status.added),
6558 (ui.label(_('%d added'), 'status.added'), status.added),
6567 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6559 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6568 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6560 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6569 (ui.label(_('%d copied'), 'status.copied'), copied),
6561 (ui.label(_('%d copied'), 'status.copied'), copied),
6570 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6562 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6571 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6563 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6572 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6564 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6573 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6565 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6574 t = []
6566 t = []
6575 for l, s in labels:
6567 for l, s in labels:
6576 if s:
6568 if s:
6577 t.append(l % len(s))
6569 t.append(l % len(s))
6578
6570
6579 t = ', '.join(t)
6571 t = ', '.join(t)
6580 cleanworkdir = False
6572 cleanworkdir = False
6581
6573
6582 if repo.vfs.exists('graftstate'):
6574 if repo.vfs.exists('graftstate'):
6583 t += _(' (graft in progress)')
6575 t += _(' (graft in progress)')
6584 if repo.vfs.exists('updatestate'):
6576 if repo.vfs.exists('updatestate'):
6585 t += _(' (interrupted update)')
6577 t += _(' (interrupted update)')
6586 elif len(parents) > 1:
6578 elif len(parents) > 1:
6587 t += _(' (merge)')
6579 t += _(' (merge)')
6588 elif branch != parents[0].branch():
6580 elif branch != parents[0].branch():
6589 t += _(' (new branch)')
6581 t += _(' (new branch)')
6590 elif (parents[0].closesbranch() and
6582 elif (parents[0].closesbranch() and
6591 pnode in repo.branchheads(branch, closed=True)):
6583 pnode in repo.branchheads(branch, closed=True)):
6592 t += _(' (head closed)')
6584 t += _(' (head closed)')
6593 elif not (status.modified or status.added or status.removed or renamed or
6585 elif not (status.modified or status.added or status.removed or renamed or
6594 copied or subs):
6586 copied or subs):
6595 t += _(' (clean)')
6587 t += _(' (clean)')
6596 cleanworkdir = True
6588 cleanworkdir = True
6597 elif pnode not in bheads:
6589 elif pnode not in bheads:
6598 t += _(' (new branch head)')
6590 t += _(' (new branch head)')
6599
6591
6600 if parents:
6592 if parents:
6601 pendingphase = max(p.phase() for p in parents)
6593 pendingphase = max(p.phase() for p in parents)
6602 else:
6594 else:
6603 pendingphase = phases.public
6595 pendingphase = phases.public
6604
6596
6605 if pendingphase > phases.newcommitphase(ui):
6597 if pendingphase > phases.newcommitphase(ui):
6606 t += ' (%s)' % phases.phasenames[pendingphase]
6598 t += ' (%s)' % phases.phasenames[pendingphase]
6607
6599
6608 if cleanworkdir:
6600 if cleanworkdir:
6609 # i18n: column positioning for "hg summary"
6601 # i18n: column positioning for "hg summary"
6610 ui.status(_('commit: %s\n') % t.strip())
6602 ui.status(_('commit: %s\n') % t.strip())
6611 else:
6603 else:
6612 # i18n: column positioning for "hg summary"
6604 # i18n: column positioning for "hg summary"
6613 ui.write(_('commit: %s\n') % t.strip())
6605 ui.write(_('commit: %s\n') % t.strip())
6614
6606
6615 # all ancestors of branch heads - all ancestors of parent = new csets
6607 # all ancestors of branch heads - all ancestors of parent = new csets
6616 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6608 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6617 bheads))
6609 bheads))
6618
6610
6619 if new == 0:
6611 if new == 0:
6620 # i18n: column positioning for "hg summary"
6612 # i18n: column positioning for "hg summary"
6621 ui.status(_('update: (current)\n'))
6613 ui.status(_('update: (current)\n'))
6622 elif pnode not in bheads:
6614 elif pnode not in bheads:
6623 # i18n: column positioning for "hg summary"
6615 # i18n: column positioning for "hg summary"
6624 ui.write(_('update: %d new changesets (update)\n') % new)
6616 ui.write(_('update: %d new changesets (update)\n') % new)
6625 else:
6617 else:
6626 # i18n: column positioning for "hg summary"
6618 # i18n: column positioning for "hg summary"
6627 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6619 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6628 (new, len(bheads)))
6620 (new, len(bheads)))
6629
6621
6630 t = []
6622 t = []
6631 draft = len(repo.revs('draft()'))
6623 draft = len(repo.revs('draft()'))
6632 if draft:
6624 if draft:
6633 t.append(_('%d draft') % draft)
6625 t.append(_('%d draft') % draft)
6634 secret = len(repo.revs('secret()'))
6626 secret = len(repo.revs('secret()'))
6635 if secret:
6627 if secret:
6636 t.append(_('%d secret') % secret)
6628 t.append(_('%d secret') % secret)
6637
6629
6638 if draft or secret:
6630 if draft or secret:
6639 ui.status(_('phases: %s\n') % ', '.join(t))
6631 ui.status(_('phases: %s\n') % ', '.join(t))
6640
6632
6641 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6633 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6642 for trouble in ("unstable", "divergent", "bumped"):
6634 for trouble in ("unstable", "divergent", "bumped"):
6643 numtrouble = len(repo.revs(trouble + "()"))
6635 numtrouble = len(repo.revs(trouble + "()"))
6644 # We write all the possibilities to ease translation
6636 # We write all the possibilities to ease translation
6645 troublemsg = {
6637 troublemsg = {
6646 "unstable": _("unstable: %d changesets"),
6638 "unstable": _("unstable: %d changesets"),
6647 "divergent": _("divergent: %d changesets"),
6639 "divergent": _("divergent: %d changesets"),
6648 "bumped": _("bumped: %d changesets"),
6640 "bumped": _("bumped: %d changesets"),
6649 }
6641 }
6650 if numtrouble > 0:
6642 if numtrouble > 0:
6651 ui.status(troublemsg[trouble] % numtrouble + "\n")
6643 ui.status(troublemsg[trouble] % numtrouble + "\n")
6652
6644
6653 cmdutil.summaryhooks(ui, repo)
6645 cmdutil.summaryhooks(ui, repo)
6654
6646
6655 if opts.get('remote'):
6647 if opts.get('remote'):
6656 needsincoming, needsoutgoing = True, True
6648 needsincoming, needsoutgoing = True, True
6657 else:
6649 else:
6658 needsincoming, needsoutgoing = False, False
6650 needsincoming, needsoutgoing = False, False
6659 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6651 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6660 if i:
6652 if i:
6661 needsincoming = True
6653 needsincoming = True
6662 if o:
6654 if o:
6663 needsoutgoing = True
6655 needsoutgoing = True
6664 if not needsincoming and not needsoutgoing:
6656 if not needsincoming and not needsoutgoing:
6665 return
6657 return
6666
6658
6667 def getincoming():
6659 def getincoming():
6668 source, branches = hg.parseurl(ui.expandpath('default'))
6660 source, branches = hg.parseurl(ui.expandpath('default'))
6669 sbranch = branches[0]
6661 sbranch = branches[0]
6670 try:
6662 try:
6671 other = hg.peer(repo, {}, source)
6663 other = hg.peer(repo, {}, source)
6672 except error.RepoError:
6664 except error.RepoError:
6673 if opts.get('remote'):
6665 if opts.get('remote'):
6674 raise
6666 raise
6675 return source, sbranch, None, None, None
6667 return source, sbranch, None, None, None
6676 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6668 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6677 if revs:
6669 if revs:
6678 revs = [other.lookup(rev) for rev in revs]
6670 revs = [other.lookup(rev) for rev in revs]
6679 ui.debug('comparing with %s\n' % util.hidepassword(source))
6671 ui.debug('comparing with %s\n' % util.hidepassword(source))
6680 repo.ui.pushbuffer()
6672 repo.ui.pushbuffer()
6681 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6673 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6682 repo.ui.popbuffer()
6674 repo.ui.popbuffer()
6683 return source, sbranch, other, commoninc, commoninc[1]
6675 return source, sbranch, other, commoninc, commoninc[1]
6684
6676
6685 if needsincoming:
6677 if needsincoming:
6686 source, sbranch, sother, commoninc, incoming = getincoming()
6678 source, sbranch, sother, commoninc, incoming = getincoming()
6687 else:
6679 else:
6688 source = sbranch = sother = commoninc = incoming = None
6680 source = sbranch = sother = commoninc = incoming = None
6689
6681
6690 def getoutgoing():
6682 def getoutgoing():
6691 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6683 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6692 dbranch = branches[0]
6684 dbranch = branches[0]
6693 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6685 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6694 if source != dest:
6686 if source != dest:
6695 try:
6687 try:
6696 dother = hg.peer(repo, {}, dest)
6688 dother = hg.peer(repo, {}, dest)
6697 except error.RepoError:
6689 except error.RepoError:
6698 if opts.get('remote'):
6690 if opts.get('remote'):
6699 raise
6691 raise
6700 return dest, dbranch, None, None
6692 return dest, dbranch, None, None
6701 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6693 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6702 elif sother is None:
6694 elif sother is None:
6703 # there is no explicit destination peer, but source one is invalid
6695 # there is no explicit destination peer, but source one is invalid
6704 return dest, dbranch, None, None
6696 return dest, dbranch, None, None
6705 else:
6697 else:
6706 dother = sother
6698 dother = sother
6707 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6699 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6708 common = None
6700 common = None
6709 else:
6701 else:
6710 common = commoninc
6702 common = commoninc
6711 if revs:
6703 if revs:
6712 revs = [repo.lookup(rev) for rev in revs]
6704 revs = [repo.lookup(rev) for rev in revs]
6713 repo.ui.pushbuffer()
6705 repo.ui.pushbuffer()
6714 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6706 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6715 commoninc=common)
6707 commoninc=common)
6716 repo.ui.popbuffer()
6708 repo.ui.popbuffer()
6717 return dest, dbranch, dother, outgoing
6709 return dest, dbranch, dother, outgoing
6718
6710
6719 if needsoutgoing:
6711 if needsoutgoing:
6720 dest, dbranch, dother, outgoing = getoutgoing()
6712 dest, dbranch, dother, outgoing = getoutgoing()
6721 else:
6713 else:
6722 dest = dbranch = dother = outgoing = None
6714 dest = dbranch = dother = outgoing = None
6723
6715
6724 if opts.get('remote'):
6716 if opts.get('remote'):
6725 t = []
6717 t = []
6726 if incoming:
6718 if incoming:
6727 t.append(_('1 or more incoming'))
6719 t.append(_('1 or more incoming'))
6728 o = outgoing.missing
6720 o = outgoing.missing
6729 if o:
6721 if o:
6730 t.append(_('%d outgoing') % len(o))
6722 t.append(_('%d outgoing') % len(o))
6731 other = dother or sother
6723 other = dother or sother
6732 if 'bookmarks' in other.listkeys('namespaces'):
6724 if 'bookmarks' in other.listkeys('namespaces'):
6733 counts = bookmarks.summary(repo, other)
6725 counts = bookmarks.summary(repo, other)
6734 if counts[0] > 0:
6726 if counts[0] > 0:
6735 t.append(_('%d incoming bookmarks') % counts[0])
6727 t.append(_('%d incoming bookmarks') % counts[0])
6736 if counts[1] > 0:
6728 if counts[1] > 0:
6737 t.append(_('%d outgoing bookmarks') % counts[1])
6729 t.append(_('%d outgoing bookmarks') % counts[1])
6738
6730
6739 if t:
6731 if t:
6740 # i18n: column positioning for "hg summary"
6732 # i18n: column positioning for "hg summary"
6741 ui.write(_('remote: %s\n') % (', '.join(t)))
6733 ui.write(_('remote: %s\n') % (', '.join(t)))
6742 else:
6734 else:
6743 # i18n: column positioning for "hg summary"
6735 # i18n: column positioning for "hg summary"
6744 ui.status(_('remote: (synced)\n'))
6736 ui.status(_('remote: (synced)\n'))
6745
6737
6746 cmdutil.summaryremotehooks(ui, repo, opts,
6738 cmdutil.summaryremotehooks(ui, repo, opts,
6747 ((source, sbranch, sother, commoninc),
6739 ((source, sbranch, sother, commoninc),
6748 (dest, dbranch, dother, outgoing)))
6740 (dest, dbranch, dother, outgoing)))
6749
6741
6750 @command('tag',
6742 @command('tag',
6751 [('f', 'force', None, _('force tag')),
6743 [('f', 'force', None, _('force tag')),
6752 ('l', 'local', None, _('make the tag local')),
6744 ('l', 'local', None, _('make the tag local')),
6753 ('r', 'rev', '', _('revision to tag'), _('REV')),
6745 ('r', 'rev', '', _('revision to tag'), _('REV')),
6754 ('', 'remove', None, _('remove a tag')),
6746 ('', 'remove', None, _('remove a tag')),
6755 # -l/--local is already there, commitopts cannot be used
6747 # -l/--local is already there, commitopts cannot be used
6756 ('e', 'edit', None, _('invoke editor on commit messages')),
6748 ('e', 'edit', None, _('invoke editor on commit messages')),
6757 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6749 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6758 ] + commitopts2,
6750 ] + commitopts2,
6759 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6751 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6760 def tag(ui, repo, name1, *names, **opts):
6752 def tag(ui, repo, name1, *names, **opts):
6761 """add one or more tags for the current or given revision
6753 """add one or more tags for the current or given revision
6762
6754
6763 Name a particular revision using <name>.
6755 Name a particular revision using <name>.
6764
6756
6765 Tags are used to name particular revisions of the repository and are
6757 Tags are used to name particular revisions of the repository and are
6766 very useful to compare different revisions, to go back to significant
6758 very useful to compare different revisions, to go back to significant
6767 earlier versions or to mark branch points as releases, etc. Changing
6759 earlier versions or to mark branch points as releases, etc. Changing
6768 an existing tag is normally disallowed; use -f/--force to override.
6760 an existing tag is normally disallowed; use -f/--force to override.
6769
6761
6770 If no revision is given, the parent of the working directory is
6762 If no revision is given, the parent of the working directory is
6771 used.
6763 used.
6772
6764
6773 To facilitate version control, distribution, and merging of tags,
6765 To facilitate version control, distribution, and merging of tags,
6774 they are stored as a file named ".hgtags" which is managed similarly
6766 they are stored as a file named ".hgtags" which is managed similarly
6775 to other project files and can be hand-edited if necessary. This
6767 to other project files and can be hand-edited if necessary. This
6776 also means that tagging creates a new commit. The file
6768 also means that tagging creates a new commit. The file
6777 ".hg/localtags" is used for local tags (not shared among
6769 ".hg/localtags" is used for local tags (not shared among
6778 repositories).
6770 repositories).
6779
6771
6780 Tag commits are usually made at the head of a branch. If the parent
6772 Tag commits are usually made at the head of a branch. If the parent
6781 of the working directory is not a branch head, :hg:`tag` aborts; use
6773 of the working directory is not a branch head, :hg:`tag` aborts; use
6782 -f/--force to force the tag commit to be based on a non-head
6774 -f/--force to force the tag commit to be based on a non-head
6783 changeset.
6775 changeset.
6784
6776
6785 See :hg:`help dates` for a list of formats valid for -d/--date.
6777 See :hg:`help dates` for a list of formats valid for -d/--date.
6786
6778
6787 Since tag names have priority over branch names during revision
6779 Since tag names have priority over branch names during revision
6788 lookup, using an existing branch name as a tag name is discouraged.
6780 lookup, using an existing branch name as a tag name is discouraged.
6789
6781
6790 Returns 0 on success.
6782 Returns 0 on success.
6791 """
6783 """
6792 wlock = lock = None
6784 wlock = lock = None
6793 try:
6785 try:
6794 wlock = repo.wlock()
6786 wlock = repo.wlock()
6795 lock = repo.lock()
6787 lock = repo.lock()
6796 rev_ = "."
6788 rev_ = "."
6797 names = [t.strip() for t in (name1,) + names]
6789 names = [t.strip() for t in (name1,) + names]
6798 if len(names) != len(set(names)):
6790 if len(names) != len(set(names)):
6799 raise error.Abort(_('tag names must be unique'))
6791 raise error.Abort(_('tag names must be unique'))
6800 for n in names:
6792 for n in names:
6801 scmutil.checknewlabel(repo, n, 'tag')
6793 scmutil.checknewlabel(repo, n, 'tag')
6802 if not n:
6794 if not n:
6803 raise error.Abort(_('tag names cannot consist entirely of '
6795 raise error.Abort(_('tag names cannot consist entirely of '
6804 'whitespace'))
6796 'whitespace'))
6805 if opts.get('rev') and opts.get('remove'):
6797 if opts.get('rev') and opts.get('remove'):
6806 raise error.Abort(_("--rev and --remove are incompatible"))
6798 raise error.Abort(_("--rev and --remove are incompatible"))
6807 if opts.get('rev'):
6799 if opts.get('rev'):
6808 rev_ = opts['rev']
6800 rev_ = opts['rev']
6809 message = opts.get('message')
6801 message = opts.get('message')
6810 if opts.get('remove'):
6802 if opts.get('remove'):
6811 if opts.get('local'):
6803 if opts.get('local'):
6812 expectedtype = 'local'
6804 expectedtype = 'local'
6813 else:
6805 else:
6814 expectedtype = 'global'
6806 expectedtype = 'global'
6815
6807
6816 for n in names:
6808 for n in names:
6817 if not repo.tagtype(n):
6809 if not repo.tagtype(n):
6818 raise error.Abort(_("tag '%s' does not exist") % n)
6810 raise error.Abort(_("tag '%s' does not exist") % n)
6819 if repo.tagtype(n) != expectedtype:
6811 if repo.tagtype(n) != expectedtype:
6820 if expectedtype == 'global':
6812 if expectedtype == 'global':
6821 raise error.Abort(_("tag '%s' is not a global tag") % n)
6813 raise error.Abort(_("tag '%s' is not a global tag") % n)
6822 else:
6814 else:
6823 raise error.Abort(_("tag '%s' is not a local tag") % n)
6815 raise error.Abort(_("tag '%s' is not a local tag") % n)
6824 rev_ = 'null'
6816 rev_ = 'null'
6825 if not message:
6817 if not message:
6826 # we don't translate commit messages
6818 # we don't translate commit messages
6827 message = 'Removed tag %s' % ', '.join(names)
6819 message = 'Removed tag %s' % ', '.join(names)
6828 elif not opts.get('force'):
6820 elif not opts.get('force'):
6829 for n in names:
6821 for n in names:
6830 if n in repo.tags():
6822 if n in repo.tags():
6831 raise error.Abort(_("tag '%s' already exists "
6823 raise error.Abort(_("tag '%s' already exists "
6832 "(use -f to force)") % n)
6824 "(use -f to force)") % n)
6833 if not opts.get('local'):
6825 if not opts.get('local'):
6834 p1, p2 = repo.dirstate.parents()
6826 p1, p2 = repo.dirstate.parents()
6835 if p2 != nullid:
6827 if p2 != nullid:
6836 raise error.Abort(_('uncommitted merge'))
6828 raise error.Abort(_('uncommitted merge'))
6837 bheads = repo.branchheads()
6829 bheads = repo.branchheads()
6838 if not opts.get('force') and bheads and p1 not in bheads:
6830 if not opts.get('force') and bheads and p1 not in bheads:
6839 raise error.Abort(_('working directory is not at a branch head '
6831 raise error.Abort(_('working directory is not at a branch head '
6840 '(use -f to force)'))
6832 '(use -f to force)'))
6841 r = scmutil.revsingle(repo, rev_).node()
6833 r = scmutil.revsingle(repo, rev_).node()
6842
6834
6843 if not message:
6835 if not message:
6844 # we don't translate commit messages
6836 # we don't translate commit messages
6845 message = ('Added tag %s for changeset %s' %
6837 message = ('Added tag %s for changeset %s' %
6846 (', '.join(names), short(r)))
6838 (', '.join(names), short(r)))
6847
6839
6848 date = opts.get('date')
6840 date = opts.get('date')
6849 if date:
6841 if date:
6850 date = util.parsedate(date)
6842 date = util.parsedate(date)
6851
6843
6852 if opts.get('remove'):
6844 if opts.get('remove'):
6853 editform = 'tag.remove'
6845 editform = 'tag.remove'
6854 else:
6846 else:
6855 editform = 'tag.add'
6847 editform = 'tag.add'
6856 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6848 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6857
6849
6858 # don't allow tagging the null rev
6850 # don't allow tagging the null rev
6859 if (not opts.get('remove') and
6851 if (not opts.get('remove') and
6860 scmutil.revsingle(repo, rev_).rev() == nullrev):
6852 scmutil.revsingle(repo, rev_).rev() == nullrev):
6861 raise error.Abort(_("cannot tag null revision"))
6853 raise error.Abort(_("cannot tag null revision"))
6862
6854
6863 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6855 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6864 editor=editor)
6856 editor=editor)
6865 finally:
6857 finally:
6866 release(lock, wlock)
6858 release(lock, wlock)
6867
6859
6868 @command('tags', formatteropts, '')
6860 @command('tags', formatteropts, '')
6869 def tags(ui, repo, **opts):
6861 def tags(ui, repo, **opts):
6870 """list repository tags
6862 """list repository tags
6871
6863
6872 This lists both regular and local tags. When the -v/--verbose
6864 This lists both regular and local tags. When the -v/--verbose
6873 switch is used, a third column "local" is printed for local tags.
6865 switch is used, a third column "local" is printed for local tags.
6874 When the -q/--quiet switch is used, only the tag name is printed.
6866 When the -q/--quiet switch is used, only the tag name is printed.
6875
6867
6876 Returns 0 on success.
6868 Returns 0 on success.
6877 """
6869 """
6878
6870
6879 fm = ui.formatter('tags', opts)
6871 fm = ui.formatter('tags', opts)
6880 hexfunc = fm.hexfunc
6872 hexfunc = fm.hexfunc
6881 tagtype = ""
6873 tagtype = ""
6882
6874
6883 for t, n in reversed(repo.tagslist()):
6875 for t, n in reversed(repo.tagslist()):
6884 hn = hexfunc(n)
6876 hn = hexfunc(n)
6885 label = 'tags.normal'
6877 label = 'tags.normal'
6886 tagtype = ''
6878 tagtype = ''
6887 if repo.tagtype(t) == 'local':
6879 if repo.tagtype(t) == 'local':
6888 label = 'tags.local'
6880 label = 'tags.local'
6889 tagtype = 'local'
6881 tagtype = 'local'
6890
6882
6891 fm.startitem()
6883 fm.startitem()
6892 fm.write('tag', '%s', t, label=label)
6884 fm.write('tag', '%s', t, label=label)
6893 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6885 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6894 fm.condwrite(not ui.quiet, 'rev node', fmt,
6886 fm.condwrite(not ui.quiet, 'rev node', fmt,
6895 repo.changelog.rev(n), hn, label=label)
6887 repo.changelog.rev(n), hn, label=label)
6896 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6888 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6897 tagtype, label=label)
6889 tagtype, label=label)
6898 fm.plain('\n')
6890 fm.plain('\n')
6899 fm.end()
6891 fm.end()
6900
6892
6901 @command('tip',
6893 @command('tip',
6902 [('p', 'patch', None, _('show patch')),
6894 [('p', 'patch', None, _('show patch')),
6903 ('g', 'git', None, _('use git extended diff format')),
6895 ('g', 'git', None, _('use git extended diff format')),
6904 ] + templateopts,
6896 ] + templateopts,
6905 _('[-p] [-g]'))
6897 _('[-p] [-g]'))
6906 def tip(ui, repo, **opts):
6898 def tip(ui, repo, **opts):
6907 """show the tip revision (DEPRECATED)
6899 """show the tip revision (DEPRECATED)
6908
6900
6909 The tip revision (usually just called the tip) is the changeset
6901 The tip revision (usually just called the tip) is the changeset
6910 most recently added to the repository (and therefore the most
6902 most recently added to the repository (and therefore the most
6911 recently changed head).
6903 recently changed head).
6912
6904
6913 If you have just made a commit, that commit will be the tip. If
6905 If you have just made a commit, that commit will be the tip. If
6914 you have just pulled changes from another repository, the tip of
6906 you have just pulled changes from another repository, the tip of
6915 that repository becomes the current tip. The "tip" tag is special
6907 that repository becomes the current tip. The "tip" tag is special
6916 and cannot be renamed or assigned to a different changeset.
6908 and cannot be renamed or assigned to a different changeset.
6917
6909
6918 This command is deprecated, please use :hg:`heads` instead.
6910 This command is deprecated, please use :hg:`heads` instead.
6919
6911
6920 Returns 0 on success.
6912 Returns 0 on success.
6921 """
6913 """
6922 displayer = cmdutil.show_changeset(ui, repo, opts)
6914 displayer = cmdutil.show_changeset(ui, repo, opts)
6923 displayer.show(repo['tip'])
6915 displayer.show(repo['tip'])
6924 displayer.close()
6916 displayer.close()
6925
6917
6926 @command('unbundle',
6918 @command('unbundle',
6927 [('u', 'update', None,
6919 [('u', 'update', None,
6928 _('update to new branch head if changesets were unbundled'))],
6920 _('update to new branch head if changesets were unbundled'))],
6929 _('[-u] FILE...'))
6921 _('[-u] FILE...'))
6930 def unbundle(ui, repo, fname1, *fnames, **opts):
6922 def unbundle(ui, repo, fname1, *fnames, **opts):
6931 """apply one or more changegroup files
6923 """apply one or more changegroup files
6932
6924
6933 Apply one or more compressed changegroup files generated by the
6925 Apply one or more compressed changegroup files generated by the
6934 bundle command.
6926 bundle command.
6935
6927
6936 Returns 0 on success, 1 if an update has unresolved files.
6928 Returns 0 on success, 1 if an update has unresolved files.
6937 """
6929 """
6938 fnames = (fname1,) + fnames
6930 fnames = (fname1,) + fnames
6939
6931
6940 with repo.lock():
6932 with repo.lock():
6941 for fname in fnames:
6933 for fname in fnames:
6942 f = hg.openpath(ui, fname)
6934 f = hg.openpath(ui, fname)
6943 gen = exchange.readbundle(ui, f, fname)
6935 gen = exchange.readbundle(ui, f, fname)
6944 if isinstance(gen, bundle2.unbundle20):
6936 if isinstance(gen, bundle2.unbundle20):
6945 tr = repo.transaction('unbundle')
6937 tr = repo.transaction('unbundle')
6946 try:
6938 try:
6947 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6939 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6948 url='bundle:' + fname)
6940 url='bundle:' + fname)
6949 tr.close()
6941 tr.close()
6950 except error.BundleUnknownFeatureError as exc:
6942 except error.BundleUnknownFeatureError as exc:
6951 raise error.Abort(_('%s: unknown bundle feature, %s')
6943 raise error.Abort(_('%s: unknown bundle feature, %s')
6952 % (fname, exc),
6944 % (fname, exc),
6953 hint=_("see https://mercurial-scm.org/"
6945 hint=_("see https://mercurial-scm.org/"
6954 "wiki/BundleFeature for more "
6946 "wiki/BundleFeature for more "
6955 "information"))
6947 "information"))
6956 finally:
6948 finally:
6957 if tr:
6949 if tr:
6958 tr.release()
6950 tr.release()
6959 changes = [r.get('return', 0)
6951 changes = [r.get('return', 0)
6960 for r in op.records['changegroup']]
6952 for r in op.records['changegroup']]
6961 modheads = changegroup.combineresults(changes)
6953 modheads = changegroup.combineresults(changes)
6962 elif isinstance(gen, streamclone.streamcloneapplier):
6954 elif isinstance(gen, streamclone.streamcloneapplier):
6963 raise error.Abort(
6955 raise error.Abort(
6964 _('packed bundles cannot be applied with '
6956 _('packed bundles cannot be applied with '
6965 '"hg unbundle"'),
6957 '"hg unbundle"'),
6966 hint=_('use "hg debugapplystreamclonebundle"'))
6958 hint=_('use "hg debugapplystreamclonebundle"'))
6967 else:
6959 else:
6968 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6960 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6969
6961
6970 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6962 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6971
6963
6972 @command('^update|up|checkout|co',
6964 @command('^update|up|checkout|co',
6973 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6965 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6974 ('c', 'check', None, _('require clean working directory')),
6966 ('c', 'check', None, _('require clean working directory')),
6975 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6967 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6976 ('r', 'rev', '', _('revision'), _('REV'))
6968 ('r', 'rev', '', _('revision'), _('REV'))
6977 ] + mergetoolopts,
6969 ] + mergetoolopts,
6978 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6970 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6979 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6971 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6980 tool=None):
6972 tool=None):
6981 """update working directory (or switch revisions)
6973 """update working directory (or switch revisions)
6982
6974
6983 Update the repository's working directory to the specified
6975 Update the repository's working directory to the specified
6984 changeset. If no changeset is specified, update to the tip of the
6976 changeset. If no changeset is specified, update to the tip of the
6985 current named branch and move the active bookmark (see :hg:`help
6977 current named branch and move the active bookmark (see :hg:`help
6986 bookmarks`).
6978 bookmarks`).
6987
6979
6988 Update sets the working directory's parent revision to the specified
6980 Update sets the working directory's parent revision to the specified
6989 changeset (see :hg:`help parents`).
6981 changeset (see :hg:`help parents`).
6990
6982
6991 If the changeset is not a descendant or ancestor of the working
6983 If the changeset is not a descendant or ancestor of the working
6992 directory's parent, the update is aborted. With the -c/--check
6984 directory's parent, the update is aborted. With the -c/--check
6993 option, the working directory is checked for uncommitted changes; if
6985 option, the working directory is checked for uncommitted changes; if
6994 none are found, the working directory is updated to the specified
6986 none are found, the working directory is updated to the specified
6995 changeset.
6987 changeset.
6996
6988
6997 .. container:: verbose
6989 .. container:: verbose
6998
6990
6999 The following rules apply when the working directory contains
6991 The following rules apply when the working directory contains
7000 uncommitted changes:
6992 uncommitted changes:
7001
6993
7002 1. If neither -c/--check nor -C/--clean is specified, and if
6994 1. If neither -c/--check nor -C/--clean is specified, and if
7003 the requested changeset is an ancestor or descendant of
6995 the requested changeset is an ancestor or descendant of
7004 the working directory's parent, the uncommitted changes
6996 the working directory's parent, the uncommitted changes
7005 are merged into the requested changeset and the merged
6997 are merged into the requested changeset and the merged
7006 result is left uncommitted. If the requested changeset is
6998 result is left uncommitted. If the requested changeset is
7007 not an ancestor or descendant (that is, it is on another
6999 not an ancestor or descendant (that is, it is on another
7008 branch), the update is aborted and the uncommitted changes
7000 branch), the update is aborted and the uncommitted changes
7009 are preserved.
7001 are preserved.
7010
7002
7011 2. With the -c/--check option, the update is aborted and the
7003 2. With the -c/--check option, the update is aborted and the
7012 uncommitted changes are preserved.
7004 uncommitted changes are preserved.
7013
7005
7014 3. With the -C/--clean option, uncommitted changes are discarded and
7006 3. With the -C/--clean option, uncommitted changes are discarded and
7015 the working directory is updated to the requested changeset.
7007 the working directory is updated to the requested changeset.
7016
7008
7017 To cancel an uncommitted merge (and lose your changes), use
7009 To cancel an uncommitted merge (and lose your changes), use
7018 :hg:`update --clean .`.
7010 :hg:`update --clean .`.
7019
7011
7020 Use null as the changeset to remove the working directory (like
7012 Use null as the changeset to remove the working directory (like
7021 :hg:`clone -U`).
7013 :hg:`clone -U`).
7022
7014
7023 If you want to revert just one file to an older revision, use
7015 If you want to revert just one file to an older revision, use
7024 :hg:`revert [-r REV] NAME`.
7016 :hg:`revert [-r REV] NAME`.
7025
7017
7026 See :hg:`help dates` for a list of formats valid for -d/--date.
7018 See :hg:`help dates` for a list of formats valid for -d/--date.
7027
7019
7028 Returns 0 on success, 1 if there are unresolved files.
7020 Returns 0 on success, 1 if there are unresolved files.
7029 """
7021 """
7030 if rev and node:
7022 if rev and node:
7031 raise error.Abort(_("please specify just one revision"))
7023 raise error.Abort(_("please specify just one revision"))
7032
7024
7033 if rev is None or rev == '':
7025 if rev is None or rev == '':
7034 rev = node
7026 rev = node
7035
7027
7036 if date and rev is not None:
7028 if date and rev is not None:
7037 raise error.Abort(_("you can't specify a revision and a date"))
7029 raise error.Abort(_("you can't specify a revision and a date"))
7038
7030
7039 if check and clean:
7031 if check and clean:
7040 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7032 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7041
7033
7042 with repo.wlock():
7034 with repo.wlock():
7043 cmdutil.clearunfinished(repo)
7035 cmdutil.clearunfinished(repo)
7044
7036
7045 if date:
7037 if date:
7046 rev = cmdutil.finddate(ui, repo, date)
7038 rev = cmdutil.finddate(ui, repo, date)
7047
7039
7048 # if we defined a bookmark, we have to remember the original name
7040 # if we defined a bookmark, we have to remember the original name
7049 brev = rev
7041 brev = rev
7050 rev = scmutil.revsingle(repo, rev, rev).rev()
7042 rev = scmutil.revsingle(repo, rev, rev).rev()
7051
7043
7052 if check:
7044 if check:
7053 cmdutil.bailifchanged(repo, merge=False)
7045 cmdutil.bailifchanged(repo, merge=False)
7054
7046
7055 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7047 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7056
7048
7057 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7049 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7058
7050
7059 @command('verify', [])
7051 @command('verify', [])
7060 def verify(ui, repo):
7052 def verify(ui, repo):
7061 """verify the integrity of the repository
7053 """verify the integrity of the repository
7062
7054
7063 Verify the integrity of the current repository.
7055 Verify the integrity of the current repository.
7064
7056
7065 This will perform an extensive check of the repository's
7057 This will perform an extensive check of the repository's
7066 integrity, validating the hashes and checksums of each entry in
7058 integrity, validating the hashes and checksums of each entry in
7067 the changelog, manifest, and tracked files, as well as the
7059 the changelog, manifest, and tracked files, as well as the
7068 integrity of their crosslinks and indices.
7060 integrity of their crosslinks and indices.
7069
7061
7070 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7062 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7071 for more information about recovery from corruption of the
7063 for more information about recovery from corruption of the
7072 repository.
7064 repository.
7073
7065
7074 Returns 0 on success, 1 if errors are encountered.
7066 Returns 0 on success, 1 if errors are encountered.
7075 """
7067 """
7076 return hg.verify(repo)
7068 return hg.verify(repo)
7077
7069
7078 @command('version', [] + formatteropts, norepo=True)
7070 @command('version', [] + formatteropts, norepo=True)
7079 def version_(ui, **opts):
7071 def version_(ui, **opts):
7080 """output version and copyright information"""
7072 """output version and copyright information"""
7081 fm = ui.formatter("version", opts)
7073 fm = ui.formatter("version", opts)
7082 fm.startitem()
7074 fm.startitem()
7083 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7075 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7084 util.version())
7076 util.version())
7085 license = _(
7077 license = _(
7086 "(see https://mercurial-scm.org for more information)\n"
7078 "(see https://mercurial-scm.org for more information)\n"
7087 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7079 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7088 "This is free software; see the source for copying conditions. "
7080 "This is free software; see the source for copying conditions. "
7089 "There is NO\nwarranty; "
7081 "There is NO\nwarranty; "
7090 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7082 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7091 )
7083 )
7092 if not ui.quiet:
7084 if not ui.quiet:
7093 fm.plain(license)
7085 fm.plain(license)
7094
7086
7095 if ui.verbose:
7087 if ui.verbose:
7096 fm.plain(_("\nEnabled extensions:\n\n"))
7088 fm.plain(_("\nEnabled extensions:\n\n"))
7097 # format names and versions into columns
7089 # format names and versions into columns
7098 names = []
7090 names = []
7099 vers = []
7091 vers = []
7100 isinternals = []
7092 isinternals = []
7101 for name, module in extensions.extensions():
7093 for name, module in extensions.extensions():
7102 names.append(name)
7094 names.append(name)
7103 vers.append(extensions.moduleversion(module) or None)
7095 vers.append(extensions.moduleversion(module) or None)
7104 isinternals.append(extensions.ismoduleinternal(module))
7096 isinternals.append(extensions.ismoduleinternal(module))
7105 fn = fm.nested("extensions")
7097 fn = fm.nested("extensions")
7106 if names:
7098 if names:
7107 namefmt = " %%-%ds " % max(len(n) for n in names)
7099 namefmt = " %%-%ds " % max(len(n) for n in names)
7108 places = [_("external"), _("internal")]
7100 places = [_("external"), _("internal")]
7109 for n, v, p in zip(names, vers, isinternals):
7101 for n, v, p in zip(names, vers, isinternals):
7110 fn.startitem()
7102 fn.startitem()
7111 fn.condwrite(ui.verbose, "name", namefmt, n)
7103 fn.condwrite(ui.verbose, "name", namefmt, n)
7112 if ui.verbose:
7104 if ui.verbose:
7113 fn.plain("%s " % places[p])
7105 fn.plain("%s " % places[p])
7114 fn.data(bundled=p)
7106 fn.data(bundled=p)
7115 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7107 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7116 if ui.verbose:
7108 if ui.verbose:
7117 fn.plain("\n")
7109 fn.plain("\n")
7118 fn.end()
7110 fn.end()
7119 fm.end()
7111 fm.end()
7120
7112
7121 def loadcmdtable(ui, name, cmdtable):
7113 def loadcmdtable(ui, name, cmdtable):
7122 """Load command functions from specified cmdtable
7114 """Load command functions from specified cmdtable
7123 """
7115 """
7124 overrides = [cmd for cmd in cmdtable if cmd in table]
7116 overrides = [cmd for cmd in cmdtable if cmd in table]
7125 if overrides:
7117 if overrides:
7126 ui.warn(_("extension '%s' overrides commands: %s\n")
7118 ui.warn(_("extension '%s' overrides commands: %s\n")
7127 % (name, " ".join(overrides)))
7119 % (name, " ".join(overrides)))
7128 table.update(cmdtable)
7120 table.update(cmdtable)
@@ -1,323 +1,331
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 hex,
14 hex,
15 )
15 )
16 from . import (
16 from . import (
17 bundle2,
17 bundle2,
18 changegroup,
18 changegroup,
19 cmdutil,
19 cmdutil,
20 commands,
20 commands,
21 context,
21 context,
22 dagparser,
22 dagparser,
23 error,
23 error,
24 exchange,
24 exchange,
25 hg,
25 hg,
26 lock as lockmod,
26 lock as lockmod,
27 revlog,
27 revlog,
28 scmutil,
28 scmutil,
29 simplemerge,
29 simplemerge,
30 streamclone,
30 streamclone,
31 )
31 )
32
32
33 release = lockmod.release
33 release = lockmod.release
34
34
35 # We reuse the command table from commands because it is easier than
35 # We reuse the command table from commands because it is easier than
36 # teaching dispatch about multiple tables.
36 # teaching dispatch about multiple tables.
37 command = cmdutil.command(commands.table)
37 command = cmdutil.command(commands.table)
38
38
39 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
39 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
40 def debugancestor(ui, repo, *args):
40 def debugancestor(ui, repo, *args):
41 """find the ancestor revision of two revisions in a given index"""
41 """find the ancestor revision of two revisions in a given index"""
42 if len(args) == 3:
42 if len(args) == 3:
43 index, rev1, rev2 = args
43 index, rev1, rev2 = args
44 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
44 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
45 lookup = r.lookup
45 lookup = r.lookup
46 elif len(args) == 2:
46 elif len(args) == 2:
47 if not repo:
47 if not repo:
48 raise error.Abort(_('there is no Mercurial repository here '
48 raise error.Abort(_('there is no Mercurial repository here '
49 '(.hg not found)'))
49 '(.hg not found)'))
50 rev1, rev2 = args
50 rev1, rev2 = args
51 r = repo.changelog
51 r = repo.changelog
52 lookup = repo.lookup
52 lookup = repo.lookup
53 else:
53 else:
54 raise error.Abort(_('either two or three arguments required'))
54 raise error.Abort(_('either two or three arguments required'))
55 a = r.ancestor(lookup(rev1), lookup(rev2))
55 a = r.ancestor(lookup(rev1), lookup(rev2))
56 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
56 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
57
57
58 @command('debugbuilddag',
58 @command('debugbuilddag',
59 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
59 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
60 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
60 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
61 ('n', 'new-file', None, _('add new file at each rev'))],
61 ('n', 'new-file', None, _('add new file at each rev'))],
62 _('[OPTION]... [TEXT]'))
62 _('[OPTION]... [TEXT]'))
63 def debugbuilddag(ui, repo, text=None,
63 def debugbuilddag(ui, repo, text=None,
64 mergeable_file=False,
64 mergeable_file=False,
65 overwritten_file=False,
65 overwritten_file=False,
66 new_file=False):
66 new_file=False):
67 """builds a repo with a given DAG from scratch in the current empty repo
67 """builds a repo with a given DAG from scratch in the current empty repo
68
68
69 The description of the DAG is read from stdin if not given on the
69 The description of the DAG is read from stdin if not given on the
70 command line.
70 command line.
71
71
72 Elements:
72 Elements:
73
73
74 - "+n" is a linear run of n nodes based on the current default parent
74 - "+n" is a linear run of n nodes based on the current default parent
75 - "." is a single node based on the current default parent
75 - "." is a single node based on the current default parent
76 - "$" resets the default parent to null (implied at the start);
76 - "$" resets the default parent to null (implied at the start);
77 otherwise the default parent is always the last node created
77 otherwise the default parent is always the last node created
78 - "<p" sets the default parent to the backref p
78 - "<p" sets the default parent to the backref p
79 - "*p" is a fork at parent p, which is a backref
79 - "*p" is a fork at parent p, which is a backref
80 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
80 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
81 - "/p2" is a merge of the preceding node and p2
81 - "/p2" is a merge of the preceding node and p2
82 - ":tag" defines a local tag for the preceding node
82 - ":tag" defines a local tag for the preceding node
83 - "@branch" sets the named branch for subsequent nodes
83 - "@branch" sets the named branch for subsequent nodes
84 - "#...\\n" is a comment up to the end of the line
84 - "#...\\n" is a comment up to the end of the line
85
85
86 Whitespace between the above elements is ignored.
86 Whitespace between the above elements is ignored.
87
87
88 A backref is either
88 A backref is either
89
89
90 - a number n, which references the node curr-n, where curr is the current
90 - a number n, which references the node curr-n, where curr is the current
91 node, or
91 node, or
92 - the name of a local tag you placed earlier using ":tag", or
92 - the name of a local tag you placed earlier using ":tag", or
93 - empty to denote the default parent.
93 - empty to denote the default parent.
94
94
95 All string valued-elements are either strictly alphanumeric, or must
95 All string valued-elements are either strictly alphanumeric, or must
96 be enclosed in double quotes ("..."), with "\\" as escape character.
96 be enclosed in double quotes ("..."), with "\\" as escape character.
97 """
97 """
98
98
99 if text is None:
99 if text is None:
100 ui.status(_("reading DAG from stdin\n"))
100 ui.status(_("reading DAG from stdin\n"))
101 text = ui.fin.read()
101 text = ui.fin.read()
102
102
103 cl = repo.changelog
103 cl = repo.changelog
104 if len(cl) > 0:
104 if len(cl) > 0:
105 raise error.Abort(_('repository is not empty'))
105 raise error.Abort(_('repository is not empty'))
106
106
107 # determine number of revs in DAG
107 # determine number of revs in DAG
108 total = 0
108 total = 0
109 for type, data in dagparser.parsedag(text):
109 for type, data in dagparser.parsedag(text):
110 if type == 'n':
110 if type == 'n':
111 total += 1
111 total += 1
112
112
113 if mergeable_file:
113 if mergeable_file:
114 linesperrev = 2
114 linesperrev = 2
115 # make a file with k lines per rev
115 # make a file with k lines per rev
116 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
116 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
117 initialmergedlines.append("")
117 initialmergedlines.append("")
118
118
119 tags = []
119 tags = []
120
120
121 wlock = lock = tr = None
121 wlock = lock = tr = None
122 try:
122 try:
123 wlock = repo.wlock()
123 wlock = repo.wlock()
124 lock = repo.lock()
124 lock = repo.lock()
125 tr = repo.transaction("builddag")
125 tr = repo.transaction("builddag")
126
126
127 at = -1
127 at = -1
128 atbranch = 'default'
128 atbranch = 'default'
129 nodeids = []
129 nodeids = []
130 id = 0
130 id = 0
131 ui.progress(_('building'), id, unit=_('revisions'), total=total)
131 ui.progress(_('building'), id, unit=_('revisions'), total=total)
132 for type, data in dagparser.parsedag(text):
132 for type, data in dagparser.parsedag(text):
133 if type == 'n':
133 if type == 'n':
134 ui.note(('node %s\n' % str(data)))
134 ui.note(('node %s\n' % str(data)))
135 id, ps = data
135 id, ps = data
136
136
137 files = []
137 files = []
138 fctxs = {}
138 fctxs = {}
139
139
140 p2 = None
140 p2 = None
141 if mergeable_file:
141 if mergeable_file:
142 fn = "mf"
142 fn = "mf"
143 p1 = repo[ps[0]]
143 p1 = repo[ps[0]]
144 if len(ps) > 1:
144 if len(ps) > 1:
145 p2 = repo[ps[1]]
145 p2 = repo[ps[1]]
146 pa = p1.ancestor(p2)
146 pa = p1.ancestor(p2)
147 base, local, other = [x[fn].data() for x in (pa, p1,
147 base, local, other = [x[fn].data() for x in (pa, p1,
148 p2)]
148 p2)]
149 m3 = simplemerge.Merge3Text(base, local, other)
149 m3 = simplemerge.Merge3Text(base, local, other)
150 ml = [l.strip() for l in m3.merge_lines()]
150 ml = [l.strip() for l in m3.merge_lines()]
151 ml.append("")
151 ml.append("")
152 elif at > 0:
152 elif at > 0:
153 ml = p1[fn].data().split("\n")
153 ml = p1[fn].data().split("\n")
154 else:
154 else:
155 ml = initialmergedlines
155 ml = initialmergedlines
156 ml[id * linesperrev] += " r%i" % id
156 ml[id * linesperrev] += " r%i" % id
157 mergedtext = "\n".join(ml)
157 mergedtext = "\n".join(ml)
158 files.append(fn)
158 files.append(fn)
159 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
159 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
160
160
161 if overwritten_file:
161 if overwritten_file:
162 fn = "of"
162 fn = "of"
163 files.append(fn)
163 files.append(fn)
164 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
164 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
165
165
166 if new_file:
166 if new_file:
167 fn = "nf%i" % id
167 fn = "nf%i" % id
168 files.append(fn)
168 files.append(fn)
169 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
169 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
170 if len(ps) > 1:
170 if len(ps) > 1:
171 if not p2:
171 if not p2:
172 p2 = repo[ps[1]]
172 p2 = repo[ps[1]]
173 for fn in p2:
173 for fn in p2:
174 if fn.startswith("nf"):
174 if fn.startswith("nf"):
175 files.append(fn)
175 files.append(fn)
176 fctxs[fn] = p2[fn]
176 fctxs[fn] = p2[fn]
177
177
178 def fctxfn(repo, cx, path):
178 def fctxfn(repo, cx, path):
179 return fctxs.get(path)
179 return fctxs.get(path)
180
180
181 if len(ps) == 0 or ps[0] < 0:
181 if len(ps) == 0 or ps[0] < 0:
182 pars = [None, None]
182 pars = [None, None]
183 elif len(ps) == 1:
183 elif len(ps) == 1:
184 pars = [nodeids[ps[0]], None]
184 pars = [nodeids[ps[0]], None]
185 else:
185 else:
186 pars = [nodeids[p] for p in ps]
186 pars = [nodeids[p] for p in ps]
187 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
187 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
188 date=(id, 0),
188 date=(id, 0),
189 user="debugbuilddag",
189 user="debugbuilddag",
190 extra={'branch': atbranch})
190 extra={'branch': atbranch})
191 nodeid = repo.commitctx(cx)
191 nodeid = repo.commitctx(cx)
192 nodeids.append(nodeid)
192 nodeids.append(nodeid)
193 at = id
193 at = id
194 elif type == 'l':
194 elif type == 'l':
195 id, name = data
195 id, name = data
196 ui.note(('tag %s\n' % name))
196 ui.note(('tag %s\n' % name))
197 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
197 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
198 elif type == 'a':
198 elif type == 'a':
199 ui.note(('branch %s\n' % data))
199 ui.note(('branch %s\n' % data))
200 atbranch = data
200 atbranch = data
201 ui.progress(_('building'), id, unit=_('revisions'), total=total)
201 ui.progress(_('building'), id, unit=_('revisions'), total=total)
202 tr.close()
202 tr.close()
203
203
204 if tags:
204 if tags:
205 repo.vfs.write("localtags", "".join(tags))
205 repo.vfs.write("localtags", "".join(tags))
206 finally:
206 finally:
207 ui.progress(_('building'), None)
207 ui.progress(_('building'), None)
208 release(tr, lock, wlock)
208 release(tr, lock, wlock)
209
209
210 @command('debugbundle',
210 @command('debugbundle',
211 [('a', 'all', None, _('show all details')),
211 [('a', 'all', None, _('show all details')),
212 ('', 'spec', None, _('print the bundlespec of the bundle'))],
212 ('', 'spec', None, _('print the bundlespec of the bundle'))],
213 _('FILE'),
213 _('FILE'),
214 norepo=True)
214 norepo=True)
215 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
215 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
216 """lists the contents of a bundle"""
216 """lists the contents of a bundle"""
217 with hg.openpath(ui, bundlepath) as f:
217 with hg.openpath(ui, bundlepath) as f:
218 if spec:
218 if spec:
219 spec = exchange.getbundlespec(ui, f)
219 spec = exchange.getbundlespec(ui, f)
220 ui.write('%s\n' % spec)
220 ui.write('%s\n' % spec)
221 return
221 return
222
222
223 gen = exchange.readbundle(ui, f, bundlepath)
223 gen = exchange.readbundle(ui, f, bundlepath)
224 if isinstance(gen, bundle2.unbundle20):
224 if isinstance(gen, bundle2.unbundle20):
225 return _debugbundle2(ui, gen, all=all, **opts)
225 return _debugbundle2(ui, gen, all=all, **opts)
226 _debugchangegroup(ui, gen, all=all, **opts)
226 _debugchangegroup(ui, gen, all=all, **opts)
227
227
228 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
228 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
229 indent_string = ' ' * indent
229 indent_string = ' ' * indent
230 if all:
230 if all:
231 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
231 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
232 % indent_string)
232 % indent_string)
233
233
234 def showchunks(named):
234 def showchunks(named):
235 ui.write("\n%s%s\n" % (indent_string, named))
235 ui.write("\n%s%s\n" % (indent_string, named))
236 chain = None
236 chain = None
237 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
237 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
238 node = chunkdata['node']
238 node = chunkdata['node']
239 p1 = chunkdata['p1']
239 p1 = chunkdata['p1']
240 p2 = chunkdata['p2']
240 p2 = chunkdata['p2']
241 cs = chunkdata['cs']
241 cs = chunkdata['cs']
242 deltabase = chunkdata['deltabase']
242 deltabase = chunkdata['deltabase']
243 delta = chunkdata['delta']
243 delta = chunkdata['delta']
244 ui.write("%s%s %s %s %s %s %s\n" %
244 ui.write("%s%s %s %s %s %s %s\n" %
245 (indent_string, hex(node), hex(p1), hex(p2),
245 (indent_string, hex(node), hex(p1), hex(p2),
246 hex(cs), hex(deltabase), len(delta)))
246 hex(cs), hex(deltabase), len(delta)))
247 chain = node
247 chain = node
248
248
249 chunkdata = gen.changelogheader()
249 chunkdata = gen.changelogheader()
250 showchunks("changelog")
250 showchunks("changelog")
251 chunkdata = gen.manifestheader()
251 chunkdata = gen.manifestheader()
252 showchunks("manifest")
252 showchunks("manifest")
253 for chunkdata in iter(gen.filelogheader, {}):
253 for chunkdata in iter(gen.filelogheader, {}):
254 fname = chunkdata['filename']
254 fname = chunkdata['filename']
255 showchunks(fname)
255 showchunks(fname)
256 else:
256 else:
257 if isinstance(gen, bundle2.unbundle20):
257 if isinstance(gen, bundle2.unbundle20):
258 raise error.Abort(_('use debugbundle2 for this file'))
258 raise error.Abort(_('use debugbundle2 for this file'))
259 chunkdata = gen.changelogheader()
259 chunkdata = gen.changelogheader()
260 chain = None
260 chain = None
261 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
261 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
262 node = chunkdata['node']
262 node = chunkdata['node']
263 ui.write("%s%s\n" % (indent_string, hex(node)))
263 ui.write("%s%s\n" % (indent_string, hex(node)))
264 chain = node
264 chain = node
265
265
266 def _debugbundle2(ui, gen, all=None, **opts):
266 def _debugbundle2(ui, gen, all=None, **opts):
267 """lists the contents of a bundle2"""
267 """lists the contents of a bundle2"""
268 if not isinstance(gen, bundle2.unbundle20):
268 if not isinstance(gen, bundle2.unbundle20):
269 raise error.Abort(_('not a bundle2 file'))
269 raise error.Abort(_('not a bundle2 file'))
270 ui.write(('Stream params: %s\n' % repr(gen.params)))
270 ui.write(('Stream params: %s\n' % repr(gen.params)))
271 for part in gen.iterparts():
271 for part in gen.iterparts():
272 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
272 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
273 if part.type == 'changegroup':
273 if part.type == 'changegroup':
274 version = part.params.get('version', '01')
274 version = part.params.get('version', '01')
275 cg = changegroup.getunbundler(version, part, 'UN')
275 cg = changegroup.getunbundler(version, part, 'UN')
276 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
276 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
277
277
278 @command('debugcreatestreamclonebundle', [], 'FILE')
278 @command('debugcreatestreamclonebundle', [], 'FILE')
279 def debugcreatestreamclonebundle(ui, repo, fname):
279 def debugcreatestreamclonebundle(ui, repo, fname):
280 """create a stream clone bundle file
280 """create a stream clone bundle file
281
281
282 Stream bundles are special bundles that are essentially archives of
282 Stream bundles are special bundles that are essentially archives of
283 revlog files. They are commonly used for cloning very quickly.
283 revlog files. They are commonly used for cloning very quickly.
284 """
284 """
285 requirements, gen = streamclone.generatebundlev1(repo)
285 requirements, gen = streamclone.generatebundlev1(repo)
286 changegroup.writechunks(ui, gen, fname)
286 changegroup.writechunks(ui, gen, fname)
287
287
288 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
288 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
289
289
290 @command('debugapplystreamclonebundle', [], 'FILE')
290 @command('debugapplystreamclonebundle', [], 'FILE')
291 def debugapplystreamclonebundle(ui, repo, fname):
291 def debugapplystreamclonebundle(ui, repo, fname):
292 """apply a stream clone bundle file"""
292 """apply a stream clone bundle file"""
293 f = hg.openpath(ui, fname)
293 f = hg.openpath(ui, fname)
294 gen = exchange.readbundle(ui, f, fname)
294 gen = exchange.readbundle(ui, f, fname)
295 gen.apply(repo)
295 gen.apply(repo)
296
296
297 @command('debugcheckstate', [], '')
297 @command('debugcheckstate', [], '')
298 def debugcheckstate(ui, repo):
298 def debugcheckstate(ui, repo):
299 """validate the correctness of the current dirstate"""
299 """validate the correctness of the current dirstate"""
300 parent1, parent2 = repo.dirstate.parents()
300 parent1, parent2 = repo.dirstate.parents()
301 m1 = repo[parent1].manifest()
301 m1 = repo[parent1].manifest()
302 m2 = repo[parent2].manifest()
302 m2 = repo[parent2].manifest()
303 errors = 0
303 errors = 0
304 for f in repo.dirstate:
304 for f in repo.dirstate:
305 state = repo.dirstate[f]
305 state = repo.dirstate[f]
306 if state in "nr" and f not in m1:
306 if state in "nr" and f not in m1:
307 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
307 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
308 errors += 1
308 errors += 1
309 if state in "a" and f in m1:
309 if state in "a" and f in m1:
310 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
310 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
311 errors += 1
311 errors += 1
312 if state in "m" and f not in m1 and f not in m2:
312 if state in "m" and f not in m1 and f not in m2:
313 ui.warn(_("%s in state %s, but not in either manifest\n") %
313 ui.warn(_("%s in state %s, but not in either manifest\n") %
314 (f, state))
314 (f, state))
315 errors += 1
315 errors += 1
316 for f in m1:
316 for f in m1:
317 state = repo.dirstate[f]
317 state = repo.dirstate[f]
318 if state not in "nrm":
318 if state not in "nrm":
319 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
319 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
320 errors += 1
320 errors += 1
321 if errors:
321 if errors:
322 error = _(".hg/dirstate inconsistent with current parent's manifest")
322 error = _(".hg/dirstate inconsistent with current parent's manifest")
323 raise error.Abort(error)
323 raise error.Abort(error)
324
325 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
326 def debugcommands(ui, cmd='', *args):
327 """list all available commands and options"""
328 for cmd, vals in sorted(commands.table.iteritems()):
329 cmd = cmd.split('|')[0].strip('^')
330 opts = ', '.join([i[1] for i in vals[1]])
331 ui.write('%s: %s\n' % (cmd, opts))
General Comments 0
You need to be logged in to leave comments. Login now