##// END OF EJS Templates
debugcommands: move 'debugknown' in the new module
Pierre-Yves David -
r30919:e1fa5fe9 default
parent child Browse files
Show More
@@ -1,6457 +1,6444
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 os
12 import os
13 import re
13 import re
14 import socket
14 import socket
15 import string
15 import string
16 import time
16 import time
17
17
18 from .i18n import _
18 from .i18n import _
19 from .node import (
19 from .node import (
20 bin,
20 bin,
21 hex,
21 hex,
22 nullhex,
22 nullhex,
23 nullid,
23 nullid,
24 nullrev,
24 nullrev,
25 short,
25 short,
26 )
26 )
27 from . import (
27 from . import (
28 archival,
28 archival,
29 bookmarks,
29 bookmarks,
30 bundle2,
30 bundle2,
31 changegroup,
31 changegroup,
32 cmdutil,
32 cmdutil,
33 copies,
33 copies,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 lock as lockmod,
46 lock as lockmod,
47 merge as mergemod,
47 merge as mergemod,
48 minirst,
48 minirst,
49 obsolete,
49 obsolete,
50 patch,
50 patch,
51 phases,
51 phases,
52 pvec,
52 pvec,
53 pycompat,
53 pycompat,
54 repair,
54 repair,
55 revlog,
55 revlog,
56 revset,
56 revset,
57 scmutil,
57 scmutil,
58 server,
58 server,
59 smartset,
59 smartset,
60 sshserver,
60 sshserver,
61 streamclone,
61 streamclone,
62 templatekw,
62 templatekw,
63 templater,
63 templater,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 )
66 )
67
67
68 release = lockmod.release
68 release = lockmod.release
69
69
70 table = {}
70 table = {}
71
71
72 command = cmdutil.command(table)
72 command = cmdutil.command(table)
73
73
74 # label constants
74 # label constants
75 # until 3.5, bookmarks.current was the advertised name, not
75 # until 3.5, bookmarks.current was the advertised name, not
76 # bookmarks.active, so we must use both to avoid breaking old
76 # bookmarks.active, so we must use both to avoid breaking old
77 # custom styles
77 # custom styles
78 activebookmarklabel = 'bookmarks.active bookmarks.current'
78 activebookmarklabel = 'bookmarks.active bookmarks.current'
79
79
80 # common command options
80 # common command options
81
81
82 globalopts = [
82 globalopts = [
83 ('R', 'repository', '',
83 ('R', 'repository', '',
84 _('repository root directory or name of overlay bundle file'),
84 _('repository root directory or name of overlay bundle file'),
85 _('REPO')),
85 _('REPO')),
86 ('', 'cwd', '',
86 ('', 'cwd', '',
87 _('change working directory'), _('DIR')),
87 _('change working directory'), _('DIR')),
88 ('y', 'noninteractive', None,
88 ('y', 'noninteractive', None,
89 _('do not prompt, automatically pick the first choice for all prompts')),
89 _('do not prompt, automatically pick the first choice for all prompts')),
90 ('q', 'quiet', None, _('suppress output')),
90 ('q', 'quiet', None, _('suppress output')),
91 ('v', 'verbose', None, _('enable additional output')),
91 ('v', 'verbose', None, _('enable additional output')),
92 ('', 'config', [],
92 ('', 'config', [],
93 _('set/override config option (use \'section.name=value\')'),
93 _('set/override config option (use \'section.name=value\')'),
94 _('CONFIG')),
94 _('CONFIG')),
95 ('', 'debug', None, _('enable debugging output')),
95 ('', 'debug', None, _('enable debugging output')),
96 ('', 'debugger', None, _('start debugger')),
96 ('', 'debugger', None, _('start debugger')),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
97 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
98 _('ENCODE')),
98 _('ENCODE')),
99 ('', 'encodingmode', encoding.encodingmode,
99 ('', 'encodingmode', encoding.encodingmode,
100 _('set the charset encoding mode'), _('MODE')),
100 _('set the charset encoding mode'), _('MODE')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
101 ('', 'traceback', None, _('always print a traceback on exception')),
102 ('', 'time', None, _('time how long the command takes')),
102 ('', 'time', None, _('time how long the command takes')),
103 ('', 'profile', None, _('print command execution profile')),
103 ('', 'profile', None, _('print command execution profile')),
104 ('', 'version', None, _('output version information and exit')),
104 ('', 'version', None, _('output version information and exit')),
105 ('h', 'help', None, _('display help and exit')),
105 ('h', 'help', None, _('display help and exit')),
106 ('', 'hidden', False, _('consider hidden changesets')),
106 ('', 'hidden', False, _('consider hidden changesets')),
107 ]
107 ]
108
108
109 dryrunopts = [('n', 'dry-run', None,
109 dryrunopts = [('n', 'dry-run', None,
110 _('do not perform actions, just print output'))]
110 _('do not perform actions, just print output'))]
111
111
112 remoteopts = [
112 remoteopts = [
113 ('e', 'ssh', '',
113 ('e', 'ssh', '',
114 _('specify ssh command to use'), _('CMD')),
114 _('specify ssh command to use'), _('CMD')),
115 ('', 'remotecmd', '',
115 ('', 'remotecmd', '',
116 _('specify hg command to run on the remote side'), _('CMD')),
116 _('specify hg command to run on the remote side'), _('CMD')),
117 ('', 'insecure', None,
117 ('', 'insecure', None,
118 _('do not verify server certificate (ignoring web.cacerts config)')),
118 _('do not verify server certificate (ignoring web.cacerts config)')),
119 ]
119 ]
120
120
121 walkopts = [
121 walkopts = [
122 ('I', 'include', [],
122 ('I', 'include', [],
123 _('include names matching the given patterns'), _('PATTERN')),
123 _('include names matching the given patterns'), _('PATTERN')),
124 ('X', 'exclude', [],
124 ('X', 'exclude', [],
125 _('exclude names matching the given patterns'), _('PATTERN')),
125 _('exclude names matching the given patterns'), _('PATTERN')),
126 ]
126 ]
127
127
128 commitopts = [
128 commitopts = [
129 ('m', 'message', '',
129 ('m', 'message', '',
130 _('use text as commit message'), _('TEXT')),
130 _('use text as commit message'), _('TEXT')),
131 ('l', 'logfile', '',
131 ('l', 'logfile', '',
132 _('read commit message from file'), _('FILE')),
132 _('read commit message from file'), _('FILE')),
133 ]
133 ]
134
134
135 commitopts2 = [
135 commitopts2 = [
136 ('d', 'date', '',
136 ('d', 'date', '',
137 _('record the specified date as commit date'), _('DATE')),
137 _('record the specified date as commit date'), _('DATE')),
138 ('u', 'user', '',
138 ('u', 'user', '',
139 _('record the specified user as committer'), _('USER')),
139 _('record the specified user as committer'), _('USER')),
140 ]
140 ]
141
141
142 # hidden for now
142 # hidden for now
143 formatteropts = [
143 formatteropts = [
144 ('T', 'template', '',
144 ('T', 'template', '',
145 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
145 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
146 ]
146 ]
147
147
148 templateopts = [
148 templateopts = [
149 ('', 'style', '',
149 ('', 'style', '',
150 _('display using template map file (DEPRECATED)'), _('STYLE')),
150 _('display using template map file (DEPRECATED)'), _('STYLE')),
151 ('T', 'template', '',
151 ('T', 'template', '',
152 _('display with template'), _('TEMPLATE')),
152 _('display with template'), _('TEMPLATE')),
153 ]
153 ]
154
154
155 logopts = [
155 logopts = [
156 ('p', 'patch', None, _('show patch')),
156 ('p', 'patch', None, _('show patch')),
157 ('g', 'git', None, _('use git extended diff format')),
157 ('g', 'git', None, _('use git extended diff format')),
158 ('l', 'limit', '',
158 ('l', 'limit', '',
159 _('limit number of changes displayed'), _('NUM')),
159 _('limit number of changes displayed'), _('NUM')),
160 ('M', 'no-merges', None, _('do not show merges')),
160 ('M', 'no-merges', None, _('do not show merges')),
161 ('', 'stat', None, _('output diffstat-style summary of changes')),
161 ('', 'stat', None, _('output diffstat-style summary of changes')),
162 ('G', 'graph', None, _("show the revision DAG")),
162 ('G', 'graph', None, _("show the revision DAG")),
163 ] + templateopts
163 ] + templateopts
164
164
165 diffopts = [
165 diffopts = [
166 ('a', 'text', None, _('treat all files as text')),
166 ('a', 'text', None, _('treat all files as text')),
167 ('g', 'git', None, _('use git extended diff format')),
167 ('g', 'git', None, _('use git extended diff format')),
168 ('', 'nodates', None, _('omit dates from diff headers'))
168 ('', 'nodates', None, _('omit dates from diff headers'))
169 ]
169 ]
170
170
171 diffwsopts = [
171 diffwsopts = [
172 ('w', 'ignore-all-space', None,
172 ('w', 'ignore-all-space', None,
173 _('ignore white space when comparing lines')),
173 _('ignore white space when comparing lines')),
174 ('b', 'ignore-space-change', None,
174 ('b', 'ignore-space-change', None,
175 _('ignore changes in the amount of white space')),
175 _('ignore changes in the amount of white space')),
176 ('B', 'ignore-blank-lines', None,
176 ('B', 'ignore-blank-lines', None,
177 _('ignore changes whose lines are all blank')),
177 _('ignore changes whose lines are all blank')),
178 ]
178 ]
179
179
180 diffopts2 = [
180 diffopts2 = [
181 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
181 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
182 ('p', 'show-function', None, _('show which function each change is in')),
182 ('p', 'show-function', None, _('show which function each change is in')),
183 ('', 'reverse', None, _('produce a diff that undoes the changes')),
183 ('', 'reverse', None, _('produce a diff that undoes the changes')),
184 ] + diffwsopts + [
184 ] + diffwsopts + [
185 ('U', 'unified', '',
185 ('U', 'unified', '',
186 _('number of lines of context to show'), _('NUM')),
186 _('number of lines of context to show'), _('NUM')),
187 ('', 'stat', None, _('output diffstat-style summary of changes')),
187 ('', 'stat', None, _('output diffstat-style summary of changes')),
188 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
188 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
189 ]
189 ]
190
190
191 mergetoolopts = [
191 mergetoolopts = [
192 ('t', 'tool', '', _('specify merge tool')),
192 ('t', 'tool', '', _('specify merge tool')),
193 ]
193 ]
194
194
195 similarityopts = [
195 similarityopts = [
196 ('s', 'similarity', '',
196 ('s', 'similarity', '',
197 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
197 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
198 ]
198 ]
199
199
200 subrepoopts = [
200 subrepoopts = [
201 ('S', 'subrepos', None,
201 ('S', 'subrepos', None,
202 _('recurse into subrepositories'))
202 _('recurse into subrepositories'))
203 ]
203 ]
204
204
205 debugrevlogopts = [
205 debugrevlogopts = [
206 ('c', 'changelog', False, _('open changelog')),
206 ('c', 'changelog', False, _('open changelog')),
207 ('m', 'manifest', False, _('open manifest')),
207 ('m', 'manifest', False, _('open manifest')),
208 ('', 'dir', '', _('open directory manifest')),
208 ('', 'dir', '', _('open directory manifest')),
209 ]
209 ]
210
210
211 # Commands start here, listed alphabetically
211 # Commands start here, listed alphabetically
212
212
213 @command('^add',
213 @command('^add',
214 walkopts + subrepoopts + dryrunopts,
214 walkopts + subrepoopts + dryrunopts,
215 _('[OPTION]... [FILE]...'),
215 _('[OPTION]... [FILE]...'),
216 inferrepo=True)
216 inferrepo=True)
217 def add(ui, repo, *pats, **opts):
217 def add(ui, repo, *pats, **opts):
218 """add the specified files on the next commit
218 """add the specified files on the next commit
219
219
220 Schedule files to be version controlled and added to the
220 Schedule files to be version controlled and added to the
221 repository.
221 repository.
222
222
223 The files will be added to the repository at the next commit. To
223 The files will be added to the repository at the next commit. To
224 undo an add before that, see :hg:`forget`.
224 undo an add before that, see :hg:`forget`.
225
225
226 If no names are given, add all files to the repository (except
226 If no names are given, add all files to the repository (except
227 files matching ``.hgignore``).
227 files matching ``.hgignore``).
228
228
229 .. container:: verbose
229 .. container:: verbose
230
230
231 Examples:
231 Examples:
232
232
233 - New (unknown) files are added
233 - New (unknown) files are added
234 automatically by :hg:`add`::
234 automatically by :hg:`add`::
235
235
236 $ ls
236 $ ls
237 foo.c
237 foo.c
238 $ hg status
238 $ hg status
239 ? foo.c
239 ? foo.c
240 $ hg add
240 $ hg add
241 adding foo.c
241 adding foo.c
242 $ hg status
242 $ hg status
243 A foo.c
243 A foo.c
244
244
245 - Specific files to be added can be specified::
245 - Specific files to be added can be specified::
246
246
247 $ ls
247 $ ls
248 bar.c foo.c
248 bar.c foo.c
249 $ hg status
249 $ hg status
250 ? bar.c
250 ? bar.c
251 ? foo.c
251 ? foo.c
252 $ hg add bar.c
252 $ hg add bar.c
253 $ hg status
253 $ hg status
254 A bar.c
254 A bar.c
255 ? foo.c
255 ? foo.c
256
256
257 Returns 0 if all files are successfully added.
257 Returns 0 if all files are successfully added.
258 """
258 """
259
259
260 m = scmutil.match(repo[None], pats, opts)
260 m = scmutil.match(repo[None], pats, opts)
261 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
261 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
262 return rejected and 1 or 0
262 return rejected and 1 or 0
263
263
264 @command('addremove',
264 @command('addremove',
265 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
266 _('[OPTION]... [FILE]...'),
266 _('[OPTION]... [FILE]...'),
267 inferrepo=True)
267 inferrepo=True)
268 def addremove(ui, repo, *pats, **opts):
268 def addremove(ui, repo, *pats, **opts):
269 """add all new files, delete all missing files
269 """add all new files, delete all missing files
270
270
271 Add all new files and remove all missing files from the
271 Add all new files and remove all missing files from the
272 repository.
272 repository.
273
273
274 Unless names are given, new files are ignored if they match any of
274 Unless names are given, new files are ignored if they match any of
275 the patterns in ``.hgignore``. As with add, these changes take
275 the patterns in ``.hgignore``. As with add, these changes take
276 effect at the next commit.
276 effect at the next commit.
277
277
278 Use the -s/--similarity option to detect renamed files. This
278 Use the -s/--similarity option to detect renamed files. This
279 option takes a percentage between 0 (disabled) and 100 (files must
279 option takes a percentage between 0 (disabled) and 100 (files must
280 be identical) as its parameter. With a parameter greater than 0,
280 be identical) as its parameter. With a parameter greater than 0,
281 this compares every removed file with every added file and records
281 this compares every removed file with every added file and records
282 those similar enough as renames. Detecting renamed files this way
282 those similar enough as renames. Detecting renamed files this way
283 can be expensive. After using this option, :hg:`status -C` can be
283 can be expensive. After using this option, :hg:`status -C` can be
284 used to check which files were identified as moved or renamed. If
284 used to check which files were identified as moved or renamed. If
285 not specified, -s/--similarity defaults to 100 and only renames of
285 not specified, -s/--similarity defaults to 100 and only renames of
286 identical files are detected.
286 identical files are detected.
287
287
288 .. container:: verbose
288 .. container:: verbose
289
289
290 Examples:
290 Examples:
291
291
292 - A number of files (bar.c and foo.c) are new,
292 - A number of files (bar.c and foo.c) are new,
293 while foobar.c has been removed (without using :hg:`remove`)
293 while foobar.c has been removed (without using :hg:`remove`)
294 from the repository::
294 from the repository::
295
295
296 $ ls
296 $ ls
297 bar.c foo.c
297 bar.c foo.c
298 $ hg status
298 $ hg status
299 ! foobar.c
299 ! foobar.c
300 ? bar.c
300 ? bar.c
301 ? foo.c
301 ? foo.c
302 $ hg addremove
302 $ hg addremove
303 adding bar.c
303 adding bar.c
304 adding foo.c
304 adding foo.c
305 removing foobar.c
305 removing foobar.c
306 $ hg status
306 $ hg status
307 A bar.c
307 A bar.c
308 A foo.c
308 A foo.c
309 R foobar.c
309 R foobar.c
310
310
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 Afterwards, it was edited slightly::
312 Afterwards, it was edited slightly::
313
313
314 $ ls
314 $ ls
315 foo.c
315 foo.c
316 $ hg status
316 $ hg status
317 ! foobar.c
317 ! foobar.c
318 ? foo.c
318 ? foo.c
319 $ hg addremove --similarity 90
319 $ hg addremove --similarity 90
320 removing foobar.c
320 removing foobar.c
321 adding foo.c
321 adding foo.c
322 recording removal of foobar.c as rename to foo.c (94% similar)
322 recording removal of foobar.c as rename to foo.c (94% similar)
323 $ hg status -C
323 $ hg status -C
324 A foo.c
324 A foo.c
325 foobar.c
325 foobar.c
326 R foobar.c
326 R foobar.c
327
327
328 Returns 0 if all files are successfully added.
328 Returns 0 if all files are successfully added.
329 """
329 """
330 try:
330 try:
331 sim = float(opts.get('similarity') or 100)
331 sim = float(opts.get('similarity') or 100)
332 except ValueError:
332 except ValueError:
333 raise error.Abort(_('similarity must be a number'))
333 raise error.Abort(_('similarity must be a number'))
334 if sim < 0 or sim > 100:
334 if sim < 0 or sim > 100:
335 raise error.Abort(_('similarity must be between 0 and 100'))
335 raise error.Abort(_('similarity must be between 0 and 100'))
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
338
338
339 @command('^annotate|blame',
339 @command('^annotate|blame',
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
341 ('', 'follow', None,
341 ('', 'follow', None,
342 _('follow copies/renames and list the filename (DEPRECATED)')),
342 _('follow copies/renames and list the filename (DEPRECATED)')),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
344 ('a', 'text', None, _('treat all files as text')),
344 ('a', 'text', None, _('treat all files as text')),
345 ('u', 'user', None, _('list the author (long with -v)')),
345 ('u', 'user', None, _('list the author (long with -v)')),
346 ('f', 'file', None, _('list the filename')),
346 ('f', 'file', None, _('list the filename')),
347 ('d', 'date', None, _('list the date (short with -q)')),
347 ('d', 'date', None, _('list the date (short with -q)')),
348 ('n', 'number', None, _('list the revision number (default)')),
348 ('n', 'number', None, _('list the revision number (default)')),
349 ('c', 'changeset', None, _('list the changeset')),
349 ('c', 'changeset', None, _('list the changeset')),
350 ('l', 'line-number', None, _('show line number at the first appearance'))
350 ('l', 'line-number', None, _('show line number at the first appearance'))
351 ] + diffwsopts + walkopts + formatteropts,
351 ] + diffwsopts + walkopts + formatteropts,
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
353 inferrepo=True)
353 inferrepo=True)
354 def annotate(ui, repo, *pats, **opts):
354 def annotate(ui, repo, *pats, **opts):
355 """show changeset information by line for each file
355 """show changeset information by line for each file
356
356
357 List changes in files, showing the revision id responsible for
357 List changes in files, showing the revision id responsible for
358 each line.
358 each line.
359
359
360 This command is useful for discovering when a change was made and
360 This command is useful for discovering when a change was made and
361 by whom.
361 by whom.
362
362
363 If you include --file, --user, or --date, the revision number is
363 If you include --file, --user, or --date, the revision number is
364 suppressed unless you also include --number.
364 suppressed unless you also include --number.
365
365
366 Without the -a/--text option, annotate will avoid processing files
366 Without the -a/--text option, annotate will avoid processing files
367 it detects as binary. With -a, annotate will annotate the file
367 it detects as binary. With -a, annotate will annotate the file
368 anyway, although the results will probably be neither useful
368 anyway, although the results will probably be neither useful
369 nor desirable.
369 nor desirable.
370
370
371 Returns 0 on success.
371 Returns 0 on success.
372 """
372 """
373 if not pats:
373 if not pats:
374 raise error.Abort(_('at least one filename or pattern is required'))
374 raise error.Abort(_('at least one filename or pattern is required'))
375
375
376 if opts.get('follow'):
376 if opts.get('follow'):
377 # --follow is deprecated and now just an alias for -f/--file
377 # --follow is deprecated and now just an alias for -f/--file
378 # to mimic the behavior of Mercurial before version 1.5
378 # to mimic the behavior of Mercurial before version 1.5
379 opts['file'] = True
379 opts['file'] = True
380
380
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
382
382
383 fm = ui.formatter('annotate', opts)
383 fm = ui.formatter('annotate', opts)
384 if ui.quiet:
384 if ui.quiet:
385 datefunc = util.shortdate
385 datefunc = util.shortdate
386 else:
386 else:
387 datefunc = util.datestr
387 datefunc = util.datestr
388 if ctx.rev() is None:
388 if ctx.rev() is None:
389 def hexfn(node):
389 def hexfn(node):
390 if node is None:
390 if node is None:
391 return None
391 return None
392 else:
392 else:
393 return fm.hexfunc(node)
393 return fm.hexfunc(node)
394 if opts.get('changeset'):
394 if opts.get('changeset'):
395 # omit "+" suffix which is appended to node hex
395 # omit "+" suffix which is appended to node hex
396 def formatrev(rev):
396 def formatrev(rev):
397 if rev is None:
397 if rev is None:
398 return '%d' % ctx.p1().rev()
398 return '%d' % ctx.p1().rev()
399 else:
399 else:
400 return '%d' % rev
400 return '%d' % rev
401 else:
401 else:
402 def formatrev(rev):
402 def formatrev(rev):
403 if rev is None:
403 if rev is None:
404 return '%d+' % ctx.p1().rev()
404 return '%d+' % ctx.p1().rev()
405 else:
405 else:
406 return '%d ' % rev
406 return '%d ' % rev
407 def formathex(hex):
407 def formathex(hex):
408 if hex is None:
408 if hex is None:
409 return '%s+' % fm.hexfunc(ctx.p1().node())
409 return '%s+' % fm.hexfunc(ctx.p1().node())
410 else:
410 else:
411 return '%s ' % hex
411 return '%s ' % hex
412 else:
412 else:
413 hexfn = fm.hexfunc
413 hexfn = fm.hexfunc
414 formatrev = formathex = str
414 formatrev = formathex = str
415
415
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
420 ('file', ' ', lambda x: x[0].path(), str),
420 ('file', ' ', lambda x: x[0].path(), str),
421 ('line_number', ':', lambda x: x[1], str),
421 ('line_number', ':', lambda x: x[1], str),
422 ]
422 ]
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
424
424
425 if (not opts.get('user') and not opts.get('changeset')
425 if (not opts.get('user') and not opts.get('changeset')
426 and not opts.get('date') and not opts.get('file')):
426 and not opts.get('date') and not opts.get('file')):
427 opts['number'] = True
427 opts['number'] = True
428
428
429 linenumber = opts.get('line_number') is not None
429 linenumber = opts.get('line_number') is not None
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
432
432
433 if fm.isplain():
433 if fm.isplain():
434 def makefunc(get, fmt):
434 def makefunc(get, fmt):
435 return lambda x: fmt(get(x))
435 return lambda x: fmt(get(x))
436 else:
436 else:
437 def makefunc(get, fmt):
437 def makefunc(get, fmt):
438 return get
438 return get
439 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
439 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
440 if opts.get(op)]
440 if opts.get(op)]
441 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
441 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
442 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
442 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
443 if opts.get(op))
443 if opts.get(op))
444
444
445 def bad(x, y):
445 def bad(x, y):
446 raise error.Abort("%s: %s" % (x, y))
446 raise error.Abort("%s: %s" % (x, y))
447
447
448 m = scmutil.match(ctx, pats, opts, badfn=bad)
448 m = scmutil.match(ctx, pats, opts, badfn=bad)
449
449
450 follow = not opts.get('no_follow')
450 follow = not opts.get('no_follow')
451 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
451 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
452 whitespace=True)
452 whitespace=True)
453 for abs in ctx.walk(m):
453 for abs in ctx.walk(m):
454 fctx = ctx[abs]
454 fctx = ctx[abs]
455 if not opts.get('text') and util.binary(fctx.data()):
455 if not opts.get('text') and util.binary(fctx.data()):
456 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
456 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
457 continue
457 continue
458
458
459 lines = fctx.annotate(follow=follow, linenumber=linenumber,
459 lines = fctx.annotate(follow=follow, linenumber=linenumber,
460 diffopts=diffopts)
460 diffopts=diffopts)
461 if not lines:
461 if not lines:
462 continue
462 continue
463 formats = []
463 formats = []
464 pieces = []
464 pieces = []
465
465
466 for f, sep in funcmap:
466 for f, sep in funcmap:
467 l = [f(n) for n, dummy in lines]
467 l = [f(n) for n, dummy in lines]
468 if fm.isplain():
468 if fm.isplain():
469 sizes = [encoding.colwidth(x) for x in l]
469 sizes = [encoding.colwidth(x) for x in l]
470 ml = max(sizes)
470 ml = max(sizes)
471 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
471 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
472 else:
472 else:
473 formats.append(['%s' for x in l])
473 formats.append(['%s' for x in l])
474 pieces.append(l)
474 pieces.append(l)
475
475
476 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
476 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
477 fm.startitem()
477 fm.startitem()
478 fm.write(fields, "".join(f), *p)
478 fm.write(fields, "".join(f), *p)
479 fm.write('line', ": %s", l[1])
479 fm.write('line', ": %s", l[1])
480
480
481 if not lines[-1][1].endswith('\n'):
481 if not lines[-1][1].endswith('\n'):
482 fm.plain('\n')
482 fm.plain('\n')
483
483
484 fm.end()
484 fm.end()
485
485
486 @command('archive',
486 @command('archive',
487 [('', 'no-decode', None, _('do not pass files through decoders')),
487 [('', 'no-decode', None, _('do not pass files through decoders')),
488 ('p', 'prefix', '', _('directory prefix for files in archive'),
488 ('p', 'prefix', '', _('directory prefix for files in archive'),
489 _('PREFIX')),
489 _('PREFIX')),
490 ('r', 'rev', '', _('revision to distribute'), _('REV')),
490 ('r', 'rev', '', _('revision to distribute'), _('REV')),
491 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
491 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
492 ] + subrepoopts + walkopts,
492 ] + subrepoopts + walkopts,
493 _('[OPTION]... DEST'))
493 _('[OPTION]... DEST'))
494 def archive(ui, repo, dest, **opts):
494 def archive(ui, repo, dest, **opts):
495 '''create an unversioned archive of a repository revision
495 '''create an unversioned archive of a repository revision
496
496
497 By default, the revision used is the parent of the working
497 By default, the revision used is the parent of the working
498 directory; use -r/--rev to specify a different revision.
498 directory; use -r/--rev to specify a different revision.
499
499
500 The archive type is automatically detected based on file
500 The archive type is automatically detected based on file
501 extension (to override, use -t/--type).
501 extension (to override, use -t/--type).
502
502
503 .. container:: verbose
503 .. container:: verbose
504
504
505 Examples:
505 Examples:
506
506
507 - create a zip file containing the 1.0 release::
507 - create a zip file containing the 1.0 release::
508
508
509 hg archive -r 1.0 project-1.0.zip
509 hg archive -r 1.0 project-1.0.zip
510
510
511 - create a tarball excluding .hg files::
511 - create a tarball excluding .hg files::
512
512
513 hg archive project.tar.gz -X ".hg*"
513 hg archive project.tar.gz -X ".hg*"
514
514
515 Valid types are:
515 Valid types are:
516
516
517 :``files``: a directory full of files (default)
517 :``files``: a directory full of files (default)
518 :``tar``: tar archive, uncompressed
518 :``tar``: tar archive, uncompressed
519 :``tbz2``: tar archive, compressed using bzip2
519 :``tbz2``: tar archive, compressed using bzip2
520 :``tgz``: tar archive, compressed using gzip
520 :``tgz``: tar archive, compressed using gzip
521 :``uzip``: zip archive, uncompressed
521 :``uzip``: zip archive, uncompressed
522 :``zip``: zip archive, compressed using deflate
522 :``zip``: zip archive, compressed using deflate
523
523
524 The exact name of the destination archive or directory is given
524 The exact name of the destination archive or directory is given
525 using a format string; see :hg:`help export` for details.
525 using a format string; see :hg:`help export` for details.
526
526
527 Each member added to an archive file has a directory prefix
527 Each member added to an archive file has a directory prefix
528 prepended. Use -p/--prefix to specify a format string for the
528 prepended. Use -p/--prefix to specify a format string for the
529 prefix. The default is the basename of the archive, with suffixes
529 prefix. The default is the basename of the archive, with suffixes
530 removed.
530 removed.
531
531
532 Returns 0 on success.
532 Returns 0 on success.
533 '''
533 '''
534
534
535 ctx = scmutil.revsingle(repo, opts.get('rev'))
535 ctx = scmutil.revsingle(repo, opts.get('rev'))
536 if not ctx:
536 if not ctx:
537 raise error.Abort(_('no working directory: please specify a revision'))
537 raise error.Abort(_('no working directory: please specify a revision'))
538 node = ctx.node()
538 node = ctx.node()
539 dest = cmdutil.makefilename(repo, dest, node)
539 dest = cmdutil.makefilename(repo, dest, node)
540 if os.path.realpath(dest) == repo.root:
540 if os.path.realpath(dest) == repo.root:
541 raise error.Abort(_('repository root cannot be destination'))
541 raise error.Abort(_('repository root cannot be destination'))
542
542
543 kind = opts.get('type') or archival.guesskind(dest) or 'files'
543 kind = opts.get('type') or archival.guesskind(dest) or 'files'
544 prefix = opts.get('prefix')
544 prefix = opts.get('prefix')
545
545
546 if dest == '-':
546 if dest == '-':
547 if kind == 'files':
547 if kind == 'files':
548 raise error.Abort(_('cannot archive plain files to stdout'))
548 raise error.Abort(_('cannot archive plain files to stdout'))
549 dest = cmdutil.makefileobj(repo, dest)
549 dest = cmdutil.makefileobj(repo, dest)
550 if not prefix:
550 if not prefix:
551 prefix = os.path.basename(repo.root) + '-%h'
551 prefix = os.path.basename(repo.root) + '-%h'
552
552
553 prefix = cmdutil.makefilename(repo, prefix, node)
553 prefix = cmdutil.makefilename(repo, prefix, node)
554 matchfn = scmutil.match(ctx, [], opts)
554 matchfn = scmutil.match(ctx, [], opts)
555 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
555 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
556 matchfn, prefix, subrepos=opts.get('subrepos'))
556 matchfn, prefix, subrepos=opts.get('subrepos'))
557
557
558 @command('backout',
558 @command('backout',
559 [('', 'merge', None, _('merge with old dirstate parent after backout')),
559 [('', 'merge', None, _('merge with old dirstate parent after backout')),
560 ('', 'commit', None,
560 ('', 'commit', None,
561 _('commit if no conflicts were encountered (DEPRECATED)')),
561 _('commit if no conflicts were encountered (DEPRECATED)')),
562 ('', 'no-commit', None, _('do not commit')),
562 ('', 'no-commit', None, _('do not commit')),
563 ('', 'parent', '',
563 ('', 'parent', '',
564 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
564 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
565 ('r', 'rev', '', _('revision to backout'), _('REV')),
565 ('r', 'rev', '', _('revision to backout'), _('REV')),
566 ('e', 'edit', False, _('invoke editor on commit messages')),
566 ('e', 'edit', False, _('invoke editor on commit messages')),
567 ] + mergetoolopts + walkopts + commitopts + commitopts2,
567 ] + mergetoolopts + walkopts + commitopts + commitopts2,
568 _('[OPTION]... [-r] REV'))
568 _('[OPTION]... [-r] REV'))
569 def backout(ui, repo, node=None, rev=None, **opts):
569 def backout(ui, repo, node=None, rev=None, **opts):
570 '''reverse effect of earlier changeset
570 '''reverse effect of earlier changeset
571
571
572 Prepare a new changeset with the effect of REV undone in the
572 Prepare a new changeset with the effect of REV undone in the
573 current working directory. If no conflicts were encountered,
573 current working directory. If no conflicts were encountered,
574 it will be committed immediately.
574 it will be committed immediately.
575
575
576 If REV is the parent of the working directory, then this new changeset
576 If REV is the parent of the working directory, then this new changeset
577 is committed automatically (unless --no-commit is specified).
577 is committed automatically (unless --no-commit is specified).
578
578
579 .. note::
579 .. note::
580
580
581 :hg:`backout` cannot be used to fix either an unwanted or
581 :hg:`backout` cannot be used to fix either an unwanted or
582 incorrect merge.
582 incorrect merge.
583
583
584 .. container:: verbose
584 .. container:: verbose
585
585
586 Examples:
586 Examples:
587
587
588 - Reverse the effect of the parent of the working directory.
588 - Reverse the effect of the parent of the working directory.
589 This backout will be committed immediately::
589 This backout will be committed immediately::
590
590
591 hg backout -r .
591 hg backout -r .
592
592
593 - Reverse the effect of previous bad revision 23::
593 - Reverse the effect of previous bad revision 23::
594
594
595 hg backout -r 23
595 hg backout -r 23
596
596
597 - Reverse the effect of previous bad revision 23 and
597 - Reverse the effect of previous bad revision 23 and
598 leave changes uncommitted::
598 leave changes uncommitted::
599
599
600 hg backout -r 23 --no-commit
600 hg backout -r 23 --no-commit
601 hg commit -m "Backout revision 23"
601 hg commit -m "Backout revision 23"
602
602
603 By default, the pending changeset will have one parent,
603 By default, the pending changeset will have one parent,
604 maintaining a linear history. With --merge, the pending
604 maintaining a linear history. With --merge, the pending
605 changeset will instead have two parents: the old parent of the
605 changeset will instead have two parents: the old parent of the
606 working directory and a new child of REV that simply undoes REV.
606 working directory and a new child of REV that simply undoes REV.
607
607
608 Before version 1.7, the behavior without --merge was equivalent
608 Before version 1.7, the behavior without --merge was equivalent
609 to specifying --merge followed by :hg:`update --clean .` to
609 to specifying --merge followed by :hg:`update --clean .` to
610 cancel the merge and leave the child of REV as a head to be
610 cancel the merge and leave the child of REV as a head to be
611 merged separately.
611 merged separately.
612
612
613 See :hg:`help dates` for a list of formats valid for -d/--date.
613 See :hg:`help dates` for a list of formats valid for -d/--date.
614
614
615 See :hg:`help revert` for a way to restore files to the state
615 See :hg:`help revert` for a way to restore files to the state
616 of another revision.
616 of another revision.
617
617
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
619 files.
619 files.
620 '''
620 '''
621 wlock = lock = None
621 wlock = lock = None
622 try:
622 try:
623 wlock = repo.wlock()
623 wlock = repo.wlock()
624 lock = repo.lock()
624 lock = repo.lock()
625 return _dobackout(ui, repo, node, rev, **opts)
625 return _dobackout(ui, repo, node, rev, **opts)
626 finally:
626 finally:
627 release(lock, wlock)
627 release(lock, wlock)
628
628
629 def _dobackout(ui, repo, node=None, rev=None, **opts):
629 def _dobackout(ui, repo, node=None, rev=None, **opts):
630 if opts.get('commit') and opts.get('no_commit'):
630 if opts.get('commit') and opts.get('no_commit'):
631 raise error.Abort(_("cannot use --commit with --no-commit"))
631 raise error.Abort(_("cannot use --commit with --no-commit"))
632 if opts.get('merge') and opts.get('no_commit'):
632 if opts.get('merge') and opts.get('no_commit'):
633 raise error.Abort(_("cannot use --merge with --no-commit"))
633 raise error.Abort(_("cannot use --merge with --no-commit"))
634
634
635 if rev and node:
635 if rev and node:
636 raise error.Abort(_("please specify just one revision"))
636 raise error.Abort(_("please specify just one revision"))
637
637
638 if not rev:
638 if not rev:
639 rev = node
639 rev = node
640
640
641 if not rev:
641 if not rev:
642 raise error.Abort(_("please specify a revision to backout"))
642 raise error.Abort(_("please specify a revision to backout"))
643
643
644 date = opts.get('date')
644 date = opts.get('date')
645 if date:
645 if date:
646 opts['date'] = util.parsedate(date)
646 opts['date'] = util.parsedate(date)
647
647
648 cmdutil.checkunfinished(repo)
648 cmdutil.checkunfinished(repo)
649 cmdutil.bailifchanged(repo)
649 cmdutil.bailifchanged(repo)
650 node = scmutil.revsingle(repo, rev).node()
650 node = scmutil.revsingle(repo, rev).node()
651
651
652 op1, op2 = repo.dirstate.parents()
652 op1, op2 = repo.dirstate.parents()
653 if not repo.changelog.isancestor(node, op1):
653 if not repo.changelog.isancestor(node, op1):
654 raise error.Abort(_('cannot backout change that is not an ancestor'))
654 raise error.Abort(_('cannot backout change that is not an ancestor'))
655
655
656 p1, p2 = repo.changelog.parents(node)
656 p1, p2 = repo.changelog.parents(node)
657 if p1 == nullid:
657 if p1 == nullid:
658 raise error.Abort(_('cannot backout a change with no parents'))
658 raise error.Abort(_('cannot backout a change with no parents'))
659 if p2 != nullid:
659 if p2 != nullid:
660 if not opts.get('parent'):
660 if not opts.get('parent'):
661 raise error.Abort(_('cannot backout a merge changeset'))
661 raise error.Abort(_('cannot backout a merge changeset'))
662 p = repo.lookup(opts['parent'])
662 p = repo.lookup(opts['parent'])
663 if p not in (p1, p2):
663 if p not in (p1, p2):
664 raise error.Abort(_('%s is not a parent of %s') %
664 raise error.Abort(_('%s is not a parent of %s') %
665 (short(p), short(node)))
665 (short(p), short(node)))
666 parent = p
666 parent = p
667 else:
667 else:
668 if opts.get('parent'):
668 if opts.get('parent'):
669 raise error.Abort(_('cannot use --parent on non-merge changeset'))
669 raise error.Abort(_('cannot use --parent on non-merge changeset'))
670 parent = p1
670 parent = p1
671
671
672 # the backout should appear on the same branch
672 # the backout should appear on the same branch
673 branch = repo.dirstate.branch()
673 branch = repo.dirstate.branch()
674 bheads = repo.branchheads(branch)
674 bheads = repo.branchheads(branch)
675 rctx = scmutil.revsingle(repo, hex(parent))
675 rctx = scmutil.revsingle(repo, hex(parent))
676 if not opts.get('merge') and op1 != node:
676 if not opts.get('merge') and op1 != node:
677 dsguard = dirstateguard.dirstateguard(repo, 'backout')
677 dsguard = dirstateguard.dirstateguard(repo, 'backout')
678 try:
678 try:
679 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
679 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
680 'backout')
680 'backout')
681 stats = mergemod.update(repo, parent, True, True, node, False)
681 stats = mergemod.update(repo, parent, True, True, node, False)
682 repo.setparents(op1, op2)
682 repo.setparents(op1, op2)
683 dsguard.close()
683 dsguard.close()
684 hg._showstats(repo, stats)
684 hg._showstats(repo, stats)
685 if stats[3]:
685 if stats[3]:
686 repo.ui.status(_("use 'hg resolve' to retry unresolved "
686 repo.ui.status(_("use 'hg resolve' to retry unresolved "
687 "file merges\n"))
687 "file merges\n"))
688 return 1
688 return 1
689 finally:
689 finally:
690 ui.setconfig('ui', 'forcemerge', '', '')
690 ui.setconfig('ui', 'forcemerge', '', '')
691 lockmod.release(dsguard)
691 lockmod.release(dsguard)
692 else:
692 else:
693 hg.clean(repo, node, show_stats=False)
693 hg.clean(repo, node, show_stats=False)
694 repo.dirstate.setbranch(branch)
694 repo.dirstate.setbranch(branch)
695 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
695 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
696
696
697 if opts.get('no_commit'):
697 if opts.get('no_commit'):
698 msg = _("changeset %s backed out, "
698 msg = _("changeset %s backed out, "
699 "don't forget to commit.\n")
699 "don't forget to commit.\n")
700 ui.status(msg % short(node))
700 ui.status(msg % short(node))
701 return 0
701 return 0
702
702
703 def commitfunc(ui, repo, message, match, opts):
703 def commitfunc(ui, repo, message, match, opts):
704 editform = 'backout'
704 editform = 'backout'
705 e = cmdutil.getcommiteditor(editform=editform, **opts)
705 e = cmdutil.getcommiteditor(editform=editform, **opts)
706 if not message:
706 if not message:
707 # we don't translate commit messages
707 # we don't translate commit messages
708 message = "Backed out changeset %s" % short(node)
708 message = "Backed out changeset %s" % short(node)
709 e = cmdutil.getcommiteditor(edit=True, editform=editform)
709 e = cmdutil.getcommiteditor(edit=True, editform=editform)
710 return repo.commit(message, opts.get('user'), opts.get('date'),
710 return repo.commit(message, opts.get('user'), opts.get('date'),
711 match, editor=e)
711 match, editor=e)
712 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
712 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
713 if not newnode:
713 if not newnode:
714 ui.status(_("nothing changed\n"))
714 ui.status(_("nothing changed\n"))
715 return 1
715 return 1
716 cmdutil.commitstatus(repo, newnode, branch, bheads)
716 cmdutil.commitstatus(repo, newnode, branch, bheads)
717
717
718 def nice(node):
718 def nice(node):
719 return '%d:%s' % (repo.changelog.rev(node), short(node))
719 return '%d:%s' % (repo.changelog.rev(node), short(node))
720 ui.status(_('changeset %s backs out changeset %s\n') %
720 ui.status(_('changeset %s backs out changeset %s\n') %
721 (nice(repo.changelog.tip()), nice(node)))
721 (nice(repo.changelog.tip()), nice(node)))
722 if opts.get('merge') and op1 != node:
722 if opts.get('merge') and op1 != node:
723 hg.clean(repo, op1, show_stats=False)
723 hg.clean(repo, op1, show_stats=False)
724 ui.status(_('merging with changeset %s\n')
724 ui.status(_('merging with changeset %s\n')
725 % nice(repo.changelog.tip()))
725 % nice(repo.changelog.tip()))
726 try:
726 try:
727 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
727 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
728 'backout')
728 'backout')
729 return hg.merge(repo, hex(repo.changelog.tip()))
729 return hg.merge(repo, hex(repo.changelog.tip()))
730 finally:
730 finally:
731 ui.setconfig('ui', 'forcemerge', '', '')
731 ui.setconfig('ui', 'forcemerge', '', '')
732 return 0
732 return 0
733
733
734 @command('bisect',
734 @command('bisect',
735 [('r', 'reset', False, _('reset bisect state')),
735 [('r', 'reset', False, _('reset bisect state')),
736 ('g', 'good', False, _('mark changeset good')),
736 ('g', 'good', False, _('mark changeset good')),
737 ('b', 'bad', False, _('mark changeset bad')),
737 ('b', 'bad', False, _('mark changeset bad')),
738 ('s', 'skip', False, _('skip testing changeset')),
738 ('s', 'skip', False, _('skip testing changeset')),
739 ('e', 'extend', False, _('extend the bisect range')),
739 ('e', 'extend', False, _('extend the bisect range')),
740 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
740 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
741 ('U', 'noupdate', False, _('do not update to target'))],
741 ('U', 'noupdate', False, _('do not update to target'))],
742 _("[-gbsr] [-U] [-c CMD] [REV]"))
742 _("[-gbsr] [-U] [-c CMD] [REV]"))
743 def bisect(ui, repo, rev=None, extra=None, command=None,
743 def bisect(ui, repo, rev=None, extra=None, command=None,
744 reset=None, good=None, bad=None, skip=None, extend=None,
744 reset=None, good=None, bad=None, skip=None, extend=None,
745 noupdate=None):
745 noupdate=None):
746 """subdivision search of changesets
746 """subdivision search of changesets
747
747
748 This command helps to find changesets which introduce problems. To
748 This command helps to find changesets which introduce problems. To
749 use, mark the earliest changeset you know exhibits the problem as
749 use, mark the earliest changeset you know exhibits the problem as
750 bad, then mark the latest changeset which is free from the problem
750 bad, then mark the latest changeset which is free from the problem
751 as good. Bisect will update your working directory to a revision
751 as good. Bisect will update your working directory to a revision
752 for testing (unless the -U/--noupdate option is specified). Once
752 for testing (unless the -U/--noupdate option is specified). Once
753 you have performed tests, mark the working directory as good or
753 you have performed tests, mark the working directory as good or
754 bad, and bisect will either update to another candidate changeset
754 bad, and bisect will either update to another candidate changeset
755 or announce that it has found the bad revision.
755 or announce that it has found the bad revision.
756
756
757 As a shortcut, you can also use the revision argument to mark a
757 As a shortcut, you can also use the revision argument to mark a
758 revision as good or bad without checking it out first.
758 revision as good or bad without checking it out first.
759
759
760 If you supply a command, it will be used for automatic bisection.
760 If you supply a command, it will be used for automatic bisection.
761 The environment variable HG_NODE will contain the ID of the
761 The environment variable HG_NODE will contain the ID of the
762 changeset being tested. The exit status of the command will be
762 changeset being tested. The exit status of the command will be
763 used to mark revisions as good or bad: status 0 means good, 125
763 used to mark revisions as good or bad: status 0 means good, 125
764 means to skip the revision, 127 (command not found) will abort the
764 means to skip the revision, 127 (command not found) will abort the
765 bisection, and any other non-zero exit status means the revision
765 bisection, and any other non-zero exit status means the revision
766 is bad.
766 is bad.
767
767
768 .. container:: verbose
768 .. container:: verbose
769
769
770 Some examples:
770 Some examples:
771
771
772 - start a bisection with known bad revision 34, and good revision 12::
772 - start a bisection with known bad revision 34, and good revision 12::
773
773
774 hg bisect --bad 34
774 hg bisect --bad 34
775 hg bisect --good 12
775 hg bisect --good 12
776
776
777 - advance the current bisection by marking current revision as good or
777 - advance the current bisection by marking current revision as good or
778 bad::
778 bad::
779
779
780 hg bisect --good
780 hg bisect --good
781 hg bisect --bad
781 hg bisect --bad
782
782
783 - mark the current revision, or a known revision, to be skipped (e.g. if
783 - mark the current revision, or a known revision, to be skipped (e.g. if
784 that revision is not usable because of another issue)::
784 that revision is not usable because of another issue)::
785
785
786 hg bisect --skip
786 hg bisect --skip
787 hg bisect --skip 23
787 hg bisect --skip 23
788
788
789 - skip all revisions that do not touch directories ``foo`` or ``bar``::
789 - skip all revisions that do not touch directories ``foo`` or ``bar``::
790
790
791 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
791 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
792
792
793 - forget the current bisection::
793 - forget the current bisection::
794
794
795 hg bisect --reset
795 hg bisect --reset
796
796
797 - use 'make && make tests' to automatically find the first broken
797 - use 'make && make tests' to automatically find the first broken
798 revision::
798 revision::
799
799
800 hg bisect --reset
800 hg bisect --reset
801 hg bisect --bad 34
801 hg bisect --bad 34
802 hg bisect --good 12
802 hg bisect --good 12
803 hg bisect --command "make && make tests"
803 hg bisect --command "make && make tests"
804
804
805 - see all changesets whose states are already known in the current
805 - see all changesets whose states are already known in the current
806 bisection::
806 bisection::
807
807
808 hg log -r "bisect(pruned)"
808 hg log -r "bisect(pruned)"
809
809
810 - see the changeset currently being bisected (especially useful
810 - see the changeset currently being bisected (especially useful
811 if running with -U/--noupdate)::
811 if running with -U/--noupdate)::
812
812
813 hg log -r "bisect(current)"
813 hg log -r "bisect(current)"
814
814
815 - see all changesets that took part in the current bisection::
815 - see all changesets that took part in the current bisection::
816
816
817 hg log -r "bisect(range)"
817 hg log -r "bisect(range)"
818
818
819 - you can even get a nice graph::
819 - you can even get a nice graph::
820
820
821 hg log --graph -r "bisect(range)"
821 hg log --graph -r "bisect(range)"
822
822
823 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
823 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
824
824
825 Returns 0 on success.
825 Returns 0 on success.
826 """
826 """
827 # backward compatibility
827 # backward compatibility
828 if rev in "good bad reset init".split():
828 if rev in "good bad reset init".split():
829 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
829 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
830 cmd, rev, extra = rev, extra, None
830 cmd, rev, extra = rev, extra, None
831 if cmd == "good":
831 if cmd == "good":
832 good = True
832 good = True
833 elif cmd == "bad":
833 elif cmd == "bad":
834 bad = True
834 bad = True
835 else:
835 else:
836 reset = True
836 reset = True
837 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
837 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
838 raise error.Abort(_('incompatible arguments'))
838 raise error.Abort(_('incompatible arguments'))
839
839
840 cmdutil.checkunfinished(repo)
840 cmdutil.checkunfinished(repo)
841
841
842 if reset:
842 if reset:
843 hbisect.resetstate(repo)
843 hbisect.resetstate(repo)
844 return
844 return
845
845
846 state = hbisect.load_state(repo)
846 state = hbisect.load_state(repo)
847
847
848 # update state
848 # update state
849 if good or bad or skip:
849 if good or bad or skip:
850 if rev:
850 if rev:
851 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
851 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
852 else:
852 else:
853 nodes = [repo.lookup('.')]
853 nodes = [repo.lookup('.')]
854 if good:
854 if good:
855 state['good'] += nodes
855 state['good'] += nodes
856 elif bad:
856 elif bad:
857 state['bad'] += nodes
857 state['bad'] += nodes
858 elif skip:
858 elif skip:
859 state['skip'] += nodes
859 state['skip'] += nodes
860 hbisect.save_state(repo, state)
860 hbisect.save_state(repo, state)
861 if not (state['good'] and state['bad']):
861 if not (state['good'] and state['bad']):
862 return
862 return
863
863
864 def mayupdate(repo, node, show_stats=True):
864 def mayupdate(repo, node, show_stats=True):
865 """common used update sequence"""
865 """common used update sequence"""
866 if noupdate:
866 if noupdate:
867 return
867 return
868 cmdutil.bailifchanged(repo)
868 cmdutil.bailifchanged(repo)
869 return hg.clean(repo, node, show_stats=show_stats)
869 return hg.clean(repo, node, show_stats=show_stats)
870
870
871 displayer = cmdutil.show_changeset(ui, repo, {})
871 displayer = cmdutil.show_changeset(ui, repo, {})
872
872
873 if command:
873 if command:
874 changesets = 1
874 changesets = 1
875 if noupdate:
875 if noupdate:
876 try:
876 try:
877 node = state['current'][0]
877 node = state['current'][0]
878 except LookupError:
878 except LookupError:
879 raise error.Abort(_('current bisect revision is unknown - '
879 raise error.Abort(_('current bisect revision is unknown - '
880 'start a new bisect to fix'))
880 'start a new bisect to fix'))
881 else:
881 else:
882 node, p2 = repo.dirstate.parents()
882 node, p2 = repo.dirstate.parents()
883 if p2 != nullid:
883 if p2 != nullid:
884 raise error.Abort(_('current bisect revision is a merge'))
884 raise error.Abort(_('current bisect revision is a merge'))
885 if rev:
885 if rev:
886 node = repo[scmutil.revsingle(repo, rev, node)].node()
886 node = repo[scmutil.revsingle(repo, rev, node)].node()
887 try:
887 try:
888 while changesets:
888 while changesets:
889 # update state
889 # update state
890 state['current'] = [node]
890 state['current'] = [node]
891 hbisect.save_state(repo, state)
891 hbisect.save_state(repo, state)
892 status = ui.system(command, environ={'HG_NODE': hex(node)})
892 status = ui.system(command, environ={'HG_NODE': hex(node)})
893 if status == 125:
893 if status == 125:
894 transition = "skip"
894 transition = "skip"
895 elif status == 0:
895 elif status == 0:
896 transition = "good"
896 transition = "good"
897 # status < 0 means process was killed
897 # status < 0 means process was killed
898 elif status == 127:
898 elif status == 127:
899 raise error.Abort(_("failed to execute %s") % command)
899 raise error.Abort(_("failed to execute %s") % command)
900 elif status < 0:
900 elif status < 0:
901 raise error.Abort(_("%s killed") % command)
901 raise error.Abort(_("%s killed") % command)
902 else:
902 else:
903 transition = "bad"
903 transition = "bad"
904 state[transition].append(node)
904 state[transition].append(node)
905 ctx = repo[node]
905 ctx = repo[node]
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
906 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
907 hbisect.checkstate(state)
907 hbisect.checkstate(state)
908 # bisect
908 # bisect
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
909 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
910 # update to next check
910 # update to next check
911 node = nodes[0]
911 node = nodes[0]
912 mayupdate(repo, node, show_stats=False)
912 mayupdate(repo, node, show_stats=False)
913 finally:
913 finally:
914 state['current'] = [node]
914 state['current'] = [node]
915 hbisect.save_state(repo, state)
915 hbisect.save_state(repo, state)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
916 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
917 return
917 return
918
918
919 hbisect.checkstate(state)
919 hbisect.checkstate(state)
920
920
921 # actually bisect
921 # actually bisect
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
922 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
923 if extend:
923 if extend:
924 if not changesets:
924 if not changesets:
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
925 extendnode = hbisect.extendrange(repo, state, nodes, good)
926 if extendnode is not None:
926 if extendnode is not None:
927 ui.write(_("Extending search to changeset %d:%s\n")
927 ui.write(_("Extending search to changeset %d:%s\n")
928 % (extendnode.rev(), extendnode))
928 % (extendnode.rev(), extendnode))
929 state['current'] = [extendnode.node()]
929 state['current'] = [extendnode.node()]
930 hbisect.save_state(repo, state)
930 hbisect.save_state(repo, state)
931 return mayupdate(repo, extendnode.node())
931 return mayupdate(repo, extendnode.node())
932 raise error.Abort(_("nothing to extend"))
932 raise error.Abort(_("nothing to extend"))
933
933
934 if changesets == 0:
934 if changesets == 0:
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
935 hbisect.printresult(ui, repo, state, displayer, nodes, good)
936 else:
936 else:
937 assert len(nodes) == 1 # only a single node can be tested next
937 assert len(nodes) == 1 # only a single node can be tested next
938 node = nodes[0]
938 node = nodes[0]
939 # compute the approximate number of remaining tests
939 # compute the approximate number of remaining tests
940 tests, size = 0, 2
940 tests, size = 0, 2
941 while size <= changesets:
941 while size <= changesets:
942 tests, size = tests + 1, size * 2
942 tests, size = tests + 1, size * 2
943 rev = repo.changelog.rev(node)
943 rev = repo.changelog.rev(node)
944 ui.write(_("Testing changeset %d:%s "
944 ui.write(_("Testing changeset %d:%s "
945 "(%d changesets remaining, ~%d tests)\n")
945 "(%d changesets remaining, ~%d tests)\n")
946 % (rev, short(node), changesets, tests))
946 % (rev, short(node), changesets, tests))
947 state['current'] = [node]
947 state['current'] = [node]
948 hbisect.save_state(repo, state)
948 hbisect.save_state(repo, state)
949 return mayupdate(repo, node)
949 return mayupdate(repo, node)
950
950
951 @command('bookmarks|bookmark',
951 @command('bookmarks|bookmark',
952 [('f', 'force', False, _('force')),
952 [('f', 'force', False, _('force')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
953 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
954 ('d', 'delete', False, _('delete a given bookmark')),
954 ('d', 'delete', False, _('delete a given bookmark')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
955 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
956 ('i', 'inactive', False, _('mark a bookmark inactive')),
957 ] + formatteropts,
957 ] + formatteropts,
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
958 _('hg bookmarks [OPTIONS]... [NAME]...'))
959 def bookmark(ui, repo, *names, **opts):
959 def bookmark(ui, repo, *names, **opts):
960 '''create a new bookmark or list existing bookmarks
960 '''create a new bookmark or list existing bookmarks
961
961
962 Bookmarks are labels on changesets to help track lines of development.
962 Bookmarks are labels on changesets to help track lines of development.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
963 Bookmarks are unversioned and can be moved, renamed and deleted.
964 Deleting or moving a bookmark has no effect on the associated changesets.
964 Deleting or moving a bookmark has no effect on the associated changesets.
965
965
966 Creating or updating to a bookmark causes it to be marked as 'active'.
966 Creating or updating to a bookmark causes it to be marked as 'active'.
967 The active bookmark is indicated with a '*'.
967 The active bookmark is indicated with a '*'.
968 When a commit is made, the active bookmark will advance to the new commit.
968 When a commit is made, the active bookmark will advance to the new commit.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
969 A plain :hg:`update` will also advance an active bookmark, if possible.
970 Updating away from a bookmark will cause it to be deactivated.
970 Updating away from a bookmark will cause it to be deactivated.
971
971
972 Bookmarks can be pushed and pulled between repositories (see
972 Bookmarks can be pushed and pulled between repositories (see
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
973 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
974 diverged, a new 'divergent bookmark' of the form 'name@path' will
975 be created. Using :hg:`merge` will resolve the divergence.
975 be created. Using :hg:`merge` will resolve the divergence.
976
976
977 A bookmark named '@' has the special property that :hg:`clone` will
977 A bookmark named '@' has the special property that :hg:`clone` will
978 check it out by default if it exists.
978 check it out by default if it exists.
979
979
980 .. container:: verbose
980 .. container:: verbose
981
981
982 Examples:
982 Examples:
983
983
984 - create an active bookmark for a new line of development::
984 - create an active bookmark for a new line of development::
985
985
986 hg book new-feature
986 hg book new-feature
987
987
988 - create an inactive bookmark as a place marker::
988 - create an inactive bookmark as a place marker::
989
989
990 hg book -i reviewed
990 hg book -i reviewed
991
991
992 - create an inactive bookmark on another changeset::
992 - create an inactive bookmark on another changeset::
993
993
994 hg book -r .^ tested
994 hg book -r .^ tested
995
995
996 - rename bookmark turkey to dinner::
996 - rename bookmark turkey to dinner::
997
997
998 hg book -m turkey dinner
998 hg book -m turkey dinner
999
999
1000 - move the '@' bookmark from another branch::
1000 - move the '@' bookmark from another branch::
1001
1001
1002 hg book -f @
1002 hg book -f @
1003 '''
1003 '''
1004 force = opts.get('force')
1004 force = opts.get('force')
1005 rev = opts.get('rev')
1005 rev = opts.get('rev')
1006 delete = opts.get('delete')
1006 delete = opts.get('delete')
1007 rename = opts.get('rename')
1007 rename = opts.get('rename')
1008 inactive = opts.get('inactive')
1008 inactive = opts.get('inactive')
1009
1009
1010 def checkformat(mark):
1010 def checkformat(mark):
1011 mark = mark.strip()
1011 mark = mark.strip()
1012 if not mark:
1012 if not mark:
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1013 raise error.Abort(_("bookmark names cannot consist entirely of "
1014 "whitespace"))
1014 "whitespace"))
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1015 scmutil.checknewlabel(repo, mark, 'bookmark')
1016 return mark
1016 return mark
1017
1017
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1018 def checkconflict(repo, mark, cur, force=False, target=None):
1019 if mark in marks and not force:
1019 if mark in marks and not force:
1020 if target:
1020 if target:
1021 if marks[mark] == target and target == cur:
1021 if marks[mark] == target and target == cur:
1022 # re-activating a bookmark
1022 # re-activating a bookmark
1023 return
1023 return
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1024 anc = repo.changelog.ancestors([repo[target].rev()])
1025 bmctx = repo[marks[mark]]
1025 bmctx = repo[marks[mark]]
1026 divs = [repo[b].node() for b in marks
1026 divs = [repo[b].node() for b in marks
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1027 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1028
1028
1029 # allow resolving a single divergent bookmark even if moving
1029 # allow resolving a single divergent bookmark even if moving
1030 # the bookmark across branches when a revision is specified
1030 # the bookmark across branches when a revision is specified
1031 # that contains a divergent bookmark
1031 # that contains a divergent bookmark
1032 if bmctx.rev() not in anc and target in divs:
1032 if bmctx.rev() not in anc and target in divs:
1033 bookmarks.deletedivergent(repo, [target], mark)
1033 bookmarks.deletedivergent(repo, [target], mark)
1034 return
1034 return
1035
1035
1036 deletefrom = [b for b in divs
1036 deletefrom = [b for b in divs
1037 if repo[b].rev() in anc or b == target]
1037 if repo[b].rev() in anc or b == target]
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1038 bookmarks.deletedivergent(repo, deletefrom, mark)
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1039 if bookmarks.validdest(repo, bmctx, repo[target]):
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1040 ui.status(_("moving bookmark '%s' forward from %s\n") %
1041 (mark, short(bmctx.node())))
1041 (mark, short(bmctx.node())))
1042 return
1042 return
1043 raise error.Abort(_("bookmark '%s' already exists "
1043 raise error.Abort(_("bookmark '%s' already exists "
1044 "(use -f to force)") % mark)
1044 "(use -f to force)") % mark)
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1045 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1046 and not force):
1046 and not force):
1047 raise error.Abort(
1047 raise error.Abort(
1048 _("a bookmark cannot have the name of an existing branch"))
1048 _("a bookmark cannot have the name of an existing branch"))
1049
1049
1050 if delete and rename:
1050 if delete and rename:
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1051 raise error.Abort(_("--delete and --rename are incompatible"))
1052 if delete and rev:
1052 if delete and rev:
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1053 raise error.Abort(_("--rev is incompatible with --delete"))
1054 if rename and rev:
1054 if rename and rev:
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1055 raise error.Abort(_("--rev is incompatible with --rename"))
1056 if not names and (delete or rev):
1056 if not names and (delete or rev):
1057 raise error.Abort(_("bookmark name required"))
1057 raise error.Abort(_("bookmark name required"))
1058
1058
1059 if delete or rename or names or inactive:
1059 if delete or rename or names or inactive:
1060 wlock = lock = tr = None
1060 wlock = lock = tr = None
1061 try:
1061 try:
1062 wlock = repo.wlock()
1062 wlock = repo.wlock()
1063 lock = repo.lock()
1063 lock = repo.lock()
1064 cur = repo.changectx('.').node()
1064 cur = repo.changectx('.').node()
1065 marks = repo._bookmarks
1065 marks = repo._bookmarks
1066 if delete:
1066 if delete:
1067 tr = repo.transaction('bookmark')
1067 tr = repo.transaction('bookmark')
1068 for mark in names:
1068 for mark in names:
1069 if mark not in marks:
1069 if mark not in marks:
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1070 raise error.Abort(_("bookmark '%s' does not exist") %
1071 mark)
1071 mark)
1072 if mark == repo._activebookmark:
1072 if mark == repo._activebookmark:
1073 bookmarks.deactivate(repo)
1073 bookmarks.deactivate(repo)
1074 del marks[mark]
1074 del marks[mark]
1075
1075
1076 elif rename:
1076 elif rename:
1077 tr = repo.transaction('bookmark')
1077 tr = repo.transaction('bookmark')
1078 if not names:
1078 if not names:
1079 raise error.Abort(_("new bookmark name required"))
1079 raise error.Abort(_("new bookmark name required"))
1080 elif len(names) > 1:
1080 elif len(names) > 1:
1081 raise error.Abort(_("only one new bookmark name allowed"))
1081 raise error.Abort(_("only one new bookmark name allowed"))
1082 mark = checkformat(names[0])
1082 mark = checkformat(names[0])
1083 if rename not in marks:
1083 if rename not in marks:
1084 raise error.Abort(_("bookmark '%s' does not exist")
1084 raise error.Abort(_("bookmark '%s' does not exist")
1085 % rename)
1085 % rename)
1086 checkconflict(repo, mark, cur, force)
1086 checkconflict(repo, mark, cur, force)
1087 marks[mark] = marks[rename]
1087 marks[mark] = marks[rename]
1088 if repo._activebookmark == rename and not inactive:
1088 if repo._activebookmark == rename and not inactive:
1089 bookmarks.activate(repo, mark)
1089 bookmarks.activate(repo, mark)
1090 del marks[rename]
1090 del marks[rename]
1091 elif names:
1091 elif names:
1092 tr = repo.transaction('bookmark')
1092 tr = repo.transaction('bookmark')
1093 newact = None
1093 newact = None
1094 for mark in names:
1094 for mark in names:
1095 mark = checkformat(mark)
1095 mark = checkformat(mark)
1096 if newact is None:
1096 if newact is None:
1097 newact = mark
1097 newact = mark
1098 if inactive and mark == repo._activebookmark:
1098 if inactive and mark == repo._activebookmark:
1099 bookmarks.deactivate(repo)
1099 bookmarks.deactivate(repo)
1100 return
1100 return
1101 tgt = cur
1101 tgt = cur
1102 if rev:
1102 if rev:
1103 tgt = scmutil.revsingle(repo, rev).node()
1103 tgt = scmutil.revsingle(repo, rev).node()
1104 checkconflict(repo, mark, cur, force, tgt)
1104 checkconflict(repo, mark, cur, force, tgt)
1105 marks[mark] = tgt
1105 marks[mark] = tgt
1106 if not inactive and cur == marks[newact] and not rev:
1106 if not inactive and cur == marks[newact] and not rev:
1107 bookmarks.activate(repo, newact)
1107 bookmarks.activate(repo, newact)
1108 elif cur != tgt and newact == repo._activebookmark:
1108 elif cur != tgt and newact == repo._activebookmark:
1109 bookmarks.deactivate(repo)
1109 bookmarks.deactivate(repo)
1110 elif inactive:
1110 elif inactive:
1111 if len(marks) == 0:
1111 if len(marks) == 0:
1112 ui.status(_("no bookmarks set\n"))
1112 ui.status(_("no bookmarks set\n"))
1113 elif not repo._activebookmark:
1113 elif not repo._activebookmark:
1114 ui.status(_("no active bookmark\n"))
1114 ui.status(_("no active bookmark\n"))
1115 else:
1115 else:
1116 bookmarks.deactivate(repo)
1116 bookmarks.deactivate(repo)
1117 if tr is not None:
1117 if tr is not None:
1118 marks.recordchange(tr)
1118 marks.recordchange(tr)
1119 tr.close()
1119 tr.close()
1120 finally:
1120 finally:
1121 lockmod.release(tr, lock, wlock)
1121 lockmod.release(tr, lock, wlock)
1122 else: # show bookmarks
1122 else: # show bookmarks
1123 fm = ui.formatter('bookmarks', opts)
1123 fm = ui.formatter('bookmarks', opts)
1124 hexfn = fm.hexfunc
1124 hexfn = fm.hexfunc
1125 marks = repo._bookmarks
1125 marks = repo._bookmarks
1126 if len(marks) == 0 and fm.isplain():
1126 if len(marks) == 0 and fm.isplain():
1127 ui.status(_("no bookmarks set\n"))
1127 ui.status(_("no bookmarks set\n"))
1128 for bmark, n in sorted(marks.iteritems()):
1128 for bmark, n in sorted(marks.iteritems()):
1129 active = repo._activebookmark
1129 active = repo._activebookmark
1130 if bmark == active:
1130 if bmark == active:
1131 prefix, label = '*', activebookmarklabel
1131 prefix, label = '*', activebookmarklabel
1132 else:
1132 else:
1133 prefix, label = ' ', ''
1133 prefix, label = ' ', ''
1134
1134
1135 fm.startitem()
1135 fm.startitem()
1136 if not ui.quiet:
1136 if not ui.quiet:
1137 fm.plain(' %s ' % prefix, label=label)
1137 fm.plain(' %s ' % prefix, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1138 fm.write('bookmark', '%s', bmark, label=label)
1139 pad = " " * (25 - encoding.colwidth(bmark))
1139 pad = " " * (25 - encoding.colwidth(bmark))
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1140 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1141 repo.changelog.rev(n), hexfn(n), label=label)
1141 repo.changelog.rev(n), hexfn(n), label=label)
1142 fm.data(active=(bmark == active))
1142 fm.data(active=(bmark == active))
1143 fm.plain('\n')
1143 fm.plain('\n')
1144 fm.end()
1144 fm.end()
1145
1145
1146 @command('branch',
1146 @command('branch',
1147 [('f', 'force', None,
1147 [('f', 'force', None,
1148 _('set branch name even if it shadows an existing branch')),
1148 _('set branch name even if it shadows an existing branch')),
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1149 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1150 _('[-fC] [NAME]'))
1150 _('[-fC] [NAME]'))
1151 def branch(ui, repo, label=None, **opts):
1151 def branch(ui, repo, label=None, **opts):
1152 """set or show the current branch name
1152 """set or show the current branch name
1153
1153
1154 .. note::
1154 .. note::
1155
1155
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1156 Branch names are permanent and global. Use :hg:`bookmark` to create a
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1157 light-weight bookmark instead. See :hg:`help glossary` for more
1158 information about named branches and bookmarks.
1158 information about named branches and bookmarks.
1159
1159
1160 With no argument, show the current branch name. With one argument,
1160 With no argument, show the current branch name. With one argument,
1161 set the working directory branch name (the branch will not exist
1161 set the working directory branch name (the branch will not exist
1162 in the repository until the next commit). Standard practice
1162 in the repository until the next commit). Standard practice
1163 recommends that primary development take place on the 'default'
1163 recommends that primary development take place on the 'default'
1164 branch.
1164 branch.
1165
1165
1166 Unless -f/--force is specified, branch will not let you set a
1166 Unless -f/--force is specified, branch will not let you set a
1167 branch name that already exists.
1167 branch name that already exists.
1168
1168
1169 Use -C/--clean to reset the working directory branch to that of
1169 Use -C/--clean to reset the working directory branch to that of
1170 the parent of the working directory, negating a previous branch
1170 the parent of the working directory, negating a previous branch
1171 change.
1171 change.
1172
1172
1173 Use the command :hg:`update` to switch to an existing branch. Use
1173 Use the command :hg:`update` to switch to an existing branch. Use
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1174 :hg:`commit --close-branch` to mark this branch head as closed.
1175 When all heads of a branch are closed, the branch will be
1175 When all heads of a branch are closed, the branch will be
1176 considered closed.
1176 considered closed.
1177
1177
1178 Returns 0 on success.
1178 Returns 0 on success.
1179 """
1179 """
1180 if label:
1180 if label:
1181 label = label.strip()
1181 label = label.strip()
1182
1182
1183 if not opts.get('clean') and not label:
1183 if not opts.get('clean') and not label:
1184 ui.write("%s\n" % repo.dirstate.branch())
1184 ui.write("%s\n" % repo.dirstate.branch())
1185 return
1185 return
1186
1186
1187 with repo.wlock():
1187 with repo.wlock():
1188 if opts.get('clean'):
1188 if opts.get('clean'):
1189 label = repo[None].p1().branch()
1189 label = repo[None].p1().branch()
1190 repo.dirstate.setbranch(label)
1190 repo.dirstate.setbranch(label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1191 ui.status(_('reset working directory to branch %s\n') % label)
1192 elif label:
1192 elif label:
1193 if not opts.get('force') and label in repo.branchmap():
1193 if not opts.get('force') and label in repo.branchmap():
1194 if label not in [p.branch() for p in repo[None].parents()]:
1194 if label not in [p.branch() for p in repo[None].parents()]:
1195 raise error.Abort(_('a branch of the same name already'
1195 raise error.Abort(_('a branch of the same name already'
1196 ' exists'),
1196 ' exists'),
1197 # i18n: "it" refers to an existing branch
1197 # i18n: "it" refers to an existing branch
1198 hint=_("use 'hg update' to switch to it"))
1198 hint=_("use 'hg update' to switch to it"))
1199 scmutil.checknewlabel(repo, label, 'branch')
1199 scmutil.checknewlabel(repo, label, 'branch')
1200 repo.dirstate.setbranch(label)
1200 repo.dirstate.setbranch(label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1201 ui.status(_('marked working directory as branch %s\n') % label)
1202
1202
1203 # find any open named branches aside from default
1203 # find any open named branches aside from default
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1204 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1205 if n != "default" and not c]
1205 if n != "default" and not c]
1206 if not others:
1206 if not others:
1207 ui.status(_('(branches are permanent and global, '
1207 ui.status(_('(branches are permanent and global, '
1208 'did you want a bookmark?)\n'))
1208 'did you want a bookmark?)\n'))
1209
1209
1210 @command('branches',
1210 @command('branches',
1211 [('a', 'active', False,
1211 [('a', 'active', False,
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1212 _('show only branches that have unmerged heads (DEPRECATED)')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1213 ('c', 'closed', False, _('show normal and closed branches')),
1214 ] + formatteropts,
1214 ] + formatteropts,
1215 _('[-c]'))
1215 _('[-c]'))
1216 def branches(ui, repo, active=False, closed=False, **opts):
1216 def branches(ui, repo, active=False, closed=False, **opts):
1217 """list repository named branches
1217 """list repository named branches
1218
1218
1219 List the repository's named branches, indicating which ones are
1219 List the repository's named branches, indicating which ones are
1220 inactive. If -c/--closed is specified, also list branches which have
1220 inactive. If -c/--closed is specified, also list branches which have
1221 been marked closed (see :hg:`commit --close-branch`).
1221 been marked closed (see :hg:`commit --close-branch`).
1222
1222
1223 Use the command :hg:`update` to switch to an existing branch.
1223 Use the command :hg:`update` to switch to an existing branch.
1224
1224
1225 Returns 0.
1225 Returns 0.
1226 """
1226 """
1227
1227
1228 fm = ui.formatter('branches', opts)
1228 fm = ui.formatter('branches', opts)
1229 hexfunc = fm.hexfunc
1229 hexfunc = fm.hexfunc
1230
1230
1231 allheads = set(repo.heads())
1231 allheads = set(repo.heads())
1232 branches = []
1232 branches = []
1233 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1233 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1234 isactive = not isclosed and bool(set(heads) & allheads)
1234 isactive = not isclosed and bool(set(heads) & allheads)
1235 branches.append((tag, repo[tip], isactive, not isclosed))
1235 branches.append((tag, repo[tip], isactive, not isclosed))
1236 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1236 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1237 reverse=True)
1237 reverse=True)
1238
1238
1239 for tag, ctx, isactive, isopen in branches:
1239 for tag, ctx, isactive, isopen in branches:
1240 if active and not isactive:
1240 if active and not isactive:
1241 continue
1241 continue
1242 if isactive:
1242 if isactive:
1243 label = 'branches.active'
1243 label = 'branches.active'
1244 notice = ''
1244 notice = ''
1245 elif not isopen:
1245 elif not isopen:
1246 if not closed:
1246 if not closed:
1247 continue
1247 continue
1248 label = 'branches.closed'
1248 label = 'branches.closed'
1249 notice = _(' (closed)')
1249 notice = _(' (closed)')
1250 else:
1250 else:
1251 label = 'branches.inactive'
1251 label = 'branches.inactive'
1252 notice = _(' (inactive)')
1252 notice = _(' (inactive)')
1253 current = (tag == repo.dirstate.branch())
1253 current = (tag == repo.dirstate.branch())
1254 if current:
1254 if current:
1255 label = 'branches.current'
1255 label = 'branches.current'
1256
1256
1257 fm.startitem()
1257 fm.startitem()
1258 fm.write('branch', '%s', tag, label=label)
1258 fm.write('branch', '%s', tag, label=label)
1259 rev = ctx.rev()
1259 rev = ctx.rev()
1260 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1260 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1261 fmt = ' ' * padsize + ' %d:%s'
1261 fmt = ' ' * padsize + ' %d:%s'
1262 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1262 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1263 label='log.changeset changeset.%s' % ctx.phasestr())
1263 label='log.changeset changeset.%s' % ctx.phasestr())
1264 fm.data(active=isactive, closed=not isopen, current=current)
1264 fm.data(active=isactive, closed=not isopen, current=current)
1265 if not ui.quiet:
1265 if not ui.quiet:
1266 fm.plain(notice)
1266 fm.plain(notice)
1267 fm.plain('\n')
1267 fm.plain('\n')
1268 fm.end()
1268 fm.end()
1269
1269
1270 @command('bundle',
1270 @command('bundle',
1271 [('f', 'force', None, _('run even when the destination is unrelated')),
1271 [('f', 'force', None, _('run even when the destination is unrelated')),
1272 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1272 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1273 _('REV')),
1273 _('REV')),
1274 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1274 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1275 _('BRANCH')),
1275 _('BRANCH')),
1276 ('', 'base', [],
1276 ('', 'base', [],
1277 _('a base changeset assumed to be available at the destination'),
1277 _('a base changeset assumed to be available at the destination'),
1278 _('REV')),
1278 _('REV')),
1279 ('a', 'all', None, _('bundle all changesets in the repository')),
1279 ('a', 'all', None, _('bundle all changesets in the repository')),
1280 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1280 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1281 ] + remoteopts,
1281 ] + remoteopts,
1282 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1282 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1283 def bundle(ui, repo, fname, dest=None, **opts):
1283 def bundle(ui, repo, fname, dest=None, **opts):
1284 """create a changegroup file
1284 """create a changegroup file
1285
1285
1286 Generate a changegroup file collecting changesets to be added
1286 Generate a changegroup file collecting changesets to be added
1287 to a repository.
1287 to a repository.
1288
1288
1289 To create a bundle containing all changesets, use -a/--all
1289 To create a bundle containing all changesets, use -a/--all
1290 (or --base null). Otherwise, hg assumes the destination will have
1290 (or --base null). Otherwise, hg assumes the destination will have
1291 all the nodes you specify with --base parameters. Otherwise, hg
1291 all the nodes you specify with --base parameters. Otherwise, hg
1292 will assume the repository has all the nodes in destination, or
1292 will assume the repository has all the nodes in destination, or
1293 default-push/default if no destination is specified.
1293 default-push/default if no destination is specified.
1294
1294
1295 You can change bundle format with the -t/--type option. You can
1295 You can change bundle format with the -t/--type option. You can
1296 specify a compression, a bundle version or both using a dash
1296 specify a compression, a bundle version or both using a dash
1297 (comp-version). The available compression methods are: none, bzip2,
1297 (comp-version). The available compression methods are: none, bzip2,
1298 and gzip (by default, bundles are compressed using bzip2). The
1298 and gzip (by default, bundles are compressed using bzip2). The
1299 available formats are: v1, v2 (default to most suitable).
1299 available formats are: v1, v2 (default to most suitable).
1300
1300
1301 The bundle file can then be transferred using conventional means
1301 The bundle file can then be transferred using conventional means
1302 and applied to another repository with the unbundle or pull
1302 and applied to another repository with the unbundle or pull
1303 command. This is useful when direct push and pull are not
1303 command. This is useful when direct push and pull are not
1304 available or when exporting an entire repository is undesirable.
1304 available or when exporting an entire repository is undesirable.
1305
1305
1306 Applying bundles preserves all changeset contents including
1306 Applying bundles preserves all changeset contents including
1307 permissions, copy/rename information, and revision history.
1307 permissions, copy/rename information, and revision history.
1308
1308
1309 Returns 0 on success, 1 if no changes found.
1309 Returns 0 on success, 1 if no changes found.
1310 """
1310 """
1311 revs = None
1311 revs = None
1312 if 'rev' in opts:
1312 if 'rev' in opts:
1313 revstrings = opts['rev']
1313 revstrings = opts['rev']
1314 revs = scmutil.revrange(repo, revstrings)
1314 revs = scmutil.revrange(repo, revstrings)
1315 if revstrings and not revs:
1315 if revstrings and not revs:
1316 raise error.Abort(_('no commits to bundle'))
1316 raise error.Abort(_('no commits to bundle'))
1317
1317
1318 bundletype = opts.get('type', 'bzip2').lower()
1318 bundletype = opts.get('type', 'bzip2').lower()
1319 try:
1319 try:
1320 bcompression, cgversion, params = exchange.parsebundlespec(
1320 bcompression, cgversion, params = exchange.parsebundlespec(
1321 repo, bundletype, strict=False)
1321 repo, bundletype, strict=False)
1322 except error.UnsupportedBundleSpecification as e:
1322 except error.UnsupportedBundleSpecification as e:
1323 raise error.Abort(str(e),
1323 raise error.Abort(str(e),
1324 hint=_("see 'hg help bundle' for supported "
1324 hint=_("see 'hg help bundle' for supported "
1325 "values for --type"))
1325 "values for --type"))
1326
1326
1327 # Packed bundles are a pseudo bundle format for now.
1327 # Packed bundles are a pseudo bundle format for now.
1328 if cgversion == 's1':
1328 if cgversion == 's1':
1329 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1329 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1330 hint=_("use 'hg debugcreatestreamclonebundle'"))
1330 hint=_("use 'hg debugcreatestreamclonebundle'"))
1331
1331
1332 if opts.get('all'):
1332 if opts.get('all'):
1333 if dest:
1333 if dest:
1334 raise error.Abort(_("--all is incompatible with specifying "
1334 raise error.Abort(_("--all is incompatible with specifying "
1335 "a destination"))
1335 "a destination"))
1336 if opts.get('base'):
1336 if opts.get('base'):
1337 ui.warn(_("ignoring --base because --all was specified\n"))
1337 ui.warn(_("ignoring --base because --all was specified\n"))
1338 base = ['null']
1338 base = ['null']
1339 else:
1339 else:
1340 base = scmutil.revrange(repo, opts.get('base'))
1340 base = scmutil.revrange(repo, opts.get('base'))
1341 # TODO: get desired bundlecaps from command line.
1341 # TODO: get desired bundlecaps from command line.
1342 bundlecaps = None
1342 bundlecaps = None
1343 if cgversion not in changegroup.supportedoutgoingversions(repo):
1343 if cgversion not in changegroup.supportedoutgoingversions(repo):
1344 raise error.Abort(_("repository does not support bundle version %s") %
1344 raise error.Abort(_("repository does not support bundle version %s") %
1345 cgversion)
1345 cgversion)
1346
1346
1347 if base:
1347 if base:
1348 if dest:
1348 if dest:
1349 raise error.Abort(_("--base is incompatible with specifying "
1349 raise error.Abort(_("--base is incompatible with specifying "
1350 "a destination"))
1350 "a destination"))
1351 common = [repo.lookup(rev) for rev in base]
1351 common = [repo.lookup(rev) for rev in base]
1352 heads = revs and map(repo.lookup, revs) or None
1352 heads = revs and map(repo.lookup, revs) or None
1353 outgoing = discovery.outgoing(repo, common, heads)
1353 outgoing = discovery.outgoing(repo, common, heads)
1354 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1354 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1355 bundlecaps=bundlecaps,
1355 bundlecaps=bundlecaps,
1356 version=cgversion)
1356 version=cgversion)
1357 outgoing = None
1357 outgoing = None
1358 else:
1358 else:
1359 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1359 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1360 dest, branches = hg.parseurl(dest, opts.get('branch'))
1360 dest, branches = hg.parseurl(dest, opts.get('branch'))
1361 other = hg.peer(repo, opts, dest)
1361 other = hg.peer(repo, opts, dest)
1362 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1362 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1363 heads = revs and map(repo.lookup, revs) or revs
1363 heads = revs and map(repo.lookup, revs) or revs
1364 outgoing = discovery.findcommonoutgoing(repo, other,
1364 outgoing = discovery.findcommonoutgoing(repo, other,
1365 onlyheads=heads,
1365 onlyheads=heads,
1366 force=opts.get('force'),
1366 force=opts.get('force'),
1367 portable=True)
1367 portable=True)
1368 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1368 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1369 bundlecaps, version=cgversion)
1369 bundlecaps, version=cgversion)
1370 if not cg:
1370 if not cg:
1371 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1371 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1372 return 1
1372 return 1
1373
1373
1374 if cgversion == '01': #bundle1
1374 if cgversion == '01': #bundle1
1375 if bcompression is None:
1375 if bcompression is None:
1376 bcompression = 'UN'
1376 bcompression = 'UN'
1377 bversion = 'HG10' + bcompression
1377 bversion = 'HG10' + bcompression
1378 bcompression = None
1378 bcompression = None
1379 else:
1379 else:
1380 assert cgversion == '02'
1380 assert cgversion == '02'
1381 bversion = 'HG20'
1381 bversion = 'HG20'
1382
1382
1383 # TODO compression options should be derived from bundlespec parsing.
1383 # TODO compression options should be derived from bundlespec parsing.
1384 # This is a temporary hack to allow adjusting bundle compression
1384 # This is a temporary hack to allow adjusting bundle compression
1385 # level without a) formalizing the bundlespec changes to declare it
1385 # level without a) formalizing the bundlespec changes to declare it
1386 # b) introducing a command flag.
1386 # b) introducing a command flag.
1387 compopts = {}
1387 compopts = {}
1388 complevel = ui.configint('experimental', 'bundlecomplevel')
1388 complevel = ui.configint('experimental', 'bundlecomplevel')
1389 if complevel is not None:
1389 if complevel is not None:
1390 compopts['level'] = complevel
1390 compopts['level'] = complevel
1391
1391
1392 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1392 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1393 compopts=compopts)
1393 compopts=compopts)
1394
1394
1395 @command('cat',
1395 @command('cat',
1396 [('o', 'output', '',
1396 [('o', 'output', '',
1397 _('print output to file with formatted name'), _('FORMAT')),
1397 _('print output to file with formatted name'), _('FORMAT')),
1398 ('r', 'rev', '', _('print the given revision'), _('REV')),
1398 ('r', 'rev', '', _('print the given revision'), _('REV')),
1399 ('', 'decode', None, _('apply any matching decode filter')),
1399 ('', 'decode', None, _('apply any matching decode filter')),
1400 ] + walkopts,
1400 ] + walkopts,
1401 _('[OPTION]... FILE...'),
1401 _('[OPTION]... FILE...'),
1402 inferrepo=True)
1402 inferrepo=True)
1403 def cat(ui, repo, file1, *pats, **opts):
1403 def cat(ui, repo, file1, *pats, **opts):
1404 """output the current or given revision of files
1404 """output the current or given revision of files
1405
1405
1406 Print the specified files as they were at the given revision. If
1406 Print the specified files as they were at the given revision. If
1407 no revision is given, the parent of the working directory is used.
1407 no revision is given, the parent of the working directory is used.
1408
1408
1409 Output may be to a file, in which case the name of the file is
1409 Output may be to a file, in which case the name of the file is
1410 given using a format string. The formatting rules as follows:
1410 given using a format string. The formatting rules as follows:
1411
1411
1412 :``%%``: literal "%" character
1412 :``%%``: literal "%" character
1413 :``%s``: basename of file being printed
1413 :``%s``: basename of file being printed
1414 :``%d``: dirname of file being printed, or '.' if in repository root
1414 :``%d``: dirname of file being printed, or '.' if in repository root
1415 :``%p``: root-relative path name of file being printed
1415 :``%p``: root-relative path name of file being printed
1416 :``%H``: changeset hash (40 hexadecimal digits)
1416 :``%H``: changeset hash (40 hexadecimal digits)
1417 :``%R``: changeset revision number
1417 :``%R``: changeset revision number
1418 :``%h``: short-form changeset hash (12 hexadecimal digits)
1418 :``%h``: short-form changeset hash (12 hexadecimal digits)
1419 :``%r``: zero-padded changeset revision number
1419 :``%r``: zero-padded changeset revision number
1420 :``%b``: basename of the exporting repository
1420 :``%b``: basename of the exporting repository
1421
1421
1422 Returns 0 on success.
1422 Returns 0 on success.
1423 """
1423 """
1424 ctx = scmutil.revsingle(repo, opts.get('rev'))
1424 ctx = scmutil.revsingle(repo, opts.get('rev'))
1425 m = scmutil.match(ctx, (file1,) + pats, opts)
1425 m = scmutil.match(ctx, (file1,) + pats, opts)
1426
1426
1427 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1427 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1428
1428
1429 @command('^clone',
1429 @command('^clone',
1430 [('U', 'noupdate', None, _('the clone will include an empty working '
1430 [('U', 'noupdate', None, _('the clone will include an empty working '
1431 'directory (only a repository)')),
1431 'directory (only a repository)')),
1432 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1432 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1433 _('REV')),
1433 _('REV')),
1434 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1434 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1435 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1435 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1436 ('', 'pull', None, _('use pull protocol to copy metadata')),
1436 ('', 'pull', None, _('use pull protocol to copy metadata')),
1437 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1437 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1438 ] + remoteopts,
1438 ] + remoteopts,
1439 _('[OPTION]... SOURCE [DEST]'),
1439 _('[OPTION]... SOURCE [DEST]'),
1440 norepo=True)
1440 norepo=True)
1441 def clone(ui, source, dest=None, **opts):
1441 def clone(ui, source, dest=None, **opts):
1442 """make a copy of an existing repository
1442 """make a copy of an existing repository
1443
1443
1444 Create a copy of an existing repository in a new directory.
1444 Create a copy of an existing repository in a new directory.
1445
1445
1446 If no destination directory name is specified, it defaults to the
1446 If no destination directory name is specified, it defaults to the
1447 basename of the source.
1447 basename of the source.
1448
1448
1449 The location of the source is added to the new repository's
1449 The location of the source is added to the new repository's
1450 ``.hg/hgrc`` file, as the default to be used for future pulls.
1450 ``.hg/hgrc`` file, as the default to be used for future pulls.
1451
1451
1452 Only local paths and ``ssh://`` URLs are supported as
1452 Only local paths and ``ssh://`` URLs are supported as
1453 destinations. For ``ssh://`` destinations, no working directory or
1453 destinations. For ``ssh://`` destinations, no working directory or
1454 ``.hg/hgrc`` will be created on the remote side.
1454 ``.hg/hgrc`` will be created on the remote side.
1455
1455
1456 If the source repository has a bookmark called '@' set, that
1456 If the source repository has a bookmark called '@' set, that
1457 revision will be checked out in the new repository by default.
1457 revision will be checked out in the new repository by default.
1458
1458
1459 To check out a particular version, use -u/--update, or
1459 To check out a particular version, use -u/--update, or
1460 -U/--noupdate to create a clone with no working directory.
1460 -U/--noupdate to create a clone with no working directory.
1461
1461
1462 To pull only a subset of changesets, specify one or more revisions
1462 To pull only a subset of changesets, specify one or more revisions
1463 identifiers with -r/--rev or branches with -b/--branch. The
1463 identifiers with -r/--rev or branches with -b/--branch. The
1464 resulting clone will contain only the specified changesets and
1464 resulting clone will contain only the specified changesets and
1465 their ancestors. These options (or 'clone src#rev dest') imply
1465 their ancestors. These options (or 'clone src#rev dest') imply
1466 --pull, even for local source repositories.
1466 --pull, even for local source repositories.
1467
1467
1468 .. note::
1468 .. note::
1469
1469
1470 Specifying a tag will include the tagged changeset but not the
1470 Specifying a tag will include the tagged changeset but not the
1471 changeset containing the tag.
1471 changeset containing the tag.
1472
1472
1473 .. container:: verbose
1473 .. container:: verbose
1474
1474
1475 For efficiency, hardlinks are used for cloning whenever the
1475 For efficiency, hardlinks are used for cloning whenever the
1476 source and destination are on the same filesystem (note this
1476 source and destination are on the same filesystem (note this
1477 applies only to the repository data, not to the working
1477 applies only to the repository data, not to the working
1478 directory). Some filesystems, such as AFS, implement hardlinking
1478 directory). Some filesystems, such as AFS, implement hardlinking
1479 incorrectly, but do not report errors. In these cases, use the
1479 incorrectly, but do not report errors. In these cases, use the
1480 --pull option to avoid hardlinking.
1480 --pull option to avoid hardlinking.
1481
1481
1482 In some cases, you can clone repositories and the working
1482 In some cases, you can clone repositories and the working
1483 directory using full hardlinks with ::
1483 directory using full hardlinks with ::
1484
1484
1485 $ cp -al REPO REPOCLONE
1485 $ cp -al REPO REPOCLONE
1486
1486
1487 This is the fastest way to clone, but it is not always safe. The
1487 This is the fastest way to clone, but it is not always safe. The
1488 operation is not atomic (making sure REPO is not modified during
1488 operation is not atomic (making sure REPO is not modified during
1489 the operation is up to you) and you have to make sure your
1489 the operation is up to you) and you have to make sure your
1490 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1490 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1491 so). Also, this is not compatible with certain extensions that
1491 so). Also, this is not compatible with certain extensions that
1492 place their metadata under the .hg directory, such as mq.
1492 place their metadata under the .hg directory, such as mq.
1493
1493
1494 Mercurial will update the working directory to the first applicable
1494 Mercurial will update the working directory to the first applicable
1495 revision from this list:
1495 revision from this list:
1496
1496
1497 a) null if -U or the source repository has no changesets
1497 a) null if -U or the source repository has no changesets
1498 b) if -u . and the source repository is local, the first parent of
1498 b) if -u . and the source repository is local, the first parent of
1499 the source repository's working directory
1499 the source repository's working directory
1500 c) the changeset specified with -u (if a branch name, this means the
1500 c) the changeset specified with -u (if a branch name, this means the
1501 latest head of that branch)
1501 latest head of that branch)
1502 d) the changeset specified with -r
1502 d) the changeset specified with -r
1503 e) the tipmost head specified with -b
1503 e) the tipmost head specified with -b
1504 f) the tipmost head specified with the url#branch source syntax
1504 f) the tipmost head specified with the url#branch source syntax
1505 g) the revision marked with the '@' bookmark, if present
1505 g) the revision marked with the '@' bookmark, if present
1506 h) the tipmost head of the default branch
1506 h) the tipmost head of the default branch
1507 i) tip
1507 i) tip
1508
1508
1509 When cloning from servers that support it, Mercurial may fetch
1509 When cloning from servers that support it, Mercurial may fetch
1510 pre-generated data from a server-advertised URL. When this is done,
1510 pre-generated data from a server-advertised URL. When this is done,
1511 hooks operating on incoming changesets and changegroups may fire twice,
1511 hooks operating on incoming changesets and changegroups may fire twice,
1512 once for the bundle fetched from the URL and another for any additional
1512 once for the bundle fetched from the URL and another for any additional
1513 data not fetched from this URL. In addition, if an error occurs, the
1513 data not fetched from this URL. In addition, if an error occurs, the
1514 repository may be rolled back to a partial clone. This behavior may
1514 repository may be rolled back to a partial clone. This behavior may
1515 change in future releases. See :hg:`help -e clonebundles` for more.
1515 change in future releases. See :hg:`help -e clonebundles` for more.
1516
1516
1517 Examples:
1517 Examples:
1518
1518
1519 - clone a remote repository to a new directory named hg/::
1519 - clone a remote repository to a new directory named hg/::
1520
1520
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1522
1522
1523 - create a lightweight local clone::
1523 - create a lightweight local clone::
1524
1524
1525 hg clone project/ project-feature/
1525 hg clone project/ project-feature/
1526
1526
1527 - clone from an absolute path on an ssh server (note double-slash)::
1527 - clone from an absolute path on an ssh server (note double-slash)::
1528
1528
1529 hg clone ssh://user@server//home/projects/alpha/
1529 hg clone ssh://user@server//home/projects/alpha/
1530
1530
1531 - do a high-speed clone over a LAN while checking out a
1531 - do a high-speed clone over a LAN while checking out a
1532 specified version::
1532 specified version::
1533
1533
1534 hg clone --uncompressed http://server/repo -u 1.5
1534 hg clone --uncompressed http://server/repo -u 1.5
1535
1535
1536 - create a repository without changesets after a particular revision::
1536 - create a repository without changesets after a particular revision::
1537
1537
1538 hg clone -r 04e544 experimental/ good/
1538 hg clone -r 04e544 experimental/ good/
1539
1539
1540 - clone (and track) a particular named branch::
1540 - clone (and track) a particular named branch::
1541
1541
1542 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1542 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1543
1543
1544 See :hg:`help urls` for details on specifying URLs.
1544 See :hg:`help urls` for details on specifying URLs.
1545
1545
1546 Returns 0 on success.
1546 Returns 0 on success.
1547 """
1547 """
1548 if opts.get('noupdate') and opts.get('updaterev'):
1548 if opts.get('noupdate') and opts.get('updaterev'):
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1550
1550
1551 r = hg.clone(ui, opts, source, dest,
1551 r = hg.clone(ui, opts, source, dest,
1552 pull=opts.get('pull'),
1552 pull=opts.get('pull'),
1553 stream=opts.get('uncompressed'),
1553 stream=opts.get('uncompressed'),
1554 rev=opts.get('rev'),
1554 rev=opts.get('rev'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1556 branch=opts.get('branch'),
1556 branch=opts.get('branch'),
1557 shareopts=opts.get('shareopts'))
1557 shareopts=opts.get('shareopts'))
1558
1558
1559 return r is None
1559 return r is None
1560
1560
1561 @command('^commit|ci',
1561 @command('^commit|ci',
1562 [('A', 'addremove', None,
1562 [('A', 'addremove', None,
1563 _('mark new/missing files as added/removed before committing')),
1563 _('mark new/missing files as added/removed before committing')),
1564 ('', 'close-branch', None,
1564 ('', 'close-branch', None,
1565 _('mark a branch head as closed')),
1565 _('mark a branch head as closed')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1571 _('[OPTION]... [FILE]...'),
1571 _('[OPTION]... [FILE]...'),
1572 inferrepo=True)
1572 inferrepo=True)
1573 def commit(ui, repo, *pats, **opts):
1573 def commit(ui, repo, *pats, **opts):
1574 """commit the specified files or all outstanding changes
1574 """commit the specified files or all outstanding changes
1575
1575
1576 Commit changes to the given files into the repository. Unlike a
1576 Commit changes to the given files into the repository. Unlike a
1577 centralized SCM, this operation is a local operation. See
1577 centralized SCM, this operation is a local operation. See
1578 :hg:`push` for a way to actively distribute your changes.
1578 :hg:`push` for a way to actively distribute your changes.
1579
1579
1580 If a list of files is omitted, all changes reported by :hg:`status`
1580 If a list of files is omitted, all changes reported by :hg:`status`
1581 will be committed.
1581 will be committed.
1582
1582
1583 If you are committing the result of a merge, do not provide any
1583 If you are committing the result of a merge, do not provide any
1584 filenames or -I/-X filters.
1584 filenames or -I/-X filters.
1585
1585
1586 If no commit message is specified, Mercurial starts your
1586 If no commit message is specified, Mercurial starts your
1587 configured editor where you can enter a message. In case your
1587 configured editor where you can enter a message. In case your
1588 commit fails, you will find a backup of your message in
1588 commit fails, you will find a backup of your message in
1589 ``.hg/last-message.txt``.
1589 ``.hg/last-message.txt``.
1590
1590
1591 The --close-branch flag can be used to mark the current branch
1591 The --close-branch flag can be used to mark the current branch
1592 head closed. When all heads of a branch are closed, the branch
1592 head closed. When all heads of a branch are closed, the branch
1593 will be considered closed and no longer listed.
1593 will be considered closed and no longer listed.
1594
1594
1595 The --amend flag can be used to amend the parent of the
1595 The --amend flag can be used to amend the parent of the
1596 working directory with a new commit that contains the changes
1596 working directory with a new commit that contains the changes
1597 in the parent in addition to those currently reported by :hg:`status`,
1597 in the parent in addition to those currently reported by :hg:`status`,
1598 if there are any. The old commit is stored in a backup bundle in
1598 if there are any. The old commit is stored in a backup bundle in
1599 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1599 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1600 on how to restore it).
1600 on how to restore it).
1601
1601
1602 Message, user and date are taken from the amended commit unless
1602 Message, user and date are taken from the amended commit unless
1603 specified. When a message isn't specified on the command line,
1603 specified. When a message isn't specified on the command line,
1604 the editor will open with the message of the amended commit.
1604 the editor will open with the message of the amended commit.
1605
1605
1606 It is not possible to amend public changesets (see :hg:`help phases`)
1606 It is not possible to amend public changesets (see :hg:`help phases`)
1607 or changesets that have children.
1607 or changesets that have children.
1608
1608
1609 See :hg:`help dates` for a list of formats valid for -d/--date.
1609 See :hg:`help dates` for a list of formats valid for -d/--date.
1610
1610
1611 Returns 0 on success, 1 if nothing changed.
1611 Returns 0 on success, 1 if nothing changed.
1612
1612
1613 .. container:: verbose
1613 .. container:: verbose
1614
1614
1615 Examples:
1615 Examples:
1616
1616
1617 - commit all files ending in .py::
1617 - commit all files ending in .py::
1618
1618
1619 hg commit --include "set:**.py"
1619 hg commit --include "set:**.py"
1620
1620
1621 - commit all non-binary files::
1621 - commit all non-binary files::
1622
1622
1623 hg commit --exclude "set:binary()"
1623 hg commit --exclude "set:binary()"
1624
1624
1625 - amend the current commit and set the date to now::
1625 - amend the current commit and set the date to now::
1626
1626
1627 hg commit --amend --date now
1627 hg commit --amend --date now
1628 """
1628 """
1629 wlock = lock = None
1629 wlock = lock = None
1630 try:
1630 try:
1631 wlock = repo.wlock()
1631 wlock = repo.wlock()
1632 lock = repo.lock()
1632 lock = repo.lock()
1633 return _docommit(ui, repo, *pats, **opts)
1633 return _docommit(ui, repo, *pats, **opts)
1634 finally:
1634 finally:
1635 release(lock, wlock)
1635 release(lock, wlock)
1636
1636
1637 def _docommit(ui, repo, *pats, **opts):
1637 def _docommit(ui, repo, *pats, **opts):
1638 if opts.get('interactive'):
1638 if opts.get('interactive'):
1639 opts.pop('interactive')
1639 opts.pop('interactive')
1640 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1640 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1641 cmdutil.recordfilter, *pats, **opts)
1641 cmdutil.recordfilter, *pats, **opts)
1642 # ret can be 0 (no changes to record) or the value returned by
1642 # ret can be 0 (no changes to record) or the value returned by
1643 # commit(), 1 if nothing changed or None on success.
1643 # commit(), 1 if nothing changed or None on success.
1644 return 1 if ret == 0 else ret
1644 return 1 if ret == 0 else ret
1645
1645
1646 if opts.get('subrepos'):
1646 if opts.get('subrepos'):
1647 if opts.get('amend'):
1647 if opts.get('amend'):
1648 raise error.Abort(_('cannot amend with --subrepos'))
1648 raise error.Abort(_('cannot amend with --subrepos'))
1649 # Let --subrepos on the command line override config setting.
1649 # Let --subrepos on the command line override config setting.
1650 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1650 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1651
1651
1652 cmdutil.checkunfinished(repo, commit=True)
1652 cmdutil.checkunfinished(repo, commit=True)
1653
1653
1654 branch = repo[None].branch()
1654 branch = repo[None].branch()
1655 bheads = repo.branchheads(branch)
1655 bheads = repo.branchheads(branch)
1656
1656
1657 extra = {}
1657 extra = {}
1658 if opts.get('close_branch'):
1658 if opts.get('close_branch'):
1659 extra['close'] = 1
1659 extra['close'] = 1
1660
1660
1661 if not bheads:
1661 if not bheads:
1662 raise error.Abort(_('can only close branch heads'))
1662 raise error.Abort(_('can only close branch heads'))
1663 elif opts.get('amend'):
1663 elif opts.get('amend'):
1664 if repo[None].parents()[0].p1().branch() != branch and \
1664 if repo[None].parents()[0].p1().branch() != branch and \
1665 repo[None].parents()[0].p2().branch() != branch:
1665 repo[None].parents()[0].p2().branch() != branch:
1666 raise error.Abort(_('can only close branch heads'))
1666 raise error.Abort(_('can only close branch heads'))
1667
1667
1668 if opts.get('amend'):
1668 if opts.get('amend'):
1669 if ui.configbool('ui', 'commitsubrepos'):
1669 if ui.configbool('ui', 'commitsubrepos'):
1670 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1670 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1671
1671
1672 old = repo['.']
1672 old = repo['.']
1673 if not old.mutable():
1673 if not old.mutable():
1674 raise error.Abort(_('cannot amend public changesets'))
1674 raise error.Abort(_('cannot amend public changesets'))
1675 if len(repo[None].parents()) > 1:
1675 if len(repo[None].parents()) > 1:
1676 raise error.Abort(_('cannot amend while merging'))
1676 raise error.Abort(_('cannot amend while merging'))
1677 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1677 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1678 if not allowunstable and old.children():
1678 if not allowunstable and old.children():
1679 raise error.Abort(_('cannot amend changeset with children'))
1679 raise error.Abort(_('cannot amend changeset with children'))
1680
1680
1681 # Currently histedit gets confused if an amend happens while histedit
1681 # Currently histedit gets confused if an amend happens while histedit
1682 # is in progress. Since we have a checkunfinished command, we are
1682 # is in progress. Since we have a checkunfinished command, we are
1683 # temporarily honoring it.
1683 # temporarily honoring it.
1684 #
1684 #
1685 # Note: eventually this guard will be removed. Please do not expect
1685 # Note: eventually this guard will be removed. Please do not expect
1686 # this behavior to remain.
1686 # this behavior to remain.
1687 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1687 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1688 cmdutil.checkunfinished(repo)
1688 cmdutil.checkunfinished(repo)
1689
1689
1690 # commitfunc is used only for temporary amend commit by cmdutil.amend
1690 # commitfunc is used only for temporary amend commit by cmdutil.amend
1691 def commitfunc(ui, repo, message, match, opts):
1691 def commitfunc(ui, repo, message, match, opts):
1692 return repo.commit(message,
1692 return repo.commit(message,
1693 opts.get('user') or old.user(),
1693 opts.get('user') or old.user(),
1694 opts.get('date') or old.date(),
1694 opts.get('date') or old.date(),
1695 match,
1695 match,
1696 extra=extra)
1696 extra=extra)
1697
1697
1698 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1698 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1699 if node == old.node():
1699 if node == old.node():
1700 ui.status(_("nothing changed\n"))
1700 ui.status(_("nothing changed\n"))
1701 return 1
1701 return 1
1702 else:
1702 else:
1703 def commitfunc(ui, repo, message, match, opts):
1703 def commitfunc(ui, repo, message, match, opts):
1704 backup = ui.backupconfig('phases', 'new-commit')
1704 backup = ui.backupconfig('phases', 'new-commit')
1705 baseui = repo.baseui
1705 baseui = repo.baseui
1706 basebackup = baseui.backupconfig('phases', 'new-commit')
1706 basebackup = baseui.backupconfig('phases', 'new-commit')
1707 try:
1707 try:
1708 if opts.get('secret'):
1708 if opts.get('secret'):
1709 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1709 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1710 # Propagate to subrepos
1710 # Propagate to subrepos
1711 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1711 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1712
1712
1713 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1713 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1714 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1714 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1715 return repo.commit(message, opts.get('user'), opts.get('date'),
1715 return repo.commit(message, opts.get('user'), opts.get('date'),
1716 match,
1716 match,
1717 editor=editor,
1717 editor=editor,
1718 extra=extra)
1718 extra=extra)
1719 finally:
1719 finally:
1720 ui.restoreconfig(backup)
1720 ui.restoreconfig(backup)
1721 repo.baseui.restoreconfig(basebackup)
1721 repo.baseui.restoreconfig(basebackup)
1722
1722
1723
1723
1724 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1724 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1725
1725
1726 if not node:
1726 if not node:
1727 stat = cmdutil.postcommitstatus(repo, pats, opts)
1727 stat = cmdutil.postcommitstatus(repo, pats, opts)
1728 if stat[3]:
1728 if stat[3]:
1729 ui.status(_("nothing changed (%d missing files, see "
1729 ui.status(_("nothing changed (%d missing files, see "
1730 "'hg status')\n") % len(stat[3]))
1730 "'hg status')\n") % len(stat[3]))
1731 else:
1731 else:
1732 ui.status(_("nothing changed\n"))
1732 ui.status(_("nothing changed\n"))
1733 return 1
1733 return 1
1734
1734
1735 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1735 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1736
1736
1737 @command('config|showconfig|debugconfig',
1737 @command('config|showconfig|debugconfig',
1738 [('u', 'untrusted', None, _('show untrusted configuration options')),
1738 [('u', 'untrusted', None, _('show untrusted configuration options')),
1739 ('e', 'edit', None, _('edit user config')),
1739 ('e', 'edit', None, _('edit user config')),
1740 ('l', 'local', None, _('edit repository config')),
1740 ('l', 'local', None, _('edit repository config')),
1741 ('g', 'global', None, _('edit global config'))] + formatteropts,
1741 ('g', 'global', None, _('edit global config'))] + formatteropts,
1742 _('[-u] [NAME]...'),
1742 _('[-u] [NAME]...'),
1743 optionalrepo=True)
1743 optionalrepo=True)
1744 def config(ui, repo, *values, **opts):
1744 def config(ui, repo, *values, **opts):
1745 """show combined config settings from all hgrc files
1745 """show combined config settings from all hgrc files
1746
1746
1747 With no arguments, print names and values of all config items.
1747 With no arguments, print names and values of all config items.
1748
1748
1749 With one argument of the form section.name, print just the value
1749 With one argument of the form section.name, print just the value
1750 of that config item.
1750 of that config item.
1751
1751
1752 With multiple arguments, print names and values of all config
1752 With multiple arguments, print names and values of all config
1753 items with matching section names.
1753 items with matching section names.
1754
1754
1755 With --edit, start an editor on the user-level config file. With
1755 With --edit, start an editor on the user-level config file. With
1756 --global, edit the system-wide config file. With --local, edit the
1756 --global, edit the system-wide config file. With --local, edit the
1757 repository-level config file.
1757 repository-level config file.
1758
1758
1759 With --debug, the source (filename and line number) is printed
1759 With --debug, the source (filename and line number) is printed
1760 for each config item.
1760 for each config item.
1761
1761
1762 See :hg:`help config` for more information about config files.
1762 See :hg:`help config` for more information about config files.
1763
1763
1764 Returns 0 on success, 1 if NAME does not exist.
1764 Returns 0 on success, 1 if NAME does not exist.
1765
1765
1766 """
1766 """
1767
1767
1768 if opts.get('edit') or opts.get('local') or opts.get('global'):
1768 if opts.get('edit') or opts.get('local') or opts.get('global'):
1769 if opts.get('local') and opts.get('global'):
1769 if opts.get('local') and opts.get('global'):
1770 raise error.Abort(_("can't use --local and --global together"))
1770 raise error.Abort(_("can't use --local and --global together"))
1771
1771
1772 if opts.get('local'):
1772 if opts.get('local'):
1773 if not repo:
1773 if not repo:
1774 raise error.Abort(_("can't use --local outside a repository"))
1774 raise error.Abort(_("can't use --local outside a repository"))
1775 paths = [repo.join('hgrc')]
1775 paths = [repo.join('hgrc')]
1776 elif opts.get('global'):
1776 elif opts.get('global'):
1777 paths = scmutil.systemrcpath()
1777 paths = scmutil.systemrcpath()
1778 else:
1778 else:
1779 paths = scmutil.userrcpath()
1779 paths = scmutil.userrcpath()
1780
1780
1781 for f in paths:
1781 for f in paths:
1782 if os.path.exists(f):
1782 if os.path.exists(f):
1783 break
1783 break
1784 else:
1784 else:
1785 if opts.get('global'):
1785 if opts.get('global'):
1786 samplehgrc = uimod.samplehgrcs['global']
1786 samplehgrc = uimod.samplehgrcs['global']
1787 elif opts.get('local'):
1787 elif opts.get('local'):
1788 samplehgrc = uimod.samplehgrcs['local']
1788 samplehgrc = uimod.samplehgrcs['local']
1789 else:
1789 else:
1790 samplehgrc = uimod.samplehgrcs['user']
1790 samplehgrc = uimod.samplehgrcs['user']
1791
1791
1792 f = paths[0]
1792 f = paths[0]
1793 fp = open(f, "w")
1793 fp = open(f, "w")
1794 fp.write(samplehgrc)
1794 fp.write(samplehgrc)
1795 fp.close()
1795 fp.close()
1796
1796
1797 editor = ui.geteditor()
1797 editor = ui.geteditor()
1798 ui.system("%s \"%s\"" % (editor, f),
1798 ui.system("%s \"%s\"" % (editor, f),
1799 onerr=error.Abort, errprefix=_("edit failed"))
1799 onerr=error.Abort, errprefix=_("edit failed"))
1800 return
1800 return
1801
1801
1802 fm = ui.formatter('config', opts)
1802 fm = ui.formatter('config', opts)
1803 for f in scmutil.rcpath():
1803 for f in scmutil.rcpath():
1804 ui.debug('read config from: %s\n' % f)
1804 ui.debug('read config from: %s\n' % f)
1805 untrusted = bool(opts.get('untrusted'))
1805 untrusted = bool(opts.get('untrusted'))
1806 if values:
1806 if values:
1807 sections = [v for v in values if '.' not in v]
1807 sections = [v for v in values if '.' not in v]
1808 items = [v for v in values if '.' in v]
1808 items = [v for v in values if '.' in v]
1809 if len(items) > 1 or items and sections:
1809 if len(items) > 1 or items and sections:
1810 raise error.Abort(_('only one config item permitted'))
1810 raise error.Abort(_('only one config item permitted'))
1811 matched = False
1811 matched = False
1812 for section, name, value in ui.walkconfig(untrusted=untrusted):
1812 for section, name, value in ui.walkconfig(untrusted=untrusted):
1813 source = ui.configsource(section, name, untrusted)
1813 source = ui.configsource(section, name, untrusted)
1814 value = str(value)
1814 value = str(value)
1815 if fm.isplain():
1815 if fm.isplain():
1816 source = source or 'none'
1816 source = source or 'none'
1817 value = value.replace('\n', '\\n')
1817 value = value.replace('\n', '\\n')
1818 entryname = section + '.' + name
1818 entryname = section + '.' + name
1819 if values:
1819 if values:
1820 for v in values:
1820 for v in values:
1821 if v == section:
1821 if v == section:
1822 fm.startitem()
1822 fm.startitem()
1823 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1823 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1824 fm.write('name value', '%s=%s\n', entryname, value)
1824 fm.write('name value', '%s=%s\n', entryname, value)
1825 matched = True
1825 matched = True
1826 elif v == entryname:
1826 elif v == entryname:
1827 fm.startitem()
1827 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 fm.write('value', '%s\n', value)
1829 fm.write('value', '%s\n', value)
1830 fm.data(name=entryname)
1830 fm.data(name=entryname)
1831 matched = True
1831 matched = True
1832 else:
1832 else:
1833 fm.startitem()
1833 fm.startitem()
1834 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1834 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1835 fm.write('name value', '%s=%s\n', entryname, value)
1835 fm.write('name value', '%s=%s\n', entryname, value)
1836 matched = True
1836 matched = True
1837 fm.end()
1837 fm.end()
1838 if matched:
1838 if matched:
1839 return 0
1839 return 0
1840 return 1
1840 return 1
1841
1841
1842 @command('copy|cp',
1842 @command('copy|cp',
1843 [('A', 'after', None, _('record a copy that has already occurred')),
1843 [('A', 'after', None, _('record a copy that has already occurred')),
1844 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1844 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1845 ] + walkopts + dryrunopts,
1845 ] + walkopts + dryrunopts,
1846 _('[OPTION]... [SOURCE]... DEST'))
1846 _('[OPTION]... [SOURCE]... DEST'))
1847 def copy(ui, repo, *pats, **opts):
1847 def copy(ui, repo, *pats, **opts):
1848 """mark files as copied for the next commit
1848 """mark files as copied for the next commit
1849
1849
1850 Mark dest as having copies of source files. If dest is a
1850 Mark dest as having copies of source files. If dest is a
1851 directory, copies are put in that directory. If dest is a file,
1851 directory, copies are put in that directory. If dest is a file,
1852 the source must be a single file.
1852 the source must be a single file.
1853
1853
1854 By default, this command copies the contents of files as they
1854 By default, this command copies the contents of files as they
1855 exist in the working directory. If invoked with -A/--after, the
1855 exist in the working directory. If invoked with -A/--after, the
1856 operation is recorded, but no copying is performed.
1856 operation is recorded, but no copying is performed.
1857
1857
1858 This command takes effect with the next commit. To undo a copy
1858 This command takes effect with the next commit. To undo a copy
1859 before that, see :hg:`revert`.
1859 before that, see :hg:`revert`.
1860
1860
1861 Returns 0 on success, 1 if errors are encountered.
1861 Returns 0 on success, 1 if errors are encountered.
1862 """
1862 """
1863 with repo.wlock(False):
1863 with repo.wlock(False):
1864 return cmdutil.copy(ui, repo, pats, opts)
1864 return cmdutil.copy(ui, repo, pats, opts)
1865
1865
1866 @command('debugknown', [], _('REPO ID...'), norepo=True)
1867 def debugknown(ui, repopath, *ids, **opts):
1868 """test whether node ids are known to a repo
1869
1870 Every ID must be a full-length hex node id string. Returns a list of 0s
1871 and 1s indicating unknown/known.
1872 """
1873 repo = hg.peer(ui, opts, repopath)
1874 if not repo.capable('known'):
1875 raise error.Abort("known() not supported by target repository")
1876 flags = repo.known([bin(s) for s in ids])
1877 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1878
1879 @command('debuglabelcomplete', [], _('LABEL...'))
1866 @command('debuglabelcomplete', [], _('LABEL...'))
1880 def debuglabelcomplete(ui, repo, *args):
1867 def debuglabelcomplete(ui, repo, *args):
1881 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1868 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1882 debugnamecomplete(ui, repo, *args)
1869 debugnamecomplete(ui, repo, *args)
1883
1870
1884 @command('debugmergestate', [], '')
1871 @command('debugmergestate', [], '')
1885 def debugmergestate(ui, repo, *args):
1872 def debugmergestate(ui, repo, *args):
1886 """print merge state
1873 """print merge state
1887
1874
1888 Use --verbose to print out information about whether v1 or v2 merge state
1875 Use --verbose to print out information about whether v1 or v2 merge state
1889 was chosen."""
1876 was chosen."""
1890 def _hashornull(h):
1877 def _hashornull(h):
1891 if h == nullhex:
1878 if h == nullhex:
1892 return 'null'
1879 return 'null'
1893 else:
1880 else:
1894 return h
1881 return h
1895
1882
1896 def printrecords(version):
1883 def printrecords(version):
1897 ui.write(('* version %s records\n') % version)
1884 ui.write(('* version %s records\n') % version)
1898 if version == 1:
1885 if version == 1:
1899 records = v1records
1886 records = v1records
1900 else:
1887 else:
1901 records = v2records
1888 records = v2records
1902
1889
1903 for rtype, record in records:
1890 for rtype, record in records:
1904 # pretty print some record types
1891 # pretty print some record types
1905 if rtype == 'L':
1892 if rtype == 'L':
1906 ui.write(('local: %s\n') % record)
1893 ui.write(('local: %s\n') % record)
1907 elif rtype == 'O':
1894 elif rtype == 'O':
1908 ui.write(('other: %s\n') % record)
1895 ui.write(('other: %s\n') % record)
1909 elif rtype == 'm':
1896 elif rtype == 'm':
1910 driver, mdstate = record.split('\0', 1)
1897 driver, mdstate = record.split('\0', 1)
1911 ui.write(('merge driver: %s (state "%s")\n')
1898 ui.write(('merge driver: %s (state "%s")\n')
1912 % (driver, mdstate))
1899 % (driver, mdstate))
1913 elif rtype in 'FDC':
1900 elif rtype in 'FDC':
1914 r = record.split('\0')
1901 r = record.split('\0')
1915 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1902 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1916 if version == 1:
1903 if version == 1:
1917 onode = 'not stored in v1 format'
1904 onode = 'not stored in v1 format'
1918 flags = r[7]
1905 flags = r[7]
1919 else:
1906 else:
1920 onode, flags = r[7:9]
1907 onode, flags = r[7:9]
1921 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1908 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1922 % (f, rtype, state, _hashornull(hash)))
1909 % (f, rtype, state, _hashornull(hash)))
1923 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1910 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1924 ui.write((' ancestor path: %s (node %s)\n')
1911 ui.write((' ancestor path: %s (node %s)\n')
1925 % (afile, _hashornull(anode)))
1912 % (afile, _hashornull(anode)))
1926 ui.write((' other path: %s (node %s)\n')
1913 ui.write((' other path: %s (node %s)\n')
1927 % (ofile, _hashornull(onode)))
1914 % (ofile, _hashornull(onode)))
1928 elif rtype == 'f':
1915 elif rtype == 'f':
1929 filename, rawextras = record.split('\0', 1)
1916 filename, rawextras = record.split('\0', 1)
1930 extras = rawextras.split('\0')
1917 extras = rawextras.split('\0')
1931 i = 0
1918 i = 0
1932 extrastrings = []
1919 extrastrings = []
1933 while i < len(extras):
1920 while i < len(extras):
1934 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1921 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1935 i += 2
1922 i += 2
1936
1923
1937 ui.write(('file extras: %s (%s)\n')
1924 ui.write(('file extras: %s (%s)\n')
1938 % (filename, ', '.join(extrastrings)))
1925 % (filename, ', '.join(extrastrings)))
1939 elif rtype == 'l':
1926 elif rtype == 'l':
1940 labels = record.split('\0', 2)
1927 labels = record.split('\0', 2)
1941 labels = [l for l in labels if len(l) > 0]
1928 labels = [l for l in labels if len(l) > 0]
1942 ui.write(('labels:\n'))
1929 ui.write(('labels:\n'))
1943 ui.write((' local: %s\n' % labels[0]))
1930 ui.write((' local: %s\n' % labels[0]))
1944 ui.write((' other: %s\n' % labels[1]))
1931 ui.write((' other: %s\n' % labels[1]))
1945 if len(labels) > 2:
1932 if len(labels) > 2:
1946 ui.write((' base: %s\n' % labels[2]))
1933 ui.write((' base: %s\n' % labels[2]))
1947 else:
1934 else:
1948 ui.write(('unrecognized entry: %s\t%s\n')
1935 ui.write(('unrecognized entry: %s\t%s\n')
1949 % (rtype, record.replace('\0', '\t')))
1936 % (rtype, record.replace('\0', '\t')))
1950
1937
1951 # Avoid mergestate.read() since it may raise an exception for unsupported
1938 # Avoid mergestate.read() since it may raise an exception for unsupported
1952 # merge state records. We shouldn't be doing this, but this is OK since this
1939 # merge state records. We shouldn't be doing this, but this is OK since this
1953 # command is pretty low-level.
1940 # command is pretty low-level.
1954 ms = mergemod.mergestate(repo)
1941 ms = mergemod.mergestate(repo)
1955
1942
1956 # sort so that reasonable information is on top
1943 # sort so that reasonable information is on top
1957 v1records = ms._readrecordsv1()
1944 v1records = ms._readrecordsv1()
1958 v2records = ms._readrecordsv2()
1945 v2records = ms._readrecordsv2()
1959 order = 'LOml'
1946 order = 'LOml'
1960 def key(r):
1947 def key(r):
1961 idx = order.find(r[0])
1948 idx = order.find(r[0])
1962 if idx == -1:
1949 if idx == -1:
1963 return (1, r[1])
1950 return (1, r[1])
1964 else:
1951 else:
1965 return (0, idx)
1952 return (0, idx)
1966 v1records.sort(key=key)
1953 v1records.sort(key=key)
1967 v2records.sort(key=key)
1954 v2records.sort(key=key)
1968
1955
1969 if not v1records and not v2records:
1956 if not v1records and not v2records:
1970 ui.write(('no merge state found\n'))
1957 ui.write(('no merge state found\n'))
1971 elif not v2records:
1958 elif not v2records:
1972 ui.note(('no version 2 merge state\n'))
1959 ui.note(('no version 2 merge state\n'))
1973 printrecords(1)
1960 printrecords(1)
1974 elif ms._v1v2match(v1records, v2records):
1961 elif ms._v1v2match(v1records, v2records):
1975 ui.note(('v1 and v2 states match: using v2\n'))
1962 ui.note(('v1 and v2 states match: using v2\n'))
1976 printrecords(2)
1963 printrecords(2)
1977 else:
1964 else:
1978 ui.note(('v1 and v2 states mismatch: using v1\n'))
1965 ui.note(('v1 and v2 states mismatch: using v1\n'))
1979 printrecords(1)
1966 printrecords(1)
1980 if ui.verbose:
1967 if ui.verbose:
1981 printrecords(2)
1968 printrecords(2)
1982
1969
1983 @command('debugnamecomplete', [], _('NAME...'))
1970 @command('debugnamecomplete', [], _('NAME...'))
1984 def debugnamecomplete(ui, repo, *args):
1971 def debugnamecomplete(ui, repo, *args):
1985 '''complete "names" - tags, open branch names, bookmark names'''
1972 '''complete "names" - tags, open branch names, bookmark names'''
1986
1973
1987 names = set()
1974 names = set()
1988 # since we previously only listed open branches, we will handle that
1975 # since we previously only listed open branches, we will handle that
1989 # specially (after this for loop)
1976 # specially (after this for loop)
1990 for name, ns in repo.names.iteritems():
1977 for name, ns in repo.names.iteritems():
1991 if name != 'branches':
1978 if name != 'branches':
1992 names.update(ns.listnames(repo))
1979 names.update(ns.listnames(repo))
1993 names.update(tag for (tag, heads, tip, closed)
1980 names.update(tag for (tag, heads, tip, closed)
1994 in repo.branchmap().iterbranches() if not closed)
1981 in repo.branchmap().iterbranches() if not closed)
1995 completions = set()
1982 completions = set()
1996 if not args:
1983 if not args:
1997 args = ['']
1984 args = ['']
1998 for a in args:
1985 for a in args:
1999 completions.update(n for n in names if n.startswith(a))
1986 completions.update(n for n in names if n.startswith(a))
2000 ui.write('\n'.join(sorted(completions)))
1987 ui.write('\n'.join(sorted(completions)))
2001 ui.write('\n')
1988 ui.write('\n')
2002
1989
2003 @command('debuglocks',
1990 @command('debuglocks',
2004 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1991 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2005 ('W', 'force-wlock', None,
1992 ('W', 'force-wlock', None,
2006 _('free the working state lock (DANGEROUS)'))],
1993 _('free the working state lock (DANGEROUS)'))],
2007 _('[OPTION]...'))
1994 _('[OPTION]...'))
2008 def debuglocks(ui, repo, **opts):
1995 def debuglocks(ui, repo, **opts):
2009 """show or modify state of locks
1996 """show or modify state of locks
2010
1997
2011 By default, this command will show which locks are held. This
1998 By default, this command will show which locks are held. This
2012 includes the user and process holding the lock, the amount of time
1999 includes the user and process holding the lock, the amount of time
2013 the lock has been held, and the machine name where the process is
2000 the lock has been held, and the machine name where the process is
2014 running if it's not local.
2001 running if it's not local.
2015
2002
2016 Locks protect the integrity of Mercurial's data, so should be
2003 Locks protect the integrity of Mercurial's data, so should be
2017 treated with care. System crashes or other interruptions may cause
2004 treated with care. System crashes or other interruptions may cause
2018 locks to not be properly released, though Mercurial will usually
2005 locks to not be properly released, though Mercurial will usually
2019 detect and remove such stale locks automatically.
2006 detect and remove such stale locks automatically.
2020
2007
2021 However, detecting stale locks may not always be possible (for
2008 However, detecting stale locks may not always be possible (for
2022 instance, on a shared filesystem). Removing locks may also be
2009 instance, on a shared filesystem). Removing locks may also be
2023 blocked by filesystem permissions.
2010 blocked by filesystem permissions.
2024
2011
2025 Returns 0 if no locks are held.
2012 Returns 0 if no locks are held.
2026
2013
2027 """
2014 """
2028
2015
2029 if opts.get('force_lock'):
2016 if opts.get('force_lock'):
2030 repo.svfs.unlink('lock')
2017 repo.svfs.unlink('lock')
2031 if opts.get('force_wlock'):
2018 if opts.get('force_wlock'):
2032 repo.vfs.unlink('wlock')
2019 repo.vfs.unlink('wlock')
2033 if opts.get('force_lock') or opts.get('force_lock'):
2020 if opts.get('force_lock') or opts.get('force_lock'):
2034 return 0
2021 return 0
2035
2022
2036 now = time.time()
2023 now = time.time()
2037 held = 0
2024 held = 0
2038
2025
2039 def report(vfs, name, method):
2026 def report(vfs, name, method):
2040 # this causes stale locks to get reaped for more accurate reporting
2027 # this causes stale locks to get reaped for more accurate reporting
2041 try:
2028 try:
2042 l = method(False)
2029 l = method(False)
2043 except error.LockHeld:
2030 except error.LockHeld:
2044 l = None
2031 l = None
2045
2032
2046 if l:
2033 if l:
2047 l.release()
2034 l.release()
2048 else:
2035 else:
2049 try:
2036 try:
2050 stat = vfs.lstat(name)
2037 stat = vfs.lstat(name)
2051 age = now - stat.st_mtime
2038 age = now - stat.st_mtime
2052 user = util.username(stat.st_uid)
2039 user = util.username(stat.st_uid)
2053 locker = vfs.readlock(name)
2040 locker = vfs.readlock(name)
2054 if ":" in locker:
2041 if ":" in locker:
2055 host, pid = locker.split(':')
2042 host, pid = locker.split(':')
2056 if host == socket.gethostname():
2043 if host == socket.gethostname():
2057 locker = 'user %s, process %s' % (user, pid)
2044 locker = 'user %s, process %s' % (user, pid)
2058 else:
2045 else:
2059 locker = 'user %s, process %s, host %s' \
2046 locker = 'user %s, process %s, host %s' \
2060 % (user, pid, host)
2047 % (user, pid, host)
2061 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2048 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2062 return 1
2049 return 1
2063 except OSError as e:
2050 except OSError as e:
2064 if e.errno != errno.ENOENT:
2051 if e.errno != errno.ENOENT:
2065 raise
2052 raise
2066
2053
2067 ui.write(("%-6s free\n") % (name + ":"))
2054 ui.write(("%-6s free\n") % (name + ":"))
2068 return 0
2055 return 0
2069
2056
2070 held += report(repo.svfs, "lock", repo.lock)
2057 held += report(repo.svfs, "lock", repo.lock)
2071 held += report(repo.vfs, "wlock", repo.wlock)
2058 held += report(repo.vfs, "wlock", repo.wlock)
2072
2059
2073 return held
2060 return held
2074
2061
2075 @command('debugobsolete',
2062 @command('debugobsolete',
2076 [('', 'flags', 0, _('markers flag')),
2063 [('', 'flags', 0, _('markers flag')),
2077 ('', 'record-parents', False,
2064 ('', 'record-parents', False,
2078 _('record parent information for the precursor')),
2065 _('record parent information for the precursor')),
2079 ('r', 'rev', [], _('display markers relevant to REV')),
2066 ('r', 'rev', [], _('display markers relevant to REV')),
2080 ('', 'index', False, _('display index of the marker')),
2067 ('', 'index', False, _('display index of the marker')),
2081 ('', 'delete', [], _('delete markers specified by indices')),
2068 ('', 'delete', [], _('delete markers specified by indices')),
2082 ] + commitopts2 + formatteropts,
2069 ] + commitopts2 + formatteropts,
2083 _('[OBSOLETED [REPLACEMENT ...]]'))
2070 _('[OBSOLETED [REPLACEMENT ...]]'))
2084 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2071 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2085 """create arbitrary obsolete marker
2072 """create arbitrary obsolete marker
2086
2073
2087 With no arguments, displays the list of obsolescence markers."""
2074 With no arguments, displays the list of obsolescence markers."""
2088
2075
2089 def parsenodeid(s):
2076 def parsenodeid(s):
2090 try:
2077 try:
2091 # We do not use revsingle/revrange functions here to accept
2078 # We do not use revsingle/revrange functions here to accept
2092 # arbitrary node identifiers, possibly not present in the
2079 # arbitrary node identifiers, possibly not present in the
2093 # local repository.
2080 # local repository.
2094 n = bin(s)
2081 n = bin(s)
2095 if len(n) != len(nullid):
2082 if len(n) != len(nullid):
2096 raise TypeError()
2083 raise TypeError()
2097 return n
2084 return n
2098 except TypeError:
2085 except TypeError:
2099 raise error.Abort('changeset references must be full hexadecimal '
2086 raise error.Abort('changeset references must be full hexadecimal '
2100 'node identifiers')
2087 'node identifiers')
2101
2088
2102 if opts.get('delete'):
2089 if opts.get('delete'):
2103 indices = []
2090 indices = []
2104 for v in opts.get('delete'):
2091 for v in opts.get('delete'):
2105 try:
2092 try:
2106 indices.append(int(v))
2093 indices.append(int(v))
2107 except ValueError:
2094 except ValueError:
2108 raise error.Abort(_('invalid index value: %r') % v,
2095 raise error.Abort(_('invalid index value: %r') % v,
2109 hint=_('use integers for indices'))
2096 hint=_('use integers for indices'))
2110
2097
2111 if repo.currenttransaction():
2098 if repo.currenttransaction():
2112 raise error.Abort(_('cannot delete obsmarkers in the middle '
2099 raise error.Abort(_('cannot delete obsmarkers in the middle '
2113 'of transaction.'))
2100 'of transaction.'))
2114
2101
2115 with repo.lock():
2102 with repo.lock():
2116 n = repair.deleteobsmarkers(repo.obsstore, indices)
2103 n = repair.deleteobsmarkers(repo.obsstore, indices)
2117 ui.write(_('deleted %i obsolescence markers\n') % n)
2104 ui.write(_('deleted %i obsolescence markers\n') % n)
2118
2105
2119 return
2106 return
2120
2107
2121 if precursor is not None:
2108 if precursor is not None:
2122 if opts['rev']:
2109 if opts['rev']:
2123 raise error.Abort('cannot select revision when creating marker')
2110 raise error.Abort('cannot select revision when creating marker')
2124 metadata = {}
2111 metadata = {}
2125 metadata['user'] = opts['user'] or ui.username()
2112 metadata['user'] = opts['user'] or ui.username()
2126 succs = tuple(parsenodeid(succ) for succ in successors)
2113 succs = tuple(parsenodeid(succ) for succ in successors)
2127 l = repo.lock()
2114 l = repo.lock()
2128 try:
2115 try:
2129 tr = repo.transaction('debugobsolete')
2116 tr = repo.transaction('debugobsolete')
2130 try:
2117 try:
2131 date = opts.get('date')
2118 date = opts.get('date')
2132 if date:
2119 if date:
2133 date = util.parsedate(date)
2120 date = util.parsedate(date)
2134 else:
2121 else:
2135 date = None
2122 date = None
2136 prec = parsenodeid(precursor)
2123 prec = parsenodeid(precursor)
2137 parents = None
2124 parents = None
2138 if opts['record_parents']:
2125 if opts['record_parents']:
2139 if prec not in repo.unfiltered():
2126 if prec not in repo.unfiltered():
2140 raise error.Abort('cannot used --record-parents on '
2127 raise error.Abort('cannot used --record-parents on '
2141 'unknown changesets')
2128 'unknown changesets')
2142 parents = repo.unfiltered()[prec].parents()
2129 parents = repo.unfiltered()[prec].parents()
2143 parents = tuple(p.node() for p in parents)
2130 parents = tuple(p.node() for p in parents)
2144 repo.obsstore.create(tr, prec, succs, opts['flags'],
2131 repo.obsstore.create(tr, prec, succs, opts['flags'],
2145 parents=parents, date=date,
2132 parents=parents, date=date,
2146 metadata=metadata)
2133 metadata=metadata)
2147 tr.close()
2134 tr.close()
2148 except ValueError as exc:
2135 except ValueError as exc:
2149 raise error.Abort(_('bad obsmarker input: %s') % exc)
2136 raise error.Abort(_('bad obsmarker input: %s') % exc)
2150 finally:
2137 finally:
2151 tr.release()
2138 tr.release()
2152 finally:
2139 finally:
2153 l.release()
2140 l.release()
2154 else:
2141 else:
2155 if opts['rev']:
2142 if opts['rev']:
2156 revs = scmutil.revrange(repo, opts['rev'])
2143 revs = scmutil.revrange(repo, opts['rev'])
2157 nodes = [repo[r].node() for r in revs]
2144 nodes = [repo[r].node() for r in revs]
2158 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2145 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2159 markers.sort(key=lambda x: x._data)
2146 markers.sort(key=lambda x: x._data)
2160 else:
2147 else:
2161 markers = obsolete.getmarkers(repo)
2148 markers = obsolete.getmarkers(repo)
2162
2149
2163 markerstoiter = markers
2150 markerstoiter = markers
2164 isrelevant = lambda m: True
2151 isrelevant = lambda m: True
2165 if opts.get('rev') and opts.get('index'):
2152 if opts.get('rev') and opts.get('index'):
2166 markerstoiter = obsolete.getmarkers(repo)
2153 markerstoiter = obsolete.getmarkers(repo)
2167 markerset = set(markers)
2154 markerset = set(markers)
2168 isrelevant = lambda m: m in markerset
2155 isrelevant = lambda m: m in markerset
2169
2156
2170 fm = ui.formatter('debugobsolete', opts)
2157 fm = ui.formatter('debugobsolete', opts)
2171 for i, m in enumerate(markerstoiter):
2158 for i, m in enumerate(markerstoiter):
2172 if not isrelevant(m):
2159 if not isrelevant(m):
2173 # marker can be irrelevant when we're iterating over a set
2160 # marker can be irrelevant when we're iterating over a set
2174 # of markers (markerstoiter) which is bigger than the set
2161 # of markers (markerstoiter) which is bigger than the set
2175 # of markers we want to display (markers)
2162 # of markers we want to display (markers)
2176 # this can happen if both --index and --rev options are
2163 # this can happen if both --index and --rev options are
2177 # provided and thus we need to iterate over all of the markers
2164 # provided and thus we need to iterate over all of the markers
2178 # to get the correct indices, but only display the ones that
2165 # to get the correct indices, but only display the ones that
2179 # are relevant to --rev value
2166 # are relevant to --rev value
2180 continue
2167 continue
2181 fm.startitem()
2168 fm.startitem()
2182 ind = i if opts.get('index') else None
2169 ind = i if opts.get('index') else None
2183 cmdutil.showmarker(fm, m, index=ind)
2170 cmdutil.showmarker(fm, m, index=ind)
2184 fm.end()
2171 fm.end()
2185
2172
2186 @command('debugpathcomplete',
2173 @command('debugpathcomplete',
2187 [('f', 'full', None, _('complete an entire path')),
2174 [('f', 'full', None, _('complete an entire path')),
2188 ('n', 'normal', None, _('show only normal files')),
2175 ('n', 'normal', None, _('show only normal files')),
2189 ('a', 'added', None, _('show only added files')),
2176 ('a', 'added', None, _('show only added files')),
2190 ('r', 'removed', None, _('show only removed files'))],
2177 ('r', 'removed', None, _('show only removed files'))],
2191 _('FILESPEC...'))
2178 _('FILESPEC...'))
2192 def debugpathcomplete(ui, repo, *specs, **opts):
2179 def debugpathcomplete(ui, repo, *specs, **opts):
2193 '''complete part or all of a tracked path
2180 '''complete part or all of a tracked path
2194
2181
2195 This command supports shells that offer path name completion. It
2182 This command supports shells that offer path name completion. It
2196 currently completes only files already known to the dirstate.
2183 currently completes only files already known to the dirstate.
2197
2184
2198 Completion extends only to the next path segment unless
2185 Completion extends only to the next path segment unless
2199 --full is specified, in which case entire paths are used.'''
2186 --full is specified, in which case entire paths are used.'''
2200
2187
2201 def complete(path, acceptable):
2188 def complete(path, acceptable):
2202 dirstate = repo.dirstate
2189 dirstate = repo.dirstate
2203 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2190 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2204 rootdir = repo.root + pycompat.ossep
2191 rootdir = repo.root + pycompat.ossep
2205 if spec != repo.root and not spec.startswith(rootdir):
2192 if spec != repo.root and not spec.startswith(rootdir):
2206 return [], []
2193 return [], []
2207 if os.path.isdir(spec):
2194 if os.path.isdir(spec):
2208 spec += '/'
2195 spec += '/'
2209 spec = spec[len(rootdir):]
2196 spec = spec[len(rootdir):]
2210 fixpaths = pycompat.ossep != '/'
2197 fixpaths = pycompat.ossep != '/'
2211 if fixpaths:
2198 if fixpaths:
2212 spec = spec.replace(pycompat.ossep, '/')
2199 spec = spec.replace(pycompat.ossep, '/')
2213 speclen = len(spec)
2200 speclen = len(spec)
2214 fullpaths = opts['full']
2201 fullpaths = opts['full']
2215 files, dirs = set(), set()
2202 files, dirs = set(), set()
2216 adddir, addfile = dirs.add, files.add
2203 adddir, addfile = dirs.add, files.add
2217 for f, st in dirstate.iteritems():
2204 for f, st in dirstate.iteritems():
2218 if f.startswith(spec) and st[0] in acceptable:
2205 if f.startswith(spec) and st[0] in acceptable:
2219 if fixpaths:
2206 if fixpaths:
2220 f = f.replace('/', pycompat.ossep)
2207 f = f.replace('/', pycompat.ossep)
2221 if fullpaths:
2208 if fullpaths:
2222 addfile(f)
2209 addfile(f)
2223 continue
2210 continue
2224 s = f.find(pycompat.ossep, speclen)
2211 s = f.find(pycompat.ossep, speclen)
2225 if s >= 0:
2212 if s >= 0:
2226 adddir(f[:s])
2213 adddir(f[:s])
2227 else:
2214 else:
2228 addfile(f)
2215 addfile(f)
2229 return files, dirs
2216 return files, dirs
2230
2217
2231 acceptable = ''
2218 acceptable = ''
2232 if opts['normal']:
2219 if opts['normal']:
2233 acceptable += 'nm'
2220 acceptable += 'nm'
2234 if opts['added']:
2221 if opts['added']:
2235 acceptable += 'a'
2222 acceptable += 'a'
2236 if opts['removed']:
2223 if opts['removed']:
2237 acceptable += 'r'
2224 acceptable += 'r'
2238 cwd = repo.getcwd()
2225 cwd = repo.getcwd()
2239 if not specs:
2226 if not specs:
2240 specs = ['.']
2227 specs = ['.']
2241
2228
2242 files, dirs = set(), set()
2229 files, dirs = set(), set()
2243 for spec in specs:
2230 for spec in specs:
2244 f, d = complete(spec, acceptable or 'nmar')
2231 f, d = complete(spec, acceptable or 'nmar')
2245 files.update(f)
2232 files.update(f)
2246 dirs.update(d)
2233 dirs.update(d)
2247 files.update(dirs)
2234 files.update(dirs)
2248 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2235 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2249 ui.write('\n')
2236 ui.write('\n')
2250
2237
2251 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2238 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2252 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2239 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2253 '''access the pushkey key/value protocol
2240 '''access the pushkey key/value protocol
2254
2241
2255 With two args, list the keys in the given namespace.
2242 With two args, list the keys in the given namespace.
2256
2243
2257 With five args, set a key to new if it currently is set to old.
2244 With five args, set a key to new if it currently is set to old.
2258 Reports success or failure.
2245 Reports success or failure.
2259 '''
2246 '''
2260
2247
2261 target = hg.peer(ui, {}, repopath)
2248 target = hg.peer(ui, {}, repopath)
2262 if keyinfo:
2249 if keyinfo:
2263 key, old, new = keyinfo
2250 key, old, new = keyinfo
2264 r = target.pushkey(namespace, key, old, new)
2251 r = target.pushkey(namespace, key, old, new)
2265 ui.status(str(r) + '\n')
2252 ui.status(str(r) + '\n')
2266 return not r
2253 return not r
2267 else:
2254 else:
2268 for k, v in sorted(target.listkeys(namespace).iteritems()):
2255 for k, v in sorted(target.listkeys(namespace).iteritems()):
2269 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2256 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2270 v.encode('string-escape')))
2257 v.encode('string-escape')))
2271
2258
2272 @command('debugpvec', [], _('A B'))
2259 @command('debugpvec', [], _('A B'))
2273 def debugpvec(ui, repo, a, b=None):
2260 def debugpvec(ui, repo, a, b=None):
2274 ca = scmutil.revsingle(repo, a)
2261 ca = scmutil.revsingle(repo, a)
2275 cb = scmutil.revsingle(repo, b)
2262 cb = scmutil.revsingle(repo, b)
2276 pa = pvec.ctxpvec(ca)
2263 pa = pvec.ctxpvec(ca)
2277 pb = pvec.ctxpvec(cb)
2264 pb = pvec.ctxpvec(cb)
2278 if pa == pb:
2265 if pa == pb:
2279 rel = "="
2266 rel = "="
2280 elif pa > pb:
2267 elif pa > pb:
2281 rel = ">"
2268 rel = ">"
2282 elif pa < pb:
2269 elif pa < pb:
2283 rel = "<"
2270 rel = "<"
2284 elif pa | pb:
2271 elif pa | pb:
2285 rel = "|"
2272 rel = "|"
2286 ui.write(_("a: %s\n") % pa)
2273 ui.write(_("a: %s\n") % pa)
2287 ui.write(_("b: %s\n") % pb)
2274 ui.write(_("b: %s\n") % pb)
2288 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2275 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2289 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2276 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2290 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2277 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2291 pa.distance(pb), rel))
2278 pa.distance(pb), rel))
2292
2279
2293 @command('debugrebuilddirstate|debugrebuildstate',
2280 @command('debugrebuilddirstate|debugrebuildstate',
2294 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2281 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2295 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2282 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2296 'the working copy parent')),
2283 'the working copy parent')),
2297 ],
2284 ],
2298 _('[-r REV]'))
2285 _('[-r REV]'))
2299 def debugrebuilddirstate(ui, repo, rev, **opts):
2286 def debugrebuilddirstate(ui, repo, rev, **opts):
2300 """rebuild the dirstate as it would look like for the given revision
2287 """rebuild the dirstate as it would look like for the given revision
2301
2288
2302 If no revision is specified the first current parent will be used.
2289 If no revision is specified the first current parent will be used.
2303
2290
2304 The dirstate will be set to the files of the given revision.
2291 The dirstate will be set to the files of the given revision.
2305 The actual working directory content or existing dirstate
2292 The actual working directory content or existing dirstate
2306 information such as adds or removes is not considered.
2293 information such as adds or removes is not considered.
2307
2294
2308 ``minimal`` will only rebuild the dirstate status for files that claim to be
2295 ``minimal`` will only rebuild the dirstate status for files that claim to be
2309 tracked but are not in the parent manifest, or that exist in the parent
2296 tracked but are not in the parent manifest, or that exist in the parent
2310 manifest but are not in the dirstate. It will not change adds, removes, or
2297 manifest but are not in the dirstate. It will not change adds, removes, or
2311 modified files that are in the working copy parent.
2298 modified files that are in the working copy parent.
2312
2299
2313 One use of this command is to make the next :hg:`status` invocation
2300 One use of this command is to make the next :hg:`status` invocation
2314 check the actual file content.
2301 check the actual file content.
2315 """
2302 """
2316 ctx = scmutil.revsingle(repo, rev)
2303 ctx = scmutil.revsingle(repo, rev)
2317 with repo.wlock():
2304 with repo.wlock():
2318 dirstate = repo.dirstate
2305 dirstate = repo.dirstate
2319 changedfiles = None
2306 changedfiles = None
2320 # See command doc for what minimal does.
2307 # See command doc for what minimal does.
2321 if opts.get('minimal'):
2308 if opts.get('minimal'):
2322 manifestfiles = set(ctx.manifest().keys())
2309 manifestfiles = set(ctx.manifest().keys())
2323 dirstatefiles = set(dirstate)
2310 dirstatefiles = set(dirstate)
2324 manifestonly = manifestfiles - dirstatefiles
2311 manifestonly = manifestfiles - dirstatefiles
2325 dsonly = dirstatefiles - manifestfiles
2312 dsonly = dirstatefiles - manifestfiles
2326 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2313 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2327 changedfiles = manifestonly | dsnotadded
2314 changedfiles = manifestonly | dsnotadded
2328
2315
2329 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2316 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2330
2317
2331 @command('debugrebuildfncache', [], '')
2318 @command('debugrebuildfncache', [], '')
2332 def debugrebuildfncache(ui, repo):
2319 def debugrebuildfncache(ui, repo):
2333 """rebuild the fncache file"""
2320 """rebuild the fncache file"""
2334 repair.rebuildfncache(ui, repo)
2321 repair.rebuildfncache(ui, repo)
2335
2322
2336 @command('debugrename',
2323 @command('debugrename',
2337 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2324 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2338 _('[-r REV] FILE'))
2325 _('[-r REV] FILE'))
2339 def debugrename(ui, repo, file1, *pats, **opts):
2326 def debugrename(ui, repo, file1, *pats, **opts):
2340 """dump rename information"""
2327 """dump rename information"""
2341
2328
2342 ctx = scmutil.revsingle(repo, opts.get('rev'))
2329 ctx = scmutil.revsingle(repo, opts.get('rev'))
2343 m = scmutil.match(ctx, (file1,) + pats, opts)
2330 m = scmutil.match(ctx, (file1,) + pats, opts)
2344 for abs in ctx.walk(m):
2331 for abs in ctx.walk(m):
2345 fctx = ctx[abs]
2332 fctx = ctx[abs]
2346 o = fctx.filelog().renamed(fctx.filenode())
2333 o = fctx.filelog().renamed(fctx.filenode())
2347 rel = m.rel(abs)
2334 rel = m.rel(abs)
2348 if o:
2335 if o:
2349 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2336 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2350 else:
2337 else:
2351 ui.write(_("%s not renamed\n") % rel)
2338 ui.write(_("%s not renamed\n") % rel)
2352
2339
2353 @command('debugrevlog', debugrevlogopts +
2340 @command('debugrevlog', debugrevlogopts +
2354 [('d', 'dump', False, _('dump index data'))],
2341 [('d', 'dump', False, _('dump index data'))],
2355 _('-c|-m|FILE'),
2342 _('-c|-m|FILE'),
2356 optionalrepo=True)
2343 optionalrepo=True)
2357 def debugrevlog(ui, repo, file_=None, **opts):
2344 def debugrevlog(ui, repo, file_=None, **opts):
2358 """show data and statistics about a revlog"""
2345 """show data and statistics about a revlog"""
2359 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2346 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2360
2347
2361 if opts.get("dump"):
2348 if opts.get("dump"):
2362 numrevs = len(r)
2349 numrevs = len(r)
2363 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2350 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2364 " rawsize totalsize compression heads chainlen\n"))
2351 " rawsize totalsize compression heads chainlen\n"))
2365 ts = 0
2352 ts = 0
2366 heads = set()
2353 heads = set()
2367
2354
2368 for rev in xrange(numrevs):
2355 for rev in xrange(numrevs):
2369 dbase = r.deltaparent(rev)
2356 dbase = r.deltaparent(rev)
2370 if dbase == -1:
2357 if dbase == -1:
2371 dbase = rev
2358 dbase = rev
2372 cbase = r.chainbase(rev)
2359 cbase = r.chainbase(rev)
2373 clen = r.chainlen(rev)
2360 clen = r.chainlen(rev)
2374 p1, p2 = r.parentrevs(rev)
2361 p1, p2 = r.parentrevs(rev)
2375 rs = r.rawsize(rev)
2362 rs = r.rawsize(rev)
2376 ts = ts + rs
2363 ts = ts + rs
2377 heads -= set(r.parentrevs(rev))
2364 heads -= set(r.parentrevs(rev))
2378 heads.add(rev)
2365 heads.add(rev)
2379 try:
2366 try:
2380 compression = ts / r.end(rev)
2367 compression = ts / r.end(rev)
2381 except ZeroDivisionError:
2368 except ZeroDivisionError:
2382 compression = 0
2369 compression = 0
2383 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2370 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2384 "%11d %5d %8d\n" %
2371 "%11d %5d %8d\n" %
2385 (rev, p1, p2, r.start(rev), r.end(rev),
2372 (rev, p1, p2, r.start(rev), r.end(rev),
2386 r.start(dbase), r.start(cbase),
2373 r.start(dbase), r.start(cbase),
2387 r.start(p1), r.start(p2),
2374 r.start(p1), r.start(p2),
2388 rs, ts, compression, len(heads), clen))
2375 rs, ts, compression, len(heads), clen))
2389 return 0
2376 return 0
2390
2377
2391 v = r.version
2378 v = r.version
2392 format = v & 0xFFFF
2379 format = v & 0xFFFF
2393 flags = []
2380 flags = []
2394 gdelta = False
2381 gdelta = False
2395 if v & revlog.REVLOGNGINLINEDATA:
2382 if v & revlog.REVLOGNGINLINEDATA:
2396 flags.append('inline')
2383 flags.append('inline')
2397 if v & revlog.REVLOGGENERALDELTA:
2384 if v & revlog.REVLOGGENERALDELTA:
2398 gdelta = True
2385 gdelta = True
2399 flags.append('generaldelta')
2386 flags.append('generaldelta')
2400 if not flags:
2387 if not flags:
2401 flags = ['(none)']
2388 flags = ['(none)']
2402
2389
2403 nummerges = 0
2390 nummerges = 0
2404 numfull = 0
2391 numfull = 0
2405 numprev = 0
2392 numprev = 0
2406 nump1 = 0
2393 nump1 = 0
2407 nump2 = 0
2394 nump2 = 0
2408 numother = 0
2395 numother = 0
2409 nump1prev = 0
2396 nump1prev = 0
2410 nump2prev = 0
2397 nump2prev = 0
2411 chainlengths = []
2398 chainlengths = []
2412
2399
2413 datasize = [None, 0, 0]
2400 datasize = [None, 0, 0]
2414 fullsize = [None, 0, 0]
2401 fullsize = [None, 0, 0]
2415 deltasize = [None, 0, 0]
2402 deltasize = [None, 0, 0]
2416 chunktypecounts = {}
2403 chunktypecounts = {}
2417 chunktypesizes = {}
2404 chunktypesizes = {}
2418
2405
2419 def addsize(size, l):
2406 def addsize(size, l):
2420 if l[0] is None or size < l[0]:
2407 if l[0] is None or size < l[0]:
2421 l[0] = size
2408 l[0] = size
2422 if size > l[1]:
2409 if size > l[1]:
2423 l[1] = size
2410 l[1] = size
2424 l[2] += size
2411 l[2] += size
2425
2412
2426 numrevs = len(r)
2413 numrevs = len(r)
2427 for rev in xrange(numrevs):
2414 for rev in xrange(numrevs):
2428 p1, p2 = r.parentrevs(rev)
2415 p1, p2 = r.parentrevs(rev)
2429 delta = r.deltaparent(rev)
2416 delta = r.deltaparent(rev)
2430 if format > 0:
2417 if format > 0:
2431 addsize(r.rawsize(rev), datasize)
2418 addsize(r.rawsize(rev), datasize)
2432 if p2 != nullrev:
2419 if p2 != nullrev:
2433 nummerges += 1
2420 nummerges += 1
2434 size = r.length(rev)
2421 size = r.length(rev)
2435 if delta == nullrev:
2422 if delta == nullrev:
2436 chainlengths.append(0)
2423 chainlengths.append(0)
2437 numfull += 1
2424 numfull += 1
2438 addsize(size, fullsize)
2425 addsize(size, fullsize)
2439 else:
2426 else:
2440 chainlengths.append(chainlengths[delta] + 1)
2427 chainlengths.append(chainlengths[delta] + 1)
2441 addsize(size, deltasize)
2428 addsize(size, deltasize)
2442 if delta == rev - 1:
2429 if delta == rev - 1:
2443 numprev += 1
2430 numprev += 1
2444 if delta == p1:
2431 if delta == p1:
2445 nump1prev += 1
2432 nump1prev += 1
2446 elif delta == p2:
2433 elif delta == p2:
2447 nump2prev += 1
2434 nump2prev += 1
2448 elif delta == p1:
2435 elif delta == p1:
2449 nump1 += 1
2436 nump1 += 1
2450 elif delta == p2:
2437 elif delta == p2:
2451 nump2 += 1
2438 nump2 += 1
2452 elif delta != nullrev:
2439 elif delta != nullrev:
2453 numother += 1
2440 numother += 1
2454
2441
2455 # Obtain data on the raw chunks in the revlog.
2442 # Obtain data on the raw chunks in the revlog.
2456 chunk = r._chunkraw(rev, rev)[1]
2443 chunk = r._chunkraw(rev, rev)[1]
2457 if chunk:
2444 if chunk:
2458 chunktype = chunk[0]
2445 chunktype = chunk[0]
2459 else:
2446 else:
2460 chunktype = 'empty'
2447 chunktype = 'empty'
2461
2448
2462 if chunktype not in chunktypecounts:
2449 if chunktype not in chunktypecounts:
2463 chunktypecounts[chunktype] = 0
2450 chunktypecounts[chunktype] = 0
2464 chunktypesizes[chunktype] = 0
2451 chunktypesizes[chunktype] = 0
2465
2452
2466 chunktypecounts[chunktype] += 1
2453 chunktypecounts[chunktype] += 1
2467 chunktypesizes[chunktype] += size
2454 chunktypesizes[chunktype] += size
2468
2455
2469 # Adjust size min value for empty cases
2456 # Adjust size min value for empty cases
2470 for size in (datasize, fullsize, deltasize):
2457 for size in (datasize, fullsize, deltasize):
2471 if size[0] is None:
2458 if size[0] is None:
2472 size[0] = 0
2459 size[0] = 0
2473
2460
2474 numdeltas = numrevs - numfull
2461 numdeltas = numrevs - numfull
2475 numoprev = numprev - nump1prev - nump2prev
2462 numoprev = numprev - nump1prev - nump2prev
2476 totalrawsize = datasize[2]
2463 totalrawsize = datasize[2]
2477 datasize[2] /= numrevs
2464 datasize[2] /= numrevs
2478 fulltotal = fullsize[2]
2465 fulltotal = fullsize[2]
2479 fullsize[2] /= numfull
2466 fullsize[2] /= numfull
2480 deltatotal = deltasize[2]
2467 deltatotal = deltasize[2]
2481 if numrevs - numfull > 0:
2468 if numrevs - numfull > 0:
2482 deltasize[2] /= numrevs - numfull
2469 deltasize[2] /= numrevs - numfull
2483 totalsize = fulltotal + deltatotal
2470 totalsize = fulltotal + deltatotal
2484 avgchainlen = sum(chainlengths) / numrevs
2471 avgchainlen = sum(chainlengths) / numrevs
2485 maxchainlen = max(chainlengths)
2472 maxchainlen = max(chainlengths)
2486 compratio = 1
2473 compratio = 1
2487 if totalsize:
2474 if totalsize:
2488 compratio = totalrawsize / totalsize
2475 compratio = totalrawsize / totalsize
2489
2476
2490 basedfmtstr = '%%%dd\n'
2477 basedfmtstr = '%%%dd\n'
2491 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2478 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2492
2479
2493 def dfmtstr(max):
2480 def dfmtstr(max):
2494 return basedfmtstr % len(str(max))
2481 return basedfmtstr % len(str(max))
2495 def pcfmtstr(max, padding=0):
2482 def pcfmtstr(max, padding=0):
2496 return basepcfmtstr % (len(str(max)), ' ' * padding)
2483 return basepcfmtstr % (len(str(max)), ' ' * padding)
2497
2484
2498 def pcfmt(value, total):
2485 def pcfmt(value, total):
2499 if total:
2486 if total:
2500 return (value, 100 * float(value) / total)
2487 return (value, 100 * float(value) / total)
2501 else:
2488 else:
2502 return value, 100.0
2489 return value, 100.0
2503
2490
2504 ui.write(('format : %d\n') % format)
2491 ui.write(('format : %d\n') % format)
2505 ui.write(('flags : %s\n') % ', '.join(flags))
2492 ui.write(('flags : %s\n') % ', '.join(flags))
2506
2493
2507 ui.write('\n')
2494 ui.write('\n')
2508 fmt = pcfmtstr(totalsize)
2495 fmt = pcfmtstr(totalsize)
2509 fmt2 = dfmtstr(totalsize)
2496 fmt2 = dfmtstr(totalsize)
2510 ui.write(('revisions : ') + fmt2 % numrevs)
2497 ui.write(('revisions : ') + fmt2 % numrevs)
2511 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2498 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2512 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2499 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2513 ui.write(('revisions : ') + fmt2 % numrevs)
2500 ui.write(('revisions : ') + fmt2 % numrevs)
2514 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2501 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2515 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2502 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2516 ui.write(('revision size : ') + fmt2 % totalsize)
2503 ui.write(('revision size : ') + fmt2 % totalsize)
2517 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2504 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2518 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2505 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2519
2506
2520 def fmtchunktype(chunktype):
2507 def fmtchunktype(chunktype):
2521 if chunktype == 'empty':
2508 if chunktype == 'empty':
2522 return ' %s : ' % chunktype
2509 return ' %s : ' % chunktype
2523 elif chunktype in string.ascii_letters:
2510 elif chunktype in string.ascii_letters:
2524 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2511 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2525 else:
2512 else:
2526 return ' 0x%s : ' % hex(chunktype)
2513 return ' 0x%s : ' % hex(chunktype)
2527
2514
2528 ui.write('\n')
2515 ui.write('\n')
2529 ui.write(('chunks : ') + fmt2 % numrevs)
2516 ui.write(('chunks : ') + fmt2 % numrevs)
2530 for chunktype in sorted(chunktypecounts):
2517 for chunktype in sorted(chunktypecounts):
2531 ui.write(fmtchunktype(chunktype))
2518 ui.write(fmtchunktype(chunktype))
2532 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2519 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2533 ui.write(('chunks size : ') + fmt2 % totalsize)
2520 ui.write(('chunks size : ') + fmt2 % totalsize)
2534 for chunktype in sorted(chunktypecounts):
2521 for chunktype in sorted(chunktypecounts):
2535 ui.write(fmtchunktype(chunktype))
2522 ui.write(fmtchunktype(chunktype))
2536 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2523 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2537
2524
2538 ui.write('\n')
2525 ui.write('\n')
2539 fmt = dfmtstr(max(avgchainlen, compratio))
2526 fmt = dfmtstr(max(avgchainlen, compratio))
2540 ui.write(('avg chain length : ') + fmt % avgchainlen)
2527 ui.write(('avg chain length : ') + fmt % avgchainlen)
2541 ui.write(('max chain length : ') + fmt % maxchainlen)
2528 ui.write(('max chain length : ') + fmt % maxchainlen)
2542 ui.write(('compression ratio : ') + fmt % compratio)
2529 ui.write(('compression ratio : ') + fmt % compratio)
2543
2530
2544 if format > 0:
2531 if format > 0:
2545 ui.write('\n')
2532 ui.write('\n')
2546 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2533 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2547 % tuple(datasize))
2534 % tuple(datasize))
2548 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2535 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2549 % tuple(fullsize))
2536 % tuple(fullsize))
2550 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2537 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2551 % tuple(deltasize))
2538 % tuple(deltasize))
2552
2539
2553 if numdeltas > 0:
2540 if numdeltas > 0:
2554 ui.write('\n')
2541 ui.write('\n')
2555 fmt = pcfmtstr(numdeltas)
2542 fmt = pcfmtstr(numdeltas)
2556 fmt2 = pcfmtstr(numdeltas, 4)
2543 fmt2 = pcfmtstr(numdeltas, 4)
2557 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2544 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2558 if numprev > 0:
2545 if numprev > 0:
2559 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2546 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2560 numprev))
2547 numprev))
2561 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2548 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2562 numprev))
2549 numprev))
2563 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2550 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2564 numprev))
2551 numprev))
2565 if gdelta:
2552 if gdelta:
2566 ui.write(('deltas against p1 : ')
2553 ui.write(('deltas against p1 : ')
2567 + fmt % pcfmt(nump1, numdeltas))
2554 + fmt % pcfmt(nump1, numdeltas))
2568 ui.write(('deltas against p2 : ')
2555 ui.write(('deltas against p2 : ')
2569 + fmt % pcfmt(nump2, numdeltas))
2556 + fmt % pcfmt(nump2, numdeltas))
2570 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2557 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2571 numdeltas))
2558 numdeltas))
2572
2559
2573 @command('debugrevspec',
2560 @command('debugrevspec',
2574 [('', 'optimize', None,
2561 [('', 'optimize', None,
2575 _('print parsed tree after optimizing (DEPRECATED)')),
2562 _('print parsed tree after optimizing (DEPRECATED)')),
2576 ('p', 'show-stage', [],
2563 ('p', 'show-stage', [],
2577 _('print parsed tree at the given stage'), _('NAME')),
2564 _('print parsed tree at the given stage'), _('NAME')),
2578 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2565 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2579 ('', 'verify-optimized', False, _('verify optimized result')),
2566 ('', 'verify-optimized', False, _('verify optimized result')),
2580 ],
2567 ],
2581 ('REVSPEC'))
2568 ('REVSPEC'))
2582 def debugrevspec(ui, repo, expr, **opts):
2569 def debugrevspec(ui, repo, expr, **opts):
2583 """parse and apply a revision specification
2570 """parse and apply a revision specification
2584
2571
2585 Use -p/--show-stage option to print the parsed tree at the given stages.
2572 Use -p/--show-stage option to print the parsed tree at the given stages.
2586 Use -p all to print tree at every stage.
2573 Use -p all to print tree at every stage.
2587
2574
2588 Use --verify-optimized to compare the optimized result with the unoptimized
2575 Use --verify-optimized to compare the optimized result with the unoptimized
2589 one. Returns 1 if the optimized result differs.
2576 one. Returns 1 if the optimized result differs.
2590 """
2577 """
2591 stages = [
2578 stages = [
2592 ('parsed', lambda tree: tree),
2579 ('parsed', lambda tree: tree),
2593 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2580 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2594 ('concatenated', revset.foldconcat),
2581 ('concatenated', revset.foldconcat),
2595 ('analyzed', revset.analyze),
2582 ('analyzed', revset.analyze),
2596 ('optimized', revset.optimize),
2583 ('optimized', revset.optimize),
2597 ]
2584 ]
2598 if opts['no_optimized']:
2585 if opts['no_optimized']:
2599 stages = stages[:-1]
2586 stages = stages[:-1]
2600 if opts['verify_optimized'] and opts['no_optimized']:
2587 if opts['verify_optimized'] and opts['no_optimized']:
2601 raise error.Abort(_('cannot use --verify-optimized with '
2588 raise error.Abort(_('cannot use --verify-optimized with '
2602 '--no-optimized'))
2589 '--no-optimized'))
2603 stagenames = set(n for n, f in stages)
2590 stagenames = set(n for n, f in stages)
2604
2591
2605 showalways = set()
2592 showalways = set()
2606 showchanged = set()
2593 showchanged = set()
2607 if ui.verbose and not opts['show_stage']:
2594 if ui.verbose and not opts['show_stage']:
2608 # show parsed tree by --verbose (deprecated)
2595 # show parsed tree by --verbose (deprecated)
2609 showalways.add('parsed')
2596 showalways.add('parsed')
2610 showchanged.update(['expanded', 'concatenated'])
2597 showchanged.update(['expanded', 'concatenated'])
2611 if opts['optimize']:
2598 if opts['optimize']:
2612 showalways.add('optimized')
2599 showalways.add('optimized')
2613 if opts['show_stage'] and opts['optimize']:
2600 if opts['show_stage'] and opts['optimize']:
2614 raise error.Abort(_('cannot use --optimize with --show-stage'))
2601 raise error.Abort(_('cannot use --optimize with --show-stage'))
2615 if opts['show_stage'] == ['all']:
2602 if opts['show_stage'] == ['all']:
2616 showalways.update(stagenames)
2603 showalways.update(stagenames)
2617 else:
2604 else:
2618 for n in opts['show_stage']:
2605 for n in opts['show_stage']:
2619 if n not in stagenames:
2606 if n not in stagenames:
2620 raise error.Abort(_('invalid stage name: %s') % n)
2607 raise error.Abort(_('invalid stage name: %s') % n)
2621 showalways.update(opts['show_stage'])
2608 showalways.update(opts['show_stage'])
2622
2609
2623 treebystage = {}
2610 treebystage = {}
2624 printedtree = None
2611 printedtree = None
2625 tree = revset.parse(expr, lookup=repo.__contains__)
2612 tree = revset.parse(expr, lookup=repo.__contains__)
2626 for n, f in stages:
2613 for n, f in stages:
2627 treebystage[n] = tree = f(tree)
2614 treebystage[n] = tree = f(tree)
2628 if n in showalways or (n in showchanged and tree != printedtree):
2615 if n in showalways or (n in showchanged and tree != printedtree):
2629 if opts['show_stage'] or n != 'parsed':
2616 if opts['show_stage'] or n != 'parsed':
2630 ui.write(("* %s:\n") % n)
2617 ui.write(("* %s:\n") % n)
2631 ui.write(revset.prettyformat(tree), "\n")
2618 ui.write(revset.prettyformat(tree), "\n")
2632 printedtree = tree
2619 printedtree = tree
2633
2620
2634 if opts['verify_optimized']:
2621 if opts['verify_optimized']:
2635 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2622 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2636 brevs = revset.makematcher(treebystage['optimized'])(repo)
2623 brevs = revset.makematcher(treebystage['optimized'])(repo)
2637 if ui.verbose:
2624 if ui.verbose:
2638 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2625 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2639 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2626 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2640 arevs = list(arevs)
2627 arevs = list(arevs)
2641 brevs = list(brevs)
2628 brevs = list(brevs)
2642 if arevs == brevs:
2629 if arevs == brevs:
2643 return 0
2630 return 0
2644 ui.write(('--- analyzed\n'), label='diff.file_a')
2631 ui.write(('--- analyzed\n'), label='diff.file_a')
2645 ui.write(('+++ optimized\n'), label='diff.file_b')
2632 ui.write(('+++ optimized\n'), label='diff.file_b')
2646 sm = difflib.SequenceMatcher(None, arevs, brevs)
2633 sm = difflib.SequenceMatcher(None, arevs, brevs)
2647 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2634 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2648 if tag in ('delete', 'replace'):
2635 if tag in ('delete', 'replace'):
2649 for c in arevs[alo:ahi]:
2636 for c in arevs[alo:ahi]:
2650 ui.write('-%s\n' % c, label='diff.deleted')
2637 ui.write('-%s\n' % c, label='diff.deleted')
2651 if tag in ('insert', 'replace'):
2638 if tag in ('insert', 'replace'):
2652 for c in brevs[blo:bhi]:
2639 for c in brevs[blo:bhi]:
2653 ui.write('+%s\n' % c, label='diff.inserted')
2640 ui.write('+%s\n' % c, label='diff.inserted')
2654 if tag == 'equal':
2641 if tag == 'equal':
2655 for c in arevs[alo:ahi]:
2642 for c in arevs[alo:ahi]:
2656 ui.write(' %s\n' % c)
2643 ui.write(' %s\n' % c)
2657 return 1
2644 return 1
2658
2645
2659 func = revset.makematcher(tree)
2646 func = revset.makematcher(tree)
2660 revs = func(repo)
2647 revs = func(repo)
2661 if ui.verbose:
2648 if ui.verbose:
2662 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2649 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
2663 for c in revs:
2650 for c in revs:
2664 ui.write("%s\n" % c)
2651 ui.write("%s\n" % c)
2665
2652
2666 @command('debugsetparents', [], _('REV1 [REV2]'))
2653 @command('debugsetparents', [], _('REV1 [REV2]'))
2667 def debugsetparents(ui, repo, rev1, rev2=None):
2654 def debugsetparents(ui, repo, rev1, rev2=None):
2668 """manually set the parents of the current working directory
2655 """manually set the parents of the current working directory
2669
2656
2670 This is useful for writing repository conversion tools, but should
2657 This is useful for writing repository conversion tools, but should
2671 be used with care. For example, neither the working directory nor the
2658 be used with care. For example, neither the working directory nor the
2672 dirstate is updated, so file status may be incorrect after running this
2659 dirstate is updated, so file status may be incorrect after running this
2673 command.
2660 command.
2674
2661
2675 Returns 0 on success.
2662 Returns 0 on success.
2676 """
2663 """
2677
2664
2678 r1 = scmutil.revsingle(repo, rev1).node()
2665 r1 = scmutil.revsingle(repo, rev1).node()
2679 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2666 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2680
2667
2681 with repo.wlock():
2668 with repo.wlock():
2682 repo.setparents(r1, r2)
2669 repo.setparents(r1, r2)
2683
2670
2684 @command('debugdirstate|debugstate',
2671 @command('debugdirstate|debugstate',
2685 [('', 'nodates', None, _('do not display the saved mtime')),
2672 [('', 'nodates', None, _('do not display the saved mtime')),
2686 ('', 'datesort', None, _('sort by saved mtime'))],
2673 ('', 'datesort', None, _('sort by saved mtime'))],
2687 _('[OPTION]...'))
2674 _('[OPTION]...'))
2688 def debugstate(ui, repo, **opts):
2675 def debugstate(ui, repo, **opts):
2689 """show the contents of the current dirstate"""
2676 """show the contents of the current dirstate"""
2690
2677
2691 nodates = opts.get('nodates')
2678 nodates = opts.get('nodates')
2692 datesort = opts.get('datesort')
2679 datesort = opts.get('datesort')
2693
2680
2694 timestr = ""
2681 timestr = ""
2695 if datesort:
2682 if datesort:
2696 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2683 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2697 else:
2684 else:
2698 keyfunc = None # sort by filename
2685 keyfunc = None # sort by filename
2699 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2686 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2700 if ent[3] == -1:
2687 if ent[3] == -1:
2701 timestr = 'unset '
2688 timestr = 'unset '
2702 elif nodates:
2689 elif nodates:
2703 timestr = 'set '
2690 timestr = 'set '
2704 else:
2691 else:
2705 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2692 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2706 time.localtime(ent[3]))
2693 time.localtime(ent[3]))
2707 if ent[1] & 0o20000:
2694 if ent[1] & 0o20000:
2708 mode = 'lnk'
2695 mode = 'lnk'
2709 else:
2696 else:
2710 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2697 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2711 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2698 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2712 for f in repo.dirstate.copies():
2699 for f in repo.dirstate.copies():
2713 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2700 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2714
2701
2715 @command('debugsub',
2702 @command('debugsub',
2716 [('r', 'rev', '',
2703 [('r', 'rev', '',
2717 _('revision to check'), _('REV'))],
2704 _('revision to check'), _('REV'))],
2718 _('[-r REV] [REV]'))
2705 _('[-r REV] [REV]'))
2719 def debugsub(ui, repo, rev=None):
2706 def debugsub(ui, repo, rev=None):
2720 ctx = scmutil.revsingle(repo, rev, None)
2707 ctx = scmutil.revsingle(repo, rev, None)
2721 for k, v in sorted(ctx.substate.items()):
2708 for k, v in sorted(ctx.substate.items()):
2722 ui.write(('path %s\n') % k)
2709 ui.write(('path %s\n') % k)
2723 ui.write((' source %s\n') % v[0])
2710 ui.write((' source %s\n') % v[0])
2724 ui.write((' revision %s\n') % v[1])
2711 ui.write((' revision %s\n') % v[1])
2725
2712
2726 @command('debugsuccessorssets',
2713 @command('debugsuccessorssets',
2727 [],
2714 [],
2728 _('[REV]'))
2715 _('[REV]'))
2729 def debugsuccessorssets(ui, repo, *revs):
2716 def debugsuccessorssets(ui, repo, *revs):
2730 """show set of successors for revision
2717 """show set of successors for revision
2731
2718
2732 A successors set of changeset A is a consistent group of revisions that
2719 A successors set of changeset A is a consistent group of revisions that
2733 succeed A. It contains non-obsolete changesets only.
2720 succeed A. It contains non-obsolete changesets only.
2734
2721
2735 In most cases a changeset A has a single successors set containing a single
2722 In most cases a changeset A has a single successors set containing a single
2736 successor (changeset A replaced by A').
2723 successor (changeset A replaced by A').
2737
2724
2738 A changeset that is made obsolete with no successors are called "pruned".
2725 A changeset that is made obsolete with no successors are called "pruned".
2739 Such changesets have no successors sets at all.
2726 Such changesets have no successors sets at all.
2740
2727
2741 A changeset that has been "split" will have a successors set containing
2728 A changeset that has been "split" will have a successors set containing
2742 more than one successor.
2729 more than one successor.
2743
2730
2744 A changeset that has been rewritten in multiple different ways is called
2731 A changeset that has been rewritten in multiple different ways is called
2745 "divergent". Such changesets have multiple successor sets (each of which
2732 "divergent". Such changesets have multiple successor sets (each of which
2746 may also be split, i.e. have multiple successors).
2733 may also be split, i.e. have multiple successors).
2747
2734
2748 Results are displayed as follows::
2735 Results are displayed as follows::
2749
2736
2750 <rev1>
2737 <rev1>
2751 <successors-1A>
2738 <successors-1A>
2752 <rev2>
2739 <rev2>
2753 <successors-2A>
2740 <successors-2A>
2754 <successors-2B1> <successors-2B2> <successors-2B3>
2741 <successors-2B1> <successors-2B2> <successors-2B3>
2755
2742
2756 Here rev2 has two possible (i.e. divergent) successors sets. The first
2743 Here rev2 has two possible (i.e. divergent) successors sets. The first
2757 holds one element, whereas the second holds three (i.e. the changeset has
2744 holds one element, whereas the second holds three (i.e. the changeset has
2758 been split).
2745 been split).
2759 """
2746 """
2760 # passed to successorssets caching computation from one call to another
2747 # passed to successorssets caching computation from one call to another
2761 cache = {}
2748 cache = {}
2762 ctx2str = str
2749 ctx2str = str
2763 node2str = short
2750 node2str = short
2764 if ui.debug():
2751 if ui.debug():
2765 def ctx2str(ctx):
2752 def ctx2str(ctx):
2766 return ctx.hex()
2753 return ctx.hex()
2767 node2str = hex
2754 node2str = hex
2768 for rev in scmutil.revrange(repo, revs):
2755 for rev in scmutil.revrange(repo, revs):
2769 ctx = repo[rev]
2756 ctx = repo[rev]
2770 ui.write('%s\n'% ctx2str(ctx))
2757 ui.write('%s\n'% ctx2str(ctx))
2771 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2758 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2772 if succsset:
2759 if succsset:
2773 ui.write(' ')
2760 ui.write(' ')
2774 ui.write(node2str(succsset[0]))
2761 ui.write(node2str(succsset[0]))
2775 for node in succsset[1:]:
2762 for node in succsset[1:]:
2776 ui.write(' ')
2763 ui.write(' ')
2777 ui.write(node2str(node))
2764 ui.write(node2str(node))
2778 ui.write('\n')
2765 ui.write('\n')
2779
2766
2780 @command('debugtemplate',
2767 @command('debugtemplate',
2781 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2768 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2782 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2769 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2783 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2770 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2784 optionalrepo=True)
2771 optionalrepo=True)
2785 def debugtemplate(ui, repo, tmpl, **opts):
2772 def debugtemplate(ui, repo, tmpl, **opts):
2786 """parse and apply a template
2773 """parse and apply a template
2787
2774
2788 If -r/--rev is given, the template is processed as a log template and
2775 If -r/--rev is given, the template is processed as a log template and
2789 applied to the given changesets. Otherwise, it is processed as a generic
2776 applied to the given changesets. Otherwise, it is processed as a generic
2790 template.
2777 template.
2791
2778
2792 Use --verbose to print the parsed tree.
2779 Use --verbose to print the parsed tree.
2793 """
2780 """
2794 revs = None
2781 revs = None
2795 if opts['rev']:
2782 if opts['rev']:
2796 if repo is None:
2783 if repo is None:
2797 raise error.RepoError(_('there is no Mercurial repository here '
2784 raise error.RepoError(_('there is no Mercurial repository here '
2798 '(.hg not found)'))
2785 '(.hg not found)'))
2799 revs = scmutil.revrange(repo, opts['rev'])
2786 revs = scmutil.revrange(repo, opts['rev'])
2800
2787
2801 props = {}
2788 props = {}
2802 for d in opts['define']:
2789 for d in opts['define']:
2803 try:
2790 try:
2804 k, v = (e.strip() for e in d.split('=', 1))
2791 k, v = (e.strip() for e in d.split('=', 1))
2805 if not k:
2792 if not k:
2806 raise ValueError
2793 raise ValueError
2807 props[k] = v
2794 props[k] = v
2808 except ValueError:
2795 except ValueError:
2809 raise error.Abort(_('malformed keyword definition: %s') % d)
2796 raise error.Abort(_('malformed keyword definition: %s') % d)
2810
2797
2811 if ui.verbose:
2798 if ui.verbose:
2812 aliases = ui.configitems('templatealias')
2799 aliases = ui.configitems('templatealias')
2813 tree = templater.parse(tmpl)
2800 tree = templater.parse(tmpl)
2814 ui.note(templater.prettyformat(tree), '\n')
2801 ui.note(templater.prettyformat(tree), '\n')
2815 newtree = templater.expandaliases(tree, aliases)
2802 newtree = templater.expandaliases(tree, aliases)
2816 if newtree != tree:
2803 if newtree != tree:
2817 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2804 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2818
2805
2819 mapfile = None
2806 mapfile = None
2820 if revs is None:
2807 if revs is None:
2821 k = 'debugtemplate'
2808 k = 'debugtemplate'
2822 t = formatter.maketemplater(ui, k, tmpl)
2809 t = formatter.maketemplater(ui, k, tmpl)
2823 ui.write(templater.stringify(t(k, **props)))
2810 ui.write(templater.stringify(t(k, **props)))
2824 else:
2811 else:
2825 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2812 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2826 mapfile, buffered=False)
2813 mapfile, buffered=False)
2827 for r in revs:
2814 for r in revs:
2828 displayer.show(repo[r], **props)
2815 displayer.show(repo[r], **props)
2829 displayer.close()
2816 displayer.close()
2830
2817
2831 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2818 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2832 def debugwalk(ui, repo, *pats, **opts):
2819 def debugwalk(ui, repo, *pats, **opts):
2833 """show how files match on given patterns"""
2820 """show how files match on given patterns"""
2834 m = scmutil.match(repo[None], pats, opts)
2821 m = scmutil.match(repo[None], pats, opts)
2835 items = list(repo.walk(m))
2822 items = list(repo.walk(m))
2836 if not items:
2823 if not items:
2837 return
2824 return
2838 f = lambda fn: fn
2825 f = lambda fn: fn
2839 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2826 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2840 f = lambda fn: util.normpath(fn)
2827 f = lambda fn: util.normpath(fn)
2841 fmt = 'f %%-%ds %%-%ds %%s' % (
2828 fmt = 'f %%-%ds %%-%ds %%s' % (
2842 max([len(abs) for abs in items]),
2829 max([len(abs) for abs in items]),
2843 max([len(m.rel(abs)) for abs in items]))
2830 max([len(m.rel(abs)) for abs in items]))
2844 for abs in items:
2831 for abs in items:
2845 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2832 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2846 ui.write("%s\n" % line.rstrip())
2833 ui.write("%s\n" % line.rstrip())
2847
2834
2848 @command('debugwireargs',
2835 @command('debugwireargs',
2849 [('', 'three', '', 'three'),
2836 [('', 'three', '', 'three'),
2850 ('', 'four', '', 'four'),
2837 ('', 'four', '', 'four'),
2851 ('', 'five', '', 'five'),
2838 ('', 'five', '', 'five'),
2852 ] + remoteopts,
2839 ] + remoteopts,
2853 _('REPO [OPTIONS]... [ONE [TWO]]'),
2840 _('REPO [OPTIONS]... [ONE [TWO]]'),
2854 norepo=True)
2841 norepo=True)
2855 def debugwireargs(ui, repopath, *vals, **opts):
2842 def debugwireargs(ui, repopath, *vals, **opts):
2856 repo = hg.peer(ui, opts, repopath)
2843 repo = hg.peer(ui, opts, repopath)
2857 for opt in remoteopts:
2844 for opt in remoteopts:
2858 del opts[opt[1]]
2845 del opts[opt[1]]
2859 args = {}
2846 args = {}
2860 for k, v in opts.iteritems():
2847 for k, v in opts.iteritems():
2861 if v:
2848 if v:
2862 args[k] = v
2849 args[k] = v
2863 # run twice to check that we don't mess up the stream for the next command
2850 # run twice to check that we don't mess up the stream for the next command
2864 res1 = repo.debugwireargs(*vals, **args)
2851 res1 = repo.debugwireargs(*vals, **args)
2865 res2 = repo.debugwireargs(*vals, **args)
2852 res2 = repo.debugwireargs(*vals, **args)
2866 ui.write("%s\n" % res1)
2853 ui.write("%s\n" % res1)
2867 if res1 != res2:
2854 if res1 != res2:
2868 ui.warn("%s\n" % res2)
2855 ui.warn("%s\n" % res2)
2869
2856
2870 @command('^diff',
2857 @command('^diff',
2871 [('r', 'rev', [], _('revision'), _('REV')),
2858 [('r', 'rev', [], _('revision'), _('REV')),
2872 ('c', 'change', '', _('change made by revision'), _('REV'))
2859 ('c', 'change', '', _('change made by revision'), _('REV'))
2873 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2860 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2874 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2861 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2875 inferrepo=True)
2862 inferrepo=True)
2876 def diff(ui, repo, *pats, **opts):
2863 def diff(ui, repo, *pats, **opts):
2877 """diff repository (or selected files)
2864 """diff repository (or selected files)
2878
2865
2879 Show differences between revisions for the specified files.
2866 Show differences between revisions for the specified files.
2880
2867
2881 Differences between files are shown using the unified diff format.
2868 Differences between files are shown using the unified diff format.
2882
2869
2883 .. note::
2870 .. note::
2884
2871
2885 :hg:`diff` may generate unexpected results for merges, as it will
2872 :hg:`diff` may generate unexpected results for merges, as it will
2886 default to comparing against the working directory's first
2873 default to comparing against the working directory's first
2887 parent changeset if no revisions are specified.
2874 parent changeset if no revisions are specified.
2888
2875
2889 When two revision arguments are given, then changes are shown
2876 When two revision arguments are given, then changes are shown
2890 between those revisions. If only one revision is specified then
2877 between those revisions. If only one revision is specified then
2891 that revision is compared to the working directory, and, when no
2878 that revision is compared to the working directory, and, when no
2892 revisions are specified, the working directory files are compared
2879 revisions are specified, the working directory files are compared
2893 to its first parent.
2880 to its first parent.
2894
2881
2895 Alternatively you can specify -c/--change with a revision to see
2882 Alternatively you can specify -c/--change with a revision to see
2896 the changes in that changeset relative to its first parent.
2883 the changes in that changeset relative to its first parent.
2897
2884
2898 Without the -a/--text option, diff will avoid generating diffs of
2885 Without the -a/--text option, diff will avoid generating diffs of
2899 files it detects as binary. With -a, diff will generate a diff
2886 files it detects as binary. With -a, diff will generate a diff
2900 anyway, probably with undesirable results.
2887 anyway, probably with undesirable results.
2901
2888
2902 Use the -g/--git option to generate diffs in the git extended diff
2889 Use the -g/--git option to generate diffs in the git extended diff
2903 format. For more information, read :hg:`help diffs`.
2890 format. For more information, read :hg:`help diffs`.
2904
2891
2905 .. container:: verbose
2892 .. container:: verbose
2906
2893
2907 Examples:
2894 Examples:
2908
2895
2909 - compare a file in the current working directory to its parent::
2896 - compare a file in the current working directory to its parent::
2910
2897
2911 hg diff foo.c
2898 hg diff foo.c
2912
2899
2913 - compare two historical versions of a directory, with rename info::
2900 - compare two historical versions of a directory, with rename info::
2914
2901
2915 hg diff --git -r 1.0:1.2 lib/
2902 hg diff --git -r 1.0:1.2 lib/
2916
2903
2917 - get change stats relative to the last change on some date::
2904 - get change stats relative to the last change on some date::
2918
2905
2919 hg diff --stat -r "date('may 2')"
2906 hg diff --stat -r "date('may 2')"
2920
2907
2921 - diff all newly-added files that contain a keyword::
2908 - diff all newly-added files that contain a keyword::
2922
2909
2923 hg diff "set:added() and grep(GNU)"
2910 hg diff "set:added() and grep(GNU)"
2924
2911
2925 - compare a revision and its parents::
2912 - compare a revision and its parents::
2926
2913
2927 hg diff -c 9353 # compare against first parent
2914 hg diff -c 9353 # compare against first parent
2928 hg diff -r 9353^:9353 # same using revset syntax
2915 hg diff -r 9353^:9353 # same using revset syntax
2929 hg diff -r 9353^2:9353 # compare against the second parent
2916 hg diff -r 9353^2:9353 # compare against the second parent
2930
2917
2931 Returns 0 on success.
2918 Returns 0 on success.
2932 """
2919 """
2933
2920
2934 revs = opts.get('rev')
2921 revs = opts.get('rev')
2935 change = opts.get('change')
2922 change = opts.get('change')
2936 stat = opts.get('stat')
2923 stat = opts.get('stat')
2937 reverse = opts.get('reverse')
2924 reverse = opts.get('reverse')
2938
2925
2939 if revs and change:
2926 if revs and change:
2940 msg = _('cannot specify --rev and --change at the same time')
2927 msg = _('cannot specify --rev and --change at the same time')
2941 raise error.Abort(msg)
2928 raise error.Abort(msg)
2942 elif change:
2929 elif change:
2943 node2 = scmutil.revsingle(repo, change, None).node()
2930 node2 = scmutil.revsingle(repo, change, None).node()
2944 node1 = repo[node2].p1().node()
2931 node1 = repo[node2].p1().node()
2945 else:
2932 else:
2946 node1, node2 = scmutil.revpair(repo, revs)
2933 node1, node2 = scmutil.revpair(repo, revs)
2947
2934
2948 if reverse:
2935 if reverse:
2949 node1, node2 = node2, node1
2936 node1, node2 = node2, node1
2950
2937
2951 diffopts = patch.diffallopts(ui, opts)
2938 diffopts = patch.diffallopts(ui, opts)
2952 m = scmutil.match(repo[node2], pats, opts)
2939 m = scmutil.match(repo[node2], pats, opts)
2953 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2940 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2954 listsubrepos=opts.get('subrepos'),
2941 listsubrepos=opts.get('subrepos'),
2955 root=opts.get('root'))
2942 root=opts.get('root'))
2956
2943
2957 @command('^export',
2944 @command('^export',
2958 [('o', 'output', '',
2945 [('o', 'output', '',
2959 _('print output to file with formatted name'), _('FORMAT')),
2946 _('print output to file with formatted name'), _('FORMAT')),
2960 ('', 'switch-parent', None, _('diff against the second parent')),
2947 ('', 'switch-parent', None, _('diff against the second parent')),
2961 ('r', 'rev', [], _('revisions to export'), _('REV')),
2948 ('r', 'rev', [], _('revisions to export'), _('REV')),
2962 ] + diffopts,
2949 ] + diffopts,
2963 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2950 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2964 def export(ui, repo, *changesets, **opts):
2951 def export(ui, repo, *changesets, **opts):
2965 """dump the header and diffs for one or more changesets
2952 """dump the header and diffs for one or more changesets
2966
2953
2967 Print the changeset header and diffs for one or more revisions.
2954 Print the changeset header and diffs for one or more revisions.
2968 If no revision is given, the parent of the working directory is used.
2955 If no revision is given, the parent of the working directory is used.
2969
2956
2970 The information shown in the changeset header is: author, date,
2957 The information shown in the changeset header is: author, date,
2971 branch name (if non-default), changeset hash, parent(s) and commit
2958 branch name (if non-default), changeset hash, parent(s) and commit
2972 comment.
2959 comment.
2973
2960
2974 .. note::
2961 .. note::
2975
2962
2976 :hg:`export` may generate unexpected diff output for merge
2963 :hg:`export` may generate unexpected diff output for merge
2977 changesets, as it will compare the merge changeset against its
2964 changesets, as it will compare the merge changeset against its
2978 first parent only.
2965 first parent only.
2979
2966
2980 Output may be to a file, in which case the name of the file is
2967 Output may be to a file, in which case the name of the file is
2981 given using a format string. The formatting rules are as follows:
2968 given using a format string. The formatting rules are as follows:
2982
2969
2983 :``%%``: literal "%" character
2970 :``%%``: literal "%" character
2984 :``%H``: changeset hash (40 hexadecimal digits)
2971 :``%H``: changeset hash (40 hexadecimal digits)
2985 :``%N``: number of patches being generated
2972 :``%N``: number of patches being generated
2986 :``%R``: changeset revision number
2973 :``%R``: changeset revision number
2987 :``%b``: basename of the exporting repository
2974 :``%b``: basename of the exporting repository
2988 :``%h``: short-form changeset hash (12 hexadecimal digits)
2975 :``%h``: short-form changeset hash (12 hexadecimal digits)
2989 :``%m``: first line of the commit message (only alphanumeric characters)
2976 :``%m``: first line of the commit message (only alphanumeric characters)
2990 :``%n``: zero-padded sequence number, starting at 1
2977 :``%n``: zero-padded sequence number, starting at 1
2991 :``%r``: zero-padded changeset revision number
2978 :``%r``: zero-padded changeset revision number
2992
2979
2993 Without the -a/--text option, export will avoid generating diffs
2980 Without the -a/--text option, export will avoid generating diffs
2994 of files it detects as binary. With -a, export will generate a
2981 of files it detects as binary. With -a, export will generate a
2995 diff anyway, probably with undesirable results.
2982 diff anyway, probably with undesirable results.
2996
2983
2997 Use the -g/--git option to generate diffs in the git extended diff
2984 Use the -g/--git option to generate diffs in the git extended diff
2998 format. See :hg:`help diffs` for more information.
2985 format. See :hg:`help diffs` for more information.
2999
2986
3000 With the --switch-parent option, the diff will be against the
2987 With the --switch-parent option, the diff will be against the
3001 second parent. It can be useful to review a merge.
2988 second parent. It can be useful to review a merge.
3002
2989
3003 .. container:: verbose
2990 .. container:: verbose
3004
2991
3005 Examples:
2992 Examples:
3006
2993
3007 - use export and import to transplant a bugfix to the current
2994 - use export and import to transplant a bugfix to the current
3008 branch::
2995 branch::
3009
2996
3010 hg export -r 9353 | hg import -
2997 hg export -r 9353 | hg import -
3011
2998
3012 - export all the changesets between two revisions to a file with
2999 - export all the changesets between two revisions to a file with
3013 rename information::
3000 rename information::
3014
3001
3015 hg export --git -r 123:150 > changes.txt
3002 hg export --git -r 123:150 > changes.txt
3016
3003
3017 - split outgoing changes into a series of patches with
3004 - split outgoing changes into a series of patches with
3018 descriptive names::
3005 descriptive names::
3019
3006
3020 hg export -r "outgoing()" -o "%n-%m.patch"
3007 hg export -r "outgoing()" -o "%n-%m.patch"
3021
3008
3022 Returns 0 on success.
3009 Returns 0 on success.
3023 """
3010 """
3024 changesets += tuple(opts.get('rev', []))
3011 changesets += tuple(opts.get('rev', []))
3025 if not changesets:
3012 if not changesets:
3026 changesets = ['.']
3013 changesets = ['.']
3027 revs = scmutil.revrange(repo, changesets)
3014 revs = scmutil.revrange(repo, changesets)
3028 if not revs:
3015 if not revs:
3029 raise error.Abort(_("export requires at least one changeset"))
3016 raise error.Abort(_("export requires at least one changeset"))
3030 if len(revs) > 1:
3017 if len(revs) > 1:
3031 ui.note(_('exporting patches:\n'))
3018 ui.note(_('exporting patches:\n'))
3032 else:
3019 else:
3033 ui.note(_('exporting patch:\n'))
3020 ui.note(_('exporting patch:\n'))
3034 cmdutil.export(repo, revs, template=opts.get('output'),
3021 cmdutil.export(repo, revs, template=opts.get('output'),
3035 switch_parent=opts.get('switch_parent'),
3022 switch_parent=opts.get('switch_parent'),
3036 opts=patch.diffallopts(ui, opts))
3023 opts=patch.diffallopts(ui, opts))
3037
3024
3038 @command('files',
3025 @command('files',
3039 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3026 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3040 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3027 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3041 ] + walkopts + formatteropts + subrepoopts,
3028 ] + walkopts + formatteropts + subrepoopts,
3042 _('[OPTION]... [FILE]...'))
3029 _('[OPTION]... [FILE]...'))
3043 def files(ui, repo, *pats, **opts):
3030 def files(ui, repo, *pats, **opts):
3044 """list tracked files
3031 """list tracked files
3045
3032
3046 Print files under Mercurial control in the working directory or
3033 Print files under Mercurial control in the working directory or
3047 specified revision for given files (excluding removed files).
3034 specified revision for given files (excluding removed files).
3048 Files can be specified as filenames or filesets.
3035 Files can be specified as filenames or filesets.
3049
3036
3050 If no files are given to match, this command prints the names
3037 If no files are given to match, this command prints the names
3051 of all files under Mercurial control.
3038 of all files under Mercurial control.
3052
3039
3053 .. container:: verbose
3040 .. container:: verbose
3054
3041
3055 Examples:
3042 Examples:
3056
3043
3057 - list all files under the current directory::
3044 - list all files under the current directory::
3058
3045
3059 hg files .
3046 hg files .
3060
3047
3061 - shows sizes and flags for current revision::
3048 - shows sizes and flags for current revision::
3062
3049
3063 hg files -vr .
3050 hg files -vr .
3064
3051
3065 - list all files named README::
3052 - list all files named README::
3066
3053
3067 hg files -I "**/README"
3054 hg files -I "**/README"
3068
3055
3069 - list all binary files::
3056 - list all binary files::
3070
3057
3071 hg files "set:binary()"
3058 hg files "set:binary()"
3072
3059
3073 - find files containing a regular expression::
3060 - find files containing a regular expression::
3074
3061
3075 hg files "set:grep('bob')"
3062 hg files "set:grep('bob')"
3076
3063
3077 - search tracked file contents with xargs and grep::
3064 - search tracked file contents with xargs and grep::
3078
3065
3079 hg files -0 | xargs -0 grep foo
3066 hg files -0 | xargs -0 grep foo
3080
3067
3081 See :hg:`help patterns` and :hg:`help filesets` for more information
3068 See :hg:`help patterns` and :hg:`help filesets` for more information
3082 on specifying file patterns.
3069 on specifying file patterns.
3083
3070
3084 Returns 0 if a match is found, 1 otherwise.
3071 Returns 0 if a match is found, 1 otherwise.
3085
3072
3086 """
3073 """
3087 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3074 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3088
3075
3089 end = '\n'
3076 end = '\n'
3090 if opts.get('print0'):
3077 if opts.get('print0'):
3091 end = '\0'
3078 end = '\0'
3092 fmt = '%s' + end
3079 fmt = '%s' + end
3093
3080
3094 m = scmutil.match(ctx, pats, opts)
3081 m = scmutil.match(ctx, pats, opts)
3095 with ui.formatter('files', opts) as fm:
3082 with ui.formatter('files', opts) as fm:
3096 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3083 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3097
3084
3098 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3085 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3099 def forget(ui, repo, *pats, **opts):
3086 def forget(ui, repo, *pats, **opts):
3100 """forget the specified files on the next commit
3087 """forget the specified files on the next commit
3101
3088
3102 Mark the specified files so they will no longer be tracked
3089 Mark the specified files so they will no longer be tracked
3103 after the next commit.
3090 after the next commit.
3104
3091
3105 This only removes files from the current branch, not from the
3092 This only removes files from the current branch, not from the
3106 entire project history, and it does not delete them from the
3093 entire project history, and it does not delete them from the
3107 working directory.
3094 working directory.
3108
3095
3109 To delete the file from the working directory, see :hg:`remove`.
3096 To delete the file from the working directory, see :hg:`remove`.
3110
3097
3111 To undo a forget before the next commit, see :hg:`add`.
3098 To undo a forget before the next commit, see :hg:`add`.
3112
3099
3113 .. container:: verbose
3100 .. container:: verbose
3114
3101
3115 Examples:
3102 Examples:
3116
3103
3117 - forget newly-added binary files::
3104 - forget newly-added binary files::
3118
3105
3119 hg forget "set:added() and binary()"
3106 hg forget "set:added() and binary()"
3120
3107
3121 - forget files that would be excluded by .hgignore::
3108 - forget files that would be excluded by .hgignore::
3122
3109
3123 hg forget "set:hgignore()"
3110 hg forget "set:hgignore()"
3124
3111
3125 Returns 0 on success.
3112 Returns 0 on success.
3126 """
3113 """
3127
3114
3128 if not pats:
3115 if not pats:
3129 raise error.Abort(_('no files specified'))
3116 raise error.Abort(_('no files specified'))
3130
3117
3131 m = scmutil.match(repo[None], pats, opts)
3118 m = scmutil.match(repo[None], pats, opts)
3132 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3119 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3133 return rejected and 1 or 0
3120 return rejected and 1 or 0
3134
3121
3135 @command(
3122 @command(
3136 'graft',
3123 'graft',
3137 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3124 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3138 ('c', 'continue', False, _('resume interrupted graft')),
3125 ('c', 'continue', False, _('resume interrupted graft')),
3139 ('e', 'edit', False, _('invoke editor on commit messages')),
3126 ('e', 'edit', False, _('invoke editor on commit messages')),
3140 ('', 'log', None, _('append graft info to log message')),
3127 ('', 'log', None, _('append graft info to log message')),
3141 ('f', 'force', False, _('force graft')),
3128 ('f', 'force', False, _('force graft')),
3142 ('D', 'currentdate', False,
3129 ('D', 'currentdate', False,
3143 _('record the current date as commit date')),
3130 _('record the current date as commit date')),
3144 ('U', 'currentuser', False,
3131 ('U', 'currentuser', False,
3145 _('record the current user as committer'), _('DATE'))]
3132 _('record the current user as committer'), _('DATE'))]
3146 + commitopts2 + mergetoolopts + dryrunopts,
3133 + commitopts2 + mergetoolopts + dryrunopts,
3147 _('[OPTION]... [-r REV]... REV...'))
3134 _('[OPTION]... [-r REV]... REV...'))
3148 def graft(ui, repo, *revs, **opts):
3135 def graft(ui, repo, *revs, **opts):
3149 '''copy changes from other branches onto the current branch
3136 '''copy changes from other branches onto the current branch
3150
3137
3151 This command uses Mercurial's merge logic to copy individual
3138 This command uses Mercurial's merge logic to copy individual
3152 changes from other branches without merging branches in the
3139 changes from other branches without merging branches in the
3153 history graph. This is sometimes known as 'backporting' or
3140 history graph. This is sometimes known as 'backporting' or
3154 'cherry-picking'. By default, graft will copy user, date, and
3141 'cherry-picking'. By default, graft will copy user, date, and
3155 description from the source changesets.
3142 description from the source changesets.
3156
3143
3157 Changesets that are ancestors of the current revision, that have
3144 Changesets that are ancestors of the current revision, that have
3158 already been grafted, or that are merges will be skipped.
3145 already been grafted, or that are merges will be skipped.
3159
3146
3160 If --log is specified, log messages will have a comment appended
3147 If --log is specified, log messages will have a comment appended
3161 of the form::
3148 of the form::
3162
3149
3163 (grafted from CHANGESETHASH)
3150 (grafted from CHANGESETHASH)
3164
3151
3165 If --force is specified, revisions will be grafted even if they
3152 If --force is specified, revisions will be grafted even if they
3166 are already ancestors of or have been grafted to the destination.
3153 are already ancestors of or have been grafted to the destination.
3167 This is useful when the revisions have since been backed out.
3154 This is useful when the revisions have since been backed out.
3168
3155
3169 If a graft merge results in conflicts, the graft process is
3156 If a graft merge results in conflicts, the graft process is
3170 interrupted so that the current merge can be manually resolved.
3157 interrupted so that the current merge can be manually resolved.
3171 Once all conflicts are addressed, the graft process can be
3158 Once all conflicts are addressed, the graft process can be
3172 continued with the -c/--continue option.
3159 continued with the -c/--continue option.
3173
3160
3174 .. note::
3161 .. note::
3175
3162
3176 The -c/--continue option does not reapply earlier options, except
3163 The -c/--continue option does not reapply earlier options, except
3177 for --force.
3164 for --force.
3178
3165
3179 .. container:: verbose
3166 .. container:: verbose
3180
3167
3181 Examples:
3168 Examples:
3182
3169
3183 - copy a single change to the stable branch and edit its description::
3170 - copy a single change to the stable branch and edit its description::
3184
3171
3185 hg update stable
3172 hg update stable
3186 hg graft --edit 9393
3173 hg graft --edit 9393
3187
3174
3188 - graft a range of changesets with one exception, updating dates::
3175 - graft a range of changesets with one exception, updating dates::
3189
3176
3190 hg graft -D "2085::2093 and not 2091"
3177 hg graft -D "2085::2093 and not 2091"
3191
3178
3192 - continue a graft after resolving conflicts::
3179 - continue a graft after resolving conflicts::
3193
3180
3194 hg graft -c
3181 hg graft -c
3195
3182
3196 - show the source of a grafted changeset::
3183 - show the source of a grafted changeset::
3197
3184
3198 hg log --debug -r .
3185 hg log --debug -r .
3199
3186
3200 - show revisions sorted by date::
3187 - show revisions sorted by date::
3201
3188
3202 hg log -r "sort(all(), date)"
3189 hg log -r "sort(all(), date)"
3203
3190
3204 See :hg:`help revisions` for more about specifying revisions.
3191 See :hg:`help revisions` for more about specifying revisions.
3205
3192
3206 Returns 0 on successful completion.
3193 Returns 0 on successful completion.
3207 '''
3194 '''
3208 with repo.wlock():
3195 with repo.wlock():
3209 return _dograft(ui, repo, *revs, **opts)
3196 return _dograft(ui, repo, *revs, **opts)
3210
3197
3211 def _dograft(ui, repo, *revs, **opts):
3198 def _dograft(ui, repo, *revs, **opts):
3212 if revs and opts.get('rev'):
3199 if revs and opts.get('rev'):
3213 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3200 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3214 'revision ordering!\n'))
3201 'revision ordering!\n'))
3215
3202
3216 revs = list(revs)
3203 revs = list(revs)
3217 revs.extend(opts.get('rev'))
3204 revs.extend(opts.get('rev'))
3218
3205
3219 if not opts.get('user') and opts.get('currentuser'):
3206 if not opts.get('user') and opts.get('currentuser'):
3220 opts['user'] = ui.username()
3207 opts['user'] = ui.username()
3221 if not opts.get('date') and opts.get('currentdate'):
3208 if not opts.get('date') and opts.get('currentdate'):
3222 opts['date'] = "%d %d" % util.makedate()
3209 opts['date'] = "%d %d" % util.makedate()
3223
3210
3224 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3211 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3225
3212
3226 cont = False
3213 cont = False
3227 if opts.get('continue'):
3214 if opts.get('continue'):
3228 cont = True
3215 cont = True
3229 if revs:
3216 if revs:
3230 raise error.Abort(_("can't specify --continue and revisions"))
3217 raise error.Abort(_("can't specify --continue and revisions"))
3231 # read in unfinished revisions
3218 # read in unfinished revisions
3232 try:
3219 try:
3233 nodes = repo.vfs.read('graftstate').splitlines()
3220 nodes = repo.vfs.read('graftstate').splitlines()
3234 revs = [repo[node].rev() for node in nodes]
3221 revs = [repo[node].rev() for node in nodes]
3235 except IOError as inst:
3222 except IOError as inst:
3236 if inst.errno != errno.ENOENT:
3223 if inst.errno != errno.ENOENT:
3237 raise
3224 raise
3238 cmdutil.wrongtooltocontinue(repo, _('graft'))
3225 cmdutil.wrongtooltocontinue(repo, _('graft'))
3239 else:
3226 else:
3240 cmdutil.checkunfinished(repo)
3227 cmdutil.checkunfinished(repo)
3241 cmdutil.bailifchanged(repo)
3228 cmdutil.bailifchanged(repo)
3242 if not revs:
3229 if not revs:
3243 raise error.Abort(_('no revisions specified'))
3230 raise error.Abort(_('no revisions specified'))
3244 revs = scmutil.revrange(repo, revs)
3231 revs = scmutil.revrange(repo, revs)
3245
3232
3246 skipped = set()
3233 skipped = set()
3247 # check for merges
3234 # check for merges
3248 for rev in repo.revs('%ld and merge()', revs):
3235 for rev in repo.revs('%ld and merge()', revs):
3249 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3236 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3250 skipped.add(rev)
3237 skipped.add(rev)
3251 revs = [r for r in revs if r not in skipped]
3238 revs = [r for r in revs if r not in skipped]
3252 if not revs:
3239 if not revs:
3253 return -1
3240 return -1
3254
3241
3255 # Don't check in the --continue case, in effect retaining --force across
3242 # Don't check in the --continue case, in effect retaining --force across
3256 # --continues. That's because without --force, any revisions we decided to
3243 # --continues. That's because without --force, any revisions we decided to
3257 # skip would have been filtered out here, so they wouldn't have made their
3244 # skip would have been filtered out here, so they wouldn't have made their
3258 # way to the graftstate. With --force, any revisions we would have otherwise
3245 # way to the graftstate. With --force, any revisions we would have otherwise
3259 # skipped would not have been filtered out, and if they hadn't been applied
3246 # skipped would not have been filtered out, and if they hadn't been applied
3260 # already, they'd have been in the graftstate.
3247 # already, they'd have been in the graftstate.
3261 if not (cont or opts.get('force')):
3248 if not (cont or opts.get('force')):
3262 # check for ancestors of dest branch
3249 # check for ancestors of dest branch
3263 crev = repo['.'].rev()
3250 crev = repo['.'].rev()
3264 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3251 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3265 # XXX make this lazy in the future
3252 # XXX make this lazy in the future
3266 # don't mutate while iterating, create a copy
3253 # don't mutate while iterating, create a copy
3267 for rev in list(revs):
3254 for rev in list(revs):
3268 if rev in ancestors:
3255 if rev in ancestors:
3269 ui.warn(_('skipping ancestor revision %d:%s\n') %
3256 ui.warn(_('skipping ancestor revision %d:%s\n') %
3270 (rev, repo[rev]))
3257 (rev, repo[rev]))
3271 # XXX remove on list is slow
3258 # XXX remove on list is slow
3272 revs.remove(rev)
3259 revs.remove(rev)
3273 if not revs:
3260 if not revs:
3274 return -1
3261 return -1
3275
3262
3276 # analyze revs for earlier grafts
3263 # analyze revs for earlier grafts
3277 ids = {}
3264 ids = {}
3278 for ctx in repo.set("%ld", revs):
3265 for ctx in repo.set("%ld", revs):
3279 ids[ctx.hex()] = ctx.rev()
3266 ids[ctx.hex()] = ctx.rev()
3280 n = ctx.extra().get('source')
3267 n = ctx.extra().get('source')
3281 if n:
3268 if n:
3282 ids[n] = ctx.rev()
3269 ids[n] = ctx.rev()
3283
3270
3284 # check ancestors for earlier grafts
3271 # check ancestors for earlier grafts
3285 ui.debug('scanning for duplicate grafts\n')
3272 ui.debug('scanning for duplicate grafts\n')
3286
3273
3287 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3274 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3288 ctx = repo[rev]
3275 ctx = repo[rev]
3289 n = ctx.extra().get('source')
3276 n = ctx.extra().get('source')
3290 if n in ids:
3277 if n in ids:
3291 try:
3278 try:
3292 r = repo[n].rev()
3279 r = repo[n].rev()
3293 except error.RepoLookupError:
3280 except error.RepoLookupError:
3294 r = None
3281 r = None
3295 if r in revs:
3282 if r in revs:
3296 ui.warn(_('skipping revision %d:%s '
3283 ui.warn(_('skipping revision %d:%s '
3297 '(already grafted to %d:%s)\n')
3284 '(already grafted to %d:%s)\n')
3298 % (r, repo[r], rev, ctx))
3285 % (r, repo[r], rev, ctx))
3299 revs.remove(r)
3286 revs.remove(r)
3300 elif ids[n] in revs:
3287 elif ids[n] in revs:
3301 if r is None:
3288 if r is None:
3302 ui.warn(_('skipping already grafted revision %d:%s '
3289 ui.warn(_('skipping already grafted revision %d:%s '
3303 '(%d:%s also has unknown origin %s)\n')
3290 '(%d:%s also has unknown origin %s)\n')
3304 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3291 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3305 else:
3292 else:
3306 ui.warn(_('skipping already grafted revision %d:%s '
3293 ui.warn(_('skipping already grafted revision %d:%s '
3307 '(%d:%s also has origin %d:%s)\n')
3294 '(%d:%s also has origin %d:%s)\n')
3308 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3295 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3309 revs.remove(ids[n])
3296 revs.remove(ids[n])
3310 elif ctx.hex() in ids:
3297 elif ctx.hex() in ids:
3311 r = ids[ctx.hex()]
3298 r = ids[ctx.hex()]
3312 ui.warn(_('skipping already grafted revision %d:%s '
3299 ui.warn(_('skipping already grafted revision %d:%s '
3313 '(was grafted from %d:%s)\n') %
3300 '(was grafted from %d:%s)\n') %
3314 (r, repo[r], rev, ctx))
3301 (r, repo[r], rev, ctx))
3315 revs.remove(r)
3302 revs.remove(r)
3316 if not revs:
3303 if not revs:
3317 return -1
3304 return -1
3318
3305
3319 for pos, ctx in enumerate(repo.set("%ld", revs)):
3306 for pos, ctx in enumerate(repo.set("%ld", revs)):
3320 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3307 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3321 ctx.description().split('\n', 1)[0])
3308 ctx.description().split('\n', 1)[0])
3322 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3309 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3323 if names:
3310 if names:
3324 desc += ' (%s)' % ' '.join(names)
3311 desc += ' (%s)' % ' '.join(names)
3325 ui.status(_('grafting %s\n') % desc)
3312 ui.status(_('grafting %s\n') % desc)
3326 if opts.get('dry_run'):
3313 if opts.get('dry_run'):
3327 continue
3314 continue
3328
3315
3329 source = ctx.extra().get('source')
3316 source = ctx.extra().get('source')
3330 extra = {}
3317 extra = {}
3331 if source:
3318 if source:
3332 extra['source'] = source
3319 extra['source'] = source
3333 extra['intermediate-source'] = ctx.hex()
3320 extra['intermediate-source'] = ctx.hex()
3334 else:
3321 else:
3335 extra['source'] = ctx.hex()
3322 extra['source'] = ctx.hex()
3336 user = ctx.user()
3323 user = ctx.user()
3337 if opts.get('user'):
3324 if opts.get('user'):
3338 user = opts['user']
3325 user = opts['user']
3339 date = ctx.date()
3326 date = ctx.date()
3340 if opts.get('date'):
3327 if opts.get('date'):
3341 date = opts['date']
3328 date = opts['date']
3342 message = ctx.description()
3329 message = ctx.description()
3343 if opts.get('log'):
3330 if opts.get('log'):
3344 message += '\n(grafted from %s)' % ctx.hex()
3331 message += '\n(grafted from %s)' % ctx.hex()
3345
3332
3346 # we don't merge the first commit when continuing
3333 # we don't merge the first commit when continuing
3347 if not cont:
3334 if not cont:
3348 # perform the graft merge with p1(rev) as 'ancestor'
3335 # perform the graft merge with p1(rev) as 'ancestor'
3349 try:
3336 try:
3350 # ui.forcemerge is an internal variable, do not document
3337 # ui.forcemerge is an internal variable, do not document
3351 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3338 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3352 'graft')
3339 'graft')
3353 stats = mergemod.graft(repo, ctx, ctx.p1(),
3340 stats = mergemod.graft(repo, ctx, ctx.p1(),
3354 ['local', 'graft'])
3341 ['local', 'graft'])
3355 finally:
3342 finally:
3356 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3343 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3357 # report any conflicts
3344 # report any conflicts
3358 if stats and stats[3] > 0:
3345 if stats and stats[3] > 0:
3359 # write out state for --continue
3346 # write out state for --continue
3360 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3347 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3361 repo.vfs.write('graftstate', ''.join(nodelines))
3348 repo.vfs.write('graftstate', ''.join(nodelines))
3362 extra = ''
3349 extra = ''
3363 if opts.get('user'):
3350 if opts.get('user'):
3364 extra += ' --user %s' % util.shellquote(opts['user'])
3351 extra += ' --user %s' % util.shellquote(opts['user'])
3365 if opts.get('date'):
3352 if opts.get('date'):
3366 extra += ' --date %s' % util.shellquote(opts['date'])
3353 extra += ' --date %s' % util.shellquote(opts['date'])
3367 if opts.get('log'):
3354 if opts.get('log'):
3368 extra += ' --log'
3355 extra += ' --log'
3369 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3356 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3370 raise error.Abort(
3357 raise error.Abort(
3371 _("unresolved conflicts, can't continue"),
3358 _("unresolved conflicts, can't continue"),
3372 hint=hint)
3359 hint=hint)
3373 else:
3360 else:
3374 cont = False
3361 cont = False
3375
3362
3376 # commit
3363 # commit
3377 node = repo.commit(text=message, user=user,
3364 node = repo.commit(text=message, user=user,
3378 date=date, extra=extra, editor=editor)
3365 date=date, extra=extra, editor=editor)
3379 if node is None:
3366 if node is None:
3380 ui.warn(
3367 ui.warn(
3381 _('note: graft of %d:%s created no changes to commit\n') %
3368 _('note: graft of %d:%s created no changes to commit\n') %
3382 (ctx.rev(), ctx))
3369 (ctx.rev(), ctx))
3383
3370
3384 # remove state when we complete successfully
3371 # remove state when we complete successfully
3385 if not opts.get('dry_run'):
3372 if not opts.get('dry_run'):
3386 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3373 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3387
3374
3388 return 0
3375 return 0
3389
3376
3390 @command('grep',
3377 @command('grep',
3391 [('0', 'print0', None, _('end fields with NUL')),
3378 [('0', 'print0', None, _('end fields with NUL')),
3392 ('', 'all', None, _('print all revisions that match')),
3379 ('', 'all', None, _('print all revisions that match')),
3393 ('a', 'text', None, _('treat all files as text')),
3380 ('a', 'text', None, _('treat all files as text')),
3394 ('f', 'follow', None,
3381 ('f', 'follow', None,
3395 _('follow changeset history,'
3382 _('follow changeset history,'
3396 ' or file history across copies and renames')),
3383 ' or file history across copies and renames')),
3397 ('i', 'ignore-case', None, _('ignore case when matching')),
3384 ('i', 'ignore-case', None, _('ignore case when matching')),
3398 ('l', 'files-with-matches', None,
3385 ('l', 'files-with-matches', None,
3399 _('print only filenames and revisions that match')),
3386 _('print only filenames and revisions that match')),
3400 ('n', 'line-number', None, _('print matching line numbers')),
3387 ('n', 'line-number', None, _('print matching line numbers')),
3401 ('r', 'rev', [],
3388 ('r', 'rev', [],
3402 _('only search files changed within revision range'), _('REV')),
3389 _('only search files changed within revision range'), _('REV')),
3403 ('u', 'user', None, _('list the author (long with -v)')),
3390 ('u', 'user', None, _('list the author (long with -v)')),
3404 ('d', 'date', None, _('list the date (short with -q)')),
3391 ('d', 'date', None, _('list the date (short with -q)')),
3405 ] + formatteropts + walkopts,
3392 ] + formatteropts + walkopts,
3406 _('[OPTION]... PATTERN [FILE]...'),
3393 _('[OPTION]... PATTERN [FILE]...'),
3407 inferrepo=True)
3394 inferrepo=True)
3408 def grep(ui, repo, pattern, *pats, **opts):
3395 def grep(ui, repo, pattern, *pats, **opts):
3409 """search revision history for a pattern in specified files
3396 """search revision history for a pattern in specified files
3410
3397
3411 Search revision history for a regular expression in the specified
3398 Search revision history for a regular expression in the specified
3412 files or the entire project.
3399 files or the entire project.
3413
3400
3414 By default, grep prints the most recent revision number for each
3401 By default, grep prints the most recent revision number for each
3415 file in which it finds a match. To get it to print every revision
3402 file in which it finds a match. To get it to print every revision
3416 that contains a change in match status ("-" for a match that becomes
3403 that contains a change in match status ("-" for a match that becomes
3417 a non-match, or "+" for a non-match that becomes a match), use the
3404 a non-match, or "+" for a non-match that becomes a match), use the
3418 --all flag.
3405 --all flag.
3419
3406
3420 PATTERN can be any Python (roughly Perl-compatible) regular
3407 PATTERN can be any Python (roughly Perl-compatible) regular
3421 expression.
3408 expression.
3422
3409
3423 If no FILEs are specified (and -f/--follow isn't set), all files in
3410 If no FILEs are specified (and -f/--follow isn't set), all files in
3424 the repository are searched, including those that don't exist in the
3411 the repository are searched, including those that don't exist in the
3425 current branch or have been deleted in a prior changeset.
3412 current branch or have been deleted in a prior changeset.
3426
3413
3427 Returns 0 if a match is found, 1 otherwise.
3414 Returns 0 if a match is found, 1 otherwise.
3428 """
3415 """
3429 reflags = re.M
3416 reflags = re.M
3430 if opts.get('ignore_case'):
3417 if opts.get('ignore_case'):
3431 reflags |= re.I
3418 reflags |= re.I
3432 try:
3419 try:
3433 regexp = util.re.compile(pattern, reflags)
3420 regexp = util.re.compile(pattern, reflags)
3434 except re.error as inst:
3421 except re.error as inst:
3435 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3422 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3436 return 1
3423 return 1
3437 sep, eol = ':', '\n'
3424 sep, eol = ':', '\n'
3438 if opts.get('print0'):
3425 if opts.get('print0'):
3439 sep = eol = '\0'
3426 sep = eol = '\0'
3440
3427
3441 getfile = util.lrucachefunc(repo.file)
3428 getfile = util.lrucachefunc(repo.file)
3442
3429
3443 def matchlines(body):
3430 def matchlines(body):
3444 begin = 0
3431 begin = 0
3445 linenum = 0
3432 linenum = 0
3446 while begin < len(body):
3433 while begin < len(body):
3447 match = regexp.search(body, begin)
3434 match = regexp.search(body, begin)
3448 if not match:
3435 if not match:
3449 break
3436 break
3450 mstart, mend = match.span()
3437 mstart, mend = match.span()
3451 linenum += body.count('\n', begin, mstart) + 1
3438 linenum += body.count('\n', begin, mstart) + 1
3452 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3439 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3453 begin = body.find('\n', mend) + 1 or len(body) + 1
3440 begin = body.find('\n', mend) + 1 or len(body) + 1
3454 lend = begin - 1
3441 lend = begin - 1
3455 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3442 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3456
3443
3457 class linestate(object):
3444 class linestate(object):
3458 def __init__(self, line, linenum, colstart, colend):
3445 def __init__(self, line, linenum, colstart, colend):
3459 self.line = line
3446 self.line = line
3460 self.linenum = linenum
3447 self.linenum = linenum
3461 self.colstart = colstart
3448 self.colstart = colstart
3462 self.colend = colend
3449 self.colend = colend
3463
3450
3464 def __hash__(self):
3451 def __hash__(self):
3465 return hash((self.linenum, self.line))
3452 return hash((self.linenum, self.line))
3466
3453
3467 def __eq__(self, other):
3454 def __eq__(self, other):
3468 return self.line == other.line
3455 return self.line == other.line
3469
3456
3470 def findpos(self):
3457 def findpos(self):
3471 """Iterate all (start, end) indices of matches"""
3458 """Iterate all (start, end) indices of matches"""
3472 yield self.colstart, self.colend
3459 yield self.colstart, self.colend
3473 p = self.colend
3460 p = self.colend
3474 while p < len(self.line):
3461 while p < len(self.line):
3475 m = regexp.search(self.line, p)
3462 m = regexp.search(self.line, p)
3476 if not m:
3463 if not m:
3477 break
3464 break
3478 yield m.span()
3465 yield m.span()
3479 p = m.end()
3466 p = m.end()
3480
3467
3481 matches = {}
3468 matches = {}
3482 copies = {}
3469 copies = {}
3483 def grepbody(fn, rev, body):
3470 def grepbody(fn, rev, body):
3484 matches[rev].setdefault(fn, [])
3471 matches[rev].setdefault(fn, [])
3485 m = matches[rev][fn]
3472 m = matches[rev][fn]
3486 for lnum, cstart, cend, line in matchlines(body):
3473 for lnum, cstart, cend, line in matchlines(body):
3487 s = linestate(line, lnum, cstart, cend)
3474 s = linestate(line, lnum, cstart, cend)
3488 m.append(s)
3475 m.append(s)
3489
3476
3490 def difflinestates(a, b):
3477 def difflinestates(a, b):
3491 sm = difflib.SequenceMatcher(None, a, b)
3478 sm = difflib.SequenceMatcher(None, a, b)
3492 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3479 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3493 if tag == 'insert':
3480 if tag == 'insert':
3494 for i in xrange(blo, bhi):
3481 for i in xrange(blo, bhi):
3495 yield ('+', b[i])
3482 yield ('+', b[i])
3496 elif tag == 'delete':
3483 elif tag == 'delete':
3497 for i in xrange(alo, ahi):
3484 for i in xrange(alo, ahi):
3498 yield ('-', a[i])
3485 yield ('-', a[i])
3499 elif tag == 'replace':
3486 elif tag == 'replace':
3500 for i in xrange(alo, ahi):
3487 for i in xrange(alo, ahi):
3501 yield ('-', a[i])
3488 yield ('-', a[i])
3502 for i in xrange(blo, bhi):
3489 for i in xrange(blo, bhi):
3503 yield ('+', b[i])
3490 yield ('+', b[i])
3504
3491
3505 def display(fm, fn, ctx, pstates, states):
3492 def display(fm, fn, ctx, pstates, states):
3506 rev = ctx.rev()
3493 rev = ctx.rev()
3507 if fm.isplain():
3494 if fm.isplain():
3508 formatuser = ui.shortuser
3495 formatuser = ui.shortuser
3509 else:
3496 else:
3510 formatuser = str
3497 formatuser = str
3511 if ui.quiet:
3498 if ui.quiet:
3512 datefmt = '%Y-%m-%d'
3499 datefmt = '%Y-%m-%d'
3513 else:
3500 else:
3514 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3501 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3515 found = False
3502 found = False
3516 @util.cachefunc
3503 @util.cachefunc
3517 def binary():
3504 def binary():
3518 flog = getfile(fn)
3505 flog = getfile(fn)
3519 return util.binary(flog.read(ctx.filenode(fn)))
3506 return util.binary(flog.read(ctx.filenode(fn)))
3520
3507
3521 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3508 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3522 if opts.get('all'):
3509 if opts.get('all'):
3523 iter = difflinestates(pstates, states)
3510 iter = difflinestates(pstates, states)
3524 else:
3511 else:
3525 iter = [('', l) for l in states]
3512 iter = [('', l) for l in states]
3526 for change, l in iter:
3513 for change, l in iter:
3527 fm.startitem()
3514 fm.startitem()
3528 fm.data(node=fm.hexfunc(ctx.node()))
3515 fm.data(node=fm.hexfunc(ctx.node()))
3529 cols = [
3516 cols = [
3530 ('filename', fn, True),
3517 ('filename', fn, True),
3531 ('rev', rev, True),
3518 ('rev', rev, True),
3532 ('linenumber', l.linenum, opts.get('line_number')),
3519 ('linenumber', l.linenum, opts.get('line_number')),
3533 ]
3520 ]
3534 if opts.get('all'):
3521 if opts.get('all'):
3535 cols.append(('change', change, True))
3522 cols.append(('change', change, True))
3536 cols.extend([
3523 cols.extend([
3537 ('user', formatuser(ctx.user()), opts.get('user')),
3524 ('user', formatuser(ctx.user()), opts.get('user')),
3538 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3525 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3539 ])
3526 ])
3540 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3527 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3541 for name, data, cond in cols:
3528 for name, data, cond in cols:
3542 field = fieldnamemap.get(name, name)
3529 field = fieldnamemap.get(name, name)
3543 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3530 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3544 if cond and name != lastcol:
3531 if cond and name != lastcol:
3545 fm.plain(sep, label='grep.sep')
3532 fm.plain(sep, label='grep.sep')
3546 if not opts.get('files_with_matches'):
3533 if not opts.get('files_with_matches'):
3547 fm.plain(sep, label='grep.sep')
3534 fm.plain(sep, label='grep.sep')
3548 if not opts.get('text') and binary():
3535 if not opts.get('text') and binary():
3549 fm.plain(_(" Binary file matches"))
3536 fm.plain(_(" Binary file matches"))
3550 else:
3537 else:
3551 displaymatches(fm.nested('texts'), l)
3538 displaymatches(fm.nested('texts'), l)
3552 fm.plain(eol)
3539 fm.plain(eol)
3553 found = True
3540 found = True
3554 if opts.get('files_with_matches'):
3541 if opts.get('files_with_matches'):
3555 break
3542 break
3556 return found
3543 return found
3557
3544
3558 def displaymatches(fm, l):
3545 def displaymatches(fm, l):
3559 p = 0
3546 p = 0
3560 for s, e in l.findpos():
3547 for s, e in l.findpos():
3561 if p < s:
3548 if p < s:
3562 fm.startitem()
3549 fm.startitem()
3563 fm.write('text', '%s', l.line[p:s])
3550 fm.write('text', '%s', l.line[p:s])
3564 fm.data(matched=False)
3551 fm.data(matched=False)
3565 fm.startitem()
3552 fm.startitem()
3566 fm.write('text', '%s', l.line[s:e], label='grep.match')
3553 fm.write('text', '%s', l.line[s:e], label='grep.match')
3567 fm.data(matched=True)
3554 fm.data(matched=True)
3568 p = e
3555 p = e
3569 if p < len(l.line):
3556 if p < len(l.line):
3570 fm.startitem()
3557 fm.startitem()
3571 fm.write('text', '%s', l.line[p:])
3558 fm.write('text', '%s', l.line[p:])
3572 fm.data(matched=False)
3559 fm.data(matched=False)
3573 fm.end()
3560 fm.end()
3574
3561
3575 skip = {}
3562 skip = {}
3576 revfiles = {}
3563 revfiles = {}
3577 matchfn = scmutil.match(repo[None], pats, opts)
3564 matchfn = scmutil.match(repo[None], pats, opts)
3578 found = False
3565 found = False
3579 follow = opts.get('follow')
3566 follow = opts.get('follow')
3580
3567
3581 def prep(ctx, fns):
3568 def prep(ctx, fns):
3582 rev = ctx.rev()
3569 rev = ctx.rev()
3583 pctx = ctx.p1()
3570 pctx = ctx.p1()
3584 parent = pctx.rev()
3571 parent = pctx.rev()
3585 matches.setdefault(rev, {})
3572 matches.setdefault(rev, {})
3586 matches.setdefault(parent, {})
3573 matches.setdefault(parent, {})
3587 files = revfiles.setdefault(rev, [])
3574 files = revfiles.setdefault(rev, [])
3588 for fn in fns:
3575 for fn in fns:
3589 flog = getfile(fn)
3576 flog = getfile(fn)
3590 try:
3577 try:
3591 fnode = ctx.filenode(fn)
3578 fnode = ctx.filenode(fn)
3592 except error.LookupError:
3579 except error.LookupError:
3593 continue
3580 continue
3594
3581
3595 copied = flog.renamed(fnode)
3582 copied = flog.renamed(fnode)
3596 copy = follow and copied and copied[0]
3583 copy = follow and copied and copied[0]
3597 if copy:
3584 if copy:
3598 copies.setdefault(rev, {})[fn] = copy
3585 copies.setdefault(rev, {})[fn] = copy
3599 if fn in skip:
3586 if fn in skip:
3600 if copy:
3587 if copy:
3601 skip[copy] = True
3588 skip[copy] = True
3602 continue
3589 continue
3603 files.append(fn)
3590 files.append(fn)
3604
3591
3605 if fn not in matches[rev]:
3592 if fn not in matches[rev]:
3606 grepbody(fn, rev, flog.read(fnode))
3593 grepbody(fn, rev, flog.read(fnode))
3607
3594
3608 pfn = copy or fn
3595 pfn = copy or fn
3609 if pfn not in matches[parent]:
3596 if pfn not in matches[parent]:
3610 try:
3597 try:
3611 fnode = pctx.filenode(pfn)
3598 fnode = pctx.filenode(pfn)
3612 grepbody(pfn, parent, flog.read(fnode))
3599 grepbody(pfn, parent, flog.read(fnode))
3613 except error.LookupError:
3600 except error.LookupError:
3614 pass
3601 pass
3615
3602
3616 fm = ui.formatter('grep', opts)
3603 fm = ui.formatter('grep', opts)
3617 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3604 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3618 rev = ctx.rev()
3605 rev = ctx.rev()
3619 parent = ctx.p1().rev()
3606 parent = ctx.p1().rev()
3620 for fn in sorted(revfiles.get(rev, [])):
3607 for fn in sorted(revfiles.get(rev, [])):
3621 states = matches[rev][fn]
3608 states = matches[rev][fn]
3622 copy = copies.get(rev, {}).get(fn)
3609 copy = copies.get(rev, {}).get(fn)
3623 if fn in skip:
3610 if fn in skip:
3624 if copy:
3611 if copy:
3625 skip[copy] = True
3612 skip[copy] = True
3626 continue
3613 continue
3627 pstates = matches.get(parent, {}).get(copy or fn, [])
3614 pstates = matches.get(parent, {}).get(copy or fn, [])
3628 if pstates or states:
3615 if pstates or states:
3629 r = display(fm, fn, ctx, pstates, states)
3616 r = display(fm, fn, ctx, pstates, states)
3630 found = found or r
3617 found = found or r
3631 if r and not opts.get('all'):
3618 if r and not opts.get('all'):
3632 skip[fn] = True
3619 skip[fn] = True
3633 if copy:
3620 if copy:
3634 skip[copy] = True
3621 skip[copy] = True
3635 del matches[rev]
3622 del matches[rev]
3636 del revfiles[rev]
3623 del revfiles[rev]
3637 fm.end()
3624 fm.end()
3638
3625
3639 return not found
3626 return not found
3640
3627
3641 @command('heads',
3628 @command('heads',
3642 [('r', 'rev', '',
3629 [('r', 'rev', '',
3643 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3630 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3644 ('t', 'topo', False, _('show topological heads only')),
3631 ('t', 'topo', False, _('show topological heads only')),
3645 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3632 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3646 ('c', 'closed', False, _('show normal and closed branch heads')),
3633 ('c', 'closed', False, _('show normal and closed branch heads')),
3647 ] + templateopts,
3634 ] + templateopts,
3648 _('[-ct] [-r STARTREV] [REV]...'))
3635 _('[-ct] [-r STARTREV] [REV]...'))
3649 def heads(ui, repo, *branchrevs, **opts):
3636 def heads(ui, repo, *branchrevs, **opts):
3650 """show branch heads
3637 """show branch heads
3651
3638
3652 With no arguments, show all open branch heads in the repository.
3639 With no arguments, show all open branch heads in the repository.
3653 Branch heads are changesets that have no descendants on the
3640 Branch heads are changesets that have no descendants on the
3654 same branch. They are where development generally takes place and
3641 same branch. They are where development generally takes place and
3655 are the usual targets for update and merge operations.
3642 are the usual targets for update and merge operations.
3656
3643
3657 If one or more REVs are given, only open branch heads on the
3644 If one or more REVs are given, only open branch heads on the
3658 branches associated with the specified changesets are shown. This
3645 branches associated with the specified changesets are shown. This
3659 means that you can use :hg:`heads .` to see the heads on the
3646 means that you can use :hg:`heads .` to see the heads on the
3660 currently checked-out branch.
3647 currently checked-out branch.
3661
3648
3662 If -c/--closed is specified, also show branch heads marked closed
3649 If -c/--closed is specified, also show branch heads marked closed
3663 (see :hg:`commit --close-branch`).
3650 (see :hg:`commit --close-branch`).
3664
3651
3665 If STARTREV is specified, only those heads that are descendants of
3652 If STARTREV is specified, only those heads that are descendants of
3666 STARTREV will be displayed.
3653 STARTREV will be displayed.
3667
3654
3668 If -t/--topo is specified, named branch mechanics will be ignored and only
3655 If -t/--topo is specified, named branch mechanics will be ignored and only
3669 topological heads (changesets with no children) will be shown.
3656 topological heads (changesets with no children) will be shown.
3670
3657
3671 Returns 0 if matching heads are found, 1 if not.
3658 Returns 0 if matching heads are found, 1 if not.
3672 """
3659 """
3673
3660
3674 start = None
3661 start = None
3675 if 'rev' in opts:
3662 if 'rev' in opts:
3676 start = scmutil.revsingle(repo, opts['rev'], None).node()
3663 start = scmutil.revsingle(repo, opts['rev'], None).node()
3677
3664
3678 if opts.get('topo'):
3665 if opts.get('topo'):
3679 heads = [repo[h] for h in repo.heads(start)]
3666 heads = [repo[h] for h in repo.heads(start)]
3680 else:
3667 else:
3681 heads = []
3668 heads = []
3682 for branch in repo.branchmap():
3669 for branch in repo.branchmap():
3683 heads += repo.branchheads(branch, start, opts.get('closed'))
3670 heads += repo.branchheads(branch, start, opts.get('closed'))
3684 heads = [repo[h] for h in heads]
3671 heads = [repo[h] for h in heads]
3685
3672
3686 if branchrevs:
3673 if branchrevs:
3687 branches = set(repo[br].branch() for br in branchrevs)
3674 branches = set(repo[br].branch() for br in branchrevs)
3688 heads = [h for h in heads if h.branch() in branches]
3675 heads = [h for h in heads if h.branch() in branches]
3689
3676
3690 if opts.get('active') and branchrevs:
3677 if opts.get('active') and branchrevs:
3691 dagheads = repo.heads(start)
3678 dagheads = repo.heads(start)
3692 heads = [h for h in heads if h.node() in dagheads]
3679 heads = [h for h in heads if h.node() in dagheads]
3693
3680
3694 if branchrevs:
3681 if branchrevs:
3695 haveheads = set(h.branch() for h in heads)
3682 haveheads = set(h.branch() for h in heads)
3696 if branches - haveheads:
3683 if branches - haveheads:
3697 headless = ', '.join(b for b in branches - haveheads)
3684 headless = ', '.join(b for b in branches - haveheads)
3698 msg = _('no open branch heads found on branches %s')
3685 msg = _('no open branch heads found on branches %s')
3699 if opts.get('rev'):
3686 if opts.get('rev'):
3700 msg += _(' (started at %s)') % opts['rev']
3687 msg += _(' (started at %s)') % opts['rev']
3701 ui.warn((msg + '\n') % headless)
3688 ui.warn((msg + '\n') % headless)
3702
3689
3703 if not heads:
3690 if not heads:
3704 return 1
3691 return 1
3705
3692
3706 heads = sorted(heads, key=lambda x: -x.rev())
3693 heads = sorted(heads, key=lambda x: -x.rev())
3707 displayer = cmdutil.show_changeset(ui, repo, opts)
3694 displayer = cmdutil.show_changeset(ui, repo, opts)
3708 for ctx in heads:
3695 for ctx in heads:
3709 displayer.show(ctx)
3696 displayer.show(ctx)
3710 displayer.close()
3697 displayer.close()
3711
3698
3712 @command('help',
3699 @command('help',
3713 [('e', 'extension', None, _('show only help for extensions')),
3700 [('e', 'extension', None, _('show only help for extensions')),
3714 ('c', 'command', None, _('show only help for commands')),
3701 ('c', 'command', None, _('show only help for commands')),
3715 ('k', 'keyword', None, _('show topics matching keyword')),
3702 ('k', 'keyword', None, _('show topics matching keyword')),
3716 ('s', 'system', [], _('show help for specific platform(s)')),
3703 ('s', 'system', [], _('show help for specific platform(s)')),
3717 ],
3704 ],
3718 _('[-ecks] [TOPIC]'),
3705 _('[-ecks] [TOPIC]'),
3719 norepo=True)
3706 norepo=True)
3720 def help_(ui, name=None, **opts):
3707 def help_(ui, name=None, **opts):
3721 """show help for a given topic or a help overview
3708 """show help for a given topic or a help overview
3722
3709
3723 With no arguments, print a list of commands with short help messages.
3710 With no arguments, print a list of commands with short help messages.
3724
3711
3725 Given a topic, extension, or command name, print help for that
3712 Given a topic, extension, or command name, print help for that
3726 topic.
3713 topic.
3727
3714
3728 Returns 0 if successful.
3715 Returns 0 if successful.
3729 """
3716 """
3730
3717
3731 textwidth = ui.configint('ui', 'textwidth', 78)
3718 textwidth = ui.configint('ui', 'textwidth', 78)
3732 termwidth = ui.termwidth() - 2
3719 termwidth = ui.termwidth() - 2
3733 if textwidth <= 0 or termwidth < textwidth:
3720 if textwidth <= 0 or termwidth < textwidth:
3734 textwidth = termwidth
3721 textwidth = termwidth
3735
3722
3736 keep = opts.get('system') or []
3723 keep = opts.get('system') or []
3737 if len(keep) == 0:
3724 if len(keep) == 0:
3738 if pycompat.sysplatform.startswith('win'):
3725 if pycompat.sysplatform.startswith('win'):
3739 keep.append('windows')
3726 keep.append('windows')
3740 elif pycompat.sysplatform == 'OpenVMS':
3727 elif pycompat.sysplatform == 'OpenVMS':
3741 keep.append('vms')
3728 keep.append('vms')
3742 elif pycompat.sysplatform == 'plan9':
3729 elif pycompat.sysplatform == 'plan9':
3743 keep.append('plan9')
3730 keep.append('plan9')
3744 else:
3731 else:
3745 keep.append('unix')
3732 keep.append('unix')
3746 keep.append(pycompat.sysplatform.lower())
3733 keep.append(pycompat.sysplatform.lower())
3747 if ui.verbose:
3734 if ui.verbose:
3748 keep.append('verbose')
3735 keep.append('verbose')
3749
3736
3750 fullname = name
3737 fullname = name
3751 section = None
3738 section = None
3752 subtopic = None
3739 subtopic = None
3753 if name and '.' in name:
3740 if name and '.' in name:
3754 name, remaining = name.split('.', 1)
3741 name, remaining = name.split('.', 1)
3755 remaining = encoding.lower(remaining)
3742 remaining = encoding.lower(remaining)
3756 if '.' in remaining:
3743 if '.' in remaining:
3757 subtopic, section = remaining.split('.', 1)
3744 subtopic, section = remaining.split('.', 1)
3758 else:
3745 else:
3759 if name in help.subtopics:
3746 if name in help.subtopics:
3760 subtopic = remaining
3747 subtopic = remaining
3761 else:
3748 else:
3762 section = remaining
3749 section = remaining
3763
3750
3764 text = help.help_(ui, name, subtopic=subtopic, **opts)
3751 text = help.help_(ui, name, subtopic=subtopic, **opts)
3765
3752
3766 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3753 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3767 section=section)
3754 section=section)
3768
3755
3769 # We could have been given a weird ".foo" section without a name
3756 # We could have been given a weird ".foo" section without a name
3770 # to look for, or we could have simply failed to found "foo.bar"
3757 # to look for, or we could have simply failed to found "foo.bar"
3771 # because bar isn't a section of foo
3758 # because bar isn't a section of foo
3772 if section and not (formatted and name):
3759 if section and not (formatted and name):
3773 raise error.Abort(_("help section not found: %s") % fullname)
3760 raise error.Abort(_("help section not found: %s") % fullname)
3774
3761
3775 if 'verbose' in pruned:
3762 if 'verbose' in pruned:
3776 keep.append('omitted')
3763 keep.append('omitted')
3777 else:
3764 else:
3778 keep.append('notomitted')
3765 keep.append('notomitted')
3779 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3766 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3780 section=section)
3767 section=section)
3781 ui.write(formatted)
3768 ui.write(formatted)
3782
3769
3783
3770
3784 @command('identify|id',
3771 @command('identify|id',
3785 [('r', 'rev', '',
3772 [('r', 'rev', '',
3786 _('identify the specified revision'), _('REV')),
3773 _('identify the specified revision'), _('REV')),
3787 ('n', 'num', None, _('show local revision number')),
3774 ('n', 'num', None, _('show local revision number')),
3788 ('i', 'id', None, _('show global revision id')),
3775 ('i', 'id', None, _('show global revision id')),
3789 ('b', 'branch', None, _('show branch')),
3776 ('b', 'branch', None, _('show branch')),
3790 ('t', 'tags', None, _('show tags')),
3777 ('t', 'tags', None, _('show tags')),
3791 ('B', 'bookmarks', None, _('show bookmarks')),
3778 ('B', 'bookmarks', None, _('show bookmarks')),
3792 ] + remoteopts,
3779 ] + remoteopts,
3793 _('[-nibtB] [-r REV] [SOURCE]'),
3780 _('[-nibtB] [-r REV] [SOURCE]'),
3794 optionalrepo=True)
3781 optionalrepo=True)
3795 def identify(ui, repo, source=None, rev=None,
3782 def identify(ui, repo, source=None, rev=None,
3796 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3783 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3797 """identify the working directory or specified revision
3784 """identify the working directory or specified revision
3798
3785
3799 Print a summary identifying the repository state at REV using one or
3786 Print a summary identifying the repository state at REV using one or
3800 two parent hash identifiers, followed by a "+" if the working
3787 two parent hash identifiers, followed by a "+" if the working
3801 directory has uncommitted changes, the branch name (if not default),
3788 directory has uncommitted changes, the branch name (if not default),
3802 a list of tags, and a list of bookmarks.
3789 a list of tags, and a list of bookmarks.
3803
3790
3804 When REV is not given, print a summary of the current state of the
3791 When REV is not given, print a summary of the current state of the
3805 repository.
3792 repository.
3806
3793
3807 Specifying a path to a repository root or Mercurial bundle will
3794 Specifying a path to a repository root or Mercurial bundle will
3808 cause lookup to operate on that repository/bundle.
3795 cause lookup to operate on that repository/bundle.
3809
3796
3810 .. container:: verbose
3797 .. container:: verbose
3811
3798
3812 Examples:
3799 Examples:
3813
3800
3814 - generate a build identifier for the working directory::
3801 - generate a build identifier for the working directory::
3815
3802
3816 hg id --id > build-id.dat
3803 hg id --id > build-id.dat
3817
3804
3818 - find the revision corresponding to a tag::
3805 - find the revision corresponding to a tag::
3819
3806
3820 hg id -n -r 1.3
3807 hg id -n -r 1.3
3821
3808
3822 - check the most recent revision of a remote repository::
3809 - check the most recent revision of a remote repository::
3823
3810
3824 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3811 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3825
3812
3826 See :hg:`log` for generating more information about specific revisions,
3813 See :hg:`log` for generating more information about specific revisions,
3827 including full hash identifiers.
3814 including full hash identifiers.
3828
3815
3829 Returns 0 if successful.
3816 Returns 0 if successful.
3830 """
3817 """
3831
3818
3832 if not repo and not source:
3819 if not repo and not source:
3833 raise error.Abort(_("there is no Mercurial repository here "
3820 raise error.Abort(_("there is no Mercurial repository here "
3834 "(.hg not found)"))
3821 "(.hg not found)"))
3835
3822
3836 if ui.debugflag:
3823 if ui.debugflag:
3837 hexfunc = hex
3824 hexfunc = hex
3838 else:
3825 else:
3839 hexfunc = short
3826 hexfunc = short
3840 default = not (num or id or branch or tags or bookmarks)
3827 default = not (num or id or branch or tags or bookmarks)
3841 output = []
3828 output = []
3842 revs = []
3829 revs = []
3843
3830
3844 if source:
3831 if source:
3845 source, branches = hg.parseurl(ui.expandpath(source))
3832 source, branches = hg.parseurl(ui.expandpath(source))
3846 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3833 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3847 repo = peer.local()
3834 repo = peer.local()
3848 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3835 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3849
3836
3850 if not repo:
3837 if not repo:
3851 if num or branch or tags:
3838 if num or branch or tags:
3852 raise error.Abort(
3839 raise error.Abort(
3853 _("can't query remote revision number, branch, or tags"))
3840 _("can't query remote revision number, branch, or tags"))
3854 if not rev and revs:
3841 if not rev and revs:
3855 rev = revs[0]
3842 rev = revs[0]
3856 if not rev:
3843 if not rev:
3857 rev = "tip"
3844 rev = "tip"
3858
3845
3859 remoterev = peer.lookup(rev)
3846 remoterev = peer.lookup(rev)
3860 if default or id:
3847 if default or id:
3861 output = [hexfunc(remoterev)]
3848 output = [hexfunc(remoterev)]
3862
3849
3863 def getbms():
3850 def getbms():
3864 bms = []
3851 bms = []
3865
3852
3866 if 'bookmarks' in peer.listkeys('namespaces'):
3853 if 'bookmarks' in peer.listkeys('namespaces'):
3867 hexremoterev = hex(remoterev)
3854 hexremoterev = hex(remoterev)
3868 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3855 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3869 if bmr == hexremoterev]
3856 if bmr == hexremoterev]
3870
3857
3871 return sorted(bms)
3858 return sorted(bms)
3872
3859
3873 if bookmarks:
3860 if bookmarks:
3874 output.extend(getbms())
3861 output.extend(getbms())
3875 elif default and not ui.quiet:
3862 elif default and not ui.quiet:
3876 # multiple bookmarks for a single parent separated by '/'
3863 # multiple bookmarks for a single parent separated by '/'
3877 bm = '/'.join(getbms())
3864 bm = '/'.join(getbms())
3878 if bm:
3865 if bm:
3879 output.append(bm)
3866 output.append(bm)
3880 else:
3867 else:
3881 ctx = scmutil.revsingle(repo, rev, None)
3868 ctx = scmutil.revsingle(repo, rev, None)
3882
3869
3883 if ctx.rev() is None:
3870 if ctx.rev() is None:
3884 ctx = repo[None]
3871 ctx = repo[None]
3885 parents = ctx.parents()
3872 parents = ctx.parents()
3886 taglist = []
3873 taglist = []
3887 for p in parents:
3874 for p in parents:
3888 taglist.extend(p.tags())
3875 taglist.extend(p.tags())
3889
3876
3890 changed = ""
3877 changed = ""
3891 if default or id or num:
3878 if default or id or num:
3892 if (any(repo.status())
3879 if (any(repo.status())
3893 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3880 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3894 changed = '+'
3881 changed = '+'
3895 if default or id:
3882 if default or id:
3896 output = ["%s%s" %
3883 output = ["%s%s" %
3897 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3884 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3898 if num:
3885 if num:
3899 output.append("%s%s" %
3886 output.append("%s%s" %
3900 ('+'.join([str(p.rev()) for p in parents]), changed))
3887 ('+'.join([str(p.rev()) for p in parents]), changed))
3901 else:
3888 else:
3902 if default or id:
3889 if default or id:
3903 output = [hexfunc(ctx.node())]
3890 output = [hexfunc(ctx.node())]
3904 if num:
3891 if num:
3905 output.append(str(ctx.rev()))
3892 output.append(str(ctx.rev()))
3906 taglist = ctx.tags()
3893 taglist = ctx.tags()
3907
3894
3908 if default and not ui.quiet:
3895 if default and not ui.quiet:
3909 b = ctx.branch()
3896 b = ctx.branch()
3910 if b != 'default':
3897 if b != 'default':
3911 output.append("(%s)" % b)
3898 output.append("(%s)" % b)
3912
3899
3913 # multiple tags for a single parent separated by '/'
3900 # multiple tags for a single parent separated by '/'
3914 t = '/'.join(taglist)
3901 t = '/'.join(taglist)
3915 if t:
3902 if t:
3916 output.append(t)
3903 output.append(t)
3917
3904
3918 # multiple bookmarks for a single parent separated by '/'
3905 # multiple bookmarks for a single parent separated by '/'
3919 bm = '/'.join(ctx.bookmarks())
3906 bm = '/'.join(ctx.bookmarks())
3920 if bm:
3907 if bm:
3921 output.append(bm)
3908 output.append(bm)
3922 else:
3909 else:
3923 if branch:
3910 if branch:
3924 output.append(ctx.branch())
3911 output.append(ctx.branch())
3925
3912
3926 if tags:
3913 if tags:
3927 output.extend(taglist)
3914 output.extend(taglist)
3928
3915
3929 if bookmarks:
3916 if bookmarks:
3930 output.extend(ctx.bookmarks())
3917 output.extend(ctx.bookmarks())
3931
3918
3932 ui.write("%s\n" % ' '.join(output))
3919 ui.write("%s\n" % ' '.join(output))
3933
3920
3934 @command('import|patch',
3921 @command('import|patch',
3935 [('p', 'strip', 1,
3922 [('p', 'strip', 1,
3936 _('directory strip option for patch. This has the same '
3923 _('directory strip option for patch. This has the same '
3937 'meaning as the corresponding patch option'), _('NUM')),
3924 'meaning as the corresponding patch option'), _('NUM')),
3938 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3925 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3939 ('e', 'edit', False, _('invoke editor on commit messages')),
3926 ('e', 'edit', False, _('invoke editor on commit messages')),
3940 ('f', 'force', None,
3927 ('f', 'force', None,
3941 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3928 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3942 ('', 'no-commit', None,
3929 ('', 'no-commit', None,
3943 _("don't commit, just update the working directory")),
3930 _("don't commit, just update the working directory")),
3944 ('', 'bypass', None,
3931 ('', 'bypass', None,
3945 _("apply patch without touching the working directory")),
3932 _("apply patch without touching the working directory")),
3946 ('', 'partial', None,
3933 ('', 'partial', None,
3947 _('commit even if some hunks fail')),
3934 _('commit even if some hunks fail')),
3948 ('', 'exact', None,
3935 ('', 'exact', None,
3949 _('abort if patch would apply lossily')),
3936 _('abort if patch would apply lossily')),
3950 ('', 'prefix', '',
3937 ('', 'prefix', '',
3951 _('apply patch to subdirectory'), _('DIR')),
3938 _('apply patch to subdirectory'), _('DIR')),
3952 ('', 'import-branch', None,
3939 ('', 'import-branch', None,
3953 _('use any branch information in patch (implied by --exact)'))] +
3940 _('use any branch information in patch (implied by --exact)'))] +
3954 commitopts + commitopts2 + similarityopts,
3941 commitopts + commitopts2 + similarityopts,
3955 _('[OPTION]... PATCH...'))
3942 _('[OPTION]... PATCH...'))
3956 def import_(ui, repo, patch1=None, *patches, **opts):
3943 def import_(ui, repo, patch1=None, *patches, **opts):
3957 """import an ordered set of patches
3944 """import an ordered set of patches
3958
3945
3959 Import a list of patches and commit them individually (unless
3946 Import a list of patches and commit them individually (unless
3960 --no-commit is specified).
3947 --no-commit is specified).
3961
3948
3962 To read a patch from standard input (stdin), use "-" as the patch
3949 To read a patch from standard input (stdin), use "-" as the patch
3963 name. If a URL is specified, the patch will be downloaded from
3950 name. If a URL is specified, the patch will be downloaded from
3964 there.
3951 there.
3965
3952
3966 Import first applies changes to the working directory (unless
3953 Import first applies changes to the working directory (unless
3967 --bypass is specified), import will abort if there are outstanding
3954 --bypass is specified), import will abort if there are outstanding
3968 changes.
3955 changes.
3969
3956
3970 Use --bypass to apply and commit patches directly to the
3957 Use --bypass to apply and commit patches directly to the
3971 repository, without affecting the working directory. Without
3958 repository, without affecting the working directory. Without
3972 --exact, patches will be applied on top of the working directory
3959 --exact, patches will be applied on top of the working directory
3973 parent revision.
3960 parent revision.
3974
3961
3975 You can import a patch straight from a mail message. Even patches
3962 You can import a patch straight from a mail message. Even patches
3976 as attachments work (to use the body part, it must have type
3963 as attachments work (to use the body part, it must have type
3977 text/plain or text/x-patch). From and Subject headers of email
3964 text/plain or text/x-patch). From and Subject headers of email
3978 message are used as default committer and commit message. All
3965 message are used as default committer and commit message. All
3979 text/plain body parts before first diff are added to the commit
3966 text/plain body parts before first diff are added to the commit
3980 message.
3967 message.
3981
3968
3982 If the imported patch was generated by :hg:`export`, user and
3969 If the imported patch was generated by :hg:`export`, user and
3983 description from patch override values from message headers and
3970 description from patch override values from message headers and
3984 body. Values given on command line with -m/--message and -u/--user
3971 body. Values given on command line with -m/--message and -u/--user
3985 override these.
3972 override these.
3986
3973
3987 If --exact is specified, import will set the working directory to
3974 If --exact is specified, import will set the working directory to
3988 the parent of each patch before applying it, and will abort if the
3975 the parent of each patch before applying it, and will abort if the
3989 resulting changeset has a different ID than the one recorded in
3976 resulting changeset has a different ID than the one recorded in
3990 the patch. This will guard against various ways that portable
3977 the patch. This will guard against various ways that portable
3991 patch formats and mail systems might fail to transfer Mercurial
3978 patch formats and mail systems might fail to transfer Mercurial
3992 data or metadata. See :hg:`bundle` for lossless transmission.
3979 data or metadata. See :hg:`bundle` for lossless transmission.
3993
3980
3994 Use --partial to ensure a changeset will be created from the patch
3981 Use --partial to ensure a changeset will be created from the patch
3995 even if some hunks fail to apply. Hunks that fail to apply will be
3982 even if some hunks fail to apply. Hunks that fail to apply will be
3996 written to a <target-file>.rej file. Conflicts can then be resolved
3983 written to a <target-file>.rej file. Conflicts can then be resolved
3997 by hand before :hg:`commit --amend` is run to update the created
3984 by hand before :hg:`commit --amend` is run to update the created
3998 changeset. This flag exists to let people import patches that
3985 changeset. This flag exists to let people import patches that
3999 partially apply without losing the associated metadata (author,
3986 partially apply without losing the associated metadata (author,
4000 date, description, ...).
3987 date, description, ...).
4001
3988
4002 .. note::
3989 .. note::
4003
3990
4004 When no hunks apply cleanly, :hg:`import --partial` will create
3991 When no hunks apply cleanly, :hg:`import --partial` will create
4005 an empty changeset, importing only the patch metadata.
3992 an empty changeset, importing only the patch metadata.
4006
3993
4007 With -s/--similarity, hg will attempt to discover renames and
3994 With -s/--similarity, hg will attempt to discover renames and
4008 copies in the patch in the same way as :hg:`addremove`.
3995 copies in the patch in the same way as :hg:`addremove`.
4009
3996
4010 It is possible to use external patch programs to perform the patch
3997 It is possible to use external patch programs to perform the patch
4011 by setting the ``ui.patch`` configuration option. For the default
3998 by setting the ``ui.patch`` configuration option. For the default
4012 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3999 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4013 See :hg:`help config` for more information about configuration
4000 See :hg:`help config` for more information about configuration
4014 files and how to use these options.
4001 files and how to use these options.
4015
4002
4016 See :hg:`help dates` for a list of formats valid for -d/--date.
4003 See :hg:`help dates` for a list of formats valid for -d/--date.
4017
4004
4018 .. container:: verbose
4005 .. container:: verbose
4019
4006
4020 Examples:
4007 Examples:
4021
4008
4022 - import a traditional patch from a website and detect renames::
4009 - import a traditional patch from a website and detect renames::
4023
4010
4024 hg import -s 80 http://example.com/bugfix.patch
4011 hg import -s 80 http://example.com/bugfix.patch
4025
4012
4026 - import a changeset from an hgweb server::
4013 - import a changeset from an hgweb server::
4027
4014
4028 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4015 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4029
4016
4030 - import all the patches in an Unix-style mbox::
4017 - import all the patches in an Unix-style mbox::
4031
4018
4032 hg import incoming-patches.mbox
4019 hg import incoming-patches.mbox
4033
4020
4034 - import patches from stdin::
4021 - import patches from stdin::
4035
4022
4036 hg import -
4023 hg import -
4037
4024
4038 - attempt to exactly restore an exported changeset (not always
4025 - attempt to exactly restore an exported changeset (not always
4039 possible)::
4026 possible)::
4040
4027
4041 hg import --exact proposed-fix.patch
4028 hg import --exact proposed-fix.patch
4042
4029
4043 - use an external tool to apply a patch which is too fuzzy for
4030 - use an external tool to apply a patch which is too fuzzy for
4044 the default internal tool.
4031 the default internal tool.
4045
4032
4046 hg import --config ui.patch="patch --merge" fuzzy.patch
4033 hg import --config ui.patch="patch --merge" fuzzy.patch
4047
4034
4048 - change the default fuzzing from 2 to a less strict 7
4035 - change the default fuzzing from 2 to a less strict 7
4049
4036
4050 hg import --config ui.fuzz=7 fuzz.patch
4037 hg import --config ui.fuzz=7 fuzz.patch
4051
4038
4052 Returns 0 on success, 1 on partial success (see --partial).
4039 Returns 0 on success, 1 on partial success (see --partial).
4053 """
4040 """
4054
4041
4055 if not patch1:
4042 if not patch1:
4056 raise error.Abort(_('need at least one patch to import'))
4043 raise error.Abort(_('need at least one patch to import'))
4057
4044
4058 patches = (patch1,) + patches
4045 patches = (patch1,) + patches
4059
4046
4060 date = opts.get('date')
4047 date = opts.get('date')
4061 if date:
4048 if date:
4062 opts['date'] = util.parsedate(date)
4049 opts['date'] = util.parsedate(date)
4063
4050
4064 exact = opts.get('exact')
4051 exact = opts.get('exact')
4065 update = not opts.get('bypass')
4052 update = not opts.get('bypass')
4066 if not update and opts.get('no_commit'):
4053 if not update and opts.get('no_commit'):
4067 raise error.Abort(_('cannot use --no-commit with --bypass'))
4054 raise error.Abort(_('cannot use --no-commit with --bypass'))
4068 try:
4055 try:
4069 sim = float(opts.get('similarity') or 0)
4056 sim = float(opts.get('similarity') or 0)
4070 except ValueError:
4057 except ValueError:
4071 raise error.Abort(_('similarity must be a number'))
4058 raise error.Abort(_('similarity must be a number'))
4072 if sim < 0 or sim > 100:
4059 if sim < 0 or sim > 100:
4073 raise error.Abort(_('similarity must be between 0 and 100'))
4060 raise error.Abort(_('similarity must be between 0 and 100'))
4074 if sim and not update:
4061 if sim and not update:
4075 raise error.Abort(_('cannot use --similarity with --bypass'))
4062 raise error.Abort(_('cannot use --similarity with --bypass'))
4076 if exact:
4063 if exact:
4077 if opts.get('edit'):
4064 if opts.get('edit'):
4078 raise error.Abort(_('cannot use --exact with --edit'))
4065 raise error.Abort(_('cannot use --exact with --edit'))
4079 if opts.get('prefix'):
4066 if opts.get('prefix'):
4080 raise error.Abort(_('cannot use --exact with --prefix'))
4067 raise error.Abort(_('cannot use --exact with --prefix'))
4081
4068
4082 base = opts["base"]
4069 base = opts["base"]
4083 wlock = dsguard = lock = tr = None
4070 wlock = dsguard = lock = tr = None
4084 msgs = []
4071 msgs = []
4085 ret = 0
4072 ret = 0
4086
4073
4087
4074
4088 try:
4075 try:
4089 wlock = repo.wlock()
4076 wlock = repo.wlock()
4090
4077
4091 if update:
4078 if update:
4092 cmdutil.checkunfinished(repo)
4079 cmdutil.checkunfinished(repo)
4093 if (exact or not opts.get('force')):
4080 if (exact or not opts.get('force')):
4094 cmdutil.bailifchanged(repo)
4081 cmdutil.bailifchanged(repo)
4095
4082
4096 if not opts.get('no_commit'):
4083 if not opts.get('no_commit'):
4097 lock = repo.lock()
4084 lock = repo.lock()
4098 tr = repo.transaction('import')
4085 tr = repo.transaction('import')
4099 else:
4086 else:
4100 dsguard = dirstateguard.dirstateguard(repo, 'import')
4087 dsguard = dirstateguard.dirstateguard(repo, 'import')
4101 parents = repo[None].parents()
4088 parents = repo[None].parents()
4102 for patchurl in patches:
4089 for patchurl in patches:
4103 if patchurl == '-':
4090 if patchurl == '-':
4104 ui.status(_('applying patch from stdin\n'))
4091 ui.status(_('applying patch from stdin\n'))
4105 patchfile = ui.fin
4092 patchfile = ui.fin
4106 patchurl = 'stdin' # for error message
4093 patchurl = 'stdin' # for error message
4107 else:
4094 else:
4108 patchurl = os.path.join(base, patchurl)
4095 patchurl = os.path.join(base, patchurl)
4109 ui.status(_('applying %s\n') % patchurl)
4096 ui.status(_('applying %s\n') % patchurl)
4110 patchfile = hg.openpath(ui, patchurl)
4097 patchfile = hg.openpath(ui, patchurl)
4111
4098
4112 haspatch = False
4099 haspatch = False
4113 for hunk in patch.split(patchfile):
4100 for hunk in patch.split(patchfile):
4114 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4101 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4115 parents, opts,
4102 parents, opts,
4116 msgs, hg.clean)
4103 msgs, hg.clean)
4117 if msg:
4104 if msg:
4118 haspatch = True
4105 haspatch = True
4119 ui.note(msg + '\n')
4106 ui.note(msg + '\n')
4120 if update or exact:
4107 if update or exact:
4121 parents = repo[None].parents()
4108 parents = repo[None].parents()
4122 else:
4109 else:
4123 parents = [repo[node]]
4110 parents = [repo[node]]
4124 if rej:
4111 if rej:
4125 ui.write_err(_("patch applied partially\n"))
4112 ui.write_err(_("patch applied partially\n"))
4126 ui.write_err(_("(fix the .rej files and run "
4113 ui.write_err(_("(fix the .rej files and run "
4127 "`hg commit --amend`)\n"))
4114 "`hg commit --amend`)\n"))
4128 ret = 1
4115 ret = 1
4129 break
4116 break
4130
4117
4131 if not haspatch:
4118 if not haspatch:
4132 raise error.Abort(_('%s: no diffs found') % patchurl)
4119 raise error.Abort(_('%s: no diffs found') % patchurl)
4133
4120
4134 if tr:
4121 if tr:
4135 tr.close()
4122 tr.close()
4136 if msgs:
4123 if msgs:
4137 repo.savecommitmessage('\n* * *\n'.join(msgs))
4124 repo.savecommitmessage('\n* * *\n'.join(msgs))
4138 if dsguard:
4125 if dsguard:
4139 dsguard.close()
4126 dsguard.close()
4140 return ret
4127 return ret
4141 finally:
4128 finally:
4142 if tr:
4129 if tr:
4143 tr.release()
4130 tr.release()
4144 release(lock, dsguard, wlock)
4131 release(lock, dsguard, wlock)
4145
4132
4146 @command('incoming|in',
4133 @command('incoming|in',
4147 [('f', 'force', None,
4134 [('f', 'force', None,
4148 _('run even if remote repository is unrelated')),
4135 _('run even if remote repository is unrelated')),
4149 ('n', 'newest-first', None, _('show newest record first')),
4136 ('n', 'newest-first', None, _('show newest record first')),
4150 ('', 'bundle', '',
4137 ('', 'bundle', '',
4151 _('file to store the bundles into'), _('FILE')),
4138 _('file to store the bundles into'), _('FILE')),
4152 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4139 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4153 ('B', 'bookmarks', False, _("compare bookmarks")),
4140 ('B', 'bookmarks', False, _("compare bookmarks")),
4154 ('b', 'branch', [],
4141 ('b', 'branch', [],
4155 _('a specific branch you would like to pull'), _('BRANCH')),
4142 _('a specific branch you would like to pull'), _('BRANCH')),
4156 ] + logopts + remoteopts + subrepoopts,
4143 ] + logopts + remoteopts + subrepoopts,
4157 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4144 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4158 def incoming(ui, repo, source="default", **opts):
4145 def incoming(ui, repo, source="default", **opts):
4159 """show new changesets found in source
4146 """show new changesets found in source
4160
4147
4161 Show new changesets found in the specified path/URL or the default
4148 Show new changesets found in the specified path/URL or the default
4162 pull location. These are the changesets that would have been pulled
4149 pull location. These are the changesets that would have been pulled
4163 if a pull at the time you issued this command.
4150 if a pull at the time you issued this command.
4164
4151
4165 See pull for valid source format details.
4152 See pull for valid source format details.
4166
4153
4167 .. container:: verbose
4154 .. container:: verbose
4168
4155
4169 With -B/--bookmarks, the result of bookmark comparison between
4156 With -B/--bookmarks, the result of bookmark comparison between
4170 local and remote repositories is displayed. With -v/--verbose,
4157 local and remote repositories is displayed. With -v/--verbose,
4171 status is also displayed for each bookmark like below::
4158 status is also displayed for each bookmark like below::
4172
4159
4173 BM1 01234567890a added
4160 BM1 01234567890a added
4174 BM2 1234567890ab advanced
4161 BM2 1234567890ab advanced
4175 BM3 234567890abc diverged
4162 BM3 234567890abc diverged
4176 BM4 34567890abcd changed
4163 BM4 34567890abcd changed
4177
4164
4178 The action taken locally when pulling depends on the
4165 The action taken locally when pulling depends on the
4179 status of each bookmark:
4166 status of each bookmark:
4180
4167
4181 :``added``: pull will create it
4168 :``added``: pull will create it
4182 :``advanced``: pull will update it
4169 :``advanced``: pull will update it
4183 :``diverged``: pull will create a divergent bookmark
4170 :``diverged``: pull will create a divergent bookmark
4184 :``changed``: result depends on remote changesets
4171 :``changed``: result depends on remote changesets
4185
4172
4186 From the point of view of pulling behavior, bookmark
4173 From the point of view of pulling behavior, bookmark
4187 existing only in the remote repository are treated as ``added``,
4174 existing only in the remote repository are treated as ``added``,
4188 even if it is in fact locally deleted.
4175 even if it is in fact locally deleted.
4189
4176
4190 .. container:: verbose
4177 .. container:: verbose
4191
4178
4192 For remote repository, using --bundle avoids downloading the
4179 For remote repository, using --bundle avoids downloading the
4193 changesets twice if the incoming is followed by a pull.
4180 changesets twice if the incoming is followed by a pull.
4194
4181
4195 Examples:
4182 Examples:
4196
4183
4197 - show incoming changes with patches and full description::
4184 - show incoming changes with patches and full description::
4198
4185
4199 hg incoming -vp
4186 hg incoming -vp
4200
4187
4201 - show incoming changes excluding merges, store a bundle::
4188 - show incoming changes excluding merges, store a bundle::
4202
4189
4203 hg in -vpM --bundle incoming.hg
4190 hg in -vpM --bundle incoming.hg
4204 hg pull incoming.hg
4191 hg pull incoming.hg
4205
4192
4206 - briefly list changes inside a bundle::
4193 - briefly list changes inside a bundle::
4207
4194
4208 hg in changes.hg -T "{desc|firstline}\\n"
4195 hg in changes.hg -T "{desc|firstline}\\n"
4209
4196
4210 Returns 0 if there are incoming changes, 1 otherwise.
4197 Returns 0 if there are incoming changes, 1 otherwise.
4211 """
4198 """
4212 if opts.get('graph'):
4199 if opts.get('graph'):
4213 cmdutil.checkunsupportedgraphflags([], opts)
4200 cmdutil.checkunsupportedgraphflags([], opts)
4214 def display(other, chlist, displayer):
4201 def display(other, chlist, displayer):
4215 revdag = cmdutil.graphrevs(other, chlist, opts)
4202 revdag = cmdutil.graphrevs(other, chlist, opts)
4216 cmdutil.displaygraph(ui, repo, revdag, displayer,
4203 cmdutil.displaygraph(ui, repo, revdag, displayer,
4217 graphmod.asciiedges)
4204 graphmod.asciiedges)
4218
4205
4219 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4206 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4220 return 0
4207 return 0
4221
4208
4222 if opts.get('bundle') and opts.get('subrepos'):
4209 if opts.get('bundle') and opts.get('subrepos'):
4223 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4210 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4224
4211
4225 if opts.get('bookmarks'):
4212 if opts.get('bookmarks'):
4226 source, branches = hg.parseurl(ui.expandpath(source),
4213 source, branches = hg.parseurl(ui.expandpath(source),
4227 opts.get('branch'))
4214 opts.get('branch'))
4228 other = hg.peer(repo, opts, source)
4215 other = hg.peer(repo, opts, source)
4229 if 'bookmarks' not in other.listkeys('namespaces'):
4216 if 'bookmarks' not in other.listkeys('namespaces'):
4230 ui.warn(_("remote doesn't support bookmarks\n"))
4217 ui.warn(_("remote doesn't support bookmarks\n"))
4231 return 0
4218 return 0
4232 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4219 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4233 return bookmarks.incoming(ui, repo, other)
4220 return bookmarks.incoming(ui, repo, other)
4234
4221
4235 repo._subtoppath = ui.expandpath(source)
4222 repo._subtoppath = ui.expandpath(source)
4236 try:
4223 try:
4237 return hg.incoming(ui, repo, source, opts)
4224 return hg.incoming(ui, repo, source, opts)
4238 finally:
4225 finally:
4239 del repo._subtoppath
4226 del repo._subtoppath
4240
4227
4241
4228
4242 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4229 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4243 norepo=True)
4230 norepo=True)
4244 def init(ui, dest=".", **opts):
4231 def init(ui, dest=".", **opts):
4245 """create a new repository in the given directory
4232 """create a new repository in the given directory
4246
4233
4247 Initialize a new repository in the given directory. If the given
4234 Initialize a new repository in the given directory. If the given
4248 directory does not exist, it will be created.
4235 directory does not exist, it will be created.
4249
4236
4250 If no directory is given, the current directory is used.
4237 If no directory is given, the current directory is used.
4251
4238
4252 It is possible to specify an ``ssh://`` URL as the destination.
4239 It is possible to specify an ``ssh://`` URL as the destination.
4253 See :hg:`help urls` for more information.
4240 See :hg:`help urls` for more information.
4254
4241
4255 Returns 0 on success.
4242 Returns 0 on success.
4256 """
4243 """
4257 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4244 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4258
4245
4259 @command('locate',
4246 @command('locate',
4260 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4247 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4261 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4248 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4262 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4249 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4263 ] + walkopts,
4250 ] + walkopts,
4264 _('[OPTION]... [PATTERN]...'))
4251 _('[OPTION]... [PATTERN]...'))
4265 def locate(ui, repo, *pats, **opts):
4252 def locate(ui, repo, *pats, **opts):
4266 """locate files matching specific patterns (DEPRECATED)
4253 """locate files matching specific patterns (DEPRECATED)
4267
4254
4268 Print files under Mercurial control in the working directory whose
4255 Print files under Mercurial control in the working directory whose
4269 names match the given patterns.
4256 names match the given patterns.
4270
4257
4271 By default, this command searches all directories in the working
4258 By default, this command searches all directories in the working
4272 directory. To search just the current directory and its
4259 directory. To search just the current directory and its
4273 subdirectories, use "--include .".
4260 subdirectories, use "--include .".
4274
4261
4275 If no patterns are given to match, this command prints the names
4262 If no patterns are given to match, this command prints the names
4276 of all files under Mercurial control in the working directory.
4263 of all files under Mercurial control in the working directory.
4277
4264
4278 If you want to feed the output of this command into the "xargs"
4265 If you want to feed the output of this command into the "xargs"
4279 command, use the -0 option to both this command and "xargs". This
4266 command, use the -0 option to both this command and "xargs". This
4280 will avoid the problem of "xargs" treating single filenames that
4267 will avoid the problem of "xargs" treating single filenames that
4281 contain whitespace as multiple filenames.
4268 contain whitespace as multiple filenames.
4282
4269
4283 See :hg:`help files` for a more versatile command.
4270 See :hg:`help files` for a more versatile command.
4284
4271
4285 Returns 0 if a match is found, 1 otherwise.
4272 Returns 0 if a match is found, 1 otherwise.
4286 """
4273 """
4287 if opts.get('print0'):
4274 if opts.get('print0'):
4288 end = '\0'
4275 end = '\0'
4289 else:
4276 else:
4290 end = '\n'
4277 end = '\n'
4291 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4278 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4292
4279
4293 ret = 1
4280 ret = 1
4294 ctx = repo[rev]
4281 ctx = repo[rev]
4295 m = scmutil.match(ctx, pats, opts, default='relglob',
4282 m = scmutil.match(ctx, pats, opts, default='relglob',
4296 badfn=lambda x, y: False)
4283 badfn=lambda x, y: False)
4297
4284
4298 for abs in ctx.matches(m):
4285 for abs in ctx.matches(m):
4299 if opts.get('fullpath'):
4286 if opts.get('fullpath'):
4300 ui.write(repo.wjoin(abs), end)
4287 ui.write(repo.wjoin(abs), end)
4301 else:
4288 else:
4302 ui.write(((pats and m.rel(abs)) or abs), end)
4289 ui.write(((pats and m.rel(abs)) or abs), end)
4303 ret = 0
4290 ret = 0
4304
4291
4305 return ret
4292 return ret
4306
4293
4307 @command('^log|history',
4294 @command('^log|history',
4308 [('f', 'follow', None,
4295 [('f', 'follow', None,
4309 _('follow changeset history, or file history across copies and renames')),
4296 _('follow changeset history, or file history across copies and renames')),
4310 ('', 'follow-first', None,
4297 ('', 'follow-first', None,
4311 _('only follow the first parent of merge changesets (DEPRECATED)')),
4298 _('only follow the first parent of merge changesets (DEPRECATED)')),
4312 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4299 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4313 ('C', 'copies', None, _('show copied files')),
4300 ('C', 'copies', None, _('show copied files')),
4314 ('k', 'keyword', [],
4301 ('k', 'keyword', [],
4315 _('do case-insensitive search for a given text'), _('TEXT')),
4302 _('do case-insensitive search for a given text'), _('TEXT')),
4316 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4303 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4317 ('', 'removed', None, _('include revisions where files were removed')),
4304 ('', 'removed', None, _('include revisions where files were removed')),
4318 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4305 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4319 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4306 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4320 ('', 'only-branch', [],
4307 ('', 'only-branch', [],
4321 _('show only changesets within the given named branch (DEPRECATED)'),
4308 _('show only changesets within the given named branch (DEPRECATED)'),
4322 _('BRANCH')),
4309 _('BRANCH')),
4323 ('b', 'branch', [],
4310 ('b', 'branch', [],
4324 _('show changesets within the given named branch'), _('BRANCH')),
4311 _('show changesets within the given named branch'), _('BRANCH')),
4325 ('P', 'prune', [],
4312 ('P', 'prune', [],
4326 _('do not display revision or any of its ancestors'), _('REV')),
4313 _('do not display revision or any of its ancestors'), _('REV')),
4327 ] + logopts + walkopts,
4314 ] + logopts + walkopts,
4328 _('[OPTION]... [FILE]'),
4315 _('[OPTION]... [FILE]'),
4329 inferrepo=True)
4316 inferrepo=True)
4330 def log(ui, repo, *pats, **opts):
4317 def log(ui, repo, *pats, **opts):
4331 """show revision history of entire repository or files
4318 """show revision history of entire repository or files
4332
4319
4333 Print the revision history of the specified files or the entire
4320 Print the revision history of the specified files or the entire
4334 project.
4321 project.
4335
4322
4336 If no revision range is specified, the default is ``tip:0`` unless
4323 If no revision range is specified, the default is ``tip:0`` unless
4337 --follow is set, in which case the working directory parent is
4324 --follow is set, in which case the working directory parent is
4338 used as the starting revision.
4325 used as the starting revision.
4339
4326
4340 File history is shown without following rename or copy history of
4327 File history is shown without following rename or copy history of
4341 files. Use -f/--follow with a filename to follow history across
4328 files. Use -f/--follow with a filename to follow history across
4342 renames and copies. --follow without a filename will only show
4329 renames and copies. --follow without a filename will only show
4343 ancestors or descendants of the starting revision.
4330 ancestors or descendants of the starting revision.
4344
4331
4345 By default this command prints revision number and changeset id,
4332 By default this command prints revision number and changeset id,
4346 tags, non-trivial parents, user, date and time, and a summary for
4333 tags, non-trivial parents, user, date and time, and a summary for
4347 each commit. When the -v/--verbose switch is used, the list of
4334 each commit. When the -v/--verbose switch is used, the list of
4348 changed files and full commit message are shown.
4335 changed files and full commit message are shown.
4349
4336
4350 With --graph the revisions are shown as an ASCII art DAG with the most
4337 With --graph the revisions are shown as an ASCII art DAG with the most
4351 recent changeset at the top.
4338 recent changeset at the top.
4352 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4339 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4353 and '+' represents a fork where the changeset from the lines below is a
4340 and '+' represents a fork where the changeset from the lines below is a
4354 parent of the 'o' merge on the same line.
4341 parent of the 'o' merge on the same line.
4355
4342
4356 .. note::
4343 .. note::
4357
4344
4358 :hg:`log --patch` may generate unexpected diff output for merge
4345 :hg:`log --patch` may generate unexpected diff output for merge
4359 changesets, as it will only compare the merge changeset against
4346 changesets, as it will only compare the merge changeset against
4360 its first parent. Also, only files different from BOTH parents
4347 its first parent. Also, only files different from BOTH parents
4361 will appear in files:.
4348 will appear in files:.
4362
4349
4363 .. note::
4350 .. note::
4364
4351
4365 For performance reasons, :hg:`log FILE` may omit duplicate changes
4352 For performance reasons, :hg:`log FILE` may omit duplicate changes
4366 made on branches and will not show removals or mode changes. To
4353 made on branches and will not show removals or mode changes. To
4367 see all such changes, use the --removed switch.
4354 see all such changes, use the --removed switch.
4368
4355
4369 .. container:: verbose
4356 .. container:: verbose
4370
4357
4371 Some examples:
4358 Some examples:
4372
4359
4373 - changesets with full descriptions and file lists::
4360 - changesets with full descriptions and file lists::
4374
4361
4375 hg log -v
4362 hg log -v
4376
4363
4377 - changesets ancestral to the working directory::
4364 - changesets ancestral to the working directory::
4378
4365
4379 hg log -f
4366 hg log -f
4380
4367
4381 - last 10 commits on the current branch::
4368 - last 10 commits on the current branch::
4382
4369
4383 hg log -l 10 -b .
4370 hg log -l 10 -b .
4384
4371
4385 - changesets showing all modifications of a file, including removals::
4372 - changesets showing all modifications of a file, including removals::
4386
4373
4387 hg log --removed file.c
4374 hg log --removed file.c
4388
4375
4389 - all changesets that touch a directory, with diffs, excluding merges::
4376 - all changesets that touch a directory, with diffs, excluding merges::
4390
4377
4391 hg log -Mp lib/
4378 hg log -Mp lib/
4392
4379
4393 - all revision numbers that match a keyword::
4380 - all revision numbers that match a keyword::
4394
4381
4395 hg log -k bug --template "{rev}\\n"
4382 hg log -k bug --template "{rev}\\n"
4396
4383
4397 - the full hash identifier of the working directory parent::
4384 - the full hash identifier of the working directory parent::
4398
4385
4399 hg log -r . --template "{node}\\n"
4386 hg log -r . --template "{node}\\n"
4400
4387
4401 - list available log templates::
4388 - list available log templates::
4402
4389
4403 hg log -T list
4390 hg log -T list
4404
4391
4405 - check if a given changeset is included in a tagged release::
4392 - check if a given changeset is included in a tagged release::
4406
4393
4407 hg log -r "a21ccf and ancestor(1.9)"
4394 hg log -r "a21ccf and ancestor(1.9)"
4408
4395
4409 - find all changesets by some user in a date range::
4396 - find all changesets by some user in a date range::
4410
4397
4411 hg log -k alice -d "may 2008 to jul 2008"
4398 hg log -k alice -d "may 2008 to jul 2008"
4412
4399
4413 - summary of all changesets after the last tag::
4400 - summary of all changesets after the last tag::
4414
4401
4415 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4402 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4416
4403
4417 See :hg:`help dates` for a list of formats valid for -d/--date.
4404 See :hg:`help dates` for a list of formats valid for -d/--date.
4418
4405
4419 See :hg:`help revisions` for more about specifying and ordering
4406 See :hg:`help revisions` for more about specifying and ordering
4420 revisions.
4407 revisions.
4421
4408
4422 See :hg:`help templates` for more about pre-packaged styles and
4409 See :hg:`help templates` for more about pre-packaged styles and
4423 specifying custom templates.
4410 specifying custom templates.
4424
4411
4425 Returns 0 on success.
4412 Returns 0 on success.
4426
4413
4427 """
4414 """
4428 if opts.get('follow') and opts.get('rev'):
4415 if opts.get('follow') and opts.get('rev'):
4429 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4416 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4430 del opts['follow']
4417 del opts['follow']
4431
4418
4432 if opts.get('graph'):
4419 if opts.get('graph'):
4433 return cmdutil.graphlog(ui, repo, *pats, **opts)
4420 return cmdutil.graphlog(ui, repo, *pats, **opts)
4434
4421
4435 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4422 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4436 limit = cmdutil.loglimit(opts)
4423 limit = cmdutil.loglimit(opts)
4437 count = 0
4424 count = 0
4438
4425
4439 getrenamed = None
4426 getrenamed = None
4440 if opts.get('copies'):
4427 if opts.get('copies'):
4441 endrev = None
4428 endrev = None
4442 if opts.get('rev'):
4429 if opts.get('rev'):
4443 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4430 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4444 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4431 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4445
4432
4446 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4433 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4447 for rev in revs:
4434 for rev in revs:
4448 if count == limit:
4435 if count == limit:
4449 break
4436 break
4450 ctx = repo[rev]
4437 ctx = repo[rev]
4451 copies = None
4438 copies = None
4452 if getrenamed is not None and rev:
4439 if getrenamed is not None and rev:
4453 copies = []
4440 copies = []
4454 for fn in ctx.files():
4441 for fn in ctx.files():
4455 rename = getrenamed(fn, rev)
4442 rename = getrenamed(fn, rev)
4456 if rename:
4443 if rename:
4457 copies.append((fn, rename[0]))
4444 copies.append((fn, rename[0]))
4458 if filematcher:
4445 if filematcher:
4459 revmatchfn = filematcher(ctx.rev())
4446 revmatchfn = filematcher(ctx.rev())
4460 else:
4447 else:
4461 revmatchfn = None
4448 revmatchfn = None
4462 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4449 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4463 if displayer.flush(ctx):
4450 if displayer.flush(ctx):
4464 count += 1
4451 count += 1
4465
4452
4466 displayer.close()
4453 displayer.close()
4467
4454
4468 @command('manifest',
4455 @command('manifest',
4469 [('r', 'rev', '', _('revision to display'), _('REV')),
4456 [('r', 'rev', '', _('revision to display'), _('REV')),
4470 ('', 'all', False, _("list files from all revisions"))]
4457 ('', 'all', False, _("list files from all revisions"))]
4471 + formatteropts,
4458 + formatteropts,
4472 _('[-r REV]'))
4459 _('[-r REV]'))
4473 def manifest(ui, repo, node=None, rev=None, **opts):
4460 def manifest(ui, repo, node=None, rev=None, **opts):
4474 """output the current or given revision of the project manifest
4461 """output the current or given revision of the project manifest
4475
4462
4476 Print a list of version controlled files for the given revision.
4463 Print a list of version controlled files for the given revision.
4477 If no revision is given, the first parent of the working directory
4464 If no revision is given, the first parent of the working directory
4478 is used, or the null revision if no revision is checked out.
4465 is used, or the null revision if no revision is checked out.
4479
4466
4480 With -v, print file permissions, symlink and executable bits.
4467 With -v, print file permissions, symlink and executable bits.
4481 With --debug, print file revision hashes.
4468 With --debug, print file revision hashes.
4482
4469
4483 If option --all is specified, the list of all files from all revisions
4470 If option --all is specified, the list of all files from all revisions
4484 is printed. This includes deleted and renamed files.
4471 is printed. This includes deleted and renamed files.
4485
4472
4486 Returns 0 on success.
4473 Returns 0 on success.
4487 """
4474 """
4488
4475
4489 fm = ui.formatter('manifest', opts)
4476 fm = ui.formatter('manifest', opts)
4490
4477
4491 if opts.get('all'):
4478 if opts.get('all'):
4492 if rev or node:
4479 if rev or node:
4493 raise error.Abort(_("can't specify a revision with --all"))
4480 raise error.Abort(_("can't specify a revision with --all"))
4494
4481
4495 res = []
4482 res = []
4496 prefix = "data/"
4483 prefix = "data/"
4497 suffix = ".i"
4484 suffix = ".i"
4498 plen = len(prefix)
4485 plen = len(prefix)
4499 slen = len(suffix)
4486 slen = len(suffix)
4500 with repo.lock():
4487 with repo.lock():
4501 for fn, b, size in repo.store.datafiles():
4488 for fn, b, size in repo.store.datafiles():
4502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4489 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4503 res.append(fn[plen:-slen])
4490 res.append(fn[plen:-slen])
4504 for f in res:
4491 for f in res:
4505 fm.startitem()
4492 fm.startitem()
4506 fm.write("path", '%s\n', f)
4493 fm.write("path", '%s\n', f)
4507 fm.end()
4494 fm.end()
4508 return
4495 return
4509
4496
4510 if rev and node:
4497 if rev and node:
4511 raise error.Abort(_("please specify just one revision"))
4498 raise error.Abort(_("please specify just one revision"))
4512
4499
4513 if not node:
4500 if not node:
4514 node = rev
4501 node = rev
4515
4502
4516 char = {'l': '@', 'x': '*', '': ''}
4503 char = {'l': '@', 'x': '*', '': ''}
4517 mode = {'l': '644', 'x': '755', '': '644'}
4504 mode = {'l': '644', 'x': '755', '': '644'}
4518 ctx = scmutil.revsingle(repo, node)
4505 ctx = scmutil.revsingle(repo, node)
4519 mf = ctx.manifest()
4506 mf = ctx.manifest()
4520 for f in ctx:
4507 for f in ctx:
4521 fm.startitem()
4508 fm.startitem()
4522 fl = ctx[f].flags()
4509 fl = ctx[f].flags()
4523 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4510 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4524 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4511 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4525 fm.write('path', '%s\n', f)
4512 fm.write('path', '%s\n', f)
4526 fm.end()
4513 fm.end()
4527
4514
4528 @command('^merge',
4515 @command('^merge',
4529 [('f', 'force', None,
4516 [('f', 'force', None,
4530 _('force a merge including outstanding changes (DEPRECATED)')),
4517 _('force a merge including outstanding changes (DEPRECATED)')),
4531 ('r', 'rev', '', _('revision to merge'), _('REV')),
4518 ('r', 'rev', '', _('revision to merge'), _('REV')),
4532 ('P', 'preview', None,
4519 ('P', 'preview', None,
4533 _('review revisions to merge (no merge is performed)'))
4520 _('review revisions to merge (no merge is performed)'))
4534 ] + mergetoolopts,
4521 ] + mergetoolopts,
4535 _('[-P] [[-r] REV]'))
4522 _('[-P] [[-r] REV]'))
4536 def merge(ui, repo, node=None, **opts):
4523 def merge(ui, repo, node=None, **opts):
4537 """merge another revision into working directory
4524 """merge another revision into working directory
4538
4525
4539 The current working directory is updated with all changes made in
4526 The current working directory is updated with all changes made in
4540 the requested revision since the last common predecessor revision.
4527 the requested revision since the last common predecessor revision.
4541
4528
4542 Files that changed between either parent are marked as changed for
4529 Files that changed between either parent are marked as changed for
4543 the next commit and a commit must be performed before any further
4530 the next commit and a commit must be performed before any further
4544 updates to the repository are allowed. The next commit will have
4531 updates to the repository are allowed. The next commit will have
4545 two parents.
4532 two parents.
4546
4533
4547 ``--tool`` can be used to specify the merge tool used for file
4534 ``--tool`` can be used to specify the merge tool used for file
4548 merges. It overrides the HGMERGE environment variable and your
4535 merges. It overrides the HGMERGE environment variable and your
4549 configuration files. See :hg:`help merge-tools` for options.
4536 configuration files. See :hg:`help merge-tools` for options.
4550
4537
4551 If no revision is specified, the working directory's parent is a
4538 If no revision is specified, the working directory's parent is a
4552 head revision, and the current branch contains exactly one other
4539 head revision, and the current branch contains exactly one other
4553 head, the other head is merged with by default. Otherwise, an
4540 head, the other head is merged with by default. Otherwise, an
4554 explicit revision with which to merge with must be provided.
4541 explicit revision with which to merge with must be provided.
4555
4542
4556 See :hg:`help resolve` for information on handling file conflicts.
4543 See :hg:`help resolve` for information on handling file conflicts.
4557
4544
4558 To undo an uncommitted merge, use :hg:`update --clean .` which
4545 To undo an uncommitted merge, use :hg:`update --clean .` which
4559 will check out a clean copy of the original merge parent, losing
4546 will check out a clean copy of the original merge parent, losing
4560 all changes.
4547 all changes.
4561
4548
4562 Returns 0 on success, 1 if there are unresolved files.
4549 Returns 0 on success, 1 if there are unresolved files.
4563 """
4550 """
4564
4551
4565 if opts.get('rev') and node:
4552 if opts.get('rev') and node:
4566 raise error.Abort(_("please specify just one revision"))
4553 raise error.Abort(_("please specify just one revision"))
4567 if not node:
4554 if not node:
4568 node = opts.get('rev')
4555 node = opts.get('rev')
4569
4556
4570 if node:
4557 if node:
4571 node = scmutil.revsingle(repo, node).node()
4558 node = scmutil.revsingle(repo, node).node()
4572
4559
4573 if not node:
4560 if not node:
4574 node = repo[destutil.destmerge(repo)].node()
4561 node = repo[destutil.destmerge(repo)].node()
4575
4562
4576 if opts.get('preview'):
4563 if opts.get('preview'):
4577 # find nodes that are ancestors of p2 but not of p1
4564 # find nodes that are ancestors of p2 but not of p1
4578 p1 = repo.lookup('.')
4565 p1 = repo.lookup('.')
4579 p2 = repo.lookup(node)
4566 p2 = repo.lookup(node)
4580 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4567 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4581
4568
4582 displayer = cmdutil.show_changeset(ui, repo, opts)
4569 displayer = cmdutil.show_changeset(ui, repo, opts)
4583 for node in nodes:
4570 for node in nodes:
4584 displayer.show(repo[node])
4571 displayer.show(repo[node])
4585 displayer.close()
4572 displayer.close()
4586 return 0
4573 return 0
4587
4574
4588 try:
4575 try:
4589 # ui.forcemerge is an internal variable, do not document
4576 # ui.forcemerge is an internal variable, do not document
4590 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4577 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4591 force = opts.get('force')
4578 force = opts.get('force')
4592 labels = ['working copy', 'merge rev']
4579 labels = ['working copy', 'merge rev']
4593 return hg.merge(repo, node, force=force, mergeforce=force,
4580 return hg.merge(repo, node, force=force, mergeforce=force,
4594 labels=labels)
4581 labels=labels)
4595 finally:
4582 finally:
4596 ui.setconfig('ui', 'forcemerge', '', 'merge')
4583 ui.setconfig('ui', 'forcemerge', '', 'merge')
4597
4584
4598 @command('outgoing|out',
4585 @command('outgoing|out',
4599 [('f', 'force', None, _('run even when the destination is unrelated')),
4586 [('f', 'force', None, _('run even when the destination is unrelated')),
4600 ('r', 'rev', [],
4587 ('r', 'rev', [],
4601 _('a changeset intended to be included in the destination'), _('REV')),
4588 _('a changeset intended to be included in the destination'), _('REV')),
4602 ('n', 'newest-first', None, _('show newest record first')),
4589 ('n', 'newest-first', None, _('show newest record first')),
4603 ('B', 'bookmarks', False, _('compare bookmarks')),
4590 ('B', 'bookmarks', False, _('compare bookmarks')),
4604 ('b', 'branch', [], _('a specific branch you would like to push'),
4591 ('b', 'branch', [], _('a specific branch you would like to push'),
4605 _('BRANCH')),
4592 _('BRANCH')),
4606 ] + logopts + remoteopts + subrepoopts,
4593 ] + logopts + remoteopts + subrepoopts,
4607 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4594 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4608 def outgoing(ui, repo, dest=None, **opts):
4595 def outgoing(ui, repo, dest=None, **opts):
4609 """show changesets not found in the destination
4596 """show changesets not found in the destination
4610
4597
4611 Show changesets not found in the specified destination repository
4598 Show changesets not found in the specified destination repository
4612 or the default push location. These are the changesets that would
4599 or the default push location. These are the changesets that would
4613 be pushed if a push was requested.
4600 be pushed if a push was requested.
4614
4601
4615 See pull for details of valid destination formats.
4602 See pull for details of valid destination formats.
4616
4603
4617 .. container:: verbose
4604 .. container:: verbose
4618
4605
4619 With -B/--bookmarks, the result of bookmark comparison between
4606 With -B/--bookmarks, the result of bookmark comparison between
4620 local and remote repositories is displayed. With -v/--verbose,
4607 local and remote repositories is displayed. With -v/--verbose,
4621 status is also displayed for each bookmark like below::
4608 status is also displayed for each bookmark like below::
4622
4609
4623 BM1 01234567890a added
4610 BM1 01234567890a added
4624 BM2 deleted
4611 BM2 deleted
4625 BM3 234567890abc advanced
4612 BM3 234567890abc advanced
4626 BM4 34567890abcd diverged
4613 BM4 34567890abcd diverged
4627 BM5 4567890abcde changed
4614 BM5 4567890abcde changed
4628
4615
4629 The action taken when pushing depends on the
4616 The action taken when pushing depends on the
4630 status of each bookmark:
4617 status of each bookmark:
4631
4618
4632 :``added``: push with ``-B`` will create it
4619 :``added``: push with ``-B`` will create it
4633 :``deleted``: push with ``-B`` will delete it
4620 :``deleted``: push with ``-B`` will delete it
4634 :``advanced``: push will update it
4621 :``advanced``: push will update it
4635 :``diverged``: push with ``-B`` will update it
4622 :``diverged``: push with ``-B`` will update it
4636 :``changed``: push with ``-B`` will update it
4623 :``changed``: push with ``-B`` will update it
4637
4624
4638 From the point of view of pushing behavior, bookmarks
4625 From the point of view of pushing behavior, bookmarks
4639 existing only in the remote repository are treated as
4626 existing only in the remote repository are treated as
4640 ``deleted``, even if it is in fact added remotely.
4627 ``deleted``, even if it is in fact added remotely.
4641
4628
4642 Returns 0 if there are outgoing changes, 1 otherwise.
4629 Returns 0 if there are outgoing changes, 1 otherwise.
4643 """
4630 """
4644 if opts.get('graph'):
4631 if opts.get('graph'):
4645 cmdutil.checkunsupportedgraphflags([], opts)
4632 cmdutil.checkunsupportedgraphflags([], opts)
4646 o, other = hg._outgoing(ui, repo, dest, opts)
4633 o, other = hg._outgoing(ui, repo, dest, opts)
4647 if not o:
4634 if not o:
4648 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4635 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4649 return
4636 return
4650
4637
4651 revdag = cmdutil.graphrevs(repo, o, opts)
4638 revdag = cmdutil.graphrevs(repo, o, opts)
4652 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4639 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4653 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4640 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4641 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4655 return 0
4642 return 0
4656
4643
4657 if opts.get('bookmarks'):
4644 if opts.get('bookmarks'):
4658 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4645 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4659 dest, branches = hg.parseurl(dest, opts.get('branch'))
4646 dest, branches = hg.parseurl(dest, opts.get('branch'))
4660 other = hg.peer(repo, opts, dest)
4647 other = hg.peer(repo, opts, dest)
4661 if 'bookmarks' not in other.listkeys('namespaces'):
4648 if 'bookmarks' not in other.listkeys('namespaces'):
4662 ui.warn(_("remote doesn't support bookmarks\n"))
4649 ui.warn(_("remote doesn't support bookmarks\n"))
4663 return 0
4650 return 0
4664 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4651 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4665 return bookmarks.outgoing(ui, repo, other)
4652 return bookmarks.outgoing(ui, repo, other)
4666
4653
4667 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4654 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4668 try:
4655 try:
4669 return hg.outgoing(ui, repo, dest, opts)
4656 return hg.outgoing(ui, repo, dest, opts)
4670 finally:
4657 finally:
4671 del repo._subtoppath
4658 del repo._subtoppath
4672
4659
4673 @command('parents',
4660 @command('parents',
4674 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4661 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4675 ] + templateopts,
4662 ] + templateopts,
4676 _('[-r REV] [FILE]'),
4663 _('[-r REV] [FILE]'),
4677 inferrepo=True)
4664 inferrepo=True)
4678 def parents(ui, repo, file_=None, **opts):
4665 def parents(ui, repo, file_=None, **opts):
4679 """show the parents of the working directory or revision (DEPRECATED)
4666 """show the parents of the working directory or revision (DEPRECATED)
4680
4667
4681 Print the working directory's parent revisions. If a revision is
4668 Print the working directory's parent revisions. If a revision is
4682 given via -r/--rev, the parent of that revision will be printed.
4669 given via -r/--rev, the parent of that revision will be printed.
4683 If a file argument is given, the revision in which the file was
4670 If a file argument is given, the revision in which the file was
4684 last changed (before the working directory revision or the
4671 last changed (before the working directory revision or the
4685 argument to --rev if given) is printed.
4672 argument to --rev if given) is printed.
4686
4673
4687 This command is equivalent to::
4674 This command is equivalent to::
4688
4675
4689 hg log -r "p1()+p2()" or
4676 hg log -r "p1()+p2()" or
4690 hg log -r "p1(REV)+p2(REV)" or
4677 hg log -r "p1(REV)+p2(REV)" or
4691 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4678 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4692 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4679 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4693
4680
4694 See :hg:`summary` and :hg:`help revsets` for related information.
4681 See :hg:`summary` and :hg:`help revsets` for related information.
4695
4682
4696 Returns 0 on success.
4683 Returns 0 on success.
4697 """
4684 """
4698
4685
4699 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4686 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4700
4687
4701 if file_:
4688 if file_:
4702 m = scmutil.match(ctx, (file_,), opts)
4689 m = scmutil.match(ctx, (file_,), opts)
4703 if m.anypats() or len(m.files()) != 1:
4690 if m.anypats() or len(m.files()) != 1:
4704 raise error.Abort(_('can only specify an explicit filename'))
4691 raise error.Abort(_('can only specify an explicit filename'))
4705 file_ = m.files()[0]
4692 file_ = m.files()[0]
4706 filenodes = []
4693 filenodes = []
4707 for cp in ctx.parents():
4694 for cp in ctx.parents():
4708 if not cp:
4695 if not cp:
4709 continue
4696 continue
4710 try:
4697 try:
4711 filenodes.append(cp.filenode(file_))
4698 filenodes.append(cp.filenode(file_))
4712 except error.LookupError:
4699 except error.LookupError:
4713 pass
4700 pass
4714 if not filenodes:
4701 if not filenodes:
4715 raise error.Abort(_("'%s' not found in manifest!") % file_)
4702 raise error.Abort(_("'%s' not found in manifest!") % file_)
4716 p = []
4703 p = []
4717 for fn in filenodes:
4704 for fn in filenodes:
4718 fctx = repo.filectx(file_, fileid=fn)
4705 fctx = repo.filectx(file_, fileid=fn)
4719 p.append(fctx.node())
4706 p.append(fctx.node())
4720 else:
4707 else:
4721 p = [cp.node() for cp in ctx.parents()]
4708 p = [cp.node() for cp in ctx.parents()]
4722
4709
4723 displayer = cmdutil.show_changeset(ui, repo, opts)
4710 displayer = cmdutil.show_changeset(ui, repo, opts)
4724 for n in p:
4711 for n in p:
4725 if n != nullid:
4712 if n != nullid:
4726 displayer.show(repo[n])
4713 displayer.show(repo[n])
4727 displayer.close()
4714 displayer.close()
4728
4715
4729 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4716 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4730 def paths(ui, repo, search=None, **opts):
4717 def paths(ui, repo, search=None, **opts):
4731 """show aliases for remote repositories
4718 """show aliases for remote repositories
4732
4719
4733 Show definition of symbolic path name NAME. If no name is given,
4720 Show definition of symbolic path name NAME. If no name is given,
4734 show definition of all available names.
4721 show definition of all available names.
4735
4722
4736 Option -q/--quiet suppresses all output when searching for NAME
4723 Option -q/--quiet suppresses all output when searching for NAME
4737 and shows only the path names when listing all definitions.
4724 and shows only the path names when listing all definitions.
4738
4725
4739 Path names are defined in the [paths] section of your
4726 Path names are defined in the [paths] section of your
4740 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4727 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4741 repository, ``.hg/hgrc`` is used, too.
4728 repository, ``.hg/hgrc`` is used, too.
4742
4729
4743 The path names ``default`` and ``default-push`` have a special
4730 The path names ``default`` and ``default-push`` have a special
4744 meaning. When performing a push or pull operation, they are used
4731 meaning. When performing a push or pull operation, they are used
4745 as fallbacks if no location is specified on the command-line.
4732 as fallbacks if no location is specified on the command-line.
4746 When ``default-push`` is set, it will be used for push and
4733 When ``default-push`` is set, it will be used for push and
4747 ``default`` will be used for pull; otherwise ``default`` is used
4734 ``default`` will be used for pull; otherwise ``default`` is used
4748 as the fallback for both. When cloning a repository, the clone
4735 as the fallback for both. When cloning a repository, the clone
4749 source is written as ``default`` in ``.hg/hgrc``.
4736 source is written as ``default`` in ``.hg/hgrc``.
4750
4737
4751 .. note::
4738 .. note::
4752
4739
4753 ``default`` and ``default-push`` apply to all inbound (e.g.
4740 ``default`` and ``default-push`` apply to all inbound (e.g.
4754 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4741 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4755 and :hg:`bundle`) operations.
4742 and :hg:`bundle`) operations.
4756
4743
4757 See :hg:`help urls` for more information.
4744 See :hg:`help urls` for more information.
4758
4745
4759 Returns 0 on success.
4746 Returns 0 on success.
4760 """
4747 """
4761 if search:
4748 if search:
4762 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4749 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4763 if name == search]
4750 if name == search]
4764 else:
4751 else:
4765 pathitems = sorted(ui.paths.iteritems())
4752 pathitems = sorted(ui.paths.iteritems())
4766
4753
4767 fm = ui.formatter('paths', opts)
4754 fm = ui.formatter('paths', opts)
4768 if fm.isplain():
4755 if fm.isplain():
4769 hidepassword = util.hidepassword
4756 hidepassword = util.hidepassword
4770 else:
4757 else:
4771 hidepassword = str
4758 hidepassword = str
4772 if ui.quiet:
4759 if ui.quiet:
4773 namefmt = '%s\n'
4760 namefmt = '%s\n'
4774 else:
4761 else:
4775 namefmt = '%s = '
4762 namefmt = '%s = '
4776 showsubopts = not search and not ui.quiet
4763 showsubopts = not search and not ui.quiet
4777
4764
4778 for name, path in pathitems:
4765 for name, path in pathitems:
4779 fm.startitem()
4766 fm.startitem()
4780 fm.condwrite(not search, 'name', namefmt, name)
4767 fm.condwrite(not search, 'name', namefmt, name)
4781 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4768 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4782 for subopt, value in sorted(path.suboptions.items()):
4769 for subopt, value in sorted(path.suboptions.items()):
4783 assert subopt not in ('name', 'url')
4770 assert subopt not in ('name', 'url')
4784 if showsubopts:
4771 if showsubopts:
4785 fm.plain('%s:%s = ' % (name, subopt))
4772 fm.plain('%s:%s = ' % (name, subopt))
4786 fm.condwrite(showsubopts, subopt, '%s\n', value)
4773 fm.condwrite(showsubopts, subopt, '%s\n', value)
4787
4774
4788 fm.end()
4775 fm.end()
4789
4776
4790 if search and not pathitems:
4777 if search and not pathitems:
4791 if not ui.quiet:
4778 if not ui.quiet:
4792 ui.warn(_("not found!\n"))
4779 ui.warn(_("not found!\n"))
4793 return 1
4780 return 1
4794 else:
4781 else:
4795 return 0
4782 return 0
4796
4783
4797 @command('phase',
4784 @command('phase',
4798 [('p', 'public', False, _('set changeset phase to public')),
4785 [('p', 'public', False, _('set changeset phase to public')),
4799 ('d', 'draft', False, _('set changeset phase to draft')),
4786 ('d', 'draft', False, _('set changeset phase to draft')),
4800 ('s', 'secret', False, _('set changeset phase to secret')),
4787 ('s', 'secret', False, _('set changeset phase to secret')),
4801 ('f', 'force', False, _('allow to move boundary backward')),
4788 ('f', 'force', False, _('allow to move boundary backward')),
4802 ('r', 'rev', [], _('target revision'), _('REV')),
4789 ('r', 'rev', [], _('target revision'), _('REV')),
4803 ],
4790 ],
4804 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4791 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4805 def phase(ui, repo, *revs, **opts):
4792 def phase(ui, repo, *revs, **opts):
4806 """set or show the current phase name
4793 """set or show the current phase name
4807
4794
4808 With no argument, show the phase name of the current revision(s).
4795 With no argument, show the phase name of the current revision(s).
4809
4796
4810 With one of -p/--public, -d/--draft or -s/--secret, change the
4797 With one of -p/--public, -d/--draft or -s/--secret, change the
4811 phase value of the specified revisions.
4798 phase value of the specified revisions.
4812
4799
4813 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4800 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4814 lower phase to an higher phase. Phases are ordered as follows::
4801 lower phase to an higher phase. Phases are ordered as follows::
4815
4802
4816 public < draft < secret
4803 public < draft < secret
4817
4804
4818 Returns 0 on success, 1 if some phases could not be changed.
4805 Returns 0 on success, 1 if some phases could not be changed.
4819
4806
4820 (For more information about the phases concept, see :hg:`help phases`.)
4807 (For more information about the phases concept, see :hg:`help phases`.)
4821 """
4808 """
4822 # search for a unique phase argument
4809 # search for a unique phase argument
4823 targetphase = None
4810 targetphase = None
4824 for idx, name in enumerate(phases.phasenames):
4811 for idx, name in enumerate(phases.phasenames):
4825 if opts[name]:
4812 if opts[name]:
4826 if targetphase is not None:
4813 if targetphase is not None:
4827 raise error.Abort(_('only one phase can be specified'))
4814 raise error.Abort(_('only one phase can be specified'))
4828 targetphase = idx
4815 targetphase = idx
4829
4816
4830 # look for specified revision
4817 # look for specified revision
4831 revs = list(revs)
4818 revs = list(revs)
4832 revs.extend(opts['rev'])
4819 revs.extend(opts['rev'])
4833 if not revs:
4820 if not revs:
4834 # display both parents as the second parent phase can influence
4821 # display both parents as the second parent phase can influence
4835 # the phase of a merge commit
4822 # the phase of a merge commit
4836 revs = [c.rev() for c in repo[None].parents()]
4823 revs = [c.rev() for c in repo[None].parents()]
4837
4824
4838 revs = scmutil.revrange(repo, revs)
4825 revs = scmutil.revrange(repo, revs)
4839
4826
4840 lock = None
4827 lock = None
4841 ret = 0
4828 ret = 0
4842 if targetphase is None:
4829 if targetphase is None:
4843 # display
4830 # display
4844 for r in revs:
4831 for r in revs:
4845 ctx = repo[r]
4832 ctx = repo[r]
4846 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4833 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4847 else:
4834 else:
4848 tr = None
4835 tr = None
4849 lock = repo.lock()
4836 lock = repo.lock()
4850 try:
4837 try:
4851 tr = repo.transaction("phase")
4838 tr = repo.transaction("phase")
4852 # set phase
4839 # set phase
4853 if not revs:
4840 if not revs:
4854 raise error.Abort(_('empty revision set'))
4841 raise error.Abort(_('empty revision set'))
4855 nodes = [repo[r].node() for r in revs]
4842 nodes = [repo[r].node() for r in revs]
4856 # moving revision from public to draft may hide them
4843 # moving revision from public to draft may hide them
4857 # We have to check result on an unfiltered repository
4844 # We have to check result on an unfiltered repository
4858 unfi = repo.unfiltered()
4845 unfi = repo.unfiltered()
4859 getphase = unfi._phasecache.phase
4846 getphase = unfi._phasecache.phase
4860 olddata = [getphase(unfi, r) for r in unfi]
4847 olddata = [getphase(unfi, r) for r in unfi]
4861 phases.advanceboundary(repo, tr, targetphase, nodes)
4848 phases.advanceboundary(repo, tr, targetphase, nodes)
4862 if opts['force']:
4849 if opts['force']:
4863 phases.retractboundary(repo, tr, targetphase, nodes)
4850 phases.retractboundary(repo, tr, targetphase, nodes)
4864 tr.close()
4851 tr.close()
4865 finally:
4852 finally:
4866 if tr is not None:
4853 if tr is not None:
4867 tr.release()
4854 tr.release()
4868 lock.release()
4855 lock.release()
4869 getphase = unfi._phasecache.phase
4856 getphase = unfi._phasecache.phase
4870 newdata = [getphase(unfi, r) for r in unfi]
4857 newdata = [getphase(unfi, r) for r in unfi]
4871 changes = sum(newdata[r] != olddata[r] for r in unfi)
4858 changes = sum(newdata[r] != olddata[r] for r in unfi)
4872 cl = unfi.changelog
4859 cl = unfi.changelog
4873 rejected = [n for n in nodes
4860 rejected = [n for n in nodes
4874 if newdata[cl.rev(n)] < targetphase]
4861 if newdata[cl.rev(n)] < targetphase]
4875 if rejected:
4862 if rejected:
4876 ui.warn(_('cannot move %i changesets to a higher '
4863 ui.warn(_('cannot move %i changesets to a higher '
4877 'phase, use --force\n') % len(rejected))
4864 'phase, use --force\n') % len(rejected))
4878 ret = 1
4865 ret = 1
4879 if changes:
4866 if changes:
4880 msg = _('phase changed for %i changesets\n') % changes
4867 msg = _('phase changed for %i changesets\n') % changes
4881 if ret:
4868 if ret:
4882 ui.status(msg)
4869 ui.status(msg)
4883 else:
4870 else:
4884 ui.note(msg)
4871 ui.note(msg)
4885 else:
4872 else:
4886 ui.warn(_('no phases changed\n'))
4873 ui.warn(_('no phases changed\n'))
4887 return ret
4874 return ret
4888
4875
4889 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4876 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4890 """Run after a changegroup has been added via pull/unbundle
4877 """Run after a changegroup has been added via pull/unbundle
4891
4878
4892 This takes arguments below:
4879 This takes arguments below:
4893
4880
4894 :modheads: change of heads by pull/unbundle
4881 :modheads: change of heads by pull/unbundle
4895 :optupdate: updating working directory is needed or not
4882 :optupdate: updating working directory is needed or not
4896 :checkout: update destination revision (or None to default destination)
4883 :checkout: update destination revision (or None to default destination)
4897 :brev: a name, which might be a bookmark to be activated after updating
4884 :brev: a name, which might be a bookmark to be activated after updating
4898 """
4885 """
4899 if modheads == 0:
4886 if modheads == 0:
4900 return
4887 return
4901 if optupdate:
4888 if optupdate:
4902 try:
4889 try:
4903 return hg.updatetotally(ui, repo, checkout, brev)
4890 return hg.updatetotally(ui, repo, checkout, brev)
4904 except error.UpdateAbort as inst:
4891 except error.UpdateAbort as inst:
4905 msg = _("not updating: %s") % str(inst)
4892 msg = _("not updating: %s") % str(inst)
4906 hint = inst.hint
4893 hint = inst.hint
4907 raise error.UpdateAbort(msg, hint=hint)
4894 raise error.UpdateAbort(msg, hint=hint)
4908 if modheads > 1:
4895 if modheads > 1:
4909 currentbranchheads = len(repo.branchheads())
4896 currentbranchheads = len(repo.branchheads())
4910 if currentbranchheads == modheads:
4897 if currentbranchheads == modheads:
4911 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4898 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4912 elif currentbranchheads > 1:
4899 elif currentbranchheads > 1:
4913 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4900 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4914 "merge)\n"))
4901 "merge)\n"))
4915 else:
4902 else:
4916 ui.status(_("(run 'hg heads' to see heads)\n"))
4903 ui.status(_("(run 'hg heads' to see heads)\n"))
4917 else:
4904 else:
4918 ui.status(_("(run 'hg update' to get a working copy)\n"))
4905 ui.status(_("(run 'hg update' to get a working copy)\n"))
4919
4906
4920 @command('^pull',
4907 @command('^pull',
4921 [('u', 'update', None,
4908 [('u', 'update', None,
4922 _('update to new branch head if changesets were pulled')),
4909 _('update to new branch head if changesets were pulled')),
4923 ('f', 'force', None, _('run even when remote repository is unrelated')),
4910 ('f', 'force', None, _('run even when remote repository is unrelated')),
4924 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4911 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4925 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4912 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4926 ('b', 'branch', [], _('a specific branch you would like to pull'),
4913 ('b', 'branch', [], _('a specific branch you would like to pull'),
4927 _('BRANCH')),
4914 _('BRANCH')),
4928 ] + remoteopts,
4915 ] + remoteopts,
4929 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4916 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4930 def pull(ui, repo, source="default", **opts):
4917 def pull(ui, repo, source="default", **opts):
4931 """pull changes from the specified source
4918 """pull changes from the specified source
4932
4919
4933 Pull changes from a remote repository to a local one.
4920 Pull changes from a remote repository to a local one.
4934
4921
4935 This finds all changes from the repository at the specified path
4922 This finds all changes from the repository at the specified path
4936 or URL and adds them to a local repository (the current one unless
4923 or URL and adds them to a local repository (the current one unless
4937 -R is specified). By default, this does not update the copy of the
4924 -R is specified). By default, this does not update the copy of the
4938 project in the working directory.
4925 project in the working directory.
4939
4926
4940 Use :hg:`incoming` if you want to see what would have been added
4927 Use :hg:`incoming` if you want to see what would have been added
4941 by a pull at the time you issued this command. If you then decide
4928 by a pull at the time you issued this command. If you then decide
4942 to add those changes to the repository, you should use :hg:`pull
4929 to add those changes to the repository, you should use :hg:`pull
4943 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4930 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4944
4931
4945 If SOURCE is omitted, the 'default' path will be used.
4932 If SOURCE is omitted, the 'default' path will be used.
4946 See :hg:`help urls` for more information.
4933 See :hg:`help urls` for more information.
4947
4934
4948 Specifying bookmark as ``.`` is equivalent to specifying the active
4935 Specifying bookmark as ``.`` is equivalent to specifying the active
4949 bookmark's name.
4936 bookmark's name.
4950
4937
4951 Returns 0 on success, 1 if an update had unresolved files.
4938 Returns 0 on success, 1 if an update had unresolved files.
4952 """
4939 """
4953 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4940 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4954 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4941 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4955 other = hg.peer(repo, opts, source)
4942 other = hg.peer(repo, opts, source)
4956 try:
4943 try:
4957 revs, checkout = hg.addbranchrevs(repo, other, branches,
4944 revs, checkout = hg.addbranchrevs(repo, other, branches,
4958 opts.get('rev'))
4945 opts.get('rev'))
4959
4946
4960
4947
4961 pullopargs = {}
4948 pullopargs = {}
4962 if opts.get('bookmark'):
4949 if opts.get('bookmark'):
4963 if not revs:
4950 if not revs:
4964 revs = []
4951 revs = []
4965 # The list of bookmark used here is not the one used to actually
4952 # The list of bookmark used here is not the one used to actually
4966 # update the bookmark name. This can result in the revision pulled
4953 # update the bookmark name. This can result in the revision pulled
4967 # not ending up with the name of the bookmark because of a race
4954 # not ending up with the name of the bookmark because of a race
4968 # condition on the server. (See issue 4689 for details)
4955 # condition on the server. (See issue 4689 for details)
4969 remotebookmarks = other.listkeys('bookmarks')
4956 remotebookmarks = other.listkeys('bookmarks')
4970 pullopargs['remotebookmarks'] = remotebookmarks
4957 pullopargs['remotebookmarks'] = remotebookmarks
4971 for b in opts['bookmark']:
4958 for b in opts['bookmark']:
4972 b = repo._bookmarks.expandname(b)
4959 b = repo._bookmarks.expandname(b)
4973 if b not in remotebookmarks:
4960 if b not in remotebookmarks:
4974 raise error.Abort(_('remote bookmark %s not found!') % b)
4961 raise error.Abort(_('remote bookmark %s not found!') % b)
4975 revs.append(remotebookmarks[b])
4962 revs.append(remotebookmarks[b])
4976
4963
4977 if revs:
4964 if revs:
4978 try:
4965 try:
4979 # When 'rev' is a bookmark name, we cannot guarantee that it
4966 # When 'rev' is a bookmark name, we cannot guarantee that it
4980 # will be updated with that name because of a race condition
4967 # will be updated with that name because of a race condition
4981 # server side. (See issue 4689 for details)
4968 # server side. (See issue 4689 for details)
4982 oldrevs = revs
4969 oldrevs = revs
4983 revs = [] # actually, nodes
4970 revs = [] # actually, nodes
4984 for r in oldrevs:
4971 for r in oldrevs:
4985 node = other.lookup(r)
4972 node = other.lookup(r)
4986 revs.append(node)
4973 revs.append(node)
4987 if r == checkout:
4974 if r == checkout:
4988 checkout = node
4975 checkout = node
4989 except error.CapabilityError:
4976 except error.CapabilityError:
4990 err = _("other repository doesn't support revision lookup, "
4977 err = _("other repository doesn't support revision lookup, "
4991 "so a rev cannot be specified.")
4978 "so a rev cannot be specified.")
4992 raise error.Abort(err)
4979 raise error.Abort(err)
4993
4980
4994 pullopargs.update(opts.get('opargs', {}))
4981 pullopargs.update(opts.get('opargs', {}))
4995 modheads = exchange.pull(repo, other, heads=revs,
4982 modheads = exchange.pull(repo, other, heads=revs,
4996 force=opts.get('force'),
4983 force=opts.get('force'),
4997 bookmarks=opts.get('bookmark', ()),
4984 bookmarks=opts.get('bookmark', ()),
4998 opargs=pullopargs).cgresult
4985 opargs=pullopargs).cgresult
4999
4986
5000 # brev is a name, which might be a bookmark to be activated at
4987 # brev is a name, which might be a bookmark to be activated at
5001 # the end of the update. In other words, it is an explicit
4988 # the end of the update. In other words, it is an explicit
5002 # destination of the update
4989 # destination of the update
5003 brev = None
4990 brev = None
5004
4991
5005 if checkout:
4992 if checkout:
5006 checkout = str(repo.changelog.rev(checkout))
4993 checkout = str(repo.changelog.rev(checkout))
5007
4994
5008 # order below depends on implementation of
4995 # order below depends on implementation of
5009 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4996 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5010 # because 'checkout' is determined without it.
4997 # because 'checkout' is determined without it.
5011 if opts.get('rev'):
4998 if opts.get('rev'):
5012 brev = opts['rev'][0]
4999 brev = opts['rev'][0]
5013 elif opts.get('branch'):
5000 elif opts.get('branch'):
5014 brev = opts['branch'][0]
5001 brev = opts['branch'][0]
5015 else:
5002 else:
5016 brev = branches[0]
5003 brev = branches[0]
5017 repo._subtoppath = source
5004 repo._subtoppath = source
5018 try:
5005 try:
5019 ret = postincoming(ui, repo, modheads, opts.get('update'),
5006 ret = postincoming(ui, repo, modheads, opts.get('update'),
5020 checkout, brev)
5007 checkout, brev)
5021
5008
5022 finally:
5009 finally:
5023 del repo._subtoppath
5010 del repo._subtoppath
5024
5011
5025 finally:
5012 finally:
5026 other.close()
5013 other.close()
5027 return ret
5014 return ret
5028
5015
5029 @command('^push',
5016 @command('^push',
5030 [('f', 'force', None, _('force push')),
5017 [('f', 'force', None, _('force push')),
5031 ('r', 'rev', [],
5018 ('r', 'rev', [],
5032 _('a changeset intended to be included in the destination'),
5019 _('a changeset intended to be included in the destination'),
5033 _('REV')),
5020 _('REV')),
5034 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5021 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5035 ('b', 'branch', [],
5022 ('b', 'branch', [],
5036 _('a specific branch you would like to push'), _('BRANCH')),
5023 _('a specific branch you would like to push'), _('BRANCH')),
5037 ('', 'new-branch', False, _('allow pushing a new branch')),
5024 ('', 'new-branch', False, _('allow pushing a new branch')),
5038 ] + remoteopts,
5025 ] + remoteopts,
5039 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5026 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5040 def push(ui, repo, dest=None, **opts):
5027 def push(ui, repo, dest=None, **opts):
5041 """push changes to the specified destination
5028 """push changes to the specified destination
5042
5029
5043 Push changesets from the local repository to the specified
5030 Push changesets from the local repository to the specified
5044 destination.
5031 destination.
5045
5032
5046 This operation is symmetrical to pull: it is identical to a pull
5033 This operation is symmetrical to pull: it is identical to a pull
5047 in the destination repository from the current one.
5034 in the destination repository from the current one.
5048
5035
5049 By default, push will not allow creation of new heads at the
5036 By default, push will not allow creation of new heads at the
5050 destination, since multiple heads would make it unclear which head
5037 destination, since multiple heads would make it unclear which head
5051 to use. In this situation, it is recommended to pull and merge
5038 to use. In this situation, it is recommended to pull and merge
5052 before pushing.
5039 before pushing.
5053
5040
5054 Use --new-branch if you want to allow push to create a new named
5041 Use --new-branch if you want to allow push to create a new named
5055 branch that is not present at the destination. This allows you to
5042 branch that is not present at the destination. This allows you to
5056 only create a new branch without forcing other changes.
5043 only create a new branch without forcing other changes.
5057
5044
5058 .. note::
5045 .. note::
5059
5046
5060 Extra care should be taken with the -f/--force option,
5047 Extra care should be taken with the -f/--force option,
5061 which will push all new heads on all branches, an action which will
5048 which will push all new heads on all branches, an action which will
5062 almost always cause confusion for collaborators.
5049 almost always cause confusion for collaborators.
5063
5050
5064 If -r/--rev is used, the specified revision and all its ancestors
5051 If -r/--rev is used, the specified revision and all its ancestors
5065 will be pushed to the remote repository.
5052 will be pushed to the remote repository.
5066
5053
5067 If -B/--bookmark is used, the specified bookmarked revision, its
5054 If -B/--bookmark is used, the specified bookmarked revision, its
5068 ancestors, and the bookmark will be pushed to the remote
5055 ancestors, and the bookmark will be pushed to the remote
5069 repository. Specifying ``.`` is equivalent to specifying the active
5056 repository. Specifying ``.`` is equivalent to specifying the active
5070 bookmark's name.
5057 bookmark's name.
5071
5058
5072 Please see :hg:`help urls` for important details about ``ssh://``
5059 Please see :hg:`help urls` for important details about ``ssh://``
5073 URLs. If DESTINATION is omitted, a default path will be used.
5060 URLs. If DESTINATION is omitted, a default path will be used.
5074
5061
5075 Returns 0 if push was successful, 1 if nothing to push.
5062 Returns 0 if push was successful, 1 if nothing to push.
5076 """
5063 """
5077
5064
5078 if opts.get('bookmark'):
5065 if opts.get('bookmark'):
5079 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5066 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5080 for b in opts['bookmark']:
5067 for b in opts['bookmark']:
5081 # translate -B options to -r so changesets get pushed
5068 # translate -B options to -r so changesets get pushed
5082 b = repo._bookmarks.expandname(b)
5069 b = repo._bookmarks.expandname(b)
5083 if b in repo._bookmarks:
5070 if b in repo._bookmarks:
5084 opts.setdefault('rev', []).append(b)
5071 opts.setdefault('rev', []).append(b)
5085 else:
5072 else:
5086 # if we try to push a deleted bookmark, translate it to null
5073 # if we try to push a deleted bookmark, translate it to null
5087 # this lets simultaneous -r, -b options continue working
5074 # this lets simultaneous -r, -b options continue working
5088 opts.setdefault('rev', []).append("null")
5075 opts.setdefault('rev', []).append("null")
5089
5076
5090 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5077 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5091 if not path:
5078 if not path:
5092 raise error.Abort(_('default repository not configured!'),
5079 raise error.Abort(_('default repository not configured!'),
5093 hint=_("see 'hg help config.paths'"))
5080 hint=_("see 'hg help config.paths'"))
5094 dest = path.pushloc or path.loc
5081 dest = path.pushloc or path.loc
5095 branches = (path.branch, opts.get('branch') or [])
5082 branches = (path.branch, opts.get('branch') or [])
5096 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5083 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5097 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5084 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5098 other = hg.peer(repo, opts, dest)
5085 other = hg.peer(repo, opts, dest)
5099
5086
5100 if revs:
5087 if revs:
5101 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5088 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5102 if not revs:
5089 if not revs:
5103 raise error.Abort(_("specified revisions evaluate to an empty set"),
5090 raise error.Abort(_("specified revisions evaluate to an empty set"),
5104 hint=_("use different revision arguments"))
5091 hint=_("use different revision arguments"))
5105 elif path.pushrev:
5092 elif path.pushrev:
5106 # It doesn't make any sense to specify ancestor revisions. So limit
5093 # It doesn't make any sense to specify ancestor revisions. So limit
5107 # to DAG heads to make discovery simpler.
5094 # to DAG heads to make discovery simpler.
5108 expr = revset.formatspec('heads(%r)', path.pushrev)
5095 expr = revset.formatspec('heads(%r)', path.pushrev)
5109 revs = scmutil.revrange(repo, [expr])
5096 revs = scmutil.revrange(repo, [expr])
5110 revs = [repo[rev].node() for rev in revs]
5097 revs = [repo[rev].node() for rev in revs]
5111 if not revs:
5098 if not revs:
5112 raise error.Abort(_('default push revset for path evaluates to an '
5099 raise error.Abort(_('default push revset for path evaluates to an '
5113 'empty set'))
5100 'empty set'))
5114
5101
5115 repo._subtoppath = dest
5102 repo._subtoppath = dest
5116 try:
5103 try:
5117 # push subrepos depth-first for coherent ordering
5104 # push subrepos depth-first for coherent ordering
5118 c = repo['']
5105 c = repo['']
5119 subs = c.substate # only repos that are committed
5106 subs = c.substate # only repos that are committed
5120 for s in sorted(subs):
5107 for s in sorted(subs):
5121 result = c.sub(s).push(opts)
5108 result = c.sub(s).push(opts)
5122 if result == 0:
5109 if result == 0:
5123 return not result
5110 return not result
5124 finally:
5111 finally:
5125 del repo._subtoppath
5112 del repo._subtoppath
5126 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5113 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5127 newbranch=opts.get('new_branch'),
5114 newbranch=opts.get('new_branch'),
5128 bookmarks=opts.get('bookmark', ()),
5115 bookmarks=opts.get('bookmark', ()),
5129 opargs=opts.get('opargs'))
5116 opargs=opts.get('opargs'))
5130
5117
5131 result = not pushop.cgresult
5118 result = not pushop.cgresult
5132
5119
5133 if pushop.bkresult is not None:
5120 if pushop.bkresult is not None:
5134 if pushop.bkresult == 2:
5121 if pushop.bkresult == 2:
5135 result = 2
5122 result = 2
5136 elif not result and pushop.bkresult:
5123 elif not result and pushop.bkresult:
5137 result = 2
5124 result = 2
5138
5125
5139 return result
5126 return result
5140
5127
5141 @command('recover', [])
5128 @command('recover', [])
5142 def recover(ui, repo):
5129 def recover(ui, repo):
5143 """roll back an interrupted transaction
5130 """roll back an interrupted transaction
5144
5131
5145 Recover from an interrupted commit or pull.
5132 Recover from an interrupted commit or pull.
5146
5133
5147 This command tries to fix the repository status after an
5134 This command tries to fix the repository status after an
5148 interrupted operation. It should only be necessary when Mercurial
5135 interrupted operation. It should only be necessary when Mercurial
5149 suggests it.
5136 suggests it.
5150
5137
5151 Returns 0 if successful, 1 if nothing to recover or verify fails.
5138 Returns 0 if successful, 1 if nothing to recover or verify fails.
5152 """
5139 """
5153 if repo.recover():
5140 if repo.recover():
5154 return hg.verify(repo)
5141 return hg.verify(repo)
5155 return 1
5142 return 1
5156
5143
5157 @command('^remove|rm',
5144 @command('^remove|rm',
5158 [('A', 'after', None, _('record delete for missing files')),
5145 [('A', 'after', None, _('record delete for missing files')),
5159 ('f', 'force', None,
5146 ('f', 'force', None,
5160 _('forget added files, delete modified files')),
5147 _('forget added files, delete modified files')),
5161 ] + subrepoopts + walkopts,
5148 ] + subrepoopts + walkopts,
5162 _('[OPTION]... FILE...'),
5149 _('[OPTION]... FILE...'),
5163 inferrepo=True)
5150 inferrepo=True)
5164 def remove(ui, repo, *pats, **opts):
5151 def remove(ui, repo, *pats, **opts):
5165 """remove the specified files on the next commit
5152 """remove the specified files on the next commit
5166
5153
5167 Schedule the indicated files for removal from the current branch.
5154 Schedule the indicated files for removal from the current branch.
5168
5155
5169 This command schedules the files to be removed at the next commit.
5156 This command schedules the files to be removed at the next commit.
5170 To undo a remove before that, see :hg:`revert`. To undo added
5157 To undo a remove before that, see :hg:`revert`. To undo added
5171 files, see :hg:`forget`.
5158 files, see :hg:`forget`.
5172
5159
5173 .. container:: verbose
5160 .. container:: verbose
5174
5161
5175 -A/--after can be used to remove only files that have already
5162 -A/--after can be used to remove only files that have already
5176 been deleted, -f/--force can be used to force deletion, and -Af
5163 been deleted, -f/--force can be used to force deletion, and -Af
5177 can be used to remove files from the next revision without
5164 can be used to remove files from the next revision without
5178 deleting them from the working directory.
5165 deleting them from the working directory.
5179
5166
5180 The following table details the behavior of remove for different
5167 The following table details the behavior of remove for different
5181 file states (columns) and option combinations (rows). The file
5168 file states (columns) and option combinations (rows). The file
5182 states are Added [A], Clean [C], Modified [M] and Missing [!]
5169 states are Added [A], Clean [C], Modified [M] and Missing [!]
5183 (as reported by :hg:`status`). The actions are Warn, Remove
5170 (as reported by :hg:`status`). The actions are Warn, Remove
5184 (from branch) and Delete (from disk):
5171 (from branch) and Delete (from disk):
5185
5172
5186 ========= == == == ==
5173 ========= == == == ==
5187 opt/state A C M !
5174 opt/state A C M !
5188 ========= == == == ==
5175 ========= == == == ==
5189 none W RD W R
5176 none W RD W R
5190 -f R RD RD R
5177 -f R RD RD R
5191 -A W W W R
5178 -A W W W R
5192 -Af R R R R
5179 -Af R R R R
5193 ========= == == == ==
5180 ========= == == == ==
5194
5181
5195 .. note::
5182 .. note::
5196
5183
5197 :hg:`remove` never deletes files in Added [A] state from the
5184 :hg:`remove` never deletes files in Added [A] state from the
5198 working directory, not even if ``--force`` is specified.
5185 working directory, not even if ``--force`` is specified.
5199
5186
5200 Returns 0 on success, 1 if any warnings encountered.
5187 Returns 0 on success, 1 if any warnings encountered.
5201 """
5188 """
5202
5189
5203 after, force = opts.get('after'), opts.get('force')
5190 after, force = opts.get('after'), opts.get('force')
5204 if not pats and not after:
5191 if not pats and not after:
5205 raise error.Abort(_('no files specified'))
5192 raise error.Abort(_('no files specified'))
5206
5193
5207 m = scmutil.match(repo[None], pats, opts)
5194 m = scmutil.match(repo[None], pats, opts)
5208 subrepos = opts.get('subrepos')
5195 subrepos = opts.get('subrepos')
5209 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5196 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5210
5197
5211 @command('rename|move|mv',
5198 @command('rename|move|mv',
5212 [('A', 'after', None, _('record a rename that has already occurred')),
5199 [('A', 'after', None, _('record a rename that has already occurred')),
5213 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5200 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5214 ] + walkopts + dryrunopts,
5201 ] + walkopts + dryrunopts,
5215 _('[OPTION]... SOURCE... DEST'))
5202 _('[OPTION]... SOURCE... DEST'))
5216 def rename(ui, repo, *pats, **opts):
5203 def rename(ui, repo, *pats, **opts):
5217 """rename files; equivalent of copy + remove
5204 """rename files; equivalent of copy + remove
5218
5205
5219 Mark dest as copies of sources; mark sources for deletion. If dest
5206 Mark dest as copies of sources; mark sources for deletion. If dest
5220 is a directory, copies are put in that directory. If dest is a
5207 is a directory, copies are put in that directory. If dest is a
5221 file, there can only be one source.
5208 file, there can only be one source.
5222
5209
5223 By default, this command copies the contents of files as they
5210 By default, this command copies the contents of files as they
5224 exist in the working directory. If invoked with -A/--after, the
5211 exist in the working directory. If invoked with -A/--after, the
5225 operation is recorded, but no copying is performed.
5212 operation is recorded, but no copying is performed.
5226
5213
5227 This command takes effect at the next commit. To undo a rename
5214 This command takes effect at the next commit. To undo a rename
5228 before that, see :hg:`revert`.
5215 before that, see :hg:`revert`.
5229
5216
5230 Returns 0 on success, 1 if errors are encountered.
5217 Returns 0 on success, 1 if errors are encountered.
5231 """
5218 """
5232 with repo.wlock(False):
5219 with repo.wlock(False):
5233 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5220 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5234
5221
5235 @command('resolve',
5222 @command('resolve',
5236 [('a', 'all', None, _('select all unresolved files')),
5223 [('a', 'all', None, _('select all unresolved files')),
5237 ('l', 'list', None, _('list state of files needing merge')),
5224 ('l', 'list', None, _('list state of files needing merge')),
5238 ('m', 'mark', None, _('mark files as resolved')),
5225 ('m', 'mark', None, _('mark files as resolved')),
5239 ('u', 'unmark', None, _('mark files as unresolved')),
5226 ('u', 'unmark', None, _('mark files as unresolved')),
5240 ('n', 'no-status', None, _('hide status prefix'))]
5227 ('n', 'no-status', None, _('hide status prefix'))]
5241 + mergetoolopts + walkopts + formatteropts,
5228 + mergetoolopts + walkopts + formatteropts,
5242 _('[OPTION]... [FILE]...'),
5229 _('[OPTION]... [FILE]...'),
5243 inferrepo=True)
5230 inferrepo=True)
5244 def resolve(ui, repo, *pats, **opts):
5231 def resolve(ui, repo, *pats, **opts):
5245 """redo merges or set/view the merge status of files
5232 """redo merges or set/view the merge status of files
5246
5233
5247 Merges with unresolved conflicts are often the result of
5234 Merges with unresolved conflicts are often the result of
5248 non-interactive merging using the ``internal:merge`` configuration
5235 non-interactive merging using the ``internal:merge`` configuration
5249 setting, or a command-line merge tool like ``diff3``. The resolve
5236 setting, or a command-line merge tool like ``diff3``. The resolve
5250 command is used to manage the files involved in a merge, after
5237 command is used to manage the files involved in a merge, after
5251 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5238 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5252 working directory must have two parents). See :hg:`help
5239 working directory must have two parents). See :hg:`help
5253 merge-tools` for information on configuring merge tools.
5240 merge-tools` for information on configuring merge tools.
5254
5241
5255 The resolve command can be used in the following ways:
5242 The resolve command can be used in the following ways:
5256
5243
5257 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5244 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5258 files, discarding any previous merge attempts. Re-merging is not
5245 files, discarding any previous merge attempts. Re-merging is not
5259 performed for files already marked as resolved. Use ``--all/-a``
5246 performed for files already marked as resolved. Use ``--all/-a``
5260 to select all unresolved files. ``--tool`` can be used to specify
5247 to select all unresolved files. ``--tool`` can be used to specify
5261 the merge tool used for the given files. It overrides the HGMERGE
5248 the merge tool used for the given files. It overrides the HGMERGE
5262 environment variable and your configuration files. Previous file
5249 environment variable and your configuration files. Previous file
5263 contents are saved with a ``.orig`` suffix.
5250 contents are saved with a ``.orig`` suffix.
5264
5251
5265 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5252 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5266 (e.g. after having manually fixed-up the files). The default is
5253 (e.g. after having manually fixed-up the files). The default is
5267 to mark all unresolved files.
5254 to mark all unresolved files.
5268
5255
5269 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5256 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5270 default is to mark all resolved files.
5257 default is to mark all resolved files.
5271
5258
5272 - :hg:`resolve -l`: list files which had or still have conflicts.
5259 - :hg:`resolve -l`: list files which had or still have conflicts.
5273 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5260 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5274
5261
5275 .. note::
5262 .. note::
5276
5263
5277 Mercurial will not let you commit files with unresolved merge
5264 Mercurial will not let you commit files with unresolved merge
5278 conflicts. You must use :hg:`resolve -m ...` before you can
5265 conflicts. You must use :hg:`resolve -m ...` before you can
5279 commit after a conflicting merge.
5266 commit after a conflicting merge.
5280
5267
5281 Returns 0 on success, 1 if any files fail a resolve attempt.
5268 Returns 0 on success, 1 if any files fail a resolve attempt.
5282 """
5269 """
5283
5270
5284 flaglist = 'all mark unmark list no_status'.split()
5271 flaglist = 'all mark unmark list no_status'.split()
5285 all, mark, unmark, show, nostatus = \
5272 all, mark, unmark, show, nostatus = \
5286 [opts.get(o) for o in flaglist]
5273 [opts.get(o) for o in flaglist]
5287
5274
5288 if (show and (mark or unmark)) or (mark and unmark):
5275 if (show and (mark or unmark)) or (mark and unmark):
5289 raise error.Abort(_("too many options specified"))
5276 raise error.Abort(_("too many options specified"))
5290 if pats and all:
5277 if pats and all:
5291 raise error.Abort(_("can't specify --all and patterns"))
5278 raise error.Abort(_("can't specify --all and patterns"))
5292 if not (all or pats or show or mark or unmark):
5279 if not (all or pats or show or mark or unmark):
5293 raise error.Abort(_('no files or directories specified'),
5280 raise error.Abort(_('no files or directories specified'),
5294 hint=('use --all to re-merge all unresolved files'))
5281 hint=('use --all to re-merge all unresolved files'))
5295
5282
5296 if show:
5283 if show:
5297 fm = ui.formatter('resolve', opts)
5284 fm = ui.formatter('resolve', opts)
5298 ms = mergemod.mergestate.read(repo)
5285 ms = mergemod.mergestate.read(repo)
5299 m = scmutil.match(repo[None], pats, opts)
5286 m = scmutil.match(repo[None], pats, opts)
5300 for f in ms:
5287 for f in ms:
5301 if not m(f):
5288 if not m(f):
5302 continue
5289 continue
5303 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5290 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5304 'd': 'driverresolved'}[ms[f]]
5291 'd': 'driverresolved'}[ms[f]]
5305 fm.startitem()
5292 fm.startitem()
5306 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5293 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5307 fm.write('path', '%s\n', f, label=l)
5294 fm.write('path', '%s\n', f, label=l)
5308 fm.end()
5295 fm.end()
5309 return 0
5296 return 0
5310
5297
5311 with repo.wlock():
5298 with repo.wlock():
5312 ms = mergemod.mergestate.read(repo)
5299 ms = mergemod.mergestate.read(repo)
5313
5300
5314 if not (ms.active() or repo.dirstate.p2() != nullid):
5301 if not (ms.active() or repo.dirstate.p2() != nullid):
5315 raise error.Abort(
5302 raise error.Abort(
5316 _('resolve command not applicable when not merging'))
5303 _('resolve command not applicable when not merging'))
5317
5304
5318 wctx = repo[None]
5305 wctx = repo[None]
5319
5306
5320 if ms.mergedriver and ms.mdstate() == 'u':
5307 if ms.mergedriver and ms.mdstate() == 'u':
5321 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5308 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5322 ms.commit()
5309 ms.commit()
5323 # allow mark and unmark to go through
5310 # allow mark and unmark to go through
5324 if not mark and not unmark and not proceed:
5311 if not mark and not unmark and not proceed:
5325 return 1
5312 return 1
5326
5313
5327 m = scmutil.match(wctx, pats, opts)
5314 m = scmutil.match(wctx, pats, opts)
5328 ret = 0
5315 ret = 0
5329 didwork = False
5316 didwork = False
5330 runconclude = False
5317 runconclude = False
5331
5318
5332 tocomplete = []
5319 tocomplete = []
5333 for f in ms:
5320 for f in ms:
5334 if not m(f):
5321 if not m(f):
5335 continue
5322 continue
5336
5323
5337 didwork = True
5324 didwork = True
5338
5325
5339 # don't let driver-resolved files be marked, and run the conclude
5326 # don't let driver-resolved files be marked, and run the conclude
5340 # step if asked to resolve
5327 # step if asked to resolve
5341 if ms[f] == "d":
5328 if ms[f] == "d":
5342 exact = m.exact(f)
5329 exact = m.exact(f)
5343 if mark:
5330 if mark:
5344 if exact:
5331 if exact:
5345 ui.warn(_('not marking %s as it is driver-resolved\n')
5332 ui.warn(_('not marking %s as it is driver-resolved\n')
5346 % f)
5333 % f)
5347 elif unmark:
5334 elif unmark:
5348 if exact:
5335 if exact:
5349 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5336 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5350 % f)
5337 % f)
5351 else:
5338 else:
5352 runconclude = True
5339 runconclude = True
5353 continue
5340 continue
5354
5341
5355 if mark:
5342 if mark:
5356 ms.mark(f, "r")
5343 ms.mark(f, "r")
5357 elif unmark:
5344 elif unmark:
5358 ms.mark(f, "u")
5345 ms.mark(f, "u")
5359 else:
5346 else:
5360 # backup pre-resolve (merge uses .orig for its own purposes)
5347 # backup pre-resolve (merge uses .orig for its own purposes)
5361 a = repo.wjoin(f)
5348 a = repo.wjoin(f)
5362 try:
5349 try:
5363 util.copyfile(a, a + ".resolve")
5350 util.copyfile(a, a + ".resolve")
5364 except (IOError, OSError) as inst:
5351 except (IOError, OSError) as inst:
5365 if inst.errno != errno.ENOENT:
5352 if inst.errno != errno.ENOENT:
5366 raise
5353 raise
5367
5354
5368 try:
5355 try:
5369 # preresolve file
5356 # preresolve file
5370 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5357 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5371 'resolve')
5358 'resolve')
5372 complete, r = ms.preresolve(f, wctx)
5359 complete, r = ms.preresolve(f, wctx)
5373 if not complete:
5360 if not complete:
5374 tocomplete.append(f)
5361 tocomplete.append(f)
5375 elif r:
5362 elif r:
5376 ret = 1
5363 ret = 1
5377 finally:
5364 finally:
5378 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5365 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5379 ms.commit()
5366 ms.commit()
5380
5367
5381 # replace filemerge's .orig file with our resolve file, but only
5368 # replace filemerge's .orig file with our resolve file, but only
5382 # for merges that are complete
5369 # for merges that are complete
5383 if complete:
5370 if complete:
5384 try:
5371 try:
5385 util.rename(a + ".resolve",
5372 util.rename(a + ".resolve",
5386 scmutil.origpath(ui, repo, a))
5373 scmutil.origpath(ui, repo, a))
5387 except OSError as inst:
5374 except OSError as inst:
5388 if inst.errno != errno.ENOENT:
5375 if inst.errno != errno.ENOENT:
5389 raise
5376 raise
5390
5377
5391 for f in tocomplete:
5378 for f in tocomplete:
5392 try:
5379 try:
5393 # resolve file
5380 # resolve file
5394 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5381 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5395 'resolve')
5382 'resolve')
5396 r = ms.resolve(f, wctx)
5383 r = ms.resolve(f, wctx)
5397 if r:
5384 if r:
5398 ret = 1
5385 ret = 1
5399 finally:
5386 finally:
5400 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5387 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5401 ms.commit()
5388 ms.commit()
5402
5389
5403 # replace filemerge's .orig file with our resolve file
5390 # replace filemerge's .orig file with our resolve file
5404 a = repo.wjoin(f)
5391 a = repo.wjoin(f)
5405 try:
5392 try:
5406 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5393 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5407 except OSError as inst:
5394 except OSError as inst:
5408 if inst.errno != errno.ENOENT:
5395 if inst.errno != errno.ENOENT:
5409 raise
5396 raise
5410
5397
5411 ms.commit()
5398 ms.commit()
5412 ms.recordactions()
5399 ms.recordactions()
5413
5400
5414 if not didwork and pats:
5401 if not didwork and pats:
5415 hint = None
5402 hint = None
5416 if not any([p for p in pats if p.find(':') >= 0]):
5403 if not any([p for p in pats if p.find(':') >= 0]):
5417 pats = ['path:%s' % p for p in pats]
5404 pats = ['path:%s' % p for p in pats]
5418 m = scmutil.match(wctx, pats, opts)
5405 m = scmutil.match(wctx, pats, opts)
5419 for f in ms:
5406 for f in ms:
5420 if not m(f):
5407 if not m(f):
5421 continue
5408 continue
5422 flags = ''.join(['-%s ' % o[0] for o in flaglist
5409 flags = ''.join(['-%s ' % o[0] for o in flaglist
5423 if opts.get(o)])
5410 if opts.get(o)])
5424 hint = _("(try: hg resolve %s%s)\n") % (
5411 hint = _("(try: hg resolve %s%s)\n") % (
5425 flags,
5412 flags,
5426 ' '.join(pats))
5413 ' '.join(pats))
5427 break
5414 break
5428 ui.warn(_("arguments do not match paths that need resolving\n"))
5415 ui.warn(_("arguments do not match paths that need resolving\n"))
5429 if hint:
5416 if hint:
5430 ui.warn(hint)
5417 ui.warn(hint)
5431 elif ms.mergedriver and ms.mdstate() != 's':
5418 elif ms.mergedriver and ms.mdstate() != 's':
5432 # run conclude step when either a driver-resolved file is requested
5419 # run conclude step when either a driver-resolved file is requested
5433 # or there are no driver-resolved files
5420 # or there are no driver-resolved files
5434 # we can't use 'ret' to determine whether any files are unresolved
5421 # we can't use 'ret' to determine whether any files are unresolved
5435 # because we might not have tried to resolve some
5422 # because we might not have tried to resolve some
5436 if ((runconclude or not list(ms.driverresolved()))
5423 if ((runconclude or not list(ms.driverresolved()))
5437 and not list(ms.unresolved())):
5424 and not list(ms.unresolved())):
5438 proceed = mergemod.driverconclude(repo, ms, wctx)
5425 proceed = mergemod.driverconclude(repo, ms, wctx)
5439 ms.commit()
5426 ms.commit()
5440 if not proceed:
5427 if not proceed:
5441 return 1
5428 return 1
5442
5429
5443 # Nudge users into finishing an unfinished operation
5430 # Nudge users into finishing an unfinished operation
5444 unresolvedf = list(ms.unresolved())
5431 unresolvedf = list(ms.unresolved())
5445 driverresolvedf = list(ms.driverresolved())
5432 driverresolvedf = list(ms.driverresolved())
5446 if not unresolvedf and not driverresolvedf:
5433 if not unresolvedf and not driverresolvedf:
5447 ui.status(_('(no more unresolved files)\n'))
5434 ui.status(_('(no more unresolved files)\n'))
5448 cmdutil.checkafterresolved(repo)
5435 cmdutil.checkafterresolved(repo)
5449 elif not unresolvedf:
5436 elif not unresolvedf:
5450 ui.status(_('(no more unresolved files -- '
5437 ui.status(_('(no more unresolved files -- '
5451 'run "hg resolve --all" to conclude)\n'))
5438 'run "hg resolve --all" to conclude)\n'))
5452
5439
5453 return ret
5440 return ret
5454
5441
5455 @command('revert',
5442 @command('revert',
5456 [('a', 'all', None, _('revert all changes when no arguments given')),
5443 [('a', 'all', None, _('revert all changes when no arguments given')),
5457 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5444 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5458 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5445 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5459 ('C', 'no-backup', None, _('do not save backup copies of files')),
5446 ('C', 'no-backup', None, _('do not save backup copies of files')),
5460 ('i', 'interactive', None,
5447 ('i', 'interactive', None,
5461 _('interactively select the changes (EXPERIMENTAL)')),
5448 _('interactively select the changes (EXPERIMENTAL)')),
5462 ] + walkopts + dryrunopts,
5449 ] + walkopts + dryrunopts,
5463 _('[OPTION]... [-r REV] [NAME]...'))
5450 _('[OPTION]... [-r REV] [NAME]...'))
5464 def revert(ui, repo, *pats, **opts):
5451 def revert(ui, repo, *pats, **opts):
5465 """restore files to their checkout state
5452 """restore files to their checkout state
5466
5453
5467 .. note::
5454 .. note::
5468
5455
5469 To check out earlier revisions, you should use :hg:`update REV`.
5456 To check out earlier revisions, you should use :hg:`update REV`.
5470 To cancel an uncommitted merge (and lose your changes),
5457 To cancel an uncommitted merge (and lose your changes),
5471 use :hg:`update --clean .`.
5458 use :hg:`update --clean .`.
5472
5459
5473 With no revision specified, revert the specified files or directories
5460 With no revision specified, revert the specified files or directories
5474 to the contents they had in the parent of the working directory.
5461 to the contents they had in the parent of the working directory.
5475 This restores the contents of files to an unmodified
5462 This restores the contents of files to an unmodified
5476 state and unschedules adds, removes, copies, and renames. If the
5463 state and unschedules adds, removes, copies, and renames. If the
5477 working directory has two parents, you must explicitly specify a
5464 working directory has two parents, you must explicitly specify a
5478 revision.
5465 revision.
5479
5466
5480 Using the -r/--rev or -d/--date options, revert the given files or
5467 Using the -r/--rev or -d/--date options, revert the given files or
5481 directories to their states as of a specific revision. Because
5468 directories to their states as of a specific revision. Because
5482 revert does not change the working directory parents, this will
5469 revert does not change the working directory parents, this will
5483 cause these files to appear modified. This can be helpful to "back
5470 cause these files to appear modified. This can be helpful to "back
5484 out" some or all of an earlier change. See :hg:`backout` for a
5471 out" some or all of an earlier change. See :hg:`backout` for a
5485 related method.
5472 related method.
5486
5473
5487 Modified files are saved with a .orig suffix before reverting.
5474 Modified files are saved with a .orig suffix before reverting.
5488 To disable these backups, use --no-backup. It is possible to store
5475 To disable these backups, use --no-backup. It is possible to store
5489 the backup files in a custom directory relative to the root of the
5476 the backup files in a custom directory relative to the root of the
5490 repository by setting the ``ui.origbackuppath`` configuration
5477 repository by setting the ``ui.origbackuppath`` configuration
5491 option.
5478 option.
5492
5479
5493 See :hg:`help dates` for a list of formats valid for -d/--date.
5480 See :hg:`help dates` for a list of formats valid for -d/--date.
5494
5481
5495 See :hg:`help backout` for a way to reverse the effect of an
5482 See :hg:`help backout` for a way to reverse the effect of an
5496 earlier changeset.
5483 earlier changeset.
5497
5484
5498 Returns 0 on success.
5485 Returns 0 on success.
5499 """
5486 """
5500
5487
5501 if opts.get("date"):
5488 if opts.get("date"):
5502 if opts.get("rev"):
5489 if opts.get("rev"):
5503 raise error.Abort(_("you can't specify a revision and a date"))
5490 raise error.Abort(_("you can't specify a revision and a date"))
5504 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5491 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5505
5492
5506 parent, p2 = repo.dirstate.parents()
5493 parent, p2 = repo.dirstate.parents()
5507 if not opts.get('rev') and p2 != nullid:
5494 if not opts.get('rev') and p2 != nullid:
5508 # revert after merge is a trap for new users (issue2915)
5495 # revert after merge is a trap for new users (issue2915)
5509 raise error.Abort(_('uncommitted merge with no revision specified'),
5496 raise error.Abort(_('uncommitted merge with no revision specified'),
5510 hint=_("use 'hg update' or see 'hg help revert'"))
5497 hint=_("use 'hg update' or see 'hg help revert'"))
5511
5498
5512 ctx = scmutil.revsingle(repo, opts.get('rev'))
5499 ctx = scmutil.revsingle(repo, opts.get('rev'))
5513
5500
5514 if (not (pats or opts.get('include') or opts.get('exclude') or
5501 if (not (pats or opts.get('include') or opts.get('exclude') or
5515 opts.get('all') or opts.get('interactive'))):
5502 opts.get('all') or opts.get('interactive'))):
5516 msg = _("no files or directories specified")
5503 msg = _("no files or directories specified")
5517 if p2 != nullid:
5504 if p2 != nullid:
5518 hint = _("uncommitted merge, use --all to discard all changes,"
5505 hint = _("uncommitted merge, use --all to discard all changes,"
5519 " or 'hg update -C .' to abort the merge")
5506 " or 'hg update -C .' to abort the merge")
5520 raise error.Abort(msg, hint=hint)
5507 raise error.Abort(msg, hint=hint)
5521 dirty = any(repo.status())
5508 dirty = any(repo.status())
5522 node = ctx.node()
5509 node = ctx.node()
5523 if node != parent:
5510 if node != parent:
5524 if dirty:
5511 if dirty:
5525 hint = _("uncommitted changes, use --all to discard all"
5512 hint = _("uncommitted changes, use --all to discard all"
5526 " changes, or 'hg update %s' to update") % ctx.rev()
5513 " changes, or 'hg update %s' to update") % ctx.rev()
5527 else:
5514 else:
5528 hint = _("use --all to revert all files,"
5515 hint = _("use --all to revert all files,"
5529 " or 'hg update %s' to update") % ctx.rev()
5516 " or 'hg update %s' to update") % ctx.rev()
5530 elif dirty:
5517 elif dirty:
5531 hint = _("uncommitted changes, use --all to discard all changes")
5518 hint = _("uncommitted changes, use --all to discard all changes")
5532 else:
5519 else:
5533 hint = _("use --all to revert all files")
5520 hint = _("use --all to revert all files")
5534 raise error.Abort(msg, hint=hint)
5521 raise error.Abort(msg, hint=hint)
5535
5522
5536 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5523 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5537
5524
5538 @command('rollback', dryrunopts +
5525 @command('rollback', dryrunopts +
5539 [('f', 'force', False, _('ignore safety measures'))])
5526 [('f', 'force', False, _('ignore safety measures'))])
5540 def rollback(ui, repo, **opts):
5527 def rollback(ui, repo, **opts):
5541 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5528 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5542
5529
5543 Please use :hg:`commit --amend` instead of rollback to correct
5530 Please use :hg:`commit --amend` instead of rollback to correct
5544 mistakes in the last commit.
5531 mistakes in the last commit.
5545
5532
5546 This command should be used with care. There is only one level of
5533 This command should be used with care. There is only one level of
5547 rollback, and there is no way to undo a rollback. It will also
5534 rollback, and there is no way to undo a rollback. It will also
5548 restore the dirstate at the time of the last transaction, losing
5535 restore the dirstate at the time of the last transaction, losing
5549 any dirstate changes since that time. This command does not alter
5536 any dirstate changes since that time. This command does not alter
5550 the working directory.
5537 the working directory.
5551
5538
5552 Transactions are used to encapsulate the effects of all commands
5539 Transactions are used to encapsulate the effects of all commands
5553 that create new changesets or propagate existing changesets into a
5540 that create new changesets or propagate existing changesets into a
5554 repository.
5541 repository.
5555
5542
5556 .. container:: verbose
5543 .. container:: verbose
5557
5544
5558 For example, the following commands are transactional, and their
5545 For example, the following commands are transactional, and their
5559 effects can be rolled back:
5546 effects can be rolled back:
5560
5547
5561 - commit
5548 - commit
5562 - import
5549 - import
5563 - pull
5550 - pull
5564 - push (with this repository as the destination)
5551 - push (with this repository as the destination)
5565 - unbundle
5552 - unbundle
5566
5553
5567 To avoid permanent data loss, rollback will refuse to rollback a
5554 To avoid permanent data loss, rollback will refuse to rollback a
5568 commit transaction if it isn't checked out. Use --force to
5555 commit transaction if it isn't checked out. Use --force to
5569 override this protection.
5556 override this protection.
5570
5557
5571 The rollback command can be entirely disabled by setting the
5558 The rollback command can be entirely disabled by setting the
5572 ``ui.rollback`` configuration setting to false. If you're here
5559 ``ui.rollback`` configuration setting to false. If you're here
5573 because you want to use rollback and it's disabled, you can
5560 because you want to use rollback and it's disabled, you can
5574 re-enable the command by setting ``ui.rollback`` to true.
5561 re-enable the command by setting ``ui.rollback`` to true.
5575
5562
5576 This command is not intended for use on public repositories. Once
5563 This command is not intended for use on public repositories. Once
5577 changes are visible for pull by other users, rolling a transaction
5564 changes are visible for pull by other users, rolling a transaction
5578 back locally is ineffective (someone else may already have pulled
5565 back locally is ineffective (someone else may already have pulled
5579 the changes). Furthermore, a race is possible with readers of the
5566 the changes). Furthermore, a race is possible with readers of the
5580 repository; for example an in-progress pull from the repository
5567 repository; for example an in-progress pull from the repository
5581 may fail if a rollback is performed.
5568 may fail if a rollback is performed.
5582
5569
5583 Returns 0 on success, 1 if no rollback data is available.
5570 Returns 0 on success, 1 if no rollback data is available.
5584 """
5571 """
5585 if not ui.configbool('ui', 'rollback', True):
5572 if not ui.configbool('ui', 'rollback', True):
5586 raise error.Abort(_('rollback is disabled because it is unsafe'),
5573 raise error.Abort(_('rollback is disabled because it is unsafe'),
5587 hint=('see `hg help -v rollback` for information'))
5574 hint=('see `hg help -v rollback` for information'))
5588 return repo.rollback(dryrun=opts.get('dry_run'),
5575 return repo.rollback(dryrun=opts.get('dry_run'),
5589 force=opts.get('force'))
5576 force=opts.get('force'))
5590
5577
5591 @command('root', [])
5578 @command('root', [])
5592 def root(ui, repo):
5579 def root(ui, repo):
5593 """print the root (top) of the current working directory
5580 """print the root (top) of the current working directory
5594
5581
5595 Print the root directory of the current repository.
5582 Print the root directory of the current repository.
5596
5583
5597 Returns 0 on success.
5584 Returns 0 on success.
5598 """
5585 """
5599 ui.write(repo.root + "\n")
5586 ui.write(repo.root + "\n")
5600
5587
5601 @command('^serve',
5588 @command('^serve',
5602 [('A', 'accesslog', '', _('name of access log file to write to'),
5589 [('A', 'accesslog', '', _('name of access log file to write to'),
5603 _('FILE')),
5590 _('FILE')),
5604 ('d', 'daemon', None, _('run server in background')),
5591 ('d', 'daemon', None, _('run server in background')),
5605 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5592 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5606 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5593 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5607 # use string type, then we can check if something was passed
5594 # use string type, then we can check if something was passed
5608 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5595 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5609 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5596 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5610 _('ADDR')),
5597 _('ADDR')),
5611 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5598 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5612 _('PREFIX')),
5599 _('PREFIX')),
5613 ('n', 'name', '',
5600 ('n', 'name', '',
5614 _('name to show in web pages (default: working directory)'), _('NAME')),
5601 _('name to show in web pages (default: working directory)'), _('NAME')),
5615 ('', 'web-conf', '',
5602 ('', 'web-conf', '',
5616 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5603 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5617 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5604 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5618 _('FILE')),
5605 _('FILE')),
5619 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5606 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5620 ('', 'stdio', None, _('for remote clients')),
5607 ('', 'stdio', None, _('for remote clients')),
5621 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5608 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5622 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5609 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5623 ('', 'style', '', _('template style to use'), _('STYLE')),
5610 ('', 'style', '', _('template style to use'), _('STYLE')),
5624 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5611 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5625 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5612 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5626 _('[OPTION]...'),
5613 _('[OPTION]...'),
5627 optionalrepo=True)
5614 optionalrepo=True)
5628 def serve(ui, repo, **opts):
5615 def serve(ui, repo, **opts):
5629 """start stand-alone webserver
5616 """start stand-alone webserver
5630
5617
5631 Start a local HTTP repository browser and pull server. You can use
5618 Start a local HTTP repository browser and pull server. You can use
5632 this for ad-hoc sharing and browsing of repositories. It is
5619 this for ad-hoc sharing and browsing of repositories. It is
5633 recommended to use a real web server to serve a repository for
5620 recommended to use a real web server to serve a repository for
5634 longer periods of time.
5621 longer periods of time.
5635
5622
5636 Please note that the server does not implement access control.
5623 Please note that the server does not implement access control.
5637 This means that, by default, anybody can read from the server and
5624 This means that, by default, anybody can read from the server and
5638 nobody can write to it by default. Set the ``web.allow_push``
5625 nobody can write to it by default. Set the ``web.allow_push``
5639 option to ``*`` to allow everybody to push to the server. You
5626 option to ``*`` to allow everybody to push to the server. You
5640 should use a real web server if you need to authenticate users.
5627 should use a real web server if you need to authenticate users.
5641
5628
5642 By default, the server logs accesses to stdout and errors to
5629 By default, the server logs accesses to stdout and errors to
5643 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5630 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5644 files.
5631 files.
5645
5632
5646 To have the server choose a free port number to listen on, specify
5633 To have the server choose a free port number to listen on, specify
5647 a port number of 0; in this case, the server will print the port
5634 a port number of 0; in this case, the server will print the port
5648 number it uses.
5635 number it uses.
5649
5636
5650 Returns 0 on success.
5637 Returns 0 on success.
5651 """
5638 """
5652
5639
5653 if opts["stdio"] and opts["cmdserver"]:
5640 if opts["stdio"] and opts["cmdserver"]:
5654 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5641 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5655
5642
5656 if opts["stdio"]:
5643 if opts["stdio"]:
5657 if repo is None:
5644 if repo is None:
5658 raise error.RepoError(_("there is no Mercurial repository here"
5645 raise error.RepoError(_("there is no Mercurial repository here"
5659 " (.hg not found)"))
5646 " (.hg not found)"))
5660 s = sshserver.sshserver(ui, repo)
5647 s = sshserver.sshserver(ui, repo)
5661 s.serve_forever()
5648 s.serve_forever()
5662
5649
5663 service = server.createservice(ui, repo, opts)
5650 service = server.createservice(ui, repo, opts)
5664 return server.runservice(opts, initfn=service.init, runfn=service.run)
5651 return server.runservice(opts, initfn=service.init, runfn=service.run)
5665
5652
5666 @command('^status|st',
5653 @command('^status|st',
5667 [('A', 'all', None, _('show status of all files')),
5654 [('A', 'all', None, _('show status of all files')),
5668 ('m', 'modified', None, _('show only modified files')),
5655 ('m', 'modified', None, _('show only modified files')),
5669 ('a', 'added', None, _('show only added files')),
5656 ('a', 'added', None, _('show only added files')),
5670 ('r', 'removed', None, _('show only removed files')),
5657 ('r', 'removed', None, _('show only removed files')),
5671 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5658 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5672 ('c', 'clean', None, _('show only files without changes')),
5659 ('c', 'clean', None, _('show only files without changes')),
5673 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5660 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5674 ('i', 'ignored', None, _('show only ignored files')),
5661 ('i', 'ignored', None, _('show only ignored files')),
5675 ('n', 'no-status', None, _('hide status prefix')),
5662 ('n', 'no-status', None, _('hide status prefix')),
5676 ('C', 'copies', None, _('show source of copied files')),
5663 ('C', 'copies', None, _('show source of copied files')),
5677 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5664 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5678 ('', 'rev', [], _('show difference from revision'), _('REV')),
5665 ('', 'rev', [], _('show difference from revision'), _('REV')),
5679 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5666 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5680 ] + walkopts + subrepoopts + formatteropts,
5667 ] + walkopts + subrepoopts + formatteropts,
5681 _('[OPTION]... [FILE]...'),
5668 _('[OPTION]... [FILE]...'),
5682 inferrepo=True)
5669 inferrepo=True)
5683 def status(ui, repo, *pats, **opts):
5670 def status(ui, repo, *pats, **opts):
5684 """show changed files in the working directory
5671 """show changed files in the working directory
5685
5672
5686 Show status of files in the repository. If names are given, only
5673 Show status of files in the repository. If names are given, only
5687 files that match are shown. Files that are clean or ignored or
5674 files that match are shown. Files that are clean or ignored or
5688 the source of a copy/move operation, are not listed unless
5675 the source of a copy/move operation, are not listed unless
5689 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5676 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5690 Unless options described with "show only ..." are given, the
5677 Unless options described with "show only ..." are given, the
5691 options -mardu are used.
5678 options -mardu are used.
5692
5679
5693 Option -q/--quiet hides untracked (unknown and ignored) files
5680 Option -q/--quiet hides untracked (unknown and ignored) files
5694 unless explicitly requested with -u/--unknown or -i/--ignored.
5681 unless explicitly requested with -u/--unknown or -i/--ignored.
5695
5682
5696 .. note::
5683 .. note::
5697
5684
5698 :hg:`status` may appear to disagree with diff if permissions have
5685 :hg:`status` may appear to disagree with diff if permissions have
5699 changed or a merge has occurred. The standard diff format does
5686 changed or a merge has occurred. The standard diff format does
5700 not report permission changes and diff only reports changes
5687 not report permission changes and diff only reports changes
5701 relative to one merge parent.
5688 relative to one merge parent.
5702
5689
5703 If one revision is given, it is used as the base revision.
5690 If one revision is given, it is used as the base revision.
5704 If two revisions are given, the differences between them are
5691 If two revisions are given, the differences between them are
5705 shown. The --change option can also be used as a shortcut to list
5692 shown. The --change option can also be used as a shortcut to list
5706 the changed files of a revision from its first parent.
5693 the changed files of a revision from its first parent.
5707
5694
5708 The codes used to show the status of files are::
5695 The codes used to show the status of files are::
5709
5696
5710 M = modified
5697 M = modified
5711 A = added
5698 A = added
5712 R = removed
5699 R = removed
5713 C = clean
5700 C = clean
5714 ! = missing (deleted by non-hg command, but still tracked)
5701 ! = missing (deleted by non-hg command, but still tracked)
5715 ? = not tracked
5702 ? = not tracked
5716 I = ignored
5703 I = ignored
5717 = origin of the previous file (with --copies)
5704 = origin of the previous file (with --copies)
5718
5705
5719 .. container:: verbose
5706 .. container:: verbose
5720
5707
5721 Examples:
5708 Examples:
5722
5709
5723 - show changes in the working directory relative to a
5710 - show changes in the working directory relative to a
5724 changeset::
5711 changeset::
5725
5712
5726 hg status --rev 9353
5713 hg status --rev 9353
5727
5714
5728 - show changes in the working directory relative to the
5715 - show changes in the working directory relative to the
5729 current directory (see :hg:`help patterns` for more information)::
5716 current directory (see :hg:`help patterns` for more information)::
5730
5717
5731 hg status re:
5718 hg status re:
5732
5719
5733 - show all changes including copies in an existing changeset::
5720 - show all changes including copies in an existing changeset::
5734
5721
5735 hg status --copies --change 9353
5722 hg status --copies --change 9353
5736
5723
5737 - get a NUL separated list of added files, suitable for xargs::
5724 - get a NUL separated list of added files, suitable for xargs::
5738
5725
5739 hg status -an0
5726 hg status -an0
5740
5727
5741 Returns 0 on success.
5728 Returns 0 on success.
5742 """
5729 """
5743
5730
5744 revs = opts.get('rev')
5731 revs = opts.get('rev')
5745 change = opts.get('change')
5732 change = opts.get('change')
5746
5733
5747 if revs and change:
5734 if revs and change:
5748 msg = _('cannot specify --rev and --change at the same time')
5735 msg = _('cannot specify --rev and --change at the same time')
5749 raise error.Abort(msg)
5736 raise error.Abort(msg)
5750 elif change:
5737 elif change:
5751 node2 = scmutil.revsingle(repo, change, None).node()
5738 node2 = scmutil.revsingle(repo, change, None).node()
5752 node1 = repo[node2].p1().node()
5739 node1 = repo[node2].p1().node()
5753 else:
5740 else:
5754 node1, node2 = scmutil.revpair(repo, revs)
5741 node1, node2 = scmutil.revpair(repo, revs)
5755
5742
5756 if pats:
5743 if pats:
5757 cwd = repo.getcwd()
5744 cwd = repo.getcwd()
5758 else:
5745 else:
5759 cwd = ''
5746 cwd = ''
5760
5747
5761 if opts.get('print0'):
5748 if opts.get('print0'):
5762 end = '\0'
5749 end = '\0'
5763 else:
5750 else:
5764 end = '\n'
5751 end = '\n'
5765 copy = {}
5752 copy = {}
5766 states = 'modified added removed deleted unknown ignored clean'.split()
5753 states = 'modified added removed deleted unknown ignored clean'.split()
5767 show = [k for k in states if opts.get(k)]
5754 show = [k for k in states if opts.get(k)]
5768 if opts.get('all'):
5755 if opts.get('all'):
5769 show += ui.quiet and (states[:4] + ['clean']) or states
5756 show += ui.quiet and (states[:4] + ['clean']) or states
5770 if not show:
5757 if not show:
5771 if ui.quiet:
5758 if ui.quiet:
5772 show = states[:4]
5759 show = states[:4]
5773 else:
5760 else:
5774 show = states[:5]
5761 show = states[:5]
5775
5762
5776 m = scmutil.match(repo[node2], pats, opts)
5763 m = scmutil.match(repo[node2], pats, opts)
5777 stat = repo.status(node1, node2, m,
5764 stat = repo.status(node1, node2, m,
5778 'ignored' in show, 'clean' in show, 'unknown' in show,
5765 'ignored' in show, 'clean' in show, 'unknown' in show,
5779 opts.get('subrepos'))
5766 opts.get('subrepos'))
5780 changestates = zip(states, 'MAR!?IC', stat)
5767 changestates = zip(states, 'MAR!?IC', stat)
5781
5768
5782 if (opts.get('all') or opts.get('copies')
5769 if (opts.get('all') or opts.get('copies')
5783 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5770 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5784 copy = copies.pathcopies(repo[node1], repo[node2], m)
5771 copy = copies.pathcopies(repo[node1], repo[node2], m)
5785
5772
5786 fm = ui.formatter('status', opts)
5773 fm = ui.formatter('status', opts)
5787 fmt = '%s' + end
5774 fmt = '%s' + end
5788 showchar = not opts.get('no_status')
5775 showchar = not opts.get('no_status')
5789
5776
5790 for state, char, files in changestates:
5777 for state, char, files in changestates:
5791 if state in show:
5778 if state in show:
5792 label = 'status.' + state
5779 label = 'status.' + state
5793 for f in files:
5780 for f in files:
5794 fm.startitem()
5781 fm.startitem()
5795 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5782 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5796 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5783 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5797 if f in copy:
5784 if f in copy:
5798 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5785 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5799 label='status.copied')
5786 label='status.copied')
5800 fm.end()
5787 fm.end()
5801
5788
5802 @command('^summary|sum',
5789 @command('^summary|sum',
5803 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5790 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5804 def summary(ui, repo, **opts):
5791 def summary(ui, repo, **opts):
5805 """summarize working directory state
5792 """summarize working directory state
5806
5793
5807 This generates a brief summary of the working directory state,
5794 This generates a brief summary of the working directory state,
5808 including parents, branch, commit status, phase and available updates.
5795 including parents, branch, commit status, phase and available updates.
5809
5796
5810 With the --remote option, this will check the default paths for
5797 With the --remote option, this will check the default paths for
5811 incoming and outgoing changes. This can be time-consuming.
5798 incoming and outgoing changes. This can be time-consuming.
5812
5799
5813 Returns 0 on success.
5800 Returns 0 on success.
5814 """
5801 """
5815
5802
5816 ctx = repo[None]
5803 ctx = repo[None]
5817 parents = ctx.parents()
5804 parents = ctx.parents()
5818 pnode = parents[0].node()
5805 pnode = parents[0].node()
5819 marks = []
5806 marks = []
5820
5807
5821 ms = None
5808 ms = None
5822 try:
5809 try:
5823 ms = mergemod.mergestate.read(repo)
5810 ms = mergemod.mergestate.read(repo)
5824 except error.UnsupportedMergeRecords as e:
5811 except error.UnsupportedMergeRecords as e:
5825 s = ' '.join(e.recordtypes)
5812 s = ' '.join(e.recordtypes)
5826 ui.warn(
5813 ui.warn(
5827 _('warning: merge state has unsupported record types: %s\n') % s)
5814 _('warning: merge state has unsupported record types: %s\n') % s)
5828 unresolved = 0
5815 unresolved = 0
5829 else:
5816 else:
5830 unresolved = [f for f in ms if ms[f] == 'u']
5817 unresolved = [f for f in ms if ms[f] == 'u']
5831
5818
5832 for p in parents:
5819 for p in parents:
5833 # label with log.changeset (instead of log.parent) since this
5820 # label with log.changeset (instead of log.parent) since this
5834 # shows a working directory parent *changeset*:
5821 # shows a working directory parent *changeset*:
5835 # i18n: column positioning for "hg summary"
5822 # i18n: column positioning for "hg summary"
5836 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5823 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5837 label=cmdutil._changesetlabels(p))
5824 label=cmdutil._changesetlabels(p))
5838 ui.write(' '.join(p.tags()), label='log.tag')
5825 ui.write(' '.join(p.tags()), label='log.tag')
5839 if p.bookmarks():
5826 if p.bookmarks():
5840 marks.extend(p.bookmarks())
5827 marks.extend(p.bookmarks())
5841 if p.rev() == -1:
5828 if p.rev() == -1:
5842 if not len(repo):
5829 if not len(repo):
5843 ui.write(_(' (empty repository)'))
5830 ui.write(_(' (empty repository)'))
5844 else:
5831 else:
5845 ui.write(_(' (no revision checked out)'))
5832 ui.write(_(' (no revision checked out)'))
5846 if p.troubled():
5833 if p.troubled():
5847 ui.write(' ('
5834 ui.write(' ('
5848 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5835 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5849 for trouble in p.troubles())
5836 for trouble in p.troubles())
5850 + ')')
5837 + ')')
5851 ui.write('\n')
5838 ui.write('\n')
5852 if p.description():
5839 if p.description():
5853 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5840 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5854 label='log.summary')
5841 label='log.summary')
5855
5842
5856 branch = ctx.branch()
5843 branch = ctx.branch()
5857 bheads = repo.branchheads(branch)
5844 bheads = repo.branchheads(branch)
5858 # i18n: column positioning for "hg summary"
5845 # i18n: column positioning for "hg summary"
5859 m = _('branch: %s\n') % branch
5846 m = _('branch: %s\n') % branch
5860 if branch != 'default':
5847 if branch != 'default':
5861 ui.write(m, label='log.branch')
5848 ui.write(m, label='log.branch')
5862 else:
5849 else:
5863 ui.status(m, label='log.branch')
5850 ui.status(m, label='log.branch')
5864
5851
5865 if marks:
5852 if marks:
5866 active = repo._activebookmark
5853 active = repo._activebookmark
5867 # i18n: column positioning for "hg summary"
5854 # i18n: column positioning for "hg summary"
5868 ui.write(_('bookmarks:'), label='log.bookmark')
5855 ui.write(_('bookmarks:'), label='log.bookmark')
5869 if active is not None:
5856 if active is not None:
5870 if active in marks:
5857 if active in marks:
5871 ui.write(' *' + active, label=activebookmarklabel)
5858 ui.write(' *' + active, label=activebookmarklabel)
5872 marks.remove(active)
5859 marks.remove(active)
5873 else:
5860 else:
5874 ui.write(' [%s]' % active, label=activebookmarklabel)
5861 ui.write(' [%s]' % active, label=activebookmarklabel)
5875 for m in marks:
5862 for m in marks:
5876 ui.write(' ' + m, label='log.bookmark')
5863 ui.write(' ' + m, label='log.bookmark')
5877 ui.write('\n', label='log.bookmark')
5864 ui.write('\n', label='log.bookmark')
5878
5865
5879 status = repo.status(unknown=True)
5866 status = repo.status(unknown=True)
5880
5867
5881 c = repo.dirstate.copies()
5868 c = repo.dirstate.copies()
5882 copied, renamed = [], []
5869 copied, renamed = [], []
5883 for d, s in c.iteritems():
5870 for d, s in c.iteritems():
5884 if s in status.removed:
5871 if s in status.removed:
5885 status.removed.remove(s)
5872 status.removed.remove(s)
5886 renamed.append(d)
5873 renamed.append(d)
5887 else:
5874 else:
5888 copied.append(d)
5875 copied.append(d)
5889 if d in status.added:
5876 if d in status.added:
5890 status.added.remove(d)
5877 status.added.remove(d)
5891
5878
5892 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5879 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5893
5880
5894 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5881 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5895 (ui.label(_('%d added'), 'status.added'), status.added),
5882 (ui.label(_('%d added'), 'status.added'), status.added),
5896 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5883 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5897 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5884 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5898 (ui.label(_('%d copied'), 'status.copied'), copied),
5885 (ui.label(_('%d copied'), 'status.copied'), copied),
5899 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5886 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5900 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5887 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5901 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5888 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5902 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5889 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5903 t = []
5890 t = []
5904 for l, s in labels:
5891 for l, s in labels:
5905 if s:
5892 if s:
5906 t.append(l % len(s))
5893 t.append(l % len(s))
5907
5894
5908 t = ', '.join(t)
5895 t = ', '.join(t)
5909 cleanworkdir = False
5896 cleanworkdir = False
5910
5897
5911 if repo.vfs.exists('graftstate'):
5898 if repo.vfs.exists('graftstate'):
5912 t += _(' (graft in progress)')
5899 t += _(' (graft in progress)')
5913 if repo.vfs.exists('updatestate'):
5900 if repo.vfs.exists('updatestate'):
5914 t += _(' (interrupted update)')
5901 t += _(' (interrupted update)')
5915 elif len(parents) > 1:
5902 elif len(parents) > 1:
5916 t += _(' (merge)')
5903 t += _(' (merge)')
5917 elif branch != parents[0].branch():
5904 elif branch != parents[0].branch():
5918 t += _(' (new branch)')
5905 t += _(' (new branch)')
5919 elif (parents[0].closesbranch() and
5906 elif (parents[0].closesbranch() and
5920 pnode in repo.branchheads(branch, closed=True)):
5907 pnode in repo.branchheads(branch, closed=True)):
5921 t += _(' (head closed)')
5908 t += _(' (head closed)')
5922 elif not (status.modified or status.added or status.removed or renamed or
5909 elif not (status.modified or status.added or status.removed or renamed or
5923 copied or subs):
5910 copied or subs):
5924 t += _(' (clean)')
5911 t += _(' (clean)')
5925 cleanworkdir = True
5912 cleanworkdir = True
5926 elif pnode not in bheads:
5913 elif pnode not in bheads:
5927 t += _(' (new branch head)')
5914 t += _(' (new branch head)')
5928
5915
5929 if parents:
5916 if parents:
5930 pendingphase = max(p.phase() for p in parents)
5917 pendingphase = max(p.phase() for p in parents)
5931 else:
5918 else:
5932 pendingphase = phases.public
5919 pendingphase = phases.public
5933
5920
5934 if pendingphase > phases.newcommitphase(ui):
5921 if pendingphase > phases.newcommitphase(ui):
5935 t += ' (%s)' % phases.phasenames[pendingphase]
5922 t += ' (%s)' % phases.phasenames[pendingphase]
5936
5923
5937 if cleanworkdir:
5924 if cleanworkdir:
5938 # i18n: column positioning for "hg summary"
5925 # i18n: column positioning for "hg summary"
5939 ui.status(_('commit: %s\n') % t.strip())
5926 ui.status(_('commit: %s\n') % t.strip())
5940 else:
5927 else:
5941 # i18n: column positioning for "hg summary"
5928 # i18n: column positioning for "hg summary"
5942 ui.write(_('commit: %s\n') % t.strip())
5929 ui.write(_('commit: %s\n') % t.strip())
5943
5930
5944 # all ancestors of branch heads - all ancestors of parent = new csets
5931 # all ancestors of branch heads - all ancestors of parent = new csets
5945 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5932 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5946 bheads))
5933 bheads))
5947
5934
5948 if new == 0:
5935 if new == 0:
5949 # i18n: column positioning for "hg summary"
5936 # i18n: column positioning for "hg summary"
5950 ui.status(_('update: (current)\n'))
5937 ui.status(_('update: (current)\n'))
5951 elif pnode not in bheads:
5938 elif pnode not in bheads:
5952 # i18n: column positioning for "hg summary"
5939 # i18n: column positioning for "hg summary"
5953 ui.write(_('update: %d new changesets (update)\n') % new)
5940 ui.write(_('update: %d new changesets (update)\n') % new)
5954 else:
5941 else:
5955 # i18n: column positioning for "hg summary"
5942 # i18n: column positioning for "hg summary"
5956 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5943 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5957 (new, len(bheads)))
5944 (new, len(bheads)))
5958
5945
5959 t = []
5946 t = []
5960 draft = len(repo.revs('draft()'))
5947 draft = len(repo.revs('draft()'))
5961 if draft:
5948 if draft:
5962 t.append(_('%d draft') % draft)
5949 t.append(_('%d draft') % draft)
5963 secret = len(repo.revs('secret()'))
5950 secret = len(repo.revs('secret()'))
5964 if secret:
5951 if secret:
5965 t.append(_('%d secret') % secret)
5952 t.append(_('%d secret') % secret)
5966
5953
5967 if draft or secret:
5954 if draft or secret:
5968 ui.status(_('phases: %s\n') % ', '.join(t))
5955 ui.status(_('phases: %s\n') % ', '.join(t))
5969
5956
5970 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5957 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5971 for trouble in ("unstable", "divergent", "bumped"):
5958 for trouble in ("unstable", "divergent", "bumped"):
5972 numtrouble = len(repo.revs(trouble + "()"))
5959 numtrouble = len(repo.revs(trouble + "()"))
5973 # We write all the possibilities to ease translation
5960 # We write all the possibilities to ease translation
5974 troublemsg = {
5961 troublemsg = {
5975 "unstable": _("unstable: %d changesets"),
5962 "unstable": _("unstable: %d changesets"),
5976 "divergent": _("divergent: %d changesets"),
5963 "divergent": _("divergent: %d changesets"),
5977 "bumped": _("bumped: %d changesets"),
5964 "bumped": _("bumped: %d changesets"),
5978 }
5965 }
5979 if numtrouble > 0:
5966 if numtrouble > 0:
5980 ui.status(troublemsg[trouble] % numtrouble + "\n")
5967 ui.status(troublemsg[trouble] % numtrouble + "\n")
5981
5968
5982 cmdutil.summaryhooks(ui, repo)
5969 cmdutil.summaryhooks(ui, repo)
5983
5970
5984 if opts.get('remote'):
5971 if opts.get('remote'):
5985 needsincoming, needsoutgoing = True, True
5972 needsincoming, needsoutgoing = True, True
5986 else:
5973 else:
5987 needsincoming, needsoutgoing = False, False
5974 needsincoming, needsoutgoing = False, False
5988 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5975 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5989 if i:
5976 if i:
5990 needsincoming = True
5977 needsincoming = True
5991 if o:
5978 if o:
5992 needsoutgoing = True
5979 needsoutgoing = True
5993 if not needsincoming and not needsoutgoing:
5980 if not needsincoming and not needsoutgoing:
5994 return
5981 return
5995
5982
5996 def getincoming():
5983 def getincoming():
5997 source, branches = hg.parseurl(ui.expandpath('default'))
5984 source, branches = hg.parseurl(ui.expandpath('default'))
5998 sbranch = branches[0]
5985 sbranch = branches[0]
5999 try:
5986 try:
6000 other = hg.peer(repo, {}, source)
5987 other = hg.peer(repo, {}, source)
6001 except error.RepoError:
5988 except error.RepoError:
6002 if opts.get('remote'):
5989 if opts.get('remote'):
6003 raise
5990 raise
6004 return source, sbranch, None, None, None
5991 return source, sbranch, None, None, None
6005 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5992 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6006 if revs:
5993 if revs:
6007 revs = [other.lookup(rev) for rev in revs]
5994 revs = [other.lookup(rev) for rev in revs]
6008 ui.debug('comparing with %s\n' % util.hidepassword(source))
5995 ui.debug('comparing with %s\n' % util.hidepassword(source))
6009 repo.ui.pushbuffer()
5996 repo.ui.pushbuffer()
6010 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5997 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6011 repo.ui.popbuffer()
5998 repo.ui.popbuffer()
6012 return source, sbranch, other, commoninc, commoninc[1]
5999 return source, sbranch, other, commoninc, commoninc[1]
6013
6000
6014 if needsincoming:
6001 if needsincoming:
6015 source, sbranch, sother, commoninc, incoming = getincoming()
6002 source, sbranch, sother, commoninc, incoming = getincoming()
6016 else:
6003 else:
6017 source = sbranch = sother = commoninc = incoming = None
6004 source = sbranch = sother = commoninc = incoming = None
6018
6005
6019 def getoutgoing():
6006 def getoutgoing():
6020 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6007 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6021 dbranch = branches[0]
6008 dbranch = branches[0]
6022 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6009 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6023 if source != dest:
6010 if source != dest:
6024 try:
6011 try:
6025 dother = hg.peer(repo, {}, dest)
6012 dother = hg.peer(repo, {}, dest)
6026 except error.RepoError:
6013 except error.RepoError:
6027 if opts.get('remote'):
6014 if opts.get('remote'):
6028 raise
6015 raise
6029 return dest, dbranch, None, None
6016 return dest, dbranch, None, None
6030 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6017 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6031 elif sother is None:
6018 elif sother is None:
6032 # there is no explicit destination peer, but source one is invalid
6019 # there is no explicit destination peer, but source one is invalid
6033 return dest, dbranch, None, None
6020 return dest, dbranch, None, None
6034 else:
6021 else:
6035 dother = sother
6022 dother = sother
6036 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6023 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6037 common = None
6024 common = None
6038 else:
6025 else:
6039 common = commoninc
6026 common = commoninc
6040 if revs:
6027 if revs:
6041 revs = [repo.lookup(rev) for rev in revs]
6028 revs = [repo.lookup(rev) for rev in revs]
6042 repo.ui.pushbuffer()
6029 repo.ui.pushbuffer()
6043 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6030 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6044 commoninc=common)
6031 commoninc=common)
6045 repo.ui.popbuffer()
6032 repo.ui.popbuffer()
6046 return dest, dbranch, dother, outgoing
6033 return dest, dbranch, dother, outgoing
6047
6034
6048 if needsoutgoing:
6035 if needsoutgoing:
6049 dest, dbranch, dother, outgoing = getoutgoing()
6036 dest, dbranch, dother, outgoing = getoutgoing()
6050 else:
6037 else:
6051 dest = dbranch = dother = outgoing = None
6038 dest = dbranch = dother = outgoing = None
6052
6039
6053 if opts.get('remote'):
6040 if opts.get('remote'):
6054 t = []
6041 t = []
6055 if incoming:
6042 if incoming:
6056 t.append(_('1 or more incoming'))
6043 t.append(_('1 or more incoming'))
6057 o = outgoing.missing
6044 o = outgoing.missing
6058 if o:
6045 if o:
6059 t.append(_('%d outgoing') % len(o))
6046 t.append(_('%d outgoing') % len(o))
6060 other = dother or sother
6047 other = dother or sother
6061 if 'bookmarks' in other.listkeys('namespaces'):
6048 if 'bookmarks' in other.listkeys('namespaces'):
6062 counts = bookmarks.summary(repo, other)
6049 counts = bookmarks.summary(repo, other)
6063 if counts[0] > 0:
6050 if counts[0] > 0:
6064 t.append(_('%d incoming bookmarks') % counts[0])
6051 t.append(_('%d incoming bookmarks') % counts[0])
6065 if counts[1] > 0:
6052 if counts[1] > 0:
6066 t.append(_('%d outgoing bookmarks') % counts[1])
6053 t.append(_('%d outgoing bookmarks') % counts[1])
6067
6054
6068 if t:
6055 if t:
6069 # i18n: column positioning for "hg summary"
6056 # i18n: column positioning for "hg summary"
6070 ui.write(_('remote: %s\n') % (', '.join(t)))
6057 ui.write(_('remote: %s\n') % (', '.join(t)))
6071 else:
6058 else:
6072 # i18n: column positioning for "hg summary"
6059 # i18n: column positioning for "hg summary"
6073 ui.status(_('remote: (synced)\n'))
6060 ui.status(_('remote: (synced)\n'))
6074
6061
6075 cmdutil.summaryremotehooks(ui, repo, opts,
6062 cmdutil.summaryremotehooks(ui, repo, opts,
6076 ((source, sbranch, sother, commoninc),
6063 ((source, sbranch, sother, commoninc),
6077 (dest, dbranch, dother, outgoing)))
6064 (dest, dbranch, dother, outgoing)))
6078
6065
6079 @command('tag',
6066 @command('tag',
6080 [('f', 'force', None, _('force tag')),
6067 [('f', 'force', None, _('force tag')),
6081 ('l', 'local', None, _('make the tag local')),
6068 ('l', 'local', None, _('make the tag local')),
6082 ('r', 'rev', '', _('revision to tag'), _('REV')),
6069 ('r', 'rev', '', _('revision to tag'), _('REV')),
6083 ('', 'remove', None, _('remove a tag')),
6070 ('', 'remove', None, _('remove a tag')),
6084 # -l/--local is already there, commitopts cannot be used
6071 # -l/--local is already there, commitopts cannot be used
6085 ('e', 'edit', None, _('invoke editor on commit messages')),
6072 ('e', 'edit', None, _('invoke editor on commit messages')),
6086 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6073 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6087 ] + commitopts2,
6074 ] + commitopts2,
6088 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6075 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6089 def tag(ui, repo, name1, *names, **opts):
6076 def tag(ui, repo, name1, *names, **opts):
6090 """add one or more tags for the current or given revision
6077 """add one or more tags for the current or given revision
6091
6078
6092 Name a particular revision using <name>.
6079 Name a particular revision using <name>.
6093
6080
6094 Tags are used to name particular revisions of the repository and are
6081 Tags are used to name particular revisions of the repository and are
6095 very useful to compare different revisions, to go back to significant
6082 very useful to compare different revisions, to go back to significant
6096 earlier versions or to mark branch points as releases, etc. Changing
6083 earlier versions or to mark branch points as releases, etc. Changing
6097 an existing tag is normally disallowed; use -f/--force to override.
6084 an existing tag is normally disallowed; use -f/--force to override.
6098
6085
6099 If no revision is given, the parent of the working directory is
6086 If no revision is given, the parent of the working directory is
6100 used.
6087 used.
6101
6088
6102 To facilitate version control, distribution, and merging of tags,
6089 To facilitate version control, distribution, and merging of tags,
6103 they are stored as a file named ".hgtags" which is managed similarly
6090 they are stored as a file named ".hgtags" which is managed similarly
6104 to other project files and can be hand-edited if necessary. This
6091 to other project files and can be hand-edited if necessary. This
6105 also means that tagging creates a new commit. The file
6092 also means that tagging creates a new commit. The file
6106 ".hg/localtags" is used for local tags (not shared among
6093 ".hg/localtags" is used for local tags (not shared among
6107 repositories).
6094 repositories).
6108
6095
6109 Tag commits are usually made at the head of a branch. If the parent
6096 Tag commits are usually made at the head of a branch. If the parent
6110 of the working directory is not a branch head, :hg:`tag` aborts; use
6097 of the working directory is not a branch head, :hg:`tag` aborts; use
6111 -f/--force to force the tag commit to be based on a non-head
6098 -f/--force to force the tag commit to be based on a non-head
6112 changeset.
6099 changeset.
6113
6100
6114 See :hg:`help dates` for a list of formats valid for -d/--date.
6101 See :hg:`help dates` for a list of formats valid for -d/--date.
6115
6102
6116 Since tag names have priority over branch names during revision
6103 Since tag names have priority over branch names during revision
6117 lookup, using an existing branch name as a tag name is discouraged.
6104 lookup, using an existing branch name as a tag name is discouraged.
6118
6105
6119 Returns 0 on success.
6106 Returns 0 on success.
6120 """
6107 """
6121 wlock = lock = None
6108 wlock = lock = None
6122 try:
6109 try:
6123 wlock = repo.wlock()
6110 wlock = repo.wlock()
6124 lock = repo.lock()
6111 lock = repo.lock()
6125 rev_ = "."
6112 rev_ = "."
6126 names = [t.strip() for t in (name1,) + names]
6113 names = [t.strip() for t in (name1,) + names]
6127 if len(names) != len(set(names)):
6114 if len(names) != len(set(names)):
6128 raise error.Abort(_('tag names must be unique'))
6115 raise error.Abort(_('tag names must be unique'))
6129 for n in names:
6116 for n in names:
6130 scmutil.checknewlabel(repo, n, 'tag')
6117 scmutil.checknewlabel(repo, n, 'tag')
6131 if not n:
6118 if not n:
6132 raise error.Abort(_('tag names cannot consist entirely of '
6119 raise error.Abort(_('tag names cannot consist entirely of '
6133 'whitespace'))
6120 'whitespace'))
6134 if opts.get('rev') and opts.get('remove'):
6121 if opts.get('rev') and opts.get('remove'):
6135 raise error.Abort(_("--rev and --remove are incompatible"))
6122 raise error.Abort(_("--rev and --remove are incompatible"))
6136 if opts.get('rev'):
6123 if opts.get('rev'):
6137 rev_ = opts['rev']
6124 rev_ = opts['rev']
6138 message = opts.get('message')
6125 message = opts.get('message')
6139 if opts.get('remove'):
6126 if opts.get('remove'):
6140 if opts.get('local'):
6127 if opts.get('local'):
6141 expectedtype = 'local'
6128 expectedtype = 'local'
6142 else:
6129 else:
6143 expectedtype = 'global'
6130 expectedtype = 'global'
6144
6131
6145 for n in names:
6132 for n in names:
6146 if not repo.tagtype(n):
6133 if not repo.tagtype(n):
6147 raise error.Abort(_("tag '%s' does not exist") % n)
6134 raise error.Abort(_("tag '%s' does not exist") % n)
6148 if repo.tagtype(n) != expectedtype:
6135 if repo.tagtype(n) != expectedtype:
6149 if expectedtype == 'global':
6136 if expectedtype == 'global':
6150 raise error.Abort(_("tag '%s' is not a global tag") % n)
6137 raise error.Abort(_("tag '%s' is not a global tag") % n)
6151 else:
6138 else:
6152 raise error.Abort(_("tag '%s' is not a local tag") % n)
6139 raise error.Abort(_("tag '%s' is not a local tag") % n)
6153 rev_ = 'null'
6140 rev_ = 'null'
6154 if not message:
6141 if not message:
6155 # we don't translate commit messages
6142 # we don't translate commit messages
6156 message = 'Removed tag %s' % ', '.join(names)
6143 message = 'Removed tag %s' % ', '.join(names)
6157 elif not opts.get('force'):
6144 elif not opts.get('force'):
6158 for n in names:
6145 for n in names:
6159 if n in repo.tags():
6146 if n in repo.tags():
6160 raise error.Abort(_("tag '%s' already exists "
6147 raise error.Abort(_("tag '%s' already exists "
6161 "(use -f to force)") % n)
6148 "(use -f to force)") % n)
6162 if not opts.get('local'):
6149 if not opts.get('local'):
6163 p1, p2 = repo.dirstate.parents()
6150 p1, p2 = repo.dirstate.parents()
6164 if p2 != nullid:
6151 if p2 != nullid:
6165 raise error.Abort(_('uncommitted merge'))
6152 raise error.Abort(_('uncommitted merge'))
6166 bheads = repo.branchheads()
6153 bheads = repo.branchheads()
6167 if not opts.get('force') and bheads and p1 not in bheads:
6154 if not opts.get('force') and bheads and p1 not in bheads:
6168 raise error.Abort(_('working directory is not at a branch head '
6155 raise error.Abort(_('working directory is not at a branch head '
6169 '(use -f to force)'))
6156 '(use -f to force)'))
6170 r = scmutil.revsingle(repo, rev_).node()
6157 r = scmutil.revsingle(repo, rev_).node()
6171
6158
6172 if not message:
6159 if not message:
6173 # we don't translate commit messages
6160 # we don't translate commit messages
6174 message = ('Added tag %s for changeset %s' %
6161 message = ('Added tag %s for changeset %s' %
6175 (', '.join(names), short(r)))
6162 (', '.join(names), short(r)))
6176
6163
6177 date = opts.get('date')
6164 date = opts.get('date')
6178 if date:
6165 if date:
6179 date = util.parsedate(date)
6166 date = util.parsedate(date)
6180
6167
6181 if opts.get('remove'):
6168 if opts.get('remove'):
6182 editform = 'tag.remove'
6169 editform = 'tag.remove'
6183 else:
6170 else:
6184 editform = 'tag.add'
6171 editform = 'tag.add'
6185 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6172 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6186
6173
6187 # don't allow tagging the null rev
6174 # don't allow tagging the null rev
6188 if (not opts.get('remove') and
6175 if (not opts.get('remove') and
6189 scmutil.revsingle(repo, rev_).rev() == nullrev):
6176 scmutil.revsingle(repo, rev_).rev() == nullrev):
6190 raise error.Abort(_("cannot tag null revision"))
6177 raise error.Abort(_("cannot tag null revision"))
6191
6178
6192 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6179 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6193 editor=editor)
6180 editor=editor)
6194 finally:
6181 finally:
6195 release(lock, wlock)
6182 release(lock, wlock)
6196
6183
6197 @command('tags', formatteropts, '')
6184 @command('tags', formatteropts, '')
6198 def tags(ui, repo, **opts):
6185 def tags(ui, repo, **opts):
6199 """list repository tags
6186 """list repository tags
6200
6187
6201 This lists both regular and local tags. When the -v/--verbose
6188 This lists both regular and local tags. When the -v/--verbose
6202 switch is used, a third column "local" is printed for local tags.
6189 switch is used, a third column "local" is printed for local tags.
6203 When the -q/--quiet switch is used, only the tag name is printed.
6190 When the -q/--quiet switch is used, only the tag name is printed.
6204
6191
6205 Returns 0 on success.
6192 Returns 0 on success.
6206 """
6193 """
6207
6194
6208 fm = ui.formatter('tags', opts)
6195 fm = ui.formatter('tags', opts)
6209 hexfunc = fm.hexfunc
6196 hexfunc = fm.hexfunc
6210 tagtype = ""
6197 tagtype = ""
6211
6198
6212 for t, n in reversed(repo.tagslist()):
6199 for t, n in reversed(repo.tagslist()):
6213 hn = hexfunc(n)
6200 hn = hexfunc(n)
6214 label = 'tags.normal'
6201 label = 'tags.normal'
6215 tagtype = ''
6202 tagtype = ''
6216 if repo.tagtype(t) == 'local':
6203 if repo.tagtype(t) == 'local':
6217 label = 'tags.local'
6204 label = 'tags.local'
6218 tagtype = 'local'
6205 tagtype = 'local'
6219
6206
6220 fm.startitem()
6207 fm.startitem()
6221 fm.write('tag', '%s', t, label=label)
6208 fm.write('tag', '%s', t, label=label)
6222 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6209 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6223 fm.condwrite(not ui.quiet, 'rev node', fmt,
6210 fm.condwrite(not ui.quiet, 'rev node', fmt,
6224 repo.changelog.rev(n), hn, label=label)
6211 repo.changelog.rev(n), hn, label=label)
6225 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6212 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6226 tagtype, label=label)
6213 tagtype, label=label)
6227 fm.plain('\n')
6214 fm.plain('\n')
6228 fm.end()
6215 fm.end()
6229
6216
6230 @command('tip',
6217 @command('tip',
6231 [('p', 'patch', None, _('show patch')),
6218 [('p', 'patch', None, _('show patch')),
6232 ('g', 'git', None, _('use git extended diff format')),
6219 ('g', 'git', None, _('use git extended diff format')),
6233 ] + templateopts,
6220 ] + templateopts,
6234 _('[-p] [-g]'))
6221 _('[-p] [-g]'))
6235 def tip(ui, repo, **opts):
6222 def tip(ui, repo, **opts):
6236 """show the tip revision (DEPRECATED)
6223 """show the tip revision (DEPRECATED)
6237
6224
6238 The tip revision (usually just called the tip) is the changeset
6225 The tip revision (usually just called the tip) is the changeset
6239 most recently added to the repository (and therefore the most
6226 most recently added to the repository (and therefore the most
6240 recently changed head).
6227 recently changed head).
6241
6228
6242 If you have just made a commit, that commit will be the tip. If
6229 If you have just made a commit, that commit will be the tip. If
6243 you have just pulled changes from another repository, the tip of
6230 you have just pulled changes from another repository, the tip of
6244 that repository becomes the current tip. The "tip" tag is special
6231 that repository becomes the current tip. The "tip" tag is special
6245 and cannot be renamed or assigned to a different changeset.
6232 and cannot be renamed or assigned to a different changeset.
6246
6233
6247 This command is deprecated, please use :hg:`heads` instead.
6234 This command is deprecated, please use :hg:`heads` instead.
6248
6235
6249 Returns 0 on success.
6236 Returns 0 on success.
6250 """
6237 """
6251 displayer = cmdutil.show_changeset(ui, repo, opts)
6238 displayer = cmdutil.show_changeset(ui, repo, opts)
6252 displayer.show(repo['tip'])
6239 displayer.show(repo['tip'])
6253 displayer.close()
6240 displayer.close()
6254
6241
6255 @command('unbundle',
6242 @command('unbundle',
6256 [('u', 'update', None,
6243 [('u', 'update', None,
6257 _('update to new branch head if changesets were unbundled'))],
6244 _('update to new branch head if changesets were unbundled'))],
6258 _('[-u] FILE...'))
6245 _('[-u] FILE...'))
6259 def unbundle(ui, repo, fname1, *fnames, **opts):
6246 def unbundle(ui, repo, fname1, *fnames, **opts):
6260 """apply one or more changegroup files
6247 """apply one or more changegroup files
6261
6248
6262 Apply one or more compressed changegroup files generated by the
6249 Apply one or more compressed changegroup files generated by the
6263 bundle command.
6250 bundle command.
6264
6251
6265 Returns 0 on success, 1 if an update has unresolved files.
6252 Returns 0 on success, 1 if an update has unresolved files.
6266 """
6253 """
6267 fnames = (fname1,) + fnames
6254 fnames = (fname1,) + fnames
6268
6255
6269 with repo.lock():
6256 with repo.lock():
6270 for fname in fnames:
6257 for fname in fnames:
6271 f = hg.openpath(ui, fname)
6258 f = hg.openpath(ui, fname)
6272 gen = exchange.readbundle(ui, f, fname)
6259 gen = exchange.readbundle(ui, f, fname)
6273 if isinstance(gen, bundle2.unbundle20):
6260 if isinstance(gen, bundle2.unbundle20):
6274 tr = repo.transaction('unbundle')
6261 tr = repo.transaction('unbundle')
6275 try:
6262 try:
6276 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6263 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6277 url='bundle:' + fname)
6264 url='bundle:' + fname)
6278 tr.close()
6265 tr.close()
6279 except error.BundleUnknownFeatureError as exc:
6266 except error.BundleUnknownFeatureError as exc:
6280 raise error.Abort(_('%s: unknown bundle feature, %s')
6267 raise error.Abort(_('%s: unknown bundle feature, %s')
6281 % (fname, exc),
6268 % (fname, exc),
6282 hint=_("see https://mercurial-scm.org/"
6269 hint=_("see https://mercurial-scm.org/"
6283 "wiki/BundleFeature for more "
6270 "wiki/BundleFeature for more "
6284 "information"))
6271 "information"))
6285 finally:
6272 finally:
6286 if tr:
6273 if tr:
6287 tr.release()
6274 tr.release()
6288 changes = [r.get('return', 0)
6275 changes = [r.get('return', 0)
6289 for r in op.records['changegroup']]
6276 for r in op.records['changegroup']]
6290 modheads = changegroup.combineresults(changes)
6277 modheads = changegroup.combineresults(changes)
6291 elif isinstance(gen, streamclone.streamcloneapplier):
6278 elif isinstance(gen, streamclone.streamcloneapplier):
6292 raise error.Abort(
6279 raise error.Abort(
6293 _('packed bundles cannot be applied with '
6280 _('packed bundles cannot be applied with '
6294 '"hg unbundle"'),
6281 '"hg unbundle"'),
6295 hint=_('use "hg debugapplystreamclonebundle"'))
6282 hint=_('use "hg debugapplystreamclonebundle"'))
6296 else:
6283 else:
6297 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6284 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6298
6285
6299 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6286 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6300
6287
6301 @command('^update|up|checkout|co',
6288 @command('^update|up|checkout|co',
6302 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6289 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6303 ('c', 'check', None, _('require clean working directory')),
6290 ('c', 'check', None, _('require clean working directory')),
6304 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6291 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6305 ('r', 'rev', '', _('revision'), _('REV'))
6292 ('r', 'rev', '', _('revision'), _('REV'))
6306 ] + mergetoolopts,
6293 ] + mergetoolopts,
6307 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6294 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6308 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6295 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6309 tool=None):
6296 tool=None):
6310 """update working directory (or switch revisions)
6297 """update working directory (or switch revisions)
6311
6298
6312 Update the repository's working directory to the specified
6299 Update the repository's working directory to the specified
6313 changeset. If no changeset is specified, update to the tip of the
6300 changeset. If no changeset is specified, update to the tip of the
6314 current named branch and move the active bookmark (see :hg:`help
6301 current named branch and move the active bookmark (see :hg:`help
6315 bookmarks`).
6302 bookmarks`).
6316
6303
6317 Update sets the working directory's parent revision to the specified
6304 Update sets the working directory's parent revision to the specified
6318 changeset (see :hg:`help parents`).
6305 changeset (see :hg:`help parents`).
6319
6306
6320 If the changeset is not a descendant or ancestor of the working
6307 If the changeset is not a descendant or ancestor of the working
6321 directory's parent and there are uncommitted changes, the update is
6308 directory's parent and there are uncommitted changes, the update is
6322 aborted. With the -c/--check option, the working directory is checked
6309 aborted. With the -c/--check option, the working directory is checked
6323 for uncommitted changes; if none are found, the working directory is
6310 for uncommitted changes; if none are found, the working directory is
6324 updated to the specified changeset.
6311 updated to the specified changeset.
6325
6312
6326 .. container:: verbose
6313 .. container:: verbose
6327
6314
6328 The following rules apply when the working directory contains
6315 The following rules apply when the working directory contains
6329 uncommitted changes:
6316 uncommitted changes:
6330
6317
6331 1. If neither -c/--check nor -C/--clean is specified, and if
6318 1. If neither -c/--check nor -C/--clean is specified, and if
6332 the requested changeset is an ancestor or descendant of
6319 the requested changeset is an ancestor or descendant of
6333 the working directory's parent, the uncommitted changes
6320 the working directory's parent, the uncommitted changes
6334 are merged into the requested changeset and the merged
6321 are merged into the requested changeset and the merged
6335 result is left uncommitted. If the requested changeset is
6322 result is left uncommitted. If the requested changeset is
6336 not an ancestor or descendant (that is, it is on another
6323 not an ancestor or descendant (that is, it is on another
6337 branch), the update is aborted and the uncommitted changes
6324 branch), the update is aborted and the uncommitted changes
6338 are preserved.
6325 are preserved.
6339
6326
6340 2. With the -c/--check option, the update is aborted and the
6327 2. With the -c/--check option, the update is aborted and the
6341 uncommitted changes are preserved.
6328 uncommitted changes are preserved.
6342
6329
6343 3. With the -C/--clean option, uncommitted changes are discarded and
6330 3. With the -C/--clean option, uncommitted changes are discarded and
6344 the working directory is updated to the requested changeset.
6331 the working directory is updated to the requested changeset.
6345
6332
6346 To cancel an uncommitted merge (and lose your changes), use
6333 To cancel an uncommitted merge (and lose your changes), use
6347 :hg:`update --clean .`.
6334 :hg:`update --clean .`.
6348
6335
6349 Use null as the changeset to remove the working directory (like
6336 Use null as the changeset to remove the working directory (like
6350 :hg:`clone -U`).
6337 :hg:`clone -U`).
6351
6338
6352 If you want to revert just one file to an older revision, use
6339 If you want to revert just one file to an older revision, use
6353 :hg:`revert [-r REV] NAME`.
6340 :hg:`revert [-r REV] NAME`.
6354
6341
6355 See :hg:`help dates` for a list of formats valid for -d/--date.
6342 See :hg:`help dates` for a list of formats valid for -d/--date.
6356
6343
6357 Returns 0 on success, 1 if there are unresolved files.
6344 Returns 0 on success, 1 if there are unresolved files.
6358 """
6345 """
6359 if rev and node:
6346 if rev and node:
6360 raise error.Abort(_("please specify just one revision"))
6347 raise error.Abort(_("please specify just one revision"))
6361
6348
6362 if rev is None or rev == '':
6349 if rev is None or rev == '':
6363 rev = node
6350 rev = node
6364
6351
6365 if date and rev is not None:
6352 if date and rev is not None:
6366 raise error.Abort(_("you can't specify a revision and a date"))
6353 raise error.Abort(_("you can't specify a revision and a date"))
6367
6354
6368 if check and clean:
6355 if check and clean:
6369 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6356 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6370
6357
6371 with repo.wlock():
6358 with repo.wlock():
6372 cmdutil.clearunfinished(repo)
6359 cmdutil.clearunfinished(repo)
6373
6360
6374 if date:
6361 if date:
6375 rev = cmdutil.finddate(ui, repo, date)
6362 rev = cmdutil.finddate(ui, repo, date)
6376
6363
6377 # if we defined a bookmark, we have to remember the original name
6364 # if we defined a bookmark, we have to remember the original name
6378 brev = rev
6365 brev = rev
6379 rev = scmutil.revsingle(repo, rev, rev).rev()
6366 rev = scmutil.revsingle(repo, rev, rev).rev()
6380
6367
6381 if check:
6368 if check:
6382 cmdutil.bailifchanged(repo, merge=False)
6369 cmdutil.bailifchanged(repo, merge=False)
6383
6370
6384 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6371 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6385
6372
6386 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6373 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6387
6374
6388 @command('verify', [])
6375 @command('verify', [])
6389 def verify(ui, repo):
6376 def verify(ui, repo):
6390 """verify the integrity of the repository
6377 """verify the integrity of the repository
6391
6378
6392 Verify the integrity of the current repository.
6379 Verify the integrity of the current repository.
6393
6380
6394 This will perform an extensive check of the repository's
6381 This will perform an extensive check of the repository's
6395 integrity, validating the hashes and checksums of each entry in
6382 integrity, validating the hashes and checksums of each entry in
6396 the changelog, manifest, and tracked files, as well as the
6383 the changelog, manifest, and tracked files, as well as the
6397 integrity of their crosslinks and indices.
6384 integrity of their crosslinks and indices.
6398
6385
6399 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6386 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6400 for more information about recovery from corruption of the
6387 for more information about recovery from corruption of the
6401 repository.
6388 repository.
6402
6389
6403 Returns 0 on success, 1 if errors are encountered.
6390 Returns 0 on success, 1 if errors are encountered.
6404 """
6391 """
6405 return hg.verify(repo)
6392 return hg.verify(repo)
6406
6393
6407 @command('version', [] + formatteropts, norepo=True)
6394 @command('version', [] + formatteropts, norepo=True)
6408 def version_(ui, **opts):
6395 def version_(ui, **opts):
6409 """output version and copyright information"""
6396 """output version and copyright information"""
6410 fm = ui.formatter("version", opts)
6397 fm = ui.formatter("version", opts)
6411 fm.startitem()
6398 fm.startitem()
6412 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6399 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6413 util.version())
6400 util.version())
6414 license = _(
6401 license = _(
6415 "(see https://mercurial-scm.org for more information)\n"
6402 "(see https://mercurial-scm.org for more information)\n"
6416 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6403 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
6417 "This is free software; see the source for copying conditions. "
6404 "This is free software; see the source for copying conditions. "
6418 "There is NO\nwarranty; "
6405 "There is NO\nwarranty; "
6419 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6406 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6420 )
6407 )
6421 if not ui.quiet:
6408 if not ui.quiet:
6422 fm.plain(license)
6409 fm.plain(license)
6423
6410
6424 if ui.verbose:
6411 if ui.verbose:
6425 fm.plain(_("\nEnabled extensions:\n\n"))
6412 fm.plain(_("\nEnabled extensions:\n\n"))
6426 # format names and versions into columns
6413 # format names and versions into columns
6427 names = []
6414 names = []
6428 vers = []
6415 vers = []
6429 isinternals = []
6416 isinternals = []
6430 for name, module in extensions.extensions():
6417 for name, module in extensions.extensions():
6431 names.append(name)
6418 names.append(name)
6432 vers.append(extensions.moduleversion(module) or None)
6419 vers.append(extensions.moduleversion(module) or None)
6433 isinternals.append(extensions.ismoduleinternal(module))
6420 isinternals.append(extensions.ismoduleinternal(module))
6434 fn = fm.nested("extensions")
6421 fn = fm.nested("extensions")
6435 if names:
6422 if names:
6436 namefmt = " %%-%ds " % max(len(n) for n in names)
6423 namefmt = " %%-%ds " % max(len(n) for n in names)
6437 places = [_("external"), _("internal")]
6424 places = [_("external"), _("internal")]
6438 for n, v, p in zip(names, vers, isinternals):
6425 for n, v, p in zip(names, vers, isinternals):
6439 fn.startitem()
6426 fn.startitem()
6440 fn.condwrite(ui.verbose, "name", namefmt, n)
6427 fn.condwrite(ui.verbose, "name", namefmt, n)
6441 if ui.verbose:
6428 if ui.verbose:
6442 fn.plain("%s " % places[p])
6429 fn.plain("%s " % places[p])
6443 fn.data(bundled=p)
6430 fn.data(bundled=p)
6444 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6431 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6445 if ui.verbose:
6432 if ui.verbose:
6446 fn.plain("\n")
6433 fn.plain("\n")
6447 fn.end()
6434 fn.end()
6448 fm.end()
6435 fm.end()
6449
6436
6450 def loadcmdtable(ui, name, cmdtable):
6437 def loadcmdtable(ui, name, cmdtable):
6451 """Load command functions from specified cmdtable
6438 """Load command functions from specified cmdtable
6452 """
6439 """
6453 overrides = [cmd for cmd in cmdtable if cmd in table]
6440 overrides = [cmd for cmd in cmdtable if cmd in table]
6454 if overrides:
6441 if overrides:
6455 ui.warn(_("extension '%s' overrides commands: %s\n")
6442 ui.warn(_("extension '%s' overrides commands: %s\n")
6456 % (name, " ".join(overrides)))
6443 % (name, " ".join(overrides)))
6457 table.update(cmdtable)
6444 table.update(cmdtable)
@@ -1,1049 +1,1062
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 operator
10 import operator
11 import os
11 import os
12 import random
12 import random
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 bin,
18 bin,
19 hex,
19 hex,
20 nullid,
20 nullid,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 bundle2,
24 bundle2,
25 changegroup,
25 changegroup,
26 cmdutil,
26 cmdutil,
27 commands,
27 commands,
28 context,
28 context,
29 dagparser,
29 dagparser,
30 dagutil,
30 dagutil,
31 encoding,
31 encoding,
32 error,
32 error,
33 exchange,
33 exchange,
34 extensions,
34 extensions,
35 fileset,
35 fileset,
36 hg,
36 hg,
37 localrepo,
37 localrepo,
38 lock as lockmod,
38 lock as lockmod,
39 policy,
39 policy,
40 pycompat,
40 pycompat,
41 repair,
41 repair,
42 revlog,
42 revlog,
43 scmutil,
43 scmutil,
44 setdiscovery,
44 setdiscovery,
45 simplemerge,
45 simplemerge,
46 sslutil,
46 sslutil,
47 streamclone,
47 streamclone,
48 templater,
48 templater,
49 treediscovery,
49 treediscovery,
50 util,
50 util,
51 )
51 )
52
52
53 release = lockmod.release
53 release = lockmod.release
54
54
55 # We reuse the command table from commands because it is easier than
55 # We reuse the command table from commands because it is easier than
56 # teaching dispatch about multiple tables.
56 # teaching dispatch about multiple tables.
57 command = cmdutil.command(commands.table)
57 command = cmdutil.command(commands.table)
58
58
59 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
59 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
60 def debugancestor(ui, repo, *args):
60 def debugancestor(ui, repo, *args):
61 """find the ancestor revision of two revisions in a given index"""
61 """find the ancestor revision of two revisions in a given index"""
62 if len(args) == 3:
62 if len(args) == 3:
63 index, rev1, rev2 = args
63 index, rev1, rev2 = args
64 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
64 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
65 lookup = r.lookup
65 lookup = r.lookup
66 elif len(args) == 2:
66 elif len(args) == 2:
67 if not repo:
67 if not repo:
68 raise error.Abort(_('there is no Mercurial repository here '
68 raise error.Abort(_('there is no Mercurial repository here '
69 '(.hg not found)'))
69 '(.hg not found)'))
70 rev1, rev2 = args
70 rev1, rev2 = args
71 r = repo.changelog
71 r = repo.changelog
72 lookup = repo.lookup
72 lookup = repo.lookup
73 else:
73 else:
74 raise error.Abort(_('either two or three arguments required'))
74 raise error.Abort(_('either two or three arguments required'))
75 a = r.ancestor(lookup(rev1), lookup(rev2))
75 a = r.ancestor(lookup(rev1), lookup(rev2))
76 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
76 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
77
77
78 @command('debugapplystreamclonebundle', [], 'FILE')
78 @command('debugapplystreamclonebundle', [], 'FILE')
79 def debugapplystreamclonebundle(ui, repo, fname):
79 def debugapplystreamclonebundle(ui, repo, fname):
80 """apply a stream clone bundle file"""
80 """apply a stream clone bundle file"""
81 f = hg.openpath(ui, fname)
81 f = hg.openpath(ui, fname)
82 gen = exchange.readbundle(ui, f, fname)
82 gen = exchange.readbundle(ui, f, fname)
83 gen.apply(repo)
83 gen.apply(repo)
84
84
85 @command('debugbuilddag',
85 @command('debugbuilddag',
86 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
86 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
87 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
87 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
88 ('n', 'new-file', None, _('add new file at each rev'))],
88 ('n', 'new-file', None, _('add new file at each rev'))],
89 _('[OPTION]... [TEXT]'))
89 _('[OPTION]... [TEXT]'))
90 def debugbuilddag(ui, repo, text=None,
90 def debugbuilddag(ui, repo, text=None,
91 mergeable_file=False,
91 mergeable_file=False,
92 overwritten_file=False,
92 overwritten_file=False,
93 new_file=False):
93 new_file=False):
94 """builds a repo with a given DAG from scratch in the current empty repo
94 """builds a repo with a given DAG from scratch in the current empty repo
95
95
96 The description of the DAG is read from stdin if not given on the
96 The description of the DAG is read from stdin if not given on the
97 command line.
97 command line.
98
98
99 Elements:
99 Elements:
100
100
101 - "+n" is a linear run of n nodes based on the current default parent
101 - "+n" is a linear run of n nodes based on the current default parent
102 - "." is a single node based on the current default parent
102 - "." is a single node based on the current default parent
103 - "$" resets the default parent to null (implied at the start);
103 - "$" resets the default parent to null (implied at the start);
104 otherwise the default parent is always the last node created
104 otherwise the default parent is always the last node created
105 - "<p" sets the default parent to the backref p
105 - "<p" sets the default parent to the backref p
106 - "*p" is a fork at parent p, which is a backref
106 - "*p" is a fork at parent p, which is a backref
107 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
107 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
108 - "/p2" is a merge of the preceding node and p2
108 - "/p2" is a merge of the preceding node and p2
109 - ":tag" defines a local tag for the preceding node
109 - ":tag" defines a local tag for the preceding node
110 - "@branch" sets the named branch for subsequent nodes
110 - "@branch" sets the named branch for subsequent nodes
111 - "#...\\n" is a comment up to the end of the line
111 - "#...\\n" is a comment up to the end of the line
112
112
113 Whitespace between the above elements is ignored.
113 Whitespace between the above elements is ignored.
114
114
115 A backref is either
115 A backref is either
116
116
117 - a number n, which references the node curr-n, where curr is the current
117 - a number n, which references the node curr-n, where curr is the current
118 node, or
118 node, or
119 - the name of a local tag you placed earlier using ":tag", or
119 - the name of a local tag you placed earlier using ":tag", or
120 - empty to denote the default parent.
120 - empty to denote the default parent.
121
121
122 All string valued-elements are either strictly alphanumeric, or must
122 All string valued-elements are either strictly alphanumeric, or must
123 be enclosed in double quotes ("..."), with "\\" as escape character.
123 be enclosed in double quotes ("..."), with "\\" as escape character.
124 """
124 """
125
125
126 if text is None:
126 if text is None:
127 ui.status(_("reading DAG from stdin\n"))
127 ui.status(_("reading DAG from stdin\n"))
128 text = ui.fin.read()
128 text = ui.fin.read()
129
129
130 cl = repo.changelog
130 cl = repo.changelog
131 if len(cl) > 0:
131 if len(cl) > 0:
132 raise error.Abort(_('repository is not empty'))
132 raise error.Abort(_('repository is not empty'))
133
133
134 # determine number of revs in DAG
134 # determine number of revs in DAG
135 total = 0
135 total = 0
136 for type, data in dagparser.parsedag(text):
136 for type, data in dagparser.parsedag(text):
137 if type == 'n':
137 if type == 'n':
138 total += 1
138 total += 1
139
139
140 if mergeable_file:
140 if mergeable_file:
141 linesperrev = 2
141 linesperrev = 2
142 # make a file with k lines per rev
142 # make a file with k lines per rev
143 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
143 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
144 initialmergedlines.append("")
144 initialmergedlines.append("")
145
145
146 tags = []
146 tags = []
147
147
148 wlock = lock = tr = None
148 wlock = lock = tr = None
149 try:
149 try:
150 wlock = repo.wlock()
150 wlock = repo.wlock()
151 lock = repo.lock()
151 lock = repo.lock()
152 tr = repo.transaction("builddag")
152 tr = repo.transaction("builddag")
153
153
154 at = -1
154 at = -1
155 atbranch = 'default'
155 atbranch = 'default'
156 nodeids = []
156 nodeids = []
157 id = 0
157 id = 0
158 ui.progress(_('building'), id, unit=_('revisions'), total=total)
158 ui.progress(_('building'), id, unit=_('revisions'), total=total)
159 for type, data in dagparser.parsedag(text):
159 for type, data in dagparser.parsedag(text):
160 if type == 'n':
160 if type == 'n':
161 ui.note(('node %s\n' % str(data)))
161 ui.note(('node %s\n' % str(data)))
162 id, ps = data
162 id, ps = data
163
163
164 files = []
164 files = []
165 fctxs = {}
165 fctxs = {}
166
166
167 p2 = None
167 p2 = None
168 if mergeable_file:
168 if mergeable_file:
169 fn = "mf"
169 fn = "mf"
170 p1 = repo[ps[0]]
170 p1 = repo[ps[0]]
171 if len(ps) > 1:
171 if len(ps) > 1:
172 p2 = repo[ps[1]]
172 p2 = repo[ps[1]]
173 pa = p1.ancestor(p2)
173 pa = p1.ancestor(p2)
174 base, local, other = [x[fn].data() for x in (pa, p1,
174 base, local, other = [x[fn].data() for x in (pa, p1,
175 p2)]
175 p2)]
176 m3 = simplemerge.Merge3Text(base, local, other)
176 m3 = simplemerge.Merge3Text(base, local, other)
177 ml = [l.strip() for l in m3.merge_lines()]
177 ml = [l.strip() for l in m3.merge_lines()]
178 ml.append("")
178 ml.append("")
179 elif at > 0:
179 elif at > 0:
180 ml = p1[fn].data().split("\n")
180 ml = p1[fn].data().split("\n")
181 else:
181 else:
182 ml = initialmergedlines
182 ml = initialmergedlines
183 ml[id * linesperrev] += " r%i" % id
183 ml[id * linesperrev] += " r%i" % id
184 mergedtext = "\n".join(ml)
184 mergedtext = "\n".join(ml)
185 files.append(fn)
185 files.append(fn)
186 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
186 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
187
187
188 if overwritten_file:
188 if overwritten_file:
189 fn = "of"
189 fn = "of"
190 files.append(fn)
190 files.append(fn)
191 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
191 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
192
192
193 if new_file:
193 if new_file:
194 fn = "nf%i" % id
194 fn = "nf%i" % id
195 files.append(fn)
195 files.append(fn)
196 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
196 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
197 if len(ps) > 1:
197 if len(ps) > 1:
198 if not p2:
198 if not p2:
199 p2 = repo[ps[1]]
199 p2 = repo[ps[1]]
200 for fn in p2:
200 for fn in p2:
201 if fn.startswith("nf"):
201 if fn.startswith("nf"):
202 files.append(fn)
202 files.append(fn)
203 fctxs[fn] = p2[fn]
203 fctxs[fn] = p2[fn]
204
204
205 def fctxfn(repo, cx, path):
205 def fctxfn(repo, cx, path):
206 return fctxs.get(path)
206 return fctxs.get(path)
207
207
208 if len(ps) == 0 or ps[0] < 0:
208 if len(ps) == 0 or ps[0] < 0:
209 pars = [None, None]
209 pars = [None, None]
210 elif len(ps) == 1:
210 elif len(ps) == 1:
211 pars = [nodeids[ps[0]], None]
211 pars = [nodeids[ps[0]], None]
212 else:
212 else:
213 pars = [nodeids[p] for p in ps]
213 pars = [nodeids[p] for p in ps]
214 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
214 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
215 date=(id, 0),
215 date=(id, 0),
216 user="debugbuilddag",
216 user="debugbuilddag",
217 extra={'branch': atbranch})
217 extra={'branch': atbranch})
218 nodeid = repo.commitctx(cx)
218 nodeid = repo.commitctx(cx)
219 nodeids.append(nodeid)
219 nodeids.append(nodeid)
220 at = id
220 at = id
221 elif type == 'l':
221 elif type == 'l':
222 id, name = data
222 id, name = data
223 ui.note(('tag %s\n' % name))
223 ui.note(('tag %s\n' % name))
224 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
224 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
225 elif type == 'a':
225 elif type == 'a':
226 ui.note(('branch %s\n' % data))
226 ui.note(('branch %s\n' % data))
227 atbranch = data
227 atbranch = data
228 ui.progress(_('building'), id, unit=_('revisions'), total=total)
228 ui.progress(_('building'), id, unit=_('revisions'), total=total)
229 tr.close()
229 tr.close()
230
230
231 if tags:
231 if tags:
232 repo.vfs.write("localtags", "".join(tags))
232 repo.vfs.write("localtags", "".join(tags))
233 finally:
233 finally:
234 ui.progress(_('building'), None)
234 ui.progress(_('building'), None)
235 release(tr, lock, wlock)
235 release(tr, lock, wlock)
236
236
237 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
237 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
238 indent_string = ' ' * indent
238 indent_string = ' ' * indent
239 if all:
239 if all:
240 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
240 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
241 % indent_string)
241 % indent_string)
242
242
243 def showchunks(named):
243 def showchunks(named):
244 ui.write("\n%s%s\n" % (indent_string, named))
244 ui.write("\n%s%s\n" % (indent_string, named))
245 chain = None
245 chain = None
246 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
246 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
247 node = chunkdata['node']
247 node = chunkdata['node']
248 p1 = chunkdata['p1']
248 p1 = chunkdata['p1']
249 p2 = chunkdata['p2']
249 p2 = chunkdata['p2']
250 cs = chunkdata['cs']
250 cs = chunkdata['cs']
251 deltabase = chunkdata['deltabase']
251 deltabase = chunkdata['deltabase']
252 delta = chunkdata['delta']
252 delta = chunkdata['delta']
253 ui.write("%s%s %s %s %s %s %s\n" %
253 ui.write("%s%s %s %s %s %s %s\n" %
254 (indent_string, hex(node), hex(p1), hex(p2),
254 (indent_string, hex(node), hex(p1), hex(p2),
255 hex(cs), hex(deltabase), len(delta)))
255 hex(cs), hex(deltabase), len(delta)))
256 chain = node
256 chain = node
257
257
258 chunkdata = gen.changelogheader()
258 chunkdata = gen.changelogheader()
259 showchunks("changelog")
259 showchunks("changelog")
260 chunkdata = gen.manifestheader()
260 chunkdata = gen.manifestheader()
261 showchunks("manifest")
261 showchunks("manifest")
262 for chunkdata in iter(gen.filelogheader, {}):
262 for chunkdata in iter(gen.filelogheader, {}):
263 fname = chunkdata['filename']
263 fname = chunkdata['filename']
264 showchunks(fname)
264 showchunks(fname)
265 else:
265 else:
266 if isinstance(gen, bundle2.unbundle20):
266 if isinstance(gen, bundle2.unbundle20):
267 raise error.Abort(_('use debugbundle2 for this file'))
267 raise error.Abort(_('use debugbundle2 for this file'))
268 chunkdata = gen.changelogheader()
268 chunkdata = gen.changelogheader()
269 chain = None
269 chain = None
270 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
270 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
271 node = chunkdata['node']
271 node = chunkdata['node']
272 ui.write("%s%s\n" % (indent_string, hex(node)))
272 ui.write("%s%s\n" % (indent_string, hex(node)))
273 chain = node
273 chain = node
274
274
275 def _debugbundle2(ui, gen, all=None, **opts):
275 def _debugbundle2(ui, gen, all=None, **opts):
276 """lists the contents of a bundle2"""
276 """lists the contents of a bundle2"""
277 if not isinstance(gen, bundle2.unbundle20):
277 if not isinstance(gen, bundle2.unbundle20):
278 raise error.Abort(_('not a bundle2 file'))
278 raise error.Abort(_('not a bundle2 file'))
279 ui.write(('Stream params: %s\n' % repr(gen.params)))
279 ui.write(('Stream params: %s\n' % repr(gen.params)))
280 for part in gen.iterparts():
280 for part in gen.iterparts():
281 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
281 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
282 if part.type == 'changegroup':
282 if part.type == 'changegroup':
283 version = part.params.get('version', '01')
283 version = part.params.get('version', '01')
284 cg = changegroup.getunbundler(version, part, 'UN')
284 cg = changegroup.getunbundler(version, part, 'UN')
285 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
285 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
286
286
287 @command('debugbundle',
287 @command('debugbundle',
288 [('a', 'all', None, _('show all details')),
288 [('a', 'all', None, _('show all details')),
289 ('', 'spec', None, _('print the bundlespec of the bundle'))],
289 ('', 'spec', None, _('print the bundlespec of the bundle'))],
290 _('FILE'),
290 _('FILE'),
291 norepo=True)
291 norepo=True)
292 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
292 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
293 """lists the contents of a bundle"""
293 """lists the contents of a bundle"""
294 with hg.openpath(ui, bundlepath) as f:
294 with hg.openpath(ui, bundlepath) as f:
295 if spec:
295 if spec:
296 spec = exchange.getbundlespec(ui, f)
296 spec = exchange.getbundlespec(ui, f)
297 ui.write('%s\n' % spec)
297 ui.write('%s\n' % spec)
298 return
298 return
299
299
300 gen = exchange.readbundle(ui, f, bundlepath)
300 gen = exchange.readbundle(ui, f, bundlepath)
301 if isinstance(gen, bundle2.unbundle20):
301 if isinstance(gen, bundle2.unbundle20):
302 return _debugbundle2(ui, gen, all=all, **opts)
302 return _debugbundle2(ui, gen, all=all, **opts)
303 _debugchangegroup(ui, gen, all=all, **opts)
303 _debugchangegroup(ui, gen, all=all, **opts)
304
304
305 @command('debugcheckstate', [], '')
305 @command('debugcheckstate', [], '')
306 def debugcheckstate(ui, repo):
306 def debugcheckstate(ui, repo):
307 """validate the correctness of the current dirstate"""
307 """validate the correctness of the current dirstate"""
308 parent1, parent2 = repo.dirstate.parents()
308 parent1, parent2 = repo.dirstate.parents()
309 m1 = repo[parent1].manifest()
309 m1 = repo[parent1].manifest()
310 m2 = repo[parent2].manifest()
310 m2 = repo[parent2].manifest()
311 errors = 0
311 errors = 0
312 for f in repo.dirstate:
312 for f in repo.dirstate:
313 state = repo.dirstate[f]
313 state = repo.dirstate[f]
314 if state in "nr" and f not in m1:
314 if state in "nr" and f not in m1:
315 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
315 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
316 errors += 1
316 errors += 1
317 if state in "a" and f in m1:
317 if state in "a" and f in m1:
318 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
318 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
319 errors += 1
319 errors += 1
320 if state in "m" and f not in m1 and f not in m2:
320 if state in "m" and f not in m1 and f not in m2:
321 ui.warn(_("%s in state %s, but not in either manifest\n") %
321 ui.warn(_("%s in state %s, but not in either manifest\n") %
322 (f, state))
322 (f, state))
323 errors += 1
323 errors += 1
324 for f in m1:
324 for f in m1:
325 state = repo.dirstate[f]
325 state = repo.dirstate[f]
326 if state not in "nrm":
326 if state not in "nrm":
327 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
327 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
328 errors += 1
328 errors += 1
329 if errors:
329 if errors:
330 error = _(".hg/dirstate inconsistent with current parent's manifest")
330 error = _(".hg/dirstate inconsistent with current parent's manifest")
331 raise error.Abort(error)
331 raise error.Abort(error)
332
332
333 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
333 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
334 def debugcommands(ui, cmd='', *args):
334 def debugcommands(ui, cmd='', *args):
335 """list all available commands and options"""
335 """list all available commands and options"""
336 for cmd, vals in sorted(commands.table.iteritems()):
336 for cmd, vals in sorted(commands.table.iteritems()):
337 cmd = cmd.split('|')[0].strip('^')
337 cmd = cmd.split('|')[0].strip('^')
338 opts = ', '.join([i[1] for i in vals[1]])
338 opts = ', '.join([i[1] for i in vals[1]])
339 ui.write('%s: %s\n' % (cmd, opts))
339 ui.write('%s: %s\n' % (cmd, opts))
340
340
341 @command('debugcomplete',
341 @command('debugcomplete',
342 [('o', 'options', None, _('show the command options'))],
342 [('o', 'options', None, _('show the command options'))],
343 _('[-o] CMD'),
343 _('[-o] CMD'),
344 norepo=True)
344 norepo=True)
345 def debugcomplete(ui, cmd='', **opts):
345 def debugcomplete(ui, cmd='', **opts):
346 """returns the completion list associated with the given command"""
346 """returns the completion list associated with the given command"""
347
347
348 if opts.get('options'):
348 if opts.get('options'):
349 options = []
349 options = []
350 otables = [commands.globalopts]
350 otables = [commands.globalopts]
351 if cmd:
351 if cmd:
352 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
352 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
353 otables.append(entry[1])
353 otables.append(entry[1])
354 for t in otables:
354 for t in otables:
355 for o in t:
355 for o in t:
356 if "(DEPRECATED)" in o[3]:
356 if "(DEPRECATED)" in o[3]:
357 continue
357 continue
358 if o[0]:
358 if o[0]:
359 options.append('-%s' % o[0])
359 options.append('-%s' % o[0])
360 options.append('--%s' % o[1])
360 options.append('--%s' % o[1])
361 ui.write("%s\n" % "\n".join(options))
361 ui.write("%s\n" % "\n".join(options))
362 return
362 return
363
363
364 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
364 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
365 if ui.verbose:
365 if ui.verbose:
366 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
366 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
367 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
367 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
368
368
369 @command('debugcreatestreamclonebundle', [], 'FILE')
369 @command('debugcreatestreamclonebundle', [], 'FILE')
370 def debugcreatestreamclonebundle(ui, repo, fname):
370 def debugcreatestreamclonebundle(ui, repo, fname):
371 """create a stream clone bundle file
371 """create a stream clone bundle file
372
372
373 Stream bundles are special bundles that are essentially archives of
373 Stream bundles are special bundles that are essentially archives of
374 revlog files. They are commonly used for cloning very quickly.
374 revlog files. They are commonly used for cloning very quickly.
375 """
375 """
376 requirements, gen = streamclone.generatebundlev1(repo)
376 requirements, gen = streamclone.generatebundlev1(repo)
377 changegroup.writechunks(ui, gen, fname)
377 changegroup.writechunks(ui, gen, fname)
378
378
379 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
379 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
380
380
381 @command('debugdag',
381 @command('debugdag',
382 [('t', 'tags', None, _('use tags as labels')),
382 [('t', 'tags', None, _('use tags as labels')),
383 ('b', 'branches', None, _('annotate with branch names')),
383 ('b', 'branches', None, _('annotate with branch names')),
384 ('', 'dots', None, _('use dots for runs')),
384 ('', 'dots', None, _('use dots for runs')),
385 ('s', 'spaces', None, _('separate elements by spaces'))],
385 ('s', 'spaces', None, _('separate elements by spaces'))],
386 _('[OPTION]... [FILE [REV]...]'),
386 _('[OPTION]... [FILE [REV]...]'),
387 optionalrepo=True)
387 optionalrepo=True)
388 def debugdag(ui, repo, file_=None, *revs, **opts):
388 def debugdag(ui, repo, file_=None, *revs, **opts):
389 """format the changelog or an index DAG as a concise textual description
389 """format the changelog or an index DAG as a concise textual description
390
390
391 If you pass a revlog index, the revlog's DAG is emitted. If you list
391 If you pass a revlog index, the revlog's DAG is emitted. If you list
392 revision numbers, they get labeled in the output as rN.
392 revision numbers, they get labeled in the output as rN.
393
393
394 Otherwise, the changelog DAG of the current repo is emitted.
394 Otherwise, the changelog DAG of the current repo is emitted.
395 """
395 """
396 spaces = opts.get('spaces')
396 spaces = opts.get('spaces')
397 dots = opts.get('dots')
397 dots = opts.get('dots')
398 if file_:
398 if file_:
399 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
399 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
400 file_)
400 file_)
401 revs = set((int(r) for r in revs))
401 revs = set((int(r) for r in revs))
402 def events():
402 def events():
403 for r in rlog:
403 for r in rlog:
404 yield 'n', (r, list(p for p in rlog.parentrevs(r)
404 yield 'n', (r, list(p for p in rlog.parentrevs(r)
405 if p != -1))
405 if p != -1))
406 if r in revs:
406 if r in revs:
407 yield 'l', (r, "r%i" % r)
407 yield 'l', (r, "r%i" % r)
408 elif repo:
408 elif repo:
409 cl = repo.changelog
409 cl = repo.changelog
410 tags = opts.get('tags')
410 tags = opts.get('tags')
411 branches = opts.get('branches')
411 branches = opts.get('branches')
412 if tags:
412 if tags:
413 labels = {}
413 labels = {}
414 for l, n in repo.tags().items():
414 for l, n in repo.tags().items():
415 labels.setdefault(cl.rev(n), []).append(l)
415 labels.setdefault(cl.rev(n), []).append(l)
416 def events():
416 def events():
417 b = "default"
417 b = "default"
418 for r in cl:
418 for r in cl:
419 if branches:
419 if branches:
420 newb = cl.read(cl.node(r))[5]['branch']
420 newb = cl.read(cl.node(r))[5]['branch']
421 if newb != b:
421 if newb != b:
422 yield 'a', newb
422 yield 'a', newb
423 b = newb
423 b = newb
424 yield 'n', (r, list(p for p in cl.parentrevs(r)
424 yield 'n', (r, list(p for p in cl.parentrevs(r)
425 if p != -1))
425 if p != -1))
426 if tags:
426 if tags:
427 ls = labels.get(r)
427 ls = labels.get(r)
428 if ls:
428 if ls:
429 for l in ls:
429 for l in ls:
430 yield 'l', (r, l)
430 yield 'l', (r, l)
431 else:
431 else:
432 raise error.Abort(_('need repo for changelog dag'))
432 raise error.Abort(_('need repo for changelog dag'))
433
433
434 for line in dagparser.dagtextlines(events(),
434 for line in dagparser.dagtextlines(events(),
435 addspaces=spaces,
435 addspaces=spaces,
436 wraplabels=True,
436 wraplabels=True,
437 wrapannotations=True,
437 wrapannotations=True,
438 wrapnonlinear=dots,
438 wrapnonlinear=dots,
439 usedots=dots,
439 usedots=dots,
440 maxlinewidth=70):
440 maxlinewidth=70):
441 ui.write(line)
441 ui.write(line)
442 ui.write("\n")
442 ui.write("\n")
443
443
444 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
444 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
445 def debugdata(ui, repo, file_, rev=None, **opts):
445 def debugdata(ui, repo, file_, rev=None, **opts):
446 """dump the contents of a data file revision"""
446 """dump the contents of a data file revision"""
447 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
447 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
448 if rev is not None:
448 if rev is not None:
449 raise error.CommandError('debugdata', _('invalid arguments'))
449 raise error.CommandError('debugdata', _('invalid arguments'))
450 file_, rev = None, file_
450 file_, rev = None, file_
451 elif rev is None:
451 elif rev is None:
452 raise error.CommandError('debugdata', _('invalid arguments'))
452 raise error.CommandError('debugdata', _('invalid arguments'))
453 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
453 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
454 try:
454 try:
455 ui.write(r.revision(r.lookup(rev), raw=True))
455 ui.write(r.revision(r.lookup(rev), raw=True))
456 except KeyError:
456 except KeyError:
457 raise error.Abort(_('invalid revision identifier %s') % rev)
457 raise error.Abort(_('invalid revision identifier %s') % rev)
458
458
459 @command('debugdate',
459 @command('debugdate',
460 [('e', 'extended', None, _('try extended date formats'))],
460 [('e', 'extended', None, _('try extended date formats'))],
461 _('[-e] DATE [RANGE]'),
461 _('[-e] DATE [RANGE]'),
462 norepo=True, optionalrepo=True)
462 norepo=True, optionalrepo=True)
463 def debugdate(ui, date, range=None, **opts):
463 def debugdate(ui, date, range=None, **opts):
464 """parse and display a date"""
464 """parse and display a date"""
465 if opts["extended"]:
465 if opts["extended"]:
466 d = util.parsedate(date, util.extendeddateformats)
466 d = util.parsedate(date, util.extendeddateformats)
467 else:
467 else:
468 d = util.parsedate(date)
468 d = util.parsedate(date)
469 ui.write(("internal: %s %s\n") % d)
469 ui.write(("internal: %s %s\n") % d)
470 ui.write(("standard: %s\n") % util.datestr(d))
470 ui.write(("standard: %s\n") % util.datestr(d))
471 if range:
471 if range:
472 m = util.matchdate(range)
472 m = util.matchdate(range)
473 ui.write(("match: %s\n") % m(d[0]))
473 ui.write(("match: %s\n") % m(d[0]))
474
474
475 @command('debugdeltachain',
475 @command('debugdeltachain',
476 commands.debugrevlogopts + commands.formatteropts,
476 commands.debugrevlogopts + commands.formatteropts,
477 _('-c|-m|FILE'),
477 _('-c|-m|FILE'),
478 optionalrepo=True)
478 optionalrepo=True)
479 def debugdeltachain(ui, repo, file_=None, **opts):
479 def debugdeltachain(ui, repo, file_=None, **opts):
480 """dump information about delta chains in a revlog
480 """dump information about delta chains in a revlog
481
481
482 Output can be templatized. Available template keywords are:
482 Output can be templatized. Available template keywords are:
483
483
484 :``rev``: revision number
484 :``rev``: revision number
485 :``chainid``: delta chain identifier (numbered by unique base)
485 :``chainid``: delta chain identifier (numbered by unique base)
486 :``chainlen``: delta chain length to this revision
486 :``chainlen``: delta chain length to this revision
487 :``prevrev``: previous revision in delta chain
487 :``prevrev``: previous revision in delta chain
488 :``deltatype``: role of delta / how it was computed
488 :``deltatype``: role of delta / how it was computed
489 :``compsize``: compressed size of revision
489 :``compsize``: compressed size of revision
490 :``uncompsize``: uncompressed size of revision
490 :``uncompsize``: uncompressed size of revision
491 :``chainsize``: total size of compressed revisions in chain
491 :``chainsize``: total size of compressed revisions in chain
492 :``chainratio``: total chain size divided by uncompressed revision size
492 :``chainratio``: total chain size divided by uncompressed revision size
493 (new delta chains typically start at ratio 2.00)
493 (new delta chains typically start at ratio 2.00)
494 :``lindist``: linear distance from base revision in delta chain to end
494 :``lindist``: linear distance from base revision in delta chain to end
495 of this revision
495 of this revision
496 :``extradist``: total size of revisions not part of this delta chain from
496 :``extradist``: total size of revisions not part of this delta chain from
497 base of delta chain to end of this revision; a measurement
497 base of delta chain to end of this revision; a measurement
498 of how much extra data we need to read/seek across to read
498 of how much extra data we need to read/seek across to read
499 the delta chain for this revision
499 the delta chain for this revision
500 :``extraratio``: extradist divided by chainsize; another representation of
500 :``extraratio``: extradist divided by chainsize; another representation of
501 how much unrelated data is needed to load this delta chain
501 how much unrelated data is needed to load this delta chain
502 """
502 """
503 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
503 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
504 index = r.index
504 index = r.index
505 generaldelta = r.version & revlog.REVLOGGENERALDELTA
505 generaldelta = r.version & revlog.REVLOGGENERALDELTA
506
506
507 def revinfo(rev):
507 def revinfo(rev):
508 e = index[rev]
508 e = index[rev]
509 compsize = e[1]
509 compsize = e[1]
510 uncompsize = e[2]
510 uncompsize = e[2]
511 chainsize = 0
511 chainsize = 0
512
512
513 if generaldelta:
513 if generaldelta:
514 if e[3] == e[5]:
514 if e[3] == e[5]:
515 deltatype = 'p1'
515 deltatype = 'p1'
516 elif e[3] == e[6]:
516 elif e[3] == e[6]:
517 deltatype = 'p2'
517 deltatype = 'p2'
518 elif e[3] == rev - 1:
518 elif e[3] == rev - 1:
519 deltatype = 'prev'
519 deltatype = 'prev'
520 elif e[3] == rev:
520 elif e[3] == rev:
521 deltatype = 'base'
521 deltatype = 'base'
522 else:
522 else:
523 deltatype = 'other'
523 deltatype = 'other'
524 else:
524 else:
525 if e[3] == rev:
525 if e[3] == rev:
526 deltatype = 'base'
526 deltatype = 'base'
527 else:
527 else:
528 deltatype = 'prev'
528 deltatype = 'prev'
529
529
530 chain = r._deltachain(rev)[0]
530 chain = r._deltachain(rev)[0]
531 for iterrev in chain:
531 for iterrev in chain:
532 e = index[iterrev]
532 e = index[iterrev]
533 chainsize += e[1]
533 chainsize += e[1]
534
534
535 return compsize, uncompsize, deltatype, chain, chainsize
535 return compsize, uncompsize, deltatype, chain, chainsize
536
536
537 fm = ui.formatter('debugdeltachain', opts)
537 fm = ui.formatter('debugdeltachain', opts)
538
538
539 fm.plain(' rev chain# chainlen prev delta '
539 fm.plain(' rev chain# chainlen prev delta '
540 'size rawsize chainsize ratio lindist extradist '
540 'size rawsize chainsize ratio lindist extradist '
541 'extraratio\n')
541 'extraratio\n')
542
542
543 chainbases = {}
543 chainbases = {}
544 for rev in r:
544 for rev in r:
545 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
545 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
546 chainbase = chain[0]
546 chainbase = chain[0]
547 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
547 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
548 basestart = r.start(chainbase)
548 basestart = r.start(chainbase)
549 revstart = r.start(rev)
549 revstart = r.start(rev)
550 lineardist = revstart + comp - basestart
550 lineardist = revstart + comp - basestart
551 extradist = lineardist - chainsize
551 extradist = lineardist - chainsize
552 try:
552 try:
553 prevrev = chain[-2]
553 prevrev = chain[-2]
554 except IndexError:
554 except IndexError:
555 prevrev = -1
555 prevrev = -1
556
556
557 chainratio = float(chainsize) / float(uncomp)
557 chainratio = float(chainsize) / float(uncomp)
558 extraratio = float(extradist) / float(chainsize)
558 extraratio = float(extradist) / float(chainsize)
559
559
560 fm.startitem()
560 fm.startitem()
561 fm.write('rev chainid chainlen prevrev deltatype compsize '
561 fm.write('rev chainid chainlen prevrev deltatype compsize '
562 'uncompsize chainsize chainratio lindist extradist '
562 'uncompsize chainsize chainratio lindist extradist '
563 'extraratio',
563 'extraratio',
564 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
564 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
565 rev, chainid, len(chain), prevrev, deltatype, comp,
565 rev, chainid, len(chain), prevrev, deltatype, comp,
566 uncomp, chainsize, chainratio, lineardist, extradist,
566 uncomp, chainsize, chainratio, lineardist, extradist,
567 extraratio,
567 extraratio,
568 rev=rev, chainid=chainid, chainlen=len(chain),
568 rev=rev, chainid=chainid, chainlen=len(chain),
569 prevrev=prevrev, deltatype=deltatype, compsize=comp,
569 prevrev=prevrev, deltatype=deltatype, compsize=comp,
570 uncompsize=uncomp, chainsize=chainsize,
570 uncompsize=uncomp, chainsize=chainsize,
571 chainratio=chainratio, lindist=lineardist,
571 chainratio=chainratio, lindist=lineardist,
572 extradist=extradist, extraratio=extraratio)
572 extradist=extradist, extraratio=extraratio)
573
573
574 fm.end()
574 fm.end()
575
575
576 @command('debugdiscovery',
576 @command('debugdiscovery',
577 [('', 'old', None, _('use old-style discovery')),
577 [('', 'old', None, _('use old-style discovery')),
578 ('', 'nonheads', None,
578 ('', 'nonheads', None,
579 _('use old-style discovery with non-heads included')),
579 _('use old-style discovery with non-heads included')),
580 ] + commands.remoteopts,
580 ] + commands.remoteopts,
581 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
581 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
582 def debugdiscovery(ui, repo, remoteurl="default", **opts):
582 def debugdiscovery(ui, repo, remoteurl="default", **opts):
583 """runs the changeset discovery protocol in isolation"""
583 """runs the changeset discovery protocol in isolation"""
584 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
584 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
585 opts.get('branch'))
585 opts.get('branch'))
586 remote = hg.peer(repo, opts, remoteurl)
586 remote = hg.peer(repo, opts, remoteurl)
587 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
587 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
588
588
589 # make sure tests are repeatable
589 # make sure tests are repeatable
590 random.seed(12323)
590 random.seed(12323)
591
591
592 def doit(localheads, remoteheads, remote=remote):
592 def doit(localheads, remoteheads, remote=remote):
593 if opts.get('old'):
593 if opts.get('old'):
594 if localheads:
594 if localheads:
595 raise error.Abort('cannot use localheads with old style '
595 raise error.Abort('cannot use localheads with old style '
596 'discovery')
596 'discovery')
597 if not util.safehasattr(remote, 'branches'):
597 if not util.safehasattr(remote, 'branches'):
598 # enable in-client legacy support
598 # enable in-client legacy support
599 remote = localrepo.locallegacypeer(remote.local())
599 remote = localrepo.locallegacypeer(remote.local())
600 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
600 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
601 force=True)
601 force=True)
602 common = set(common)
602 common = set(common)
603 if not opts.get('nonheads'):
603 if not opts.get('nonheads'):
604 ui.write(("unpruned common: %s\n") %
604 ui.write(("unpruned common: %s\n") %
605 " ".join(sorted(short(n) for n in common)))
605 " ".join(sorted(short(n) for n in common)))
606 dag = dagutil.revlogdag(repo.changelog)
606 dag = dagutil.revlogdag(repo.changelog)
607 all = dag.ancestorset(dag.internalizeall(common))
607 all = dag.ancestorset(dag.internalizeall(common))
608 common = dag.externalizeall(dag.headsetofconnecteds(all))
608 common = dag.externalizeall(dag.headsetofconnecteds(all))
609 else:
609 else:
610 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
610 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
611 common = set(common)
611 common = set(common)
612 rheads = set(hds)
612 rheads = set(hds)
613 lheads = set(repo.heads())
613 lheads = set(repo.heads())
614 ui.write(("common heads: %s\n") %
614 ui.write(("common heads: %s\n") %
615 " ".join(sorted(short(n) for n in common)))
615 " ".join(sorted(short(n) for n in common)))
616 if lheads <= common:
616 if lheads <= common:
617 ui.write(("local is subset\n"))
617 ui.write(("local is subset\n"))
618 elif rheads <= common:
618 elif rheads <= common:
619 ui.write(("remote is subset\n"))
619 ui.write(("remote is subset\n"))
620
620
621 serverlogs = opts.get('serverlog')
621 serverlogs = opts.get('serverlog')
622 if serverlogs:
622 if serverlogs:
623 for filename in serverlogs:
623 for filename in serverlogs:
624 with open(filename, 'r') as logfile:
624 with open(filename, 'r') as logfile:
625 line = logfile.readline()
625 line = logfile.readline()
626 while line:
626 while line:
627 parts = line.strip().split(';')
627 parts = line.strip().split(';')
628 op = parts[1]
628 op = parts[1]
629 if op == 'cg':
629 if op == 'cg':
630 pass
630 pass
631 elif op == 'cgss':
631 elif op == 'cgss':
632 doit(parts[2].split(' '), parts[3].split(' '))
632 doit(parts[2].split(' '), parts[3].split(' '))
633 elif op == 'unb':
633 elif op == 'unb':
634 doit(parts[3].split(' '), parts[2].split(' '))
634 doit(parts[3].split(' '), parts[2].split(' '))
635 line = logfile.readline()
635 line = logfile.readline()
636 else:
636 else:
637 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
637 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
638 opts.get('remote_head'))
638 opts.get('remote_head'))
639 localrevs = opts.get('local_head')
639 localrevs = opts.get('local_head')
640 doit(localrevs, remoterevs)
640 doit(localrevs, remoterevs)
641
641
642 @command('debugextensions', commands.formatteropts, [], norepo=True)
642 @command('debugextensions', commands.formatteropts, [], norepo=True)
643 def debugextensions(ui, **opts):
643 def debugextensions(ui, **opts):
644 '''show information about active extensions'''
644 '''show information about active extensions'''
645 exts = extensions.extensions(ui)
645 exts = extensions.extensions(ui)
646 hgver = util.version()
646 hgver = util.version()
647 fm = ui.formatter('debugextensions', opts)
647 fm = ui.formatter('debugextensions', opts)
648 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
648 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
649 isinternal = extensions.ismoduleinternal(extmod)
649 isinternal = extensions.ismoduleinternal(extmod)
650 extsource = extmod.__file__
650 extsource = extmod.__file__
651 if isinternal:
651 if isinternal:
652 exttestedwith = [] # never expose magic string to users
652 exttestedwith = [] # never expose magic string to users
653 else:
653 else:
654 exttestedwith = getattr(extmod, 'testedwith', '').split()
654 exttestedwith = getattr(extmod, 'testedwith', '').split()
655 extbuglink = getattr(extmod, 'buglink', None)
655 extbuglink = getattr(extmod, 'buglink', None)
656
656
657 fm.startitem()
657 fm.startitem()
658
658
659 if ui.quiet or ui.verbose:
659 if ui.quiet or ui.verbose:
660 fm.write('name', '%s\n', extname)
660 fm.write('name', '%s\n', extname)
661 else:
661 else:
662 fm.write('name', '%s', extname)
662 fm.write('name', '%s', extname)
663 if isinternal or hgver in exttestedwith:
663 if isinternal or hgver in exttestedwith:
664 fm.plain('\n')
664 fm.plain('\n')
665 elif not exttestedwith:
665 elif not exttestedwith:
666 fm.plain(_(' (untested!)\n'))
666 fm.plain(_(' (untested!)\n'))
667 else:
667 else:
668 lasttestedversion = exttestedwith[-1]
668 lasttestedversion = exttestedwith[-1]
669 fm.plain(' (%s!)\n' % lasttestedversion)
669 fm.plain(' (%s!)\n' % lasttestedversion)
670
670
671 fm.condwrite(ui.verbose and extsource, 'source',
671 fm.condwrite(ui.verbose and extsource, 'source',
672 _(' location: %s\n'), extsource or "")
672 _(' location: %s\n'), extsource or "")
673
673
674 if ui.verbose:
674 if ui.verbose:
675 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
675 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
676 fm.data(bundled=isinternal)
676 fm.data(bundled=isinternal)
677
677
678 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
678 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
679 _(' tested with: %s\n'),
679 _(' tested with: %s\n'),
680 fm.formatlist(exttestedwith, name='ver'))
680 fm.formatlist(exttestedwith, name='ver'))
681
681
682 fm.condwrite(ui.verbose and extbuglink, 'buglink',
682 fm.condwrite(ui.verbose and extbuglink, 'buglink',
683 _(' bug reporting: %s\n'), extbuglink or "")
683 _(' bug reporting: %s\n'), extbuglink or "")
684
684
685 fm.end()
685 fm.end()
686
686
687 @command('debugfileset',
687 @command('debugfileset',
688 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
688 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
689 _('[-r REV] FILESPEC'))
689 _('[-r REV] FILESPEC'))
690 def debugfileset(ui, repo, expr, **opts):
690 def debugfileset(ui, repo, expr, **opts):
691 '''parse and apply a fileset specification'''
691 '''parse and apply a fileset specification'''
692 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
692 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
693 if ui.verbose:
693 if ui.verbose:
694 tree = fileset.parse(expr)
694 tree = fileset.parse(expr)
695 ui.note(fileset.prettyformat(tree), "\n")
695 ui.note(fileset.prettyformat(tree), "\n")
696
696
697 for f in ctx.getfileset(expr):
697 for f in ctx.getfileset(expr):
698 ui.write("%s\n" % f)
698 ui.write("%s\n" % f)
699
699
700 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
700 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
701 def debugfsinfo(ui, path="."):
701 def debugfsinfo(ui, path="."):
702 """show information detected about current filesystem"""
702 """show information detected about current filesystem"""
703 util.writefile('.debugfsinfo', '')
703 util.writefile('.debugfsinfo', '')
704 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
704 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
705 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
705 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
706 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
706 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
707 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
707 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
708 and 'yes' or 'no'))
708 and 'yes' or 'no'))
709 os.unlink('.debugfsinfo')
709 os.unlink('.debugfsinfo')
710
710
711 @command('debuggetbundle',
711 @command('debuggetbundle',
712 [('H', 'head', [], _('id of head node'), _('ID')),
712 [('H', 'head', [], _('id of head node'), _('ID')),
713 ('C', 'common', [], _('id of common node'), _('ID')),
713 ('C', 'common', [], _('id of common node'), _('ID')),
714 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
714 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
715 _('REPO FILE [-H|-C ID]...'),
715 _('REPO FILE [-H|-C ID]...'),
716 norepo=True)
716 norepo=True)
717 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
717 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
718 """retrieves a bundle from a repo
718 """retrieves a bundle from a repo
719
719
720 Every ID must be a full-length hex node id string. Saves the bundle to the
720 Every ID must be a full-length hex node id string. Saves the bundle to the
721 given file.
721 given file.
722 """
722 """
723 repo = hg.peer(ui, opts, repopath)
723 repo = hg.peer(ui, opts, repopath)
724 if not repo.capable('getbundle'):
724 if not repo.capable('getbundle'):
725 raise error.Abort("getbundle() not supported by target repository")
725 raise error.Abort("getbundle() not supported by target repository")
726 args = {}
726 args = {}
727 if common:
727 if common:
728 args['common'] = [bin(s) for s in common]
728 args['common'] = [bin(s) for s in common]
729 if head:
729 if head:
730 args['heads'] = [bin(s) for s in head]
730 args['heads'] = [bin(s) for s in head]
731 # TODO: get desired bundlecaps from command line.
731 # TODO: get desired bundlecaps from command line.
732 args['bundlecaps'] = None
732 args['bundlecaps'] = None
733 bundle = repo.getbundle('debug', **args)
733 bundle = repo.getbundle('debug', **args)
734
734
735 bundletype = opts.get('type', 'bzip2').lower()
735 bundletype = opts.get('type', 'bzip2').lower()
736 btypes = {'none': 'HG10UN',
736 btypes = {'none': 'HG10UN',
737 'bzip2': 'HG10BZ',
737 'bzip2': 'HG10BZ',
738 'gzip': 'HG10GZ',
738 'gzip': 'HG10GZ',
739 'bundle2': 'HG20'}
739 'bundle2': 'HG20'}
740 bundletype = btypes.get(bundletype)
740 bundletype = btypes.get(bundletype)
741 if bundletype not in bundle2.bundletypes:
741 if bundletype not in bundle2.bundletypes:
742 raise error.Abort(_('unknown bundle type specified with --type'))
742 raise error.Abort(_('unknown bundle type specified with --type'))
743 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
743 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
744
744
745 @command('debugignore', [], '[FILE]')
745 @command('debugignore', [], '[FILE]')
746 def debugignore(ui, repo, *files, **opts):
746 def debugignore(ui, repo, *files, **opts):
747 """display the combined ignore pattern and information about ignored files
747 """display the combined ignore pattern and information about ignored files
748
748
749 With no argument display the combined ignore pattern.
749 With no argument display the combined ignore pattern.
750
750
751 Given space separated file names, shows if the given file is ignored and
751 Given space separated file names, shows if the given file is ignored and
752 if so, show the ignore rule (file and line number) that matched it.
752 if so, show the ignore rule (file and line number) that matched it.
753 """
753 """
754 ignore = repo.dirstate._ignore
754 ignore = repo.dirstate._ignore
755 if not files:
755 if not files:
756 # Show all the patterns
756 # Show all the patterns
757 includepat = getattr(ignore, 'includepat', None)
757 includepat = getattr(ignore, 'includepat', None)
758 if includepat is not None:
758 if includepat is not None:
759 ui.write("%s\n" % includepat)
759 ui.write("%s\n" % includepat)
760 else:
760 else:
761 raise error.Abort(_("no ignore patterns found"))
761 raise error.Abort(_("no ignore patterns found"))
762 else:
762 else:
763 for f in files:
763 for f in files:
764 nf = util.normpath(f)
764 nf = util.normpath(f)
765 ignored = None
765 ignored = None
766 ignoredata = None
766 ignoredata = None
767 if nf != '.':
767 if nf != '.':
768 if ignore(nf):
768 if ignore(nf):
769 ignored = nf
769 ignored = nf
770 ignoredata = repo.dirstate._ignorefileandline(nf)
770 ignoredata = repo.dirstate._ignorefileandline(nf)
771 else:
771 else:
772 for p in util.finddirs(nf):
772 for p in util.finddirs(nf):
773 if ignore(p):
773 if ignore(p):
774 ignored = p
774 ignored = p
775 ignoredata = repo.dirstate._ignorefileandline(p)
775 ignoredata = repo.dirstate._ignorefileandline(p)
776 break
776 break
777 if ignored:
777 if ignored:
778 if ignored == nf:
778 if ignored == nf:
779 ui.write(_("%s is ignored\n") % f)
779 ui.write(_("%s is ignored\n") % f)
780 else:
780 else:
781 ui.write(_("%s is ignored because of "
781 ui.write(_("%s is ignored because of "
782 "containing folder %s\n")
782 "containing folder %s\n")
783 % (f, ignored))
783 % (f, ignored))
784 ignorefile, lineno, line = ignoredata
784 ignorefile, lineno, line = ignoredata
785 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
785 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
786 % (ignorefile, lineno, line))
786 % (ignorefile, lineno, line))
787 else:
787 else:
788 ui.write(_("%s is not ignored\n") % f)
788 ui.write(_("%s is not ignored\n") % f)
789
789
790 @command('debugindex', commands.debugrevlogopts +
790 @command('debugindex', commands.debugrevlogopts +
791 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
791 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
792 _('[-f FORMAT] -c|-m|FILE'),
792 _('[-f FORMAT] -c|-m|FILE'),
793 optionalrepo=True)
793 optionalrepo=True)
794 def debugindex(ui, repo, file_=None, **opts):
794 def debugindex(ui, repo, file_=None, **opts):
795 """dump the contents of an index file"""
795 """dump the contents of an index file"""
796 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
796 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
797 format = opts.get('format', 0)
797 format = opts.get('format', 0)
798 if format not in (0, 1):
798 if format not in (0, 1):
799 raise error.Abort(_("unknown format %d") % format)
799 raise error.Abort(_("unknown format %d") % format)
800
800
801 generaldelta = r.version & revlog.REVLOGGENERALDELTA
801 generaldelta = r.version & revlog.REVLOGGENERALDELTA
802 if generaldelta:
802 if generaldelta:
803 basehdr = ' delta'
803 basehdr = ' delta'
804 else:
804 else:
805 basehdr = ' base'
805 basehdr = ' base'
806
806
807 if ui.debugflag:
807 if ui.debugflag:
808 shortfn = hex
808 shortfn = hex
809 else:
809 else:
810 shortfn = short
810 shortfn = short
811
811
812 # There might not be anything in r, so have a sane default
812 # There might not be anything in r, so have a sane default
813 idlen = 12
813 idlen = 12
814 for i in r:
814 for i in r:
815 idlen = len(shortfn(r.node(i)))
815 idlen = len(shortfn(r.node(i)))
816 break
816 break
817
817
818 if format == 0:
818 if format == 0:
819 ui.write((" rev offset length " + basehdr + " linkrev"
819 ui.write((" rev offset length " + basehdr + " linkrev"
820 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
820 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
821 elif format == 1:
821 elif format == 1:
822 ui.write((" rev flag offset length"
822 ui.write((" rev flag offset length"
823 " size " + basehdr + " link p1 p2"
823 " size " + basehdr + " link p1 p2"
824 " %s\n") % "nodeid".rjust(idlen))
824 " %s\n") % "nodeid".rjust(idlen))
825
825
826 for i in r:
826 for i in r:
827 node = r.node(i)
827 node = r.node(i)
828 if generaldelta:
828 if generaldelta:
829 base = r.deltaparent(i)
829 base = r.deltaparent(i)
830 else:
830 else:
831 base = r.chainbase(i)
831 base = r.chainbase(i)
832 if format == 0:
832 if format == 0:
833 try:
833 try:
834 pp = r.parents(node)
834 pp = r.parents(node)
835 except Exception:
835 except Exception:
836 pp = [nullid, nullid]
836 pp = [nullid, nullid]
837 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
837 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
838 i, r.start(i), r.length(i), base, r.linkrev(i),
838 i, r.start(i), r.length(i), base, r.linkrev(i),
839 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
839 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
840 elif format == 1:
840 elif format == 1:
841 pr = r.parentrevs(i)
841 pr = r.parentrevs(i)
842 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
842 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
843 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
843 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
844 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
844 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
845
845
846 @command('debugindexdot', commands.debugrevlogopts,
846 @command('debugindexdot', commands.debugrevlogopts,
847 _('-c|-m|FILE'), optionalrepo=True)
847 _('-c|-m|FILE'), optionalrepo=True)
848 def debugindexdot(ui, repo, file_=None, **opts):
848 def debugindexdot(ui, repo, file_=None, **opts):
849 """dump an index DAG as a graphviz dot file"""
849 """dump an index DAG as a graphviz dot file"""
850 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
850 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
851 ui.write(("digraph G {\n"))
851 ui.write(("digraph G {\n"))
852 for i in r:
852 for i in r:
853 node = r.node(i)
853 node = r.node(i)
854 pp = r.parents(node)
854 pp = r.parents(node)
855 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
855 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
856 if pp[1] != nullid:
856 if pp[1] != nullid:
857 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
857 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
858 ui.write("}\n")
858 ui.write("}\n")
859
859
860 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
860 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
861 def debuginstall(ui, **opts):
861 def debuginstall(ui, **opts):
862 '''test Mercurial installation
862 '''test Mercurial installation
863
863
864 Returns 0 on success.
864 Returns 0 on success.
865 '''
865 '''
866
866
867 def writetemp(contents):
867 def writetemp(contents):
868 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
868 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
869 f = os.fdopen(fd, "wb")
869 f = os.fdopen(fd, "wb")
870 f.write(contents)
870 f.write(contents)
871 f.close()
871 f.close()
872 return name
872 return name
873
873
874 problems = 0
874 problems = 0
875
875
876 fm = ui.formatter('debuginstall', opts)
876 fm = ui.formatter('debuginstall', opts)
877 fm.startitem()
877 fm.startitem()
878
878
879 # encoding
879 # encoding
880 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
880 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
881 err = None
881 err = None
882 try:
882 try:
883 encoding.fromlocal("test")
883 encoding.fromlocal("test")
884 except error.Abort as inst:
884 except error.Abort as inst:
885 err = inst
885 err = inst
886 problems += 1
886 problems += 1
887 fm.condwrite(err, 'encodingerror', _(" %s\n"
887 fm.condwrite(err, 'encodingerror', _(" %s\n"
888 " (check that your locale is properly set)\n"), err)
888 " (check that your locale is properly set)\n"), err)
889
889
890 # Python
890 # Python
891 fm.write('pythonexe', _("checking Python executable (%s)\n"),
891 fm.write('pythonexe', _("checking Python executable (%s)\n"),
892 pycompat.sysexecutable)
892 pycompat.sysexecutable)
893 fm.write('pythonver', _("checking Python version (%s)\n"),
893 fm.write('pythonver', _("checking Python version (%s)\n"),
894 ("%d.%d.%d" % sys.version_info[:3]))
894 ("%d.%d.%d" % sys.version_info[:3]))
895 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
895 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
896 os.path.dirname(pycompat.fsencode(os.__file__)))
896 os.path.dirname(pycompat.fsencode(os.__file__)))
897
897
898 security = set(sslutil.supportedprotocols)
898 security = set(sslutil.supportedprotocols)
899 if sslutil.hassni:
899 if sslutil.hassni:
900 security.add('sni')
900 security.add('sni')
901
901
902 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
902 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
903 fm.formatlist(sorted(security), name='protocol',
903 fm.formatlist(sorted(security), name='protocol',
904 fmt='%s', sep=','))
904 fmt='%s', sep=','))
905
905
906 # These are warnings, not errors. So don't increment problem count. This
906 # These are warnings, not errors. So don't increment problem count. This
907 # may change in the future.
907 # may change in the future.
908 if 'tls1.2' not in security:
908 if 'tls1.2' not in security:
909 fm.plain(_(' TLS 1.2 not supported by Python install; '
909 fm.plain(_(' TLS 1.2 not supported by Python install; '
910 'network connections lack modern security\n'))
910 'network connections lack modern security\n'))
911 if 'sni' not in security:
911 if 'sni' not in security:
912 fm.plain(_(' SNI not supported by Python install; may have '
912 fm.plain(_(' SNI not supported by Python install; may have '
913 'connectivity issues with some servers\n'))
913 'connectivity issues with some servers\n'))
914
914
915 # TODO print CA cert info
915 # TODO print CA cert info
916
916
917 # hg version
917 # hg version
918 hgver = util.version()
918 hgver = util.version()
919 fm.write('hgver', _("checking Mercurial version (%s)\n"),
919 fm.write('hgver', _("checking Mercurial version (%s)\n"),
920 hgver.split('+')[0])
920 hgver.split('+')[0])
921 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
921 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
922 '+'.join(hgver.split('+')[1:]))
922 '+'.join(hgver.split('+')[1:]))
923
923
924 # compiled modules
924 # compiled modules
925 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
925 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
926 policy.policy)
926 policy.policy)
927 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
927 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
928 os.path.dirname(__file__))
928 os.path.dirname(__file__))
929
929
930 err = None
930 err = None
931 try:
931 try:
932 from . import (
932 from . import (
933 base85,
933 base85,
934 bdiff,
934 bdiff,
935 mpatch,
935 mpatch,
936 osutil,
936 osutil,
937 )
937 )
938 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
938 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
939 except Exception as inst:
939 except Exception as inst:
940 err = inst
940 err = inst
941 problems += 1
941 problems += 1
942 fm.condwrite(err, 'extensionserror', " %s\n", err)
942 fm.condwrite(err, 'extensionserror', " %s\n", err)
943
943
944 compengines = util.compengines._engines.values()
944 compengines = util.compengines._engines.values()
945 fm.write('compengines', _('checking registered compression engines (%s)\n'),
945 fm.write('compengines', _('checking registered compression engines (%s)\n'),
946 fm.formatlist(sorted(e.name() for e in compengines),
946 fm.formatlist(sorted(e.name() for e in compengines),
947 name='compengine', fmt='%s', sep=', '))
947 name='compengine', fmt='%s', sep=', '))
948 fm.write('compenginesavail', _('checking available compression engines '
948 fm.write('compenginesavail', _('checking available compression engines '
949 '(%s)\n'),
949 '(%s)\n'),
950 fm.formatlist(sorted(e.name() for e in compengines
950 fm.formatlist(sorted(e.name() for e in compengines
951 if e.available()),
951 if e.available()),
952 name='compengine', fmt='%s', sep=', '))
952 name='compengine', fmt='%s', sep=', '))
953 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
953 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
954 fm.write('compenginesserver', _('checking available compression engines '
954 fm.write('compenginesserver', _('checking available compression engines '
955 'for wire protocol (%s)\n'),
955 'for wire protocol (%s)\n'),
956 fm.formatlist([e.name() for e in wirecompengines
956 fm.formatlist([e.name() for e in wirecompengines
957 if e.wireprotosupport()],
957 if e.wireprotosupport()],
958 name='compengine', fmt='%s', sep=', '))
958 name='compengine', fmt='%s', sep=', '))
959
959
960 # templates
960 # templates
961 p = templater.templatepaths()
961 p = templater.templatepaths()
962 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
962 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
963 fm.condwrite(not p, '', _(" no template directories found\n"))
963 fm.condwrite(not p, '', _(" no template directories found\n"))
964 if p:
964 if p:
965 m = templater.templatepath("map-cmdline.default")
965 m = templater.templatepath("map-cmdline.default")
966 if m:
966 if m:
967 # template found, check if it is working
967 # template found, check if it is working
968 err = None
968 err = None
969 try:
969 try:
970 templater.templater.frommapfile(m)
970 templater.templater.frommapfile(m)
971 except Exception as inst:
971 except Exception as inst:
972 err = inst
972 err = inst
973 p = None
973 p = None
974 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
974 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
975 else:
975 else:
976 p = None
976 p = None
977 fm.condwrite(p, 'defaulttemplate',
977 fm.condwrite(p, 'defaulttemplate',
978 _("checking default template (%s)\n"), m)
978 _("checking default template (%s)\n"), m)
979 fm.condwrite(not m, 'defaulttemplatenotfound',
979 fm.condwrite(not m, 'defaulttemplatenotfound',
980 _(" template '%s' not found\n"), "default")
980 _(" template '%s' not found\n"), "default")
981 if not p:
981 if not p:
982 problems += 1
982 problems += 1
983 fm.condwrite(not p, '',
983 fm.condwrite(not p, '',
984 _(" (templates seem to have been installed incorrectly)\n"))
984 _(" (templates seem to have been installed incorrectly)\n"))
985
985
986 # editor
986 # editor
987 editor = ui.geteditor()
987 editor = ui.geteditor()
988 editor = util.expandpath(editor)
988 editor = util.expandpath(editor)
989 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
989 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
990 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
990 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
991 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
991 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
992 _(" No commit editor set and can't find %s in PATH\n"
992 _(" No commit editor set and can't find %s in PATH\n"
993 " (specify a commit editor in your configuration"
993 " (specify a commit editor in your configuration"
994 " file)\n"), not cmdpath and editor == 'vi' and editor)
994 " file)\n"), not cmdpath and editor == 'vi' and editor)
995 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
995 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
996 _(" Can't find editor '%s' in PATH\n"
996 _(" Can't find editor '%s' in PATH\n"
997 " (specify a commit editor in your configuration"
997 " (specify a commit editor in your configuration"
998 " file)\n"), not cmdpath and editor)
998 " file)\n"), not cmdpath and editor)
999 if not cmdpath and editor != 'vi':
999 if not cmdpath and editor != 'vi':
1000 problems += 1
1000 problems += 1
1001
1001
1002 # check username
1002 # check username
1003 username = None
1003 username = None
1004 err = None
1004 err = None
1005 try:
1005 try:
1006 username = ui.username()
1006 username = ui.username()
1007 except error.Abort as e:
1007 except error.Abort as e:
1008 err = e
1008 err = e
1009 problems += 1
1009 problems += 1
1010
1010
1011 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1011 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1012 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1012 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1013 " (specify a username in your configuration file)\n"), err)
1013 " (specify a username in your configuration file)\n"), err)
1014
1014
1015 fm.condwrite(not problems, '',
1015 fm.condwrite(not problems, '',
1016 _("no problems detected\n"))
1016 _("no problems detected\n"))
1017 if not problems:
1017 if not problems:
1018 fm.data(problems=problems)
1018 fm.data(problems=problems)
1019 fm.condwrite(problems, 'problems',
1019 fm.condwrite(problems, 'problems',
1020 _("%d problems detected,"
1020 _("%d problems detected,"
1021 " please check your install!\n"), problems)
1021 " please check your install!\n"), problems)
1022 fm.end()
1022 fm.end()
1023
1023
1024 return problems
1024 return problems
1025
1025
1026 @command('debugknown', [], _('REPO ID...'), norepo=True)
1027 def debugknown(ui, repopath, *ids, **opts):
1028 """test whether node ids are known to a repo
1029
1030 Every ID must be a full-length hex node id string. Returns a list of 0s
1031 and 1s indicating unknown/known.
1032 """
1033 repo = hg.peer(ui, opts, repopath)
1034 if not repo.capable('known'):
1035 raise error.Abort("known() not supported by target repository")
1036 flags = repo.known([bin(s) for s in ids])
1037 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1038
1026 @command('debugupgraderepo', [
1039 @command('debugupgraderepo', [
1027 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1040 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1028 ('', 'run', False, _('performs an upgrade')),
1041 ('', 'run', False, _('performs an upgrade')),
1029 ])
1042 ])
1030 def debugupgraderepo(ui, repo, run=False, optimize=None):
1043 def debugupgraderepo(ui, repo, run=False, optimize=None):
1031 """upgrade a repository to use different features
1044 """upgrade a repository to use different features
1032
1045
1033 If no arguments are specified, the repository is evaluated for upgrade
1046 If no arguments are specified, the repository is evaluated for upgrade
1034 and a list of problems and potential optimizations is printed.
1047 and a list of problems and potential optimizations is printed.
1035
1048
1036 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1049 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1037 can be influenced via additional arguments. More details will be provided
1050 can be influenced via additional arguments. More details will be provided
1038 by the command output when run without ``--run``.
1051 by the command output when run without ``--run``.
1039
1052
1040 During the upgrade, the repository will be locked and no writes will be
1053 During the upgrade, the repository will be locked and no writes will be
1041 allowed.
1054 allowed.
1042
1055
1043 At the end of the upgrade, the repository may not be readable while new
1056 At the end of the upgrade, the repository may not be readable while new
1044 repository data is swapped in. This window will be as long as it takes to
1057 repository data is swapped in. This window will be as long as it takes to
1045 rename some directories inside the ``.hg`` directory. On most machines, this
1058 rename some directories inside the ``.hg`` directory. On most machines, this
1046 should complete almost instantaneously and the chances of a consumer being
1059 should complete almost instantaneously and the chances of a consumer being
1047 unable to access the repository should be low.
1060 unable to access the repository should be low.
1048 """
1061 """
1049 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1062 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now