##// END OF EJS Templates
debugcommands: move 'debugsuccessorssets' in the new module
Pierre-Yves David -
r30956:db30c6bf default
parent child Browse files
Show More
@@ -1,5588 +1,5534
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
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 )
21 )
22 from . import (
22 from . import (
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 changegroup,
26 changegroup,
27 cmdutil,
27 cmdutil,
28 copies,
28 copies,
29 destutil,
29 destutil,
30 dirstateguard,
30 dirstateguard,
31 discovery,
31 discovery,
32 encoding,
32 encoding,
33 error,
33 error,
34 exchange,
34 exchange,
35 extensions,
35 extensions,
36 formatter,
36 formatter,
37 graphmod,
37 graphmod,
38 hbisect,
38 hbisect,
39 help,
39 help,
40 hg,
40 hg,
41 lock as lockmod,
41 lock as lockmod,
42 merge as mergemod,
42 merge as mergemod,
43 minirst,
43 minirst,
44 obsolete,
44 obsolete,
45 patch,
45 patch,
46 phases,
46 phases,
47 pycompat,
47 pycompat,
48 revset,
48 revset,
49 scmutil,
49 scmutil,
50 server,
50 server,
51 sshserver,
51 sshserver,
52 streamclone,
52 streamclone,
53 templatekw,
53 templatekw,
54 templater,
54 templater,
55 ui as uimod,
55 ui as uimod,
56 util,
56 util,
57 )
57 )
58
58
59 release = lockmod.release
59 release = lockmod.release
60
60
61 table = {}
61 table = {}
62
62
63 command = cmdutil.command(table)
63 command = cmdutil.command(table)
64
64
65 # label constants
65 # label constants
66 # until 3.5, bookmarks.current was the advertised name, not
66 # until 3.5, bookmarks.current was the advertised name, not
67 # bookmarks.active, so we must use both to avoid breaking old
67 # bookmarks.active, so we must use both to avoid breaking old
68 # custom styles
68 # custom styles
69 activebookmarklabel = 'bookmarks.active bookmarks.current'
69 activebookmarklabel = 'bookmarks.active bookmarks.current'
70
70
71 # common command options
71 # common command options
72
72
73 globalopts = [
73 globalopts = [
74 ('R', 'repository', '',
74 ('R', 'repository', '',
75 _('repository root directory or name of overlay bundle file'),
75 _('repository root directory or name of overlay bundle file'),
76 _('REPO')),
76 _('REPO')),
77 ('', 'cwd', '',
77 ('', 'cwd', '',
78 _('change working directory'), _('DIR')),
78 _('change working directory'), _('DIR')),
79 ('y', 'noninteractive', None,
79 ('y', 'noninteractive', None,
80 _('do not prompt, automatically pick the first choice for all prompts')),
80 _('do not prompt, automatically pick the first choice for all prompts')),
81 ('q', 'quiet', None, _('suppress output')),
81 ('q', 'quiet', None, _('suppress output')),
82 ('v', 'verbose', None, _('enable additional output')),
82 ('v', 'verbose', None, _('enable additional output')),
83 ('', 'config', [],
83 ('', 'config', [],
84 _('set/override config option (use \'section.name=value\')'),
84 _('set/override config option (use \'section.name=value\')'),
85 _('CONFIG')),
85 _('CONFIG')),
86 ('', 'debug', None, _('enable debugging output')),
86 ('', 'debug', None, _('enable debugging output')),
87 ('', 'debugger', None, _('start debugger')),
87 ('', 'debugger', None, _('start debugger')),
88 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
88 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
89 _('ENCODE')),
89 _('ENCODE')),
90 ('', 'encodingmode', encoding.encodingmode,
90 ('', 'encodingmode', encoding.encodingmode,
91 _('set the charset encoding mode'), _('MODE')),
91 _('set the charset encoding mode'), _('MODE')),
92 ('', 'traceback', None, _('always print a traceback on exception')),
92 ('', 'traceback', None, _('always print a traceback on exception')),
93 ('', 'time', None, _('time how long the command takes')),
93 ('', 'time', None, _('time how long the command takes')),
94 ('', 'profile', None, _('print command execution profile')),
94 ('', 'profile', None, _('print command execution profile')),
95 ('', 'version', None, _('output version information and exit')),
95 ('', 'version', None, _('output version information and exit')),
96 ('h', 'help', None, _('display help and exit')),
96 ('h', 'help', None, _('display help and exit')),
97 ('', 'hidden', False, _('consider hidden changesets')),
97 ('', 'hidden', False, _('consider hidden changesets')),
98 ]
98 ]
99
99
100 dryrunopts = [('n', 'dry-run', None,
100 dryrunopts = [('n', 'dry-run', None,
101 _('do not perform actions, just print output'))]
101 _('do not perform actions, just print output'))]
102
102
103 remoteopts = [
103 remoteopts = [
104 ('e', 'ssh', '',
104 ('e', 'ssh', '',
105 _('specify ssh command to use'), _('CMD')),
105 _('specify ssh command to use'), _('CMD')),
106 ('', 'remotecmd', '',
106 ('', 'remotecmd', '',
107 _('specify hg command to run on the remote side'), _('CMD')),
107 _('specify hg command to run on the remote side'), _('CMD')),
108 ('', 'insecure', None,
108 ('', 'insecure', None,
109 _('do not verify server certificate (ignoring web.cacerts config)')),
109 _('do not verify server certificate (ignoring web.cacerts config)')),
110 ]
110 ]
111
111
112 walkopts = [
112 walkopts = [
113 ('I', 'include', [],
113 ('I', 'include', [],
114 _('include names matching the given patterns'), _('PATTERN')),
114 _('include names matching the given patterns'), _('PATTERN')),
115 ('X', 'exclude', [],
115 ('X', 'exclude', [],
116 _('exclude names matching the given patterns'), _('PATTERN')),
116 _('exclude names matching the given patterns'), _('PATTERN')),
117 ]
117 ]
118
118
119 commitopts = [
119 commitopts = [
120 ('m', 'message', '',
120 ('m', 'message', '',
121 _('use text as commit message'), _('TEXT')),
121 _('use text as commit message'), _('TEXT')),
122 ('l', 'logfile', '',
122 ('l', 'logfile', '',
123 _('read commit message from file'), _('FILE')),
123 _('read commit message from file'), _('FILE')),
124 ]
124 ]
125
125
126 commitopts2 = [
126 commitopts2 = [
127 ('d', 'date', '',
127 ('d', 'date', '',
128 _('record the specified date as commit date'), _('DATE')),
128 _('record the specified date as commit date'), _('DATE')),
129 ('u', 'user', '',
129 ('u', 'user', '',
130 _('record the specified user as committer'), _('USER')),
130 _('record the specified user as committer'), _('USER')),
131 ]
131 ]
132
132
133 # hidden for now
133 # hidden for now
134 formatteropts = [
134 formatteropts = [
135 ('T', 'template', '',
135 ('T', 'template', '',
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
137 ]
137 ]
138
138
139 templateopts = [
139 templateopts = [
140 ('', 'style', '',
140 ('', 'style', '',
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
142 ('T', 'template', '',
142 ('T', 'template', '',
143 _('display with template'), _('TEMPLATE')),
143 _('display with template'), _('TEMPLATE')),
144 ]
144 ]
145
145
146 logopts = [
146 logopts = [
147 ('p', 'patch', None, _('show patch')),
147 ('p', 'patch', None, _('show patch')),
148 ('g', 'git', None, _('use git extended diff format')),
148 ('g', 'git', None, _('use git extended diff format')),
149 ('l', 'limit', '',
149 ('l', 'limit', '',
150 _('limit number of changes displayed'), _('NUM')),
150 _('limit number of changes displayed'), _('NUM')),
151 ('M', 'no-merges', None, _('do not show merges')),
151 ('M', 'no-merges', None, _('do not show merges')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
153 ('G', 'graph', None, _("show the revision DAG")),
153 ('G', 'graph', None, _("show the revision DAG")),
154 ] + templateopts
154 ] + templateopts
155
155
156 diffopts = [
156 diffopts = [
157 ('a', 'text', None, _('treat all files as text')),
157 ('a', 'text', None, _('treat all files as text')),
158 ('g', 'git', None, _('use git extended diff format')),
158 ('g', 'git', None, _('use git extended diff format')),
159 ('', 'nodates', None, _('omit dates from diff headers'))
159 ('', 'nodates', None, _('omit dates from diff headers'))
160 ]
160 ]
161
161
162 diffwsopts = [
162 diffwsopts = [
163 ('w', 'ignore-all-space', None,
163 ('w', 'ignore-all-space', None,
164 _('ignore white space when comparing lines')),
164 _('ignore white space when comparing lines')),
165 ('b', 'ignore-space-change', None,
165 ('b', 'ignore-space-change', None,
166 _('ignore changes in the amount of white space')),
166 _('ignore changes in the amount of white space')),
167 ('B', 'ignore-blank-lines', None,
167 ('B', 'ignore-blank-lines', None,
168 _('ignore changes whose lines are all blank')),
168 _('ignore changes whose lines are all blank')),
169 ]
169 ]
170
170
171 diffopts2 = [
171 diffopts2 = [
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
173 ('p', 'show-function', None, _('show which function each change is in')),
173 ('p', 'show-function', None, _('show which function each change is in')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
175 ] + diffwsopts + [
175 ] + diffwsopts + [
176 ('U', 'unified', '',
176 ('U', 'unified', '',
177 _('number of lines of context to show'), _('NUM')),
177 _('number of lines of context to show'), _('NUM')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
180 ]
180 ]
181
181
182 mergetoolopts = [
182 mergetoolopts = [
183 ('t', 'tool', '', _('specify merge tool')),
183 ('t', 'tool', '', _('specify merge tool')),
184 ]
184 ]
185
185
186 similarityopts = [
186 similarityopts = [
187 ('s', 'similarity', '',
187 ('s', 'similarity', '',
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
189 ]
189 ]
190
190
191 subrepoopts = [
191 subrepoopts = [
192 ('S', 'subrepos', None,
192 ('S', 'subrepos', None,
193 _('recurse into subrepositories'))
193 _('recurse into subrepositories'))
194 ]
194 ]
195
195
196 debugrevlogopts = [
196 debugrevlogopts = [
197 ('c', 'changelog', False, _('open changelog')),
197 ('c', 'changelog', False, _('open changelog')),
198 ('m', 'manifest', False, _('open manifest')),
198 ('m', 'manifest', False, _('open manifest')),
199 ('', 'dir', '', _('open directory manifest')),
199 ('', 'dir', '', _('open directory manifest')),
200 ]
200 ]
201
201
202 # Commands start here, listed alphabetically
202 # Commands start here, listed alphabetically
203
203
204 @command('^add',
204 @command('^add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _('[OPTION]... [FILE]...'),
206 _('[OPTION]... [FILE]...'),
207 inferrepo=True)
207 inferrepo=True)
208 def add(ui, repo, *pats, **opts):
208 def add(ui, repo, *pats, **opts):
209 """add the specified files on the next commit
209 """add the specified files on the next commit
210
210
211 Schedule files to be version controlled and added to the
211 Schedule files to be version controlled and added to the
212 repository.
212 repository.
213
213
214 The files will be added to the repository at the next commit. To
214 The files will be added to the repository at the next commit. To
215 undo an add before that, see :hg:`forget`.
215 undo an add before that, see :hg:`forget`.
216
216
217 If no names are given, add all files to the repository (except
217 If no names are given, add all files to the repository (except
218 files matching ``.hgignore``).
218 files matching ``.hgignore``).
219
219
220 .. container:: verbose
220 .. container:: verbose
221
221
222 Examples:
222 Examples:
223
223
224 - New (unknown) files are added
224 - New (unknown) files are added
225 automatically by :hg:`add`::
225 automatically by :hg:`add`::
226
226
227 $ ls
227 $ ls
228 foo.c
228 foo.c
229 $ hg status
229 $ hg status
230 ? foo.c
230 ? foo.c
231 $ hg add
231 $ hg add
232 adding foo.c
232 adding foo.c
233 $ hg status
233 $ hg status
234 A foo.c
234 A foo.c
235
235
236 - Specific files to be added can be specified::
236 - Specific files to be added can be specified::
237
237
238 $ ls
238 $ ls
239 bar.c foo.c
239 bar.c foo.c
240 $ hg status
240 $ hg status
241 ? bar.c
241 ? bar.c
242 ? foo.c
242 ? foo.c
243 $ hg add bar.c
243 $ hg add bar.c
244 $ hg status
244 $ hg status
245 A bar.c
245 A bar.c
246 ? foo.c
246 ? foo.c
247
247
248 Returns 0 if all files are successfully added.
248 Returns 0 if all files are successfully added.
249 """
249 """
250
250
251 m = scmutil.match(repo[None], pats, opts)
251 m = scmutil.match(repo[None], pats, opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
253 return rejected and 1 or 0
253 return rejected and 1 or 0
254
254
255 @command('addremove',
255 @command('addremove',
256 similarityopts + subrepoopts + walkopts + dryrunopts,
256 similarityopts + subrepoopts + walkopts + dryrunopts,
257 _('[OPTION]... [FILE]...'),
257 _('[OPTION]... [FILE]...'),
258 inferrepo=True)
258 inferrepo=True)
259 def addremove(ui, repo, *pats, **opts):
259 def addremove(ui, repo, *pats, **opts):
260 """add all new files, delete all missing files
260 """add all new files, delete all missing files
261
261
262 Add all new files and remove all missing files from the
262 Add all new files and remove all missing files from the
263 repository.
263 repository.
264
264
265 Unless names are given, new files are ignored if they match any of
265 Unless names are given, new files are ignored if they match any of
266 the patterns in ``.hgignore``. As with add, these changes take
266 the patterns in ``.hgignore``. As with add, these changes take
267 effect at the next commit.
267 effect at the next commit.
268
268
269 Use the -s/--similarity option to detect renamed files. This
269 Use the -s/--similarity option to detect renamed files. This
270 option takes a percentage between 0 (disabled) and 100 (files must
270 option takes a percentage between 0 (disabled) and 100 (files must
271 be identical) as its parameter. With a parameter greater than 0,
271 be identical) as its parameter. With a parameter greater than 0,
272 this compares every removed file with every added file and records
272 this compares every removed file with every added file and records
273 those similar enough as renames. Detecting renamed files this way
273 those similar enough as renames. Detecting renamed files this way
274 can be expensive. After using this option, :hg:`status -C` can be
274 can be expensive. After using this option, :hg:`status -C` can be
275 used to check which files were identified as moved or renamed. If
275 used to check which files were identified as moved or renamed. If
276 not specified, -s/--similarity defaults to 100 and only renames of
276 not specified, -s/--similarity defaults to 100 and only renames of
277 identical files are detected.
277 identical files are detected.
278
278
279 .. container:: verbose
279 .. container:: verbose
280
280
281 Examples:
281 Examples:
282
282
283 - A number of files (bar.c and foo.c) are new,
283 - A number of files (bar.c and foo.c) are new,
284 while foobar.c has been removed (without using :hg:`remove`)
284 while foobar.c has been removed (without using :hg:`remove`)
285 from the repository::
285 from the repository::
286
286
287 $ ls
287 $ ls
288 bar.c foo.c
288 bar.c foo.c
289 $ hg status
289 $ hg status
290 ! foobar.c
290 ! foobar.c
291 ? bar.c
291 ? bar.c
292 ? foo.c
292 ? foo.c
293 $ hg addremove
293 $ hg addremove
294 adding bar.c
294 adding bar.c
295 adding foo.c
295 adding foo.c
296 removing foobar.c
296 removing foobar.c
297 $ hg status
297 $ hg status
298 A bar.c
298 A bar.c
299 A foo.c
299 A foo.c
300 R foobar.c
300 R foobar.c
301
301
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
303 Afterwards, it was edited slightly::
303 Afterwards, it was edited slightly::
304
304
305 $ ls
305 $ ls
306 foo.c
306 foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? foo.c
309 ? foo.c
310 $ hg addremove --similarity 90
310 $ hg addremove --similarity 90
311 removing foobar.c
311 removing foobar.c
312 adding foo.c
312 adding foo.c
313 recording removal of foobar.c as rename to foo.c (94% similar)
313 recording removal of foobar.c as rename to foo.c (94% similar)
314 $ hg status -C
314 $ hg status -C
315 A foo.c
315 A foo.c
316 foobar.c
316 foobar.c
317 R foobar.c
317 R foobar.c
318
318
319 Returns 0 if all files are successfully added.
319 Returns 0 if all files are successfully added.
320 """
320 """
321 try:
321 try:
322 sim = float(opts.get('similarity') or 100)
322 sim = float(opts.get('similarity') or 100)
323 except ValueError:
323 except ValueError:
324 raise error.Abort(_('similarity must be a number'))
324 raise error.Abort(_('similarity must be a number'))
325 if sim < 0 or sim > 100:
325 if sim < 0 or sim > 100:
326 raise error.Abort(_('similarity must be between 0 and 100'))
326 raise error.Abort(_('similarity must be between 0 and 100'))
327 matcher = scmutil.match(repo[None], pats, opts)
327 matcher = scmutil.match(repo[None], pats, opts)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
329
329
330 @command('^annotate|blame',
330 @command('^annotate|blame',
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
332 ('', 'follow', None,
332 ('', 'follow', None,
333 _('follow copies/renames and list the filename (DEPRECATED)')),
333 _('follow copies/renames and list the filename (DEPRECATED)')),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
335 ('a', 'text', None, _('treat all files as text')),
335 ('a', 'text', None, _('treat all files as text')),
336 ('u', 'user', None, _('list the author (long with -v)')),
336 ('u', 'user', None, _('list the author (long with -v)')),
337 ('f', 'file', None, _('list the filename')),
337 ('f', 'file', None, _('list the filename')),
338 ('d', 'date', None, _('list the date (short with -q)')),
338 ('d', 'date', None, _('list the date (short with -q)')),
339 ('n', 'number', None, _('list the revision number (default)')),
339 ('n', 'number', None, _('list the revision number (default)')),
340 ('c', 'changeset', None, _('list the changeset')),
340 ('c', 'changeset', None, _('list the changeset')),
341 ('l', 'line-number', None, _('show line number at the first appearance'))
341 ('l', 'line-number', None, _('show line number at the first appearance'))
342 ] + diffwsopts + walkopts + formatteropts,
342 ] + diffwsopts + walkopts + formatteropts,
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
344 inferrepo=True)
344 inferrepo=True)
345 def annotate(ui, repo, *pats, **opts):
345 def annotate(ui, repo, *pats, **opts):
346 """show changeset information by line for each file
346 """show changeset information by line for each file
347
347
348 List changes in files, showing the revision id responsible for
348 List changes in files, showing the revision id responsible for
349 each line.
349 each line.
350
350
351 This command is useful for discovering when a change was made and
351 This command is useful for discovering when a change was made and
352 by whom.
352 by whom.
353
353
354 If you include --file, --user, or --date, the revision number is
354 If you include --file, --user, or --date, the revision number is
355 suppressed unless you also include --number.
355 suppressed unless you also include --number.
356
356
357 Without the -a/--text option, annotate will avoid processing files
357 Without the -a/--text option, annotate will avoid processing files
358 it detects as binary. With -a, annotate will annotate the file
358 it detects as binary. With -a, annotate will annotate the file
359 anyway, although the results will probably be neither useful
359 anyway, although the results will probably be neither useful
360 nor desirable.
360 nor desirable.
361
361
362 Returns 0 on success.
362 Returns 0 on success.
363 """
363 """
364 if not pats:
364 if not pats:
365 raise error.Abort(_('at least one filename or pattern is required'))
365 raise error.Abort(_('at least one filename or pattern is required'))
366
366
367 if opts.get('follow'):
367 if opts.get('follow'):
368 # --follow is deprecated and now just an alias for -f/--file
368 # --follow is deprecated and now just an alias for -f/--file
369 # to mimic the behavior of Mercurial before version 1.5
369 # to mimic the behavior of Mercurial before version 1.5
370 opts['file'] = True
370 opts['file'] = True
371
371
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
373
373
374 fm = ui.formatter('annotate', opts)
374 fm = ui.formatter('annotate', opts)
375 if ui.quiet:
375 if ui.quiet:
376 datefunc = util.shortdate
376 datefunc = util.shortdate
377 else:
377 else:
378 datefunc = util.datestr
378 datefunc = util.datestr
379 if ctx.rev() is None:
379 if ctx.rev() is None:
380 def hexfn(node):
380 def hexfn(node):
381 if node is None:
381 if node is None:
382 return None
382 return None
383 else:
383 else:
384 return fm.hexfunc(node)
384 return fm.hexfunc(node)
385 if opts.get('changeset'):
385 if opts.get('changeset'):
386 # omit "+" suffix which is appended to node hex
386 # omit "+" suffix which is appended to node hex
387 def formatrev(rev):
387 def formatrev(rev):
388 if rev is None:
388 if rev is None:
389 return '%d' % ctx.p1().rev()
389 return '%d' % ctx.p1().rev()
390 else:
390 else:
391 return '%d' % rev
391 return '%d' % rev
392 else:
392 else:
393 def formatrev(rev):
393 def formatrev(rev):
394 if rev is None:
394 if rev is None:
395 return '%d+' % ctx.p1().rev()
395 return '%d+' % ctx.p1().rev()
396 else:
396 else:
397 return '%d ' % rev
397 return '%d ' % rev
398 def formathex(hex):
398 def formathex(hex):
399 if hex is None:
399 if hex is None:
400 return '%s+' % fm.hexfunc(ctx.p1().node())
400 return '%s+' % fm.hexfunc(ctx.p1().node())
401 else:
401 else:
402 return '%s ' % hex
402 return '%s ' % hex
403 else:
403 else:
404 hexfn = fm.hexfunc
404 hexfn = fm.hexfunc
405 formatrev = formathex = str
405 formatrev = formathex = str
406
406
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
411 ('file', ' ', lambda x: x[0].path(), str),
411 ('file', ' ', lambda x: x[0].path(), str),
412 ('line_number', ':', lambda x: x[1], str),
412 ('line_number', ':', lambda x: x[1], str),
413 ]
413 ]
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
415
415
416 if (not opts.get('user') and not opts.get('changeset')
416 if (not opts.get('user') and not opts.get('changeset')
417 and not opts.get('date') and not opts.get('file')):
417 and not opts.get('date') and not opts.get('file')):
418 opts['number'] = True
418 opts['number'] = True
419
419
420 linenumber = opts.get('line_number') is not None
420 linenumber = opts.get('line_number') is not None
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
423
423
424 if fm.isplain():
424 if fm.isplain():
425 def makefunc(get, fmt):
425 def makefunc(get, fmt):
426 return lambda x: fmt(get(x))
426 return lambda x: fmt(get(x))
427 else:
427 else:
428 def makefunc(get, fmt):
428 def makefunc(get, fmt):
429 return get
429 return get
430 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
430 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
431 if opts.get(op)]
431 if opts.get(op)]
432 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
432 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
433 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
433 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
434 if opts.get(op))
434 if opts.get(op))
435
435
436 def bad(x, y):
436 def bad(x, y):
437 raise error.Abort("%s: %s" % (x, y))
437 raise error.Abort("%s: %s" % (x, y))
438
438
439 m = scmutil.match(ctx, pats, opts, badfn=bad)
439 m = scmutil.match(ctx, pats, opts, badfn=bad)
440
440
441 follow = not opts.get('no_follow')
441 follow = not opts.get('no_follow')
442 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
442 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
443 whitespace=True)
443 whitespace=True)
444 for abs in ctx.walk(m):
444 for abs in ctx.walk(m):
445 fctx = ctx[abs]
445 fctx = ctx[abs]
446 if not opts.get('text') and util.binary(fctx.data()):
446 if not opts.get('text') and util.binary(fctx.data()):
447 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
447 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
448 continue
448 continue
449
449
450 lines = fctx.annotate(follow=follow, linenumber=linenumber,
450 lines = fctx.annotate(follow=follow, linenumber=linenumber,
451 diffopts=diffopts)
451 diffopts=diffopts)
452 if not lines:
452 if not lines:
453 continue
453 continue
454 formats = []
454 formats = []
455 pieces = []
455 pieces = []
456
456
457 for f, sep in funcmap:
457 for f, sep in funcmap:
458 l = [f(n) for n, dummy in lines]
458 l = [f(n) for n, dummy in lines]
459 if fm.isplain():
459 if fm.isplain():
460 sizes = [encoding.colwidth(x) for x in l]
460 sizes = [encoding.colwidth(x) for x in l]
461 ml = max(sizes)
461 ml = max(sizes)
462 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
462 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
463 else:
463 else:
464 formats.append(['%s' for x in l])
464 formats.append(['%s' for x in l])
465 pieces.append(l)
465 pieces.append(l)
466
466
467 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
467 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
468 fm.startitem()
468 fm.startitem()
469 fm.write(fields, "".join(f), *p)
469 fm.write(fields, "".join(f), *p)
470 fm.write('line', ": %s", l[1])
470 fm.write('line', ": %s", l[1])
471
471
472 if not lines[-1][1].endswith('\n'):
472 if not lines[-1][1].endswith('\n'):
473 fm.plain('\n')
473 fm.plain('\n')
474
474
475 fm.end()
475 fm.end()
476
476
477 @command('archive',
477 @command('archive',
478 [('', 'no-decode', None, _('do not pass files through decoders')),
478 [('', 'no-decode', None, _('do not pass files through decoders')),
479 ('p', 'prefix', '', _('directory prefix for files in archive'),
479 ('p', 'prefix', '', _('directory prefix for files in archive'),
480 _('PREFIX')),
480 _('PREFIX')),
481 ('r', 'rev', '', _('revision to distribute'), _('REV')),
481 ('r', 'rev', '', _('revision to distribute'), _('REV')),
482 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
482 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
483 ] + subrepoopts + walkopts,
483 ] + subrepoopts + walkopts,
484 _('[OPTION]... DEST'))
484 _('[OPTION]... DEST'))
485 def archive(ui, repo, dest, **opts):
485 def archive(ui, repo, dest, **opts):
486 '''create an unversioned archive of a repository revision
486 '''create an unversioned archive of a repository revision
487
487
488 By default, the revision used is the parent of the working
488 By default, the revision used is the parent of the working
489 directory; use -r/--rev to specify a different revision.
489 directory; use -r/--rev to specify a different revision.
490
490
491 The archive type is automatically detected based on file
491 The archive type is automatically detected based on file
492 extension (to override, use -t/--type).
492 extension (to override, use -t/--type).
493
493
494 .. container:: verbose
494 .. container:: verbose
495
495
496 Examples:
496 Examples:
497
497
498 - create a zip file containing the 1.0 release::
498 - create a zip file containing the 1.0 release::
499
499
500 hg archive -r 1.0 project-1.0.zip
500 hg archive -r 1.0 project-1.0.zip
501
501
502 - create a tarball excluding .hg files::
502 - create a tarball excluding .hg files::
503
503
504 hg archive project.tar.gz -X ".hg*"
504 hg archive project.tar.gz -X ".hg*"
505
505
506 Valid types are:
506 Valid types are:
507
507
508 :``files``: a directory full of files (default)
508 :``files``: a directory full of files (default)
509 :``tar``: tar archive, uncompressed
509 :``tar``: tar archive, uncompressed
510 :``tbz2``: tar archive, compressed using bzip2
510 :``tbz2``: tar archive, compressed using bzip2
511 :``tgz``: tar archive, compressed using gzip
511 :``tgz``: tar archive, compressed using gzip
512 :``uzip``: zip archive, uncompressed
512 :``uzip``: zip archive, uncompressed
513 :``zip``: zip archive, compressed using deflate
513 :``zip``: zip archive, compressed using deflate
514
514
515 The exact name of the destination archive or directory is given
515 The exact name of the destination archive or directory is given
516 using a format string; see :hg:`help export` for details.
516 using a format string; see :hg:`help export` for details.
517
517
518 Each member added to an archive file has a directory prefix
518 Each member added to an archive file has a directory prefix
519 prepended. Use -p/--prefix to specify a format string for the
519 prepended. Use -p/--prefix to specify a format string for the
520 prefix. The default is the basename of the archive, with suffixes
520 prefix. The default is the basename of the archive, with suffixes
521 removed.
521 removed.
522
522
523 Returns 0 on success.
523 Returns 0 on success.
524 '''
524 '''
525
525
526 ctx = scmutil.revsingle(repo, opts.get('rev'))
526 ctx = scmutil.revsingle(repo, opts.get('rev'))
527 if not ctx:
527 if not ctx:
528 raise error.Abort(_('no working directory: please specify a revision'))
528 raise error.Abort(_('no working directory: please specify a revision'))
529 node = ctx.node()
529 node = ctx.node()
530 dest = cmdutil.makefilename(repo, dest, node)
530 dest = cmdutil.makefilename(repo, dest, node)
531 if os.path.realpath(dest) == repo.root:
531 if os.path.realpath(dest) == repo.root:
532 raise error.Abort(_('repository root cannot be destination'))
532 raise error.Abort(_('repository root cannot be destination'))
533
533
534 kind = opts.get('type') or archival.guesskind(dest) or 'files'
534 kind = opts.get('type') or archival.guesskind(dest) or 'files'
535 prefix = opts.get('prefix')
535 prefix = opts.get('prefix')
536
536
537 if dest == '-':
537 if dest == '-':
538 if kind == 'files':
538 if kind == 'files':
539 raise error.Abort(_('cannot archive plain files to stdout'))
539 raise error.Abort(_('cannot archive plain files to stdout'))
540 dest = cmdutil.makefileobj(repo, dest)
540 dest = cmdutil.makefileobj(repo, dest)
541 if not prefix:
541 if not prefix:
542 prefix = os.path.basename(repo.root) + '-%h'
542 prefix = os.path.basename(repo.root) + '-%h'
543
543
544 prefix = cmdutil.makefilename(repo, prefix, node)
544 prefix = cmdutil.makefilename(repo, prefix, node)
545 matchfn = scmutil.match(ctx, [], opts)
545 matchfn = scmutil.match(ctx, [], opts)
546 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
546 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
547 matchfn, prefix, subrepos=opts.get('subrepos'))
547 matchfn, prefix, subrepos=opts.get('subrepos'))
548
548
549 @command('backout',
549 @command('backout',
550 [('', 'merge', None, _('merge with old dirstate parent after backout')),
550 [('', 'merge', None, _('merge with old dirstate parent after backout')),
551 ('', 'commit', None,
551 ('', 'commit', None,
552 _('commit if no conflicts were encountered (DEPRECATED)')),
552 _('commit if no conflicts were encountered (DEPRECATED)')),
553 ('', 'no-commit', None, _('do not commit')),
553 ('', 'no-commit', None, _('do not commit')),
554 ('', 'parent', '',
554 ('', 'parent', '',
555 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
555 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
556 ('r', 'rev', '', _('revision to backout'), _('REV')),
556 ('r', 'rev', '', _('revision to backout'), _('REV')),
557 ('e', 'edit', False, _('invoke editor on commit messages')),
557 ('e', 'edit', False, _('invoke editor on commit messages')),
558 ] + mergetoolopts + walkopts + commitopts + commitopts2,
558 ] + mergetoolopts + walkopts + commitopts + commitopts2,
559 _('[OPTION]... [-r] REV'))
559 _('[OPTION]... [-r] REV'))
560 def backout(ui, repo, node=None, rev=None, **opts):
560 def backout(ui, repo, node=None, rev=None, **opts):
561 '''reverse effect of earlier changeset
561 '''reverse effect of earlier changeset
562
562
563 Prepare a new changeset with the effect of REV undone in the
563 Prepare a new changeset with the effect of REV undone in the
564 current working directory. If no conflicts were encountered,
564 current working directory. If no conflicts were encountered,
565 it will be committed immediately.
565 it will be committed immediately.
566
566
567 If REV is the parent of the working directory, then this new changeset
567 If REV is the parent of the working directory, then this new changeset
568 is committed automatically (unless --no-commit is specified).
568 is committed automatically (unless --no-commit is specified).
569
569
570 .. note::
570 .. note::
571
571
572 :hg:`backout` cannot be used to fix either an unwanted or
572 :hg:`backout` cannot be used to fix either an unwanted or
573 incorrect merge.
573 incorrect merge.
574
574
575 .. container:: verbose
575 .. container:: verbose
576
576
577 Examples:
577 Examples:
578
578
579 - Reverse the effect of the parent of the working directory.
579 - Reverse the effect of the parent of the working directory.
580 This backout will be committed immediately::
580 This backout will be committed immediately::
581
581
582 hg backout -r .
582 hg backout -r .
583
583
584 - Reverse the effect of previous bad revision 23::
584 - Reverse the effect of previous bad revision 23::
585
585
586 hg backout -r 23
586 hg backout -r 23
587
587
588 - Reverse the effect of previous bad revision 23 and
588 - Reverse the effect of previous bad revision 23 and
589 leave changes uncommitted::
589 leave changes uncommitted::
590
590
591 hg backout -r 23 --no-commit
591 hg backout -r 23 --no-commit
592 hg commit -m "Backout revision 23"
592 hg commit -m "Backout revision 23"
593
593
594 By default, the pending changeset will have one parent,
594 By default, the pending changeset will have one parent,
595 maintaining a linear history. With --merge, the pending
595 maintaining a linear history. With --merge, the pending
596 changeset will instead have two parents: the old parent of the
596 changeset will instead have two parents: the old parent of the
597 working directory and a new child of REV that simply undoes REV.
597 working directory and a new child of REV that simply undoes REV.
598
598
599 Before version 1.7, the behavior without --merge was equivalent
599 Before version 1.7, the behavior without --merge was equivalent
600 to specifying --merge followed by :hg:`update --clean .` to
600 to specifying --merge followed by :hg:`update --clean .` to
601 cancel the merge and leave the child of REV as a head to be
601 cancel the merge and leave the child of REV as a head to be
602 merged separately.
602 merged separately.
603
603
604 See :hg:`help dates` for a list of formats valid for -d/--date.
604 See :hg:`help dates` for a list of formats valid for -d/--date.
605
605
606 See :hg:`help revert` for a way to restore files to the state
606 See :hg:`help revert` for a way to restore files to the state
607 of another revision.
607 of another revision.
608
608
609 Returns 0 on success, 1 if nothing to backout or there are unresolved
609 Returns 0 on success, 1 if nothing to backout or there are unresolved
610 files.
610 files.
611 '''
611 '''
612 wlock = lock = None
612 wlock = lock = None
613 try:
613 try:
614 wlock = repo.wlock()
614 wlock = repo.wlock()
615 lock = repo.lock()
615 lock = repo.lock()
616 return _dobackout(ui, repo, node, rev, **opts)
616 return _dobackout(ui, repo, node, rev, **opts)
617 finally:
617 finally:
618 release(lock, wlock)
618 release(lock, wlock)
619
619
620 def _dobackout(ui, repo, node=None, rev=None, **opts):
620 def _dobackout(ui, repo, node=None, rev=None, **opts):
621 if opts.get('commit') and opts.get('no_commit'):
621 if opts.get('commit') and opts.get('no_commit'):
622 raise error.Abort(_("cannot use --commit with --no-commit"))
622 raise error.Abort(_("cannot use --commit with --no-commit"))
623 if opts.get('merge') and opts.get('no_commit'):
623 if opts.get('merge') and opts.get('no_commit'):
624 raise error.Abort(_("cannot use --merge with --no-commit"))
624 raise error.Abort(_("cannot use --merge with --no-commit"))
625
625
626 if rev and node:
626 if rev and node:
627 raise error.Abort(_("please specify just one revision"))
627 raise error.Abort(_("please specify just one revision"))
628
628
629 if not rev:
629 if not rev:
630 rev = node
630 rev = node
631
631
632 if not rev:
632 if not rev:
633 raise error.Abort(_("please specify a revision to backout"))
633 raise error.Abort(_("please specify a revision to backout"))
634
634
635 date = opts.get('date')
635 date = opts.get('date')
636 if date:
636 if date:
637 opts['date'] = util.parsedate(date)
637 opts['date'] = util.parsedate(date)
638
638
639 cmdutil.checkunfinished(repo)
639 cmdutil.checkunfinished(repo)
640 cmdutil.bailifchanged(repo)
640 cmdutil.bailifchanged(repo)
641 node = scmutil.revsingle(repo, rev).node()
641 node = scmutil.revsingle(repo, rev).node()
642
642
643 op1, op2 = repo.dirstate.parents()
643 op1, op2 = repo.dirstate.parents()
644 if not repo.changelog.isancestor(node, op1):
644 if not repo.changelog.isancestor(node, op1):
645 raise error.Abort(_('cannot backout change that is not an ancestor'))
645 raise error.Abort(_('cannot backout change that is not an ancestor'))
646
646
647 p1, p2 = repo.changelog.parents(node)
647 p1, p2 = repo.changelog.parents(node)
648 if p1 == nullid:
648 if p1 == nullid:
649 raise error.Abort(_('cannot backout a change with no parents'))
649 raise error.Abort(_('cannot backout a change with no parents'))
650 if p2 != nullid:
650 if p2 != nullid:
651 if not opts.get('parent'):
651 if not opts.get('parent'):
652 raise error.Abort(_('cannot backout a merge changeset'))
652 raise error.Abort(_('cannot backout a merge changeset'))
653 p = repo.lookup(opts['parent'])
653 p = repo.lookup(opts['parent'])
654 if p not in (p1, p2):
654 if p not in (p1, p2):
655 raise error.Abort(_('%s is not a parent of %s') %
655 raise error.Abort(_('%s is not a parent of %s') %
656 (short(p), short(node)))
656 (short(p), short(node)))
657 parent = p
657 parent = p
658 else:
658 else:
659 if opts.get('parent'):
659 if opts.get('parent'):
660 raise error.Abort(_('cannot use --parent on non-merge changeset'))
660 raise error.Abort(_('cannot use --parent on non-merge changeset'))
661 parent = p1
661 parent = p1
662
662
663 # the backout should appear on the same branch
663 # the backout should appear on the same branch
664 branch = repo.dirstate.branch()
664 branch = repo.dirstate.branch()
665 bheads = repo.branchheads(branch)
665 bheads = repo.branchheads(branch)
666 rctx = scmutil.revsingle(repo, hex(parent))
666 rctx = scmutil.revsingle(repo, hex(parent))
667 if not opts.get('merge') and op1 != node:
667 if not opts.get('merge') and op1 != node:
668 dsguard = dirstateguard.dirstateguard(repo, 'backout')
668 dsguard = dirstateguard.dirstateguard(repo, 'backout')
669 try:
669 try:
670 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
670 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 'backout')
671 'backout')
672 stats = mergemod.update(repo, parent, True, True, node, False)
672 stats = mergemod.update(repo, parent, True, True, node, False)
673 repo.setparents(op1, op2)
673 repo.setparents(op1, op2)
674 dsguard.close()
674 dsguard.close()
675 hg._showstats(repo, stats)
675 hg._showstats(repo, stats)
676 if stats[3]:
676 if stats[3]:
677 repo.ui.status(_("use 'hg resolve' to retry unresolved "
677 repo.ui.status(_("use 'hg resolve' to retry unresolved "
678 "file merges\n"))
678 "file merges\n"))
679 return 1
679 return 1
680 finally:
680 finally:
681 ui.setconfig('ui', 'forcemerge', '', '')
681 ui.setconfig('ui', 'forcemerge', '', '')
682 lockmod.release(dsguard)
682 lockmod.release(dsguard)
683 else:
683 else:
684 hg.clean(repo, node, show_stats=False)
684 hg.clean(repo, node, show_stats=False)
685 repo.dirstate.setbranch(branch)
685 repo.dirstate.setbranch(branch)
686 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
686 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
687
687
688 if opts.get('no_commit'):
688 if opts.get('no_commit'):
689 msg = _("changeset %s backed out, "
689 msg = _("changeset %s backed out, "
690 "don't forget to commit.\n")
690 "don't forget to commit.\n")
691 ui.status(msg % short(node))
691 ui.status(msg % short(node))
692 return 0
692 return 0
693
693
694 def commitfunc(ui, repo, message, match, opts):
694 def commitfunc(ui, repo, message, match, opts):
695 editform = 'backout'
695 editform = 'backout'
696 e = cmdutil.getcommiteditor(editform=editform, **opts)
696 e = cmdutil.getcommiteditor(editform=editform, **opts)
697 if not message:
697 if not message:
698 # we don't translate commit messages
698 # we don't translate commit messages
699 message = "Backed out changeset %s" % short(node)
699 message = "Backed out changeset %s" % short(node)
700 e = cmdutil.getcommiteditor(edit=True, editform=editform)
700 e = cmdutil.getcommiteditor(edit=True, editform=editform)
701 return repo.commit(message, opts.get('user'), opts.get('date'),
701 return repo.commit(message, opts.get('user'), opts.get('date'),
702 match, editor=e)
702 match, editor=e)
703 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
703 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
704 if not newnode:
704 if not newnode:
705 ui.status(_("nothing changed\n"))
705 ui.status(_("nothing changed\n"))
706 return 1
706 return 1
707 cmdutil.commitstatus(repo, newnode, branch, bheads)
707 cmdutil.commitstatus(repo, newnode, branch, bheads)
708
708
709 def nice(node):
709 def nice(node):
710 return '%d:%s' % (repo.changelog.rev(node), short(node))
710 return '%d:%s' % (repo.changelog.rev(node), short(node))
711 ui.status(_('changeset %s backs out changeset %s\n') %
711 ui.status(_('changeset %s backs out changeset %s\n') %
712 (nice(repo.changelog.tip()), nice(node)))
712 (nice(repo.changelog.tip()), nice(node)))
713 if opts.get('merge') and op1 != node:
713 if opts.get('merge') and op1 != node:
714 hg.clean(repo, op1, show_stats=False)
714 hg.clean(repo, op1, show_stats=False)
715 ui.status(_('merging with changeset %s\n')
715 ui.status(_('merging with changeset %s\n')
716 % nice(repo.changelog.tip()))
716 % nice(repo.changelog.tip()))
717 try:
717 try:
718 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
718 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
719 'backout')
719 'backout')
720 return hg.merge(repo, hex(repo.changelog.tip()))
720 return hg.merge(repo, hex(repo.changelog.tip()))
721 finally:
721 finally:
722 ui.setconfig('ui', 'forcemerge', '', '')
722 ui.setconfig('ui', 'forcemerge', '', '')
723 return 0
723 return 0
724
724
725 @command('bisect',
725 @command('bisect',
726 [('r', 'reset', False, _('reset bisect state')),
726 [('r', 'reset', False, _('reset bisect state')),
727 ('g', 'good', False, _('mark changeset good')),
727 ('g', 'good', False, _('mark changeset good')),
728 ('b', 'bad', False, _('mark changeset bad')),
728 ('b', 'bad', False, _('mark changeset bad')),
729 ('s', 'skip', False, _('skip testing changeset')),
729 ('s', 'skip', False, _('skip testing changeset')),
730 ('e', 'extend', False, _('extend the bisect range')),
730 ('e', 'extend', False, _('extend the bisect range')),
731 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
731 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
732 ('U', 'noupdate', False, _('do not update to target'))],
732 ('U', 'noupdate', False, _('do not update to target'))],
733 _("[-gbsr] [-U] [-c CMD] [REV]"))
733 _("[-gbsr] [-U] [-c CMD] [REV]"))
734 def bisect(ui, repo, rev=None, extra=None, command=None,
734 def bisect(ui, repo, rev=None, extra=None, command=None,
735 reset=None, good=None, bad=None, skip=None, extend=None,
735 reset=None, good=None, bad=None, skip=None, extend=None,
736 noupdate=None):
736 noupdate=None):
737 """subdivision search of changesets
737 """subdivision search of changesets
738
738
739 This command helps to find changesets which introduce problems. To
739 This command helps to find changesets which introduce problems. To
740 use, mark the earliest changeset you know exhibits the problem as
740 use, mark the earliest changeset you know exhibits the problem as
741 bad, then mark the latest changeset which is free from the problem
741 bad, then mark the latest changeset which is free from the problem
742 as good. Bisect will update your working directory to a revision
742 as good. Bisect will update your working directory to a revision
743 for testing (unless the -U/--noupdate option is specified). Once
743 for testing (unless the -U/--noupdate option is specified). Once
744 you have performed tests, mark the working directory as good or
744 you have performed tests, mark the working directory as good or
745 bad, and bisect will either update to another candidate changeset
745 bad, and bisect will either update to another candidate changeset
746 or announce that it has found the bad revision.
746 or announce that it has found the bad revision.
747
747
748 As a shortcut, you can also use the revision argument to mark a
748 As a shortcut, you can also use the revision argument to mark a
749 revision as good or bad without checking it out first.
749 revision as good or bad without checking it out first.
750
750
751 If you supply a command, it will be used for automatic bisection.
751 If you supply a command, it will be used for automatic bisection.
752 The environment variable HG_NODE will contain the ID of the
752 The environment variable HG_NODE will contain the ID of the
753 changeset being tested. The exit status of the command will be
753 changeset being tested. The exit status of the command will be
754 used to mark revisions as good or bad: status 0 means good, 125
754 used to mark revisions as good or bad: status 0 means good, 125
755 means to skip the revision, 127 (command not found) will abort the
755 means to skip the revision, 127 (command not found) will abort the
756 bisection, and any other non-zero exit status means the revision
756 bisection, and any other non-zero exit status means the revision
757 is bad.
757 is bad.
758
758
759 .. container:: verbose
759 .. container:: verbose
760
760
761 Some examples:
761 Some examples:
762
762
763 - start a bisection with known bad revision 34, and good revision 12::
763 - start a bisection with known bad revision 34, and good revision 12::
764
764
765 hg bisect --bad 34
765 hg bisect --bad 34
766 hg bisect --good 12
766 hg bisect --good 12
767
767
768 - advance the current bisection by marking current revision as good or
768 - advance the current bisection by marking current revision as good or
769 bad::
769 bad::
770
770
771 hg bisect --good
771 hg bisect --good
772 hg bisect --bad
772 hg bisect --bad
773
773
774 - mark the current revision, or a known revision, to be skipped (e.g. if
774 - mark the current revision, or a known revision, to be skipped (e.g. if
775 that revision is not usable because of another issue)::
775 that revision is not usable because of another issue)::
776
776
777 hg bisect --skip
777 hg bisect --skip
778 hg bisect --skip 23
778 hg bisect --skip 23
779
779
780 - skip all revisions that do not touch directories ``foo`` or ``bar``::
780 - skip all revisions that do not touch directories ``foo`` or ``bar``::
781
781
782 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
782 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
783
783
784 - forget the current bisection::
784 - forget the current bisection::
785
785
786 hg bisect --reset
786 hg bisect --reset
787
787
788 - use 'make && make tests' to automatically find the first broken
788 - use 'make && make tests' to automatically find the first broken
789 revision::
789 revision::
790
790
791 hg bisect --reset
791 hg bisect --reset
792 hg bisect --bad 34
792 hg bisect --bad 34
793 hg bisect --good 12
793 hg bisect --good 12
794 hg bisect --command "make && make tests"
794 hg bisect --command "make && make tests"
795
795
796 - see all changesets whose states are already known in the current
796 - see all changesets whose states are already known in the current
797 bisection::
797 bisection::
798
798
799 hg log -r "bisect(pruned)"
799 hg log -r "bisect(pruned)"
800
800
801 - see the changeset currently being bisected (especially useful
801 - see the changeset currently being bisected (especially useful
802 if running with -U/--noupdate)::
802 if running with -U/--noupdate)::
803
803
804 hg log -r "bisect(current)"
804 hg log -r "bisect(current)"
805
805
806 - see all changesets that took part in the current bisection::
806 - see all changesets that took part in the current bisection::
807
807
808 hg log -r "bisect(range)"
808 hg log -r "bisect(range)"
809
809
810 - you can even get a nice graph::
810 - you can even get a nice graph::
811
811
812 hg log --graph -r "bisect(range)"
812 hg log --graph -r "bisect(range)"
813
813
814 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
814 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
815
815
816 Returns 0 on success.
816 Returns 0 on success.
817 """
817 """
818 # backward compatibility
818 # backward compatibility
819 if rev in "good bad reset init".split():
819 if rev in "good bad reset init".split():
820 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
820 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
821 cmd, rev, extra = rev, extra, None
821 cmd, rev, extra = rev, extra, None
822 if cmd == "good":
822 if cmd == "good":
823 good = True
823 good = True
824 elif cmd == "bad":
824 elif cmd == "bad":
825 bad = True
825 bad = True
826 else:
826 else:
827 reset = True
827 reset = True
828 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
828 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
829 raise error.Abort(_('incompatible arguments'))
829 raise error.Abort(_('incompatible arguments'))
830
830
831 cmdutil.checkunfinished(repo)
831 cmdutil.checkunfinished(repo)
832
832
833 if reset:
833 if reset:
834 hbisect.resetstate(repo)
834 hbisect.resetstate(repo)
835 return
835 return
836
836
837 state = hbisect.load_state(repo)
837 state = hbisect.load_state(repo)
838
838
839 # update state
839 # update state
840 if good or bad or skip:
840 if good or bad or skip:
841 if rev:
841 if rev:
842 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
842 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
843 else:
843 else:
844 nodes = [repo.lookup('.')]
844 nodes = [repo.lookup('.')]
845 if good:
845 if good:
846 state['good'] += nodes
846 state['good'] += nodes
847 elif bad:
847 elif bad:
848 state['bad'] += nodes
848 state['bad'] += nodes
849 elif skip:
849 elif skip:
850 state['skip'] += nodes
850 state['skip'] += nodes
851 hbisect.save_state(repo, state)
851 hbisect.save_state(repo, state)
852 if not (state['good'] and state['bad']):
852 if not (state['good'] and state['bad']):
853 return
853 return
854
854
855 def mayupdate(repo, node, show_stats=True):
855 def mayupdate(repo, node, show_stats=True):
856 """common used update sequence"""
856 """common used update sequence"""
857 if noupdate:
857 if noupdate:
858 return
858 return
859 cmdutil.bailifchanged(repo)
859 cmdutil.bailifchanged(repo)
860 return hg.clean(repo, node, show_stats=show_stats)
860 return hg.clean(repo, node, show_stats=show_stats)
861
861
862 displayer = cmdutil.show_changeset(ui, repo, {})
862 displayer = cmdutil.show_changeset(ui, repo, {})
863
863
864 if command:
864 if command:
865 changesets = 1
865 changesets = 1
866 if noupdate:
866 if noupdate:
867 try:
867 try:
868 node = state['current'][0]
868 node = state['current'][0]
869 except LookupError:
869 except LookupError:
870 raise error.Abort(_('current bisect revision is unknown - '
870 raise error.Abort(_('current bisect revision is unknown - '
871 'start a new bisect to fix'))
871 'start a new bisect to fix'))
872 else:
872 else:
873 node, p2 = repo.dirstate.parents()
873 node, p2 = repo.dirstate.parents()
874 if p2 != nullid:
874 if p2 != nullid:
875 raise error.Abort(_('current bisect revision is a merge'))
875 raise error.Abort(_('current bisect revision is a merge'))
876 if rev:
876 if rev:
877 node = repo[scmutil.revsingle(repo, rev, node)].node()
877 node = repo[scmutil.revsingle(repo, rev, node)].node()
878 try:
878 try:
879 while changesets:
879 while changesets:
880 # update state
880 # update state
881 state['current'] = [node]
881 state['current'] = [node]
882 hbisect.save_state(repo, state)
882 hbisect.save_state(repo, state)
883 status = ui.system(command, environ={'HG_NODE': hex(node)})
883 status = ui.system(command, environ={'HG_NODE': hex(node)})
884 if status == 125:
884 if status == 125:
885 transition = "skip"
885 transition = "skip"
886 elif status == 0:
886 elif status == 0:
887 transition = "good"
887 transition = "good"
888 # status < 0 means process was killed
888 # status < 0 means process was killed
889 elif status == 127:
889 elif status == 127:
890 raise error.Abort(_("failed to execute %s") % command)
890 raise error.Abort(_("failed to execute %s") % command)
891 elif status < 0:
891 elif status < 0:
892 raise error.Abort(_("%s killed") % command)
892 raise error.Abort(_("%s killed") % command)
893 else:
893 else:
894 transition = "bad"
894 transition = "bad"
895 state[transition].append(node)
895 state[transition].append(node)
896 ctx = repo[node]
896 ctx = repo[node]
897 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
897 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
898 hbisect.checkstate(state)
898 hbisect.checkstate(state)
899 # bisect
899 # bisect
900 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
900 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
901 # update to next check
901 # update to next check
902 node = nodes[0]
902 node = nodes[0]
903 mayupdate(repo, node, show_stats=False)
903 mayupdate(repo, node, show_stats=False)
904 finally:
904 finally:
905 state['current'] = [node]
905 state['current'] = [node]
906 hbisect.save_state(repo, state)
906 hbisect.save_state(repo, state)
907 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
907 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
908 return
908 return
909
909
910 hbisect.checkstate(state)
910 hbisect.checkstate(state)
911
911
912 # actually bisect
912 # actually bisect
913 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
913 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
914 if extend:
914 if extend:
915 if not changesets:
915 if not changesets:
916 extendnode = hbisect.extendrange(repo, state, nodes, good)
916 extendnode = hbisect.extendrange(repo, state, nodes, good)
917 if extendnode is not None:
917 if extendnode is not None:
918 ui.write(_("Extending search to changeset %d:%s\n")
918 ui.write(_("Extending search to changeset %d:%s\n")
919 % (extendnode.rev(), extendnode))
919 % (extendnode.rev(), extendnode))
920 state['current'] = [extendnode.node()]
920 state['current'] = [extendnode.node()]
921 hbisect.save_state(repo, state)
921 hbisect.save_state(repo, state)
922 return mayupdate(repo, extendnode.node())
922 return mayupdate(repo, extendnode.node())
923 raise error.Abort(_("nothing to extend"))
923 raise error.Abort(_("nothing to extend"))
924
924
925 if changesets == 0:
925 if changesets == 0:
926 hbisect.printresult(ui, repo, state, displayer, nodes, good)
926 hbisect.printresult(ui, repo, state, displayer, nodes, good)
927 else:
927 else:
928 assert len(nodes) == 1 # only a single node can be tested next
928 assert len(nodes) == 1 # only a single node can be tested next
929 node = nodes[0]
929 node = nodes[0]
930 # compute the approximate number of remaining tests
930 # compute the approximate number of remaining tests
931 tests, size = 0, 2
931 tests, size = 0, 2
932 while size <= changesets:
932 while size <= changesets:
933 tests, size = tests + 1, size * 2
933 tests, size = tests + 1, size * 2
934 rev = repo.changelog.rev(node)
934 rev = repo.changelog.rev(node)
935 ui.write(_("Testing changeset %d:%s "
935 ui.write(_("Testing changeset %d:%s "
936 "(%d changesets remaining, ~%d tests)\n")
936 "(%d changesets remaining, ~%d tests)\n")
937 % (rev, short(node), changesets, tests))
937 % (rev, short(node), changesets, tests))
938 state['current'] = [node]
938 state['current'] = [node]
939 hbisect.save_state(repo, state)
939 hbisect.save_state(repo, state)
940 return mayupdate(repo, node)
940 return mayupdate(repo, node)
941
941
942 @command('bookmarks|bookmark',
942 @command('bookmarks|bookmark',
943 [('f', 'force', False, _('force')),
943 [('f', 'force', False, _('force')),
944 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
944 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
945 ('d', 'delete', False, _('delete a given bookmark')),
945 ('d', 'delete', False, _('delete a given bookmark')),
946 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
946 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
947 ('i', 'inactive', False, _('mark a bookmark inactive')),
947 ('i', 'inactive', False, _('mark a bookmark inactive')),
948 ] + formatteropts,
948 ] + formatteropts,
949 _('hg bookmarks [OPTIONS]... [NAME]...'))
949 _('hg bookmarks [OPTIONS]... [NAME]...'))
950 def bookmark(ui, repo, *names, **opts):
950 def bookmark(ui, repo, *names, **opts):
951 '''create a new bookmark or list existing bookmarks
951 '''create a new bookmark or list existing bookmarks
952
952
953 Bookmarks are labels on changesets to help track lines of development.
953 Bookmarks are labels on changesets to help track lines of development.
954 Bookmarks are unversioned and can be moved, renamed and deleted.
954 Bookmarks are unversioned and can be moved, renamed and deleted.
955 Deleting or moving a bookmark has no effect on the associated changesets.
955 Deleting or moving a bookmark has no effect on the associated changesets.
956
956
957 Creating or updating to a bookmark causes it to be marked as 'active'.
957 Creating or updating to a bookmark causes it to be marked as 'active'.
958 The active bookmark is indicated with a '*'.
958 The active bookmark is indicated with a '*'.
959 When a commit is made, the active bookmark will advance to the new commit.
959 When a commit is made, the active bookmark will advance to the new commit.
960 A plain :hg:`update` will also advance an active bookmark, if possible.
960 A plain :hg:`update` will also advance an active bookmark, if possible.
961 Updating away from a bookmark will cause it to be deactivated.
961 Updating away from a bookmark will cause it to be deactivated.
962
962
963 Bookmarks can be pushed and pulled between repositories (see
963 Bookmarks can be pushed and pulled between repositories (see
964 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
964 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
965 diverged, a new 'divergent bookmark' of the form 'name@path' will
965 diverged, a new 'divergent bookmark' of the form 'name@path' will
966 be created. Using :hg:`merge` will resolve the divergence.
966 be created. Using :hg:`merge` will resolve the divergence.
967
967
968 A bookmark named '@' has the special property that :hg:`clone` will
968 A bookmark named '@' has the special property that :hg:`clone` will
969 check it out by default if it exists.
969 check it out by default if it exists.
970
970
971 .. container:: verbose
971 .. container:: verbose
972
972
973 Examples:
973 Examples:
974
974
975 - create an active bookmark for a new line of development::
975 - create an active bookmark for a new line of development::
976
976
977 hg book new-feature
977 hg book new-feature
978
978
979 - create an inactive bookmark as a place marker::
979 - create an inactive bookmark as a place marker::
980
980
981 hg book -i reviewed
981 hg book -i reviewed
982
982
983 - create an inactive bookmark on another changeset::
983 - create an inactive bookmark on another changeset::
984
984
985 hg book -r .^ tested
985 hg book -r .^ tested
986
986
987 - rename bookmark turkey to dinner::
987 - rename bookmark turkey to dinner::
988
988
989 hg book -m turkey dinner
989 hg book -m turkey dinner
990
990
991 - move the '@' bookmark from another branch::
991 - move the '@' bookmark from another branch::
992
992
993 hg book -f @
993 hg book -f @
994 '''
994 '''
995 force = opts.get('force')
995 force = opts.get('force')
996 rev = opts.get('rev')
996 rev = opts.get('rev')
997 delete = opts.get('delete')
997 delete = opts.get('delete')
998 rename = opts.get('rename')
998 rename = opts.get('rename')
999 inactive = opts.get('inactive')
999 inactive = opts.get('inactive')
1000
1000
1001 def checkformat(mark):
1001 def checkformat(mark):
1002 mark = mark.strip()
1002 mark = mark.strip()
1003 if not mark:
1003 if not mark:
1004 raise error.Abort(_("bookmark names cannot consist entirely of "
1004 raise error.Abort(_("bookmark names cannot consist entirely of "
1005 "whitespace"))
1005 "whitespace"))
1006 scmutil.checknewlabel(repo, mark, 'bookmark')
1006 scmutil.checknewlabel(repo, mark, 'bookmark')
1007 return mark
1007 return mark
1008
1008
1009 def checkconflict(repo, mark, cur, force=False, target=None):
1009 def checkconflict(repo, mark, cur, force=False, target=None):
1010 if mark in marks and not force:
1010 if mark in marks and not force:
1011 if target:
1011 if target:
1012 if marks[mark] == target and target == cur:
1012 if marks[mark] == target and target == cur:
1013 # re-activating a bookmark
1013 # re-activating a bookmark
1014 return
1014 return
1015 anc = repo.changelog.ancestors([repo[target].rev()])
1015 anc = repo.changelog.ancestors([repo[target].rev()])
1016 bmctx = repo[marks[mark]]
1016 bmctx = repo[marks[mark]]
1017 divs = [repo[b].node() for b in marks
1017 divs = [repo[b].node() for b in marks
1018 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1018 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1019
1019
1020 # allow resolving a single divergent bookmark even if moving
1020 # allow resolving a single divergent bookmark even if moving
1021 # the bookmark across branches when a revision is specified
1021 # the bookmark across branches when a revision is specified
1022 # that contains a divergent bookmark
1022 # that contains a divergent bookmark
1023 if bmctx.rev() not in anc and target in divs:
1023 if bmctx.rev() not in anc and target in divs:
1024 bookmarks.deletedivergent(repo, [target], mark)
1024 bookmarks.deletedivergent(repo, [target], mark)
1025 return
1025 return
1026
1026
1027 deletefrom = [b for b in divs
1027 deletefrom = [b for b in divs
1028 if repo[b].rev() in anc or b == target]
1028 if repo[b].rev() in anc or b == target]
1029 bookmarks.deletedivergent(repo, deletefrom, mark)
1029 bookmarks.deletedivergent(repo, deletefrom, mark)
1030 if bookmarks.validdest(repo, bmctx, repo[target]):
1030 if bookmarks.validdest(repo, bmctx, repo[target]):
1031 ui.status(_("moving bookmark '%s' forward from %s\n") %
1031 ui.status(_("moving bookmark '%s' forward from %s\n") %
1032 (mark, short(bmctx.node())))
1032 (mark, short(bmctx.node())))
1033 return
1033 return
1034 raise error.Abort(_("bookmark '%s' already exists "
1034 raise error.Abort(_("bookmark '%s' already exists "
1035 "(use -f to force)") % mark)
1035 "(use -f to force)") % mark)
1036 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1036 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1037 and not force):
1037 and not force):
1038 raise error.Abort(
1038 raise error.Abort(
1039 _("a bookmark cannot have the name of an existing branch"))
1039 _("a bookmark cannot have the name of an existing branch"))
1040
1040
1041 if delete and rename:
1041 if delete and rename:
1042 raise error.Abort(_("--delete and --rename are incompatible"))
1042 raise error.Abort(_("--delete and --rename are incompatible"))
1043 if delete and rev:
1043 if delete and rev:
1044 raise error.Abort(_("--rev is incompatible with --delete"))
1044 raise error.Abort(_("--rev is incompatible with --delete"))
1045 if rename and rev:
1045 if rename and rev:
1046 raise error.Abort(_("--rev is incompatible with --rename"))
1046 raise error.Abort(_("--rev is incompatible with --rename"))
1047 if not names and (delete or rev):
1047 if not names and (delete or rev):
1048 raise error.Abort(_("bookmark name required"))
1048 raise error.Abort(_("bookmark name required"))
1049
1049
1050 if delete or rename or names or inactive:
1050 if delete or rename or names or inactive:
1051 wlock = lock = tr = None
1051 wlock = lock = tr = None
1052 try:
1052 try:
1053 wlock = repo.wlock()
1053 wlock = repo.wlock()
1054 lock = repo.lock()
1054 lock = repo.lock()
1055 cur = repo.changectx('.').node()
1055 cur = repo.changectx('.').node()
1056 marks = repo._bookmarks
1056 marks = repo._bookmarks
1057 if delete:
1057 if delete:
1058 tr = repo.transaction('bookmark')
1058 tr = repo.transaction('bookmark')
1059 for mark in names:
1059 for mark in names:
1060 if mark not in marks:
1060 if mark not in marks:
1061 raise error.Abort(_("bookmark '%s' does not exist") %
1061 raise error.Abort(_("bookmark '%s' does not exist") %
1062 mark)
1062 mark)
1063 if mark == repo._activebookmark:
1063 if mark == repo._activebookmark:
1064 bookmarks.deactivate(repo)
1064 bookmarks.deactivate(repo)
1065 del marks[mark]
1065 del marks[mark]
1066
1066
1067 elif rename:
1067 elif rename:
1068 tr = repo.transaction('bookmark')
1068 tr = repo.transaction('bookmark')
1069 if not names:
1069 if not names:
1070 raise error.Abort(_("new bookmark name required"))
1070 raise error.Abort(_("new bookmark name required"))
1071 elif len(names) > 1:
1071 elif len(names) > 1:
1072 raise error.Abort(_("only one new bookmark name allowed"))
1072 raise error.Abort(_("only one new bookmark name allowed"))
1073 mark = checkformat(names[0])
1073 mark = checkformat(names[0])
1074 if rename not in marks:
1074 if rename not in marks:
1075 raise error.Abort(_("bookmark '%s' does not exist")
1075 raise error.Abort(_("bookmark '%s' does not exist")
1076 % rename)
1076 % rename)
1077 checkconflict(repo, mark, cur, force)
1077 checkconflict(repo, mark, cur, force)
1078 marks[mark] = marks[rename]
1078 marks[mark] = marks[rename]
1079 if repo._activebookmark == rename and not inactive:
1079 if repo._activebookmark == rename and not inactive:
1080 bookmarks.activate(repo, mark)
1080 bookmarks.activate(repo, mark)
1081 del marks[rename]
1081 del marks[rename]
1082 elif names:
1082 elif names:
1083 tr = repo.transaction('bookmark')
1083 tr = repo.transaction('bookmark')
1084 newact = None
1084 newact = None
1085 for mark in names:
1085 for mark in names:
1086 mark = checkformat(mark)
1086 mark = checkformat(mark)
1087 if newact is None:
1087 if newact is None:
1088 newact = mark
1088 newact = mark
1089 if inactive and mark == repo._activebookmark:
1089 if inactive and mark == repo._activebookmark:
1090 bookmarks.deactivate(repo)
1090 bookmarks.deactivate(repo)
1091 return
1091 return
1092 tgt = cur
1092 tgt = cur
1093 if rev:
1093 if rev:
1094 tgt = scmutil.revsingle(repo, rev).node()
1094 tgt = scmutil.revsingle(repo, rev).node()
1095 checkconflict(repo, mark, cur, force, tgt)
1095 checkconflict(repo, mark, cur, force, tgt)
1096 marks[mark] = tgt
1096 marks[mark] = tgt
1097 if not inactive and cur == marks[newact] and not rev:
1097 if not inactive and cur == marks[newact] and not rev:
1098 bookmarks.activate(repo, newact)
1098 bookmarks.activate(repo, newact)
1099 elif cur != tgt and newact == repo._activebookmark:
1099 elif cur != tgt and newact == repo._activebookmark:
1100 bookmarks.deactivate(repo)
1100 bookmarks.deactivate(repo)
1101 elif inactive:
1101 elif inactive:
1102 if len(marks) == 0:
1102 if len(marks) == 0:
1103 ui.status(_("no bookmarks set\n"))
1103 ui.status(_("no bookmarks set\n"))
1104 elif not repo._activebookmark:
1104 elif not repo._activebookmark:
1105 ui.status(_("no active bookmark\n"))
1105 ui.status(_("no active bookmark\n"))
1106 else:
1106 else:
1107 bookmarks.deactivate(repo)
1107 bookmarks.deactivate(repo)
1108 if tr is not None:
1108 if tr is not None:
1109 marks.recordchange(tr)
1109 marks.recordchange(tr)
1110 tr.close()
1110 tr.close()
1111 finally:
1111 finally:
1112 lockmod.release(tr, lock, wlock)
1112 lockmod.release(tr, lock, wlock)
1113 else: # show bookmarks
1113 else: # show bookmarks
1114 fm = ui.formatter('bookmarks', opts)
1114 fm = ui.formatter('bookmarks', opts)
1115 hexfn = fm.hexfunc
1115 hexfn = fm.hexfunc
1116 marks = repo._bookmarks
1116 marks = repo._bookmarks
1117 if len(marks) == 0 and fm.isplain():
1117 if len(marks) == 0 and fm.isplain():
1118 ui.status(_("no bookmarks set\n"))
1118 ui.status(_("no bookmarks set\n"))
1119 for bmark, n in sorted(marks.iteritems()):
1119 for bmark, n in sorted(marks.iteritems()):
1120 active = repo._activebookmark
1120 active = repo._activebookmark
1121 if bmark == active:
1121 if bmark == active:
1122 prefix, label = '*', activebookmarklabel
1122 prefix, label = '*', activebookmarklabel
1123 else:
1123 else:
1124 prefix, label = ' ', ''
1124 prefix, label = ' ', ''
1125
1125
1126 fm.startitem()
1126 fm.startitem()
1127 if not ui.quiet:
1127 if not ui.quiet:
1128 fm.plain(' %s ' % prefix, label=label)
1128 fm.plain(' %s ' % prefix, label=label)
1129 fm.write('bookmark', '%s', bmark, label=label)
1129 fm.write('bookmark', '%s', bmark, label=label)
1130 pad = " " * (25 - encoding.colwidth(bmark))
1130 pad = " " * (25 - encoding.colwidth(bmark))
1131 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1131 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1132 repo.changelog.rev(n), hexfn(n), label=label)
1132 repo.changelog.rev(n), hexfn(n), label=label)
1133 fm.data(active=(bmark == active))
1133 fm.data(active=(bmark == active))
1134 fm.plain('\n')
1134 fm.plain('\n')
1135 fm.end()
1135 fm.end()
1136
1136
1137 @command('branch',
1137 @command('branch',
1138 [('f', 'force', None,
1138 [('f', 'force', None,
1139 _('set branch name even if it shadows an existing branch')),
1139 _('set branch name even if it shadows an existing branch')),
1140 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1140 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1141 _('[-fC] [NAME]'))
1141 _('[-fC] [NAME]'))
1142 def branch(ui, repo, label=None, **opts):
1142 def branch(ui, repo, label=None, **opts):
1143 """set or show the current branch name
1143 """set or show the current branch name
1144
1144
1145 .. note::
1145 .. note::
1146
1146
1147 Branch names are permanent and global. Use :hg:`bookmark` to create a
1147 Branch names are permanent and global. Use :hg:`bookmark` to create a
1148 light-weight bookmark instead. See :hg:`help glossary` for more
1148 light-weight bookmark instead. See :hg:`help glossary` for more
1149 information about named branches and bookmarks.
1149 information about named branches and bookmarks.
1150
1150
1151 With no argument, show the current branch name. With one argument,
1151 With no argument, show the current branch name. With one argument,
1152 set the working directory branch name (the branch will not exist
1152 set the working directory branch name (the branch will not exist
1153 in the repository until the next commit). Standard practice
1153 in the repository until the next commit). Standard practice
1154 recommends that primary development take place on the 'default'
1154 recommends that primary development take place on the 'default'
1155 branch.
1155 branch.
1156
1156
1157 Unless -f/--force is specified, branch will not let you set a
1157 Unless -f/--force is specified, branch will not let you set a
1158 branch name that already exists.
1158 branch name that already exists.
1159
1159
1160 Use -C/--clean to reset the working directory branch to that of
1160 Use -C/--clean to reset the working directory branch to that of
1161 the parent of the working directory, negating a previous branch
1161 the parent of the working directory, negating a previous branch
1162 change.
1162 change.
1163
1163
1164 Use the command :hg:`update` to switch to an existing branch. Use
1164 Use the command :hg:`update` to switch to an existing branch. Use
1165 :hg:`commit --close-branch` to mark this branch head as closed.
1165 :hg:`commit --close-branch` to mark this branch head as closed.
1166 When all heads of a branch are closed, the branch will be
1166 When all heads of a branch are closed, the branch will be
1167 considered closed.
1167 considered closed.
1168
1168
1169 Returns 0 on success.
1169 Returns 0 on success.
1170 """
1170 """
1171 if label:
1171 if label:
1172 label = label.strip()
1172 label = label.strip()
1173
1173
1174 if not opts.get('clean') and not label:
1174 if not opts.get('clean') and not label:
1175 ui.write("%s\n" % repo.dirstate.branch())
1175 ui.write("%s\n" % repo.dirstate.branch())
1176 return
1176 return
1177
1177
1178 with repo.wlock():
1178 with repo.wlock():
1179 if opts.get('clean'):
1179 if opts.get('clean'):
1180 label = repo[None].p1().branch()
1180 label = repo[None].p1().branch()
1181 repo.dirstate.setbranch(label)
1181 repo.dirstate.setbranch(label)
1182 ui.status(_('reset working directory to branch %s\n') % label)
1182 ui.status(_('reset working directory to branch %s\n') % label)
1183 elif label:
1183 elif label:
1184 if not opts.get('force') and label in repo.branchmap():
1184 if not opts.get('force') and label in repo.branchmap():
1185 if label not in [p.branch() for p in repo[None].parents()]:
1185 if label not in [p.branch() for p in repo[None].parents()]:
1186 raise error.Abort(_('a branch of the same name already'
1186 raise error.Abort(_('a branch of the same name already'
1187 ' exists'),
1187 ' exists'),
1188 # i18n: "it" refers to an existing branch
1188 # i18n: "it" refers to an existing branch
1189 hint=_("use 'hg update' to switch to it"))
1189 hint=_("use 'hg update' to switch to it"))
1190 scmutil.checknewlabel(repo, label, 'branch')
1190 scmutil.checknewlabel(repo, label, 'branch')
1191 repo.dirstate.setbranch(label)
1191 repo.dirstate.setbranch(label)
1192 ui.status(_('marked working directory as branch %s\n') % label)
1192 ui.status(_('marked working directory as branch %s\n') % label)
1193
1193
1194 # find any open named branches aside from default
1194 # find any open named branches aside from default
1195 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1195 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1196 if n != "default" and not c]
1196 if n != "default" and not c]
1197 if not others:
1197 if not others:
1198 ui.status(_('(branches are permanent and global, '
1198 ui.status(_('(branches are permanent and global, '
1199 'did you want a bookmark?)\n'))
1199 'did you want a bookmark?)\n'))
1200
1200
1201 @command('branches',
1201 @command('branches',
1202 [('a', 'active', False,
1202 [('a', 'active', False,
1203 _('show only branches that have unmerged heads (DEPRECATED)')),
1203 _('show only branches that have unmerged heads (DEPRECATED)')),
1204 ('c', 'closed', False, _('show normal and closed branches')),
1204 ('c', 'closed', False, _('show normal and closed branches')),
1205 ] + formatteropts,
1205 ] + formatteropts,
1206 _('[-c]'))
1206 _('[-c]'))
1207 def branches(ui, repo, active=False, closed=False, **opts):
1207 def branches(ui, repo, active=False, closed=False, **opts):
1208 """list repository named branches
1208 """list repository named branches
1209
1209
1210 List the repository's named branches, indicating which ones are
1210 List the repository's named branches, indicating which ones are
1211 inactive. If -c/--closed is specified, also list branches which have
1211 inactive. If -c/--closed is specified, also list branches which have
1212 been marked closed (see :hg:`commit --close-branch`).
1212 been marked closed (see :hg:`commit --close-branch`).
1213
1213
1214 Use the command :hg:`update` to switch to an existing branch.
1214 Use the command :hg:`update` to switch to an existing branch.
1215
1215
1216 Returns 0.
1216 Returns 0.
1217 """
1217 """
1218
1218
1219 fm = ui.formatter('branches', opts)
1219 fm = ui.formatter('branches', opts)
1220 hexfunc = fm.hexfunc
1220 hexfunc = fm.hexfunc
1221
1221
1222 allheads = set(repo.heads())
1222 allheads = set(repo.heads())
1223 branches = []
1223 branches = []
1224 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1224 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1225 isactive = not isclosed and bool(set(heads) & allheads)
1225 isactive = not isclosed and bool(set(heads) & allheads)
1226 branches.append((tag, repo[tip], isactive, not isclosed))
1226 branches.append((tag, repo[tip], isactive, not isclosed))
1227 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1227 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1228 reverse=True)
1228 reverse=True)
1229
1229
1230 for tag, ctx, isactive, isopen in branches:
1230 for tag, ctx, isactive, isopen in branches:
1231 if active and not isactive:
1231 if active and not isactive:
1232 continue
1232 continue
1233 if isactive:
1233 if isactive:
1234 label = 'branches.active'
1234 label = 'branches.active'
1235 notice = ''
1235 notice = ''
1236 elif not isopen:
1236 elif not isopen:
1237 if not closed:
1237 if not closed:
1238 continue
1238 continue
1239 label = 'branches.closed'
1239 label = 'branches.closed'
1240 notice = _(' (closed)')
1240 notice = _(' (closed)')
1241 else:
1241 else:
1242 label = 'branches.inactive'
1242 label = 'branches.inactive'
1243 notice = _(' (inactive)')
1243 notice = _(' (inactive)')
1244 current = (tag == repo.dirstate.branch())
1244 current = (tag == repo.dirstate.branch())
1245 if current:
1245 if current:
1246 label = 'branches.current'
1246 label = 'branches.current'
1247
1247
1248 fm.startitem()
1248 fm.startitem()
1249 fm.write('branch', '%s', tag, label=label)
1249 fm.write('branch', '%s', tag, label=label)
1250 rev = ctx.rev()
1250 rev = ctx.rev()
1251 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1251 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1252 fmt = ' ' * padsize + ' %d:%s'
1252 fmt = ' ' * padsize + ' %d:%s'
1253 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1253 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1254 label='log.changeset changeset.%s' % ctx.phasestr())
1254 label='log.changeset changeset.%s' % ctx.phasestr())
1255 fm.data(active=isactive, closed=not isopen, current=current)
1255 fm.data(active=isactive, closed=not isopen, current=current)
1256 if not ui.quiet:
1256 if not ui.quiet:
1257 fm.plain(notice)
1257 fm.plain(notice)
1258 fm.plain('\n')
1258 fm.plain('\n')
1259 fm.end()
1259 fm.end()
1260
1260
1261 @command('bundle',
1261 @command('bundle',
1262 [('f', 'force', None, _('run even when the destination is unrelated')),
1262 [('f', 'force', None, _('run even when the destination is unrelated')),
1263 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1263 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1264 _('REV')),
1264 _('REV')),
1265 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1265 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1266 _('BRANCH')),
1266 _('BRANCH')),
1267 ('', 'base', [],
1267 ('', 'base', [],
1268 _('a base changeset assumed to be available at the destination'),
1268 _('a base changeset assumed to be available at the destination'),
1269 _('REV')),
1269 _('REV')),
1270 ('a', 'all', None, _('bundle all changesets in the repository')),
1270 ('a', 'all', None, _('bundle all changesets in the repository')),
1271 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1271 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1272 ] + remoteopts,
1272 ] + remoteopts,
1273 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1273 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1274 def bundle(ui, repo, fname, dest=None, **opts):
1274 def bundle(ui, repo, fname, dest=None, **opts):
1275 """create a changegroup file
1275 """create a changegroup file
1276
1276
1277 Generate a changegroup file collecting changesets to be added
1277 Generate a changegroup file collecting changesets to be added
1278 to a repository.
1278 to a repository.
1279
1279
1280 To create a bundle containing all changesets, use -a/--all
1280 To create a bundle containing all changesets, use -a/--all
1281 (or --base null). Otherwise, hg assumes the destination will have
1281 (or --base null). Otherwise, hg assumes the destination will have
1282 all the nodes you specify with --base parameters. Otherwise, hg
1282 all the nodes you specify with --base parameters. Otherwise, hg
1283 will assume the repository has all the nodes in destination, or
1283 will assume the repository has all the nodes in destination, or
1284 default-push/default if no destination is specified.
1284 default-push/default if no destination is specified.
1285
1285
1286 You can change bundle format with the -t/--type option. You can
1286 You can change bundle format with the -t/--type option. You can
1287 specify a compression, a bundle version or both using a dash
1287 specify a compression, a bundle version or both using a dash
1288 (comp-version). The available compression methods are: none, bzip2,
1288 (comp-version). The available compression methods are: none, bzip2,
1289 and gzip (by default, bundles are compressed using bzip2). The
1289 and gzip (by default, bundles are compressed using bzip2). The
1290 available formats are: v1, v2 (default to most suitable).
1290 available formats are: v1, v2 (default to most suitable).
1291
1291
1292 The bundle file can then be transferred using conventional means
1292 The bundle file can then be transferred using conventional means
1293 and applied to another repository with the unbundle or pull
1293 and applied to another repository with the unbundle or pull
1294 command. This is useful when direct push and pull are not
1294 command. This is useful when direct push and pull are not
1295 available or when exporting an entire repository is undesirable.
1295 available or when exporting an entire repository is undesirable.
1296
1296
1297 Applying bundles preserves all changeset contents including
1297 Applying bundles preserves all changeset contents including
1298 permissions, copy/rename information, and revision history.
1298 permissions, copy/rename information, and revision history.
1299
1299
1300 Returns 0 on success, 1 if no changes found.
1300 Returns 0 on success, 1 if no changes found.
1301 """
1301 """
1302 revs = None
1302 revs = None
1303 if 'rev' in opts:
1303 if 'rev' in opts:
1304 revstrings = opts['rev']
1304 revstrings = opts['rev']
1305 revs = scmutil.revrange(repo, revstrings)
1305 revs = scmutil.revrange(repo, revstrings)
1306 if revstrings and not revs:
1306 if revstrings and not revs:
1307 raise error.Abort(_('no commits to bundle'))
1307 raise error.Abort(_('no commits to bundle'))
1308
1308
1309 bundletype = opts.get('type', 'bzip2').lower()
1309 bundletype = opts.get('type', 'bzip2').lower()
1310 try:
1310 try:
1311 bcompression, cgversion, params = exchange.parsebundlespec(
1311 bcompression, cgversion, params = exchange.parsebundlespec(
1312 repo, bundletype, strict=False)
1312 repo, bundletype, strict=False)
1313 except error.UnsupportedBundleSpecification as e:
1313 except error.UnsupportedBundleSpecification as e:
1314 raise error.Abort(str(e),
1314 raise error.Abort(str(e),
1315 hint=_("see 'hg help bundle' for supported "
1315 hint=_("see 'hg help bundle' for supported "
1316 "values for --type"))
1316 "values for --type"))
1317
1317
1318 # Packed bundles are a pseudo bundle format for now.
1318 # Packed bundles are a pseudo bundle format for now.
1319 if cgversion == 's1':
1319 if cgversion == 's1':
1320 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1320 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1321 hint=_("use 'hg debugcreatestreamclonebundle'"))
1321 hint=_("use 'hg debugcreatestreamclonebundle'"))
1322
1322
1323 if opts.get('all'):
1323 if opts.get('all'):
1324 if dest:
1324 if dest:
1325 raise error.Abort(_("--all is incompatible with specifying "
1325 raise error.Abort(_("--all is incompatible with specifying "
1326 "a destination"))
1326 "a destination"))
1327 if opts.get('base'):
1327 if opts.get('base'):
1328 ui.warn(_("ignoring --base because --all was specified\n"))
1328 ui.warn(_("ignoring --base because --all was specified\n"))
1329 base = ['null']
1329 base = ['null']
1330 else:
1330 else:
1331 base = scmutil.revrange(repo, opts.get('base'))
1331 base = scmutil.revrange(repo, opts.get('base'))
1332 # TODO: get desired bundlecaps from command line.
1332 # TODO: get desired bundlecaps from command line.
1333 bundlecaps = None
1333 bundlecaps = None
1334 if cgversion not in changegroup.supportedoutgoingversions(repo):
1334 if cgversion not in changegroup.supportedoutgoingversions(repo):
1335 raise error.Abort(_("repository does not support bundle version %s") %
1335 raise error.Abort(_("repository does not support bundle version %s") %
1336 cgversion)
1336 cgversion)
1337
1337
1338 if base:
1338 if base:
1339 if dest:
1339 if dest:
1340 raise error.Abort(_("--base is incompatible with specifying "
1340 raise error.Abort(_("--base is incompatible with specifying "
1341 "a destination"))
1341 "a destination"))
1342 common = [repo.lookup(rev) for rev in base]
1342 common = [repo.lookup(rev) for rev in base]
1343 heads = revs and map(repo.lookup, revs) or None
1343 heads = revs and map(repo.lookup, revs) or None
1344 outgoing = discovery.outgoing(repo, common, heads)
1344 outgoing = discovery.outgoing(repo, common, heads)
1345 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1345 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1346 bundlecaps=bundlecaps,
1346 bundlecaps=bundlecaps,
1347 version=cgversion)
1347 version=cgversion)
1348 outgoing = None
1348 outgoing = None
1349 else:
1349 else:
1350 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1350 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1351 dest, branches = hg.parseurl(dest, opts.get('branch'))
1351 dest, branches = hg.parseurl(dest, opts.get('branch'))
1352 other = hg.peer(repo, opts, dest)
1352 other = hg.peer(repo, opts, dest)
1353 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1353 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1354 heads = revs and map(repo.lookup, revs) or revs
1354 heads = revs and map(repo.lookup, revs) or revs
1355 outgoing = discovery.findcommonoutgoing(repo, other,
1355 outgoing = discovery.findcommonoutgoing(repo, other,
1356 onlyheads=heads,
1356 onlyheads=heads,
1357 force=opts.get('force'),
1357 force=opts.get('force'),
1358 portable=True)
1358 portable=True)
1359 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1359 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1360 bundlecaps, version=cgversion)
1360 bundlecaps, version=cgversion)
1361 if not cg:
1361 if not cg:
1362 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1362 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1363 return 1
1363 return 1
1364
1364
1365 if cgversion == '01': #bundle1
1365 if cgversion == '01': #bundle1
1366 if bcompression is None:
1366 if bcompression is None:
1367 bcompression = 'UN'
1367 bcompression = 'UN'
1368 bversion = 'HG10' + bcompression
1368 bversion = 'HG10' + bcompression
1369 bcompression = None
1369 bcompression = None
1370 else:
1370 else:
1371 assert cgversion == '02'
1371 assert cgversion == '02'
1372 bversion = 'HG20'
1372 bversion = 'HG20'
1373
1373
1374 # TODO compression options should be derived from bundlespec parsing.
1374 # TODO compression options should be derived from bundlespec parsing.
1375 # This is a temporary hack to allow adjusting bundle compression
1375 # This is a temporary hack to allow adjusting bundle compression
1376 # level without a) formalizing the bundlespec changes to declare it
1376 # level without a) formalizing the bundlespec changes to declare it
1377 # b) introducing a command flag.
1377 # b) introducing a command flag.
1378 compopts = {}
1378 compopts = {}
1379 complevel = ui.configint('experimental', 'bundlecomplevel')
1379 complevel = ui.configint('experimental', 'bundlecomplevel')
1380 if complevel is not None:
1380 if complevel is not None:
1381 compopts['level'] = complevel
1381 compopts['level'] = complevel
1382
1382
1383 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1383 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1384 compopts=compopts)
1384 compopts=compopts)
1385
1385
1386 @command('cat',
1386 @command('cat',
1387 [('o', 'output', '',
1387 [('o', 'output', '',
1388 _('print output to file with formatted name'), _('FORMAT')),
1388 _('print output to file with formatted name'), _('FORMAT')),
1389 ('r', 'rev', '', _('print the given revision'), _('REV')),
1389 ('r', 'rev', '', _('print the given revision'), _('REV')),
1390 ('', 'decode', None, _('apply any matching decode filter')),
1390 ('', 'decode', None, _('apply any matching decode filter')),
1391 ] + walkopts,
1391 ] + walkopts,
1392 _('[OPTION]... FILE...'),
1392 _('[OPTION]... FILE...'),
1393 inferrepo=True)
1393 inferrepo=True)
1394 def cat(ui, repo, file1, *pats, **opts):
1394 def cat(ui, repo, file1, *pats, **opts):
1395 """output the current or given revision of files
1395 """output the current or given revision of files
1396
1396
1397 Print the specified files as they were at the given revision. If
1397 Print the specified files as they were at the given revision. If
1398 no revision is given, the parent of the working directory is used.
1398 no revision is given, the parent of the working directory is used.
1399
1399
1400 Output may be to a file, in which case the name of the file is
1400 Output may be to a file, in which case the name of the file is
1401 given using a format string. The formatting rules as follows:
1401 given using a format string. The formatting rules as follows:
1402
1402
1403 :``%%``: literal "%" character
1403 :``%%``: literal "%" character
1404 :``%s``: basename of file being printed
1404 :``%s``: basename of file being printed
1405 :``%d``: dirname of file being printed, or '.' if in repository root
1405 :``%d``: dirname of file being printed, or '.' if in repository root
1406 :``%p``: root-relative path name of file being printed
1406 :``%p``: root-relative path name of file being printed
1407 :``%H``: changeset hash (40 hexadecimal digits)
1407 :``%H``: changeset hash (40 hexadecimal digits)
1408 :``%R``: changeset revision number
1408 :``%R``: changeset revision number
1409 :``%h``: short-form changeset hash (12 hexadecimal digits)
1409 :``%h``: short-form changeset hash (12 hexadecimal digits)
1410 :``%r``: zero-padded changeset revision number
1410 :``%r``: zero-padded changeset revision number
1411 :``%b``: basename of the exporting repository
1411 :``%b``: basename of the exporting repository
1412
1412
1413 Returns 0 on success.
1413 Returns 0 on success.
1414 """
1414 """
1415 ctx = scmutil.revsingle(repo, opts.get('rev'))
1415 ctx = scmutil.revsingle(repo, opts.get('rev'))
1416 m = scmutil.match(ctx, (file1,) + pats, opts)
1416 m = scmutil.match(ctx, (file1,) + pats, opts)
1417
1417
1418 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1418 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1419
1419
1420 @command('^clone',
1420 @command('^clone',
1421 [('U', 'noupdate', None, _('the clone will include an empty working '
1421 [('U', 'noupdate', None, _('the clone will include an empty working '
1422 'directory (only a repository)')),
1422 'directory (only a repository)')),
1423 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1423 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1424 _('REV')),
1424 _('REV')),
1425 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1425 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1426 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1426 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1427 ('', 'pull', None, _('use pull protocol to copy metadata')),
1427 ('', 'pull', None, _('use pull protocol to copy metadata')),
1428 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1428 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1429 ] + remoteopts,
1429 ] + remoteopts,
1430 _('[OPTION]... SOURCE [DEST]'),
1430 _('[OPTION]... SOURCE [DEST]'),
1431 norepo=True)
1431 norepo=True)
1432 def clone(ui, source, dest=None, **opts):
1432 def clone(ui, source, dest=None, **opts):
1433 """make a copy of an existing repository
1433 """make a copy of an existing repository
1434
1434
1435 Create a copy of an existing repository in a new directory.
1435 Create a copy of an existing repository in a new directory.
1436
1436
1437 If no destination directory name is specified, it defaults to the
1437 If no destination directory name is specified, it defaults to the
1438 basename of the source.
1438 basename of the source.
1439
1439
1440 The location of the source is added to the new repository's
1440 The location of the source is added to the new repository's
1441 ``.hg/hgrc`` file, as the default to be used for future pulls.
1441 ``.hg/hgrc`` file, as the default to be used for future pulls.
1442
1442
1443 Only local paths and ``ssh://`` URLs are supported as
1443 Only local paths and ``ssh://`` URLs are supported as
1444 destinations. For ``ssh://`` destinations, no working directory or
1444 destinations. For ``ssh://`` destinations, no working directory or
1445 ``.hg/hgrc`` will be created on the remote side.
1445 ``.hg/hgrc`` will be created on the remote side.
1446
1446
1447 If the source repository has a bookmark called '@' set, that
1447 If the source repository has a bookmark called '@' set, that
1448 revision will be checked out in the new repository by default.
1448 revision will be checked out in the new repository by default.
1449
1449
1450 To check out a particular version, use -u/--update, or
1450 To check out a particular version, use -u/--update, or
1451 -U/--noupdate to create a clone with no working directory.
1451 -U/--noupdate to create a clone with no working directory.
1452
1452
1453 To pull only a subset of changesets, specify one or more revisions
1453 To pull only a subset of changesets, specify one or more revisions
1454 identifiers with -r/--rev or branches with -b/--branch. The
1454 identifiers with -r/--rev or branches with -b/--branch. The
1455 resulting clone will contain only the specified changesets and
1455 resulting clone will contain only the specified changesets and
1456 their ancestors. These options (or 'clone src#rev dest') imply
1456 their ancestors. These options (or 'clone src#rev dest') imply
1457 --pull, even for local source repositories.
1457 --pull, even for local source repositories.
1458
1458
1459 .. note::
1459 .. note::
1460
1460
1461 Specifying a tag will include the tagged changeset but not the
1461 Specifying a tag will include the tagged changeset but not the
1462 changeset containing the tag.
1462 changeset containing the tag.
1463
1463
1464 .. container:: verbose
1464 .. container:: verbose
1465
1465
1466 For efficiency, hardlinks are used for cloning whenever the
1466 For efficiency, hardlinks are used for cloning whenever the
1467 source and destination are on the same filesystem (note this
1467 source and destination are on the same filesystem (note this
1468 applies only to the repository data, not to the working
1468 applies only to the repository data, not to the working
1469 directory). Some filesystems, such as AFS, implement hardlinking
1469 directory). Some filesystems, such as AFS, implement hardlinking
1470 incorrectly, but do not report errors. In these cases, use the
1470 incorrectly, but do not report errors. In these cases, use the
1471 --pull option to avoid hardlinking.
1471 --pull option to avoid hardlinking.
1472
1472
1473 In some cases, you can clone repositories and the working
1473 In some cases, you can clone repositories and the working
1474 directory using full hardlinks with ::
1474 directory using full hardlinks with ::
1475
1475
1476 $ cp -al REPO REPOCLONE
1476 $ cp -al REPO REPOCLONE
1477
1477
1478 This is the fastest way to clone, but it is not always safe. The
1478 This is the fastest way to clone, but it is not always safe. The
1479 operation is not atomic (making sure REPO is not modified during
1479 operation is not atomic (making sure REPO is not modified during
1480 the operation is up to you) and you have to make sure your
1480 the operation is up to you) and you have to make sure your
1481 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1481 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1482 so). Also, this is not compatible with certain extensions that
1482 so). Also, this is not compatible with certain extensions that
1483 place their metadata under the .hg directory, such as mq.
1483 place their metadata under the .hg directory, such as mq.
1484
1484
1485 Mercurial will update the working directory to the first applicable
1485 Mercurial will update the working directory to the first applicable
1486 revision from this list:
1486 revision from this list:
1487
1487
1488 a) null if -U or the source repository has no changesets
1488 a) null if -U or the source repository has no changesets
1489 b) if -u . and the source repository is local, the first parent of
1489 b) if -u . and the source repository is local, the first parent of
1490 the source repository's working directory
1490 the source repository's working directory
1491 c) the changeset specified with -u (if a branch name, this means the
1491 c) the changeset specified with -u (if a branch name, this means the
1492 latest head of that branch)
1492 latest head of that branch)
1493 d) the changeset specified with -r
1493 d) the changeset specified with -r
1494 e) the tipmost head specified with -b
1494 e) the tipmost head specified with -b
1495 f) the tipmost head specified with the url#branch source syntax
1495 f) the tipmost head specified with the url#branch source syntax
1496 g) the revision marked with the '@' bookmark, if present
1496 g) the revision marked with the '@' bookmark, if present
1497 h) the tipmost head of the default branch
1497 h) the tipmost head of the default branch
1498 i) tip
1498 i) tip
1499
1499
1500 When cloning from servers that support it, Mercurial may fetch
1500 When cloning from servers that support it, Mercurial may fetch
1501 pre-generated data from a server-advertised URL. When this is done,
1501 pre-generated data from a server-advertised URL. When this is done,
1502 hooks operating on incoming changesets and changegroups may fire twice,
1502 hooks operating on incoming changesets and changegroups may fire twice,
1503 once for the bundle fetched from the URL and another for any additional
1503 once for the bundle fetched from the URL and another for any additional
1504 data not fetched from this URL. In addition, if an error occurs, the
1504 data not fetched from this URL. In addition, if an error occurs, the
1505 repository may be rolled back to a partial clone. This behavior may
1505 repository may be rolled back to a partial clone. This behavior may
1506 change in future releases. See :hg:`help -e clonebundles` for more.
1506 change in future releases. See :hg:`help -e clonebundles` for more.
1507
1507
1508 Examples:
1508 Examples:
1509
1509
1510 - clone a remote repository to a new directory named hg/::
1510 - clone a remote repository to a new directory named hg/::
1511
1511
1512 hg clone https://www.mercurial-scm.org/repo/hg/
1512 hg clone https://www.mercurial-scm.org/repo/hg/
1513
1513
1514 - create a lightweight local clone::
1514 - create a lightweight local clone::
1515
1515
1516 hg clone project/ project-feature/
1516 hg clone project/ project-feature/
1517
1517
1518 - clone from an absolute path on an ssh server (note double-slash)::
1518 - clone from an absolute path on an ssh server (note double-slash)::
1519
1519
1520 hg clone ssh://user@server//home/projects/alpha/
1520 hg clone ssh://user@server//home/projects/alpha/
1521
1521
1522 - do a high-speed clone over a LAN while checking out a
1522 - do a high-speed clone over a LAN while checking out a
1523 specified version::
1523 specified version::
1524
1524
1525 hg clone --uncompressed http://server/repo -u 1.5
1525 hg clone --uncompressed http://server/repo -u 1.5
1526
1526
1527 - create a repository without changesets after a particular revision::
1527 - create a repository without changesets after a particular revision::
1528
1528
1529 hg clone -r 04e544 experimental/ good/
1529 hg clone -r 04e544 experimental/ good/
1530
1530
1531 - clone (and track) a particular named branch::
1531 - clone (and track) a particular named branch::
1532
1532
1533 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1533 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1534
1534
1535 See :hg:`help urls` for details on specifying URLs.
1535 See :hg:`help urls` for details on specifying URLs.
1536
1536
1537 Returns 0 on success.
1537 Returns 0 on success.
1538 """
1538 """
1539 if opts.get('noupdate') and opts.get('updaterev'):
1539 if opts.get('noupdate') and opts.get('updaterev'):
1540 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1540 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1541
1541
1542 r = hg.clone(ui, opts, source, dest,
1542 r = hg.clone(ui, opts, source, dest,
1543 pull=opts.get('pull'),
1543 pull=opts.get('pull'),
1544 stream=opts.get('uncompressed'),
1544 stream=opts.get('uncompressed'),
1545 rev=opts.get('rev'),
1545 rev=opts.get('rev'),
1546 update=opts.get('updaterev') or not opts.get('noupdate'),
1546 update=opts.get('updaterev') or not opts.get('noupdate'),
1547 branch=opts.get('branch'),
1547 branch=opts.get('branch'),
1548 shareopts=opts.get('shareopts'))
1548 shareopts=opts.get('shareopts'))
1549
1549
1550 return r is None
1550 return r is None
1551
1551
1552 @command('^commit|ci',
1552 @command('^commit|ci',
1553 [('A', 'addremove', None,
1553 [('A', 'addremove', None,
1554 _('mark new/missing files as added/removed before committing')),
1554 _('mark new/missing files as added/removed before committing')),
1555 ('', 'close-branch', None,
1555 ('', 'close-branch', None,
1556 _('mark a branch head as closed')),
1556 _('mark a branch head as closed')),
1557 ('', 'amend', None, _('amend the parent of the working directory')),
1557 ('', 'amend', None, _('amend the parent of the working directory')),
1558 ('s', 'secret', None, _('use the secret phase for committing')),
1558 ('s', 'secret', None, _('use the secret phase for committing')),
1559 ('e', 'edit', None, _('invoke editor on commit messages')),
1559 ('e', 'edit', None, _('invoke editor on commit messages')),
1560 ('i', 'interactive', None, _('use interactive mode')),
1560 ('i', 'interactive', None, _('use interactive mode')),
1561 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1561 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1562 _('[OPTION]... [FILE]...'),
1562 _('[OPTION]... [FILE]...'),
1563 inferrepo=True)
1563 inferrepo=True)
1564 def commit(ui, repo, *pats, **opts):
1564 def commit(ui, repo, *pats, **opts):
1565 """commit the specified files or all outstanding changes
1565 """commit the specified files or all outstanding changes
1566
1566
1567 Commit changes to the given files into the repository. Unlike a
1567 Commit changes to the given files into the repository. Unlike a
1568 centralized SCM, this operation is a local operation. See
1568 centralized SCM, this operation is a local operation. See
1569 :hg:`push` for a way to actively distribute your changes.
1569 :hg:`push` for a way to actively distribute your changes.
1570
1570
1571 If a list of files is omitted, all changes reported by :hg:`status`
1571 If a list of files is omitted, all changes reported by :hg:`status`
1572 will be committed.
1572 will be committed.
1573
1573
1574 If you are committing the result of a merge, do not provide any
1574 If you are committing the result of a merge, do not provide any
1575 filenames or -I/-X filters.
1575 filenames or -I/-X filters.
1576
1576
1577 If no commit message is specified, Mercurial starts your
1577 If no commit message is specified, Mercurial starts your
1578 configured editor where you can enter a message. In case your
1578 configured editor where you can enter a message. In case your
1579 commit fails, you will find a backup of your message in
1579 commit fails, you will find a backup of your message in
1580 ``.hg/last-message.txt``.
1580 ``.hg/last-message.txt``.
1581
1581
1582 The --close-branch flag can be used to mark the current branch
1582 The --close-branch flag can be used to mark the current branch
1583 head closed. When all heads of a branch are closed, the branch
1583 head closed. When all heads of a branch are closed, the branch
1584 will be considered closed and no longer listed.
1584 will be considered closed and no longer listed.
1585
1585
1586 The --amend flag can be used to amend the parent of the
1586 The --amend flag can be used to amend the parent of the
1587 working directory with a new commit that contains the changes
1587 working directory with a new commit that contains the changes
1588 in the parent in addition to those currently reported by :hg:`status`,
1588 in the parent in addition to those currently reported by :hg:`status`,
1589 if there are any. The old commit is stored in a backup bundle in
1589 if there are any. The old commit is stored in a backup bundle in
1590 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1590 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1591 on how to restore it).
1591 on how to restore it).
1592
1592
1593 Message, user and date are taken from the amended commit unless
1593 Message, user and date are taken from the amended commit unless
1594 specified. When a message isn't specified on the command line,
1594 specified. When a message isn't specified on the command line,
1595 the editor will open with the message of the amended commit.
1595 the editor will open with the message of the amended commit.
1596
1596
1597 It is not possible to amend public changesets (see :hg:`help phases`)
1597 It is not possible to amend public changesets (see :hg:`help phases`)
1598 or changesets that have children.
1598 or changesets that have children.
1599
1599
1600 See :hg:`help dates` for a list of formats valid for -d/--date.
1600 See :hg:`help dates` for a list of formats valid for -d/--date.
1601
1601
1602 Returns 0 on success, 1 if nothing changed.
1602 Returns 0 on success, 1 if nothing changed.
1603
1603
1604 .. container:: verbose
1604 .. container:: verbose
1605
1605
1606 Examples:
1606 Examples:
1607
1607
1608 - commit all files ending in .py::
1608 - commit all files ending in .py::
1609
1609
1610 hg commit --include "set:**.py"
1610 hg commit --include "set:**.py"
1611
1611
1612 - commit all non-binary files::
1612 - commit all non-binary files::
1613
1613
1614 hg commit --exclude "set:binary()"
1614 hg commit --exclude "set:binary()"
1615
1615
1616 - amend the current commit and set the date to now::
1616 - amend the current commit and set the date to now::
1617
1617
1618 hg commit --amend --date now
1618 hg commit --amend --date now
1619 """
1619 """
1620 wlock = lock = None
1620 wlock = lock = None
1621 try:
1621 try:
1622 wlock = repo.wlock()
1622 wlock = repo.wlock()
1623 lock = repo.lock()
1623 lock = repo.lock()
1624 return _docommit(ui, repo, *pats, **opts)
1624 return _docommit(ui, repo, *pats, **opts)
1625 finally:
1625 finally:
1626 release(lock, wlock)
1626 release(lock, wlock)
1627
1627
1628 def _docommit(ui, repo, *pats, **opts):
1628 def _docommit(ui, repo, *pats, **opts):
1629 if opts.get('interactive'):
1629 if opts.get('interactive'):
1630 opts.pop('interactive')
1630 opts.pop('interactive')
1631 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1631 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1632 cmdutil.recordfilter, *pats, **opts)
1632 cmdutil.recordfilter, *pats, **opts)
1633 # ret can be 0 (no changes to record) or the value returned by
1633 # ret can be 0 (no changes to record) or the value returned by
1634 # commit(), 1 if nothing changed or None on success.
1634 # commit(), 1 if nothing changed or None on success.
1635 return 1 if ret == 0 else ret
1635 return 1 if ret == 0 else ret
1636
1636
1637 if opts.get('subrepos'):
1637 if opts.get('subrepos'):
1638 if opts.get('amend'):
1638 if opts.get('amend'):
1639 raise error.Abort(_('cannot amend with --subrepos'))
1639 raise error.Abort(_('cannot amend with --subrepos'))
1640 # Let --subrepos on the command line override config setting.
1640 # Let --subrepos on the command line override config setting.
1641 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1641 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1642
1642
1643 cmdutil.checkunfinished(repo, commit=True)
1643 cmdutil.checkunfinished(repo, commit=True)
1644
1644
1645 branch = repo[None].branch()
1645 branch = repo[None].branch()
1646 bheads = repo.branchheads(branch)
1646 bheads = repo.branchheads(branch)
1647
1647
1648 extra = {}
1648 extra = {}
1649 if opts.get('close_branch'):
1649 if opts.get('close_branch'):
1650 extra['close'] = 1
1650 extra['close'] = 1
1651
1651
1652 if not bheads:
1652 if not bheads:
1653 raise error.Abort(_('can only close branch heads'))
1653 raise error.Abort(_('can only close branch heads'))
1654 elif opts.get('amend'):
1654 elif opts.get('amend'):
1655 if repo[None].parents()[0].p1().branch() != branch and \
1655 if repo[None].parents()[0].p1().branch() != branch and \
1656 repo[None].parents()[0].p2().branch() != branch:
1656 repo[None].parents()[0].p2().branch() != branch:
1657 raise error.Abort(_('can only close branch heads'))
1657 raise error.Abort(_('can only close branch heads'))
1658
1658
1659 if opts.get('amend'):
1659 if opts.get('amend'):
1660 if ui.configbool('ui', 'commitsubrepos'):
1660 if ui.configbool('ui', 'commitsubrepos'):
1661 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1661 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1662
1662
1663 old = repo['.']
1663 old = repo['.']
1664 if not old.mutable():
1664 if not old.mutable():
1665 raise error.Abort(_('cannot amend public changesets'))
1665 raise error.Abort(_('cannot amend public changesets'))
1666 if len(repo[None].parents()) > 1:
1666 if len(repo[None].parents()) > 1:
1667 raise error.Abort(_('cannot amend while merging'))
1667 raise error.Abort(_('cannot amend while merging'))
1668 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1668 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1669 if not allowunstable and old.children():
1669 if not allowunstable and old.children():
1670 raise error.Abort(_('cannot amend changeset with children'))
1670 raise error.Abort(_('cannot amend changeset with children'))
1671
1671
1672 # Currently histedit gets confused if an amend happens while histedit
1672 # Currently histedit gets confused if an amend happens while histedit
1673 # is in progress. Since we have a checkunfinished command, we are
1673 # is in progress. Since we have a checkunfinished command, we are
1674 # temporarily honoring it.
1674 # temporarily honoring it.
1675 #
1675 #
1676 # Note: eventually this guard will be removed. Please do not expect
1676 # Note: eventually this guard will be removed. Please do not expect
1677 # this behavior to remain.
1677 # this behavior to remain.
1678 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1678 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1679 cmdutil.checkunfinished(repo)
1679 cmdutil.checkunfinished(repo)
1680
1680
1681 # commitfunc is used only for temporary amend commit by cmdutil.amend
1681 # commitfunc is used only for temporary amend commit by cmdutil.amend
1682 def commitfunc(ui, repo, message, match, opts):
1682 def commitfunc(ui, repo, message, match, opts):
1683 return repo.commit(message,
1683 return repo.commit(message,
1684 opts.get('user') or old.user(),
1684 opts.get('user') or old.user(),
1685 opts.get('date') or old.date(),
1685 opts.get('date') or old.date(),
1686 match,
1686 match,
1687 extra=extra)
1687 extra=extra)
1688
1688
1689 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1689 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1690 if node == old.node():
1690 if node == old.node():
1691 ui.status(_("nothing changed\n"))
1691 ui.status(_("nothing changed\n"))
1692 return 1
1692 return 1
1693 else:
1693 else:
1694 def commitfunc(ui, repo, message, match, opts):
1694 def commitfunc(ui, repo, message, match, opts):
1695 backup = ui.backupconfig('phases', 'new-commit')
1695 backup = ui.backupconfig('phases', 'new-commit')
1696 baseui = repo.baseui
1696 baseui = repo.baseui
1697 basebackup = baseui.backupconfig('phases', 'new-commit')
1697 basebackup = baseui.backupconfig('phases', 'new-commit')
1698 try:
1698 try:
1699 if opts.get('secret'):
1699 if opts.get('secret'):
1700 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1700 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1701 # Propagate to subrepos
1701 # Propagate to subrepos
1702 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1702 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1703
1703
1704 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1704 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1705 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1705 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1706 return repo.commit(message, opts.get('user'), opts.get('date'),
1706 return repo.commit(message, opts.get('user'), opts.get('date'),
1707 match,
1707 match,
1708 editor=editor,
1708 editor=editor,
1709 extra=extra)
1709 extra=extra)
1710 finally:
1710 finally:
1711 ui.restoreconfig(backup)
1711 ui.restoreconfig(backup)
1712 repo.baseui.restoreconfig(basebackup)
1712 repo.baseui.restoreconfig(basebackup)
1713
1713
1714
1714
1715 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1715 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1716
1716
1717 if not node:
1717 if not node:
1718 stat = cmdutil.postcommitstatus(repo, pats, opts)
1718 stat = cmdutil.postcommitstatus(repo, pats, opts)
1719 if stat[3]:
1719 if stat[3]:
1720 ui.status(_("nothing changed (%d missing files, see "
1720 ui.status(_("nothing changed (%d missing files, see "
1721 "'hg status')\n") % len(stat[3]))
1721 "'hg status')\n") % len(stat[3]))
1722 else:
1722 else:
1723 ui.status(_("nothing changed\n"))
1723 ui.status(_("nothing changed\n"))
1724 return 1
1724 return 1
1725
1725
1726 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1726 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1727
1727
1728 @command('config|showconfig|debugconfig',
1728 @command('config|showconfig|debugconfig',
1729 [('u', 'untrusted', None, _('show untrusted configuration options')),
1729 [('u', 'untrusted', None, _('show untrusted configuration options')),
1730 ('e', 'edit', None, _('edit user config')),
1730 ('e', 'edit', None, _('edit user config')),
1731 ('l', 'local', None, _('edit repository config')),
1731 ('l', 'local', None, _('edit repository config')),
1732 ('g', 'global', None, _('edit global config'))] + formatteropts,
1732 ('g', 'global', None, _('edit global config'))] + formatteropts,
1733 _('[-u] [NAME]...'),
1733 _('[-u] [NAME]...'),
1734 optionalrepo=True)
1734 optionalrepo=True)
1735 def config(ui, repo, *values, **opts):
1735 def config(ui, repo, *values, **opts):
1736 """show combined config settings from all hgrc files
1736 """show combined config settings from all hgrc files
1737
1737
1738 With no arguments, print names and values of all config items.
1738 With no arguments, print names and values of all config items.
1739
1739
1740 With one argument of the form section.name, print just the value
1740 With one argument of the form section.name, print just the value
1741 of that config item.
1741 of that config item.
1742
1742
1743 With multiple arguments, print names and values of all config
1743 With multiple arguments, print names and values of all config
1744 items with matching section names.
1744 items with matching section names.
1745
1745
1746 With --edit, start an editor on the user-level config file. With
1746 With --edit, start an editor on the user-level config file. With
1747 --global, edit the system-wide config file. With --local, edit the
1747 --global, edit the system-wide config file. With --local, edit the
1748 repository-level config file.
1748 repository-level config file.
1749
1749
1750 With --debug, the source (filename and line number) is printed
1750 With --debug, the source (filename and line number) is printed
1751 for each config item.
1751 for each config item.
1752
1752
1753 See :hg:`help config` for more information about config files.
1753 See :hg:`help config` for more information about config files.
1754
1754
1755 Returns 0 on success, 1 if NAME does not exist.
1755 Returns 0 on success, 1 if NAME does not exist.
1756
1756
1757 """
1757 """
1758
1758
1759 if opts.get('edit') or opts.get('local') or opts.get('global'):
1759 if opts.get('edit') or opts.get('local') or opts.get('global'):
1760 if opts.get('local') and opts.get('global'):
1760 if opts.get('local') and opts.get('global'):
1761 raise error.Abort(_("can't use --local and --global together"))
1761 raise error.Abort(_("can't use --local and --global together"))
1762
1762
1763 if opts.get('local'):
1763 if opts.get('local'):
1764 if not repo:
1764 if not repo:
1765 raise error.Abort(_("can't use --local outside a repository"))
1765 raise error.Abort(_("can't use --local outside a repository"))
1766 paths = [repo.join('hgrc')]
1766 paths = [repo.join('hgrc')]
1767 elif opts.get('global'):
1767 elif opts.get('global'):
1768 paths = scmutil.systemrcpath()
1768 paths = scmutil.systemrcpath()
1769 else:
1769 else:
1770 paths = scmutil.userrcpath()
1770 paths = scmutil.userrcpath()
1771
1771
1772 for f in paths:
1772 for f in paths:
1773 if os.path.exists(f):
1773 if os.path.exists(f):
1774 break
1774 break
1775 else:
1775 else:
1776 if opts.get('global'):
1776 if opts.get('global'):
1777 samplehgrc = uimod.samplehgrcs['global']
1777 samplehgrc = uimod.samplehgrcs['global']
1778 elif opts.get('local'):
1778 elif opts.get('local'):
1779 samplehgrc = uimod.samplehgrcs['local']
1779 samplehgrc = uimod.samplehgrcs['local']
1780 else:
1780 else:
1781 samplehgrc = uimod.samplehgrcs['user']
1781 samplehgrc = uimod.samplehgrcs['user']
1782
1782
1783 f = paths[0]
1783 f = paths[0]
1784 fp = open(f, "w")
1784 fp = open(f, "w")
1785 fp.write(samplehgrc)
1785 fp.write(samplehgrc)
1786 fp.close()
1786 fp.close()
1787
1787
1788 editor = ui.geteditor()
1788 editor = ui.geteditor()
1789 ui.system("%s \"%s\"" % (editor, f),
1789 ui.system("%s \"%s\"" % (editor, f),
1790 onerr=error.Abort, errprefix=_("edit failed"))
1790 onerr=error.Abort, errprefix=_("edit failed"))
1791 return
1791 return
1792
1792
1793 fm = ui.formatter('config', opts)
1793 fm = ui.formatter('config', opts)
1794 for f in scmutil.rcpath():
1794 for f in scmutil.rcpath():
1795 ui.debug('read config from: %s\n' % f)
1795 ui.debug('read config from: %s\n' % f)
1796 untrusted = bool(opts.get('untrusted'))
1796 untrusted = bool(opts.get('untrusted'))
1797 if values:
1797 if values:
1798 sections = [v for v in values if '.' not in v]
1798 sections = [v for v in values if '.' not in v]
1799 items = [v for v in values if '.' in v]
1799 items = [v for v in values if '.' in v]
1800 if len(items) > 1 or items and sections:
1800 if len(items) > 1 or items and sections:
1801 raise error.Abort(_('only one config item permitted'))
1801 raise error.Abort(_('only one config item permitted'))
1802 matched = False
1802 matched = False
1803 for section, name, value in ui.walkconfig(untrusted=untrusted):
1803 for section, name, value in ui.walkconfig(untrusted=untrusted):
1804 source = ui.configsource(section, name, untrusted)
1804 source = ui.configsource(section, name, untrusted)
1805 value = str(value)
1805 value = str(value)
1806 if fm.isplain():
1806 if fm.isplain():
1807 source = source or 'none'
1807 source = source or 'none'
1808 value = value.replace('\n', '\\n')
1808 value = value.replace('\n', '\\n')
1809 entryname = section + '.' + name
1809 entryname = section + '.' + name
1810 if values:
1810 if values:
1811 for v in values:
1811 for v in values:
1812 if v == section:
1812 if v == section:
1813 fm.startitem()
1813 fm.startitem()
1814 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1814 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1815 fm.write('name value', '%s=%s\n', entryname, value)
1815 fm.write('name value', '%s=%s\n', entryname, value)
1816 matched = True
1816 matched = True
1817 elif v == entryname:
1817 elif v == entryname:
1818 fm.startitem()
1818 fm.startitem()
1819 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1819 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1820 fm.write('value', '%s\n', value)
1820 fm.write('value', '%s\n', value)
1821 fm.data(name=entryname)
1821 fm.data(name=entryname)
1822 matched = True
1822 matched = True
1823 else:
1823 else:
1824 fm.startitem()
1824 fm.startitem()
1825 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1825 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1826 fm.write('name value', '%s=%s\n', entryname, value)
1826 fm.write('name value', '%s=%s\n', entryname, value)
1827 matched = True
1827 matched = True
1828 fm.end()
1828 fm.end()
1829 if matched:
1829 if matched:
1830 return 0
1830 return 0
1831 return 1
1831 return 1
1832
1832
1833 @command('copy|cp',
1833 @command('copy|cp',
1834 [('A', 'after', None, _('record a copy that has already occurred')),
1834 [('A', 'after', None, _('record a copy that has already occurred')),
1835 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1835 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1836 ] + walkopts + dryrunopts,
1836 ] + walkopts + dryrunopts,
1837 _('[OPTION]... [SOURCE]... DEST'))
1837 _('[OPTION]... [SOURCE]... DEST'))
1838 def copy(ui, repo, *pats, **opts):
1838 def copy(ui, repo, *pats, **opts):
1839 """mark files as copied for the next commit
1839 """mark files as copied for the next commit
1840
1840
1841 Mark dest as having copies of source files. If dest is a
1841 Mark dest as having copies of source files. If dest is a
1842 directory, copies are put in that directory. If dest is a file,
1842 directory, copies are put in that directory. If dest is a file,
1843 the source must be a single file.
1843 the source must be a single file.
1844
1844
1845 By default, this command copies the contents of files as they
1845 By default, this command copies the contents of files as they
1846 exist in the working directory. If invoked with -A/--after, the
1846 exist in the working directory. If invoked with -A/--after, the
1847 operation is recorded, but no copying is performed.
1847 operation is recorded, but no copying is performed.
1848
1848
1849 This command takes effect with the next commit. To undo a copy
1849 This command takes effect with the next commit. To undo a copy
1850 before that, see :hg:`revert`.
1850 before that, see :hg:`revert`.
1851
1851
1852 Returns 0 on success, 1 if errors are encountered.
1852 Returns 0 on success, 1 if errors are encountered.
1853 """
1853 """
1854 with repo.wlock(False):
1854 with repo.wlock(False):
1855 return cmdutil.copy(ui, repo, pats, opts)
1855 return cmdutil.copy(ui, repo, pats, opts)
1856
1856
1857 @command('debugsuccessorssets',
1858 [],
1859 _('[REV]'))
1860 def debugsuccessorssets(ui, repo, *revs):
1861 """show set of successors for revision
1862
1863 A successors set of changeset A is a consistent group of revisions that
1864 succeed A. It contains non-obsolete changesets only.
1865
1866 In most cases a changeset A has a single successors set containing a single
1867 successor (changeset A replaced by A').
1868
1869 A changeset that is made obsolete with no successors are called "pruned".
1870 Such changesets have no successors sets at all.
1871
1872 A changeset that has been "split" will have a successors set containing
1873 more than one successor.
1874
1875 A changeset that has been rewritten in multiple different ways is called
1876 "divergent". Such changesets have multiple successor sets (each of which
1877 may also be split, i.e. have multiple successors).
1878
1879 Results are displayed as follows::
1880
1881 <rev1>
1882 <successors-1A>
1883 <rev2>
1884 <successors-2A>
1885 <successors-2B1> <successors-2B2> <successors-2B3>
1886
1887 Here rev2 has two possible (i.e. divergent) successors sets. The first
1888 holds one element, whereas the second holds three (i.e. the changeset has
1889 been split).
1890 """
1891 # passed to successorssets caching computation from one call to another
1892 cache = {}
1893 ctx2str = str
1894 node2str = short
1895 if ui.debug():
1896 def ctx2str(ctx):
1897 return ctx.hex()
1898 node2str = hex
1899 for rev in scmutil.revrange(repo, revs):
1900 ctx = repo[rev]
1901 ui.write('%s\n'% ctx2str(ctx))
1902 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
1903 if succsset:
1904 ui.write(' ')
1905 ui.write(node2str(succsset[0]))
1906 for node in succsset[1:]:
1907 ui.write(' ')
1908 ui.write(node2str(node))
1909 ui.write('\n')
1910
1911 @command('debugtemplate',
1857 @command('debugtemplate',
1912 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
1858 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
1913 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
1859 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
1914 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
1860 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
1915 optionalrepo=True)
1861 optionalrepo=True)
1916 def debugtemplate(ui, repo, tmpl, **opts):
1862 def debugtemplate(ui, repo, tmpl, **opts):
1917 """parse and apply a template
1863 """parse and apply a template
1918
1864
1919 If -r/--rev is given, the template is processed as a log template and
1865 If -r/--rev is given, the template is processed as a log template and
1920 applied to the given changesets. Otherwise, it is processed as a generic
1866 applied to the given changesets. Otherwise, it is processed as a generic
1921 template.
1867 template.
1922
1868
1923 Use --verbose to print the parsed tree.
1869 Use --verbose to print the parsed tree.
1924 """
1870 """
1925 revs = None
1871 revs = None
1926 if opts['rev']:
1872 if opts['rev']:
1927 if repo is None:
1873 if repo is None:
1928 raise error.RepoError(_('there is no Mercurial repository here '
1874 raise error.RepoError(_('there is no Mercurial repository here '
1929 '(.hg not found)'))
1875 '(.hg not found)'))
1930 revs = scmutil.revrange(repo, opts['rev'])
1876 revs = scmutil.revrange(repo, opts['rev'])
1931
1877
1932 props = {}
1878 props = {}
1933 for d in opts['define']:
1879 for d in opts['define']:
1934 try:
1880 try:
1935 k, v = (e.strip() for e in d.split('=', 1))
1881 k, v = (e.strip() for e in d.split('=', 1))
1936 if not k:
1882 if not k:
1937 raise ValueError
1883 raise ValueError
1938 props[k] = v
1884 props[k] = v
1939 except ValueError:
1885 except ValueError:
1940 raise error.Abort(_('malformed keyword definition: %s') % d)
1886 raise error.Abort(_('malformed keyword definition: %s') % d)
1941
1887
1942 if ui.verbose:
1888 if ui.verbose:
1943 aliases = ui.configitems('templatealias')
1889 aliases = ui.configitems('templatealias')
1944 tree = templater.parse(tmpl)
1890 tree = templater.parse(tmpl)
1945 ui.note(templater.prettyformat(tree), '\n')
1891 ui.note(templater.prettyformat(tree), '\n')
1946 newtree = templater.expandaliases(tree, aliases)
1892 newtree = templater.expandaliases(tree, aliases)
1947 if newtree != tree:
1893 if newtree != tree:
1948 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
1894 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
1949
1895
1950 mapfile = None
1896 mapfile = None
1951 if revs is None:
1897 if revs is None:
1952 k = 'debugtemplate'
1898 k = 'debugtemplate'
1953 t = formatter.maketemplater(ui, k, tmpl)
1899 t = formatter.maketemplater(ui, k, tmpl)
1954 ui.write(templater.stringify(t(k, **props)))
1900 ui.write(templater.stringify(t(k, **props)))
1955 else:
1901 else:
1956 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
1902 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
1957 mapfile, buffered=False)
1903 mapfile, buffered=False)
1958 for r in revs:
1904 for r in revs:
1959 displayer.show(repo[r], **props)
1905 displayer.show(repo[r], **props)
1960 displayer.close()
1906 displayer.close()
1961
1907
1962 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
1908 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
1963 def debugwalk(ui, repo, *pats, **opts):
1909 def debugwalk(ui, repo, *pats, **opts):
1964 """show how files match on given patterns"""
1910 """show how files match on given patterns"""
1965 m = scmutil.match(repo[None], pats, opts)
1911 m = scmutil.match(repo[None], pats, opts)
1966 items = list(repo.walk(m))
1912 items = list(repo.walk(m))
1967 if not items:
1913 if not items:
1968 return
1914 return
1969 f = lambda fn: fn
1915 f = lambda fn: fn
1970 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
1916 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
1971 f = lambda fn: util.normpath(fn)
1917 f = lambda fn: util.normpath(fn)
1972 fmt = 'f %%-%ds %%-%ds %%s' % (
1918 fmt = 'f %%-%ds %%-%ds %%s' % (
1973 max([len(abs) for abs in items]),
1919 max([len(abs) for abs in items]),
1974 max([len(m.rel(abs)) for abs in items]))
1920 max([len(m.rel(abs)) for abs in items]))
1975 for abs in items:
1921 for abs in items:
1976 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
1922 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
1977 ui.write("%s\n" % line.rstrip())
1923 ui.write("%s\n" % line.rstrip())
1978
1924
1979 @command('debugwireargs',
1925 @command('debugwireargs',
1980 [('', 'three', '', 'three'),
1926 [('', 'three', '', 'three'),
1981 ('', 'four', '', 'four'),
1927 ('', 'four', '', 'four'),
1982 ('', 'five', '', 'five'),
1928 ('', 'five', '', 'five'),
1983 ] + remoteopts,
1929 ] + remoteopts,
1984 _('REPO [OPTIONS]... [ONE [TWO]]'),
1930 _('REPO [OPTIONS]... [ONE [TWO]]'),
1985 norepo=True)
1931 norepo=True)
1986 def debugwireargs(ui, repopath, *vals, **opts):
1932 def debugwireargs(ui, repopath, *vals, **opts):
1987 repo = hg.peer(ui, opts, repopath)
1933 repo = hg.peer(ui, opts, repopath)
1988 for opt in remoteopts:
1934 for opt in remoteopts:
1989 del opts[opt[1]]
1935 del opts[opt[1]]
1990 args = {}
1936 args = {}
1991 for k, v in opts.iteritems():
1937 for k, v in opts.iteritems():
1992 if v:
1938 if v:
1993 args[k] = v
1939 args[k] = v
1994 # run twice to check that we don't mess up the stream for the next command
1940 # run twice to check that we don't mess up the stream for the next command
1995 res1 = repo.debugwireargs(*vals, **args)
1941 res1 = repo.debugwireargs(*vals, **args)
1996 res2 = repo.debugwireargs(*vals, **args)
1942 res2 = repo.debugwireargs(*vals, **args)
1997 ui.write("%s\n" % res1)
1943 ui.write("%s\n" % res1)
1998 if res1 != res2:
1944 if res1 != res2:
1999 ui.warn("%s\n" % res2)
1945 ui.warn("%s\n" % res2)
2000
1946
2001 @command('^diff',
1947 @command('^diff',
2002 [('r', 'rev', [], _('revision'), _('REV')),
1948 [('r', 'rev', [], _('revision'), _('REV')),
2003 ('c', 'change', '', _('change made by revision'), _('REV'))
1949 ('c', 'change', '', _('change made by revision'), _('REV'))
2004 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1950 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2005 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1951 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2006 inferrepo=True)
1952 inferrepo=True)
2007 def diff(ui, repo, *pats, **opts):
1953 def diff(ui, repo, *pats, **opts):
2008 """diff repository (or selected files)
1954 """diff repository (or selected files)
2009
1955
2010 Show differences between revisions for the specified files.
1956 Show differences between revisions for the specified files.
2011
1957
2012 Differences between files are shown using the unified diff format.
1958 Differences between files are shown using the unified diff format.
2013
1959
2014 .. note::
1960 .. note::
2015
1961
2016 :hg:`diff` may generate unexpected results for merges, as it will
1962 :hg:`diff` may generate unexpected results for merges, as it will
2017 default to comparing against the working directory's first
1963 default to comparing against the working directory's first
2018 parent changeset if no revisions are specified.
1964 parent changeset if no revisions are specified.
2019
1965
2020 When two revision arguments are given, then changes are shown
1966 When two revision arguments are given, then changes are shown
2021 between those revisions. If only one revision is specified then
1967 between those revisions. If only one revision is specified then
2022 that revision is compared to the working directory, and, when no
1968 that revision is compared to the working directory, and, when no
2023 revisions are specified, the working directory files are compared
1969 revisions are specified, the working directory files are compared
2024 to its first parent.
1970 to its first parent.
2025
1971
2026 Alternatively you can specify -c/--change with a revision to see
1972 Alternatively you can specify -c/--change with a revision to see
2027 the changes in that changeset relative to its first parent.
1973 the changes in that changeset relative to its first parent.
2028
1974
2029 Without the -a/--text option, diff will avoid generating diffs of
1975 Without the -a/--text option, diff will avoid generating diffs of
2030 files it detects as binary. With -a, diff will generate a diff
1976 files it detects as binary. With -a, diff will generate a diff
2031 anyway, probably with undesirable results.
1977 anyway, probably with undesirable results.
2032
1978
2033 Use the -g/--git option to generate diffs in the git extended diff
1979 Use the -g/--git option to generate diffs in the git extended diff
2034 format. For more information, read :hg:`help diffs`.
1980 format. For more information, read :hg:`help diffs`.
2035
1981
2036 .. container:: verbose
1982 .. container:: verbose
2037
1983
2038 Examples:
1984 Examples:
2039
1985
2040 - compare a file in the current working directory to its parent::
1986 - compare a file in the current working directory to its parent::
2041
1987
2042 hg diff foo.c
1988 hg diff foo.c
2043
1989
2044 - compare two historical versions of a directory, with rename info::
1990 - compare two historical versions of a directory, with rename info::
2045
1991
2046 hg diff --git -r 1.0:1.2 lib/
1992 hg diff --git -r 1.0:1.2 lib/
2047
1993
2048 - get change stats relative to the last change on some date::
1994 - get change stats relative to the last change on some date::
2049
1995
2050 hg diff --stat -r "date('may 2')"
1996 hg diff --stat -r "date('may 2')"
2051
1997
2052 - diff all newly-added files that contain a keyword::
1998 - diff all newly-added files that contain a keyword::
2053
1999
2054 hg diff "set:added() and grep(GNU)"
2000 hg diff "set:added() and grep(GNU)"
2055
2001
2056 - compare a revision and its parents::
2002 - compare a revision and its parents::
2057
2003
2058 hg diff -c 9353 # compare against first parent
2004 hg diff -c 9353 # compare against first parent
2059 hg diff -r 9353^:9353 # same using revset syntax
2005 hg diff -r 9353^:9353 # same using revset syntax
2060 hg diff -r 9353^2:9353 # compare against the second parent
2006 hg diff -r 9353^2:9353 # compare against the second parent
2061
2007
2062 Returns 0 on success.
2008 Returns 0 on success.
2063 """
2009 """
2064
2010
2065 revs = opts.get('rev')
2011 revs = opts.get('rev')
2066 change = opts.get('change')
2012 change = opts.get('change')
2067 stat = opts.get('stat')
2013 stat = opts.get('stat')
2068 reverse = opts.get('reverse')
2014 reverse = opts.get('reverse')
2069
2015
2070 if revs and change:
2016 if revs and change:
2071 msg = _('cannot specify --rev and --change at the same time')
2017 msg = _('cannot specify --rev and --change at the same time')
2072 raise error.Abort(msg)
2018 raise error.Abort(msg)
2073 elif change:
2019 elif change:
2074 node2 = scmutil.revsingle(repo, change, None).node()
2020 node2 = scmutil.revsingle(repo, change, None).node()
2075 node1 = repo[node2].p1().node()
2021 node1 = repo[node2].p1().node()
2076 else:
2022 else:
2077 node1, node2 = scmutil.revpair(repo, revs)
2023 node1, node2 = scmutil.revpair(repo, revs)
2078
2024
2079 if reverse:
2025 if reverse:
2080 node1, node2 = node2, node1
2026 node1, node2 = node2, node1
2081
2027
2082 diffopts = patch.diffallopts(ui, opts)
2028 diffopts = patch.diffallopts(ui, opts)
2083 m = scmutil.match(repo[node2], pats, opts)
2029 m = scmutil.match(repo[node2], pats, opts)
2084 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2030 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2085 listsubrepos=opts.get('subrepos'),
2031 listsubrepos=opts.get('subrepos'),
2086 root=opts.get('root'))
2032 root=opts.get('root'))
2087
2033
2088 @command('^export',
2034 @command('^export',
2089 [('o', 'output', '',
2035 [('o', 'output', '',
2090 _('print output to file with formatted name'), _('FORMAT')),
2036 _('print output to file with formatted name'), _('FORMAT')),
2091 ('', 'switch-parent', None, _('diff against the second parent')),
2037 ('', 'switch-parent', None, _('diff against the second parent')),
2092 ('r', 'rev', [], _('revisions to export'), _('REV')),
2038 ('r', 'rev', [], _('revisions to export'), _('REV')),
2093 ] + diffopts,
2039 ] + diffopts,
2094 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2040 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2095 def export(ui, repo, *changesets, **opts):
2041 def export(ui, repo, *changesets, **opts):
2096 """dump the header and diffs for one or more changesets
2042 """dump the header and diffs for one or more changesets
2097
2043
2098 Print the changeset header and diffs for one or more revisions.
2044 Print the changeset header and diffs for one or more revisions.
2099 If no revision is given, the parent of the working directory is used.
2045 If no revision is given, the parent of the working directory is used.
2100
2046
2101 The information shown in the changeset header is: author, date,
2047 The information shown in the changeset header is: author, date,
2102 branch name (if non-default), changeset hash, parent(s) and commit
2048 branch name (if non-default), changeset hash, parent(s) and commit
2103 comment.
2049 comment.
2104
2050
2105 .. note::
2051 .. note::
2106
2052
2107 :hg:`export` may generate unexpected diff output for merge
2053 :hg:`export` may generate unexpected diff output for merge
2108 changesets, as it will compare the merge changeset against its
2054 changesets, as it will compare the merge changeset against its
2109 first parent only.
2055 first parent only.
2110
2056
2111 Output may be to a file, in which case the name of the file is
2057 Output may be to a file, in which case the name of the file is
2112 given using a format string. The formatting rules are as follows:
2058 given using a format string. The formatting rules are as follows:
2113
2059
2114 :``%%``: literal "%" character
2060 :``%%``: literal "%" character
2115 :``%H``: changeset hash (40 hexadecimal digits)
2061 :``%H``: changeset hash (40 hexadecimal digits)
2116 :``%N``: number of patches being generated
2062 :``%N``: number of patches being generated
2117 :``%R``: changeset revision number
2063 :``%R``: changeset revision number
2118 :``%b``: basename of the exporting repository
2064 :``%b``: basename of the exporting repository
2119 :``%h``: short-form changeset hash (12 hexadecimal digits)
2065 :``%h``: short-form changeset hash (12 hexadecimal digits)
2120 :``%m``: first line of the commit message (only alphanumeric characters)
2066 :``%m``: first line of the commit message (only alphanumeric characters)
2121 :``%n``: zero-padded sequence number, starting at 1
2067 :``%n``: zero-padded sequence number, starting at 1
2122 :``%r``: zero-padded changeset revision number
2068 :``%r``: zero-padded changeset revision number
2123
2069
2124 Without the -a/--text option, export will avoid generating diffs
2070 Without the -a/--text option, export will avoid generating diffs
2125 of files it detects as binary. With -a, export will generate a
2071 of files it detects as binary. With -a, export will generate a
2126 diff anyway, probably with undesirable results.
2072 diff anyway, probably with undesirable results.
2127
2073
2128 Use the -g/--git option to generate diffs in the git extended diff
2074 Use the -g/--git option to generate diffs in the git extended diff
2129 format. See :hg:`help diffs` for more information.
2075 format. See :hg:`help diffs` for more information.
2130
2076
2131 With the --switch-parent option, the diff will be against the
2077 With the --switch-parent option, the diff will be against the
2132 second parent. It can be useful to review a merge.
2078 second parent. It can be useful to review a merge.
2133
2079
2134 .. container:: verbose
2080 .. container:: verbose
2135
2081
2136 Examples:
2082 Examples:
2137
2083
2138 - use export and import to transplant a bugfix to the current
2084 - use export and import to transplant a bugfix to the current
2139 branch::
2085 branch::
2140
2086
2141 hg export -r 9353 | hg import -
2087 hg export -r 9353 | hg import -
2142
2088
2143 - export all the changesets between two revisions to a file with
2089 - export all the changesets between two revisions to a file with
2144 rename information::
2090 rename information::
2145
2091
2146 hg export --git -r 123:150 > changes.txt
2092 hg export --git -r 123:150 > changes.txt
2147
2093
2148 - split outgoing changes into a series of patches with
2094 - split outgoing changes into a series of patches with
2149 descriptive names::
2095 descriptive names::
2150
2096
2151 hg export -r "outgoing()" -o "%n-%m.patch"
2097 hg export -r "outgoing()" -o "%n-%m.patch"
2152
2098
2153 Returns 0 on success.
2099 Returns 0 on success.
2154 """
2100 """
2155 changesets += tuple(opts.get('rev', []))
2101 changesets += tuple(opts.get('rev', []))
2156 if not changesets:
2102 if not changesets:
2157 changesets = ['.']
2103 changesets = ['.']
2158 revs = scmutil.revrange(repo, changesets)
2104 revs = scmutil.revrange(repo, changesets)
2159 if not revs:
2105 if not revs:
2160 raise error.Abort(_("export requires at least one changeset"))
2106 raise error.Abort(_("export requires at least one changeset"))
2161 if len(revs) > 1:
2107 if len(revs) > 1:
2162 ui.note(_('exporting patches:\n'))
2108 ui.note(_('exporting patches:\n'))
2163 else:
2109 else:
2164 ui.note(_('exporting patch:\n'))
2110 ui.note(_('exporting patch:\n'))
2165 cmdutil.export(repo, revs, template=opts.get('output'),
2111 cmdutil.export(repo, revs, template=opts.get('output'),
2166 switch_parent=opts.get('switch_parent'),
2112 switch_parent=opts.get('switch_parent'),
2167 opts=patch.diffallopts(ui, opts))
2113 opts=patch.diffallopts(ui, opts))
2168
2114
2169 @command('files',
2115 @command('files',
2170 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2116 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2171 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2117 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2172 ] + walkopts + formatteropts + subrepoopts,
2118 ] + walkopts + formatteropts + subrepoopts,
2173 _('[OPTION]... [FILE]...'))
2119 _('[OPTION]... [FILE]...'))
2174 def files(ui, repo, *pats, **opts):
2120 def files(ui, repo, *pats, **opts):
2175 """list tracked files
2121 """list tracked files
2176
2122
2177 Print files under Mercurial control in the working directory or
2123 Print files under Mercurial control in the working directory or
2178 specified revision for given files (excluding removed files).
2124 specified revision for given files (excluding removed files).
2179 Files can be specified as filenames or filesets.
2125 Files can be specified as filenames or filesets.
2180
2126
2181 If no files are given to match, this command prints the names
2127 If no files are given to match, this command prints the names
2182 of all files under Mercurial control.
2128 of all files under Mercurial control.
2183
2129
2184 .. container:: verbose
2130 .. container:: verbose
2185
2131
2186 Examples:
2132 Examples:
2187
2133
2188 - list all files under the current directory::
2134 - list all files under the current directory::
2189
2135
2190 hg files .
2136 hg files .
2191
2137
2192 - shows sizes and flags for current revision::
2138 - shows sizes and flags for current revision::
2193
2139
2194 hg files -vr .
2140 hg files -vr .
2195
2141
2196 - list all files named README::
2142 - list all files named README::
2197
2143
2198 hg files -I "**/README"
2144 hg files -I "**/README"
2199
2145
2200 - list all binary files::
2146 - list all binary files::
2201
2147
2202 hg files "set:binary()"
2148 hg files "set:binary()"
2203
2149
2204 - find files containing a regular expression::
2150 - find files containing a regular expression::
2205
2151
2206 hg files "set:grep('bob')"
2152 hg files "set:grep('bob')"
2207
2153
2208 - search tracked file contents with xargs and grep::
2154 - search tracked file contents with xargs and grep::
2209
2155
2210 hg files -0 | xargs -0 grep foo
2156 hg files -0 | xargs -0 grep foo
2211
2157
2212 See :hg:`help patterns` and :hg:`help filesets` for more information
2158 See :hg:`help patterns` and :hg:`help filesets` for more information
2213 on specifying file patterns.
2159 on specifying file patterns.
2214
2160
2215 Returns 0 if a match is found, 1 otherwise.
2161 Returns 0 if a match is found, 1 otherwise.
2216
2162
2217 """
2163 """
2218 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2164 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2219
2165
2220 end = '\n'
2166 end = '\n'
2221 if opts.get('print0'):
2167 if opts.get('print0'):
2222 end = '\0'
2168 end = '\0'
2223 fmt = '%s' + end
2169 fmt = '%s' + end
2224
2170
2225 m = scmutil.match(ctx, pats, opts)
2171 m = scmutil.match(ctx, pats, opts)
2226 with ui.formatter('files', opts) as fm:
2172 with ui.formatter('files', opts) as fm:
2227 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2173 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2228
2174
2229 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2175 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2230 def forget(ui, repo, *pats, **opts):
2176 def forget(ui, repo, *pats, **opts):
2231 """forget the specified files on the next commit
2177 """forget the specified files on the next commit
2232
2178
2233 Mark the specified files so they will no longer be tracked
2179 Mark the specified files so they will no longer be tracked
2234 after the next commit.
2180 after the next commit.
2235
2181
2236 This only removes files from the current branch, not from the
2182 This only removes files from the current branch, not from the
2237 entire project history, and it does not delete them from the
2183 entire project history, and it does not delete them from the
2238 working directory.
2184 working directory.
2239
2185
2240 To delete the file from the working directory, see :hg:`remove`.
2186 To delete the file from the working directory, see :hg:`remove`.
2241
2187
2242 To undo a forget before the next commit, see :hg:`add`.
2188 To undo a forget before the next commit, see :hg:`add`.
2243
2189
2244 .. container:: verbose
2190 .. container:: verbose
2245
2191
2246 Examples:
2192 Examples:
2247
2193
2248 - forget newly-added binary files::
2194 - forget newly-added binary files::
2249
2195
2250 hg forget "set:added() and binary()"
2196 hg forget "set:added() and binary()"
2251
2197
2252 - forget files that would be excluded by .hgignore::
2198 - forget files that would be excluded by .hgignore::
2253
2199
2254 hg forget "set:hgignore()"
2200 hg forget "set:hgignore()"
2255
2201
2256 Returns 0 on success.
2202 Returns 0 on success.
2257 """
2203 """
2258
2204
2259 if not pats:
2205 if not pats:
2260 raise error.Abort(_('no files specified'))
2206 raise error.Abort(_('no files specified'))
2261
2207
2262 m = scmutil.match(repo[None], pats, opts)
2208 m = scmutil.match(repo[None], pats, opts)
2263 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2209 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2264 return rejected and 1 or 0
2210 return rejected and 1 or 0
2265
2211
2266 @command(
2212 @command(
2267 'graft',
2213 'graft',
2268 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2214 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2269 ('c', 'continue', False, _('resume interrupted graft')),
2215 ('c', 'continue', False, _('resume interrupted graft')),
2270 ('e', 'edit', False, _('invoke editor on commit messages')),
2216 ('e', 'edit', False, _('invoke editor on commit messages')),
2271 ('', 'log', None, _('append graft info to log message')),
2217 ('', 'log', None, _('append graft info to log message')),
2272 ('f', 'force', False, _('force graft')),
2218 ('f', 'force', False, _('force graft')),
2273 ('D', 'currentdate', False,
2219 ('D', 'currentdate', False,
2274 _('record the current date as commit date')),
2220 _('record the current date as commit date')),
2275 ('U', 'currentuser', False,
2221 ('U', 'currentuser', False,
2276 _('record the current user as committer'), _('DATE'))]
2222 _('record the current user as committer'), _('DATE'))]
2277 + commitopts2 + mergetoolopts + dryrunopts,
2223 + commitopts2 + mergetoolopts + dryrunopts,
2278 _('[OPTION]... [-r REV]... REV...'))
2224 _('[OPTION]... [-r REV]... REV...'))
2279 def graft(ui, repo, *revs, **opts):
2225 def graft(ui, repo, *revs, **opts):
2280 '''copy changes from other branches onto the current branch
2226 '''copy changes from other branches onto the current branch
2281
2227
2282 This command uses Mercurial's merge logic to copy individual
2228 This command uses Mercurial's merge logic to copy individual
2283 changes from other branches without merging branches in the
2229 changes from other branches without merging branches in the
2284 history graph. This is sometimes known as 'backporting' or
2230 history graph. This is sometimes known as 'backporting' or
2285 'cherry-picking'. By default, graft will copy user, date, and
2231 'cherry-picking'. By default, graft will copy user, date, and
2286 description from the source changesets.
2232 description from the source changesets.
2287
2233
2288 Changesets that are ancestors of the current revision, that have
2234 Changesets that are ancestors of the current revision, that have
2289 already been grafted, or that are merges will be skipped.
2235 already been grafted, or that are merges will be skipped.
2290
2236
2291 If --log is specified, log messages will have a comment appended
2237 If --log is specified, log messages will have a comment appended
2292 of the form::
2238 of the form::
2293
2239
2294 (grafted from CHANGESETHASH)
2240 (grafted from CHANGESETHASH)
2295
2241
2296 If --force is specified, revisions will be grafted even if they
2242 If --force is specified, revisions will be grafted even if they
2297 are already ancestors of or have been grafted to the destination.
2243 are already ancestors of or have been grafted to the destination.
2298 This is useful when the revisions have since been backed out.
2244 This is useful when the revisions have since been backed out.
2299
2245
2300 If a graft merge results in conflicts, the graft process is
2246 If a graft merge results in conflicts, the graft process is
2301 interrupted so that the current merge can be manually resolved.
2247 interrupted so that the current merge can be manually resolved.
2302 Once all conflicts are addressed, the graft process can be
2248 Once all conflicts are addressed, the graft process can be
2303 continued with the -c/--continue option.
2249 continued with the -c/--continue option.
2304
2250
2305 .. note::
2251 .. note::
2306
2252
2307 The -c/--continue option does not reapply earlier options, except
2253 The -c/--continue option does not reapply earlier options, except
2308 for --force.
2254 for --force.
2309
2255
2310 .. container:: verbose
2256 .. container:: verbose
2311
2257
2312 Examples:
2258 Examples:
2313
2259
2314 - copy a single change to the stable branch and edit its description::
2260 - copy a single change to the stable branch and edit its description::
2315
2261
2316 hg update stable
2262 hg update stable
2317 hg graft --edit 9393
2263 hg graft --edit 9393
2318
2264
2319 - graft a range of changesets with one exception, updating dates::
2265 - graft a range of changesets with one exception, updating dates::
2320
2266
2321 hg graft -D "2085::2093 and not 2091"
2267 hg graft -D "2085::2093 and not 2091"
2322
2268
2323 - continue a graft after resolving conflicts::
2269 - continue a graft after resolving conflicts::
2324
2270
2325 hg graft -c
2271 hg graft -c
2326
2272
2327 - show the source of a grafted changeset::
2273 - show the source of a grafted changeset::
2328
2274
2329 hg log --debug -r .
2275 hg log --debug -r .
2330
2276
2331 - show revisions sorted by date::
2277 - show revisions sorted by date::
2332
2278
2333 hg log -r "sort(all(), date)"
2279 hg log -r "sort(all(), date)"
2334
2280
2335 See :hg:`help revisions` for more about specifying revisions.
2281 See :hg:`help revisions` for more about specifying revisions.
2336
2282
2337 Returns 0 on successful completion.
2283 Returns 0 on successful completion.
2338 '''
2284 '''
2339 with repo.wlock():
2285 with repo.wlock():
2340 return _dograft(ui, repo, *revs, **opts)
2286 return _dograft(ui, repo, *revs, **opts)
2341
2287
2342 def _dograft(ui, repo, *revs, **opts):
2288 def _dograft(ui, repo, *revs, **opts):
2343 if revs and opts.get('rev'):
2289 if revs and opts.get('rev'):
2344 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2290 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2345 'revision ordering!\n'))
2291 'revision ordering!\n'))
2346
2292
2347 revs = list(revs)
2293 revs = list(revs)
2348 revs.extend(opts.get('rev'))
2294 revs.extend(opts.get('rev'))
2349
2295
2350 if not opts.get('user') and opts.get('currentuser'):
2296 if not opts.get('user') and opts.get('currentuser'):
2351 opts['user'] = ui.username()
2297 opts['user'] = ui.username()
2352 if not opts.get('date') and opts.get('currentdate'):
2298 if not opts.get('date') and opts.get('currentdate'):
2353 opts['date'] = "%d %d" % util.makedate()
2299 opts['date'] = "%d %d" % util.makedate()
2354
2300
2355 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2301 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2356
2302
2357 cont = False
2303 cont = False
2358 if opts.get('continue'):
2304 if opts.get('continue'):
2359 cont = True
2305 cont = True
2360 if revs:
2306 if revs:
2361 raise error.Abort(_("can't specify --continue and revisions"))
2307 raise error.Abort(_("can't specify --continue and revisions"))
2362 # read in unfinished revisions
2308 # read in unfinished revisions
2363 try:
2309 try:
2364 nodes = repo.vfs.read('graftstate').splitlines()
2310 nodes = repo.vfs.read('graftstate').splitlines()
2365 revs = [repo[node].rev() for node in nodes]
2311 revs = [repo[node].rev() for node in nodes]
2366 except IOError as inst:
2312 except IOError as inst:
2367 if inst.errno != errno.ENOENT:
2313 if inst.errno != errno.ENOENT:
2368 raise
2314 raise
2369 cmdutil.wrongtooltocontinue(repo, _('graft'))
2315 cmdutil.wrongtooltocontinue(repo, _('graft'))
2370 else:
2316 else:
2371 cmdutil.checkunfinished(repo)
2317 cmdutil.checkunfinished(repo)
2372 cmdutil.bailifchanged(repo)
2318 cmdutil.bailifchanged(repo)
2373 if not revs:
2319 if not revs:
2374 raise error.Abort(_('no revisions specified'))
2320 raise error.Abort(_('no revisions specified'))
2375 revs = scmutil.revrange(repo, revs)
2321 revs = scmutil.revrange(repo, revs)
2376
2322
2377 skipped = set()
2323 skipped = set()
2378 # check for merges
2324 # check for merges
2379 for rev in repo.revs('%ld and merge()', revs):
2325 for rev in repo.revs('%ld and merge()', revs):
2380 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2326 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2381 skipped.add(rev)
2327 skipped.add(rev)
2382 revs = [r for r in revs if r not in skipped]
2328 revs = [r for r in revs if r not in skipped]
2383 if not revs:
2329 if not revs:
2384 return -1
2330 return -1
2385
2331
2386 # Don't check in the --continue case, in effect retaining --force across
2332 # Don't check in the --continue case, in effect retaining --force across
2387 # --continues. That's because without --force, any revisions we decided to
2333 # --continues. That's because without --force, any revisions we decided to
2388 # skip would have been filtered out here, so they wouldn't have made their
2334 # skip would have been filtered out here, so they wouldn't have made their
2389 # way to the graftstate. With --force, any revisions we would have otherwise
2335 # way to the graftstate. With --force, any revisions we would have otherwise
2390 # skipped would not have been filtered out, and if they hadn't been applied
2336 # skipped would not have been filtered out, and if they hadn't been applied
2391 # already, they'd have been in the graftstate.
2337 # already, they'd have been in the graftstate.
2392 if not (cont or opts.get('force')):
2338 if not (cont or opts.get('force')):
2393 # check for ancestors of dest branch
2339 # check for ancestors of dest branch
2394 crev = repo['.'].rev()
2340 crev = repo['.'].rev()
2395 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2341 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2396 # XXX make this lazy in the future
2342 # XXX make this lazy in the future
2397 # don't mutate while iterating, create a copy
2343 # don't mutate while iterating, create a copy
2398 for rev in list(revs):
2344 for rev in list(revs):
2399 if rev in ancestors:
2345 if rev in ancestors:
2400 ui.warn(_('skipping ancestor revision %d:%s\n') %
2346 ui.warn(_('skipping ancestor revision %d:%s\n') %
2401 (rev, repo[rev]))
2347 (rev, repo[rev]))
2402 # XXX remove on list is slow
2348 # XXX remove on list is slow
2403 revs.remove(rev)
2349 revs.remove(rev)
2404 if not revs:
2350 if not revs:
2405 return -1
2351 return -1
2406
2352
2407 # analyze revs for earlier grafts
2353 # analyze revs for earlier grafts
2408 ids = {}
2354 ids = {}
2409 for ctx in repo.set("%ld", revs):
2355 for ctx in repo.set("%ld", revs):
2410 ids[ctx.hex()] = ctx.rev()
2356 ids[ctx.hex()] = ctx.rev()
2411 n = ctx.extra().get('source')
2357 n = ctx.extra().get('source')
2412 if n:
2358 if n:
2413 ids[n] = ctx.rev()
2359 ids[n] = ctx.rev()
2414
2360
2415 # check ancestors for earlier grafts
2361 # check ancestors for earlier grafts
2416 ui.debug('scanning for duplicate grafts\n')
2362 ui.debug('scanning for duplicate grafts\n')
2417
2363
2418 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2364 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2419 ctx = repo[rev]
2365 ctx = repo[rev]
2420 n = ctx.extra().get('source')
2366 n = ctx.extra().get('source')
2421 if n in ids:
2367 if n in ids:
2422 try:
2368 try:
2423 r = repo[n].rev()
2369 r = repo[n].rev()
2424 except error.RepoLookupError:
2370 except error.RepoLookupError:
2425 r = None
2371 r = None
2426 if r in revs:
2372 if r in revs:
2427 ui.warn(_('skipping revision %d:%s '
2373 ui.warn(_('skipping revision %d:%s '
2428 '(already grafted to %d:%s)\n')
2374 '(already grafted to %d:%s)\n')
2429 % (r, repo[r], rev, ctx))
2375 % (r, repo[r], rev, ctx))
2430 revs.remove(r)
2376 revs.remove(r)
2431 elif ids[n] in revs:
2377 elif ids[n] in revs:
2432 if r is None:
2378 if r is None:
2433 ui.warn(_('skipping already grafted revision %d:%s '
2379 ui.warn(_('skipping already grafted revision %d:%s '
2434 '(%d:%s also has unknown origin %s)\n')
2380 '(%d:%s also has unknown origin %s)\n')
2435 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2381 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2436 else:
2382 else:
2437 ui.warn(_('skipping already grafted revision %d:%s '
2383 ui.warn(_('skipping already grafted revision %d:%s '
2438 '(%d:%s also has origin %d:%s)\n')
2384 '(%d:%s also has origin %d:%s)\n')
2439 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2385 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2440 revs.remove(ids[n])
2386 revs.remove(ids[n])
2441 elif ctx.hex() in ids:
2387 elif ctx.hex() in ids:
2442 r = ids[ctx.hex()]
2388 r = ids[ctx.hex()]
2443 ui.warn(_('skipping already grafted revision %d:%s '
2389 ui.warn(_('skipping already grafted revision %d:%s '
2444 '(was grafted from %d:%s)\n') %
2390 '(was grafted from %d:%s)\n') %
2445 (r, repo[r], rev, ctx))
2391 (r, repo[r], rev, ctx))
2446 revs.remove(r)
2392 revs.remove(r)
2447 if not revs:
2393 if not revs:
2448 return -1
2394 return -1
2449
2395
2450 for pos, ctx in enumerate(repo.set("%ld", revs)):
2396 for pos, ctx in enumerate(repo.set("%ld", revs)):
2451 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2397 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2452 ctx.description().split('\n', 1)[0])
2398 ctx.description().split('\n', 1)[0])
2453 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2399 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2454 if names:
2400 if names:
2455 desc += ' (%s)' % ' '.join(names)
2401 desc += ' (%s)' % ' '.join(names)
2456 ui.status(_('grafting %s\n') % desc)
2402 ui.status(_('grafting %s\n') % desc)
2457 if opts.get('dry_run'):
2403 if opts.get('dry_run'):
2458 continue
2404 continue
2459
2405
2460 source = ctx.extra().get('source')
2406 source = ctx.extra().get('source')
2461 extra = {}
2407 extra = {}
2462 if source:
2408 if source:
2463 extra['source'] = source
2409 extra['source'] = source
2464 extra['intermediate-source'] = ctx.hex()
2410 extra['intermediate-source'] = ctx.hex()
2465 else:
2411 else:
2466 extra['source'] = ctx.hex()
2412 extra['source'] = ctx.hex()
2467 user = ctx.user()
2413 user = ctx.user()
2468 if opts.get('user'):
2414 if opts.get('user'):
2469 user = opts['user']
2415 user = opts['user']
2470 date = ctx.date()
2416 date = ctx.date()
2471 if opts.get('date'):
2417 if opts.get('date'):
2472 date = opts['date']
2418 date = opts['date']
2473 message = ctx.description()
2419 message = ctx.description()
2474 if opts.get('log'):
2420 if opts.get('log'):
2475 message += '\n(grafted from %s)' % ctx.hex()
2421 message += '\n(grafted from %s)' % ctx.hex()
2476
2422
2477 # we don't merge the first commit when continuing
2423 # we don't merge the first commit when continuing
2478 if not cont:
2424 if not cont:
2479 # perform the graft merge with p1(rev) as 'ancestor'
2425 # perform the graft merge with p1(rev) as 'ancestor'
2480 try:
2426 try:
2481 # ui.forcemerge is an internal variable, do not document
2427 # ui.forcemerge is an internal variable, do not document
2482 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2428 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2483 'graft')
2429 'graft')
2484 stats = mergemod.graft(repo, ctx, ctx.p1(),
2430 stats = mergemod.graft(repo, ctx, ctx.p1(),
2485 ['local', 'graft'])
2431 ['local', 'graft'])
2486 finally:
2432 finally:
2487 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2433 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2488 # report any conflicts
2434 # report any conflicts
2489 if stats and stats[3] > 0:
2435 if stats and stats[3] > 0:
2490 # write out state for --continue
2436 # write out state for --continue
2491 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2437 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2492 repo.vfs.write('graftstate', ''.join(nodelines))
2438 repo.vfs.write('graftstate', ''.join(nodelines))
2493 extra = ''
2439 extra = ''
2494 if opts.get('user'):
2440 if opts.get('user'):
2495 extra += ' --user %s' % util.shellquote(opts['user'])
2441 extra += ' --user %s' % util.shellquote(opts['user'])
2496 if opts.get('date'):
2442 if opts.get('date'):
2497 extra += ' --date %s' % util.shellquote(opts['date'])
2443 extra += ' --date %s' % util.shellquote(opts['date'])
2498 if opts.get('log'):
2444 if opts.get('log'):
2499 extra += ' --log'
2445 extra += ' --log'
2500 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2446 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2501 raise error.Abort(
2447 raise error.Abort(
2502 _("unresolved conflicts, can't continue"),
2448 _("unresolved conflicts, can't continue"),
2503 hint=hint)
2449 hint=hint)
2504 else:
2450 else:
2505 cont = False
2451 cont = False
2506
2452
2507 # commit
2453 # commit
2508 node = repo.commit(text=message, user=user,
2454 node = repo.commit(text=message, user=user,
2509 date=date, extra=extra, editor=editor)
2455 date=date, extra=extra, editor=editor)
2510 if node is None:
2456 if node is None:
2511 ui.warn(
2457 ui.warn(
2512 _('note: graft of %d:%s created no changes to commit\n') %
2458 _('note: graft of %d:%s created no changes to commit\n') %
2513 (ctx.rev(), ctx))
2459 (ctx.rev(), ctx))
2514
2460
2515 # remove state when we complete successfully
2461 # remove state when we complete successfully
2516 if not opts.get('dry_run'):
2462 if not opts.get('dry_run'):
2517 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2463 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2518
2464
2519 return 0
2465 return 0
2520
2466
2521 @command('grep',
2467 @command('grep',
2522 [('0', 'print0', None, _('end fields with NUL')),
2468 [('0', 'print0', None, _('end fields with NUL')),
2523 ('', 'all', None, _('print all revisions that match')),
2469 ('', 'all', None, _('print all revisions that match')),
2524 ('a', 'text', None, _('treat all files as text')),
2470 ('a', 'text', None, _('treat all files as text')),
2525 ('f', 'follow', None,
2471 ('f', 'follow', None,
2526 _('follow changeset history,'
2472 _('follow changeset history,'
2527 ' or file history across copies and renames')),
2473 ' or file history across copies and renames')),
2528 ('i', 'ignore-case', None, _('ignore case when matching')),
2474 ('i', 'ignore-case', None, _('ignore case when matching')),
2529 ('l', 'files-with-matches', None,
2475 ('l', 'files-with-matches', None,
2530 _('print only filenames and revisions that match')),
2476 _('print only filenames and revisions that match')),
2531 ('n', 'line-number', None, _('print matching line numbers')),
2477 ('n', 'line-number', None, _('print matching line numbers')),
2532 ('r', 'rev', [],
2478 ('r', 'rev', [],
2533 _('only search files changed within revision range'), _('REV')),
2479 _('only search files changed within revision range'), _('REV')),
2534 ('u', 'user', None, _('list the author (long with -v)')),
2480 ('u', 'user', None, _('list the author (long with -v)')),
2535 ('d', 'date', None, _('list the date (short with -q)')),
2481 ('d', 'date', None, _('list the date (short with -q)')),
2536 ] + formatteropts + walkopts,
2482 ] + formatteropts + walkopts,
2537 _('[OPTION]... PATTERN [FILE]...'),
2483 _('[OPTION]... PATTERN [FILE]...'),
2538 inferrepo=True)
2484 inferrepo=True)
2539 def grep(ui, repo, pattern, *pats, **opts):
2485 def grep(ui, repo, pattern, *pats, **opts):
2540 """search revision history for a pattern in specified files
2486 """search revision history for a pattern in specified files
2541
2487
2542 Search revision history for a regular expression in the specified
2488 Search revision history for a regular expression in the specified
2543 files or the entire project.
2489 files or the entire project.
2544
2490
2545 By default, grep prints the most recent revision number for each
2491 By default, grep prints the most recent revision number for each
2546 file in which it finds a match. To get it to print every revision
2492 file in which it finds a match. To get it to print every revision
2547 that contains a change in match status ("-" for a match that becomes
2493 that contains a change in match status ("-" for a match that becomes
2548 a non-match, or "+" for a non-match that becomes a match), use the
2494 a non-match, or "+" for a non-match that becomes a match), use the
2549 --all flag.
2495 --all flag.
2550
2496
2551 PATTERN can be any Python (roughly Perl-compatible) regular
2497 PATTERN can be any Python (roughly Perl-compatible) regular
2552 expression.
2498 expression.
2553
2499
2554 If no FILEs are specified (and -f/--follow isn't set), all files in
2500 If no FILEs are specified (and -f/--follow isn't set), all files in
2555 the repository are searched, including those that don't exist in the
2501 the repository are searched, including those that don't exist in the
2556 current branch or have been deleted in a prior changeset.
2502 current branch or have been deleted in a prior changeset.
2557
2503
2558 Returns 0 if a match is found, 1 otherwise.
2504 Returns 0 if a match is found, 1 otherwise.
2559 """
2505 """
2560 reflags = re.M
2506 reflags = re.M
2561 if opts.get('ignore_case'):
2507 if opts.get('ignore_case'):
2562 reflags |= re.I
2508 reflags |= re.I
2563 try:
2509 try:
2564 regexp = util.re.compile(pattern, reflags)
2510 regexp = util.re.compile(pattern, reflags)
2565 except re.error as inst:
2511 except re.error as inst:
2566 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2512 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2567 return 1
2513 return 1
2568 sep, eol = ':', '\n'
2514 sep, eol = ':', '\n'
2569 if opts.get('print0'):
2515 if opts.get('print0'):
2570 sep = eol = '\0'
2516 sep = eol = '\0'
2571
2517
2572 getfile = util.lrucachefunc(repo.file)
2518 getfile = util.lrucachefunc(repo.file)
2573
2519
2574 def matchlines(body):
2520 def matchlines(body):
2575 begin = 0
2521 begin = 0
2576 linenum = 0
2522 linenum = 0
2577 while begin < len(body):
2523 while begin < len(body):
2578 match = regexp.search(body, begin)
2524 match = regexp.search(body, begin)
2579 if not match:
2525 if not match:
2580 break
2526 break
2581 mstart, mend = match.span()
2527 mstart, mend = match.span()
2582 linenum += body.count('\n', begin, mstart) + 1
2528 linenum += body.count('\n', begin, mstart) + 1
2583 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2529 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2584 begin = body.find('\n', mend) + 1 or len(body) + 1
2530 begin = body.find('\n', mend) + 1 or len(body) + 1
2585 lend = begin - 1
2531 lend = begin - 1
2586 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2532 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2587
2533
2588 class linestate(object):
2534 class linestate(object):
2589 def __init__(self, line, linenum, colstart, colend):
2535 def __init__(self, line, linenum, colstart, colend):
2590 self.line = line
2536 self.line = line
2591 self.linenum = linenum
2537 self.linenum = linenum
2592 self.colstart = colstart
2538 self.colstart = colstart
2593 self.colend = colend
2539 self.colend = colend
2594
2540
2595 def __hash__(self):
2541 def __hash__(self):
2596 return hash((self.linenum, self.line))
2542 return hash((self.linenum, self.line))
2597
2543
2598 def __eq__(self, other):
2544 def __eq__(self, other):
2599 return self.line == other.line
2545 return self.line == other.line
2600
2546
2601 def findpos(self):
2547 def findpos(self):
2602 """Iterate all (start, end) indices of matches"""
2548 """Iterate all (start, end) indices of matches"""
2603 yield self.colstart, self.colend
2549 yield self.colstart, self.colend
2604 p = self.colend
2550 p = self.colend
2605 while p < len(self.line):
2551 while p < len(self.line):
2606 m = regexp.search(self.line, p)
2552 m = regexp.search(self.line, p)
2607 if not m:
2553 if not m:
2608 break
2554 break
2609 yield m.span()
2555 yield m.span()
2610 p = m.end()
2556 p = m.end()
2611
2557
2612 matches = {}
2558 matches = {}
2613 copies = {}
2559 copies = {}
2614 def grepbody(fn, rev, body):
2560 def grepbody(fn, rev, body):
2615 matches[rev].setdefault(fn, [])
2561 matches[rev].setdefault(fn, [])
2616 m = matches[rev][fn]
2562 m = matches[rev][fn]
2617 for lnum, cstart, cend, line in matchlines(body):
2563 for lnum, cstart, cend, line in matchlines(body):
2618 s = linestate(line, lnum, cstart, cend)
2564 s = linestate(line, lnum, cstart, cend)
2619 m.append(s)
2565 m.append(s)
2620
2566
2621 def difflinestates(a, b):
2567 def difflinestates(a, b):
2622 sm = difflib.SequenceMatcher(None, a, b)
2568 sm = difflib.SequenceMatcher(None, a, b)
2623 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2569 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2624 if tag == 'insert':
2570 if tag == 'insert':
2625 for i in xrange(blo, bhi):
2571 for i in xrange(blo, bhi):
2626 yield ('+', b[i])
2572 yield ('+', b[i])
2627 elif tag == 'delete':
2573 elif tag == 'delete':
2628 for i in xrange(alo, ahi):
2574 for i in xrange(alo, ahi):
2629 yield ('-', a[i])
2575 yield ('-', a[i])
2630 elif tag == 'replace':
2576 elif tag == 'replace':
2631 for i in xrange(alo, ahi):
2577 for i in xrange(alo, ahi):
2632 yield ('-', a[i])
2578 yield ('-', a[i])
2633 for i in xrange(blo, bhi):
2579 for i in xrange(blo, bhi):
2634 yield ('+', b[i])
2580 yield ('+', b[i])
2635
2581
2636 def display(fm, fn, ctx, pstates, states):
2582 def display(fm, fn, ctx, pstates, states):
2637 rev = ctx.rev()
2583 rev = ctx.rev()
2638 if fm.isplain():
2584 if fm.isplain():
2639 formatuser = ui.shortuser
2585 formatuser = ui.shortuser
2640 else:
2586 else:
2641 formatuser = str
2587 formatuser = str
2642 if ui.quiet:
2588 if ui.quiet:
2643 datefmt = '%Y-%m-%d'
2589 datefmt = '%Y-%m-%d'
2644 else:
2590 else:
2645 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2591 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2646 found = False
2592 found = False
2647 @util.cachefunc
2593 @util.cachefunc
2648 def binary():
2594 def binary():
2649 flog = getfile(fn)
2595 flog = getfile(fn)
2650 return util.binary(flog.read(ctx.filenode(fn)))
2596 return util.binary(flog.read(ctx.filenode(fn)))
2651
2597
2652 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2598 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2653 if opts.get('all'):
2599 if opts.get('all'):
2654 iter = difflinestates(pstates, states)
2600 iter = difflinestates(pstates, states)
2655 else:
2601 else:
2656 iter = [('', l) for l in states]
2602 iter = [('', l) for l in states]
2657 for change, l in iter:
2603 for change, l in iter:
2658 fm.startitem()
2604 fm.startitem()
2659 fm.data(node=fm.hexfunc(ctx.node()))
2605 fm.data(node=fm.hexfunc(ctx.node()))
2660 cols = [
2606 cols = [
2661 ('filename', fn, True),
2607 ('filename', fn, True),
2662 ('rev', rev, True),
2608 ('rev', rev, True),
2663 ('linenumber', l.linenum, opts.get('line_number')),
2609 ('linenumber', l.linenum, opts.get('line_number')),
2664 ]
2610 ]
2665 if opts.get('all'):
2611 if opts.get('all'):
2666 cols.append(('change', change, True))
2612 cols.append(('change', change, True))
2667 cols.extend([
2613 cols.extend([
2668 ('user', formatuser(ctx.user()), opts.get('user')),
2614 ('user', formatuser(ctx.user()), opts.get('user')),
2669 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2615 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2670 ])
2616 ])
2671 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2617 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2672 for name, data, cond in cols:
2618 for name, data, cond in cols:
2673 field = fieldnamemap.get(name, name)
2619 field = fieldnamemap.get(name, name)
2674 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2620 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2675 if cond and name != lastcol:
2621 if cond and name != lastcol:
2676 fm.plain(sep, label='grep.sep')
2622 fm.plain(sep, label='grep.sep')
2677 if not opts.get('files_with_matches'):
2623 if not opts.get('files_with_matches'):
2678 fm.plain(sep, label='grep.sep')
2624 fm.plain(sep, label='grep.sep')
2679 if not opts.get('text') and binary():
2625 if not opts.get('text') and binary():
2680 fm.plain(_(" Binary file matches"))
2626 fm.plain(_(" Binary file matches"))
2681 else:
2627 else:
2682 displaymatches(fm.nested('texts'), l)
2628 displaymatches(fm.nested('texts'), l)
2683 fm.plain(eol)
2629 fm.plain(eol)
2684 found = True
2630 found = True
2685 if opts.get('files_with_matches'):
2631 if opts.get('files_with_matches'):
2686 break
2632 break
2687 return found
2633 return found
2688
2634
2689 def displaymatches(fm, l):
2635 def displaymatches(fm, l):
2690 p = 0
2636 p = 0
2691 for s, e in l.findpos():
2637 for s, e in l.findpos():
2692 if p < s:
2638 if p < s:
2693 fm.startitem()
2639 fm.startitem()
2694 fm.write('text', '%s', l.line[p:s])
2640 fm.write('text', '%s', l.line[p:s])
2695 fm.data(matched=False)
2641 fm.data(matched=False)
2696 fm.startitem()
2642 fm.startitem()
2697 fm.write('text', '%s', l.line[s:e], label='grep.match')
2643 fm.write('text', '%s', l.line[s:e], label='grep.match')
2698 fm.data(matched=True)
2644 fm.data(matched=True)
2699 p = e
2645 p = e
2700 if p < len(l.line):
2646 if p < len(l.line):
2701 fm.startitem()
2647 fm.startitem()
2702 fm.write('text', '%s', l.line[p:])
2648 fm.write('text', '%s', l.line[p:])
2703 fm.data(matched=False)
2649 fm.data(matched=False)
2704 fm.end()
2650 fm.end()
2705
2651
2706 skip = {}
2652 skip = {}
2707 revfiles = {}
2653 revfiles = {}
2708 matchfn = scmutil.match(repo[None], pats, opts)
2654 matchfn = scmutil.match(repo[None], pats, opts)
2709 found = False
2655 found = False
2710 follow = opts.get('follow')
2656 follow = opts.get('follow')
2711
2657
2712 def prep(ctx, fns):
2658 def prep(ctx, fns):
2713 rev = ctx.rev()
2659 rev = ctx.rev()
2714 pctx = ctx.p1()
2660 pctx = ctx.p1()
2715 parent = pctx.rev()
2661 parent = pctx.rev()
2716 matches.setdefault(rev, {})
2662 matches.setdefault(rev, {})
2717 matches.setdefault(parent, {})
2663 matches.setdefault(parent, {})
2718 files = revfiles.setdefault(rev, [])
2664 files = revfiles.setdefault(rev, [])
2719 for fn in fns:
2665 for fn in fns:
2720 flog = getfile(fn)
2666 flog = getfile(fn)
2721 try:
2667 try:
2722 fnode = ctx.filenode(fn)
2668 fnode = ctx.filenode(fn)
2723 except error.LookupError:
2669 except error.LookupError:
2724 continue
2670 continue
2725
2671
2726 copied = flog.renamed(fnode)
2672 copied = flog.renamed(fnode)
2727 copy = follow and copied and copied[0]
2673 copy = follow and copied and copied[0]
2728 if copy:
2674 if copy:
2729 copies.setdefault(rev, {})[fn] = copy
2675 copies.setdefault(rev, {})[fn] = copy
2730 if fn in skip:
2676 if fn in skip:
2731 if copy:
2677 if copy:
2732 skip[copy] = True
2678 skip[copy] = True
2733 continue
2679 continue
2734 files.append(fn)
2680 files.append(fn)
2735
2681
2736 if fn not in matches[rev]:
2682 if fn not in matches[rev]:
2737 grepbody(fn, rev, flog.read(fnode))
2683 grepbody(fn, rev, flog.read(fnode))
2738
2684
2739 pfn = copy or fn
2685 pfn = copy or fn
2740 if pfn not in matches[parent]:
2686 if pfn not in matches[parent]:
2741 try:
2687 try:
2742 fnode = pctx.filenode(pfn)
2688 fnode = pctx.filenode(pfn)
2743 grepbody(pfn, parent, flog.read(fnode))
2689 grepbody(pfn, parent, flog.read(fnode))
2744 except error.LookupError:
2690 except error.LookupError:
2745 pass
2691 pass
2746
2692
2747 fm = ui.formatter('grep', opts)
2693 fm = ui.formatter('grep', opts)
2748 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2694 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2749 rev = ctx.rev()
2695 rev = ctx.rev()
2750 parent = ctx.p1().rev()
2696 parent = ctx.p1().rev()
2751 for fn in sorted(revfiles.get(rev, [])):
2697 for fn in sorted(revfiles.get(rev, [])):
2752 states = matches[rev][fn]
2698 states = matches[rev][fn]
2753 copy = copies.get(rev, {}).get(fn)
2699 copy = copies.get(rev, {}).get(fn)
2754 if fn in skip:
2700 if fn in skip:
2755 if copy:
2701 if copy:
2756 skip[copy] = True
2702 skip[copy] = True
2757 continue
2703 continue
2758 pstates = matches.get(parent, {}).get(copy or fn, [])
2704 pstates = matches.get(parent, {}).get(copy or fn, [])
2759 if pstates or states:
2705 if pstates or states:
2760 r = display(fm, fn, ctx, pstates, states)
2706 r = display(fm, fn, ctx, pstates, states)
2761 found = found or r
2707 found = found or r
2762 if r and not opts.get('all'):
2708 if r and not opts.get('all'):
2763 skip[fn] = True
2709 skip[fn] = True
2764 if copy:
2710 if copy:
2765 skip[copy] = True
2711 skip[copy] = True
2766 del matches[rev]
2712 del matches[rev]
2767 del revfiles[rev]
2713 del revfiles[rev]
2768 fm.end()
2714 fm.end()
2769
2715
2770 return not found
2716 return not found
2771
2717
2772 @command('heads',
2718 @command('heads',
2773 [('r', 'rev', '',
2719 [('r', 'rev', '',
2774 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2720 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2775 ('t', 'topo', False, _('show topological heads only')),
2721 ('t', 'topo', False, _('show topological heads only')),
2776 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2722 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2777 ('c', 'closed', False, _('show normal and closed branch heads')),
2723 ('c', 'closed', False, _('show normal and closed branch heads')),
2778 ] + templateopts,
2724 ] + templateopts,
2779 _('[-ct] [-r STARTREV] [REV]...'))
2725 _('[-ct] [-r STARTREV] [REV]...'))
2780 def heads(ui, repo, *branchrevs, **opts):
2726 def heads(ui, repo, *branchrevs, **opts):
2781 """show branch heads
2727 """show branch heads
2782
2728
2783 With no arguments, show all open branch heads in the repository.
2729 With no arguments, show all open branch heads in the repository.
2784 Branch heads are changesets that have no descendants on the
2730 Branch heads are changesets that have no descendants on the
2785 same branch. They are where development generally takes place and
2731 same branch. They are where development generally takes place and
2786 are the usual targets for update and merge operations.
2732 are the usual targets for update and merge operations.
2787
2733
2788 If one or more REVs are given, only open branch heads on the
2734 If one or more REVs are given, only open branch heads on the
2789 branches associated with the specified changesets are shown. This
2735 branches associated with the specified changesets are shown. This
2790 means that you can use :hg:`heads .` to see the heads on the
2736 means that you can use :hg:`heads .` to see the heads on the
2791 currently checked-out branch.
2737 currently checked-out branch.
2792
2738
2793 If -c/--closed is specified, also show branch heads marked closed
2739 If -c/--closed is specified, also show branch heads marked closed
2794 (see :hg:`commit --close-branch`).
2740 (see :hg:`commit --close-branch`).
2795
2741
2796 If STARTREV is specified, only those heads that are descendants of
2742 If STARTREV is specified, only those heads that are descendants of
2797 STARTREV will be displayed.
2743 STARTREV will be displayed.
2798
2744
2799 If -t/--topo is specified, named branch mechanics will be ignored and only
2745 If -t/--topo is specified, named branch mechanics will be ignored and only
2800 topological heads (changesets with no children) will be shown.
2746 topological heads (changesets with no children) will be shown.
2801
2747
2802 Returns 0 if matching heads are found, 1 if not.
2748 Returns 0 if matching heads are found, 1 if not.
2803 """
2749 """
2804
2750
2805 start = None
2751 start = None
2806 if 'rev' in opts:
2752 if 'rev' in opts:
2807 start = scmutil.revsingle(repo, opts['rev'], None).node()
2753 start = scmutil.revsingle(repo, opts['rev'], None).node()
2808
2754
2809 if opts.get('topo'):
2755 if opts.get('topo'):
2810 heads = [repo[h] for h in repo.heads(start)]
2756 heads = [repo[h] for h in repo.heads(start)]
2811 else:
2757 else:
2812 heads = []
2758 heads = []
2813 for branch in repo.branchmap():
2759 for branch in repo.branchmap():
2814 heads += repo.branchheads(branch, start, opts.get('closed'))
2760 heads += repo.branchheads(branch, start, opts.get('closed'))
2815 heads = [repo[h] for h in heads]
2761 heads = [repo[h] for h in heads]
2816
2762
2817 if branchrevs:
2763 if branchrevs:
2818 branches = set(repo[br].branch() for br in branchrevs)
2764 branches = set(repo[br].branch() for br in branchrevs)
2819 heads = [h for h in heads if h.branch() in branches]
2765 heads = [h for h in heads if h.branch() in branches]
2820
2766
2821 if opts.get('active') and branchrevs:
2767 if opts.get('active') and branchrevs:
2822 dagheads = repo.heads(start)
2768 dagheads = repo.heads(start)
2823 heads = [h for h in heads if h.node() in dagheads]
2769 heads = [h for h in heads if h.node() in dagheads]
2824
2770
2825 if branchrevs:
2771 if branchrevs:
2826 haveheads = set(h.branch() for h in heads)
2772 haveheads = set(h.branch() for h in heads)
2827 if branches - haveheads:
2773 if branches - haveheads:
2828 headless = ', '.join(b for b in branches - haveheads)
2774 headless = ', '.join(b for b in branches - haveheads)
2829 msg = _('no open branch heads found on branches %s')
2775 msg = _('no open branch heads found on branches %s')
2830 if opts.get('rev'):
2776 if opts.get('rev'):
2831 msg += _(' (started at %s)') % opts['rev']
2777 msg += _(' (started at %s)') % opts['rev']
2832 ui.warn((msg + '\n') % headless)
2778 ui.warn((msg + '\n') % headless)
2833
2779
2834 if not heads:
2780 if not heads:
2835 return 1
2781 return 1
2836
2782
2837 heads = sorted(heads, key=lambda x: -x.rev())
2783 heads = sorted(heads, key=lambda x: -x.rev())
2838 displayer = cmdutil.show_changeset(ui, repo, opts)
2784 displayer = cmdutil.show_changeset(ui, repo, opts)
2839 for ctx in heads:
2785 for ctx in heads:
2840 displayer.show(ctx)
2786 displayer.show(ctx)
2841 displayer.close()
2787 displayer.close()
2842
2788
2843 @command('help',
2789 @command('help',
2844 [('e', 'extension', None, _('show only help for extensions')),
2790 [('e', 'extension', None, _('show only help for extensions')),
2845 ('c', 'command', None, _('show only help for commands')),
2791 ('c', 'command', None, _('show only help for commands')),
2846 ('k', 'keyword', None, _('show topics matching keyword')),
2792 ('k', 'keyword', None, _('show topics matching keyword')),
2847 ('s', 'system', [], _('show help for specific platform(s)')),
2793 ('s', 'system', [], _('show help for specific platform(s)')),
2848 ],
2794 ],
2849 _('[-ecks] [TOPIC]'),
2795 _('[-ecks] [TOPIC]'),
2850 norepo=True)
2796 norepo=True)
2851 def help_(ui, name=None, **opts):
2797 def help_(ui, name=None, **opts):
2852 """show help for a given topic or a help overview
2798 """show help for a given topic or a help overview
2853
2799
2854 With no arguments, print a list of commands with short help messages.
2800 With no arguments, print a list of commands with short help messages.
2855
2801
2856 Given a topic, extension, or command name, print help for that
2802 Given a topic, extension, or command name, print help for that
2857 topic.
2803 topic.
2858
2804
2859 Returns 0 if successful.
2805 Returns 0 if successful.
2860 """
2806 """
2861
2807
2862 textwidth = ui.configint('ui', 'textwidth', 78)
2808 textwidth = ui.configint('ui', 'textwidth', 78)
2863 termwidth = ui.termwidth() - 2
2809 termwidth = ui.termwidth() - 2
2864 if textwidth <= 0 or termwidth < textwidth:
2810 if textwidth <= 0 or termwidth < textwidth:
2865 textwidth = termwidth
2811 textwidth = termwidth
2866
2812
2867 keep = opts.get('system') or []
2813 keep = opts.get('system') or []
2868 if len(keep) == 0:
2814 if len(keep) == 0:
2869 if pycompat.sysplatform.startswith('win'):
2815 if pycompat.sysplatform.startswith('win'):
2870 keep.append('windows')
2816 keep.append('windows')
2871 elif pycompat.sysplatform == 'OpenVMS':
2817 elif pycompat.sysplatform == 'OpenVMS':
2872 keep.append('vms')
2818 keep.append('vms')
2873 elif pycompat.sysplatform == 'plan9':
2819 elif pycompat.sysplatform == 'plan9':
2874 keep.append('plan9')
2820 keep.append('plan9')
2875 else:
2821 else:
2876 keep.append('unix')
2822 keep.append('unix')
2877 keep.append(pycompat.sysplatform.lower())
2823 keep.append(pycompat.sysplatform.lower())
2878 if ui.verbose:
2824 if ui.verbose:
2879 keep.append('verbose')
2825 keep.append('verbose')
2880
2826
2881 fullname = name
2827 fullname = name
2882 section = None
2828 section = None
2883 subtopic = None
2829 subtopic = None
2884 if name and '.' in name:
2830 if name and '.' in name:
2885 name, remaining = name.split('.', 1)
2831 name, remaining = name.split('.', 1)
2886 remaining = encoding.lower(remaining)
2832 remaining = encoding.lower(remaining)
2887 if '.' in remaining:
2833 if '.' in remaining:
2888 subtopic, section = remaining.split('.', 1)
2834 subtopic, section = remaining.split('.', 1)
2889 else:
2835 else:
2890 if name in help.subtopics:
2836 if name in help.subtopics:
2891 subtopic = remaining
2837 subtopic = remaining
2892 else:
2838 else:
2893 section = remaining
2839 section = remaining
2894
2840
2895 text = help.help_(ui, name, subtopic=subtopic, **opts)
2841 text = help.help_(ui, name, subtopic=subtopic, **opts)
2896
2842
2897 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2843 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2898 section=section)
2844 section=section)
2899
2845
2900 # We could have been given a weird ".foo" section without a name
2846 # We could have been given a weird ".foo" section without a name
2901 # to look for, or we could have simply failed to found "foo.bar"
2847 # to look for, or we could have simply failed to found "foo.bar"
2902 # because bar isn't a section of foo
2848 # because bar isn't a section of foo
2903 if section and not (formatted and name):
2849 if section and not (formatted and name):
2904 raise error.Abort(_("help section not found: %s") % fullname)
2850 raise error.Abort(_("help section not found: %s") % fullname)
2905
2851
2906 if 'verbose' in pruned:
2852 if 'verbose' in pruned:
2907 keep.append('omitted')
2853 keep.append('omitted')
2908 else:
2854 else:
2909 keep.append('notomitted')
2855 keep.append('notomitted')
2910 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2856 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2911 section=section)
2857 section=section)
2912 ui.write(formatted)
2858 ui.write(formatted)
2913
2859
2914
2860
2915 @command('identify|id',
2861 @command('identify|id',
2916 [('r', 'rev', '',
2862 [('r', 'rev', '',
2917 _('identify the specified revision'), _('REV')),
2863 _('identify the specified revision'), _('REV')),
2918 ('n', 'num', None, _('show local revision number')),
2864 ('n', 'num', None, _('show local revision number')),
2919 ('i', 'id', None, _('show global revision id')),
2865 ('i', 'id', None, _('show global revision id')),
2920 ('b', 'branch', None, _('show branch')),
2866 ('b', 'branch', None, _('show branch')),
2921 ('t', 'tags', None, _('show tags')),
2867 ('t', 'tags', None, _('show tags')),
2922 ('B', 'bookmarks', None, _('show bookmarks')),
2868 ('B', 'bookmarks', None, _('show bookmarks')),
2923 ] + remoteopts,
2869 ] + remoteopts,
2924 _('[-nibtB] [-r REV] [SOURCE]'),
2870 _('[-nibtB] [-r REV] [SOURCE]'),
2925 optionalrepo=True)
2871 optionalrepo=True)
2926 def identify(ui, repo, source=None, rev=None,
2872 def identify(ui, repo, source=None, rev=None,
2927 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2873 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2928 """identify the working directory or specified revision
2874 """identify the working directory or specified revision
2929
2875
2930 Print a summary identifying the repository state at REV using one or
2876 Print a summary identifying the repository state at REV using one or
2931 two parent hash identifiers, followed by a "+" if the working
2877 two parent hash identifiers, followed by a "+" if the working
2932 directory has uncommitted changes, the branch name (if not default),
2878 directory has uncommitted changes, the branch name (if not default),
2933 a list of tags, and a list of bookmarks.
2879 a list of tags, and a list of bookmarks.
2934
2880
2935 When REV is not given, print a summary of the current state of the
2881 When REV is not given, print a summary of the current state of the
2936 repository.
2882 repository.
2937
2883
2938 Specifying a path to a repository root or Mercurial bundle will
2884 Specifying a path to a repository root or Mercurial bundle will
2939 cause lookup to operate on that repository/bundle.
2885 cause lookup to operate on that repository/bundle.
2940
2886
2941 .. container:: verbose
2887 .. container:: verbose
2942
2888
2943 Examples:
2889 Examples:
2944
2890
2945 - generate a build identifier for the working directory::
2891 - generate a build identifier for the working directory::
2946
2892
2947 hg id --id > build-id.dat
2893 hg id --id > build-id.dat
2948
2894
2949 - find the revision corresponding to a tag::
2895 - find the revision corresponding to a tag::
2950
2896
2951 hg id -n -r 1.3
2897 hg id -n -r 1.3
2952
2898
2953 - check the most recent revision of a remote repository::
2899 - check the most recent revision of a remote repository::
2954
2900
2955 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2901 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2956
2902
2957 See :hg:`log` for generating more information about specific revisions,
2903 See :hg:`log` for generating more information about specific revisions,
2958 including full hash identifiers.
2904 including full hash identifiers.
2959
2905
2960 Returns 0 if successful.
2906 Returns 0 if successful.
2961 """
2907 """
2962
2908
2963 if not repo and not source:
2909 if not repo and not source:
2964 raise error.Abort(_("there is no Mercurial repository here "
2910 raise error.Abort(_("there is no Mercurial repository here "
2965 "(.hg not found)"))
2911 "(.hg not found)"))
2966
2912
2967 if ui.debugflag:
2913 if ui.debugflag:
2968 hexfunc = hex
2914 hexfunc = hex
2969 else:
2915 else:
2970 hexfunc = short
2916 hexfunc = short
2971 default = not (num or id or branch or tags or bookmarks)
2917 default = not (num or id or branch or tags or bookmarks)
2972 output = []
2918 output = []
2973 revs = []
2919 revs = []
2974
2920
2975 if source:
2921 if source:
2976 source, branches = hg.parseurl(ui.expandpath(source))
2922 source, branches = hg.parseurl(ui.expandpath(source))
2977 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2923 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2978 repo = peer.local()
2924 repo = peer.local()
2979 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2925 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2980
2926
2981 if not repo:
2927 if not repo:
2982 if num or branch or tags:
2928 if num or branch or tags:
2983 raise error.Abort(
2929 raise error.Abort(
2984 _("can't query remote revision number, branch, or tags"))
2930 _("can't query remote revision number, branch, or tags"))
2985 if not rev and revs:
2931 if not rev and revs:
2986 rev = revs[0]
2932 rev = revs[0]
2987 if not rev:
2933 if not rev:
2988 rev = "tip"
2934 rev = "tip"
2989
2935
2990 remoterev = peer.lookup(rev)
2936 remoterev = peer.lookup(rev)
2991 if default or id:
2937 if default or id:
2992 output = [hexfunc(remoterev)]
2938 output = [hexfunc(remoterev)]
2993
2939
2994 def getbms():
2940 def getbms():
2995 bms = []
2941 bms = []
2996
2942
2997 if 'bookmarks' in peer.listkeys('namespaces'):
2943 if 'bookmarks' in peer.listkeys('namespaces'):
2998 hexremoterev = hex(remoterev)
2944 hexremoterev = hex(remoterev)
2999 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2945 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3000 if bmr == hexremoterev]
2946 if bmr == hexremoterev]
3001
2947
3002 return sorted(bms)
2948 return sorted(bms)
3003
2949
3004 if bookmarks:
2950 if bookmarks:
3005 output.extend(getbms())
2951 output.extend(getbms())
3006 elif default and not ui.quiet:
2952 elif default and not ui.quiet:
3007 # multiple bookmarks for a single parent separated by '/'
2953 # multiple bookmarks for a single parent separated by '/'
3008 bm = '/'.join(getbms())
2954 bm = '/'.join(getbms())
3009 if bm:
2955 if bm:
3010 output.append(bm)
2956 output.append(bm)
3011 else:
2957 else:
3012 ctx = scmutil.revsingle(repo, rev, None)
2958 ctx = scmutil.revsingle(repo, rev, None)
3013
2959
3014 if ctx.rev() is None:
2960 if ctx.rev() is None:
3015 ctx = repo[None]
2961 ctx = repo[None]
3016 parents = ctx.parents()
2962 parents = ctx.parents()
3017 taglist = []
2963 taglist = []
3018 for p in parents:
2964 for p in parents:
3019 taglist.extend(p.tags())
2965 taglist.extend(p.tags())
3020
2966
3021 changed = ""
2967 changed = ""
3022 if default or id or num:
2968 if default or id or num:
3023 if (any(repo.status())
2969 if (any(repo.status())
3024 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2970 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3025 changed = '+'
2971 changed = '+'
3026 if default or id:
2972 if default or id:
3027 output = ["%s%s" %
2973 output = ["%s%s" %
3028 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2974 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3029 if num:
2975 if num:
3030 output.append("%s%s" %
2976 output.append("%s%s" %
3031 ('+'.join([str(p.rev()) for p in parents]), changed))
2977 ('+'.join([str(p.rev()) for p in parents]), changed))
3032 else:
2978 else:
3033 if default or id:
2979 if default or id:
3034 output = [hexfunc(ctx.node())]
2980 output = [hexfunc(ctx.node())]
3035 if num:
2981 if num:
3036 output.append(str(ctx.rev()))
2982 output.append(str(ctx.rev()))
3037 taglist = ctx.tags()
2983 taglist = ctx.tags()
3038
2984
3039 if default and not ui.quiet:
2985 if default and not ui.quiet:
3040 b = ctx.branch()
2986 b = ctx.branch()
3041 if b != 'default':
2987 if b != 'default':
3042 output.append("(%s)" % b)
2988 output.append("(%s)" % b)
3043
2989
3044 # multiple tags for a single parent separated by '/'
2990 # multiple tags for a single parent separated by '/'
3045 t = '/'.join(taglist)
2991 t = '/'.join(taglist)
3046 if t:
2992 if t:
3047 output.append(t)
2993 output.append(t)
3048
2994
3049 # multiple bookmarks for a single parent separated by '/'
2995 # multiple bookmarks for a single parent separated by '/'
3050 bm = '/'.join(ctx.bookmarks())
2996 bm = '/'.join(ctx.bookmarks())
3051 if bm:
2997 if bm:
3052 output.append(bm)
2998 output.append(bm)
3053 else:
2999 else:
3054 if branch:
3000 if branch:
3055 output.append(ctx.branch())
3001 output.append(ctx.branch())
3056
3002
3057 if tags:
3003 if tags:
3058 output.extend(taglist)
3004 output.extend(taglist)
3059
3005
3060 if bookmarks:
3006 if bookmarks:
3061 output.extend(ctx.bookmarks())
3007 output.extend(ctx.bookmarks())
3062
3008
3063 ui.write("%s\n" % ' '.join(output))
3009 ui.write("%s\n" % ' '.join(output))
3064
3010
3065 @command('import|patch',
3011 @command('import|patch',
3066 [('p', 'strip', 1,
3012 [('p', 'strip', 1,
3067 _('directory strip option for patch. This has the same '
3013 _('directory strip option for patch. This has the same '
3068 'meaning as the corresponding patch option'), _('NUM')),
3014 'meaning as the corresponding patch option'), _('NUM')),
3069 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3015 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3070 ('e', 'edit', False, _('invoke editor on commit messages')),
3016 ('e', 'edit', False, _('invoke editor on commit messages')),
3071 ('f', 'force', None,
3017 ('f', 'force', None,
3072 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3018 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3073 ('', 'no-commit', None,
3019 ('', 'no-commit', None,
3074 _("don't commit, just update the working directory")),
3020 _("don't commit, just update the working directory")),
3075 ('', 'bypass', None,
3021 ('', 'bypass', None,
3076 _("apply patch without touching the working directory")),
3022 _("apply patch without touching the working directory")),
3077 ('', 'partial', None,
3023 ('', 'partial', None,
3078 _('commit even if some hunks fail')),
3024 _('commit even if some hunks fail')),
3079 ('', 'exact', None,
3025 ('', 'exact', None,
3080 _('abort if patch would apply lossily')),
3026 _('abort if patch would apply lossily')),
3081 ('', 'prefix', '',
3027 ('', 'prefix', '',
3082 _('apply patch to subdirectory'), _('DIR')),
3028 _('apply patch to subdirectory'), _('DIR')),
3083 ('', 'import-branch', None,
3029 ('', 'import-branch', None,
3084 _('use any branch information in patch (implied by --exact)'))] +
3030 _('use any branch information in patch (implied by --exact)'))] +
3085 commitopts + commitopts2 + similarityopts,
3031 commitopts + commitopts2 + similarityopts,
3086 _('[OPTION]... PATCH...'))
3032 _('[OPTION]... PATCH...'))
3087 def import_(ui, repo, patch1=None, *patches, **opts):
3033 def import_(ui, repo, patch1=None, *patches, **opts):
3088 """import an ordered set of patches
3034 """import an ordered set of patches
3089
3035
3090 Import a list of patches and commit them individually (unless
3036 Import a list of patches and commit them individually (unless
3091 --no-commit is specified).
3037 --no-commit is specified).
3092
3038
3093 To read a patch from standard input (stdin), use "-" as the patch
3039 To read a patch from standard input (stdin), use "-" as the patch
3094 name. If a URL is specified, the patch will be downloaded from
3040 name. If a URL is specified, the patch will be downloaded from
3095 there.
3041 there.
3096
3042
3097 Import first applies changes to the working directory (unless
3043 Import first applies changes to the working directory (unless
3098 --bypass is specified), import will abort if there are outstanding
3044 --bypass is specified), import will abort if there are outstanding
3099 changes.
3045 changes.
3100
3046
3101 Use --bypass to apply and commit patches directly to the
3047 Use --bypass to apply and commit patches directly to the
3102 repository, without affecting the working directory. Without
3048 repository, without affecting the working directory. Without
3103 --exact, patches will be applied on top of the working directory
3049 --exact, patches will be applied on top of the working directory
3104 parent revision.
3050 parent revision.
3105
3051
3106 You can import a patch straight from a mail message. Even patches
3052 You can import a patch straight from a mail message. Even patches
3107 as attachments work (to use the body part, it must have type
3053 as attachments work (to use the body part, it must have type
3108 text/plain or text/x-patch). From and Subject headers of email
3054 text/plain or text/x-patch). From and Subject headers of email
3109 message are used as default committer and commit message. All
3055 message are used as default committer and commit message. All
3110 text/plain body parts before first diff are added to the commit
3056 text/plain body parts before first diff are added to the commit
3111 message.
3057 message.
3112
3058
3113 If the imported patch was generated by :hg:`export`, user and
3059 If the imported patch was generated by :hg:`export`, user and
3114 description from patch override values from message headers and
3060 description from patch override values from message headers and
3115 body. Values given on command line with -m/--message and -u/--user
3061 body. Values given on command line with -m/--message and -u/--user
3116 override these.
3062 override these.
3117
3063
3118 If --exact is specified, import will set the working directory to
3064 If --exact is specified, import will set the working directory to
3119 the parent of each patch before applying it, and will abort if the
3065 the parent of each patch before applying it, and will abort if the
3120 resulting changeset has a different ID than the one recorded in
3066 resulting changeset has a different ID than the one recorded in
3121 the patch. This will guard against various ways that portable
3067 the patch. This will guard against various ways that portable
3122 patch formats and mail systems might fail to transfer Mercurial
3068 patch formats and mail systems might fail to transfer Mercurial
3123 data or metadata. See :hg:`bundle` for lossless transmission.
3069 data or metadata. See :hg:`bundle` for lossless transmission.
3124
3070
3125 Use --partial to ensure a changeset will be created from the patch
3071 Use --partial to ensure a changeset will be created from the patch
3126 even if some hunks fail to apply. Hunks that fail to apply will be
3072 even if some hunks fail to apply. Hunks that fail to apply will be
3127 written to a <target-file>.rej file. Conflicts can then be resolved
3073 written to a <target-file>.rej file. Conflicts can then be resolved
3128 by hand before :hg:`commit --amend` is run to update the created
3074 by hand before :hg:`commit --amend` is run to update the created
3129 changeset. This flag exists to let people import patches that
3075 changeset. This flag exists to let people import patches that
3130 partially apply without losing the associated metadata (author,
3076 partially apply without losing the associated metadata (author,
3131 date, description, ...).
3077 date, description, ...).
3132
3078
3133 .. note::
3079 .. note::
3134
3080
3135 When no hunks apply cleanly, :hg:`import --partial` will create
3081 When no hunks apply cleanly, :hg:`import --partial` will create
3136 an empty changeset, importing only the patch metadata.
3082 an empty changeset, importing only the patch metadata.
3137
3083
3138 With -s/--similarity, hg will attempt to discover renames and
3084 With -s/--similarity, hg will attempt to discover renames and
3139 copies in the patch in the same way as :hg:`addremove`.
3085 copies in the patch in the same way as :hg:`addremove`.
3140
3086
3141 It is possible to use external patch programs to perform the patch
3087 It is possible to use external patch programs to perform the patch
3142 by setting the ``ui.patch`` configuration option. For the default
3088 by setting the ``ui.patch`` configuration option. For the default
3143 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3089 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3144 See :hg:`help config` for more information about configuration
3090 See :hg:`help config` for more information about configuration
3145 files and how to use these options.
3091 files and how to use these options.
3146
3092
3147 See :hg:`help dates` for a list of formats valid for -d/--date.
3093 See :hg:`help dates` for a list of formats valid for -d/--date.
3148
3094
3149 .. container:: verbose
3095 .. container:: verbose
3150
3096
3151 Examples:
3097 Examples:
3152
3098
3153 - import a traditional patch from a website and detect renames::
3099 - import a traditional patch from a website and detect renames::
3154
3100
3155 hg import -s 80 http://example.com/bugfix.patch
3101 hg import -s 80 http://example.com/bugfix.patch
3156
3102
3157 - import a changeset from an hgweb server::
3103 - import a changeset from an hgweb server::
3158
3104
3159 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3105 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3160
3106
3161 - import all the patches in an Unix-style mbox::
3107 - import all the patches in an Unix-style mbox::
3162
3108
3163 hg import incoming-patches.mbox
3109 hg import incoming-patches.mbox
3164
3110
3165 - import patches from stdin::
3111 - import patches from stdin::
3166
3112
3167 hg import -
3113 hg import -
3168
3114
3169 - attempt to exactly restore an exported changeset (not always
3115 - attempt to exactly restore an exported changeset (not always
3170 possible)::
3116 possible)::
3171
3117
3172 hg import --exact proposed-fix.patch
3118 hg import --exact proposed-fix.patch
3173
3119
3174 - use an external tool to apply a patch which is too fuzzy for
3120 - use an external tool to apply a patch which is too fuzzy for
3175 the default internal tool.
3121 the default internal tool.
3176
3122
3177 hg import --config ui.patch="patch --merge" fuzzy.patch
3123 hg import --config ui.patch="patch --merge" fuzzy.patch
3178
3124
3179 - change the default fuzzing from 2 to a less strict 7
3125 - change the default fuzzing from 2 to a less strict 7
3180
3126
3181 hg import --config ui.fuzz=7 fuzz.patch
3127 hg import --config ui.fuzz=7 fuzz.patch
3182
3128
3183 Returns 0 on success, 1 on partial success (see --partial).
3129 Returns 0 on success, 1 on partial success (see --partial).
3184 """
3130 """
3185
3131
3186 if not patch1:
3132 if not patch1:
3187 raise error.Abort(_('need at least one patch to import'))
3133 raise error.Abort(_('need at least one patch to import'))
3188
3134
3189 patches = (patch1,) + patches
3135 patches = (patch1,) + patches
3190
3136
3191 date = opts.get('date')
3137 date = opts.get('date')
3192 if date:
3138 if date:
3193 opts['date'] = util.parsedate(date)
3139 opts['date'] = util.parsedate(date)
3194
3140
3195 exact = opts.get('exact')
3141 exact = opts.get('exact')
3196 update = not opts.get('bypass')
3142 update = not opts.get('bypass')
3197 if not update and opts.get('no_commit'):
3143 if not update and opts.get('no_commit'):
3198 raise error.Abort(_('cannot use --no-commit with --bypass'))
3144 raise error.Abort(_('cannot use --no-commit with --bypass'))
3199 try:
3145 try:
3200 sim = float(opts.get('similarity') or 0)
3146 sim = float(opts.get('similarity') or 0)
3201 except ValueError:
3147 except ValueError:
3202 raise error.Abort(_('similarity must be a number'))
3148 raise error.Abort(_('similarity must be a number'))
3203 if sim < 0 or sim > 100:
3149 if sim < 0 or sim > 100:
3204 raise error.Abort(_('similarity must be between 0 and 100'))
3150 raise error.Abort(_('similarity must be between 0 and 100'))
3205 if sim and not update:
3151 if sim and not update:
3206 raise error.Abort(_('cannot use --similarity with --bypass'))
3152 raise error.Abort(_('cannot use --similarity with --bypass'))
3207 if exact:
3153 if exact:
3208 if opts.get('edit'):
3154 if opts.get('edit'):
3209 raise error.Abort(_('cannot use --exact with --edit'))
3155 raise error.Abort(_('cannot use --exact with --edit'))
3210 if opts.get('prefix'):
3156 if opts.get('prefix'):
3211 raise error.Abort(_('cannot use --exact with --prefix'))
3157 raise error.Abort(_('cannot use --exact with --prefix'))
3212
3158
3213 base = opts["base"]
3159 base = opts["base"]
3214 wlock = dsguard = lock = tr = None
3160 wlock = dsguard = lock = tr = None
3215 msgs = []
3161 msgs = []
3216 ret = 0
3162 ret = 0
3217
3163
3218
3164
3219 try:
3165 try:
3220 wlock = repo.wlock()
3166 wlock = repo.wlock()
3221
3167
3222 if update:
3168 if update:
3223 cmdutil.checkunfinished(repo)
3169 cmdutil.checkunfinished(repo)
3224 if (exact or not opts.get('force')):
3170 if (exact or not opts.get('force')):
3225 cmdutil.bailifchanged(repo)
3171 cmdutil.bailifchanged(repo)
3226
3172
3227 if not opts.get('no_commit'):
3173 if not opts.get('no_commit'):
3228 lock = repo.lock()
3174 lock = repo.lock()
3229 tr = repo.transaction('import')
3175 tr = repo.transaction('import')
3230 else:
3176 else:
3231 dsguard = dirstateguard.dirstateguard(repo, 'import')
3177 dsguard = dirstateguard.dirstateguard(repo, 'import')
3232 parents = repo[None].parents()
3178 parents = repo[None].parents()
3233 for patchurl in patches:
3179 for patchurl in patches:
3234 if patchurl == '-':
3180 if patchurl == '-':
3235 ui.status(_('applying patch from stdin\n'))
3181 ui.status(_('applying patch from stdin\n'))
3236 patchfile = ui.fin
3182 patchfile = ui.fin
3237 patchurl = 'stdin' # for error message
3183 patchurl = 'stdin' # for error message
3238 else:
3184 else:
3239 patchurl = os.path.join(base, patchurl)
3185 patchurl = os.path.join(base, patchurl)
3240 ui.status(_('applying %s\n') % patchurl)
3186 ui.status(_('applying %s\n') % patchurl)
3241 patchfile = hg.openpath(ui, patchurl)
3187 patchfile = hg.openpath(ui, patchurl)
3242
3188
3243 haspatch = False
3189 haspatch = False
3244 for hunk in patch.split(patchfile):
3190 for hunk in patch.split(patchfile):
3245 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3191 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3246 parents, opts,
3192 parents, opts,
3247 msgs, hg.clean)
3193 msgs, hg.clean)
3248 if msg:
3194 if msg:
3249 haspatch = True
3195 haspatch = True
3250 ui.note(msg + '\n')
3196 ui.note(msg + '\n')
3251 if update or exact:
3197 if update or exact:
3252 parents = repo[None].parents()
3198 parents = repo[None].parents()
3253 else:
3199 else:
3254 parents = [repo[node]]
3200 parents = [repo[node]]
3255 if rej:
3201 if rej:
3256 ui.write_err(_("patch applied partially\n"))
3202 ui.write_err(_("patch applied partially\n"))
3257 ui.write_err(_("(fix the .rej files and run "
3203 ui.write_err(_("(fix the .rej files and run "
3258 "`hg commit --amend`)\n"))
3204 "`hg commit --amend`)\n"))
3259 ret = 1
3205 ret = 1
3260 break
3206 break
3261
3207
3262 if not haspatch:
3208 if not haspatch:
3263 raise error.Abort(_('%s: no diffs found') % patchurl)
3209 raise error.Abort(_('%s: no diffs found') % patchurl)
3264
3210
3265 if tr:
3211 if tr:
3266 tr.close()
3212 tr.close()
3267 if msgs:
3213 if msgs:
3268 repo.savecommitmessage('\n* * *\n'.join(msgs))
3214 repo.savecommitmessage('\n* * *\n'.join(msgs))
3269 if dsguard:
3215 if dsguard:
3270 dsguard.close()
3216 dsguard.close()
3271 return ret
3217 return ret
3272 finally:
3218 finally:
3273 if tr:
3219 if tr:
3274 tr.release()
3220 tr.release()
3275 release(lock, dsguard, wlock)
3221 release(lock, dsguard, wlock)
3276
3222
3277 @command('incoming|in',
3223 @command('incoming|in',
3278 [('f', 'force', None,
3224 [('f', 'force', None,
3279 _('run even if remote repository is unrelated')),
3225 _('run even if remote repository is unrelated')),
3280 ('n', 'newest-first', None, _('show newest record first')),
3226 ('n', 'newest-first', None, _('show newest record first')),
3281 ('', 'bundle', '',
3227 ('', 'bundle', '',
3282 _('file to store the bundles into'), _('FILE')),
3228 _('file to store the bundles into'), _('FILE')),
3283 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3229 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3284 ('B', 'bookmarks', False, _("compare bookmarks")),
3230 ('B', 'bookmarks', False, _("compare bookmarks")),
3285 ('b', 'branch', [],
3231 ('b', 'branch', [],
3286 _('a specific branch you would like to pull'), _('BRANCH')),
3232 _('a specific branch you would like to pull'), _('BRANCH')),
3287 ] + logopts + remoteopts + subrepoopts,
3233 ] + logopts + remoteopts + subrepoopts,
3288 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3234 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3289 def incoming(ui, repo, source="default", **opts):
3235 def incoming(ui, repo, source="default", **opts):
3290 """show new changesets found in source
3236 """show new changesets found in source
3291
3237
3292 Show new changesets found in the specified path/URL or the default
3238 Show new changesets found in the specified path/URL or the default
3293 pull location. These are the changesets that would have been pulled
3239 pull location. These are the changesets that would have been pulled
3294 if a pull at the time you issued this command.
3240 if a pull at the time you issued this command.
3295
3241
3296 See pull for valid source format details.
3242 See pull for valid source format details.
3297
3243
3298 .. container:: verbose
3244 .. container:: verbose
3299
3245
3300 With -B/--bookmarks, the result of bookmark comparison between
3246 With -B/--bookmarks, the result of bookmark comparison between
3301 local and remote repositories is displayed. With -v/--verbose,
3247 local and remote repositories is displayed. With -v/--verbose,
3302 status is also displayed for each bookmark like below::
3248 status is also displayed for each bookmark like below::
3303
3249
3304 BM1 01234567890a added
3250 BM1 01234567890a added
3305 BM2 1234567890ab advanced
3251 BM2 1234567890ab advanced
3306 BM3 234567890abc diverged
3252 BM3 234567890abc diverged
3307 BM4 34567890abcd changed
3253 BM4 34567890abcd changed
3308
3254
3309 The action taken locally when pulling depends on the
3255 The action taken locally when pulling depends on the
3310 status of each bookmark:
3256 status of each bookmark:
3311
3257
3312 :``added``: pull will create it
3258 :``added``: pull will create it
3313 :``advanced``: pull will update it
3259 :``advanced``: pull will update it
3314 :``diverged``: pull will create a divergent bookmark
3260 :``diverged``: pull will create a divergent bookmark
3315 :``changed``: result depends on remote changesets
3261 :``changed``: result depends on remote changesets
3316
3262
3317 From the point of view of pulling behavior, bookmark
3263 From the point of view of pulling behavior, bookmark
3318 existing only in the remote repository are treated as ``added``,
3264 existing only in the remote repository are treated as ``added``,
3319 even if it is in fact locally deleted.
3265 even if it is in fact locally deleted.
3320
3266
3321 .. container:: verbose
3267 .. container:: verbose
3322
3268
3323 For remote repository, using --bundle avoids downloading the
3269 For remote repository, using --bundle avoids downloading the
3324 changesets twice if the incoming is followed by a pull.
3270 changesets twice if the incoming is followed by a pull.
3325
3271
3326 Examples:
3272 Examples:
3327
3273
3328 - show incoming changes with patches and full description::
3274 - show incoming changes with patches and full description::
3329
3275
3330 hg incoming -vp
3276 hg incoming -vp
3331
3277
3332 - show incoming changes excluding merges, store a bundle::
3278 - show incoming changes excluding merges, store a bundle::
3333
3279
3334 hg in -vpM --bundle incoming.hg
3280 hg in -vpM --bundle incoming.hg
3335 hg pull incoming.hg
3281 hg pull incoming.hg
3336
3282
3337 - briefly list changes inside a bundle::
3283 - briefly list changes inside a bundle::
3338
3284
3339 hg in changes.hg -T "{desc|firstline}\\n"
3285 hg in changes.hg -T "{desc|firstline}\\n"
3340
3286
3341 Returns 0 if there are incoming changes, 1 otherwise.
3287 Returns 0 if there are incoming changes, 1 otherwise.
3342 """
3288 """
3343 if opts.get('graph'):
3289 if opts.get('graph'):
3344 cmdutil.checkunsupportedgraphflags([], opts)
3290 cmdutil.checkunsupportedgraphflags([], opts)
3345 def display(other, chlist, displayer):
3291 def display(other, chlist, displayer):
3346 revdag = cmdutil.graphrevs(other, chlist, opts)
3292 revdag = cmdutil.graphrevs(other, chlist, opts)
3347 cmdutil.displaygraph(ui, repo, revdag, displayer,
3293 cmdutil.displaygraph(ui, repo, revdag, displayer,
3348 graphmod.asciiedges)
3294 graphmod.asciiedges)
3349
3295
3350 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3296 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3351 return 0
3297 return 0
3352
3298
3353 if opts.get('bundle') and opts.get('subrepos'):
3299 if opts.get('bundle') and opts.get('subrepos'):
3354 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3300 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3355
3301
3356 if opts.get('bookmarks'):
3302 if opts.get('bookmarks'):
3357 source, branches = hg.parseurl(ui.expandpath(source),
3303 source, branches = hg.parseurl(ui.expandpath(source),
3358 opts.get('branch'))
3304 opts.get('branch'))
3359 other = hg.peer(repo, opts, source)
3305 other = hg.peer(repo, opts, source)
3360 if 'bookmarks' not in other.listkeys('namespaces'):
3306 if 'bookmarks' not in other.listkeys('namespaces'):
3361 ui.warn(_("remote doesn't support bookmarks\n"))
3307 ui.warn(_("remote doesn't support bookmarks\n"))
3362 return 0
3308 return 0
3363 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3309 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3364 return bookmarks.incoming(ui, repo, other)
3310 return bookmarks.incoming(ui, repo, other)
3365
3311
3366 repo._subtoppath = ui.expandpath(source)
3312 repo._subtoppath = ui.expandpath(source)
3367 try:
3313 try:
3368 return hg.incoming(ui, repo, source, opts)
3314 return hg.incoming(ui, repo, source, opts)
3369 finally:
3315 finally:
3370 del repo._subtoppath
3316 del repo._subtoppath
3371
3317
3372
3318
3373 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3319 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3374 norepo=True)
3320 norepo=True)
3375 def init(ui, dest=".", **opts):
3321 def init(ui, dest=".", **opts):
3376 """create a new repository in the given directory
3322 """create a new repository in the given directory
3377
3323
3378 Initialize a new repository in the given directory. If the given
3324 Initialize a new repository in the given directory. If the given
3379 directory does not exist, it will be created.
3325 directory does not exist, it will be created.
3380
3326
3381 If no directory is given, the current directory is used.
3327 If no directory is given, the current directory is used.
3382
3328
3383 It is possible to specify an ``ssh://`` URL as the destination.
3329 It is possible to specify an ``ssh://`` URL as the destination.
3384 See :hg:`help urls` for more information.
3330 See :hg:`help urls` for more information.
3385
3331
3386 Returns 0 on success.
3332 Returns 0 on success.
3387 """
3333 """
3388 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3334 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3389
3335
3390 @command('locate',
3336 @command('locate',
3391 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3337 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3392 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3338 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3393 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3339 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3394 ] + walkopts,
3340 ] + walkopts,
3395 _('[OPTION]... [PATTERN]...'))
3341 _('[OPTION]... [PATTERN]...'))
3396 def locate(ui, repo, *pats, **opts):
3342 def locate(ui, repo, *pats, **opts):
3397 """locate files matching specific patterns (DEPRECATED)
3343 """locate files matching specific patterns (DEPRECATED)
3398
3344
3399 Print files under Mercurial control in the working directory whose
3345 Print files under Mercurial control in the working directory whose
3400 names match the given patterns.
3346 names match the given patterns.
3401
3347
3402 By default, this command searches all directories in the working
3348 By default, this command searches all directories in the working
3403 directory. To search just the current directory and its
3349 directory. To search just the current directory and its
3404 subdirectories, use "--include .".
3350 subdirectories, use "--include .".
3405
3351
3406 If no patterns are given to match, this command prints the names
3352 If no patterns are given to match, this command prints the names
3407 of all files under Mercurial control in the working directory.
3353 of all files under Mercurial control in the working directory.
3408
3354
3409 If you want to feed the output of this command into the "xargs"
3355 If you want to feed the output of this command into the "xargs"
3410 command, use the -0 option to both this command and "xargs". This
3356 command, use the -0 option to both this command and "xargs". This
3411 will avoid the problem of "xargs" treating single filenames that
3357 will avoid the problem of "xargs" treating single filenames that
3412 contain whitespace as multiple filenames.
3358 contain whitespace as multiple filenames.
3413
3359
3414 See :hg:`help files` for a more versatile command.
3360 See :hg:`help files` for a more versatile command.
3415
3361
3416 Returns 0 if a match is found, 1 otherwise.
3362 Returns 0 if a match is found, 1 otherwise.
3417 """
3363 """
3418 if opts.get('print0'):
3364 if opts.get('print0'):
3419 end = '\0'
3365 end = '\0'
3420 else:
3366 else:
3421 end = '\n'
3367 end = '\n'
3422 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3368 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3423
3369
3424 ret = 1
3370 ret = 1
3425 ctx = repo[rev]
3371 ctx = repo[rev]
3426 m = scmutil.match(ctx, pats, opts, default='relglob',
3372 m = scmutil.match(ctx, pats, opts, default='relglob',
3427 badfn=lambda x, y: False)
3373 badfn=lambda x, y: False)
3428
3374
3429 for abs in ctx.matches(m):
3375 for abs in ctx.matches(m):
3430 if opts.get('fullpath'):
3376 if opts.get('fullpath'):
3431 ui.write(repo.wjoin(abs), end)
3377 ui.write(repo.wjoin(abs), end)
3432 else:
3378 else:
3433 ui.write(((pats and m.rel(abs)) or abs), end)
3379 ui.write(((pats and m.rel(abs)) or abs), end)
3434 ret = 0
3380 ret = 0
3435
3381
3436 return ret
3382 return ret
3437
3383
3438 @command('^log|history',
3384 @command('^log|history',
3439 [('f', 'follow', None,
3385 [('f', 'follow', None,
3440 _('follow changeset history, or file history across copies and renames')),
3386 _('follow changeset history, or file history across copies and renames')),
3441 ('', 'follow-first', None,
3387 ('', 'follow-first', None,
3442 _('only follow the first parent of merge changesets (DEPRECATED)')),
3388 _('only follow the first parent of merge changesets (DEPRECATED)')),
3443 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3389 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3444 ('C', 'copies', None, _('show copied files')),
3390 ('C', 'copies', None, _('show copied files')),
3445 ('k', 'keyword', [],
3391 ('k', 'keyword', [],
3446 _('do case-insensitive search for a given text'), _('TEXT')),
3392 _('do case-insensitive search for a given text'), _('TEXT')),
3447 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3393 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3448 ('', 'removed', None, _('include revisions where files were removed')),
3394 ('', 'removed', None, _('include revisions where files were removed')),
3449 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3395 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3450 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3396 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3451 ('', 'only-branch', [],
3397 ('', 'only-branch', [],
3452 _('show only changesets within the given named branch (DEPRECATED)'),
3398 _('show only changesets within the given named branch (DEPRECATED)'),
3453 _('BRANCH')),
3399 _('BRANCH')),
3454 ('b', 'branch', [],
3400 ('b', 'branch', [],
3455 _('show changesets within the given named branch'), _('BRANCH')),
3401 _('show changesets within the given named branch'), _('BRANCH')),
3456 ('P', 'prune', [],
3402 ('P', 'prune', [],
3457 _('do not display revision or any of its ancestors'), _('REV')),
3403 _('do not display revision or any of its ancestors'), _('REV')),
3458 ] + logopts + walkopts,
3404 ] + logopts + walkopts,
3459 _('[OPTION]... [FILE]'),
3405 _('[OPTION]... [FILE]'),
3460 inferrepo=True)
3406 inferrepo=True)
3461 def log(ui, repo, *pats, **opts):
3407 def log(ui, repo, *pats, **opts):
3462 """show revision history of entire repository or files
3408 """show revision history of entire repository or files
3463
3409
3464 Print the revision history of the specified files or the entire
3410 Print the revision history of the specified files or the entire
3465 project.
3411 project.
3466
3412
3467 If no revision range is specified, the default is ``tip:0`` unless
3413 If no revision range is specified, the default is ``tip:0`` unless
3468 --follow is set, in which case the working directory parent is
3414 --follow is set, in which case the working directory parent is
3469 used as the starting revision.
3415 used as the starting revision.
3470
3416
3471 File history is shown without following rename or copy history of
3417 File history is shown without following rename or copy history of
3472 files. Use -f/--follow with a filename to follow history across
3418 files. Use -f/--follow with a filename to follow history across
3473 renames and copies. --follow without a filename will only show
3419 renames and copies. --follow without a filename will only show
3474 ancestors or descendants of the starting revision.
3420 ancestors or descendants of the starting revision.
3475
3421
3476 By default this command prints revision number and changeset id,
3422 By default this command prints revision number and changeset id,
3477 tags, non-trivial parents, user, date and time, and a summary for
3423 tags, non-trivial parents, user, date and time, and a summary for
3478 each commit. When the -v/--verbose switch is used, the list of
3424 each commit. When the -v/--verbose switch is used, the list of
3479 changed files and full commit message are shown.
3425 changed files and full commit message are shown.
3480
3426
3481 With --graph the revisions are shown as an ASCII art DAG with the most
3427 With --graph the revisions are shown as an ASCII art DAG with the most
3482 recent changeset at the top.
3428 recent changeset at the top.
3483 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3429 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3484 and '+' represents a fork where the changeset from the lines below is a
3430 and '+' represents a fork where the changeset from the lines below is a
3485 parent of the 'o' merge on the same line.
3431 parent of the 'o' merge on the same line.
3486
3432
3487 .. note::
3433 .. note::
3488
3434
3489 :hg:`log --patch` may generate unexpected diff output for merge
3435 :hg:`log --patch` may generate unexpected diff output for merge
3490 changesets, as it will only compare the merge changeset against
3436 changesets, as it will only compare the merge changeset against
3491 its first parent. Also, only files different from BOTH parents
3437 its first parent. Also, only files different from BOTH parents
3492 will appear in files:.
3438 will appear in files:.
3493
3439
3494 .. note::
3440 .. note::
3495
3441
3496 For performance reasons, :hg:`log FILE` may omit duplicate changes
3442 For performance reasons, :hg:`log FILE` may omit duplicate changes
3497 made on branches and will not show removals or mode changes. To
3443 made on branches and will not show removals or mode changes. To
3498 see all such changes, use the --removed switch.
3444 see all such changes, use the --removed switch.
3499
3445
3500 .. container:: verbose
3446 .. container:: verbose
3501
3447
3502 Some examples:
3448 Some examples:
3503
3449
3504 - changesets with full descriptions and file lists::
3450 - changesets with full descriptions and file lists::
3505
3451
3506 hg log -v
3452 hg log -v
3507
3453
3508 - changesets ancestral to the working directory::
3454 - changesets ancestral to the working directory::
3509
3455
3510 hg log -f
3456 hg log -f
3511
3457
3512 - last 10 commits on the current branch::
3458 - last 10 commits on the current branch::
3513
3459
3514 hg log -l 10 -b .
3460 hg log -l 10 -b .
3515
3461
3516 - changesets showing all modifications of a file, including removals::
3462 - changesets showing all modifications of a file, including removals::
3517
3463
3518 hg log --removed file.c
3464 hg log --removed file.c
3519
3465
3520 - all changesets that touch a directory, with diffs, excluding merges::
3466 - all changesets that touch a directory, with diffs, excluding merges::
3521
3467
3522 hg log -Mp lib/
3468 hg log -Mp lib/
3523
3469
3524 - all revision numbers that match a keyword::
3470 - all revision numbers that match a keyword::
3525
3471
3526 hg log -k bug --template "{rev}\\n"
3472 hg log -k bug --template "{rev}\\n"
3527
3473
3528 - the full hash identifier of the working directory parent::
3474 - the full hash identifier of the working directory parent::
3529
3475
3530 hg log -r . --template "{node}\\n"
3476 hg log -r . --template "{node}\\n"
3531
3477
3532 - list available log templates::
3478 - list available log templates::
3533
3479
3534 hg log -T list
3480 hg log -T list
3535
3481
3536 - check if a given changeset is included in a tagged release::
3482 - check if a given changeset is included in a tagged release::
3537
3483
3538 hg log -r "a21ccf and ancestor(1.9)"
3484 hg log -r "a21ccf and ancestor(1.9)"
3539
3485
3540 - find all changesets by some user in a date range::
3486 - find all changesets by some user in a date range::
3541
3487
3542 hg log -k alice -d "may 2008 to jul 2008"
3488 hg log -k alice -d "may 2008 to jul 2008"
3543
3489
3544 - summary of all changesets after the last tag::
3490 - summary of all changesets after the last tag::
3545
3491
3546 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3492 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3547
3493
3548 See :hg:`help dates` for a list of formats valid for -d/--date.
3494 See :hg:`help dates` for a list of formats valid for -d/--date.
3549
3495
3550 See :hg:`help revisions` for more about specifying and ordering
3496 See :hg:`help revisions` for more about specifying and ordering
3551 revisions.
3497 revisions.
3552
3498
3553 See :hg:`help templates` for more about pre-packaged styles and
3499 See :hg:`help templates` for more about pre-packaged styles and
3554 specifying custom templates.
3500 specifying custom templates.
3555
3501
3556 Returns 0 on success.
3502 Returns 0 on success.
3557
3503
3558 """
3504 """
3559 if opts.get('follow') and opts.get('rev'):
3505 if opts.get('follow') and opts.get('rev'):
3560 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3506 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3561 del opts['follow']
3507 del opts['follow']
3562
3508
3563 if opts.get('graph'):
3509 if opts.get('graph'):
3564 return cmdutil.graphlog(ui, repo, *pats, **opts)
3510 return cmdutil.graphlog(ui, repo, *pats, **opts)
3565
3511
3566 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3512 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3567 limit = cmdutil.loglimit(opts)
3513 limit = cmdutil.loglimit(opts)
3568 count = 0
3514 count = 0
3569
3515
3570 getrenamed = None
3516 getrenamed = None
3571 if opts.get('copies'):
3517 if opts.get('copies'):
3572 endrev = None
3518 endrev = None
3573 if opts.get('rev'):
3519 if opts.get('rev'):
3574 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3520 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3575 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3521 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3576
3522
3577 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3523 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3578 for rev in revs:
3524 for rev in revs:
3579 if count == limit:
3525 if count == limit:
3580 break
3526 break
3581 ctx = repo[rev]
3527 ctx = repo[rev]
3582 copies = None
3528 copies = None
3583 if getrenamed is not None and rev:
3529 if getrenamed is not None and rev:
3584 copies = []
3530 copies = []
3585 for fn in ctx.files():
3531 for fn in ctx.files():
3586 rename = getrenamed(fn, rev)
3532 rename = getrenamed(fn, rev)
3587 if rename:
3533 if rename:
3588 copies.append((fn, rename[0]))
3534 copies.append((fn, rename[0]))
3589 if filematcher:
3535 if filematcher:
3590 revmatchfn = filematcher(ctx.rev())
3536 revmatchfn = filematcher(ctx.rev())
3591 else:
3537 else:
3592 revmatchfn = None
3538 revmatchfn = None
3593 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3539 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3594 if displayer.flush(ctx):
3540 if displayer.flush(ctx):
3595 count += 1
3541 count += 1
3596
3542
3597 displayer.close()
3543 displayer.close()
3598
3544
3599 @command('manifest',
3545 @command('manifest',
3600 [('r', 'rev', '', _('revision to display'), _('REV')),
3546 [('r', 'rev', '', _('revision to display'), _('REV')),
3601 ('', 'all', False, _("list files from all revisions"))]
3547 ('', 'all', False, _("list files from all revisions"))]
3602 + formatteropts,
3548 + formatteropts,
3603 _('[-r REV]'))
3549 _('[-r REV]'))
3604 def manifest(ui, repo, node=None, rev=None, **opts):
3550 def manifest(ui, repo, node=None, rev=None, **opts):
3605 """output the current or given revision of the project manifest
3551 """output the current or given revision of the project manifest
3606
3552
3607 Print a list of version controlled files for the given revision.
3553 Print a list of version controlled files for the given revision.
3608 If no revision is given, the first parent of the working directory
3554 If no revision is given, the first parent of the working directory
3609 is used, or the null revision if no revision is checked out.
3555 is used, or the null revision if no revision is checked out.
3610
3556
3611 With -v, print file permissions, symlink and executable bits.
3557 With -v, print file permissions, symlink and executable bits.
3612 With --debug, print file revision hashes.
3558 With --debug, print file revision hashes.
3613
3559
3614 If option --all is specified, the list of all files from all revisions
3560 If option --all is specified, the list of all files from all revisions
3615 is printed. This includes deleted and renamed files.
3561 is printed. This includes deleted and renamed files.
3616
3562
3617 Returns 0 on success.
3563 Returns 0 on success.
3618 """
3564 """
3619
3565
3620 fm = ui.formatter('manifest', opts)
3566 fm = ui.formatter('manifest', opts)
3621
3567
3622 if opts.get('all'):
3568 if opts.get('all'):
3623 if rev or node:
3569 if rev or node:
3624 raise error.Abort(_("can't specify a revision with --all"))
3570 raise error.Abort(_("can't specify a revision with --all"))
3625
3571
3626 res = []
3572 res = []
3627 prefix = "data/"
3573 prefix = "data/"
3628 suffix = ".i"
3574 suffix = ".i"
3629 plen = len(prefix)
3575 plen = len(prefix)
3630 slen = len(suffix)
3576 slen = len(suffix)
3631 with repo.lock():
3577 with repo.lock():
3632 for fn, b, size in repo.store.datafiles():
3578 for fn, b, size in repo.store.datafiles():
3633 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3579 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3634 res.append(fn[plen:-slen])
3580 res.append(fn[plen:-slen])
3635 for f in res:
3581 for f in res:
3636 fm.startitem()
3582 fm.startitem()
3637 fm.write("path", '%s\n', f)
3583 fm.write("path", '%s\n', f)
3638 fm.end()
3584 fm.end()
3639 return
3585 return
3640
3586
3641 if rev and node:
3587 if rev and node:
3642 raise error.Abort(_("please specify just one revision"))
3588 raise error.Abort(_("please specify just one revision"))
3643
3589
3644 if not node:
3590 if not node:
3645 node = rev
3591 node = rev
3646
3592
3647 char = {'l': '@', 'x': '*', '': ''}
3593 char = {'l': '@', 'x': '*', '': ''}
3648 mode = {'l': '644', 'x': '755', '': '644'}
3594 mode = {'l': '644', 'x': '755', '': '644'}
3649 ctx = scmutil.revsingle(repo, node)
3595 ctx = scmutil.revsingle(repo, node)
3650 mf = ctx.manifest()
3596 mf = ctx.manifest()
3651 for f in ctx:
3597 for f in ctx:
3652 fm.startitem()
3598 fm.startitem()
3653 fl = ctx[f].flags()
3599 fl = ctx[f].flags()
3654 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3600 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3655 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3601 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3656 fm.write('path', '%s\n', f)
3602 fm.write('path', '%s\n', f)
3657 fm.end()
3603 fm.end()
3658
3604
3659 @command('^merge',
3605 @command('^merge',
3660 [('f', 'force', None,
3606 [('f', 'force', None,
3661 _('force a merge including outstanding changes (DEPRECATED)')),
3607 _('force a merge including outstanding changes (DEPRECATED)')),
3662 ('r', 'rev', '', _('revision to merge'), _('REV')),
3608 ('r', 'rev', '', _('revision to merge'), _('REV')),
3663 ('P', 'preview', None,
3609 ('P', 'preview', None,
3664 _('review revisions to merge (no merge is performed)'))
3610 _('review revisions to merge (no merge is performed)'))
3665 ] + mergetoolopts,
3611 ] + mergetoolopts,
3666 _('[-P] [[-r] REV]'))
3612 _('[-P] [[-r] REV]'))
3667 def merge(ui, repo, node=None, **opts):
3613 def merge(ui, repo, node=None, **opts):
3668 """merge another revision into working directory
3614 """merge another revision into working directory
3669
3615
3670 The current working directory is updated with all changes made in
3616 The current working directory is updated with all changes made in
3671 the requested revision since the last common predecessor revision.
3617 the requested revision since the last common predecessor revision.
3672
3618
3673 Files that changed between either parent are marked as changed for
3619 Files that changed between either parent are marked as changed for
3674 the next commit and a commit must be performed before any further
3620 the next commit and a commit must be performed before any further
3675 updates to the repository are allowed. The next commit will have
3621 updates to the repository are allowed. The next commit will have
3676 two parents.
3622 two parents.
3677
3623
3678 ``--tool`` can be used to specify the merge tool used for file
3624 ``--tool`` can be used to specify the merge tool used for file
3679 merges. It overrides the HGMERGE environment variable and your
3625 merges. It overrides the HGMERGE environment variable and your
3680 configuration files. See :hg:`help merge-tools` for options.
3626 configuration files. See :hg:`help merge-tools` for options.
3681
3627
3682 If no revision is specified, the working directory's parent is a
3628 If no revision is specified, the working directory's parent is a
3683 head revision, and the current branch contains exactly one other
3629 head revision, and the current branch contains exactly one other
3684 head, the other head is merged with by default. Otherwise, an
3630 head, the other head is merged with by default. Otherwise, an
3685 explicit revision with which to merge with must be provided.
3631 explicit revision with which to merge with must be provided.
3686
3632
3687 See :hg:`help resolve` for information on handling file conflicts.
3633 See :hg:`help resolve` for information on handling file conflicts.
3688
3634
3689 To undo an uncommitted merge, use :hg:`update --clean .` which
3635 To undo an uncommitted merge, use :hg:`update --clean .` which
3690 will check out a clean copy of the original merge parent, losing
3636 will check out a clean copy of the original merge parent, losing
3691 all changes.
3637 all changes.
3692
3638
3693 Returns 0 on success, 1 if there are unresolved files.
3639 Returns 0 on success, 1 if there are unresolved files.
3694 """
3640 """
3695
3641
3696 if opts.get('rev') and node:
3642 if opts.get('rev') and node:
3697 raise error.Abort(_("please specify just one revision"))
3643 raise error.Abort(_("please specify just one revision"))
3698 if not node:
3644 if not node:
3699 node = opts.get('rev')
3645 node = opts.get('rev')
3700
3646
3701 if node:
3647 if node:
3702 node = scmutil.revsingle(repo, node).node()
3648 node = scmutil.revsingle(repo, node).node()
3703
3649
3704 if not node:
3650 if not node:
3705 node = repo[destutil.destmerge(repo)].node()
3651 node = repo[destutil.destmerge(repo)].node()
3706
3652
3707 if opts.get('preview'):
3653 if opts.get('preview'):
3708 # find nodes that are ancestors of p2 but not of p1
3654 # find nodes that are ancestors of p2 but not of p1
3709 p1 = repo.lookup('.')
3655 p1 = repo.lookup('.')
3710 p2 = repo.lookup(node)
3656 p2 = repo.lookup(node)
3711 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3657 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3712
3658
3713 displayer = cmdutil.show_changeset(ui, repo, opts)
3659 displayer = cmdutil.show_changeset(ui, repo, opts)
3714 for node in nodes:
3660 for node in nodes:
3715 displayer.show(repo[node])
3661 displayer.show(repo[node])
3716 displayer.close()
3662 displayer.close()
3717 return 0
3663 return 0
3718
3664
3719 try:
3665 try:
3720 # ui.forcemerge is an internal variable, do not document
3666 # ui.forcemerge is an internal variable, do not document
3721 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3667 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3722 force = opts.get('force')
3668 force = opts.get('force')
3723 labels = ['working copy', 'merge rev']
3669 labels = ['working copy', 'merge rev']
3724 return hg.merge(repo, node, force=force, mergeforce=force,
3670 return hg.merge(repo, node, force=force, mergeforce=force,
3725 labels=labels)
3671 labels=labels)
3726 finally:
3672 finally:
3727 ui.setconfig('ui', 'forcemerge', '', 'merge')
3673 ui.setconfig('ui', 'forcemerge', '', 'merge')
3728
3674
3729 @command('outgoing|out',
3675 @command('outgoing|out',
3730 [('f', 'force', None, _('run even when the destination is unrelated')),
3676 [('f', 'force', None, _('run even when the destination is unrelated')),
3731 ('r', 'rev', [],
3677 ('r', 'rev', [],
3732 _('a changeset intended to be included in the destination'), _('REV')),
3678 _('a changeset intended to be included in the destination'), _('REV')),
3733 ('n', 'newest-first', None, _('show newest record first')),
3679 ('n', 'newest-first', None, _('show newest record first')),
3734 ('B', 'bookmarks', False, _('compare bookmarks')),
3680 ('B', 'bookmarks', False, _('compare bookmarks')),
3735 ('b', 'branch', [], _('a specific branch you would like to push'),
3681 ('b', 'branch', [], _('a specific branch you would like to push'),
3736 _('BRANCH')),
3682 _('BRANCH')),
3737 ] + logopts + remoteopts + subrepoopts,
3683 ] + logopts + remoteopts + subrepoopts,
3738 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3684 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3739 def outgoing(ui, repo, dest=None, **opts):
3685 def outgoing(ui, repo, dest=None, **opts):
3740 """show changesets not found in the destination
3686 """show changesets not found in the destination
3741
3687
3742 Show changesets not found in the specified destination repository
3688 Show changesets not found in the specified destination repository
3743 or the default push location. These are the changesets that would
3689 or the default push location. These are the changesets that would
3744 be pushed if a push was requested.
3690 be pushed if a push was requested.
3745
3691
3746 See pull for details of valid destination formats.
3692 See pull for details of valid destination formats.
3747
3693
3748 .. container:: verbose
3694 .. container:: verbose
3749
3695
3750 With -B/--bookmarks, the result of bookmark comparison between
3696 With -B/--bookmarks, the result of bookmark comparison between
3751 local and remote repositories is displayed. With -v/--verbose,
3697 local and remote repositories is displayed. With -v/--verbose,
3752 status is also displayed for each bookmark like below::
3698 status is also displayed for each bookmark like below::
3753
3699
3754 BM1 01234567890a added
3700 BM1 01234567890a added
3755 BM2 deleted
3701 BM2 deleted
3756 BM3 234567890abc advanced
3702 BM3 234567890abc advanced
3757 BM4 34567890abcd diverged
3703 BM4 34567890abcd diverged
3758 BM5 4567890abcde changed
3704 BM5 4567890abcde changed
3759
3705
3760 The action taken when pushing depends on the
3706 The action taken when pushing depends on the
3761 status of each bookmark:
3707 status of each bookmark:
3762
3708
3763 :``added``: push with ``-B`` will create it
3709 :``added``: push with ``-B`` will create it
3764 :``deleted``: push with ``-B`` will delete it
3710 :``deleted``: push with ``-B`` will delete it
3765 :``advanced``: push will update it
3711 :``advanced``: push will update it
3766 :``diverged``: push with ``-B`` will update it
3712 :``diverged``: push with ``-B`` will update it
3767 :``changed``: push with ``-B`` will update it
3713 :``changed``: push with ``-B`` will update it
3768
3714
3769 From the point of view of pushing behavior, bookmarks
3715 From the point of view of pushing behavior, bookmarks
3770 existing only in the remote repository are treated as
3716 existing only in the remote repository are treated as
3771 ``deleted``, even if it is in fact added remotely.
3717 ``deleted``, even if it is in fact added remotely.
3772
3718
3773 Returns 0 if there are outgoing changes, 1 otherwise.
3719 Returns 0 if there are outgoing changes, 1 otherwise.
3774 """
3720 """
3775 if opts.get('graph'):
3721 if opts.get('graph'):
3776 cmdutil.checkunsupportedgraphflags([], opts)
3722 cmdutil.checkunsupportedgraphflags([], opts)
3777 o, other = hg._outgoing(ui, repo, dest, opts)
3723 o, other = hg._outgoing(ui, repo, dest, opts)
3778 if not o:
3724 if not o:
3779 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3725 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3780 return
3726 return
3781
3727
3782 revdag = cmdutil.graphrevs(repo, o, opts)
3728 revdag = cmdutil.graphrevs(repo, o, opts)
3783 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3729 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3784 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3730 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3785 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3731 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3786 return 0
3732 return 0
3787
3733
3788 if opts.get('bookmarks'):
3734 if opts.get('bookmarks'):
3789 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3735 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3790 dest, branches = hg.parseurl(dest, opts.get('branch'))
3736 dest, branches = hg.parseurl(dest, opts.get('branch'))
3791 other = hg.peer(repo, opts, dest)
3737 other = hg.peer(repo, opts, dest)
3792 if 'bookmarks' not in other.listkeys('namespaces'):
3738 if 'bookmarks' not in other.listkeys('namespaces'):
3793 ui.warn(_("remote doesn't support bookmarks\n"))
3739 ui.warn(_("remote doesn't support bookmarks\n"))
3794 return 0
3740 return 0
3795 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3741 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3796 return bookmarks.outgoing(ui, repo, other)
3742 return bookmarks.outgoing(ui, repo, other)
3797
3743
3798 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3744 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3799 try:
3745 try:
3800 return hg.outgoing(ui, repo, dest, opts)
3746 return hg.outgoing(ui, repo, dest, opts)
3801 finally:
3747 finally:
3802 del repo._subtoppath
3748 del repo._subtoppath
3803
3749
3804 @command('parents',
3750 @command('parents',
3805 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3751 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3806 ] + templateopts,
3752 ] + templateopts,
3807 _('[-r REV] [FILE]'),
3753 _('[-r REV] [FILE]'),
3808 inferrepo=True)
3754 inferrepo=True)
3809 def parents(ui, repo, file_=None, **opts):
3755 def parents(ui, repo, file_=None, **opts):
3810 """show the parents of the working directory or revision (DEPRECATED)
3756 """show the parents of the working directory or revision (DEPRECATED)
3811
3757
3812 Print the working directory's parent revisions. If a revision is
3758 Print the working directory's parent revisions. If a revision is
3813 given via -r/--rev, the parent of that revision will be printed.
3759 given via -r/--rev, the parent of that revision will be printed.
3814 If a file argument is given, the revision in which the file was
3760 If a file argument is given, the revision in which the file was
3815 last changed (before the working directory revision or the
3761 last changed (before the working directory revision or the
3816 argument to --rev if given) is printed.
3762 argument to --rev if given) is printed.
3817
3763
3818 This command is equivalent to::
3764 This command is equivalent to::
3819
3765
3820 hg log -r "p1()+p2()" or
3766 hg log -r "p1()+p2()" or
3821 hg log -r "p1(REV)+p2(REV)" or
3767 hg log -r "p1(REV)+p2(REV)" or
3822 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3768 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3823 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3769 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3824
3770
3825 See :hg:`summary` and :hg:`help revsets` for related information.
3771 See :hg:`summary` and :hg:`help revsets` for related information.
3826
3772
3827 Returns 0 on success.
3773 Returns 0 on success.
3828 """
3774 """
3829
3775
3830 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3776 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3831
3777
3832 if file_:
3778 if file_:
3833 m = scmutil.match(ctx, (file_,), opts)
3779 m = scmutil.match(ctx, (file_,), opts)
3834 if m.anypats() or len(m.files()) != 1:
3780 if m.anypats() or len(m.files()) != 1:
3835 raise error.Abort(_('can only specify an explicit filename'))
3781 raise error.Abort(_('can only specify an explicit filename'))
3836 file_ = m.files()[0]
3782 file_ = m.files()[0]
3837 filenodes = []
3783 filenodes = []
3838 for cp in ctx.parents():
3784 for cp in ctx.parents():
3839 if not cp:
3785 if not cp:
3840 continue
3786 continue
3841 try:
3787 try:
3842 filenodes.append(cp.filenode(file_))
3788 filenodes.append(cp.filenode(file_))
3843 except error.LookupError:
3789 except error.LookupError:
3844 pass
3790 pass
3845 if not filenodes:
3791 if not filenodes:
3846 raise error.Abort(_("'%s' not found in manifest!") % file_)
3792 raise error.Abort(_("'%s' not found in manifest!") % file_)
3847 p = []
3793 p = []
3848 for fn in filenodes:
3794 for fn in filenodes:
3849 fctx = repo.filectx(file_, fileid=fn)
3795 fctx = repo.filectx(file_, fileid=fn)
3850 p.append(fctx.node())
3796 p.append(fctx.node())
3851 else:
3797 else:
3852 p = [cp.node() for cp in ctx.parents()]
3798 p = [cp.node() for cp in ctx.parents()]
3853
3799
3854 displayer = cmdutil.show_changeset(ui, repo, opts)
3800 displayer = cmdutil.show_changeset(ui, repo, opts)
3855 for n in p:
3801 for n in p:
3856 if n != nullid:
3802 if n != nullid:
3857 displayer.show(repo[n])
3803 displayer.show(repo[n])
3858 displayer.close()
3804 displayer.close()
3859
3805
3860 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3806 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3861 def paths(ui, repo, search=None, **opts):
3807 def paths(ui, repo, search=None, **opts):
3862 """show aliases for remote repositories
3808 """show aliases for remote repositories
3863
3809
3864 Show definition of symbolic path name NAME. If no name is given,
3810 Show definition of symbolic path name NAME. If no name is given,
3865 show definition of all available names.
3811 show definition of all available names.
3866
3812
3867 Option -q/--quiet suppresses all output when searching for NAME
3813 Option -q/--quiet suppresses all output when searching for NAME
3868 and shows only the path names when listing all definitions.
3814 and shows only the path names when listing all definitions.
3869
3815
3870 Path names are defined in the [paths] section of your
3816 Path names are defined in the [paths] section of your
3871 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3817 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3872 repository, ``.hg/hgrc`` is used, too.
3818 repository, ``.hg/hgrc`` is used, too.
3873
3819
3874 The path names ``default`` and ``default-push`` have a special
3820 The path names ``default`` and ``default-push`` have a special
3875 meaning. When performing a push or pull operation, they are used
3821 meaning. When performing a push or pull operation, they are used
3876 as fallbacks if no location is specified on the command-line.
3822 as fallbacks if no location is specified on the command-line.
3877 When ``default-push`` is set, it will be used for push and
3823 When ``default-push`` is set, it will be used for push and
3878 ``default`` will be used for pull; otherwise ``default`` is used
3824 ``default`` will be used for pull; otherwise ``default`` is used
3879 as the fallback for both. When cloning a repository, the clone
3825 as the fallback for both. When cloning a repository, the clone
3880 source is written as ``default`` in ``.hg/hgrc``.
3826 source is written as ``default`` in ``.hg/hgrc``.
3881
3827
3882 .. note::
3828 .. note::
3883
3829
3884 ``default`` and ``default-push`` apply to all inbound (e.g.
3830 ``default`` and ``default-push`` apply to all inbound (e.g.
3885 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3831 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3886 and :hg:`bundle`) operations.
3832 and :hg:`bundle`) operations.
3887
3833
3888 See :hg:`help urls` for more information.
3834 See :hg:`help urls` for more information.
3889
3835
3890 Returns 0 on success.
3836 Returns 0 on success.
3891 """
3837 """
3892 if search:
3838 if search:
3893 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3839 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3894 if name == search]
3840 if name == search]
3895 else:
3841 else:
3896 pathitems = sorted(ui.paths.iteritems())
3842 pathitems = sorted(ui.paths.iteritems())
3897
3843
3898 fm = ui.formatter('paths', opts)
3844 fm = ui.formatter('paths', opts)
3899 if fm.isplain():
3845 if fm.isplain():
3900 hidepassword = util.hidepassword
3846 hidepassword = util.hidepassword
3901 else:
3847 else:
3902 hidepassword = str
3848 hidepassword = str
3903 if ui.quiet:
3849 if ui.quiet:
3904 namefmt = '%s\n'
3850 namefmt = '%s\n'
3905 else:
3851 else:
3906 namefmt = '%s = '
3852 namefmt = '%s = '
3907 showsubopts = not search and not ui.quiet
3853 showsubopts = not search and not ui.quiet
3908
3854
3909 for name, path in pathitems:
3855 for name, path in pathitems:
3910 fm.startitem()
3856 fm.startitem()
3911 fm.condwrite(not search, 'name', namefmt, name)
3857 fm.condwrite(not search, 'name', namefmt, name)
3912 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3858 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3913 for subopt, value in sorted(path.suboptions.items()):
3859 for subopt, value in sorted(path.suboptions.items()):
3914 assert subopt not in ('name', 'url')
3860 assert subopt not in ('name', 'url')
3915 if showsubopts:
3861 if showsubopts:
3916 fm.plain('%s:%s = ' % (name, subopt))
3862 fm.plain('%s:%s = ' % (name, subopt))
3917 fm.condwrite(showsubopts, subopt, '%s\n', value)
3863 fm.condwrite(showsubopts, subopt, '%s\n', value)
3918
3864
3919 fm.end()
3865 fm.end()
3920
3866
3921 if search and not pathitems:
3867 if search and not pathitems:
3922 if not ui.quiet:
3868 if not ui.quiet:
3923 ui.warn(_("not found!\n"))
3869 ui.warn(_("not found!\n"))
3924 return 1
3870 return 1
3925 else:
3871 else:
3926 return 0
3872 return 0
3927
3873
3928 @command('phase',
3874 @command('phase',
3929 [('p', 'public', False, _('set changeset phase to public')),
3875 [('p', 'public', False, _('set changeset phase to public')),
3930 ('d', 'draft', False, _('set changeset phase to draft')),
3876 ('d', 'draft', False, _('set changeset phase to draft')),
3931 ('s', 'secret', False, _('set changeset phase to secret')),
3877 ('s', 'secret', False, _('set changeset phase to secret')),
3932 ('f', 'force', False, _('allow to move boundary backward')),
3878 ('f', 'force', False, _('allow to move boundary backward')),
3933 ('r', 'rev', [], _('target revision'), _('REV')),
3879 ('r', 'rev', [], _('target revision'), _('REV')),
3934 ],
3880 ],
3935 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3881 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3936 def phase(ui, repo, *revs, **opts):
3882 def phase(ui, repo, *revs, **opts):
3937 """set or show the current phase name
3883 """set or show the current phase name
3938
3884
3939 With no argument, show the phase name of the current revision(s).
3885 With no argument, show the phase name of the current revision(s).
3940
3886
3941 With one of -p/--public, -d/--draft or -s/--secret, change the
3887 With one of -p/--public, -d/--draft or -s/--secret, change the
3942 phase value of the specified revisions.
3888 phase value of the specified revisions.
3943
3889
3944 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3890 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3945 lower phase to an higher phase. Phases are ordered as follows::
3891 lower phase to an higher phase. Phases are ordered as follows::
3946
3892
3947 public < draft < secret
3893 public < draft < secret
3948
3894
3949 Returns 0 on success, 1 if some phases could not be changed.
3895 Returns 0 on success, 1 if some phases could not be changed.
3950
3896
3951 (For more information about the phases concept, see :hg:`help phases`.)
3897 (For more information about the phases concept, see :hg:`help phases`.)
3952 """
3898 """
3953 # search for a unique phase argument
3899 # search for a unique phase argument
3954 targetphase = None
3900 targetphase = None
3955 for idx, name in enumerate(phases.phasenames):
3901 for idx, name in enumerate(phases.phasenames):
3956 if opts[name]:
3902 if opts[name]:
3957 if targetphase is not None:
3903 if targetphase is not None:
3958 raise error.Abort(_('only one phase can be specified'))
3904 raise error.Abort(_('only one phase can be specified'))
3959 targetphase = idx
3905 targetphase = idx
3960
3906
3961 # look for specified revision
3907 # look for specified revision
3962 revs = list(revs)
3908 revs = list(revs)
3963 revs.extend(opts['rev'])
3909 revs.extend(opts['rev'])
3964 if not revs:
3910 if not revs:
3965 # display both parents as the second parent phase can influence
3911 # display both parents as the second parent phase can influence
3966 # the phase of a merge commit
3912 # the phase of a merge commit
3967 revs = [c.rev() for c in repo[None].parents()]
3913 revs = [c.rev() for c in repo[None].parents()]
3968
3914
3969 revs = scmutil.revrange(repo, revs)
3915 revs = scmutil.revrange(repo, revs)
3970
3916
3971 lock = None
3917 lock = None
3972 ret = 0
3918 ret = 0
3973 if targetphase is None:
3919 if targetphase is None:
3974 # display
3920 # display
3975 for r in revs:
3921 for r in revs:
3976 ctx = repo[r]
3922 ctx = repo[r]
3977 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3923 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3978 else:
3924 else:
3979 tr = None
3925 tr = None
3980 lock = repo.lock()
3926 lock = repo.lock()
3981 try:
3927 try:
3982 tr = repo.transaction("phase")
3928 tr = repo.transaction("phase")
3983 # set phase
3929 # set phase
3984 if not revs:
3930 if not revs:
3985 raise error.Abort(_('empty revision set'))
3931 raise error.Abort(_('empty revision set'))
3986 nodes = [repo[r].node() for r in revs]
3932 nodes = [repo[r].node() for r in revs]
3987 # moving revision from public to draft may hide them
3933 # moving revision from public to draft may hide them
3988 # We have to check result on an unfiltered repository
3934 # We have to check result on an unfiltered repository
3989 unfi = repo.unfiltered()
3935 unfi = repo.unfiltered()
3990 getphase = unfi._phasecache.phase
3936 getphase = unfi._phasecache.phase
3991 olddata = [getphase(unfi, r) for r in unfi]
3937 olddata = [getphase(unfi, r) for r in unfi]
3992 phases.advanceboundary(repo, tr, targetphase, nodes)
3938 phases.advanceboundary(repo, tr, targetphase, nodes)
3993 if opts['force']:
3939 if opts['force']:
3994 phases.retractboundary(repo, tr, targetphase, nodes)
3940 phases.retractboundary(repo, tr, targetphase, nodes)
3995 tr.close()
3941 tr.close()
3996 finally:
3942 finally:
3997 if tr is not None:
3943 if tr is not None:
3998 tr.release()
3944 tr.release()
3999 lock.release()
3945 lock.release()
4000 getphase = unfi._phasecache.phase
3946 getphase = unfi._phasecache.phase
4001 newdata = [getphase(unfi, r) for r in unfi]
3947 newdata = [getphase(unfi, r) for r in unfi]
4002 changes = sum(newdata[r] != olddata[r] for r in unfi)
3948 changes = sum(newdata[r] != olddata[r] for r in unfi)
4003 cl = unfi.changelog
3949 cl = unfi.changelog
4004 rejected = [n for n in nodes
3950 rejected = [n for n in nodes
4005 if newdata[cl.rev(n)] < targetphase]
3951 if newdata[cl.rev(n)] < targetphase]
4006 if rejected:
3952 if rejected:
4007 ui.warn(_('cannot move %i changesets to a higher '
3953 ui.warn(_('cannot move %i changesets to a higher '
4008 'phase, use --force\n') % len(rejected))
3954 'phase, use --force\n') % len(rejected))
4009 ret = 1
3955 ret = 1
4010 if changes:
3956 if changes:
4011 msg = _('phase changed for %i changesets\n') % changes
3957 msg = _('phase changed for %i changesets\n') % changes
4012 if ret:
3958 if ret:
4013 ui.status(msg)
3959 ui.status(msg)
4014 else:
3960 else:
4015 ui.note(msg)
3961 ui.note(msg)
4016 else:
3962 else:
4017 ui.warn(_('no phases changed\n'))
3963 ui.warn(_('no phases changed\n'))
4018 return ret
3964 return ret
4019
3965
4020 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3966 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4021 """Run after a changegroup has been added via pull/unbundle
3967 """Run after a changegroup has been added via pull/unbundle
4022
3968
4023 This takes arguments below:
3969 This takes arguments below:
4024
3970
4025 :modheads: change of heads by pull/unbundle
3971 :modheads: change of heads by pull/unbundle
4026 :optupdate: updating working directory is needed or not
3972 :optupdate: updating working directory is needed or not
4027 :checkout: update destination revision (or None to default destination)
3973 :checkout: update destination revision (or None to default destination)
4028 :brev: a name, which might be a bookmark to be activated after updating
3974 :brev: a name, which might be a bookmark to be activated after updating
4029 """
3975 """
4030 if modheads == 0:
3976 if modheads == 0:
4031 return
3977 return
4032 if optupdate:
3978 if optupdate:
4033 try:
3979 try:
4034 return hg.updatetotally(ui, repo, checkout, brev)
3980 return hg.updatetotally(ui, repo, checkout, brev)
4035 except error.UpdateAbort as inst:
3981 except error.UpdateAbort as inst:
4036 msg = _("not updating: %s") % str(inst)
3982 msg = _("not updating: %s") % str(inst)
4037 hint = inst.hint
3983 hint = inst.hint
4038 raise error.UpdateAbort(msg, hint=hint)
3984 raise error.UpdateAbort(msg, hint=hint)
4039 if modheads > 1:
3985 if modheads > 1:
4040 currentbranchheads = len(repo.branchheads())
3986 currentbranchheads = len(repo.branchheads())
4041 if currentbranchheads == modheads:
3987 if currentbranchheads == modheads:
4042 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3988 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4043 elif currentbranchheads > 1:
3989 elif currentbranchheads > 1:
4044 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3990 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4045 "merge)\n"))
3991 "merge)\n"))
4046 else:
3992 else:
4047 ui.status(_("(run 'hg heads' to see heads)\n"))
3993 ui.status(_("(run 'hg heads' to see heads)\n"))
4048 else:
3994 else:
4049 ui.status(_("(run 'hg update' to get a working copy)\n"))
3995 ui.status(_("(run 'hg update' to get a working copy)\n"))
4050
3996
4051 @command('^pull',
3997 @command('^pull',
4052 [('u', 'update', None,
3998 [('u', 'update', None,
4053 _('update to new branch head if changesets were pulled')),
3999 _('update to new branch head if changesets were pulled')),
4054 ('f', 'force', None, _('run even when remote repository is unrelated')),
4000 ('f', 'force', None, _('run even when remote repository is unrelated')),
4055 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4001 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4056 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4002 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4057 ('b', 'branch', [], _('a specific branch you would like to pull'),
4003 ('b', 'branch', [], _('a specific branch you would like to pull'),
4058 _('BRANCH')),
4004 _('BRANCH')),
4059 ] + remoteopts,
4005 ] + remoteopts,
4060 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4006 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4061 def pull(ui, repo, source="default", **opts):
4007 def pull(ui, repo, source="default", **opts):
4062 """pull changes from the specified source
4008 """pull changes from the specified source
4063
4009
4064 Pull changes from a remote repository to a local one.
4010 Pull changes from a remote repository to a local one.
4065
4011
4066 This finds all changes from the repository at the specified path
4012 This finds all changes from the repository at the specified path
4067 or URL and adds them to a local repository (the current one unless
4013 or URL and adds them to a local repository (the current one unless
4068 -R is specified). By default, this does not update the copy of the
4014 -R is specified). By default, this does not update the copy of the
4069 project in the working directory.
4015 project in the working directory.
4070
4016
4071 Use :hg:`incoming` if you want to see what would have been added
4017 Use :hg:`incoming` if you want to see what would have been added
4072 by a pull at the time you issued this command. If you then decide
4018 by a pull at the time you issued this command. If you then decide
4073 to add those changes to the repository, you should use :hg:`pull
4019 to add those changes to the repository, you should use :hg:`pull
4074 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4020 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4075
4021
4076 If SOURCE is omitted, the 'default' path will be used.
4022 If SOURCE is omitted, the 'default' path will be used.
4077 See :hg:`help urls` for more information.
4023 See :hg:`help urls` for more information.
4078
4024
4079 Specifying bookmark as ``.`` is equivalent to specifying the active
4025 Specifying bookmark as ``.`` is equivalent to specifying the active
4080 bookmark's name.
4026 bookmark's name.
4081
4027
4082 Returns 0 on success, 1 if an update had unresolved files.
4028 Returns 0 on success, 1 if an update had unresolved files.
4083 """
4029 """
4084 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4030 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4085 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4031 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4086 other = hg.peer(repo, opts, source)
4032 other = hg.peer(repo, opts, source)
4087 try:
4033 try:
4088 revs, checkout = hg.addbranchrevs(repo, other, branches,
4034 revs, checkout = hg.addbranchrevs(repo, other, branches,
4089 opts.get('rev'))
4035 opts.get('rev'))
4090
4036
4091
4037
4092 pullopargs = {}
4038 pullopargs = {}
4093 if opts.get('bookmark'):
4039 if opts.get('bookmark'):
4094 if not revs:
4040 if not revs:
4095 revs = []
4041 revs = []
4096 # The list of bookmark used here is not the one used to actually
4042 # The list of bookmark used here is not the one used to actually
4097 # update the bookmark name. This can result in the revision pulled
4043 # update the bookmark name. This can result in the revision pulled
4098 # not ending up with the name of the bookmark because of a race
4044 # not ending up with the name of the bookmark because of a race
4099 # condition on the server. (See issue 4689 for details)
4045 # condition on the server. (See issue 4689 for details)
4100 remotebookmarks = other.listkeys('bookmarks')
4046 remotebookmarks = other.listkeys('bookmarks')
4101 pullopargs['remotebookmarks'] = remotebookmarks
4047 pullopargs['remotebookmarks'] = remotebookmarks
4102 for b in opts['bookmark']:
4048 for b in opts['bookmark']:
4103 b = repo._bookmarks.expandname(b)
4049 b = repo._bookmarks.expandname(b)
4104 if b not in remotebookmarks:
4050 if b not in remotebookmarks:
4105 raise error.Abort(_('remote bookmark %s not found!') % b)
4051 raise error.Abort(_('remote bookmark %s not found!') % b)
4106 revs.append(remotebookmarks[b])
4052 revs.append(remotebookmarks[b])
4107
4053
4108 if revs:
4054 if revs:
4109 try:
4055 try:
4110 # When 'rev' is a bookmark name, we cannot guarantee that it
4056 # When 'rev' is a bookmark name, we cannot guarantee that it
4111 # will be updated with that name because of a race condition
4057 # will be updated with that name because of a race condition
4112 # server side. (See issue 4689 for details)
4058 # server side. (See issue 4689 for details)
4113 oldrevs = revs
4059 oldrevs = revs
4114 revs = [] # actually, nodes
4060 revs = [] # actually, nodes
4115 for r in oldrevs:
4061 for r in oldrevs:
4116 node = other.lookup(r)
4062 node = other.lookup(r)
4117 revs.append(node)
4063 revs.append(node)
4118 if r == checkout:
4064 if r == checkout:
4119 checkout = node
4065 checkout = node
4120 except error.CapabilityError:
4066 except error.CapabilityError:
4121 err = _("other repository doesn't support revision lookup, "
4067 err = _("other repository doesn't support revision lookup, "
4122 "so a rev cannot be specified.")
4068 "so a rev cannot be specified.")
4123 raise error.Abort(err)
4069 raise error.Abort(err)
4124
4070
4125 pullopargs.update(opts.get('opargs', {}))
4071 pullopargs.update(opts.get('opargs', {}))
4126 modheads = exchange.pull(repo, other, heads=revs,
4072 modheads = exchange.pull(repo, other, heads=revs,
4127 force=opts.get('force'),
4073 force=opts.get('force'),
4128 bookmarks=opts.get('bookmark', ()),
4074 bookmarks=opts.get('bookmark', ()),
4129 opargs=pullopargs).cgresult
4075 opargs=pullopargs).cgresult
4130
4076
4131 # brev is a name, which might be a bookmark to be activated at
4077 # brev is a name, which might be a bookmark to be activated at
4132 # the end of the update. In other words, it is an explicit
4078 # the end of the update. In other words, it is an explicit
4133 # destination of the update
4079 # destination of the update
4134 brev = None
4080 brev = None
4135
4081
4136 if checkout:
4082 if checkout:
4137 checkout = str(repo.changelog.rev(checkout))
4083 checkout = str(repo.changelog.rev(checkout))
4138
4084
4139 # order below depends on implementation of
4085 # order below depends on implementation of
4140 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4086 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4141 # because 'checkout' is determined without it.
4087 # because 'checkout' is determined without it.
4142 if opts.get('rev'):
4088 if opts.get('rev'):
4143 brev = opts['rev'][0]
4089 brev = opts['rev'][0]
4144 elif opts.get('branch'):
4090 elif opts.get('branch'):
4145 brev = opts['branch'][0]
4091 brev = opts['branch'][0]
4146 else:
4092 else:
4147 brev = branches[0]
4093 brev = branches[0]
4148 repo._subtoppath = source
4094 repo._subtoppath = source
4149 try:
4095 try:
4150 ret = postincoming(ui, repo, modheads, opts.get('update'),
4096 ret = postincoming(ui, repo, modheads, opts.get('update'),
4151 checkout, brev)
4097 checkout, brev)
4152
4098
4153 finally:
4099 finally:
4154 del repo._subtoppath
4100 del repo._subtoppath
4155
4101
4156 finally:
4102 finally:
4157 other.close()
4103 other.close()
4158 return ret
4104 return ret
4159
4105
4160 @command('^push',
4106 @command('^push',
4161 [('f', 'force', None, _('force push')),
4107 [('f', 'force', None, _('force push')),
4162 ('r', 'rev', [],
4108 ('r', 'rev', [],
4163 _('a changeset intended to be included in the destination'),
4109 _('a changeset intended to be included in the destination'),
4164 _('REV')),
4110 _('REV')),
4165 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4111 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4166 ('b', 'branch', [],
4112 ('b', 'branch', [],
4167 _('a specific branch you would like to push'), _('BRANCH')),
4113 _('a specific branch you would like to push'), _('BRANCH')),
4168 ('', 'new-branch', False, _('allow pushing a new branch')),
4114 ('', 'new-branch', False, _('allow pushing a new branch')),
4169 ] + remoteopts,
4115 ] + remoteopts,
4170 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4116 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4171 def push(ui, repo, dest=None, **opts):
4117 def push(ui, repo, dest=None, **opts):
4172 """push changes to the specified destination
4118 """push changes to the specified destination
4173
4119
4174 Push changesets from the local repository to the specified
4120 Push changesets from the local repository to the specified
4175 destination.
4121 destination.
4176
4122
4177 This operation is symmetrical to pull: it is identical to a pull
4123 This operation is symmetrical to pull: it is identical to a pull
4178 in the destination repository from the current one.
4124 in the destination repository from the current one.
4179
4125
4180 By default, push will not allow creation of new heads at the
4126 By default, push will not allow creation of new heads at the
4181 destination, since multiple heads would make it unclear which head
4127 destination, since multiple heads would make it unclear which head
4182 to use. In this situation, it is recommended to pull and merge
4128 to use. In this situation, it is recommended to pull and merge
4183 before pushing.
4129 before pushing.
4184
4130
4185 Use --new-branch if you want to allow push to create a new named
4131 Use --new-branch if you want to allow push to create a new named
4186 branch that is not present at the destination. This allows you to
4132 branch that is not present at the destination. This allows you to
4187 only create a new branch without forcing other changes.
4133 only create a new branch without forcing other changes.
4188
4134
4189 .. note::
4135 .. note::
4190
4136
4191 Extra care should be taken with the -f/--force option,
4137 Extra care should be taken with the -f/--force option,
4192 which will push all new heads on all branches, an action which will
4138 which will push all new heads on all branches, an action which will
4193 almost always cause confusion for collaborators.
4139 almost always cause confusion for collaborators.
4194
4140
4195 If -r/--rev is used, the specified revision and all its ancestors
4141 If -r/--rev is used, the specified revision and all its ancestors
4196 will be pushed to the remote repository.
4142 will be pushed to the remote repository.
4197
4143
4198 If -B/--bookmark is used, the specified bookmarked revision, its
4144 If -B/--bookmark is used, the specified bookmarked revision, its
4199 ancestors, and the bookmark will be pushed to the remote
4145 ancestors, and the bookmark will be pushed to the remote
4200 repository. Specifying ``.`` is equivalent to specifying the active
4146 repository. Specifying ``.`` is equivalent to specifying the active
4201 bookmark's name.
4147 bookmark's name.
4202
4148
4203 Please see :hg:`help urls` for important details about ``ssh://``
4149 Please see :hg:`help urls` for important details about ``ssh://``
4204 URLs. If DESTINATION is omitted, a default path will be used.
4150 URLs. If DESTINATION is omitted, a default path will be used.
4205
4151
4206 Returns 0 if push was successful, 1 if nothing to push.
4152 Returns 0 if push was successful, 1 if nothing to push.
4207 """
4153 """
4208
4154
4209 if opts.get('bookmark'):
4155 if opts.get('bookmark'):
4210 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4156 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4211 for b in opts['bookmark']:
4157 for b in opts['bookmark']:
4212 # translate -B options to -r so changesets get pushed
4158 # translate -B options to -r so changesets get pushed
4213 b = repo._bookmarks.expandname(b)
4159 b = repo._bookmarks.expandname(b)
4214 if b in repo._bookmarks:
4160 if b in repo._bookmarks:
4215 opts.setdefault('rev', []).append(b)
4161 opts.setdefault('rev', []).append(b)
4216 else:
4162 else:
4217 # if we try to push a deleted bookmark, translate it to null
4163 # if we try to push a deleted bookmark, translate it to null
4218 # this lets simultaneous -r, -b options continue working
4164 # this lets simultaneous -r, -b options continue working
4219 opts.setdefault('rev', []).append("null")
4165 opts.setdefault('rev', []).append("null")
4220
4166
4221 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4167 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4222 if not path:
4168 if not path:
4223 raise error.Abort(_('default repository not configured!'),
4169 raise error.Abort(_('default repository not configured!'),
4224 hint=_("see 'hg help config.paths'"))
4170 hint=_("see 'hg help config.paths'"))
4225 dest = path.pushloc or path.loc
4171 dest = path.pushloc or path.loc
4226 branches = (path.branch, opts.get('branch') or [])
4172 branches = (path.branch, opts.get('branch') or [])
4227 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4173 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4228 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4174 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4229 other = hg.peer(repo, opts, dest)
4175 other = hg.peer(repo, opts, dest)
4230
4176
4231 if revs:
4177 if revs:
4232 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4178 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4233 if not revs:
4179 if not revs:
4234 raise error.Abort(_("specified revisions evaluate to an empty set"),
4180 raise error.Abort(_("specified revisions evaluate to an empty set"),
4235 hint=_("use different revision arguments"))
4181 hint=_("use different revision arguments"))
4236 elif path.pushrev:
4182 elif path.pushrev:
4237 # It doesn't make any sense to specify ancestor revisions. So limit
4183 # It doesn't make any sense to specify ancestor revisions. So limit
4238 # to DAG heads to make discovery simpler.
4184 # to DAG heads to make discovery simpler.
4239 expr = revset.formatspec('heads(%r)', path.pushrev)
4185 expr = revset.formatspec('heads(%r)', path.pushrev)
4240 revs = scmutil.revrange(repo, [expr])
4186 revs = scmutil.revrange(repo, [expr])
4241 revs = [repo[rev].node() for rev in revs]
4187 revs = [repo[rev].node() for rev in revs]
4242 if not revs:
4188 if not revs:
4243 raise error.Abort(_('default push revset for path evaluates to an '
4189 raise error.Abort(_('default push revset for path evaluates to an '
4244 'empty set'))
4190 'empty set'))
4245
4191
4246 repo._subtoppath = dest
4192 repo._subtoppath = dest
4247 try:
4193 try:
4248 # push subrepos depth-first for coherent ordering
4194 # push subrepos depth-first for coherent ordering
4249 c = repo['']
4195 c = repo['']
4250 subs = c.substate # only repos that are committed
4196 subs = c.substate # only repos that are committed
4251 for s in sorted(subs):
4197 for s in sorted(subs):
4252 result = c.sub(s).push(opts)
4198 result = c.sub(s).push(opts)
4253 if result == 0:
4199 if result == 0:
4254 return not result
4200 return not result
4255 finally:
4201 finally:
4256 del repo._subtoppath
4202 del repo._subtoppath
4257 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4203 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4258 newbranch=opts.get('new_branch'),
4204 newbranch=opts.get('new_branch'),
4259 bookmarks=opts.get('bookmark', ()),
4205 bookmarks=opts.get('bookmark', ()),
4260 opargs=opts.get('opargs'))
4206 opargs=opts.get('opargs'))
4261
4207
4262 result = not pushop.cgresult
4208 result = not pushop.cgresult
4263
4209
4264 if pushop.bkresult is not None:
4210 if pushop.bkresult is not None:
4265 if pushop.bkresult == 2:
4211 if pushop.bkresult == 2:
4266 result = 2
4212 result = 2
4267 elif not result and pushop.bkresult:
4213 elif not result and pushop.bkresult:
4268 result = 2
4214 result = 2
4269
4215
4270 return result
4216 return result
4271
4217
4272 @command('recover', [])
4218 @command('recover', [])
4273 def recover(ui, repo):
4219 def recover(ui, repo):
4274 """roll back an interrupted transaction
4220 """roll back an interrupted transaction
4275
4221
4276 Recover from an interrupted commit or pull.
4222 Recover from an interrupted commit or pull.
4277
4223
4278 This command tries to fix the repository status after an
4224 This command tries to fix the repository status after an
4279 interrupted operation. It should only be necessary when Mercurial
4225 interrupted operation. It should only be necessary when Mercurial
4280 suggests it.
4226 suggests it.
4281
4227
4282 Returns 0 if successful, 1 if nothing to recover or verify fails.
4228 Returns 0 if successful, 1 if nothing to recover or verify fails.
4283 """
4229 """
4284 if repo.recover():
4230 if repo.recover():
4285 return hg.verify(repo)
4231 return hg.verify(repo)
4286 return 1
4232 return 1
4287
4233
4288 @command('^remove|rm',
4234 @command('^remove|rm',
4289 [('A', 'after', None, _('record delete for missing files')),
4235 [('A', 'after', None, _('record delete for missing files')),
4290 ('f', 'force', None,
4236 ('f', 'force', None,
4291 _('forget added files, delete modified files')),
4237 _('forget added files, delete modified files')),
4292 ] + subrepoopts + walkopts,
4238 ] + subrepoopts + walkopts,
4293 _('[OPTION]... FILE...'),
4239 _('[OPTION]... FILE...'),
4294 inferrepo=True)
4240 inferrepo=True)
4295 def remove(ui, repo, *pats, **opts):
4241 def remove(ui, repo, *pats, **opts):
4296 """remove the specified files on the next commit
4242 """remove the specified files on the next commit
4297
4243
4298 Schedule the indicated files for removal from the current branch.
4244 Schedule the indicated files for removal from the current branch.
4299
4245
4300 This command schedules the files to be removed at the next commit.
4246 This command schedules the files to be removed at the next commit.
4301 To undo a remove before that, see :hg:`revert`. To undo added
4247 To undo a remove before that, see :hg:`revert`. To undo added
4302 files, see :hg:`forget`.
4248 files, see :hg:`forget`.
4303
4249
4304 .. container:: verbose
4250 .. container:: verbose
4305
4251
4306 -A/--after can be used to remove only files that have already
4252 -A/--after can be used to remove only files that have already
4307 been deleted, -f/--force can be used to force deletion, and -Af
4253 been deleted, -f/--force can be used to force deletion, and -Af
4308 can be used to remove files from the next revision without
4254 can be used to remove files from the next revision without
4309 deleting them from the working directory.
4255 deleting them from the working directory.
4310
4256
4311 The following table details the behavior of remove for different
4257 The following table details the behavior of remove for different
4312 file states (columns) and option combinations (rows). The file
4258 file states (columns) and option combinations (rows). The file
4313 states are Added [A], Clean [C], Modified [M] and Missing [!]
4259 states are Added [A], Clean [C], Modified [M] and Missing [!]
4314 (as reported by :hg:`status`). The actions are Warn, Remove
4260 (as reported by :hg:`status`). The actions are Warn, Remove
4315 (from branch) and Delete (from disk):
4261 (from branch) and Delete (from disk):
4316
4262
4317 ========= == == == ==
4263 ========= == == == ==
4318 opt/state A C M !
4264 opt/state A C M !
4319 ========= == == == ==
4265 ========= == == == ==
4320 none W RD W R
4266 none W RD W R
4321 -f R RD RD R
4267 -f R RD RD R
4322 -A W W W R
4268 -A W W W R
4323 -Af R R R R
4269 -Af R R R R
4324 ========= == == == ==
4270 ========= == == == ==
4325
4271
4326 .. note::
4272 .. note::
4327
4273
4328 :hg:`remove` never deletes files in Added [A] state from the
4274 :hg:`remove` never deletes files in Added [A] state from the
4329 working directory, not even if ``--force`` is specified.
4275 working directory, not even if ``--force`` is specified.
4330
4276
4331 Returns 0 on success, 1 if any warnings encountered.
4277 Returns 0 on success, 1 if any warnings encountered.
4332 """
4278 """
4333
4279
4334 after, force = opts.get('after'), opts.get('force')
4280 after, force = opts.get('after'), opts.get('force')
4335 if not pats and not after:
4281 if not pats and not after:
4336 raise error.Abort(_('no files specified'))
4282 raise error.Abort(_('no files specified'))
4337
4283
4338 m = scmutil.match(repo[None], pats, opts)
4284 m = scmutil.match(repo[None], pats, opts)
4339 subrepos = opts.get('subrepos')
4285 subrepos = opts.get('subrepos')
4340 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4286 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4341
4287
4342 @command('rename|move|mv',
4288 @command('rename|move|mv',
4343 [('A', 'after', None, _('record a rename that has already occurred')),
4289 [('A', 'after', None, _('record a rename that has already occurred')),
4344 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4290 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4345 ] + walkopts + dryrunopts,
4291 ] + walkopts + dryrunopts,
4346 _('[OPTION]... SOURCE... DEST'))
4292 _('[OPTION]... SOURCE... DEST'))
4347 def rename(ui, repo, *pats, **opts):
4293 def rename(ui, repo, *pats, **opts):
4348 """rename files; equivalent of copy + remove
4294 """rename files; equivalent of copy + remove
4349
4295
4350 Mark dest as copies of sources; mark sources for deletion. If dest
4296 Mark dest as copies of sources; mark sources for deletion. If dest
4351 is a directory, copies are put in that directory. If dest is a
4297 is a directory, copies are put in that directory. If dest is a
4352 file, there can only be one source.
4298 file, there can only be one source.
4353
4299
4354 By default, this command copies the contents of files as they
4300 By default, this command copies the contents of files as they
4355 exist in the working directory. If invoked with -A/--after, the
4301 exist in the working directory. If invoked with -A/--after, the
4356 operation is recorded, but no copying is performed.
4302 operation is recorded, but no copying is performed.
4357
4303
4358 This command takes effect at the next commit. To undo a rename
4304 This command takes effect at the next commit. To undo a rename
4359 before that, see :hg:`revert`.
4305 before that, see :hg:`revert`.
4360
4306
4361 Returns 0 on success, 1 if errors are encountered.
4307 Returns 0 on success, 1 if errors are encountered.
4362 """
4308 """
4363 with repo.wlock(False):
4309 with repo.wlock(False):
4364 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4310 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4365
4311
4366 @command('resolve',
4312 @command('resolve',
4367 [('a', 'all', None, _('select all unresolved files')),
4313 [('a', 'all', None, _('select all unresolved files')),
4368 ('l', 'list', None, _('list state of files needing merge')),
4314 ('l', 'list', None, _('list state of files needing merge')),
4369 ('m', 'mark', None, _('mark files as resolved')),
4315 ('m', 'mark', None, _('mark files as resolved')),
4370 ('u', 'unmark', None, _('mark files as unresolved')),
4316 ('u', 'unmark', None, _('mark files as unresolved')),
4371 ('n', 'no-status', None, _('hide status prefix'))]
4317 ('n', 'no-status', None, _('hide status prefix'))]
4372 + mergetoolopts + walkopts + formatteropts,
4318 + mergetoolopts + walkopts + formatteropts,
4373 _('[OPTION]... [FILE]...'),
4319 _('[OPTION]... [FILE]...'),
4374 inferrepo=True)
4320 inferrepo=True)
4375 def resolve(ui, repo, *pats, **opts):
4321 def resolve(ui, repo, *pats, **opts):
4376 """redo merges or set/view the merge status of files
4322 """redo merges or set/view the merge status of files
4377
4323
4378 Merges with unresolved conflicts are often the result of
4324 Merges with unresolved conflicts are often the result of
4379 non-interactive merging using the ``internal:merge`` configuration
4325 non-interactive merging using the ``internal:merge`` configuration
4380 setting, or a command-line merge tool like ``diff3``. The resolve
4326 setting, or a command-line merge tool like ``diff3``. The resolve
4381 command is used to manage the files involved in a merge, after
4327 command is used to manage the files involved in a merge, after
4382 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4328 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4383 working directory must have two parents). See :hg:`help
4329 working directory must have two parents). See :hg:`help
4384 merge-tools` for information on configuring merge tools.
4330 merge-tools` for information on configuring merge tools.
4385
4331
4386 The resolve command can be used in the following ways:
4332 The resolve command can be used in the following ways:
4387
4333
4388 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4334 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4389 files, discarding any previous merge attempts. Re-merging is not
4335 files, discarding any previous merge attempts. Re-merging is not
4390 performed for files already marked as resolved. Use ``--all/-a``
4336 performed for files already marked as resolved. Use ``--all/-a``
4391 to select all unresolved files. ``--tool`` can be used to specify
4337 to select all unresolved files. ``--tool`` can be used to specify
4392 the merge tool used for the given files. It overrides the HGMERGE
4338 the merge tool used for the given files. It overrides the HGMERGE
4393 environment variable and your configuration files. Previous file
4339 environment variable and your configuration files. Previous file
4394 contents are saved with a ``.orig`` suffix.
4340 contents are saved with a ``.orig`` suffix.
4395
4341
4396 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4342 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4397 (e.g. after having manually fixed-up the files). The default is
4343 (e.g. after having manually fixed-up the files). The default is
4398 to mark all unresolved files.
4344 to mark all unresolved files.
4399
4345
4400 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4346 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4401 default is to mark all resolved files.
4347 default is to mark all resolved files.
4402
4348
4403 - :hg:`resolve -l`: list files which had or still have conflicts.
4349 - :hg:`resolve -l`: list files which had or still have conflicts.
4404 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4350 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4405
4351
4406 .. note::
4352 .. note::
4407
4353
4408 Mercurial will not let you commit files with unresolved merge
4354 Mercurial will not let you commit files with unresolved merge
4409 conflicts. You must use :hg:`resolve -m ...` before you can
4355 conflicts. You must use :hg:`resolve -m ...` before you can
4410 commit after a conflicting merge.
4356 commit after a conflicting merge.
4411
4357
4412 Returns 0 on success, 1 if any files fail a resolve attempt.
4358 Returns 0 on success, 1 if any files fail a resolve attempt.
4413 """
4359 """
4414
4360
4415 flaglist = 'all mark unmark list no_status'.split()
4361 flaglist = 'all mark unmark list no_status'.split()
4416 all, mark, unmark, show, nostatus = \
4362 all, mark, unmark, show, nostatus = \
4417 [opts.get(o) for o in flaglist]
4363 [opts.get(o) for o in flaglist]
4418
4364
4419 if (show and (mark or unmark)) or (mark and unmark):
4365 if (show and (mark or unmark)) or (mark and unmark):
4420 raise error.Abort(_("too many options specified"))
4366 raise error.Abort(_("too many options specified"))
4421 if pats and all:
4367 if pats and all:
4422 raise error.Abort(_("can't specify --all and patterns"))
4368 raise error.Abort(_("can't specify --all and patterns"))
4423 if not (all or pats or show or mark or unmark):
4369 if not (all or pats or show or mark or unmark):
4424 raise error.Abort(_('no files or directories specified'),
4370 raise error.Abort(_('no files or directories specified'),
4425 hint=('use --all to re-merge all unresolved files'))
4371 hint=('use --all to re-merge all unresolved files'))
4426
4372
4427 if show:
4373 if show:
4428 fm = ui.formatter('resolve', opts)
4374 fm = ui.formatter('resolve', opts)
4429 ms = mergemod.mergestate.read(repo)
4375 ms = mergemod.mergestate.read(repo)
4430 m = scmutil.match(repo[None], pats, opts)
4376 m = scmutil.match(repo[None], pats, opts)
4431 for f in ms:
4377 for f in ms:
4432 if not m(f):
4378 if not m(f):
4433 continue
4379 continue
4434 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4380 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4435 'd': 'driverresolved'}[ms[f]]
4381 'd': 'driverresolved'}[ms[f]]
4436 fm.startitem()
4382 fm.startitem()
4437 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4383 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4438 fm.write('path', '%s\n', f, label=l)
4384 fm.write('path', '%s\n', f, label=l)
4439 fm.end()
4385 fm.end()
4440 return 0
4386 return 0
4441
4387
4442 with repo.wlock():
4388 with repo.wlock():
4443 ms = mergemod.mergestate.read(repo)
4389 ms = mergemod.mergestate.read(repo)
4444
4390
4445 if not (ms.active() or repo.dirstate.p2() != nullid):
4391 if not (ms.active() or repo.dirstate.p2() != nullid):
4446 raise error.Abort(
4392 raise error.Abort(
4447 _('resolve command not applicable when not merging'))
4393 _('resolve command not applicable when not merging'))
4448
4394
4449 wctx = repo[None]
4395 wctx = repo[None]
4450
4396
4451 if ms.mergedriver and ms.mdstate() == 'u':
4397 if ms.mergedriver and ms.mdstate() == 'u':
4452 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4398 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4453 ms.commit()
4399 ms.commit()
4454 # allow mark and unmark to go through
4400 # allow mark and unmark to go through
4455 if not mark and not unmark and not proceed:
4401 if not mark and not unmark and not proceed:
4456 return 1
4402 return 1
4457
4403
4458 m = scmutil.match(wctx, pats, opts)
4404 m = scmutil.match(wctx, pats, opts)
4459 ret = 0
4405 ret = 0
4460 didwork = False
4406 didwork = False
4461 runconclude = False
4407 runconclude = False
4462
4408
4463 tocomplete = []
4409 tocomplete = []
4464 for f in ms:
4410 for f in ms:
4465 if not m(f):
4411 if not m(f):
4466 continue
4412 continue
4467
4413
4468 didwork = True
4414 didwork = True
4469
4415
4470 # don't let driver-resolved files be marked, and run the conclude
4416 # don't let driver-resolved files be marked, and run the conclude
4471 # step if asked to resolve
4417 # step if asked to resolve
4472 if ms[f] == "d":
4418 if ms[f] == "d":
4473 exact = m.exact(f)
4419 exact = m.exact(f)
4474 if mark:
4420 if mark:
4475 if exact:
4421 if exact:
4476 ui.warn(_('not marking %s as it is driver-resolved\n')
4422 ui.warn(_('not marking %s as it is driver-resolved\n')
4477 % f)
4423 % f)
4478 elif unmark:
4424 elif unmark:
4479 if exact:
4425 if exact:
4480 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4426 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4481 % f)
4427 % f)
4482 else:
4428 else:
4483 runconclude = True
4429 runconclude = True
4484 continue
4430 continue
4485
4431
4486 if mark:
4432 if mark:
4487 ms.mark(f, "r")
4433 ms.mark(f, "r")
4488 elif unmark:
4434 elif unmark:
4489 ms.mark(f, "u")
4435 ms.mark(f, "u")
4490 else:
4436 else:
4491 # backup pre-resolve (merge uses .orig for its own purposes)
4437 # backup pre-resolve (merge uses .orig for its own purposes)
4492 a = repo.wjoin(f)
4438 a = repo.wjoin(f)
4493 try:
4439 try:
4494 util.copyfile(a, a + ".resolve")
4440 util.copyfile(a, a + ".resolve")
4495 except (IOError, OSError) as inst:
4441 except (IOError, OSError) as inst:
4496 if inst.errno != errno.ENOENT:
4442 if inst.errno != errno.ENOENT:
4497 raise
4443 raise
4498
4444
4499 try:
4445 try:
4500 # preresolve file
4446 # preresolve file
4501 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4447 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4502 'resolve')
4448 'resolve')
4503 complete, r = ms.preresolve(f, wctx)
4449 complete, r = ms.preresolve(f, wctx)
4504 if not complete:
4450 if not complete:
4505 tocomplete.append(f)
4451 tocomplete.append(f)
4506 elif r:
4452 elif r:
4507 ret = 1
4453 ret = 1
4508 finally:
4454 finally:
4509 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4455 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4510 ms.commit()
4456 ms.commit()
4511
4457
4512 # replace filemerge's .orig file with our resolve file, but only
4458 # replace filemerge's .orig file with our resolve file, but only
4513 # for merges that are complete
4459 # for merges that are complete
4514 if complete:
4460 if complete:
4515 try:
4461 try:
4516 util.rename(a + ".resolve",
4462 util.rename(a + ".resolve",
4517 scmutil.origpath(ui, repo, a))
4463 scmutil.origpath(ui, repo, a))
4518 except OSError as inst:
4464 except OSError as inst:
4519 if inst.errno != errno.ENOENT:
4465 if inst.errno != errno.ENOENT:
4520 raise
4466 raise
4521
4467
4522 for f in tocomplete:
4468 for f in tocomplete:
4523 try:
4469 try:
4524 # resolve file
4470 # resolve file
4525 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4471 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4526 'resolve')
4472 'resolve')
4527 r = ms.resolve(f, wctx)
4473 r = ms.resolve(f, wctx)
4528 if r:
4474 if r:
4529 ret = 1
4475 ret = 1
4530 finally:
4476 finally:
4531 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4477 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4532 ms.commit()
4478 ms.commit()
4533
4479
4534 # replace filemerge's .orig file with our resolve file
4480 # replace filemerge's .orig file with our resolve file
4535 a = repo.wjoin(f)
4481 a = repo.wjoin(f)
4536 try:
4482 try:
4537 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4483 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4538 except OSError as inst:
4484 except OSError as inst:
4539 if inst.errno != errno.ENOENT:
4485 if inst.errno != errno.ENOENT:
4540 raise
4486 raise
4541
4487
4542 ms.commit()
4488 ms.commit()
4543 ms.recordactions()
4489 ms.recordactions()
4544
4490
4545 if not didwork and pats:
4491 if not didwork and pats:
4546 hint = None
4492 hint = None
4547 if not any([p for p in pats if p.find(':') >= 0]):
4493 if not any([p for p in pats if p.find(':') >= 0]):
4548 pats = ['path:%s' % p for p in pats]
4494 pats = ['path:%s' % p for p in pats]
4549 m = scmutil.match(wctx, pats, opts)
4495 m = scmutil.match(wctx, pats, opts)
4550 for f in ms:
4496 for f in ms:
4551 if not m(f):
4497 if not m(f):
4552 continue
4498 continue
4553 flags = ''.join(['-%s ' % o[0] for o in flaglist
4499 flags = ''.join(['-%s ' % o[0] for o in flaglist
4554 if opts.get(o)])
4500 if opts.get(o)])
4555 hint = _("(try: hg resolve %s%s)\n") % (
4501 hint = _("(try: hg resolve %s%s)\n") % (
4556 flags,
4502 flags,
4557 ' '.join(pats))
4503 ' '.join(pats))
4558 break
4504 break
4559 ui.warn(_("arguments do not match paths that need resolving\n"))
4505 ui.warn(_("arguments do not match paths that need resolving\n"))
4560 if hint:
4506 if hint:
4561 ui.warn(hint)
4507 ui.warn(hint)
4562 elif ms.mergedriver and ms.mdstate() != 's':
4508 elif ms.mergedriver and ms.mdstate() != 's':
4563 # run conclude step when either a driver-resolved file is requested
4509 # run conclude step when either a driver-resolved file is requested
4564 # or there are no driver-resolved files
4510 # or there are no driver-resolved files
4565 # we can't use 'ret' to determine whether any files are unresolved
4511 # we can't use 'ret' to determine whether any files are unresolved
4566 # because we might not have tried to resolve some
4512 # because we might not have tried to resolve some
4567 if ((runconclude or not list(ms.driverresolved()))
4513 if ((runconclude or not list(ms.driverresolved()))
4568 and not list(ms.unresolved())):
4514 and not list(ms.unresolved())):
4569 proceed = mergemod.driverconclude(repo, ms, wctx)
4515 proceed = mergemod.driverconclude(repo, ms, wctx)
4570 ms.commit()
4516 ms.commit()
4571 if not proceed:
4517 if not proceed:
4572 return 1
4518 return 1
4573
4519
4574 # Nudge users into finishing an unfinished operation
4520 # Nudge users into finishing an unfinished operation
4575 unresolvedf = list(ms.unresolved())
4521 unresolvedf = list(ms.unresolved())
4576 driverresolvedf = list(ms.driverresolved())
4522 driverresolvedf = list(ms.driverresolved())
4577 if not unresolvedf and not driverresolvedf:
4523 if not unresolvedf and not driverresolvedf:
4578 ui.status(_('(no more unresolved files)\n'))
4524 ui.status(_('(no more unresolved files)\n'))
4579 cmdutil.checkafterresolved(repo)
4525 cmdutil.checkafterresolved(repo)
4580 elif not unresolvedf:
4526 elif not unresolvedf:
4581 ui.status(_('(no more unresolved files -- '
4527 ui.status(_('(no more unresolved files -- '
4582 'run "hg resolve --all" to conclude)\n'))
4528 'run "hg resolve --all" to conclude)\n'))
4583
4529
4584 return ret
4530 return ret
4585
4531
4586 @command('revert',
4532 @command('revert',
4587 [('a', 'all', None, _('revert all changes when no arguments given')),
4533 [('a', 'all', None, _('revert all changes when no arguments given')),
4588 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4534 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4589 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4535 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4590 ('C', 'no-backup', None, _('do not save backup copies of files')),
4536 ('C', 'no-backup', None, _('do not save backup copies of files')),
4591 ('i', 'interactive', None,
4537 ('i', 'interactive', None,
4592 _('interactively select the changes (EXPERIMENTAL)')),
4538 _('interactively select the changes (EXPERIMENTAL)')),
4593 ] + walkopts + dryrunopts,
4539 ] + walkopts + dryrunopts,
4594 _('[OPTION]... [-r REV] [NAME]...'))
4540 _('[OPTION]... [-r REV] [NAME]...'))
4595 def revert(ui, repo, *pats, **opts):
4541 def revert(ui, repo, *pats, **opts):
4596 """restore files to their checkout state
4542 """restore files to their checkout state
4597
4543
4598 .. note::
4544 .. note::
4599
4545
4600 To check out earlier revisions, you should use :hg:`update REV`.
4546 To check out earlier revisions, you should use :hg:`update REV`.
4601 To cancel an uncommitted merge (and lose your changes),
4547 To cancel an uncommitted merge (and lose your changes),
4602 use :hg:`update --clean .`.
4548 use :hg:`update --clean .`.
4603
4549
4604 With no revision specified, revert the specified files or directories
4550 With no revision specified, revert the specified files or directories
4605 to the contents they had in the parent of the working directory.
4551 to the contents they had in the parent of the working directory.
4606 This restores the contents of files to an unmodified
4552 This restores the contents of files to an unmodified
4607 state and unschedules adds, removes, copies, and renames. If the
4553 state and unschedules adds, removes, copies, and renames. If the
4608 working directory has two parents, you must explicitly specify a
4554 working directory has two parents, you must explicitly specify a
4609 revision.
4555 revision.
4610
4556
4611 Using the -r/--rev or -d/--date options, revert the given files or
4557 Using the -r/--rev or -d/--date options, revert the given files or
4612 directories to their states as of a specific revision. Because
4558 directories to their states as of a specific revision. Because
4613 revert does not change the working directory parents, this will
4559 revert does not change the working directory parents, this will
4614 cause these files to appear modified. This can be helpful to "back
4560 cause these files to appear modified. This can be helpful to "back
4615 out" some or all of an earlier change. See :hg:`backout` for a
4561 out" some or all of an earlier change. See :hg:`backout` for a
4616 related method.
4562 related method.
4617
4563
4618 Modified files are saved with a .orig suffix before reverting.
4564 Modified files are saved with a .orig suffix before reverting.
4619 To disable these backups, use --no-backup. It is possible to store
4565 To disable these backups, use --no-backup. It is possible to store
4620 the backup files in a custom directory relative to the root of the
4566 the backup files in a custom directory relative to the root of the
4621 repository by setting the ``ui.origbackuppath`` configuration
4567 repository by setting the ``ui.origbackuppath`` configuration
4622 option.
4568 option.
4623
4569
4624 See :hg:`help dates` for a list of formats valid for -d/--date.
4570 See :hg:`help dates` for a list of formats valid for -d/--date.
4625
4571
4626 See :hg:`help backout` for a way to reverse the effect of an
4572 See :hg:`help backout` for a way to reverse the effect of an
4627 earlier changeset.
4573 earlier changeset.
4628
4574
4629 Returns 0 on success.
4575 Returns 0 on success.
4630 """
4576 """
4631
4577
4632 if opts.get("date"):
4578 if opts.get("date"):
4633 if opts.get("rev"):
4579 if opts.get("rev"):
4634 raise error.Abort(_("you can't specify a revision and a date"))
4580 raise error.Abort(_("you can't specify a revision and a date"))
4635 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4581 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4636
4582
4637 parent, p2 = repo.dirstate.parents()
4583 parent, p2 = repo.dirstate.parents()
4638 if not opts.get('rev') and p2 != nullid:
4584 if not opts.get('rev') and p2 != nullid:
4639 # revert after merge is a trap for new users (issue2915)
4585 # revert after merge is a trap for new users (issue2915)
4640 raise error.Abort(_('uncommitted merge with no revision specified'),
4586 raise error.Abort(_('uncommitted merge with no revision specified'),
4641 hint=_("use 'hg update' or see 'hg help revert'"))
4587 hint=_("use 'hg update' or see 'hg help revert'"))
4642
4588
4643 ctx = scmutil.revsingle(repo, opts.get('rev'))
4589 ctx = scmutil.revsingle(repo, opts.get('rev'))
4644
4590
4645 if (not (pats or opts.get('include') or opts.get('exclude') or
4591 if (not (pats or opts.get('include') or opts.get('exclude') or
4646 opts.get('all') or opts.get('interactive'))):
4592 opts.get('all') or opts.get('interactive'))):
4647 msg = _("no files or directories specified")
4593 msg = _("no files or directories specified")
4648 if p2 != nullid:
4594 if p2 != nullid:
4649 hint = _("uncommitted merge, use --all to discard all changes,"
4595 hint = _("uncommitted merge, use --all to discard all changes,"
4650 " or 'hg update -C .' to abort the merge")
4596 " or 'hg update -C .' to abort the merge")
4651 raise error.Abort(msg, hint=hint)
4597 raise error.Abort(msg, hint=hint)
4652 dirty = any(repo.status())
4598 dirty = any(repo.status())
4653 node = ctx.node()
4599 node = ctx.node()
4654 if node != parent:
4600 if node != parent:
4655 if dirty:
4601 if dirty:
4656 hint = _("uncommitted changes, use --all to discard all"
4602 hint = _("uncommitted changes, use --all to discard all"
4657 " changes, or 'hg update %s' to update") % ctx.rev()
4603 " changes, or 'hg update %s' to update") % ctx.rev()
4658 else:
4604 else:
4659 hint = _("use --all to revert all files,"
4605 hint = _("use --all to revert all files,"
4660 " or 'hg update %s' to update") % ctx.rev()
4606 " or 'hg update %s' to update") % ctx.rev()
4661 elif dirty:
4607 elif dirty:
4662 hint = _("uncommitted changes, use --all to discard all changes")
4608 hint = _("uncommitted changes, use --all to discard all changes")
4663 else:
4609 else:
4664 hint = _("use --all to revert all files")
4610 hint = _("use --all to revert all files")
4665 raise error.Abort(msg, hint=hint)
4611 raise error.Abort(msg, hint=hint)
4666
4612
4667 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4613 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4668
4614
4669 @command('rollback', dryrunopts +
4615 @command('rollback', dryrunopts +
4670 [('f', 'force', False, _('ignore safety measures'))])
4616 [('f', 'force', False, _('ignore safety measures'))])
4671 def rollback(ui, repo, **opts):
4617 def rollback(ui, repo, **opts):
4672 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4618 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4673
4619
4674 Please use :hg:`commit --amend` instead of rollback to correct
4620 Please use :hg:`commit --amend` instead of rollback to correct
4675 mistakes in the last commit.
4621 mistakes in the last commit.
4676
4622
4677 This command should be used with care. There is only one level of
4623 This command should be used with care. There is only one level of
4678 rollback, and there is no way to undo a rollback. It will also
4624 rollback, and there is no way to undo a rollback. It will also
4679 restore the dirstate at the time of the last transaction, losing
4625 restore the dirstate at the time of the last transaction, losing
4680 any dirstate changes since that time. This command does not alter
4626 any dirstate changes since that time. This command does not alter
4681 the working directory.
4627 the working directory.
4682
4628
4683 Transactions are used to encapsulate the effects of all commands
4629 Transactions are used to encapsulate the effects of all commands
4684 that create new changesets or propagate existing changesets into a
4630 that create new changesets or propagate existing changesets into a
4685 repository.
4631 repository.
4686
4632
4687 .. container:: verbose
4633 .. container:: verbose
4688
4634
4689 For example, the following commands are transactional, and their
4635 For example, the following commands are transactional, and their
4690 effects can be rolled back:
4636 effects can be rolled back:
4691
4637
4692 - commit
4638 - commit
4693 - import
4639 - import
4694 - pull
4640 - pull
4695 - push (with this repository as the destination)
4641 - push (with this repository as the destination)
4696 - unbundle
4642 - unbundle
4697
4643
4698 To avoid permanent data loss, rollback will refuse to rollback a
4644 To avoid permanent data loss, rollback will refuse to rollback a
4699 commit transaction if it isn't checked out. Use --force to
4645 commit transaction if it isn't checked out. Use --force to
4700 override this protection.
4646 override this protection.
4701
4647
4702 The rollback command can be entirely disabled by setting the
4648 The rollback command can be entirely disabled by setting the
4703 ``ui.rollback`` configuration setting to false. If you're here
4649 ``ui.rollback`` configuration setting to false. If you're here
4704 because you want to use rollback and it's disabled, you can
4650 because you want to use rollback and it's disabled, you can
4705 re-enable the command by setting ``ui.rollback`` to true.
4651 re-enable the command by setting ``ui.rollback`` to true.
4706
4652
4707 This command is not intended for use on public repositories. Once
4653 This command is not intended for use on public repositories. Once
4708 changes are visible for pull by other users, rolling a transaction
4654 changes are visible for pull by other users, rolling a transaction
4709 back locally is ineffective (someone else may already have pulled
4655 back locally is ineffective (someone else may already have pulled
4710 the changes). Furthermore, a race is possible with readers of the
4656 the changes). Furthermore, a race is possible with readers of the
4711 repository; for example an in-progress pull from the repository
4657 repository; for example an in-progress pull from the repository
4712 may fail if a rollback is performed.
4658 may fail if a rollback is performed.
4713
4659
4714 Returns 0 on success, 1 if no rollback data is available.
4660 Returns 0 on success, 1 if no rollback data is available.
4715 """
4661 """
4716 if not ui.configbool('ui', 'rollback', True):
4662 if not ui.configbool('ui', 'rollback', True):
4717 raise error.Abort(_('rollback is disabled because it is unsafe'),
4663 raise error.Abort(_('rollback is disabled because it is unsafe'),
4718 hint=('see `hg help -v rollback` for information'))
4664 hint=('see `hg help -v rollback` for information'))
4719 return repo.rollback(dryrun=opts.get('dry_run'),
4665 return repo.rollback(dryrun=opts.get('dry_run'),
4720 force=opts.get('force'))
4666 force=opts.get('force'))
4721
4667
4722 @command('root', [])
4668 @command('root', [])
4723 def root(ui, repo):
4669 def root(ui, repo):
4724 """print the root (top) of the current working directory
4670 """print the root (top) of the current working directory
4725
4671
4726 Print the root directory of the current repository.
4672 Print the root directory of the current repository.
4727
4673
4728 Returns 0 on success.
4674 Returns 0 on success.
4729 """
4675 """
4730 ui.write(repo.root + "\n")
4676 ui.write(repo.root + "\n")
4731
4677
4732 @command('^serve',
4678 @command('^serve',
4733 [('A', 'accesslog', '', _('name of access log file to write to'),
4679 [('A', 'accesslog', '', _('name of access log file to write to'),
4734 _('FILE')),
4680 _('FILE')),
4735 ('d', 'daemon', None, _('run server in background')),
4681 ('d', 'daemon', None, _('run server in background')),
4736 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4682 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4737 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4683 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4738 # use string type, then we can check if something was passed
4684 # use string type, then we can check if something was passed
4739 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4685 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4740 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4686 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4741 _('ADDR')),
4687 _('ADDR')),
4742 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4688 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4743 _('PREFIX')),
4689 _('PREFIX')),
4744 ('n', 'name', '',
4690 ('n', 'name', '',
4745 _('name to show in web pages (default: working directory)'), _('NAME')),
4691 _('name to show in web pages (default: working directory)'), _('NAME')),
4746 ('', 'web-conf', '',
4692 ('', 'web-conf', '',
4747 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4693 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4748 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4694 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4749 _('FILE')),
4695 _('FILE')),
4750 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4696 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4751 ('', 'stdio', None, _('for remote clients')),
4697 ('', 'stdio', None, _('for remote clients')),
4752 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4698 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4753 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4699 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4754 ('', 'style', '', _('template style to use'), _('STYLE')),
4700 ('', 'style', '', _('template style to use'), _('STYLE')),
4755 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4701 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4756 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4702 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4757 _('[OPTION]...'),
4703 _('[OPTION]...'),
4758 optionalrepo=True)
4704 optionalrepo=True)
4759 def serve(ui, repo, **opts):
4705 def serve(ui, repo, **opts):
4760 """start stand-alone webserver
4706 """start stand-alone webserver
4761
4707
4762 Start a local HTTP repository browser and pull server. You can use
4708 Start a local HTTP repository browser and pull server. You can use
4763 this for ad-hoc sharing and browsing of repositories. It is
4709 this for ad-hoc sharing and browsing of repositories. It is
4764 recommended to use a real web server to serve a repository for
4710 recommended to use a real web server to serve a repository for
4765 longer periods of time.
4711 longer periods of time.
4766
4712
4767 Please note that the server does not implement access control.
4713 Please note that the server does not implement access control.
4768 This means that, by default, anybody can read from the server and
4714 This means that, by default, anybody can read from the server and
4769 nobody can write to it by default. Set the ``web.allow_push``
4715 nobody can write to it by default. Set the ``web.allow_push``
4770 option to ``*`` to allow everybody to push to the server. You
4716 option to ``*`` to allow everybody to push to the server. You
4771 should use a real web server if you need to authenticate users.
4717 should use a real web server if you need to authenticate users.
4772
4718
4773 By default, the server logs accesses to stdout and errors to
4719 By default, the server logs accesses to stdout and errors to
4774 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4720 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4775 files.
4721 files.
4776
4722
4777 To have the server choose a free port number to listen on, specify
4723 To have the server choose a free port number to listen on, specify
4778 a port number of 0; in this case, the server will print the port
4724 a port number of 0; in this case, the server will print the port
4779 number it uses.
4725 number it uses.
4780
4726
4781 Returns 0 on success.
4727 Returns 0 on success.
4782 """
4728 """
4783
4729
4784 if opts["stdio"] and opts["cmdserver"]:
4730 if opts["stdio"] and opts["cmdserver"]:
4785 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4731 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4786
4732
4787 if opts["stdio"]:
4733 if opts["stdio"]:
4788 if repo is None:
4734 if repo is None:
4789 raise error.RepoError(_("there is no Mercurial repository here"
4735 raise error.RepoError(_("there is no Mercurial repository here"
4790 " (.hg not found)"))
4736 " (.hg not found)"))
4791 s = sshserver.sshserver(ui, repo)
4737 s = sshserver.sshserver(ui, repo)
4792 s.serve_forever()
4738 s.serve_forever()
4793
4739
4794 service = server.createservice(ui, repo, opts)
4740 service = server.createservice(ui, repo, opts)
4795 return server.runservice(opts, initfn=service.init, runfn=service.run)
4741 return server.runservice(opts, initfn=service.init, runfn=service.run)
4796
4742
4797 @command('^status|st',
4743 @command('^status|st',
4798 [('A', 'all', None, _('show status of all files')),
4744 [('A', 'all', None, _('show status of all files')),
4799 ('m', 'modified', None, _('show only modified files')),
4745 ('m', 'modified', None, _('show only modified files')),
4800 ('a', 'added', None, _('show only added files')),
4746 ('a', 'added', None, _('show only added files')),
4801 ('r', 'removed', None, _('show only removed files')),
4747 ('r', 'removed', None, _('show only removed files')),
4802 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4748 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4803 ('c', 'clean', None, _('show only files without changes')),
4749 ('c', 'clean', None, _('show only files without changes')),
4804 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4750 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4805 ('i', 'ignored', None, _('show only ignored files')),
4751 ('i', 'ignored', None, _('show only ignored files')),
4806 ('n', 'no-status', None, _('hide status prefix')),
4752 ('n', 'no-status', None, _('hide status prefix')),
4807 ('C', 'copies', None, _('show source of copied files')),
4753 ('C', 'copies', None, _('show source of copied files')),
4808 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4754 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4809 ('', 'rev', [], _('show difference from revision'), _('REV')),
4755 ('', 'rev', [], _('show difference from revision'), _('REV')),
4810 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4756 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4811 ] + walkopts + subrepoopts + formatteropts,
4757 ] + walkopts + subrepoopts + formatteropts,
4812 _('[OPTION]... [FILE]...'),
4758 _('[OPTION]... [FILE]...'),
4813 inferrepo=True)
4759 inferrepo=True)
4814 def status(ui, repo, *pats, **opts):
4760 def status(ui, repo, *pats, **opts):
4815 """show changed files in the working directory
4761 """show changed files in the working directory
4816
4762
4817 Show status of files in the repository. If names are given, only
4763 Show status of files in the repository. If names are given, only
4818 files that match are shown. Files that are clean or ignored or
4764 files that match are shown. Files that are clean or ignored or
4819 the source of a copy/move operation, are not listed unless
4765 the source of a copy/move operation, are not listed unless
4820 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4766 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4821 Unless options described with "show only ..." are given, the
4767 Unless options described with "show only ..." are given, the
4822 options -mardu are used.
4768 options -mardu are used.
4823
4769
4824 Option -q/--quiet hides untracked (unknown and ignored) files
4770 Option -q/--quiet hides untracked (unknown and ignored) files
4825 unless explicitly requested with -u/--unknown or -i/--ignored.
4771 unless explicitly requested with -u/--unknown or -i/--ignored.
4826
4772
4827 .. note::
4773 .. note::
4828
4774
4829 :hg:`status` may appear to disagree with diff if permissions have
4775 :hg:`status` may appear to disagree with diff if permissions have
4830 changed or a merge has occurred. The standard diff format does
4776 changed or a merge has occurred. The standard diff format does
4831 not report permission changes and diff only reports changes
4777 not report permission changes and diff only reports changes
4832 relative to one merge parent.
4778 relative to one merge parent.
4833
4779
4834 If one revision is given, it is used as the base revision.
4780 If one revision is given, it is used as the base revision.
4835 If two revisions are given, the differences between them are
4781 If two revisions are given, the differences between them are
4836 shown. The --change option can also be used as a shortcut to list
4782 shown. The --change option can also be used as a shortcut to list
4837 the changed files of a revision from its first parent.
4783 the changed files of a revision from its first parent.
4838
4784
4839 The codes used to show the status of files are::
4785 The codes used to show the status of files are::
4840
4786
4841 M = modified
4787 M = modified
4842 A = added
4788 A = added
4843 R = removed
4789 R = removed
4844 C = clean
4790 C = clean
4845 ! = missing (deleted by non-hg command, but still tracked)
4791 ! = missing (deleted by non-hg command, but still tracked)
4846 ? = not tracked
4792 ? = not tracked
4847 I = ignored
4793 I = ignored
4848 = origin of the previous file (with --copies)
4794 = origin of the previous file (with --copies)
4849
4795
4850 .. container:: verbose
4796 .. container:: verbose
4851
4797
4852 Examples:
4798 Examples:
4853
4799
4854 - show changes in the working directory relative to a
4800 - show changes in the working directory relative to a
4855 changeset::
4801 changeset::
4856
4802
4857 hg status --rev 9353
4803 hg status --rev 9353
4858
4804
4859 - show changes in the working directory relative to the
4805 - show changes in the working directory relative to the
4860 current directory (see :hg:`help patterns` for more information)::
4806 current directory (see :hg:`help patterns` for more information)::
4861
4807
4862 hg status re:
4808 hg status re:
4863
4809
4864 - show all changes including copies in an existing changeset::
4810 - show all changes including copies in an existing changeset::
4865
4811
4866 hg status --copies --change 9353
4812 hg status --copies --change 9353
4867
4813
4868 - get a NUL separated list of added files, suitable for xargs::
4814 - get a NUL separated list of added files, suitable for xargs::
4869
4815
4870 hg status -an0
4816 hg status -an0
4871
4817
4872 Returns 0 on success.
4818 Returns 0 on success.
4873 """
4819 """
4874
4820
4875 revs = opts.get('rev')
4821 revs = opts.get('rev')
4876 change = opts.get('change')
4822 change = opts.get('change')
4877
4823
4878 if revs and change:
4824 if revs and change:
4879 msg = _('cannot specify --rev and --change at the same time')
4825 msg = _('cannot specify --rev and --change at the same time')
4880 raise error.Abort(msg)
4826 raise error.Abort(msg)
4881 elif change:
4827 elif change:
4882 node2 = scmutil.revsingle(repo, change, None).node()
4828 node2 = scmutil.revsingle(repo, change, None).node()
4883 node1 = repo[node2].p1().node()
4829 node1 = repo[node2].p1().node()
4884 else:
4830 else:
4885 node1, node2 = scmutil.revpair(repo, revs)
4831 node1, node2 = scmutil.revpair(repo, revs)
4886
4832
4887 if pats:
4833 if pats:
4888 cwd = repo.getcwd()
4834 cwd = repo.getcwd()
4889 else:
4835 else:
4890 cwd = ''
4836 cwd = ''
4891
4837
4892 if opts.get('print0'):
4838 if opts.get('print0'):
4893 end = '\0'
4839 end = '\0'
4894 else:
4840 else:
4895 end = '\n'
4841 end = '\n'
4896 copy = {}
4842 copy = {}
4897 states = 'modified added removed deleted unknown ignored clean'.split()
4843 states = 'modified added removed deleted unknown ignored clean'.split()
4898 show = [k for k in states if opts.get(k)]
4844 show = [k for k in states if opts.get(k)]
4899 if opts.get('all'):
4845 if opts.get('all'):
4900 show += ui.quiet and (states[:4] + ['clean']) or states
4846 show += ui.quiet and (states[:4] + ['clean']) or states
4901 if not show:
4847 if not show:
4902 if ui.quiet:
4848 if ui.quiet:
4903 show = states[:4]
4849 show = states[:4]
4904 else:
4850 else:
4905 show = states[:5]
4851 show = states[:5]
4906
4852
4907 m = scmutil.match(repo[node2], pats, opts)
4853 m = scmutil.match(repo[node2], pats, opts)
4908 stat = repo.status(node1, node2, m,
4854 stat = repo.status(node1, node2, m,
4909 'ignored' in show, 'clean' in show, 'unknown' in show,
4855 'ignored' in show, 'clean' in show, 'unknown' in show,
4910 opts.get('subrepos'))
4856 opts.get('subrepos'))
4911 changestates = zip(states, 'MAR!?IC', stat)
4857 changestates = zip(states, 'MAR!?IC', stat)
4912
4858
4913 if (opts.get('all') or opts.get('copies')
4859 if (opts.get('all') or opts.get('copies')
4914 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4860 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4915 copy = copies.pathcopies(repo[node1], repo[node2], m)
4861 copy = copies.pathcopies(repo[node1], repo[node2], m)
4916
4862
4917 fm = ui.formatter('status', opts)
4863 fm = ui.formatter('status', opts)
4918 fmt = '%s' + end
4864 fmt = '%s' + end
4919 showchar = not opts.get('no_status')
4865 showchar = not opts.get('no_status')
4920
4866
4921 for state, char, files in changestates:
4867 for state, char, files in changestates:
4922 if state in show:
4868 if state in show:
4923 label = 'status.' + state
4869 label = 'status.' + state
4924 for f in files:
4870 for f in files:
4925 fm.startitem()
4871 fm.startitem()
4926 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4872 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4927 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4873 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4928 if f in copy:
4874 if f in copy:
4929 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4875 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4930 label='status.copied')
4876 label='status.copied')
4931 fm.end()
4877 fm.end()
4932
4878
4933 @command('^summary|sum',
4879 @command('^summary|sum',
4934 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4880 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4935 def summary(ui, repo, **opts):
4881 def summary(ui, repo, **opts):
4936 """summarize working directory state
4882 """summarize working directory state
4937
4883
4938 This generates a brief summary of the working directory state,
4884 This generates a brief summary of the working directory state,
4939 including parents, branch, commit status, phase and available updates.
4885 including parents, branch, commit status, phase and available updates.
4940
4886
4941 With the --remote option, this will check the default paths for
4887 With the --remote option, this will check the default paths for
4942 incoming and outgoing changes. This can be time-consuming.
4888 incoming and outgoing changes. This can be time-consuming.
4943
4889
4944 Returns 0 on success.
4890 Returns 0 on success.
4945 """
4891 """
4946
4892
4947 ctx = repo[None]
4893 ctx = repo[None]
4948 parents = ctx.parents()
4894 parents = ctx.parents()
4949 pnode = parents[0].node()
4895 pnode = parents[0].node()
4950 marks = []
4896 marks = []
4951
4897
4952 ms = None
4898 ms = None
4953 try:
4899 try:
4954 ms = mergemod.mergestate.read(repo)
4900 ms = mergemod.mergestate.read(repo)
4955 except error.UnsupportedMergeRecords as e:
4901 except error.UnsupportedMergeRecords as e:
4956 s = ' '.join(e.recordtypes)
4902 s = ' '.join(e.recordtypes)
4957 ui.warn(
4903 ui.warn(
4958 _('warning: merge state has unsupported record types: %s\n') % s)
4904 _('warning: merge state has unsupported record types: %s\n') % s)
4959 unresolved = 0
4905 unresolved = 0
4960 else:
4906 else:
4961 unresolved = [f for f in ms if ms[f] == 'u']
4907 unresolved = [f for f in ms if ms[f] == 'u']
4962
4908
4963 for p in parents:
4909 for p in parents:
4964 # label with log.changeset (instead of log.parent) since this
4910 # label with log.changeset (instead of log.parent) since this
4965 # shows a working directory parent *changeset*:
4911 # shows a working directory parent *changeset*:
4966 # i18n: column positioning for "hg summary"
4912 # i18n: column positioning for "hg summary"
4967 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4913 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4968 label=cmdutil._changesetlabels(p))
4914 label=cmdutil._changesetlabels(p))
4969 ui.write(' '.join(p.tags()), label='log.tag')
4915 ui.write(' '.join(p.tags()), label='log.tag')
4970 if p.bookmarks():
4916 if p.bookmarks():
4971 marks.extend(p.bookmarks())
4917 marks.extend(p.bookmarks())
4972 if p.rev() == -1:
4918 if p.rev() == -1:
4973 if not len(repo):
4919 if not len(repo):
4974 ui.write(_(' (empty repository)'))
4920 ui.write(_(' (empty repository)'))
4975 else:
4921 else:
4976 ui.write(_(' (no revision checked out)'))
4922 ui.write(_(' (no revision checked out)'))
4977 if p.troubled():
4923 if p.troubled():
4978 ui.write(' ('
4924 ui.write(' ('
4979 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4925 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4980 for trouble in p.troubles())
4926 for trouble in p.troubles())
4981 + ')')
4927 + ')')
4982 ui.write('\n')
4928 ui.write('\n')
4983 if p.description():
4929 if p.description():
4984 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4930 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4985 label='log.summary')
4931 label='log.summary')
4986
4932
4987 branch = ctx.branch()
4933 branch = ctx.branch()
4988 bheads = repo.branchheads(branch)
4934 bheads = repo.branchheads(branch)
4989 # i18n: column positioning for "hg summary"
4935 # i18n: column positioning for "hg summary"
4990 m = _('branch: %s\n') % branch
4936 m = _('branch: %s\n') % branch
4991 if branch != 'default':
4937 if branch != 'default':
4992 ui.write(m, label='log.branch')
4938 ui.write(m, label='log.branch')
4993 else:
4939 else:
4994 ui.status(m, label='log.branch')
4940 ui.status(m, label='log.branch')
4995
4941
4996 if marks:
4942 if marks:
4997 active = repo._activebookmark
4943 active = repo._activebookmark
4998 # i18n: column positioning for "hg summary"
4944 # i18n: column positioning for "hg summary"
4999 ui.write(_('bookmarks:'), label='log.bookmark')
4945 ui.write(_('bookmarks:'), label='log.bookmark')
5000 if active is not None:
4946 if active is not None:
5001 if active in marks:
4947 if active in marks:
5002 ui.write(' *' + active, label=activebookmarklabel)
4948 ui.write(' *' + active, label=activebookmarklabel)
5003 marks.remove(active)
4949 marks.remove(active)
5004 else:
4950 else:
5005 ui.write(' [%s]' % active, label=activebookmarklabel)
4951 ui.write(' [%s]' % active, label=activebookmarklabel)
5006 for m in marks:
4952 for m in marks:
5007 ui.write(' ' + m, label='log.bookmark')
4953 ui.write(' ' + m, label='log.bookmark')
5008 ui.write('\n', label='log.bookmark')
4954 ui.write('\n', label='log.bookmark')
5009
4955
5010 status = repo.status(unknown=True)
4956 status = repo.status(unknown=True)
5011
4957
5012 c = repo.dirstate.copies()
4958 c = repo.dirstate.copies()
5013 copied, renamed = [], []
4959 copied, renamed = [], []
5014 for d, s in c.iteritems():
4960 for d, s in c.iteritems():
5015 if s in status.removed:
4961 if s in status.removed:
5016 status.removed.remove(s)
4962 status.removed.remove(s)
5017 renamed.append(d)
4963 renamed.append(d)
5018 else:
4964 else:
5019 copied.append(d)
4965 copied.append(d)
5020 if d in status.added:
4966 if d in status.added:
5021 status.added.remove(d)
4967 status.added.remove(d)
5022
4968
5023 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4969 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5024
4970
5025 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4971 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5026 (ui.label(_('%d added'), 'status.added'), status.added),
4972 (ui.label(_('%d added'), 'status.added'), status.added),
5027 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4973 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5028 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4974 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5029 (ui.label(_('%d copied'), 'status.copied'), copied),
4975 (ui.label(_('%d copied'), 'status.copied'), copied),
5030 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4976 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5031 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4977 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5032 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4978 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5033 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4979 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5034 t = []
4980 t = []
5035 for l, s in labels:
4981 for l, s in labels:
5036 if s:
4982 if s:
5037 t.append(l % len(s))
4983 t.append(l % len(s))
5038
4984
5039 t = ', '.join(t)
4985 t = ', '.join(t)
5040 cleanworkdir = False
4986 cleanworkdir = False
5041
4987
5042 if repo.vfs.exists('graftstate'):
4988 if repo.vfs.exists('graftstate'):
5043 t += _(' (graft in progress)')
4989 t += _(' (graft in progress)')
5044 if repo.vfs.exists('updatestate'):
4990 if repo.vfs.exists('updatestate'):
5045 t += _(' (interrupted update)')
4991 t += _(' (interrupted update)')
5046 elif len(parents) > 1:
4992 elif len(parents) > 1:
5047 t += _(' (merge)')
4993 t += _(' (merge)')
5048 elif branch != parents[0].branch():
4994 elif branch != parents[0].branch():
5049 t += _(' (new branch)')
4995 t += _(' (new branch)')
5050 elif (parents[0].closesbranch() and
4996 elif (parents[0].closesbranch() and
5051 pnode in repo.branchheads(branch, closed=True)):
4997 pnode in repo.branchheads(branch, closed=True)):
5052 t += _(' (head closed)')
4998 t += _(' (head closed)')
5053 elif not (status.modified or status.added or status.removed or renamed or
4999 elif not (status.modified or status.added or status.removed or renamed or
5054 copied or subs):
5000 copied or subs):
5055 t += _(' (clean)')
5001 t += _(' (clean)')
5056 cleanworkdir = True
5002 cleanworkdir = True
5057 elif pnode not in bheads:
5003 elif pnode not in bheads:
5058 t += _(' (new branch head)')
5004 t += _(' (new branch head)')
5059
5005
5060 if parents:
5006 if parents:
5061 pendingphase = max(p.phase() for p in parents)
5007 pendingphase = max(p.phase() for p in parents)
5062 else:
5008 else:
5063 pendingphase = phases.public
5009 pendingphase = phases.public
5064
5010
5065 if pendingphase > phases.newcommitphase(ui):
5011 if pendingphase > phases.newcommitphase(ui):
5066 t += ' (%s)' % phases.phasenames[pendingphase]
5012 t += ' (%s)' % phases.phasenames[pendingphase]
5067
5013
5068 if cleanworkdir:
5014 if cleanworkdir:
5069 # i18n: column positioning for "hg summary"
5015 # i18n: column positioning for "hg summary"
5070 ui.status(_('commit: %s\n') % t.strip())
5016 ui.status(_('commit: %s\n') % t.strip())
5071 else:
5017 else:
5072 # i18n: column positioning for "hg summary"
5018 # i18n: column positioning for "hg summary"
5073 ui.write(_('commit: %s\n') % t.strip())
5019 ui.write(_('commit: %s\n') % t.strip())
5074
5020
5075 # all ancestors of branch heads - all ancestors of parent = new csets
5021 # all ancestors of branch heads - all ancestors of parent = new csets
5076 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5022 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5077 bheads))
5023 bheads))
5078
5024
5079 if new == 0:
5025 if new == 0:
5080 # i18n: column positioning for "hg summary"
5026 # i18n: column positioning for "hg summary"
5081 ui.status(_('update: (current)\n'))
5027 ui.status(_('update: (current)\n'))
5082 elif pnode not in bheads:
5028 elif pnode not in bheads:
5083 # i18n: column positioning for "hg summary"
5029 # i18n: column positioning for "hg summary"
5084 ui.write(_('update: %d new changesets (update)\n') % new)
5030 ui.write(_('update: %d new changesets (update)\n') % new)
5085 else:
5031 else:
5086 # i18n: column positioning for "hg summary"
5032 # i18n: column positioning for "hg summary"
5087 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5033 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5088 (new, len(bheads)))
5034 (new, len(bheads)))
5089
5035
5090 t = []
5036 t = []
5091 draft = len(repo.revs('draft()'))
5037 draft = len(repo.revs('draft()'))
5092 if draft:
5038 if draft:
5093 t.append(_('%d draft') % draft)
5039 t.append(_('%d draft') % draft)
5094 secret = len(repo.revs('secret()'))
5040 secret = len(repo.revs('secret()'))
5095 if secret:
5041 if secret:
5096 t.append(_('%d secret') % secret)
5042 t.append(_('%d secret') % secret)
5097
5043
5098 if draft or secret:
5044 if draft or secret:
5099 ui.status(_('phases: %s\n') % ', '.join(t))
5045 ui.status(_('phases: %s\n') % ', '.join(t))
5100
5046
5101 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5047 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5102 for trouble in ("unstable", "divergent", "bumped"):
5048 for trouble in ("unstable", "divergent", "bumped"):
5103 numtrouble = len(repo.revs(trouble + "()"))
5049 numtrouble = len(repo.revs(trouble + "()"))
5104 # We write all the possibilities to ease translation
5050 # We write all the possibilities to ease translation
5105 troublemsg = {
5051 troublemsg = {
5106 "unstable": _("unstable: %d changesets"),
5052 "unstable": _("unstable: %d changesets"),
5107 "divergent": _("divergent: %d changesets"),
5053 "divergent": _("divergent: %d changesets"),
5108 "bumped": _("bumped: %d changesets"),
5054 "bumped": _("bumped: %d changesets"),
5109 }
5055 }
5110 if numtrouble > 0:
5056 if numtrouble > 0:
5111 ui.status(troublemsg[trouble] % numtrouble + "\n")
5057 ui.status(troublemsg[trouble] % numtrouble + "\n")
5112
5058
5113 cmdutil.summaryhooks(ui, repo)
5059 cmdutil.summaryhooks(ui, repo)
5114
5060
5115 if opts.get('remote'):
5061 if opts.get('remote'):
5116 needsincoming, needsoutgoing = True, True
5062 needsincoming, needsoutgoing = True, True
5117 else:
5063 else:
5118 needsincoming, needsoutgoing = False, False
5064 needsincoming, needsoutgoing = False, False
5119 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5065 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5120 if i:
5066 if i:
5121 needsincoming = True
5067 needsincoming = True
5122 if o:
5068 if o:
5123 needsoutgoing = True
5069 needsoutgoing = True
5124 if not needsincoming and not needsoutgoing:
5070 if not needsincoming and not needsoutgoing:
5125 return
5071 return
5126
5072
5127 def getincoming():
5073 def getincoming():
5128 source, branches = hg.parseurl(ui.expandpath('default'))
5074 source, branches = hg.parseurl(ui.expandpath('default'))
5129 sbranch = branches[0]
5075 sbranch = branches[0]
5130 try:
5076 try:
5131 other = hg.peer(repo, {}, source)
5077 other = hg.peer(repo, {}, source)
5132 except error.RepoError:
5078 except error.RepoError:
5133 if opts.get('remote'):
5079 if opts.get('remote'):
5134 raise
5080 raise
5135 return source, sbranch, None, None, None
5081 return source, sbranch, None, None, None
5136 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5082 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5137 if revs:
5083 if revs:
5138 revs = [other.lookup(rev) for rev in revs]
5084 revs = [other.lookup(rev) for rev in revs]
5139 ui.debug('comparing with %s\n' % util.hidepassword(source))
5085 ui.debug('comparing with %s\n' % util.hidepassword(source))
5140 repo.ui.pushbuffer()
5086 repo.ui.pushbuffer()
5141 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5087 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5142 repo.ui.popbuffer()
5088 repo.ui.popbuffer()
5143 return source, sbranch, other, commoninc, commoninc[1]
5089 return source, sbranch, other, commoninc, commoninc[1]
5144
5090
5145 if needsincoming:
5091 if needsincoming:
5146 source, sbranch, sother, commoninc, incoming = getincoming()
5092 source, sbranch, sother, commoninc, incoming = getincoming()
5147 else:
5093 else:
5148 source = sbranch = sother = commoninc = incoming = None
5094 source = sbranch = sother = commoninc = incoming = None
5149
5095
5150 def getoutgoing():
5096 def getoutgoing():
5151 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5097 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5152 dbranch = branches[0]
5098 dbranch = branches[0]
5153 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5099 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5154 if source != dest:
5100 if source != dest:
5155 try:
5101 try:
5156 dother = hg.peer(repo, {}, dest)
5102 dother = hg.peer(repo, {}, dest)
5157 except error.RepoError:
5103 except error.RepoError:
5158 if opts.get('remote'):
5104 if opts.get('remote'):
5159 raise
5105 raise
5160 return dest, dbranch, None, None
5106 return dest, dbranch, None, None
5161 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5107 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5162 elif sother is None:
5108 elif sother is None:
5163 # there is no explicit destination peer, but source one is invalid
5109 # there is no explicit destination peer, but source one is invalid
5164 return dest, dbranch, None, None
5110 return dest, dbranch, None, None
5165 else:
5111 else:
5166 dother = sother
5112 dother = sother
5167 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5113 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5168 common = None
5114 common = None
5169 else:
5115 else:
5170 common = commoninc
5116 common = commoninc
5171 if revs:
5117 if revs:
5172 revs = [repo.lookup(rev) for rev in revs]
5118 revs = [repo.lookup(rev) for rev in revs]
5173 repo.ui.pushbuffer()
5119 repo.ui.pushbuffer()
5174 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5120 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5175 commoninc=common)
5121 commoninc=common)
5176 repo.ui.popbuffer()
5122 repo.ui.popbuffer()
5177 return dest, dbranch, dother, outgoing
5123 return dest, dbranch, dother, outgoing
5178
5124
5179 if needsoutgoing:
5125 if needsoutgoing:
5180 dest, dbranch, dother, outgoing = getoutgoing()
5126 dest, dbranch, dother, outgoing = getoutgoing()
5181 else:
5127 else:
5182 dest = dbranch = dother = outgoing = None
5128 dest = dbranch = dother = outgoing = None
5183
5129
5184 if opts.get('remote'):
5130 if opts.get('remote'):
5185 t = []
5131 t = []
5186 if incoming:
5132 if incoming:
5187 t.append(_('1 or more incoming'))
5133 t.append(_('1 or more incoming'))
5188 o = outgoing.missing
5134 o = outgoing.missing
5189 if o:
5135 if o:
5190 t.append(_('%d outgoing') % len(o))
5136 t.append(_('%d outgoing') % len(o))
5191 other = dother or sother
5137 other = dother or sother
5192 if 'bookmarks' in other.listkeys('namespaces'):
5138 if 'bookmarks' in other.listkeys('namespaces'):
5193 counts = bookmarks.summary(repo, other)
5139 counts = bookmarks.summary(repo, other)
5194 if counts[0] > 0:
5140 if counts[0] > 0:
5195 t.append(_('%d incoming bookmarks') % counts[0])
5141 t.append(_('%d incoming bookmarks') % counts[0])
5196 if counts[1] > 0:
5142 if counts[1] > 0:
5197 t.append(_('%d outgoing bookmarks') % counts[1])
5143 t.append(_('%d outgoing bookmarks') % counts[1])
5198
5144
5199 if t:
5145 if t:
5200 # i18n: column positioning for "hg summary"
5146 # i18n: column positioning for "hg summary"
5201 ui.write(_('remote: %s\n') % (', '.join(t)))
5147 ui.write(_('remote: %s\n') % (', '.join(t)))
5202 else:
5148 else:
5203 # i18n: column positioning for "hg summary"
5149 # i18n: column positioning for "hg summary"
5204 ui.status(_('remote: (synced)\n'))
5150 ui.status(_('remote: (synced)\n'))
5205
5151
5206 cmdutil.summaryremotehooks(ui, repo, opts,
5152 cmdutil.summaryremotehooks(ui, repo, opts,
5207 ((source, sbranch, sother, commoninc),
5153 ((source, sbranch, sother, commoninc),
5208 (dest, dbranch, dother, outgoing)))
5154 (dest, dbranch, dother, outgoing)))
5209
5155
5210 @command('tag',
5156 @command('tag',
5211 [('f', 'force', None, _('force tag')),
5157 [('f', 'force', None, _('force tag')),
5212 ('l', 'local', None, _('make the tag local')),
5158 ('l', 'local', None, _('make the tag local')),
5213 ('r', 'rev', '', _('revision to tag'), _('REV')),
5159 ('r', 'rev', '', _('revision to tag'), _('REV')),
5214 ('', 'remove', None, _('remove a tag')),
5160 ('', 'remove', None, _('remove a tag')),
5215 # -l/--local is already there, commitopts cannot be used
5161 # -l/--local is already there, commitopts cannot be used
5216 ('e', 'edit', None, _('invoke editor on commit messages')),
5162 ('e', 'edit', None, _('invoke editor on commit messages')),
5217 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5163 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5218 ] + commitopts2,
5164 ] + commitopts2,
5219 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5165 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5220 def tag(ui, repo, name1, *names, **opts):
5166 def tag(ui, repo, name1, *names, **opts):
5221 """add one or more tags for the current or given revision
5167 """add one or more tags for the current or given revision
5222
5168
5223 Name a particular revision using <name>.
5169 Name a particular revision using <name>.
5224
5170
5225 Tags are used to name particular revisions of the repository and are
5171 Tags are used to name particular revisions of the repository and are
5226 very useful to compare different revisions, to go back to significant
5172 very useful to compare different revisions, to go back to significant
5227 earlier versions or to mark branch points as releases, etc. Changing
5173 earlier versions or to mark branch points as releases, etc. Changing
5228 an existing tag is normally disallowed; use -f/--force to override.
5174 an existing tag is normally disallowed; use -f/--force to override.
5229
5175
5230 If no revision is given, the parent of the working directory is
5176 If no revision is given, the parent of the working directory is
5231 used.
5177 used.
5232
5178
5233 To facilitate version control, distribution, and merging of tags,
5179 To facilitate version control, distribution, and merging of tags,
5234 they are stored as a file named ".hgtags" which is managed similarly
5180 they are stored as a file named ".hgtags" which is managed similarly
5235 to other project files and can be hand-edited if necessary. This
5181 to other project files and can be hand-edited if necessary. This
5236 also means that tagging creates a new commit. The file
5182 also means that tagging creates a new commit. The file
5237 ".hg/localtags" is used for local tags (not shared among
5183 ".hg/localtags" is used for local tags (not shared among
5238 repositories).
5184 repositories).
5239
5185
5240 Tag commits are usually made at the head of a branch. If the parent
5186 Tag commits are usually made at the head of a branch. If the parent
5241 of the working directory is not a branch head, :hg:`tag` aborts; use
5187 of the working directory is not a branch head, :hg:`tag` aborts; use
5242 -f/--force to force the tag commit to be based on a non-head
5188 -f/--force to force the tag commit to be based on a non-head
5243 changeset.
5189 changeset.
5244
5190
5245 See :hg:`help dates` for a list of formats valid for -d/--date.
5191 See :hg:`help dates` for a list of formats valid for -d/--date.
5246
5192
5247 Since tag names have priority over branch names during revision
5193 Since tag names have priority over branch names during revision
5248 lookup, using an existing branch name as a tag name is discouraged.
5194 lookup, using an existing branch name as a tag name is discouraged.
5249
5195
5250 Returns 0 on success.
5196 Returns 0 on success.
5251 """
5197 """
5252 wlock = lock = None
5198 wlock = lock = None
5253 try:
5199 try:
5254 wlock = repo.wlock()
5200 wlock = repo.wlock()
5255 lock = repo.lock()
5201 lock = repo.lock()
5256 rev_ = "."
5202 rev_ = "."
5257 names = [t.strip() for t in (name1,) + names]
5203 names = [t.strip() for t in (name1,) + names]
5258 if len(names) != len(set(names)):
5204 if len(names) != len(set(names)):
5259 raise error.Abort(_('tag names must be unique'))
5205 raise error.Abort(_('tag names must be unique'))
5260 for n in names:
5206 for n in names:
5261 scmutil.checknewlabel(repo, n, 'tag')
5207 scmutil.checknewlabel(repo, n, 'tag')
5262 if not n:
5208 if not n:
5263 raise error.Abort(_('tag names cannot consist entirely of '
5209 raise error.Abort(_('tag names cannot consist entirely of '
5264 'whitespace'))
5210 'whitespace'))
5265 if opts.get('rev') and opts.get('remove'):
5211 if opts.get('rev') and opts.get('remove'):
5266 raise error.Abort(_("--rev and --remove are incompatible"))
5212 raise error.Abort(_("--rev and --remove are incompatible"))
5267 if opts.get('rev'):
5213 if opts.get('rev'):
5268 rev_ = opts['rev']
5214 rev_ = opts['rev']
5269 message = opts.get('message')
5215 message = opts.get('message')
5270 if opts.get('remove'):
5216 if opts.get('remove'):
5271 if opts.get('local'):
5217 if opts.get('local'):
5272 expectedtype = 'local'
5218 expectedtype = 'local'
5273 else:
5219 else:
5274 expectedtype = 'global'
5220 expectedtype = 'global'
5275
5221
5276 for n in names:
5222 for n in names:
5277 if not repo.tagtype(n):
5223 if not repo.tagtype(n):
5278 raise error.Abort(_("tag '%s' does not exist") % n)
5224 raise error.Abort(_("tag '%s' does not exist") % n)
5279 if repo.tagtype(n) != expectedtype:
5225 if repo.tagtype(n) != expectedtype:
5280 if expectedtype == 'global':
5226 if expectedtype == 'global':
5281 raise error.Abort(_("tag '%s' is not a global tag") % n)
5227 raise error.Abort(_("tag '%s' is not a global tag") % n)
5282 else:
5228 else:
5283 raise error.Abort(_("tag '%s' is not a local tag") % n)
5229 raise error.Abort(_("tag '%s' is not a local tag") % n)
5284 rev_ = 'null'
5230 rev_ = 'null'
5285 if not message:
5231 if not message:
5286 # we don't translate commit messages
5232 # we don't translate commit messages
5287 message = 'Removed tag %s' % ', '.join(names)
5233 message = 'Removed tag %s' % ', '.join(names)
5288 elif not opts.get('force'):
5234 elif not opts.get('force'):
5289 for n in names:
5235 for n in names:
5290 if n in repo.tags():
5236 if n in repo.tags():
5291 raise error.Abort(_("tag '%s' already exists "
5237 raise error.Abort(_("tag '%s' already exists "
5292 "(use -f to force)") % n)
5238 "(use -f to force)") % n)
5293 if not opts.get('local'):
5239 if not opts.get('local'):
5294 p1, p2 = repo.dirstate.parents()
5240 p1, p2 = repo.dirstate.parents()
5295 if p2 != nullid:
5241 if p2 != nullid:
5296 raise error.Abort(_('uncommitted merge'))
5242 raise error.Abort(_('uncommitted merge'))
5297 bheads = repo.branchheads()
5243 bheads = repo.branchheads()
5298 if not opts.get('force') and bheads and p1 not in bheads:
5244 if not opts.get('force') and bheads and p1 not in bheads:
5299 raise error.Abort(_('working directory is not at a branch head '
5245 raise error.Abort(_('working directory is not at a branch head '
5300 '(use -f to force)'))
5246 '(use -f to force)'))
5301 r = scmutil.revsingle(repo, rev_).node()
5247 r = scmutil.revsingle(repo, rev_).node()
5302
5248
5303 if not message:
5249 if not message:
5304 # we don't translate commit messages
5250 # we don't translate commit messages
5305 message = ('Added tag %s for changeset %s' %
5251 message = ('Added tag %s for changeset %s' %
5306 (', '.join(names), short(r)))
5252 (', '.join(names), short(r)))
5307
5253
5308 date = opts.get('date')
5254 date = opts.get('date')
5309 if date:
5255 if date:
5310 date = util.parsedate(date)
5256 date = util.parsedate(date)
5311
5257
5312 if opts.get('remove'):
5258 if opts.get('remove'):
5313 editform = 'tag.remove'
5259 editform = 'tag.remove'
5314 else:
5260 else:
5315 editform = 'tag.add'
5261 editform = 'tag.add'
5316 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5262 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5317
5263
5318 # don't allow tagging the null rev
5264 # don't allow tagging the null rev
5319 if (not opts.get('remove') and
5265 if (not opts.get('remove') and
5320 scmutil.revsingle(repo, rev_).rev() == nullrev):
5266 scmutil.revsingle(repo, rev_).rev() == nullrev):
5321 raise error.Abort(_("cannot tag null revision"))
5267 raise error.Abort(_("cannot tag null revision"))
5322
5268
5323 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5269 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5324 editor=editor)
5270 editor=editor)
5325 finally:
5271 finally:
5326 release(lock, wlock)
5272 release(lock, wlock)
5327
5273
5328 @command('tags', formatteropts, '')
5274 @command('tags', formatteropts, '')
5329 def tags(ui, repo, **opts):
5275 def tags(ui, repo, **opts):
5330 """list repository tags
5276 """list repository tags
5331
5277
5332 This lists both regular and local tags. When the -v/--verbose
5278 This lists both regular and local tags. When the -v/--verbose
5333 switch is used, a third column "local" is printed for local tags.
5279 switch is used, a third column "local" is printed for local tags.
5334 When the -q/--quiet switch is used, only the tag name is printed.
5280 When the -q/--quiet switch is used, only the tag name is printed.
5335
5281
5336 Returns 0 on success.
5282 Returns 0 on success.
5337 """
5283 """
5338
5284
5339 fm = ui.formatter('tags', opts)
5285 fm = ui.formatter('tags', opts)
5340 hexfunc = fm.hexfunc
5286 hexfunc = fm.hexfunc
5341 tagtype = ""
5287 tagtype = ""
5342
5288
5343 for t, n in reversed(repo.tagslist()):
5289 for t, n in reversed(repo.tagslist()):
5344 hn = hexfunc(n)
5290 hn = hexfunc(n)
5345 label = 'tags.normal'
5291 label = 'tags.normal'
5346 tagtype = ''
5292 tagtype = ''
5347 if repo.tagtype(t) == 'local':
5293 if repo.tagtype(t) == 'local':
5348 label = 'tags.local'
5294 label = 'tags.local'
5349 tagtype = 'local'
5295 tagtype = 'local'
5350
5296
5351 fm.startitem()
5297 fm.startitem()
5352 fm.write('tag', '%s', t, label=label)
5298 fm.write('tag', '%s', t, label=label)
5353 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5299 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5354 fm.condwrite(not ui.quiet, 'rev node', fmt,
5300 fm.condwrite(not ui.quiet, 'rev node', fmt,
5355 repo.changelog.rev(n), hn, label=label)
5301 repo.changelog.rev(n), hn, label=label)
5356 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5302 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5357 tagtype, label=label)
5303 tagtype, label=label)
5358 fm.plain('\n')
5304 fm.plain('\n')
5359 fm.end()
5305 fm.end()
5360
5306
5361 @command('tip',
5307 @command('tip',
5362 [('p', 'patch', None, _('show patch')),
5308 [('p', 'patch', None, _('show patch')),
5363 ('g', 'git', None, _('use git extended diff format')),
5309 ('g', 'git', None, _('use git extended diff format')),
5364 ] + templateopts,
5310 ] + templateopts,
5365 _('[-p] [-g]'))
5311 _('[-p] [-g]'))
5366 def tip(ui, repo, **opts):
5312 def tip(ui, repo, **opts):
5367 """show the tip revision (DEPRECATED)
5313 """show the tip revision (DEPRECATED)
5368
5314
5369 The tip revision (usually just called the tip) is the changeset
5315 The tip revision (usually just called the tip) is the changeset
5370 most recently added to the repository (and therefore the most
5316 most recently added to the repository (and therefore the most
5371 recently changed head).
5317 recently changed head).
5372
5318
5373 If you have just made a commit, that commit will be the tip. If
5319 If you have just made a commit, that commit will be the tip. If
5374 you have just pulled changes from another repository, the tip of
5320 you have just pulled changes from another repository, the tip of
5375 that repository becomes the current tip. The "tip" tag is special
5321 that repository becomes the current tip. The "tip" tag is special
5376 and cannot be renamed or assigned to a different changeset.
5322 and cannot be renamed or assigned to a different changeset.
5377
5323
5378 This command is deprecated, please use :hg:`heads` instead.
5324 This command is deprecated, please use :hg:`heads` instead.
5379
5325
5380 Returns 0 on success.
5326 Returns 0 on success.
5381 """
5327 """
5382 displayer = cmdutil.show_changeset(ui, repo, opts)
5328 displayer = cmdutil.show_changeset(ui, repo, opts)
5383 displayer.show(repo['tip'])
5329 displayer.show(repo['tip'])
5384 displayer.close()
5330 displayer.close()
5385
5331
5386 @command('unbundle',
5332 @command('unbundle',
5387 [('u', 'update', None,
5333 [('u', 'update', None,
5388 _('update to new branch head if changesets were unbundled'))],
5334 _('update to new branch head if changesets were unbundled'))],
5389 _('[-u] FILE...'))
5335 _('[-u] FILE...'))
5390 def unbundle(ui, repo, fname1, *fnames, **opts):
5336 def unbundle(ui, repo, fname1, *fnames, **opts):
5391 """apply one or more changegroup files
5337 """apply one or more changegroup files
5392
5338
5393 Apply one or more compressed changegroup files generated by the
5339 Apply one or more compressed changegroup files generated by the
5394 bundle command.
5340 bundle command.
5395
5341
5396 Returns 0 on success, 1 if an update has unresolved files.
5342 Returns 0 on success, 1 if an update has unresolved files.
5397 """
5343 """
5398 fnames = (fname1,) + fnames
5344 fnames = (fname1,) + fnames
5399
5345
5400 with repo.lock():
5346 with repo.lock():
5401 for fname in fnames:
5347 for fname in fnames:
5402 f = hg.openpath(ui, fname)
5348 f = hg.openpath(ui, fname)
5403 gen = exchange.readbundle(ui, f, fname)
5349 gen = exchange.readbundle(ui, f, fname)
5404 if isinstance(gen, bundle2.unbundle20):
5350 if isinstance(gen, bundle2.unbundle20):
5405 tr = repo.transaction('unbundle')
5351 tr = repo.transaction('unbundle')
5406 try:
5352 try:
5407 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5353 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5408 url='bundle:' + fname)
5354 url='bundle:' + fname)
5409 tr.close()
5355 tr.close()
5410 except error.BundleUnknownFeatureError as exc:
5356 except error.BundleUnknownFeatureError as exc:
5411 raise error.Abort(_('%s: unknown bundle feature, %s')
5357 raise error.Abort(_('%s: unknown bundle feature, %s')
5412 % (fname, exc),
5358 % (fname, exc),
5413 hint=_("see https://mercurial-scm.org/"
5359 hint=_("see https://mercurial-scm.org/"
5414 "wiki/BundleFeature for more "
5360 "wiki/BundleFeature for more "
5415 "information"))
5361 "information"))
5416 finally:
5362 finally:
5417 if tr:
5363 if tr:
5418 tr.release()
5364 tr.release()
5419 changes = [r.get('return', 0)
5365 changes = [r.get('return', 0)
5420 for r in op.records['changegroup']]
5366 for r in op.records['changegroup']]
5421 modheads = changegroup.combineresults(changes)
5367 modheads = changegroup.combineresults(changes)
5422 elif isinstance(gen, streamclone.streamcloneapplier):
5368 elif isinstance(gen, streamclone.streamcloneapplier):
5423 raise error.Abort(
5369 raise error.Abort(
5424 _('packed bundles cannot be applied with '
5370 _('packed bundles cannot be applied with '
5425 '"hg unbundle"'),
5371 '"hg unbundle"'),
5426 hint=_('use "hg debugapplystreamclonebundle"'))
5372 hint=_('use "hg debugapplystreamclonebundle"'))
5427 else:
5373 else:
5428 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5374 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5429
5375
5430 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5376 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5431
5377
5432 @command('^update|up|checkout|co',
5378 @command('^update|up|checkout|co',
5433 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5379 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5434 ('c', 'check', None, _('require clean working directory')),
5380 ('c', 'check', None, _('require clean working directory')),
5435 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5381 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5436 ('r', 'rev', '', _('revision'), _('REV'))
5382 ('r', 'rev', '', _('revision'), _('REV'))
5437 ] + mergetoolopts,
5383 ] + mergetoolopts,
5438 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5384 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5439 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5385 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5440 tool=None):
5386 tool=None):
5441 """update working directory (or switch revisions)
5387 """update working directory (or switch revisions)
5442
5388
5443 Update the repository's working directory to the specified
5389 Update the repository's working directory to the specified
5444 changeset. If no changeset is specified, update to the tip of the
5390 changeset. If no changeset is specified, update to the tip of the
5445 current named branch and move the active bookmark (see :hg:`help
5391 current named branch and move the active bookmark (see :hg:`help
5446 bookmarks`).
5392 bookmarks`).
5447
5393
5448 Update sets the working directory's parent revision to the specified
5394 Update sets the working directory's parent revision to the specified
5449 changeset (see :hg:`help parents`).
5395 changeset (see :hg:`help parents`).
5450
5396
5451 If the changeset is not a descendant or ancestor of the working
5397 If the changeset is not a descendant or ancestor of the working
5452 directory's parent and there are uncommitted changes, the update is
5398 directory's parent and there are uncommitted changes, the update is
5453 aborted. With the -c/--check option, the working directory is checked
5399 aborted. With the -c/--check option, the working directory is checked
5454 for uncommitted changes; if none are found, the working directory is
5400 for uncommitted changes; if none are found, the working directory is
5455 updated to the specified changeset.
5401 updated to the specified changeset.
5456
5402
5457 .. container:: verbose
5403 .. container:: verbose
5458
5404
5459 The following rules apply when the working directory contains
5405 The following rules apply when the working directory contains
5460 uncommitted changes:
5406 uncommitted changes:
5461
5407
5462 1. If neither -c/--check nor -C/--clean is specified, and if
5408 1. If neither -c/--check nor -C/--clean is specified, and if
5463 the requested changeset is an ancestor or descendant of
5409 the requested changeset is an ancestor or descendant of
5464 the working directory's parent, the uncommitted changes
5410 the working directory's parent, the uncommitted changes
5465 are merged into the requested changeset and the merged
5411 are merged into the requested changeset and the merged
5466 result is left uncommitted. If the requested changeset is
5412 result is left uncommitted. If the requested changeset is
5467 not an ancestor or descendant (that is, it is on another
5413 not an ancestor or descendant (that is, it is on another
5468 branch), the update is aborted and the uncommitted changes
5414 branch), the update is aborted and the uncommitted changes
5469 are preserved.
5415 are preserved.
5470
5416
5471 2. With the -c/--check option, the update is aborted and the
5417 2. With the -c/--check option, the update is aborted and the
5472 uncommitted changes are preserved.
5418 uncommitted changes are preserved.
5473
5419
5474 3. With the -C/--clean option, uncommitted changes are discarded and
5420 3. With the -C/--clean option, uncommitted changes are discarded and
5475 the working directory is updated to the requested changeset.
5421 the working directory is updated to the requested changeset.
5476
5422
5477 To cancel an uncommitted merge (and lose your changes), use
5423 To cancel an uncommitted merge (and lose your changes), use
5478 :hg:`update --clean .`.
5424 :hg:`update --clean .`.
5479
5425
5480 Use null as the changeset to remove the working directory (like
5426 Use null as the changeset to remove the working directory (like
5481 :hg:`clone -U`).
5427 :hg:`clone -U`).
5482
5428
5483 If you want to revert just one file to an older revision, use
5429 If you want to revert just one file to an older revision, use
5484 :hg:`revert [-r REV] NAME`.
5430 :hg:`revert [-r REV] NAME`.
5485
5431
5486 See :hg:`help dates` for a list of formats valid for -d/--date.
5432 See :hg:`help dates` for a list of formats valid for -d/--date.
5487
5433
5488 Returns 0 on success, 1 if there are unresolved files.
5434 Returns 0 on success, 1 if there are unresolved files.
5489 """
5435 """
5490 if rev and node:
5436 if rev and node:
5491 raise error.Abort(_("please specify just one revision"))
5437 raise error.Abort(_("please specify just one revision"))
5492
5438
5493 if rev is None or rev == '':
5439 if rev is None or rev == '':
5494 rev = node
5440 rev = node
5495
5441
5496 if date and rev is not None:
5442 if date and rev is not None:
5497 raise error.Abort(_("you can't specify a revision and a date"))
5443 raise error.Abort(_("you can't specify a revision and a date"))
5498
5444
5499 if check and clean:
5445 if check and clean:
5500 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5446 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5501
5447
5502 with repo.wlock():
5448 with repo.wlock():
5503 cmdutil.clearunfinished(repo)
5449 cmdutil.clearunfinished(repo)
5504
5450
5505 if date:
5451 if date:
5506 rev = cmdutil.finddate(ui, repo, date)
5452 rev = cmdutil.finddate(ui, repo, date)
5507
5453
5508 # if we defined a bookmark, we have to remember the original name
5454 # if we defined a bookmark, we have to remember the original name
5509 brev = rev
5455 brev = rev
5510 rev = scmutil.revsingle(repo, rev, rev).rev()
5456 rev = scmutil.revsingle(repo, rev, rev).rev()
5511
5457
5512 if check:
5458 if check:
5513 cmdutil.bailifchanged(repo, merge=False)
5459 cmdutil.bailifchanged(repo, merge=False)
5514
5460
5515 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5461 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5516
5462
5517 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5463 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5518
5464
5519 @command('verify', [])
5465 @command('verify', [])
5520 def verify(ui, repo):
5466 def verify(ui, repo):
5521 """verify the integrity of the repository
5467 """verify the integrity of the repository
5522
5468
5523 Verify the integrity of the current repository.
5469 Verify the integrity of the current repository.
5524
5470
5525 This will perform an extensive check of the repository's
5471 This will perform an extensive check of the repository's
5526 integrity, validating the hashes and checksums of each entry in
5472 integrity, validating the hashes and checksums of each entry in
5527 the changelog, manifest, and tracked files, as well as the
5473 the changelog, manifest, and tracked files, as well as the
5528 integrity of their crosslinks and indices.
5474 integrity of their crosslinks and indices.
5529
5475
5530 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5476 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5531 for more information about recovery from corruption of the
5477 for more information about recovery from corruption of the
5532 repository.
5478 repository.
5533
5479
5534 Returns 0 on success, 1 if errors are encountered.
5480 Returns 0 on success, 1 if errors are encountered.
5535 """
5481 """
5536 return hg.verify(repo)
5482 return hg.verify(repo)
5537
5483
5538 @command('version', [] + formatteropts, norepo=True)
5484 @command('version', [] + formatteropts, norepo=True)
5539 def version_(ui, **opts):
5485 def version_(ui, **opts):
5540 """output version and copyright information"""
5486 """output version and copyright information"""
5541 fm = ui.formatter("version", opts)
5487 fm = ui.formatter("version", opts)
5542 fm.startitem()
5488 fm.startitem()
5543 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5489 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5544 util.version())
5490 util.version())
5545 license = _(
5491 license = _(
5546 "(see https://mercurial-scm.org for more information)\n"
5492 "(see https://mercurial-scm.org for more information)\n"
5547 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5493 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5548 "This is free software; see the source for copying conditions. "
5494 "This is free software; see the source for copying conditions. "
5549 "There is NO\nwarranty; "
5495 "There is NO\nwarranty; "
5550 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5496 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5551 )
5497 )
5552 if not ui.quiet:
5498 if not ui.quiet:
5553 fm.plain(license)
5499 fm.plain(license)
5554
5500
5555 if ui.verbose:
5501 if ui.verbose:
5556 fm.plain(_("\nEnabled extensions:\n\n"))
5502 fm.plain(_("\nEnabled extensions:\n\n"))
5557 # format names and versions into columns
5503 # format names and versions into columns
5558 names = []
5504 names = []
5559 vers = []
5505 vers = []
5560 isinternals = []
5506 isinternals = []
5561 for name, module in extensions.extensions():
5507 for name, module in extensions.extensions():
5562 names.append(name)
5508 names.append(name)
5563 vers.append(extensions.moduleversion(module) or None)
5509 vers.append(extensions.moduleversion(module) or None)
5564 isinternals.append(extensions.ismoduleinternal(module))
5510 isinternals.append(extensions.ismoduleinternal(module))
5565 fn = fm.nested("extensions")
5511 fn = fm.nested("extensions")
5566 if names:
5512 if names:
5567 namefmt = " %%-%ds " % max(len(n) for n in names)
5513 namefmt = " %%-%ds " % max(len(n) for n in names)
5568 places = [_("external"), _("internal")]
5514 places = [_("external"), _("internal")]
5569 for n, v, p in zip(names, vers, isinternals):
5515 for n, v, p in zip(names, vers, isinternals):
5570 fn.startitem()
5516 fn.startitem()
5571 fn.condwrite(ui.verbose, "name", namefmt, n)
5517 fn.condwrite(ui.verbose, "name", namefmt, n)
5572 if ui.verbose:
5518 if ui.verbose:
5573 fn.plain("%s " % places[p])
5519 fn.plain("%s " % places[p])
5574 fn.data(bundled=p)
5520 fn.data(bundled=p)
5575 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5521 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5576 if ui.verbose:
5522 if ui.verbose:
5577 fn.plain("\n")
5523 fn.plain("\n")
5578 fn.end()
5524 fn.end()
5579 fm.end()
5525 fm.end()
5580
5526
5581 def loadcmdtable(ui, name, cmdtable):
5527 def loadcmdtable(ui, name, cmdtable):
5582 """Load command functions from specified cmdtable
5528 """Load command functions from specified cmdtable
5583 """
5529 """
5584 overrides = [cmd for cmd in cmdtable if cmd in table]
5530 overrides = [cmd for cmd in cmdtable if cmd in table]
5585 if overrides:
5531 if overrides:
5586 ui.warn(_("extension '%s' overrides commands: %s\n")
5532 ui.warn(_("extension '%s' overrides commands: %s\n")
5587 % (name, " ".join(overrides)))
5533 % (name, " ".join(overrides)))
5588 table.update(cmdtable)
5534 table.update(cmdtable)
@@ -1,1921 +1,1975
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 difflib
10 import difflib
11 import errno
11 import errno
12 import operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import socket
15 import socket
16 import string
16 import string
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import time
19 import time
20
20
21 from .i18n import _
21 from .i18n import _
22 from .node import (
22 from .node import (
23 bin,
23 bin,
24 hex,
24 hex,
25 nullhex,
25 nullhex,
26 nullid,
26 nullid,
27 nullrev,
27 nullrev,
28 short,
28 short,
29 )
29 )
30 from . import (
30 from . import (
31 bundle2,
31 bundle2,
32 changegroup,
32 changegroup,
33 cmdutil,
33 cmdutil,
34 commands,
34 commands,
35 context,
35 context,
36 dagparser,
36 dagparser,
37 dagutil,
37 dagutil,
38 encoding,
38 encoding,
39 error,
39 error,
40 exchange,
40 exchange,
41 extensions,
41 extensions,
42 fileset,
42 fileset,
43 hg,
43 hg,
44 localrepo,
44 localrepo,
45 lock as lockmod,
45 lock as lockmod,
46 merge as mergemod,
46 merge as mergemod,
47 obsolete,
47 obsolete,
48 policy,
48 policy,
49 pvec,
49 pvec,
50 pycompat,
50 pycompat,
51 repair,
51 repair,
52 revlog,
52 revlog,
53 revset,
53 revset,
54 scmutil,
54 scmutil,
55 setdiscovery,
55 setdiscovery,
56 simplemerge,
56 simplemerge,
57 smartset,
57 smartset,
58 sslutil,
58 sslutil,
59 streamclone,
59 streamclone,
60 templater,
60 templater,
61 treediscovery,
61 treediscovery,
62 util,
62 util,
63 )
63 )
64
64
65 release = lockmod.release
65 release = lockmod.release
66
66
67 # We reuse the command table from commands because it is easier than
67 # We reuse the command table from commands because it is easier than
68 # teaching dispatch about multiple tables.
68 # teaching dispatch about multiple tables.
69 command = cmdutil.command(commands.table)
69 command = cmdutil.command(commands.table)
70
70
71 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
71 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
72 def debugancestor(ui, repo, *args):
72 def debugancestor(ui, repo, *args):
73 """find the ancestor revision of two revisions in a given index"""
73 """find the ancestor revision of two revisions in a given index"""
74 if len(args) == 3:
74 if len(args) == 3:
75 index, rev1, rev2 = args
75 index, rev1, rev2 = args
76 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
76 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
77 lookup = r.lookup
77 lookup = r.lookup
78 elif len(args) == 2:
78 elif len(args) == 2:
79 if not repo:
79 if not repo:
80 raise error.Abort(_('there is no Mercurial repository here '
80 raise error.Abort(_('there is no Mercurial repository here '
81 '(.hg not found)'))
81 '(.hg not found)'))
82 rev1, rev2 = args
82 rev1, rev2 = args
83 r = repo.changelog
83 r = repo.changelog
84 lookup = repo.lookup
84 lookup = repo.lookup
85 else:
85 else:
86 raise error.Abort(_('either two or three arguments required'))
86 raise error.Abort(_('either two or three arguments required'))
87 a = r.ancestor(lookup(rev1), lookup(rev2))
87 a = r.ancestor(lookup(rev1), lookup(rev2))
88 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
88 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
89
89
90 @command('debugapplystreamclonebundle', [], 'FILE')
90 @command('debugapplystreamclonebundle', [], 'FILE')
91 def debugapplystreamclonebundle(ui, repo, fname):
91 def debugapplystreamclonebundle(ui, repo, fname):
92 """apply a stream clone bundle file"""
92 """apply a stream clone bundle file"""
93 f = hg.openpath(ui, fname)
93 f = hg.openpath(ui, fname)
94 gen = exchange.readbundle(ui, f, fname)
94 gen = exchange.readbundle(ui, f, fname)
95 gen.apply(repo)
95 gen.apply(repo)
96
96
97 @command('debugbuilddag',
97 @command('debugbuilddag',
98 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
98 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
99 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
99 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
100 ('n', 'new-file', None, _('add new file at each rev'))],
100 ('n', 'new-file', None, _('add new file at each rev'))],
101 _('[OPTION]... [TEXT]'))
101 _('[OPTION]... [TEXT]'))
102 def debugbuilddag(ui, repo, text=None,
102 def debugbuilddag(ui, repo, text=None,
103 mergeable_file=False,
103 mergeable_file=False,
104 overwritten_file=False,
104 overwritten_file=False,
105 new_file=False):
105 new_file=False):
106 """builds a repo with a given DAG from scratch in the current empty repo
106 """builds a repo with a given DAG from scratch in the current empty repo
107
107
108 The description of the DAG is read from stdin if not given on the
108 The description of the DAG is read from stdin if not given on the
109 command line.
109 command line.
110
110
111 Elements:
111 Elements:
112
112
113 - "+n" is a linear run of n nodes based on the current default parent
113 - "+n" is a linear run of n nodes based on the current default parent
114 - "." is a single node based on the current default parent
114 - "." is a single node based on the current default parent
115 - "$" resets the default parent to null (implied at the start);
115 - "$" resets the default parent to null (implied at the start);
116 otherwise the default parent is always the last node created
116 otherwise the default parent is always the last node created
117 - "<p" sets the default parent to the backref p
117 - "<p" sets the default parent to the backref p
118 - "*p" is a fork at parent p, which is a backref
118 - "*p" is a fork at parent p, which is a backref
119 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
119 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
120 - "/p2" is a merge of the preceding node and p2
120 - "/p2" is a merge of the preceding node and p2
121 - ":tag" defines a local tag for the preceding node
121 - ":tag" defines a local tag for the preceding node
122 - "@branch" sets the named branch for subsequent nodes
122 - "@branch" sets the named branch for subsequent nodes
123 - "#...\\n" is a comment up to the end of the line
123 - "#...\\n" is a comment up to the end of the line
124
124
125 Whitespace between the above elements is ignored.
125 Whitespace between the above elements is ignored.
126
126
127 A backref is either
127 A backref is either
128
128
129 - a number n, which references the node curr-n, where curr is the current
129 - a number n, which references the node curr-n, where curr is the current
130 node, or
130 node, or
131 - the name of a local tag you placed earlier using ":tag", or
131 - the name of a local tag you placed earlier using ":tag", or
132 - empty to denote the default parent.
132 - empty to denote the default parent.
133
133
134 All string valued-elements are either strictly alphanumeric, or must
134 All string valued-elements are either strictly alphanumeric, or must
135 be enclosed in double quotes ("..."), with "\\" as escape character.
135 be enclosed in double quotes ("..."), with "\\" as escape character.
136 """
136 """
137
137
138 if text is None:
138 if text is None:
139 ui.status(_("reading DAG from stdin\n"))
139 ui.status(_("reading DAG from stdin\n"))
140 text = ui.fin.read()
140 text = ui.fin.read()
141
141
142 cl = repo.changelog
142 cl = repo.changelog
143 if len(cl) > 0:
143 if len(cl) > 0:
144 raise error.Abort(_('repository is not empty'))
144 raise error.Abort(_('repository is not empty'))
145
145
146 # determine number of revs in DAG
146 # determine number of revs in DAG
147 total = 0
147 total = 0
148 for type, data in dagparser.parsedag(text):
148 for type, data in dagparser.parsedag(text):
149 if type == 'n':
149 if type == 'n':
150 total += 1
150 total += 1
151
151
152 if mergeable_file:
152 if mergeable_file:
153 linesperrev = 2
153 linesperrev = 2
154 # make a file with k lines per rev
154 # make a file with k lines per rev
155 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
155 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
156 initialmergedlines.append("")
156 initialmergedlines.append("")
157
157
158 tags = []
158 tags = []
159
159
160 wlock = lock = tr = None
160 wlock = lock = tr = None
161 try:
161 try:
162 wlock = repo.wlock()
162 wlock = repo.wlock()
163 lock = repo.lock()
163 lock = repo.lock()
164 tr = repo.transaction("builddag")
164 tr = repo.transaction("builddag")
165
165
166 at = -1
166 at = -1
167 atbranch = 'default'
167 atbranch = 'default'
168 nodeids = []
168 nodeids = []
169 id = 0
169 id = 0
170 ui.progress(_('building'), id, unit=_('revisions'), total=total)
170 ui.progress(_('building'), id, unit=_('revisions'), total=total)
171 for type, data in dagparser.parsedag(text):
171 for type, data in dagparser.parsedag(text):
172 if type == 'n':
172 if type == 'n':
173 ui.note(('node %s\n' % str(data)))
173 ui.note(('node %s\n' % str(data)))
174 id, ps = data
174 id, ps = data
175
175
176 files = []
176 files = []
177 fctxs = {}
177 fctxs = {}
178
178
179 p2 = None
179 p2 = None
180 if mergeable_file:
180 if mergeable_file:
181 fn = "mf"
181 fn = "mf"
182 p1 = repo[ps[0]]
182 p1 = repo[ps[0]]
183 if len(ps) > 1:
183 if len(ps) > 1:
184 p2 = repo[ps[1]]
184 p2 = repo[ps[1]]
185 pa = p1.ancestor(p2)
185 pa = p1.ancestor(p2)
186 base, local, other = [x[fn].data() for x in (pa, p1,
186 base, local, other = [x[fn].data() for x in (pa, p1,
187 p2)]
187 p2)]
188 m3 = simplemerge.Merge3Text(base, local, other)
188 m3 = simplemerge.Merge3Text(base, local, other)
189 ml = [l.strip() for l in m3.merge_lines()]
189 ml = [l.strip() for l in m3.merge_lines()]
190 ml.append("")
190 ml.append("")
191 elif at > 0:
191 elif at > 0:
192 ml = p1[fn].data().split("\n")
192 ml = p1[fn].data().split("\n")
193 else:
193 else:
194 ml = initialmergedlines
194 ml = initialmergedlines
195 ml[id * linesperrev] += " r%i" % id
195 ml[id * linesperrev] += " r%i" % id
196 mergedtext = "\n".join(ml)
196 mergedtext = "\n".join(ml)
197 files.append(fn)
197 files.append(fn)
198 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
198 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
199
199
200 if overwritten_file:
200 if overwritten_file:
201 fn = "of"
201 fn = "of"
202 files.append(fn)
202 files.append(fn)
203 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
203 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
204
204
205 if new_file:
205 if new_file:
206 fn = "nf%i" % id
206 fn = "nf%i" % id
207 files.append(fn)
207 files.append(fn)
208 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
208 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
209 if len(ps) > 1:
209 if len(ps) > 1:
210 if not p2:
210 if not p2:
211 p2 = repo[ps[1]]
211 p2 = repo[ps[1]]
212 for fn in p2:
212 for fn in p2:
213 if fn.startswith("nf"):
213 if fn.startswith("nf"):
214 files.append(fn)
214 files.append(fn)
215 fctxs[fn] = p2[fn]
215 fctxs[fn] = p2[fn]
216
216
217 def fctxfn(repo, cx, path):
217 def fctxfn(repo, cx, path):
218 return fctxs.get(path)
218 return fctxs.get(path)
219
219
220 if len(ps) == 0 or ps[0] < 0:
220 if len(ps) == 0 or ps[0] < 0:
221 pars = [None, None]
221 pars = [None, None]
222 elif len(ps) == 1:
222 elif len(ps) == 1:
223 pars = [nodeids[ps[0]], None]
223 pars = [nodeids[ps[0]], None]
224 else:
224 else:
225 pars = [nodeids[p] for p in ps]
225 pars = [nodeids[p] for p in ps]
226 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
226 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
227 date=(id, 0),
227 date=(id, 0),
228 user="debugbuilddag",
228 user="debugbuilddag",
229 extra={'branch': atbranch})
229 extra={'branch': atbranch})
230 nodeid = repo.commitctx(cx)
230 nodeid = repo.commitctx(cx)
231 nodeids.append(nodeid)
231 nodeids.append(nodeid)
232 at = id
232 at = id
233 elif type == 'l':
233 elif type == 'l':
234 id, name = data
234 id, name = data
235 ui.note(('tag %s\n' % name))
235 ui.note(('tag %s\n' % name))
236 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
236 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
237 elif type == 'a':
237 elif type == 'a':
238 ui.note(('branch %s\n' % data))
238 ui.note(('branch %s\n' % data))
239 atbranch = data
239 atbranch = data
240 ui.progress(_('building'), id, unit=_('revisions'), total=total)
240 ui.progress(_('building'), id, unit=_('revisions'), total=total)
241 tr.close()
241 tr.close()
242
242
243 if tags:
243 if tags:
244 repo.vfs.write("localtags", "".join(tags))
244 repo.vfs.write("localtags", "".join(tags))
245 finally:
245 finally:
246 ui.progress(_('building'), None)
246 ui.progress(_('building'), None)
247 release(tr, lock, wlock)
247 release(tr, lock, wlock)
248
248
249 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
249 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
250 indent_string = ' ' * indent
250 indent_string = ' ' * indent
251 if all:
251 if all:
252 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
252 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
253 % indent_string)
253 % indent_string)
254
254
255 def showchunks(named):
255 def showchunks(named):
256 ui.write("\n%s%s\n" % (indent_string, named))
256 ui.write("\n%s%s\n" % (indent_string, named))
257 chain = None
257 chain = None
258 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
258 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
259 node = chunkdata['node']
259 node = chunkdata['node']
260 p1 = chunkdata['p1']
260 p1 = chunkdata['p1']
261 p2 = chunkdata['p2']
261 p2 = chunkdata['p2']
262 cs = chunkdata['cs']
262 cs = chunkdata['cs']
263 deltabase = chunkdata['deltabase']
263 deltabase = chunkdata['deltabase']
264 delta = chunkdata['delta']
264 delta = chunkdata['delta']
265 ui.write("%s%s %s %s %s %s %s\n" %
265 ui.write("%s%s %s %s %s %s %s\n" %
266 (indent_string, hex(node), hex(p1), hex(p2),
266 (indent_string, hex(node), hex(p1), hex(p2),
267 hex(cs), hex(deltabase), len(delta)))
267 hex(cs), hex(deltabase), len(delta)))
268 chain = node
268 chain = node
269
269
270 chunkdata = gen.changelogheader()
270 chunkdata = gen.changelogheader()
271 showchunks("changelog")
271 showchunks("changelog")
272 chunkdata = gen.manifestheader()
272 chunkdata = gen.manifestheader()
273 showchunks("manifest")
273 showchunks("manifest")
274 for chunkdata in iter(gen.filelogheader, {}):
274 for chunkdata in iter(gen.filelogheader, {}):
275 fname = chunkdata['filename']
275 fname = chunkdata['filename']
276 showchunks(fname)
276 showchunks(fname)
277 else:
277 else:
278 if isinstance(gen, bundle2.unbundle20):
278 if isinstance(gen, bundle2.unbundle20):
279 raise error.Abort(_('use debugbundle2 for this file'))
279 raise error.Abort(_('use debugbundle2 for this file'))
280 chunkdata = gen.changelogheader()
280 chunkdata = gen.changelogheader()
281 chain = None
281 chain = None
282 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
282 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
283 node = chunkdata['node']
283 node = chunkdata['node']
284 ui.write("%s%s\n" % (indent_string, hex(node)))
284 ui.write("%s%s\n" % (indent_string, hex(node)))
285 chain = node
285 chain = node
286
286
287 def _debugbundle2(ui, gen, all=None, **opts):
287 def _debugbundle2(ui, gen, all=None, **opts):
288 """lists the contents of a bundle2"""
288 """lists the contents of a bundle2"""
289 if not isinstance(gen, bundle2.unbundle20):
289 if not isinstance(gen, bundle2.unbundle20):
290 raise error.Abort(_('not a bundle2 file'))
290 raise error.Abort(_('not a bundle2 file'))
291 ui.write(('Stream params: %s\n' % repr(gen.params)))
291 ui.write(('Stream params: %s\n' % repr(gen.params)))
292 for part in gen.iterparts():
292 for part in gen.iterparts():
293 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
293 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
294 if part.type == 'changegroup':
294 if part.type == 'changegroup':
295 version = part.params.get('version', '01')
295 version = part.params.get('version', '01')
296 cg = changegroup.getunbundler(version, part, 'UN')
296 cg = changegroup.getunbundler(version, part, 'UN')
297 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
297 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
298
298
299 @command('debugbundle',
299 @command('debugbundle',
300 [('a', 'all', None, _('show all details')),
300 [('a', 'all', None, _('show all details')),
301 ('', 'spec', None, _('print the bundlespec of the bundle'))],
301 ('', 'spec', None, _('print the bundlespec of the bundle'))],
302 _('FILE'),
302 _('FILE'),
303 norepo=True)
303 norepo=True)
304 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
304 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
305 """lists the contents of a bundle"""
305 """lists the contents of a bundle"""
306 with hg.openpath(ui, bundlepath) as f:
306 with hg.openpath(ui, bundlepath) as f:
307 if spec:
307 if spec:
308 spec = exchange.getbundlespec(ui, f)
308 spec = exchange.getbundlespec(ui, f)
309 ui.write('%s\n' % spec)
309 ui.write('%s\n' % spec)
310 return
310 return
311
311
312 gen = exchange.readbundle(ui, f, bundlepath)
312 gen = exchange.readbundle(ui, f, bundlepath)
313 if isinstance(gen, bundle2.unbundle20):
313 if isinstance(gen, bundle2.unbundle20):
314 return _debugbundle2(ui, gen, all=all, **opts)
314 return _debugbundle2(ui, gen, all=all, **opts)
315 _debugchangegroup(ui, gen, all=all, **opts)
315 _debugchangegroup(ui, gen, all=all, **opts)
316
316
317 @command('debugcheckstate', [], '')
317 @command('debugcheckstate', [], '')
318 def debugcheckstate(ui, repo):
318 def debugcheckstate(ui, repo):
319 """validate the correctness of the current dirstate"""
319 """validate the correctness of the current dirstate"""
320 parent1, parent2 = repo.dirstate.parents()
320 parent1, parent2 = repo.dirstate.parents()
321 m1 = repo[parent1].manifest()
321 m1 = repo[parent1].manifest()
322 m2 = repo[parent2].manifest()
322 m2 = repo[parent2].manifest()
323 errors = 0
323 errors = 0
324 for f in repo.dirstate:
324 for f in repo.dirstate:
325 state = repo.dirstate[f]
325 state = repo.dirstate[f]
326 if state in "nr" and f not in m1:
326 if state in "nr" and f not in m1:
327 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
327 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
328 errors += 1
328 errors += 1
329 if state in "a" and f in m1:
329 if state in "a" and f in m1:
330 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
330 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
331 errors += 1
331 errors += 1
332 if state in "m" and f not in m1 and f not in m2:
332 if state in "m" and f not in m1 and f not in m2:
333 ui.warn(_("%s in state %s, but not in either manifest\n") %
333 ui.warn(_("%s in state %s, but not in either manifest\n") %
334 (f, state))
334 (f, state))
335 errors += 1
335 errors += 1
336 for f in m1:
336 for f in m1:
337 state = repo.dirstate[f]
337 state = repo.dirstate[f]
338 if state not in "nrm":
338 if state not in "nrm":
339 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
339 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
340 errors += 1
340 errors += 1
341 if errors:
341 if errors:
342 error = _(".hg/dirstate inconsistent with current parent's manifest")
342 error = _(".hg/dirstate inconsistent with current parent's manifest")
343 raise error.Abort(error)
343 raise error.Abort(error)
344
344
345 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
345 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
346 def debugcommands(ui, cmd='', *args):
346 def debugcommands(ui, cmd='', *args):
347 """list all available commands and options"""
347 """list all available commands and options"""
348 for cmd, vals in sorted(commands.table.iteritems()):
348 for cmd, vals in sorted(commands.table.iteritems()):
349 cmd = cmd.split('|')[0].strip('^')
349 cmd = cmd.split('|')[0].strip('^')
350 opts = ', '.join([i[1] for i in vals[1]])
350 opts = ', '.join([i[1] for i in vals[1]])
351 ui.write('%s: %s\n' % (cmd, opts))
351 ui.write('%s: %s\n' % (cmd, opts))
352
352
353 @command('debugcomplete',
353 @command('debugcomplete',
354 [('o', 'options', None, _('show the command options'))],
354 [('o', 'options', None, _('show the command options'))],
355 _('[-o] CMD'),
355 _('[-o] CMD'),
356 norepo=True)
356 norepo=True)
357 def debugcomplete(ui, cmd='', **opts):
357 def debugcomplete(ui, cmd='', **opts):
358 """returns the completion list associated with the given command"""
358 """returns the completion list associated with the given command"""
359
359
360 if opts.get('options'):
360 if opts.get('options'):
361 options = []
361 options = []
362 otables = [commands.globalopts]
362 otables = [commands.globalopts]
363 if cmd:
363 if cmd:
364 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
364 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
365 otables.append(entry[1])
365 otables.append(entry[1])
366 for t in otables:
366 for t in otables:
367 for o in t:
367 for o in t:
368 if "(DEPRECATED)" in o[3]:
368 if "(DEPRECATED)" in o[3]:
369 continue
369 continue
370 if o[0]:
370 if o[0]:
371 options.append('-%s' % o[0])
371 options.append('-%s' % o[0])
372 options.append('--%s' % o[1])
372 options.append('--%s' % o[1])
373 ui.write("%s\n" % "\n".join(options))
373 ui.write("%s\n" % "\n".join(options))
374 return
374 return
375
375
376 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
376 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
377 if ui.verbose:
377 if ui.verbose:
378 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
378 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
379 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
379 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
380
380
381 @command('debugcreatestreamclonebundle', [], 'FILE')
381 @command('debugcreatestreamclonebundle', [], 'FILE')
382 def debugcreatestreamclonebundle(ui, repo, fname):
382 def debugcreatestreamclonebundle(ui, repo, fname):
383 """create a stream clone bundle file
383 """create a stream clone bundle file
384
384
385 Stream bundles are special bundles that are essentially archives of
385 Stream bundles are special bundles that are essentially archives of
386 revlog files. They are commonly used for cloning very quickly.
386 revlog files. They are commonly used for cloning very quickly.
387 """
387 """
388 requirements, gen = streamclone.generatebundlev1(repo)
388 requirements, gen = streamclone.generatebundlev1(repo)
389 changegroup.writechunks(ui, gen, fname)
389 changegroup.writechunks(ui, gen, fname)
390
390
391 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
391 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
392
392
393 @command('debugdag',
393 @command('debugdag',
394 [('t', 'tags', None, _('use tags as labels')),
394 [('t', 'tags', None, _('use tags as labels')),
395 ('b', 'branches', None, _('annotate with branch names')),
395 ('b', 'branches', None, _('annotate with branch names')),
396 ('', 'dots', None, _('use dots for runs')),
396 ('', 'dots', None, _('use dots for runs')),
397 ('s', 'spaces', None, _('separate elements by spaces'))],
397 ('s', 'spaces', None, _('separate elements by spaces'))],
398 _('[OPTION]... [FILE [REV]...]'),
398 _('[OPTION]... [FILE [REV]...]'),
399 optionalrepo=True)
399 optionalrepo=True)
400 def debugdag(ui, repo, file_=None, *revs, **opts):
400 def debugdag(ui, repo, file_=None, *revs, **opts):
401 """format the changelog or an index DAG as a concise textual description
401 """format the changelog or an index DAG as a concise textual description
402
402
403 If you pass a revlog index, the revlog's DAG is emitted. If you list
403 If you pass a revlog index, the revlog's DAG is emitted. If you list
404 revision numbers, they get labeled in the output as rN.
404 revision numbers, they get labeled in the output as rN.
405
405
406 Otherwise, the changelog DAG of the current repo is emitted.
406 Otherwise, the changelog DAG of the current repo is emitted.
407 """
407 """
408 spaces = opts.get('spaces')
408 spaces = opts.get('spaces')
409 dots = opts.get('dots')
409 dots = opts.get('dots')
410 if file_:
410 if file_:
411 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
411 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
412 file_)
412 file_)
413 revs = set((int(r) for r in revs))
413 revs = set((int(r) for r in revs))
414 def events():
414 def events():
415 for r in rlog:
415 for r in rlog:
416 yield 'n', (r, list(p for p in rlog.parentrevs(r)
416 yield 'n', (r, list(p for p in rlog.parentrevs(r)
417 if p != -1))
417 if p != -1))
418 if r in revs:
418 if r in revs:
419 yield 'l', (r, "r%i" % r)
419 yield 'l', (r, "r%i" % r)
420 elif repo:
420 elif repo:
421 cl = repo.changelog
421 cl = repo.changelog
422 tags = opts.get('tags')
422 tags = opts.get('tags')
423 branches = opts.get('branches')
423 branches = opts.get('branches')
424 if tags:
424 if tags:
425 labels = {}
425 labels = {}
426 for l, n in repo.tags().items():
426 for l, n in repo.tags().items():
427 labels.setdefault(cl.rev(n), []).append(l)
427 labels.setdefault(cl.rev(n), []).append(l)
428 def events():
428 def events():
429 b = "default"
429 b = "default"
430 for r in cl:
430 for r in cl:
431 if branches:
431 if branches:
432 newb = cl.read(cl.node(r))[5]['branch']
432 newb = cl.read(cl.node(r))[5]['branch']
433 if newb != b:
433 if newb != b:
434 yield 'a', newb
434 yield 'a', newb
435 b = newb
435 b = newb
436 yield 'n', (r, list(p for p in cl.parentrevs(r)
436 yield 'n', (r, list(p for p in cl.parentrevs(r)
437 if p != -1))
437 if p != -1))
438 if tags:
438 if tags:
439 ls = labels.get(r)
439 ls = labels.get(r)
440 if ls:
440 if ls:
441 for l in ls:
441 for l in ls:
442 yield 'l', (r, l)
442 yield 'l', (r, l)
443 else:
443 else:
444 raise error.Abort(_('need repo for changelog dag'))
444 raise error.Abort(_('need repo for changelog dag'))
445
445
446 for line in dagparser.dagtextlines(events(),
446 for line in dagparser.dagtextlines(events(),
447 addspaces=spaces,
447 addspaces=spaces,
448 wraplabels=True,
448 wraplabels=True,
449 wrapannotations=True,
449 wrapannotations=True,
450 wrapnonlinear=dots,
450 wrapnonlinear=dots,
451 usedots=dots,
451 usedots=dots,
452 maxlinewidth=70):
452 maxlinewidth=70):
453 ui.write(line)
453 ui.write(line)
454 ui.write("\n")
454 ui.write("\n")
455
455
456 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
456 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
457 def debugdata(ui, repo, file_, rev=None, **opts):
457 def debugdata(ui, repo, file_, rev=None, **opts):
458 """dump the contents of a data file revision"""
458 """dump the contents of a data file revision"""
459 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
459 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
460 if rev is not None:
460 if rev is not None:
461 raise error.CommandError('debugdata', _('invalid arguments'))
461 raise error.CommandError('debugdata', _('invalid arguments'))
462 file_, rev = None, file_
462 file_, rev = None, file_
463 elif rev is None:
463 elif rev is None:
464 raise error.CommandError('debugdata', _('invalid arguments'))
464 raise error.CommandError('debugdata', _('invalid arguments'))
465 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
465 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
466 try:
466 try:
467 ui.write(r.revision(r.lookup(rev), raw=True))
467 ui.write(r.revision(r.lookup(rev), raw=True))
468 except KeyError:
468 except KeyError:
469 raise error.Abort(_('invalid revision identifier %s') % rev)
469 raise error.Abort(_('invalid revision identifier %s') % rev)
470
470
471 @command('debugdate',
471 @command('debugdate',
472 [('e', 'extended', None, _('try extended date formats'))],
472 [('e', 'extended', None, _('try extended date formats'))],
473 _('[-e] DATE [RANGE]'),
473 _('[-e] DATE [RANGE]'),
474 norepo=True, optionalrepo=True)
474 norepo=True, optionalrepo=True)
475 def debugdate(ui, date, range=None, **opts):
475 def debugdate(ui, date, range=None, **opts):
476 """parse and display a date"""
476 """parse and display a date"""
477 if opts["extended"]:
477 if opts["extended"]:
478 d = util.parsedate(date, util.extendeddateformats)
478 d = util.parsedate(date, util.extendeddateformats)
479 else:
479 else:
480 d = util.parsedate(date)
480 d = util.parsedate(date)
481 ui.write(("internal: %s %s\n") % d)
481 ui.write(("internal: %s %s\n") % d)
482 ui.write(("standard: %s\n") % util.datestr(d))
482 ui.write(("standard: %s\n") % util.datestr(d))
483 if range:
483 if range:
484 m = util.matchdate(range)
484 m = util.matchdate(range)
485 ui.write(("match: %s\n") % m(d[0]))
485 ui.write(("match: %s\n") % m(d[0]))
486
486
487 @command('debugdeltachain',
487 @command('debugdeltachain',
488 commands.debugrevlogopts + commands.formatteropts,
488 commands.debugrevlogopts + commands.formatteropts,
489 _('-c|-m|FILE'),
489 _('-c|-m|FILE'),
490 optionalrepo=True)
490 optionalrepo=True)
491 def debugdeltachain(ui, repo, file_=None, **opts):
491 def debugdeltachain(ui, repo, file_=None, **opts):
492 """dump information about delta chains in a revlog
492 """dump information about delta chains in a revlog
493
493
494 Output can be templatized. Available template keywords are:
494 Output can be templatized. Available template keywords are:
495
495
496 :``rev``: revision number
496 :``rev``: revision number
497 :``chainid``: delta chain identifier (numbered by unique base)
497 :``chainid``: delta chain identifier (numbered by unique base)
498 :``chainlen``: delta chain length to this revision
498 :``chainlen``: delta chain length to this revision
499 :``prevrev``: previous revision in delta chain
499 :``prevrev``: previous revision in delta chain
500 :``deltatype``: role of delta / how it was computed
500 :``deltatype``: role of delta / how it was computed
501 :``compsize``: compressed size of revision
501 :``compsize``: compressed size of revision
502 :``uncompsize``: uncompressed size of revision
502 :``uncompsize``: uncompressed size of revision
503 :``chainsize``: total size of compressed revisions in chain
503 :``chainsize``: total size of compressed revisions in chain
504 :``chainratio``: total chain size divided by uncompressed revision size
504 :``chainratio``: total chain size divided by uncompressed revision size
505 (new delta chains typically start at ratio 2.00)
505 (new delta chains typically start at ratio 2.00)
506 :``lindist``: linear distance from base revision in delta chain to end
506 :``lindist``: linear distance from base revision in delta chain to end
507 of this revision
507 of this revision
508 :``extradist``: total size of revisions not part of this delta chain from
508 :``extradist``: total size of revisions not part of this delta chain from
509 base of delta chain to end of this revision; a measurement
509 base of delta chain to end of this revision; a measurement
510 of how much extra data we need to read/seek across to read
510 of how much extra data we need to read/seek across to read
511 the delta chain for this revision
511 the delta chain for this revision
512 :``extraratio``: extradist divided by chainsize; another representation of
512 :``extraratio``: extradist divided by chainsize; another representation of
513 how much unrelated data is needed to load this delta chain
513 how much unrelated data is needed to load this delta chain
514 """
514 """
515 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
515 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
516 index = r.index
516 index = r.index
517 generaldelta = r.version & revlog.REVLOGGENERALDELTA
517 generaldelta = r.version & revlog.REVLOGGENERALDELTA
518
518
519 def revinfo(rev):
519 def revinfo(rev):
520 e = index[rev]
520 e = index[rev]
521 compsize = e[1]
521 compsize = e[1]
522 uncompsize = e[2]
522 uncompsize = e[2]
523 chainsize = 0
523 chainsize = 0
524
524
525 if generaldelta:
525 if generaldelta:
526 if e[3] == e[5]:
526 if e[3] == e[5]:
527 deltatype = 'p1'
527 deltatype = 'p1'
528 elif e[3] == e[6]:
528 elif e[3] == e[6]:
529 deltatype = 'p2'
529 deltatype = 'p2'
530 elif e[3] == rev - 1:
530 elif e[3] == rev - 1:
531 deltatype = 'prev'
531 deltatype = 'prev'
532 elif e[3] == rev:
532 elif e[3] == rev:
533 deltatype = 'base'
533 deltatype = 'base'
534 else:
534 else:
535 deltatype = 'other'
535 deltatype = 'other'
536 else:
536 else:
537 if e[3] == rev:
537 if e[3] == rev:
538 deltatype = 'base'
538 deltatype = 'base'
539 else:
539 else:
540 deltatype = 'prev'
540 deltatype = 'prev'
541
541
542 chain = r._deltachain(rev)[0]
542 chain = r._deltachain(rev)[0]
543 for iterrev in chain:
543 for iterrev in chain:
544 e = index[iterrev]
544 e = index[iterrev]
545 chainsize += e[1]
545 chainsize += e[1]
546
546
547 return compsize, uncompsize, deltatype, chain, chainsize
547 return compsize, uncompsize, deltatype, chain, chainsize
548
548
549 fm = ui.formatter('debugdeltachain', opts)
549 fm = ui.formatter('debugdeltachain', opts)
550
550
551 fm.plain(' rev chain# chainlen prev delta '
551 fm.plain(' rev chain# chainlen prev delta '
552 'size rawsize chainsize ratio lindist extradist '
552 'size rawsize chainsize ratio lindist extradist '
553 'extraratio\n')
553 'extraratio\n')
554
554
555 chainbases = {}
555 chainbases = {}
556 for rev in r:
556 for rev in r:
557 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
557 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
558 chainbase = chain[0]
558 chainbase = chain[0]
559 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
559 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
560 basestart = r.start(chainbase)
560 basestart = r.start(chainbase)
561 revstart = r.start(rev)
561 revstart = r.start(rev)
562 lineardist = revstart + comp - basestart
562 lineardist = revstart + comp - basestart
563 extradist = lineardist - chainsize
563 extradist = lineardist - chainsize
564 try:
564 try:
565 prevrev = chain[-2]
565 prevrev = chain[-2]
566 except IndexError:
566 except IndexError:
567 prevrev = -1
567 prevrev = -1
568
568
569 chainratio = float(chainsize) / float(uncomp)
569 chainratio = float(chainsize) / float(uncomp)
570 extraratio = float(extradist) / float(chainsize)
570 extraratio = float(extradist) / float(chainsize)
571
571
572 fm.startitem()
572 fm.startitem()
573 fm.write('rev chainid chainlen prevrev deltatype compsize '
573 fm.write('rev chainid chainlen prevrev deltatype compsize '
574 'uncompsize chainsize chainratio lindist extradist '
574 'uncompsize chainsize chainratio lindist extradist '
575 'extraratio',
575 'extraratio',
576 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
576 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
577 rev, chainid, len(chain), prevrev, deltatype, comp,
577 rev, chainid, len(chain), prevrev, deltatype, comp,
578 uncomp, chainsize, chainratio, lineardist, extradist,
578 uncomp, chainsize, chainratio, lineardist, extradist,
579 extraratio,
579 extraratio,
580 rev=rev, chainid=chainid, chainlen=len(chain),
580 rev=rev, chainid=chainid, chainlen=len(chain),
581 prevrev=prevrev, deltatype=deltatype, compsize=comp,
581 prevrev=prevrev, deltatype=deltatype, compsize=comp,
582 uncompsize=uncomp, chainsize=chainsize,
582 uncompsize=uncomp, chainsize=chainsize,
583 chainratio=chainratio, lindist=lineardist,
583 chainratio=chainratio, lindist=lineardist,
584 extradist=extradist, extraratio=extraratio)
584 extradist=extradist, extraratio=extraratio)
585
585
586 fm.end()
586 fm.end()
587
587
588 @command('debugdirstate|debugstate',
588 @command('debugdirstate|debugstate',
589 [('', 'nodates', None, _('do not display the saved mtime')),
589 [('', 'nodates', None, _('do not display the saved mtime')),
590 ('', 'datesort', None, _('sort by saved mtime'))],
590 ('', 'datesort', None, _('sort by saved mtime'))],
591 _('[OPTION]...'))
591 _('[OPTION]...'))
592 def debugstate(ui, repo, **opts):
592 def debugstate(ui, repo, **opts):
593 """show the contents of the current dirstate"""
593 """show the contents of the current dirstate"""
594
594
595 nodates = opts.get('nodates')
595 nodates = opts.get('nodates')
596 datesort = opts.get('datesort')
596 datesort = opts.get('datesort')
597
597
598 timestr = ""
598 timestr = ""
599 if datesort:
599 if datesort:
600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
601 else:
601 else:
602 keyfunc = None # sort by filename
602 keyfunc = None # sort by filename
603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
604 if ent[3] == -1:
604 if ent[3] == -1:
605 timestr = 'unset '
605 timestr = 'unset '
606 elif nodates:
606 elif nodates:
607 timestr = 'set '
607 timestr = 'set '
608 else:
608 else:
609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
610 time.localtime(ent[3]))
610 time.localtime(ent[3]))
611 if ent[1] & 0o20000:
611 if ent[1] & 0o20000:
612 mode = 'lnk'
612 mode = 'lnk'
613 else:
613 else:
614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
616 for f in repo.dirstate.copies():
616 for f in repo.dirstate.copies():
617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
618
618
619 @command('debugdiscovery',
619 @command('debugdiscovery',
620 [('', 'old', None, _('use old-style discovery')),
620 [('', 'old', None, _('use old-style discovery')),
621 ('', 'nonheads', None,
621 ('', 'nonheads', None,
622 _('use old-style discovery with non-heads included')),
622 _('use old-style discovery with non-heads included')),
623 ] + commands.remoteopts,
623 ] + commands.remoteopts,
624 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
624 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
625 def debugdiscovery(ui, repo, remoteurl="default", **opts):
625 def debugdiscovery(ui, repo, remoteurl="default", **opts):
626 """runs the changeset discovery protocol in isolation"""
626 """runs the changeset discovery protocol in isolation"""
627 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
627 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
628 opts.get('branch'))
628 opts.get('branch'))
629 remote = hg.peer(repo, opts, remoteurl)
629 remote = hg.peer(repo, opts, remoteurl)
630 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
630 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
631
631
632 # make sure tests are repeatable
632 # make sure tests are repeatable
633 random.seed(12323)
633 random.seed(12323)
634
634
635 def doit(localheads, remoteheads, remote=remote):
635 def doit(localheads, remoteheads, remote=remote):
636 if opts.get('old'):
636 if opts.get('old'):
637 if localheads:
637 if localheads:
638 raise error.Abort('cannot use localheads with old style '
638 raise error.Abort('cannot use localheads with old style '
639 'discovery')
639 'discovery')
640 if not util.safehasattr(remote, 'branches'):
640 if not util.safehasattr(remote, 'branches'):
641 # enable in-client legacy support
641 # enable in-client legacy support
642 remote = localrepo.locallegacypeer(remote.local())
642 remote = localrepo.locallegacypeer(remote.local())
643 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
643 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
644 force=True)
644 force=True)
645 common = set(common)
645 common = set(common)
646 if not opts.get('nonheads'):
646 if not opts.get('nonheads'):
647 ui.write(("unpruned common: %s\n") %
647 ui.write(("unpruned common: %s\n") %
648 " ".join(sorted(short(n) for n in common)))
648 " ".join(sorted(short(n) for n in common)))
649 dag = dagutil.revlogdag(repo.changelog)
649 dag = dagutil.revlogdag(repo.changelog)
650 all = dag.ancestorset(dag.internalizeall(common))
650 all = dag.ancestorset(dag.internalizeall(common))
651 common = dag.externalizeall(dag.headsetofconnecteds(all))
651 common = dag.externalizeall(dag.headsetofconnecteds(all))
652 else:
652 else:
653 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
653 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
654 common = set(common)
654 common = set(common)
655 rheads = set(hds)
655 rheads = set(hds)
656 lheads = set(repo.heads())
656 lheads = set(repo.heads())
657 ui.write(("common heads: %s\n") %
657 ui.write(("common heads: %s\n") %
658 " ".join(sorted(short(n) for n in common)))
658 " ".join(sorted(short(n) for n in common)))
659 if lheads <= common:
659 if lheads <= common:
660 ui.write(("local is subset\n"))
660 ui.write(("local is subset\n"))
661 elif rheads <= common:
661 elif rheads <= common:
662 ui.write(("remote is subset\n"))
662 ui.write(("remote is subset\n"))
663
663
664 serverlogs = opts.get('serverlog')
664 serverlogs = opts.get('serverlog')
665 if serverlogs:
665 if serverlogs:
666 for filename in serverlogs:
666 for filename in serverlogs:
667 with open(filename, 'r') as logfile:
667 with open(filename, 'r') as logfile:
668 line = logfile.readline()
668 line = logfile.readline()
669 while line:
669 while line:
670 parts = line.strip().split(';')
670 parts = line.strip().split(';')
671 op = parts[1]
671 op = parts[1]
672 if op == 'cg':
672 if op == 'cg':
673 pass
673 pass
674 elif op == 'cgss':
674 elif op == 'cgss':
675 doit(parts[2].split(' '), parts[3].split(' '))
675 doit(parts[2].split(' '), parts[3].split(' '))
676 elif op == 'unb':
676 elif op == 'unb':
677 doit(parts[3].split(' '), parts[2].split(' '))
677 doit(parts[3].split(' '), parts[2].split(' '))
678 line = logfile.readline()
678 line = logfile.readline()
679 else:
679 else:
680 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
680 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
681 opts.get('remote_head'))
681 opts.get('remote_head'))
682 localrevs = opts.get('local_head')
682 localrevs = opts.get('local_head')
683 doit(localrevs, remoterevs)
683 doit(localrevs, remoterevs)
684
684
685 @command('debugextensions', commands.formatteropts, [], norepo=True)
685 @command('debugextensions', commands.formatteropts, [], norepo=True)
686 def debugextensions(ui, **opts):
686 def debugextensions(ui, **opts):
687 '''show information about active extensions'''
687 '''show information about active extensions'''
688 exts = extensions.extensions(ui)
688 exts = extensions.extensions(ui)
689 hgver = util.version()
689 hgver = util.version()
690 fm = ui.formatter('debugextensions', opts)
690 fm = ui.formatter('debugextensions', opts)
691 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
691 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
692 isinternal = extensions.ismoduleinternal(extmod)
692 isinternal = extensions.ismoduleinternal(extmod)
693 extsource = extmod.__file__
693 extsource = extmod.__file__
694 if isinternal:
694 if isinternal:
695 exttestedwith = [] # never expose magic string to users
695 exttestedwith = [] # never expose magic string to users
696 else:
696 else:
697 exttestedwith = getattr(extmod, 'testedwith', '').split()
697 exttestedwith = getattr(extmod, 'testedwith', '').split()
698 extbuglink = getattr(extmod, 'buglink', None)
698 extbuglink = getattr(extmod, 'buglink', None)
699
699
700 fm.startitem()
700 fm.startitem()
701
701
702 if ui.quiet or ui.verbose:
702 if ui.quiet or ui.verbose:
703 fm.write('name', '%s\n', extname)
703 fm.write('name', '%s\n', extname)
704 else:
704 else:
705 fm.write('name', '%s', extname)
705 fm.write('name', '%s', extname)
706 if isinternal or hgver in exttestedwith:
706 if isinternal or hgver in exttestedwith:
707 fm.plain('\n')
707 fm.plain('\n')
708 elif not exttestedwith:
708 elif not exttestedwith:
709 fm.plain(_(' (untested!)\n'))
709 fm.plain(_(' (untested!)\n'))
710 else:
710 else:
711 lasttestedversion = exttestedwith[-1]
711 lasttestedversion = exttestedwith[-1]
712 fm.plain(' (%s!)\n' % lasttestedversion)
712 fm.plain(' (%s!)\n' % lasttestedversion)
713
713
714 fm.condwrite(ui.verbose and extsource, 'source',
714 fm.condwrite(ui.verbose and extsource, 'source',
715 _(' location: %s\n'), extsource or "")
715 _(' location: %s\n'), extsource or "")
716
716
717 if ui.verbose:
717 if ui.verbose:
718 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
718 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
719 fm.data(bundled=isinternal)
719 fm.data(bundled=isinternal)
720
720
721 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
721 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
722 _(' tested with: %s\n'),
722 _(' tested with: %s\n'),
723 fm.formatlist(exttestedwith, name='ver'))
723 fm.formatlist(exttestedwith, name='ver'))
724
724
725 fm.condwrite(ui.verbose and extbuglink, 'buglink',
725 fm.condwrite(ui.verbose and extbuglink, 'buglink',
726 _(' bug reporting: %s\n'), extbuglink or "")
726 _(' bug reporting: %s\n'), extbuglink or "")
727
727
728 fm.end()
728 fm.end()
729
729
730 @command('debugfileset',
730 @command('debugfileset',
731 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
731 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
732 _('[-r REV] FILESPEC'))
732 _('[-r REV] FILESPEC'))
733 def debugfileset(ui, repo, expr, **opts):
733 def debugfileset(ui, repo, expr, **opts):
734 '''parse and apply a fileset specification'''
734 '''parse and apply a fileset specification'''
735 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
735 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
736 if ui.verbose:
736 if ui.verbose:
737 tree = fileset.parse(expr)
737 tree = fileset.parse(expr)
738 ui.note(fileset.prettyformat(tree), "\n")
738 ui.note(fileset.prettyformat(tree), "\n")
739
739
740 for f in ctx.getfileset(expr):
740 for f in ctx.getfileset(expr):
741 ui.write("%s\n" % f)
741 ui.write("%s\n" % f)
742
742
743 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
743 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
744 def debugfsinfo(ui, path="."):
744 def debugfsinfo(ui, path="."):
745 """show information detected about current filesystem"""
745 """show information detected about current filesystem"""
746 util.writefile('.debugfsinfo', '')
746 util.writefile('.debugfsinfo', '')
747 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
747 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
748 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
748 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
749 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
749 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
750 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
750 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
751 and 'yes' or 'no'))
751 and 'yes' or 'no'))
752 os.unlink('.debugfsinfo')
752 os.unlink('.debugfsinfo')
753
753
754 @command('debuggetbundle',
754 @command('debuggetbundle',
755 [('H', 'head', [], _('id of head node'), _('ID')),
755 [('H', 'head', [], _('id of head node'), _('ID')),
756 ('C', 'common', [], _('id of common node'), _('ID')),
756 ('C', 'common', [], _('id of common node'), _('ID')),
757 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
757 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
758 _('REPO FILE [-H|-C ID]...'),
758 _('REPO FILE [-H|-C ID]...'),
759 norepo=True)
759 norepo=True)
760 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
760 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
761 """retrieves a bundle from a repo
761 """retrieves a bundle from a repo
762
762
763 Every ID must be a full-length hex node id string. Saves the bundle to the
763 Every ID must be a full-length hex node id string. Saves the bundle to the
764 given file.
764 given file.
765 """
765 """
766 repo = hg.peer(ui, opts, repopath)
766 repo = hg.peer(ui, opts, repopath)
767 if not repo.capable('getbundle'):
767 if not repo.capable('getbundle'):
768 raise error.Abort("getbundle() not supported by target repository")
768 raise error.Abort("getbundle() not supported by target repository")
769 args = {}
769 args = {}
770 if common:
770 if common:
771 args['common'] = [bin(s) for s in common]
771 args['common'] = [bin(s) for s in common]
772 if head:
772 if head:
773 args['heads'] = [bin(s) for s in head]
773 args['heads'] = [bin(s) for s in head]
774 # TODO: get desired bundlecaps from command line.
774 # TODO: get desired bundlecaps from command line.
775 args['bundlecaps'] = None
775 args['bundlecaps'] = None
776 bundle = repo.getbundle('debug', **args)
776 bundle = repo.getbundle('debug', **args)
777
777
778 bundletype = opts.get('type', 'bzip2').lower()
778 bundletype = opts.get('type', 'bzip2').lower()
779 btypes = {'none': 'HG10UN',
779 btypes = {'none': 'HG10UN',
780 'bzip2': 'HG10BZ',
780 'bzip2': 'HG10BZ',
781 'gzip': 'HG10GZ',
781 'gzip': 'HG10GZ',
782 'bundle2': 'HG20'}
782 'bundle2': 'HG20'}
783 bundletype = btypes.get(bundletype)
783 bundletype = btypes.get(bundletype)
784 if bundletype not in bundle2.bundletypes:
784 if bundletype not in bundle2.bundletypes:
785 raise error.Abort(_('unknown bundle type specified with --type'))
785 raise error.Abort(_('unknown bundle type specified with --type'))
786 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
786 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
787
787
788 @command('debugignore', [], '[FILE]')
788 @command('debugignore', [], '[FILE]')
789 def debugignore(ui, repo, *files, **opts):
789 def debugignore(ui, repo, *files, **opts):
790 """display the combined ignore pattern and information about ignored files
790 """display the combined ignore pattern and information about ignored files
791
791
792 With no argument display the combined ignore pattern.
792 With no argument display the combined ignore pattern.
793
793
794 Given space separated file names, shows if the given file is ignored and
794 Given space separated file names, shows if the given file is ignored and
795 if so, show the ignore rule (file and line number) that matched it.
795 if so, show the ignore rule (file and line number) that matched it.
796 """
796 """
797 ignore = repo.dirstate._ignore
797 ignore = repo.dirstate._ignore
798 if not files:
798 if not files:
799 # Show all the patterns
799 # Show all the patterns
800 includepat = getattr(ignore, 'includepat', None)
800 includepat = getattr(ignore, 'includepat', None)
801 if includepat is not None:
801 if includepat is not None:
802 ui.write("%s\n" % includepat)
802 ui.write("%s\n" % includepat)
803 else:
803 else:
804 raise error.Abort(_("no ignore patterns found"))
804 raise error.Abort(_("no ignore patterns found"))
805 else:
805 else:
806 for f in files:
806 for f in files:
807 nf = util.normpath(f)
807 nf = util.normpath(f)
808 ignored = None
808 ignored = None
809 ignoredata = None
809 ignoredata = None
810 if nf != '.':
810 if nf != '.':
811 if ignore(nf):
811 if ignore(nf):
812 ignored = nf
812 ignored = nf
813 ignoredata = repo.dirstate._ignorefileandline(nf)
813 ignoredata = repo.dirstate._ignorefileandline(nf)
814 else:
814 else:
815 for p in util.finddirs(nf):
815 for p in util.finddirs(nf):
816 if ignore(p):
816 if ignore(p):
817 ignored = p
817 ignored = p
818 ignoredata = repo.dirstate._ignorefileandline(p)
818 ignoredata = repo.dirstate._ignorefileandline(p)
819 break
819 break
820 if ignored:
820 if ignored:
821 if ignored == nf:
821 if ignored == nf:
822 ui.write(_("%s is ignored\n") % f)
822 ui.write(_("%s is ignored\n") % f)
823 else:
823 else:
824 ui.write(_("%s is ignored because of "
824 ui.write(_("%s is ignored because of "
825 "containing folder %s\n")
825 "containing folder %s\n")
826 % (f, ignored))
826 % (f, ignored))
827 ignorefile, lineno, line = ignoredata
827 ignorefile, lineno, line = ignoredata
828 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
828 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
829 % (ignorefile, lineno, line))
829 % (ignorefile, lineno, line))
830 else:
830 else:
831 ui.write(_("%s is not ignored\n") % f)
831 ui.write(_("%s is not ignored\n") % f)
832
832
833 @command('debugindex', commands.debugrevlogopts +
833 @command('debugindex', commands.debugrevlogopts +
834 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
834 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
835 _('[-f FORMAT] -c|-m|FILE'),
835 _('[-f FORMAT] -c|-m|FILE'),
836 optionalrepo=True)
836 optionalrepo=True)
837 def debugindex(ui, repo, file_=None, **opts):
837 def debugindex(ui, repo, file_=None, **opts):
838 """dump the contents of an index file"""
838 """dump the contents of an index file"""
839 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
839 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
840 format = opts.get('format', 0)
840 format = opts.get('format', 0)
841 if format not in (0, 1):
841 if format not in (0, 1):
842 raise error.Abort(_("unknown format %d") % format)
842 raise error.Abort(_("unknown format %d") % format)
843
843
844 generaldelta = r.version & revlog.REVLOGGENERALDELTA
844 generaldelta = r.version & revlog.REVLOGGENERALDELTA
845 if generaldelta:
845 if generaldelta:
846 basehdr = ' delta'
846 basehdr = ' delta'
847 else:
847 else:
848 basehdr = ' base'
848 basehdr = ' base'
849
849
850 if ui.debugflag:
850 if ui.debugflag:
851 shortfn = hex
851 shortfn = hex
852 else:
852 else:
853 shortfn = short
853 shortfn = short
854
854
855 # There might not be anything in r, so have a sane default
855 # There might not be anything in r, so have a sane default
856 idlen = 12
856 idlen = 12
857 for i in r:
857 for i in r:
858 idlen = len(shortfn(r.node(i)))
858 idlen = len(shortfn(r.node(i)))
859 break
859 break
860
860
861 if format == 0:
861 if format == 0:
862 ui.write((" rev offset length " + basehdr + " linkrev"
862 ui.write((" rev offset length " + basehdr + " linkrev"
863 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
863 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
864 elif format == 1:
864 elif format == 1:
865 ui.write((" rev flag offset length"
865 ui.write((" rev flag offset length"
866 " size " + basehdr + " link p1 p2"
866 " size " + basehdr + " link p1 p2"
867 " %s\n") % "nodeid".rjust(idlen))
867 " %s\n") % "nodeid".rjust(idlen))
868
868
869 for i in r:
869 for i in r:
870 node = r.node(i)
870 node = r.node(i)
871 if generaldelta:
871 if generaldelta:
872 base = r.deltaparent(i)
872 base = r.deltaparent(i)
873 else:
873 else:
874 base = r.chainbase(i)
874 base = r.chainbase(i)
875 if format == 0:
875 if format == 0:
876 try:
876 try:
877 pp = r.parents(node)
877 pp = r.parents(node)
878 except Exception:
878 except Exception:
879 pp = [nullid, nullid]
879 pp = [nullid, nullid]
880 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
880 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
881 i, r.start(i), r.length(i), base, r.linkrev(i),
881 i, r.start(i), r.length(i), base, r.linkrev(i),
882 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
882 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
883 elif format == 1:
883 elif format == 1:
884 pr = r.parentrevs(i)
884 pr = r.parentrevs(i)
885 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
885 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
886 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
886 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
887 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
887 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
888
888
889 @command('debugindexdot', commands.debugrevlogopts,
889 @command('debugindexdot', commands.debugrevlogopts,
890 _('-c|-m|FILE'), optionalrepo=True)
890 _('-c|-m|FILE'), optionalrepo=True)
891 def debugindexdot(ui, repo, file_=None, **opts):
891 def debugindexdot(ui, repo, file_=None, **opts):
892 """dump an index DAG as a graphviz dot file"""
892 """dump an index DAG as a graphviz dot file"""
893 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
893 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
894 ui.write(("digraph G {\n"))
894 ui.write(("digraph G {\n"))
895 for i in r:
895 for i in r:
896 node = r.node(i)
896 node = r.node(i)
897 pp = r.parents(node)
897 pp = r.parents(node)
898 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
898 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
899 if pp[1] != nullid:
899 if pp[1] != nullid:
900 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
900 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
901 ui.write("}\n")
901 ui.write("}\n")
902
902
903 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
903 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
904 def debuginstall(ui, **opts):
904 def debuginstall(ui, **opts):
905 '''test Mercurial installation
905 '''test Mercurial installation
906
906
907 Returns 0 on success.
907 Returns 0 on success.
908 '''
908 '''
909
909
910 def writetemp(contents):
910 def writetemp(contents):
911 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
911 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
912 f = os.fdopen(fd, "wb")
912 f = os.fdopen(fd, "wb")
913 f.write(contents)
913 f.write(contents)
914 f.close()
914 f.close()
915 return name
915 return name
916
916
917 problems = 0
917 problems = 0
918
918
919 fm = ui.formatter('debuginstall', opts)
919 fm = ui.formatter('debuginstall', opts)
920 fm.startitem()
920 fm.startitem()
921
921
922 # encoding
922 # encoding
923 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
923 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
924 err = None
924 err = None
925 try:
925 try:
926 encoding.fromlocal("test")
926 encoding.fromlocal("test")
927 except error.Abort as inst:
927 except error.Abort as inst:
928 err = inst
928 err = inst
929 problems += 1
929 problems += 1
930 fm.condwrite(err, 'encodingerror', _(" %s\n"
930 fm.condwrite(err, 'encodingerror', _(" %s\n"
931 " (check that your locale is properly set)\n"), err)
931 " (check that your locale is properly set)\n"), err)
932
932
933 # Python
933 # Python
934 fm.write('pythonexe', _("checking Python executable (%s)\n"),
934 fm.write('pythonexe', _("checking Python executable (%s)\n"),
935 pycompat.sysexecutable)
935 pycompat.sysexecutable)
936 fm.write('pythonver', _("checking Python version (%s)\n"),
936 fm.write('pythonver', _("checking Python version (%s)\n"),
937 ("%d.%d.%d" % sys.version_info[:3]))
937 ("%d.%d.%d" % sys.version_info[:3]))
938 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
938 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
939 os.path.dirname(pycompat.fsencode(os.__file__)))
939 os.path.dirname(pycompat.fsencode(os.__file__)))
940
940
941 security = set(sslutil.supportedprotocols)
941 security = set(sslutil.supportedprotocols)
942 if sslutil.hassni:
942 if sslutil.hassni:
943 security.add('sni')
943 security.add('sni')
944
944
945 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
945 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
946 fm.formatlist(sorted(security), name='protocol',
946 fm.formatlist(sorted(security), name='protocol',
947 fmt='%s', sep=','))
947 fmt='%s', sep=','))
948
948
949 # These are warnings, not errors. So don't increment problem count. This
949 # These are warnings, not errors. So don't increment problem count. This
950 # may change in the future.
950 # may change in the future.
951 if 'tls1.2' not in security:
951 if 'tls1.2' not in security:
952 fm.plain(_(' TLS 1.2 not supported by Python install; '
952 fm.plain(_(' TLS 1.2 not supported by Python install; '
953 'network connections lack modern security\n'))
953 'network connections lack modern security\n'))
954 if 'sni' not in security:
954 if 'sni' not in security:
955 fm.plain(_(' SNI not supported by Python install; may have '
955 fm.plain(_(' SNI not supported by Python install; may have '
956 'connectivity issues with some servers\n'))
956 'connectivity issues with some servers\n'))
957
957
958 # TODO print CA cert info
958 # TODO print CA cert info
959
959
960 # hg version
960 # hg version
961 hgver = util.version()
961 hgver = util.version()
962 fm.write('hgver', _("checking Mercurial version (%s)\n"),
962 fm.write('hgver', _("checking Mercurial version (%s)\n"),
963 hgver.split('+')[0])
963 hgver.split('+')[0])
964 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
964 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
965 '+'.join(hgver.split('+')[1:]))
965 '+'.join(hgver.split('+')[1:]))
966
966
967 # compiled modules
967 # compiled modules
968 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
968 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
969 policy.policy)
969 policy.policy)
970 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
970 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
971 os.path.dirname(__file__))
971 os.path.dirname(__file__))
972
972
973 err = None
973 err = None
974 try:
974 try:
975 from . import (
975 from . import (
976 base85,
976 base85,
977 bdiff,
977 bdiff,
978 mpatch,
978 mpatch,
979 osutil,
979 osutil,
980 )
980 )
981 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
981 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
982 except Exception as inst:
982 except Exception as inst:
983 err = inst
983 err = inst
984 problems += 1
984 problems += 1
985 fm.condwrite(err, 'extensionserror', " %s\n", err)
985 fm.condwrite(err, 'extensionserror', " %s\n", err)
986
986
987 compengines = util.compengines._engines.values()
987 compengines = util.compengines._engines.values()
988 fm.write('compengines', _('checking registered compression engines (%s)\n'),
988 fm.write('compengines', _('checking registered compression engines (%s)\n'),
989 fm.formatlist(sorted(e.name() for e in compengines),
989 fm.formatlist(sorted(e.name() for e in compengines),
990 name='compengine', fmt='%s', sep=', '))
990 name='compengine', fmt='%s', sep=', '))
991 fm.write('compenginesavail', _('checking available compression engines '
991 fm.write('compenginesavail', _('checking available compression engines '
992 '(%s)\n'),
992 '(%s)\n'),
993 fm.formatlist(sorted(e.name() for e in compengines
993 fm.formatlist(sorted(e.name() for e in compengines
994 if e.available()),
994 if e.available()),
995 name='compengine', fmt='%s', sep=', '))
995 name='compengine', fmt='%s', sep=', '))
996 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
996 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
997 fm.write('compenginesserver', _('checking available compression engines '
997 fm.write('compenginesserver', _('checking available compression engines '
998 'for wire protocol (%s)\n'),
998 'for wire protocol (%s)\n'),
999 fm.formatlist([e.name() for e in wirecompengines
999 fm.formatlist([e.name() for e in wirecompengines
1000 if e.wireprotosupport()],
1000 if e.wireprotosupport()],
1001 name='compengine', fmt='%s', sep=', '))
1001 name='compengine', fmt='%s', sep=', '))
1002
1002
1003 # templates
1003 # templates
1004 p = templater.templatepaths()
1004 p = templater.templatepaths()
1005 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1005 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1006 fm.condwrite(not p, '', _(" no template directories found\n"))
1006 fm.condwrite(not p, '', _(" no template directories found\n"))
1007 if p:
1007 if p:
1008 m = templater.templatepath("map-cmdline.default")
1008 m = templater.templatepath("map-cmdline.default")
1009 if m:
1009 if m:
1010 # template found, check if it is working
1010 # template found, check if it is working
1011 err = None
1011 err = None
1012 try:
1012 try:
1013 templater.templater.frommapfile(m)
1013 templater.templater.frommapfile(m)
1014 except Exception as inst:
1014 except Exception as inst:
1015 err = inst
1015 err = inst
1016 p = None
1016 p = None
1017 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1017 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1018 else:
1018 else:
1019 p = None
1019 p = None
1020 fm.condwrite(p, 'defaulttemplate',
1020 fm.condwrite(p, 'defaulttemplate',
1021 _("checking default template (%s)\n"), m)
1021 _("checking default template (%s)\n"), m)
1022 fm.condwrite(not m, 'defaulttemplatenotfound',
1022 fm.condwrite(not m, 'defaulttemplatenotfound',
1023 _(" template '%s' not found\n"), "default")
1023 _(" template '%s' not found\n"), "default")
1024 if not p:
1024 if not p:
1025 problems += 1
1025 problems += 1
1026 fm.condwrite(not p, '',
1026 fm.condwrite(not p, '',
1027 _(" (templates seem to have been installed incorrectly)\n"))
1027 _(" (templates seem to have been installed incorrectly)\n"))
1028
1028
1029 # editor
1029 # editor
1030 editor = ui.geteditor()
1030 editor = ui.geteditor()
1031 editor = util.expandpath(editor)
1031 editor = util.expandpath(editor)
1032 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1032 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1033 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1033 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1034 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1034 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1035 _(" No commit editor set and can't find %s in PATH\n"
1035 _(" No commit editor set and can't find %s in PATH\n"
1036 " (specify a commit editor in your configuration"
1036 " (specify a commit editor in your configuration"
1037 " file)\n"), not cmdpath and editor == 'vi' and editor)
1037 " file)\n"), not cmdpath and editor == 'vi' and editor)
1038 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1038 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1039 _(" Can't find editor '%s' in PATH\n"
1039 _(" Can't find editor '%s' in PATH\n"
1040 " (specify a commit editor in your configuration"
1040 " (specify a commit editor in your configuration"
1041 " file)\n"), not cmdpath and editor)
1041 " file)\n"), not cmdpath and editor)
1042 if not cmdpath and editor != 'vi':
1042 if not cmdpath and editor != 'vi':
1043 problems += 1
1043 problems += 1
1044
1044
1045 # check username
1045 # check username
1046 username = None
1046 username = None
1047 err = None
1047 err = None
1048 try:
1048 try:
1049 username = ui.username()
1049 username = ui.username()
1050 except error.Abort as e:
1050 except error.Abort as e:
1051 err = e
1051 err = e
1052 problems += 1
1052 problems += 1
1053
1053
1054 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1054 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1055 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1055 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1056 " (specify a username in your configuration file)\n"), err)
1056 " (specify a username in your configuration file)\n"), err)
1057
1057
1058 fm.condwrite(not problems, '',
1058 fm.condwrite(not problems, '',
1059 _("no problems detected\n"))
1059 _("no problems detected\n"))
1060 if not problems:
1060 if not problems:
1061 fm.data(problems=problems)
1061 fm.data(problems=problems)
1062 fm.condwrite(problems, 'problems',
1062 fm.condwrite(problems, 'problems',
1063 _("%d problems detected,"
1063 _("%d problems detected,"
1064 " please check your install!\n"), problems)
1064 " please check your install!\n"), problems)
1065 fm.end()
1065 fm.end()
1066
1066
1067 return problems
1067 return problems
1068
1068
1069 @command('debugknown', [], _('REPO ID...'), norepo=True)
1069 @command('debugknown', [], _('REPO ID...'), norepo=True)
1070 def debugknown(ui, repopath, *ids, **opts):
1070 def debugknown(ui, repopath, *ids, **opts):
1071 """test whether node ids are known to a repo
1071 """test whether node ids are known to a repo
1072
1072
1073 Every ID must be a full-length hex node id string. Returns a list of 0s
1073 Every ID must be a full-length hex node id string. Returns a list of 0s
1074 and 1s indicating unknown/known.
1074 and 1s indicating unknown/known.
1075 """
1075 """
1076 repo = hg.peer(ui, opts, repopath)
1076 repo = hg.peer(ui, opts, repopath)
1077 if not repo.capable('known'):
1077 if not repo.capable('known'):
1078 raise error.Abort("known() not supported by target repository")
1078 raise error.Abort("known() not supported by target repository")
1079 flags = repo.known([bin(s) for s in ids])
1079 flags = repo.known([bin(s) for s in ids])
1080 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1080 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1081
1081
1082 @command('debuglabelcomplete', [], _('LABEL...'))
1082 @command('debuglabelcomplete', [], _('LABEL...'))
1083 def debuglabelcomplete(ui, repo, *args):
1083 def debuglabelcomplete(ui, repo, *args):
1084 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1084 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1085 commands.debugnamecomplete(ui, repo, *args)
1085 commands.debugnamecomplete(ui, repo, *args)
1086
1086
1087 @command('debuglocks',
1087 @command('debuglocks',
1088 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1088 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1089 ('W', 'force-wlock', None,
1089 ('W', 'force-wlock', None,
1090 _('free the working state lock (DANGEROUS)'))],
1090 _('free the working state lock (DANGEROUS)'))],
1091 _('[OPTION]...'))
1091 _('[OPTION]...'))
1092 def debuglocks(ui, repo, **opts):
1092 def debuglocks(ui, repo, **opts):
1093 """show or modify state of locks
1093 """show or modify state of locks
1094
1094
1095 By default, this command will show which locks are held. This
1095 By default, this command will show which locks are held. This
1096 includes the user and process holding the lock, the amount of time
1096 includes the user and process holding the lock, the amount of time
1097 the lock has been held, and the machine name where the process is
1097 the lock has been held, and the machine name where the process is
1098 running if it's not local.
1098 running if it's not local.
1099
1099
1100 Locks protect the integrity of Mercurial's data, so should be
1100 Locks protect the integrity of Mercurial's data, so should be
1101 treated with care. System crashes or other interruptions may cause
1101 treated with care. System crashes or other interruptions may cause
1102 locks to not be properly released, though Mercurial will usually
1102 locks to not be properly released, though Mercurial will usually
1103 detect and remove such stale locks automatically.
1103 detect and remove such stale locks automatically.
1104
1104
1105 However, detecting stale locks may not always be possible (for
1105 However, detecting stale locks may not always be possible (for
1106 instance, on a shared filesystem). Removing locks may also be
1106 instance, on a shared filesystem). Removing locks may also be
1107 blocked by filesystem permissions.
1107 blocked by filesystem permissions.
1108
1108
1109 Returns 0 if no locks are held.
1109 Returns 0 if no locks are held.
1110
1110
1111 """
1111 """
1112
1112
1113 if opts.get('force_lock'):
1113 if opts.get('force_lock'):
1114 repo.svfs.unlink('lock')
1114 repo.svfs.unlink('lock')
1115 if opts.get('force_wlock'):
1115 if opts.get('force_wlock'):
1116 repo.vfs.unlink('wlock')
1116 repo.vfs.unlink('wlock')
1117 if opts.get('force_lock') or opts.get('force_lock'):
1117 if opts.get('force_lock') or opts.get('force_lock'):
1118 return 0
1118 return 0
1119
1119
1120 now = time.time()
1120 now = time.time()
1121 held = 0
1121 held = 0
1122
1122
1123 def report(vfs, name, method):
1123 def report(vfs, name, method):
1124 # this causes stale locks to get reaped for more accurate reporting
1124 # this causes stale locks to get reaped for more accurate reporting
1125 try:
1125 try:
1126 l = method(False)
1126 l = method(False)
1127 except error.LockHeld:
1127 except error.LockHeld:
1128 l = None
1128 l = None
1129
1129
1130 if l:
1130 if l:
1131 l.release()
1131 l.release()
1132 else:
1132 else:
1133 try:
1133 try:
1134 stat = vfs.lstat(name)
1134 stat = vfs.lstat(name)
1135 age = now - stat.st_mtime
1135 age = now - stat.st_mtime
1136 user = util.username(stat.st_uid)
1136 user = util.username(stat.st_uid)
1137 locker = vfs.readlock(name)
1137 locker = vfs.readlock(name)
1138 if ":" in locker:
1138 if ":" in locker:
1139 host, pid = locker.split(':')
1139 host, pid = locker.split(':')
1140 if host == socket.gethostname():
1140 if host == socket.gethostname():
1141 locker = 'user %s, process %s' % (user, pid)
1141 locker = 'user %s, process %s' % (user, pid)
1142 else:
1142 else:
1143 locker = 'user %s, process %s, host %s' \
1143 locker = 'user %s, process %s, host %s' \
1144 % (user, pid, host)
1144 % (user, pid, host)
1145 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1145 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1146 return 1
1146 return 1
1147 except OSError as e:
1147 except OSError as e:
1148 if e.errno != errno.ENOENT:
1148 if e.errno != errno.ENOENT:
1149 raise
1149 raise
1150
1150
1151 ui.write(("%-6s free\n") % (name + ":"))
1151 ui.write(("%-6s free\n") % (name + ":"))
1152 return 0
1152 return 0
1153
1153
1154 held += report(repo.svfs, "lock", repo.lock)
1154 held += report(repo.svfs, "lock", repo.lock)
1155 held += report(repo.vfs, "wlock", repo.wlock)
1155 held += report(repo.vfs, "wlock", repo.wlock)
1156
1156
1157 return held
1157 return held
1158
1158
1159 @command('debugmergestate', [], '')
1159 @command('debugmergestate', [], '')
1160 def debugmergestate(ui, repo, *args):
1160 def debugmergestate(ui, repo, *args):
1161 """print merge state
1161 """print merge state
1162
1162
1163 Use --verbose to print out information about whether v1 or v2 merge state
1163 Use --verbose to print out information about whether v1 or v2 merge state
1164 was chosen."""
1164 was chosen."""
1165 def _hashornull(h):
1165 def _hashornull(h):
1166 if h == nullhex:
1166 if h == nullhex:
1167 return 'null'
1167 return 'null'
1168 else:
1168 else:
1169 return h
1169 return h
1170
1170
1171 def printrecords(version):
1171 def printrecords(version):
1172 ui.write(('* version %s records\n') % version)
1172 ui.write(('* version %s records\n') % version)
1173 if version == 1:
1173 if version == 1:
1174 records = v1records
1174 records = v1records
1175 else:
1175 else:
1176 records = v2records
1176 records = v2records
1177
1177
1178 for rtype, record in records:
1178 for rtype, record in records:
1179 # pretty print some record types
1179 # pretty print some record types
1180 if rtype == 'L':
1180 if rtype == 'L':
1181 ui.write(('local: %s\n') % record)
1181 ui.write(('local: %s\n') % record)
1182 elif rtype == 'O':
1182 elif rtype == 'O':
1183 ui.write(('other: %s\n') % record)
1183 ui.write(('other: %s\n') % record)
1184 elif rtype == 'm':
1184 elif rtype == 'm':
1185 driver, mdstate = record.split('\0', 1)
1185 driver, mdstate = record.split('\0', 1)
1186 ui.write(('merge driver: %s (state "%s")\n')
1186 ui.write(('merge driver: %s (state "%s")\n')
1187 % (driver, mdstate))
1187 % (driver, mdstate))
1188 elif rtype in 'FDC':
1188 elif rtype in 'FDC':
1189 r = record.split('\0')
1189 r = record.split('\0')
1190 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1190 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1191 if version == 1:
1191 if version == 1:
1192 onode = 'not stored in v1 format'
1192 onode = 'not stored in v1 format'
1193 flags = r[7]
1193 flags = r[7]
1194 else:
1194 else:
1195 onode, flags = r[7:9]
1195 onode, flags = r[7:9]
1196 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1196 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1197 % (f, rtype, state, _hashornull(hash)))
1197 % (f, rtype, state, _hashornull(hash)))
1198 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1198 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1199 ui.write((' ancestor path: %s (node %s)\n')
1199 ui.write((' ancestor path: %s (node %s)\n')
1200 % (afile, _hashornull(anode)))
1200 % (afile, _hashornull(anode)))
1201 ui.write((' other path: %s (node %s)\n')
1201 ui.write((' other path: %s (node %s)\n')
1202 % (ofile, _hashornull(onode)))
1202 % (ofile, _hashornull(onode)))
1203 elif rtype == 'f':
1203 elif rtype == 'f':
1204 filename, rawextras = record.split('\0', 1)
1204 filename, rawextras = record.split('\0', 1)
1205 extras = rawextras.split('\0')
1205 extras = rawextras.split('\0')
1206 i = 0
1206 i = 0
1207 extrastrings = []
1207 extrastrings = []
1208 while i < len(extras):
1208 while i < len(extras):
1209 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1209 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1210 i += 2
1210 i += 2
1211
1211
1212 ui.write(('file extras: %s (%s)\n')
1212 ui.write(('file extras: %s (%s)\n')
1213 % (filename, ', '.join(extrastrings)))
1213 % (filename, ', '.join(extrastrings)))
1214 elif rtype == 'l':
1214 elif rtype == 'l':
1215 labels = record.split('\0', 2)
1215 labels = record.split('\0', 2)
1216 labels = [l for l in labels if len(l) > 0]
1216 labels = [l for l in labels if len(l) > 0]
1217 ui.write(('labels:\n'))
1217 ui.write(('labels:\n'))
1218 ui.write((' local: %s\n' % labels[0]))
1218 ui.write((' local: %s\n' % labels[0]))
1219 ui.write((' other: %s\n' % labels[1]))
1219 ui.write((' other: %s\n' % labels[1]))
1220 if len(labels) > 2:
1220 if len(labels) > 2:
1221 ui.write((' base: %s\n' % labels[2]))
1221 ui.write((' base: %s\n' % labels[2]))
1222 else:
1222 else:
1223 ui.write(('unrecognized entry: %s\t%s\n')
1223 ui.write(('unrecognized entry: %s\t%s\n')
1224 % (rtype, record.replace('\0', '\t')))
1224 % (rtype, record.replace('\0', '\t')))
1225
1225
1226 # Avoid mergestate.read() since it may raise an exception for unsupported
1226 # Avoid mergestate.read() since it may raise an exception for unsupported
1227 # merge state records. We shouldn't be doing this, but this is OK since this
1227 # merge state records. We shouldn't be doing this, but this is OK since this
1228 # command is pretty low-level.
1228 # command is pretty low-level.
1229 ms = mergemod.mergestate(repo)
1229 ms = mergemod.mergestate(repo)
1230
1230
1231 # sort so that reasonable information is on top
1231 # sort so that reasonable information is on top
1232 v1records = ms._readrecordsv1()
1232 v1records = ms._readrecordsv1()
1233 v2records = ms._readrecordsv2()
1233 v2records = ms._readrecordsv2()
1234 order = 'LOml'
1234 order = 'LOml'
1235 def key(r):
1235 def key(r):
1236 idx = order.find(r[0])
1236 idx = order.find(r[0])
1237 if idx == -1:
1237 if idx == -1:
1238 return (1, r[1])
1238 return (1, r[1])
1239 else:
1239 else:
1240 return (0, idx)
1240 return (0, idx)
1241 v1records.sort(key=key)
1241 v1records.sort(key=key)
1242 v2records.sort(key=key)
1242 v2records.sort(key=key)
1243
1243
1244 if not v1records and not v2records:
1244 if not v1records and not v2records:
1245 ui.write(('no merge state found\n'))
1245 ui.write(('no merge state found\n'))
1246 elif not v2records:
1246 elif not v2records:
1247 ui.note(('no version 2 merge state\n'))
1247 ui.note(('no version 2 merge state\n'))
1248 printrecords(1)
1248 printrecords(1)
1249 elif ms._v1v2match(v1records, v2records):
1249 elif ms._v1v2match(v1records, v2records):
1250 ui.note(('v1 and v2 states match: using v2\n'))
1250 ui.note(('v1 and v2 states match: using v2\n'))
1251 printrecords(2)
1251 printrecords(2)
1252 else:
1252 else:
1253 ui.note(('v1 and v2 states mismatch: using v1\n'))
1253 ui.note(('v1 and v2 states mismatch: using v1\n'))
1254 printrecords(1)
1254 printrecords(1)
1255 if ui.verbose:
1255 if ui.verbose:
1256 printrecords(2)
1256 printrecords(2)
1257
1257
1258 @command('debugnamecomplete', [], _('NAME...'))
1258 @command('debugnamecomplete', [], _('NAME...'))
1259 def debugnamecomplete(ui, repo, *args):
1259 def debugnamecomplete(ui, repo, *args):
1260 '''complete "names" - tags, open branch names, bookmark names'''
1260 '''complete "names" - tags, open branch names, bookmark names'''
1261
1261
1262 names = set()
1262 names = set()
1263 # since we previously only listed open branches, we will handle that
1263 # since we previously only listed open branches, we will handle that
1264 # specially (after this for loop)
1264 # specially (after this for loop)
1265 for name, ns in repo.names.iteritems():
1265 for name, ns in repo.names.iteritems():
1266 if name != 'branches':
1266 if name != 'branches':
1267 names.update(ns.listnames(repo))
1267 names.update(ns.listnames(repo))
1268 names.update(tag for (tag, heads, tip, closed)
1268 names.update(tag for (tag, heads, tip, closed)
1269 in repo.branchmap().iterbranches() if not closed)
1269 in repo.branchmap().iterbranches() if not closed)
1270 completions = set()
1270 completions = set()
1271 if not args:
1271 if not args:
1272 args = ['']
1272 args = ['']
1273 for a in args:
1273 for a in args:
1274 completions.update(n for n in names if n.startswith(a))
1274 completions.update(n for n in names if n.startswith(a))
1275 ui.write('\n'.join(sorted(completions)))
1275 ui.write('\n'.join(sorted(completions)))
1276 ui.write('\n')
1276 ui.write('\n')
1277
1277
1278 @command('debugobsolete',
1278 @command('debugobsolete',
1279 [('', 'flags', 0, _('markers flag')),
1279 [('', 'flags', 0, _('markers flag')),
1280 ('', 'record-parents', False,
1280 ('', 'record-parents', False,
1281 _('record parent information for the precursor')),
1281 _('record parent information for the precursor')),
1282 ('r', 'rev', [], _('display markers relevant to REV')),
1282 ('r', 'rev', [], _('display markers relevant to REV')),
1283 ('', 'index', False, _('display index of the marker')),
1283 ('', 'index', False, _('display index of the marker')),
1284 ('', 'delete', [], _('delete markers specified by indices')),
1284 ('', 'delete', [], _('delete markers specified by indices')),
1285 ] + commands.commitopts2 + commands.formatteropts,
1285 ] + commands.commitopts2 + commands.formatteropts,
1286 _('[OBSOLETED [REPLACEMENT ...]]'))
1286 _('[OBSOLETED [REPLACEMENT ...]]'))
1287 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1287 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1288 """create arbitrary obsolete marker
1288 """create arbitrary obsolete marker
1289
1289
1290 With no arguments, displays the list of obsolescence markers."""
1290 With no arguments, displays the list of obsolescence markers."""
1291
1291
1292 def parsenodeid(s):
1292 def parsenodeid(s):
1293 try:
1293 try:
1294 # We do not use revsingle/revrange functions here to accept
1294 # We do not use revsingle/revrange functions here to accept
1295 # arbitrary node identifiers, possibly not present in the
1295 # arbitrary node identifiers, possibly not present in the
1296 # local repository.
1296 # local repository.
1297 n = bin(s)
1297 n = bin(s)
1298 if len(n) != len(nullid):
1298 if len(n) != len(nullid):
1299 raise TypeError()
1299 raise TypeError()
1300 return n
1300 return n
1301 except TypeError:
1301 except TypeError:
1302 raise error.Abort('changeset references must be full hexadecimal '
1302 raise error.Abort('changeset references must be full hexadecimal '
1303 'node identifiers')
1303 'node identifiers')
1304
1304
1305 if opts.get('delete'):
1305 if opts.get('delete'):
1306 indices = []
1306 indices = []
1307 for v in opts.get('delete'):
1307 for v in opts.get('delete'):
1308 try:
1308 try:
1309 indices.append(int(v))
1309 indices.append(int(v))
1310 except ValueError:
1310 except ValueError:
1311 raise error.Abort(_('invalid index value: %r') % v,
1311 raise error.Abort(_('invalid index value: %r') % v,
1312 hint=_('use integers for indices'))
1312 hint=_('use integers for indices'))
1313
1313
1314 if repo.currenttransaction():
1314 if repo.currenttransaction():
1315 raise error.Abort(_('cannot delete obsmarkers in the middle '
1315 raise error.Abort(_('cannot delete obsmarkers in the middle '
1316 'of transaction.'))
1316 'of transaction.'))
1317
1317
1318 with repo.lock():
1318 with repo.lock():
1319 n = repair.deleteobsmarkers(repo.obsstore, indices)
1319 n = repair.deleteobsmarkers(repo.obsstore, indices)
1320 ui.write(_('deleted %i obsolescence markers\n') % n)
1320 ui.write(_('deleted %i obsolescence markers\n') % n)
1321
1321
1322 return
1322 return
1323
1323
1324 if precursor is not None:
1324 if precursor is not None:
1325 if opts['rev']:
1325 if opts['rev']:
1326 raise error.Abort('cannot select revision when creating marker')
1326 raise error.Abort('cannot select revision when creating marker')
1327 metadata = {}
1327 metadata = {}
1328 metadata['user'] = opts['user'] or ui.username()
1328 metadata['user'] = opts['user'] or ui.username()
1329 succs = tuple(parsenodeid(succ) for succ in successors)
1329 succs = tuple(parsenodeid(succ) for succ in successors)
1330 l = repo.lock()
1330 l = repo.lock()
1331 try:
1331 try:
1332 tr = repo.transaction('debugobsolete')
1332 tr = repo.transaction('debugobsolete')
1333 try:
1333 try:
1334 date = opts.get('date')
1334 date = opts.get('date')
1335 if date:
1335 if date:
1336 date = util.parsedate(date)
1336 date = util.parsedate(date)
1337 else:
1337 else:
1338 date = None
1338 date = None
1339 prec = parsenodeid(precursor)
1339 prec = parsenodeid(precursor)
1340 parents = None
1340 parents = None
1341 if opts['record_parents']:
1341 if opts['record_parents']:
1342 if prec not in repo.unfiltered():
1342 if prec not in repo.unfiltered():
1343 raise error.Abort('cannot used --record-parents on '
1343 raise error.Abort('cannot used --record-parents on '
1344 'unknown changesets')
1344 'unknown changesets')
1345 parents = repo.unfiltered()[prec].parents()
1345 parents = repo.unfiltered()[prec].parents()
1346 parents = tuple(p.node() for p in parents)
1346 parents = tuple(p.node() for p in parents)
1347 repo.obsstore.create(tr, prec, succs, opts['flags'],
1347 repo.obsstore.create(tr, prec, succs, opts['flags'],
1348 parents=parents, date=date,
1348 parents=parents, date=date,
1349 metadata=metadata)
1349 metadata=metadata)
1350 tr.close()
1350 tr.close()
1351 except ValueError as exc:
1351 except ValueError as exc:
1352 raise error.Abort(_('bad obsmarker input: %s') % exc)
1352 raise error.Abort(_('bad obsmarker input: %s') % exc)
1353 finally:
1353 finally:
1354 tr.release()
1354 tr.release()
1355 finally:
1355 finally:
1356 l.release()
1356 l.release()
1357 else:
1357 else:
1358 if opts['rev']:
1358 if opts['rev']:
1359 revs = scmutil.revrange(repo, opts['rev'])
1359 revs = scmutil.revrange(repo, opts['rev'])
1360 nodes = [repo[r].node() for r in revs]
1360 nodes = [repo[r].node() for r in revs]
1361 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1361 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1362 markers.sort(key=lambda x: x._data)
1362 markers.sort(key=lambda x: x._data)
1363 else:
1363 else:
1364 markers = obsolete.getmarkers(repo)
1364 markers = obsolete.getmarkers(repo)
1365
1365
1366 markerstoiter = markers
1366 markerstoiter = markers
1367 isrelevant = lambda m: True
1367 isrelevant = lambda m: True
1368 if opts.get('rev') and opts.get('index'):
1368 if opts.get('rev') and opts.get('index'):
1369 markerstoiter = obsolete.getmarkers(repo)
1369 markerstoiter = obsolete.getmarkers(repo)
1370 markerset = set(markers)
1370 markerset = set(markers)
1371 isrelevant = lambda m: m in markerset
1371 isrelevant = lambda m: m in markerset
1372
1372
1373 fm = ui.formatter('debugobsolete', opts)
1373 fm = ui.formatter('debugobsolete', opts)
1374 for i, m in enumerate(markerstoiter):
1374 for i, m in enumerate(markerstoiter):
1375 if not isrelevant(m):
1375 if not isrelevant(m):
1376 # marker can be irrelevant when we're iterating over a set
1376 # marker can be irrelevant when we're iterating over a set
1377 # of markers (markerstoiter) which is bigger than the set
1377 # of markers (markerstoiter) which is bigger than the set
1378 # of markers we want to display (markers)
1378 # of markers we want to display (markers)
1379 # this can happen if both --index and --rev options are
1379 # this can happen if both --index and --rev options are
1380 # provided and thus we need to iterate over all of the markers
1380 # provided and thus we need to iterate over all of the markers
1381 # to get the correct indices, but only display the ones that
1381 # to get the correct indices, but only display the ones that
1382 # are relevant to --rev value
1382 # are relevant to --rev value
1383 continue
1383 continue
1384 fm.startitem()
1384 fm.startitem()
1385 ind = i if opts.get('index') else None
1385 ind = i if opts.get('index') else None
1386 cmdutil.showmarker(fm, m, index=ind)
1386 cmdutil.showmarker(fm, m, index=ind)
1387 fm.end()
1387 fm.end()
1388
1388
1389 @command('debugpathcomplete',
1389 @command('debugpathcomplete',
1390 [('f', 'full', None, _('complete an entire path')),
1390 [('f', 'full', None, _('complete an entire path')),
1391 ('n', 'normal', None, _('show only normal files')),
1391 ('n', 'normal', None, _('show only normal files')),
1392 ('a', 'added', None, _('show only added files')),
1392 ('a', 'added', None, _('show only added files')),
1393 ('r', 'removed', None, _('show only removed files'))],
1393 ('r', 'removed', None, _('show only removed files'))],
1394 _('FILESPEC...'))
1394 _('FILESPEC...'))
1395 def debugpathcomplete(ui, repo, *specs, **opts):
1395 def debugpathcomplete(ui, repo, *specs, **opts):
1396 '''complete part or all of a tracked path
1396 '''complete part or all of a tracked path
1397
1397
1398 This command supports shells that offer path name completion. It
1398 This command supports shells that offer path name completion. It
1399 currently completes only files already known to the dirstate.
1399 currently completes only files already known to the dirstate.
1400
1400
1401 Completion extends only to the next path segment unless
1401 Completion extends only to the next path segment unless
1402 --full is specified, in which case entire paths are used.'''
1402 --full is specified, in which case entire paths are used.'''
1403
1403
1404 def complete(path, acceptable):
1404 def complete(path, acceptable):
1405 dirstate = repo.dirstate
1405 dirstate = repo.dirstate
1406 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1406 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1407 rootdir = repo.root + pycompat.ossep
1407 rootdir = repo.root + pycompat.ossep
1408 if spec != repo.root and not spec.startswith(rootdir):
1408 if spec != repo.root and not spec.startswith(rootdir):
1409 return [], []
1409 return [], []
1410 if os.path.isdir(spec):
1410 if os.path.isdir(spec):
1411 spec += '/'
1411 spec += '/'
1412 spec = spec[len(rootdir):]
1412 spec = spec[len(rootdir):]
1413 fixpaths = pycompat.ossep != '/'
1413 fixpaths = pycompat.ossep != '/'
1414 if fixpaths:
1414 if fixpaths:
1415 spec = spec.replace(pycompat.ossep, '/')
1415 spec = spec.replace(pycompat.ossep, '/')
1416 speclen = len(spec)
1416 speclen = len(spec)
1417 fullpaths = opts['full']
1417 fullpaths = opts['full']
1418 files, dirs = set(), set()
1418 files, dirs = set(), set()
1419 adddir, addfile = dirs.add, files.add
1419 adddir, addfile = dirs.add, files.add
1420 for f, st in dirstate.iteritems():
1420 for f, st in dirstate.iteritems():
1421 if f.startswith(spec) and st[0] in acceptable:
1421 if f.startswith(spec) and st[0] in acceptable:
1422 if fixpaths:
1422 if fixpaths:
1423 f = f.replace('/', pycompat.ossep)
1423 f = f.replace('/', pycompat.ossep)
1424 if fullpaths:
1424 if fullpaths:
1425 addfile(f)
1425 addfile(f)
1426 continue
1426 continue
1427 s = f.find(pycompat.ossep, speclen)
1427 s = f.find(pycompat.ossep, speclen)
1428 if s >= 0:
1428 if s >= 0:
1429 adddir(f[:s])
1429 adddir(f[:s])
1430 else:
1430 else:
1431 addfile(f)
1431 addfile(f)
1432 return files, dirs
1432 return files, dirs
1433
1433
1434 acceptable = ''
1434 acceptable = ''
1435 if opts['normal']:
1435 if opts['normal']:
1436 acceptable += 'nm'
1436 acceptable += 'nm'
1437 if opts['added']:
1437 if opts['added']:
1438 acceptable += 'a'
1438 acceptable += 'a'
1439 if opts['removed']:
1439 if opts['removed']:
1440 acceptable += 'r'
1440 acceptable += 'r'
1441 cwd = repo.getcwd()
1441 cwd = repo.getcwd()
1442 if not specs:
1442 if not specs:
1443 specs = ['.']
1443 specs = ['.']
1444
1444
1445 files, dirs = set(), set()
1445 files, dirs = set(), set()
1446 for spec in specs:
1446 for spec in specs:
1447 f, d = complete(spec, acceptable or 'nmar')
1447 f, d = complete(spec, acceptable or 'nmar')
1448 files.update(f)
1448 files.update(f)
1449 dirs.update(d)
1449 dirs.update(d)
1450 files.update(dirs)
1450 files.update(dirs)
1451 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1451 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1452 ui.write('\n')
1452 ui.write('\n')
1453
1453
1454 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1454 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1455 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1455 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1456 '''access the pushkey key/value protocol
1456 '''access the pushkey key/value protocol
1457
1457
1458 With two args, list the keys in the given namespace.
1458 With two args, list the keys in the given namespace.
1459
1459
1460 With five args, set a key to new if it currently is set to old.
1460 With five args, set a key to new if it currently is set to old.
1461 Reports success or failure.
1461 Reports success or failure.
1462 '''
1462 '''
1463
1463
1464 target = hg.peer(ui, {}, repopath)
1464 target = hg.peer(ui, {}, repopath)
1465 if keyinfo:
1465 if keyinfo:
1466 key, old, new = keyinfo
1466 key, old, new = keyinfo
1467 r = target.pushkey(namespace, key, old, new)
1467 r = target.pushkey(namespace, key, old, new)
1468 ui.status(str(r) + '\n')
1468 ui.status(str(r) + '\n')
1469 return not r
1469 return not r
1470 else:
1470 else:
1471 for k, v in sorted(target.listkeys(namespace).iteritems()):
1471 for k, v in sorted(target.listkeys(namespace).iteritems()):
1472 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1472 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1473 v.encode('string-escape')))
1473 v.encode('string-escape')))
1474
1474
1475 @command('debugpvec', [], _('A B'))
1475 @command('debugpvec', [], _('A B'))
1476 def debugpvec(ui, repo, a, b=None):
1476 def debugpvec(ui, repo, a, b=None):
1477 ca = scmutil.revsingle(repo, a)
1477 ca = scmutil.revsingle(repo, a)
1478 cb = scmutil.revsingle(repo, b)
1478 cb = scmutil.revsingle(repo, b)
1479 pa = pvec.ctxpvec(ca)
1479 pa = pvec.ctxpvec(ca)
1480 pb = pvec.ctxpvec(cb)
1480 pb = pvec.ctxpvec(cb)
1481 if pa == pb:
1481 if pa == pb:
1482 rel = "="
1482 rel = "="
1483 elif pa > pb:
1483 elif pa > pb:
1484 rel = ">"
1484 rel = ">"
1485 elif pa < pb:
1485 elif pa < pb:
1486 rel = "<"
1486 rel = "<"
1487 elif pa | pb:
1487 elif pa | pb:
1488 rel = "|"
1488 rel = "|"
1489 ui.write(_("a: %s\n") % pa)
1489 ui.write(_("a: %s\n") % pa)
1490 ui.write(_("b: %s\n") % pb)
1490 ui.write(_("b: %s\n") % pb)
1491 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1491 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1492 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1492 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1493 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1493 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1494 pa.distance(pb), rel))
1494 pa.distance(pb), rel))
1495
1495
1496 @command('debugrebuilddirstate|debugrebuildstate',
1496 @command('debugrebuilddirstate|debugrebuildstate',
1497 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1497 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1498 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1498 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1499 'the working copy parent')),
1499 'the working copy parent')),
1500 ],
1500 ],
1501 _('[-r REV]'))
1501 _('[-r REV]'))
1502 def debugrebuilddirstate(ui, repo, rev, **opts):
1502 def debugrebuilddirstate(ui, repo, rev, **opts):
1503 """rebuild the dirstate as it would look like for the given revision
1503 """rebuild the dirstate as it would look like for the given revision
1504
1504
1505 If no revision is specified the first current parent will be used.
1505 If no revision is specified the first current parent will be used.
1506
1506
1507 The dirstate will be set to the files of the given revision.
1507 The dirstate will be set to the files of the given revision.
1508 The actual working directory content or existing dirstate
1508 The actual working directory content or existing dirstate
1509 information such as adds or removes is not considered.
1509 information such as adds or removes is not considered.
1510
1510
1511 ``minimal`` will only rebuild the dirstate status for files that claim to be
1511 ``minimal`` will only rebuild the dirstate status for files that claim to be
1512 tracked but are not in the parent manifest, or that exist in the parent
1512 tracked but are not in the parent manifest, or that exist in the parent
1513 manifest but are not in the dirstate. It will not change adds, removes, or
1513 manifest but are not in the dirstate. It will not change adds, removes, or
1514 modified files that are in the working copy parent.
1514 modified files that are in the working copy parent.
1515
1515
1516 One use of this command is to make the next :hg:`status` invocation
1516 One use of this command is to make the next :hg:`status` invocation
1517 check the actual file content.
1517 check the actual file content.
1518 """
1518 """
1519 ctx = scmutil.revsingle(repo, rev)
1519 ctx = scmutil.revsingle(repo, rev)
1520 with repo.wlock():
1520 with repo.wlock():
1521 dirstate = repo.dirstate
1521 dirstate = repo.dirstate
1522 changedfiles = None
1522 changedfiles = None
1523 # See command doc for what minimal does.
1523 # See command doc for what minimal does.
1524 if opts.get('minimal'):
1524 if opts.get('minimal'):
1525 manifestfiles = set(ctx.manifest().keys())
1525 manifestfiles = set(ctx.manifest().keys())
1526 dirstatefiles = set(dirstate)
1526 dirstatefiles = set(dirstate)
1527 manifestonly = manifestfiles - dirstatefiles
1527 manifestonly = manifestfiles - dirstatefiles
1528 dsonly = dirstatefiles - manifestfiles
1528 dsonly = dirstatefiles - manifestfiles
1529 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1529 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1530 changedfiles = manifestonly | dsnotadded
1530 changedfiles = manifestonly | dsnotadded
1531
1531
1532 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1532 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1533
1533
1534 @command('debugrebuildfncache', [], '')
1534 @command('debugrebuildfncache', [], '')
1535 def debugrebuildfncache(ui, repo):
1535 def debugrebuildfncache(ui, repo):
1536 """rebuild the fncache file"""
1536 """rebuild the fncache file"""
1537 repair.rebuildfncache(ui, repo)
1537 repair.rebuildfncache(ui, repo)
1538
1538
1539 @command('debugrename',
1539 @command('debugrename',
1540 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1540 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1541 _('[-r REV] FILE'))
1541 _('[-r REV] FILE'))
1542 def debugrename(ui, repo, file1, *pats, **opts):
1542 def debugrename(ui, repo, file1, *pats, **opts):
1543 """dump rename information"""
1543 """dump rename information"""
1544
1544
1545 ctx = scmutil.revsingle(repo, opts.get('rev'))
1545 ctx = scmutil.revsingle(repo, opts.get('rev'))
1546 m = scmutil.match(ctx, (file1,) + pats, opts)
1546 m = scmutil.match(ctx, (file1,) + pats, opts)
1547 for abs in ctx.walk(m):
1547 for abs in ctx.walk(m):
1548 fctx = ctx[abs]
1548 fctx = ctx[abs]
1549 o = fctx.filelog().renamed(fctx.filenode())
1549 o = fctx.filelog().renamed(fctx.filenode())
1550 rel = m.rel(abs)
1550 rel = m.rel(abs)
1551 if o:
1551 if o:
1552 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1552 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1553 else:
1553 else:
1554 ui.write(_("%s not renamed\n") % rel)
1554 ui.write(_("%s not renamed\n") % rel)
1555
1555
1556 @command('debugrevlog', commands.debugrevlogopts +
1556 @command('debugrevlog', commands.debugrevlogopts +
1557 [('d', 'dump', False, _('dump index data'))],
1557 [('d', 'dump', False, _('dump index data'))],
1558 _('-c|-m|FILE'),
1558 _('-c|-m|FILE'),
1559 optionalrepo=True)
1559 optionalrepo=True)
1560 def debugrevlog(ui, repo, file_=None, **opts):
1560 def debugrevlog(ui, repo, file_=None, **opts):
1561 """show data and statistics about a revlog"""
1561 """show data and statistics about a revlog"""
1562 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1562 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1563
1563
1564 if opts.get("dump"):
1564 if opts.get("dump"):
1565 numrevs = len(r)
1565 numrevs = len(r)
1566 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1566 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1567 " rawsize totalsize compression heads chainlen\n"))
1567 " rawsize totalsize compression heads chainlen\n"))
1568 ts = 0
1568 ts = 0
1569 heads = set()
1569 heads = set()
1570
1570
1571 for rev in xrange(numrevs):
1571 for rev in xrange(numrevs):
1572 dbase = r.deltaparent(rev)
1572 dbase = r.deltaparent(rev)
1573 if dbase == -1:
1573 if dbase == -1:
1574 dbase = rev
1574 dbase = rev
1575 cbase = r.chainbase(rev)
1575 cbase = r.chainbase(rev)
1576 clen = r.chainlen(rev)
1576 clen = r.chainlen(rev)
1577 p1, p2 = r.parentrevs(rev)
1577 p1, p2 = r.parentrevs(rev)
1578 rs = r.rawsize(rev)
1578 rs = r.rawsize(rev)
1579 ts = ts + rs
1579 ts = ts + rs
1580 heads -= set(r.parentrevs(rev))
1580 heads -= set(r.parentrevs(rev))
1581 heads.add(rev)
1581 heads.add(rev)
1582 try:
1582 try:
1583 compression = ts / r.end(rev)
1583 compression = ts / r.end(rev)
1584 except ZeroDivisionError:
1584 except ZeroDivisionError:
1585 compression = 0
1585 compression = 0
1586 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1586 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1587 "%11d %5d %8d\n" %
1587 "%11d %5d %8d\n" %
1588 (rev, p1, p2, r.start(rev), r.end(rev),
1588 (rev, p1, p2, r.start(rev), r.end(rev),
1589 r.start(dbase), r.start(cbase),
1589 r.start(dbase), r.start(cbase),
1590 r.start(p1), r.start(p2),
1590 r.start(p1), r.start(p2),
1591 rs, ts, compression, len(heads), clen))
1591 rs, ts, compression, len(heads), clen))
1592 return 0
1592 return 0
1593
1593
1594 v = r.version
1594 v = r.version
1595 format = v & 0xFFFF
1595 format = v & 0xFFFF
1596 flags = []
1596 flags = []
1597 gdelta = False
1597 gdelta = False
1598 if v & revlog.REVLOGNGINLINEDATA:
1598 if v & revlog.REVLOGNGINLINEDATA:
1599 flags.append('inline')
1599 flags.append('inline')
1600 if v & revlog.REVLOGGENERALDELTA:
1600 if v & revlog.REVLOGGENERALDELTA:
1601 gdelta = True
1601 gdelta = True
1602 flags.append('generaldelta')
1602 flags.append('generaldelta')
1603 if not flags:
1603 if not flags:
1604 flags = ['(none)']
1604 flags = ['(none)']
1605
1605
1606 nummerges = 0
1606 nummerges = 0
1607 numfull = 0
1607 numfull = 0
1608 numprev = 0
1608 numprev = 0
1609 nump1 = 0
1609 nump1 = 0
1610 nump2 = 0
1610 nump2 = 0
1611 numother = 0
1611 numother = 0
1612 nump1prev = 0
1612 nump1prev = 0
1613 nump2prev = 0
1613 nump2prev = 0
1614 chainlengths = []
1614 chainlengths = []
1615
1615
1616 datasize = [None, 0, 0]
1616 datasize = [None, 0, 0]
1617 fullsize = [None, 0, 0]
1617 fullsize = [None, 0, 0]
1618 deltasize = [None, 0, 0]
1618 deltasize = [None, 0, 0]
1619 chunktypecounts = {}
1619 chunktypecounts = {}
1620 chunktypesizes = {}
1620 chunktypesizes = {}
1621
1621
1622 def addsize(size, l):
1622 def addsize(size, l):
1623 if l[0] is None or size < l[0]:
1623 if l[0] is None or size < l[0]:
1624 l[0] = size
1624 l[0] = size
1625 if size > l[1]:
1625 if size > l[1]:
1626 l[1] = size
1626 l[1] = size
1627 l[2] += size
1627 l[2] += size
1628
1628
1629 numrevs = len(r)
1629 numrevs = len(r)
1630 for rev in xrange(numrevs):
1630 for rev in xrange(numrevs):
1631 p1, p2 = r.parentrevs(rev)
1631 p1, p2 = r.parentrevs(rev)
1632 delta = r.deltaparent(rev)
1632 delta = r.deltaparent(rev)
1633 if format > 0:
1633 if format > 0:
1634 addsize(r.rawsize(rev), datasize)
1634 addsize(r.rawsize(rev), datasize)
1635 if p2 != nullrev:
1635 if p2 != nullrev:
1636 nummerges += 1
1636 nummerges += 1
1637 size = r.length(rev)
1637 size = r.length(rev)
1638 if delta == nullrev:
1638 if delta == nullrev:
1639 chainlengths.append(0)
1639 chainlengths.append(0)
1640 numfull += 1
1640 numfull += 1
1641 addsize(size, fullsize)
1641 addsize(size, fullsize)
1642 else:
1642 else:
1643 chainlengths.append(chainlengths[delta] + 1)
1643 chainlengths.append(chainlengths[delta] + 1)
1644 addsize(size, deltasize)
1644 addsize(size, deltasize)
1645 if delta == rev - 1:
1645 if delta == rev - 1:
1646 numprev += 1
1646 numprev += 1
1647 if delta == p1:
1647 if delta == p1:
1648 nump1prev += 1
1648 nump1prev += 1
1649 elif delta == p2:
1649 elif delta == p2:
1650 nump2prev += 1
1650 nump2prev += 1
1651 elif delta == p1:
1651 elif delta == p1:
1652 nump1 += 1
1652 nump1 += 1
1653 elif delta == p2:
1653 elif delta == p2:
1654 nump2 += 1
1654 nump2 += 1
1655 elif delta != nullrev:
1655 elif delta != nullrev:
1656 numother += 1
1656 numother += 1
1657
1657
1658 # Obtain data on the raw chunks in the revlog.
1658 # Obtain data on the raw chunks in the revlog.
1659 chunk = r._chunkraw(rev, rev)[1]
1659 chunk = r._chunkraw(rev, rev)[1]
1660 if chunk:
1660 if chunk:
1661 chunktype = chunk[0]
1661 chunktype = chunk[0]
1662 else:
1662 else:
1663 chunktype = 'empty'
1663 chunktype = 'empty'
1664
1664
1665 if chunktype not in chunktypecounts:
1665 if chunktype not in chunktypecounts:
1666 chunktypecounts[chunktype] = 0
1666 chunktypecounts[chunktype] = 0
1667 chunktypesizes[chunktype] = 0
1667 chunktypesizes[chunktype] = 0
1668
1668
1669 chunktypecounts[chunktype] += 1
1669 chunktypecounts[chunktype] += 1
1670 chunktypesizes[chunktype] += size
1670 chunktypesizes[chunktype] += size
1671
1671
1672 # Adjust size min value for empty cases
1672 # Adjust size min value for empty cases
1673 for size in (datasize, fullsize, deltasize):
1673 for size in (datasize, fullsize, deltasize):
1674 if size[0] is None:
1674 if size[0] is None:
1675 size[0] = 0
1675 size[0] = 0
1676
1676
1677 numdeltas = numrevs - numfull
1677 numdeltas = numrevs - numfull
1678 numoprev = numprev - nump1prev - nump2prev
1678 numoprev = numprev - nump1prev - nump2prev
1679 totalrawsize = datasize[2]
1679 totalrawsize = datasize[2]
1680 datasize[2] /= numrevs
1680 datasize[2] /= numrevs
1681 fulltotal = fullsize[2]
1681 fulltotal = fullsize[2]
1682 fullsize[2] /= numfull
1682 fullsize[2] /= numfull
1683 deltatotal = deltasize[2]
1683 deltatotal = deltasize[2]
1684 if numrevs - numfull > 0:
1684 if numrevs - numfull > 0:
1685 deltasize[2] /= numrevs - numfull
1685 deltasize[2] /= numrevs - numfull
1686 totalsize = fulltotal + deltatotal
1686 totalsize = fulltotal + deltatotal
1687 avgchainlen = sum(chainlengths) / numrevs
1687 avgchainlen = sum(chainlengths) / numrevs
1688 maxchainlen = max(chainlengths)
1688 maxchainlen = max(chainlengths)
1689 compratio = 1
1689 compratio = 1
1690 if totalsize:
1690 if totalsize:
1691 compratio = totalrawsize / totalsize
1691 compratio = totalrawsize / totalsize
1692
1692
1693 basedfmtstr = '%%%dd\n'
1693 basedfmtstr = '%%%dd\n'
1694 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1694 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1695
1695
1696 def dfmtstr(max):
1696 def dfmtstr(max):
1697 return basedfmtstr % len(str(max))
1697 return basedfmtstr % len(str(max))
1698 def pcfmtstr(max, padding=0):
1698 def pcfmtstr(max, padding=0):
1699 return basepcfmtstr % (len(str(max)), ' ' * padding)
1699 return basepcfmtstr % (len(str(max)), ' ' * padding)
1700
1700
1701 def pcfmt(value, total):
1701 def pcfmt(value, total):
1702 if total:
1702 if total:
1703 return (value, 100 * float(value) / total)
1703 return (value, 100 * float(value) / total)
1704 else:
1704 else:
1705 return value, 100.0
1705 return value, 100.0
1706
1706
1707 ui.write(('format : %d\n') % format)
1707 ui.write(('format : %d\n') % format)
1708 ui.write(('flags : %s\n') % ', '.join(flags))
1708 ui.write(('flags : %s\n') % ', '.join(flags))
1709
1709
1710 ui.write('\n')
1710 ui.write('\n')
1711 fmt = pcfmtstr(totalsize)
1711 fmt = pcfmtstr(totalsize)
1712 fmt2 = dfmtstr(totalsize)
1712 fmt2 = dfmtstr(totalsize)
1713 ui.write(('revisions : ') + fmt2 % numrevs)
1713 ui.write(('revisions : ') + fmt2 % numrevs)
1714 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1714 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1715 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1715 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1716 ui.write(('revisions : ') + fmt2 % numrevs)
1716 ui.write(('revisions : ') + fmt2 % numrevs)
1717 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1717 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1718 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1718 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1719 ui.write(('revision size : ') + fmt2 % totalsize)
1719 ui.write(('revision size : ') + fmt2 % totalsize)
1720 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1720 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1721 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1721 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1722
1722
1723 def fmtchunktype(chunktype):
1723 def fmtchunktype(chunktype):
1724 if chunktype == 'empty':
1724 if chunktype == 'empty':
1725 return ' %s : ' % chunktype
1725 return ' %s : ' % chunktype
1726 elif chunktype in string.ascii_letters:
1726 elif chunktype in string.ascii_letters:
1727 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1727 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1728 else:
1728 else:
1729 return ' 0x%s : ' % hex(chunktype)
1729 return ' 0x%s : ' % hex(chunktype)
1730
1730
1731 ui.write('\n')
1731 ui.write('\n')
1732 ui.write(('chunks : ') + fmt2 % numrevs)
1732 ui.write(('chunks : ') + fmt2 % numrevs)
1733 for chunktype in sorted(chunktypecounts):
1733 for chunktype in sorted(chunktypecounts):
1734 ui.write(fmtchunktype(chunktype))
1734 ui.write(fmtchunktype(chunktype))
1735 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1735 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1736 ui.write(('chunks size : ') + fmt2 % totalsize)
1736 ui.write(('chunks size : ') + fmt2 % totalsize)
1737 for chunktype in sorted(chunktypecounts):
1737 for chunktype in sorted(chunktypecounts):
1738 ui.write(fmtchunktype(chunktype))
1738 ui.write(fmtchunktype(chunktype))
1739 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1739 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1740
1740
1741 ui.write('\n')
1741 ui.write('\n')
1742 fmt = dfmtstr(max(avgchainlen, compratio))
1742 fmt = dfmtstr(max(avgchainlen, compratio))
1743 ui.write(('avg chain length : ') + fmt % avgchainlen)
1743 ui.write(('avg chain length : ') + fmt % avgchainlen)
1744 ui.write(('max chain length : ') + fmt % maxchainlen)
1744 ui.write(('max chain length : ') + fmt % maxchainlen)
1745 ui.write(('compression ratio : ') + fmt % compratio)
1745 ui.write(('compression ratio : ') + fmt % compratio)
1746
1746
1747 if format > 0:
1747 if format > 0:
1748 ui.write('\n')
1748 ui.write('\n')
1749 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1749 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1750 % tuple(datasize))
1750 % tuple(datasize))
1751 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1751 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1752 % tuple(fullsize))
1752 % tuple(fullsize))
1753 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1753 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1754 % tuple(deltasize))
1754 % tuple(deltasize))
1755
1755
1756 if numdeltas > 0:
1756 if numdeltas > 0:
1757 ui.write('\n')
1757 ui.write('\n')
1758 fmt = pcfmtstr(numdeltas)
1758 fmt = pcfmtstr(numdeltas)
1759 fmt2 = pcfmtstr(numdeltas, 4)
1759 fmt2 = pcfmtstr(numdeltas, 4)
1760 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1760 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1761 if numprev > 0:
1761 if numprev > 0:
1762 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1762 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1763 numprev))
1763 numprev))
1764 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1764 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1765 numprev))
1765 numprev))
1766 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1766 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1767 numprev))
1767 numprev))
1768 if gdelta:
1768 if gdelta:
1769 ui.write(('deltas against p1 : ')
1769 ui.write(('deltas against p1 : ')
1770 + fmt % pcfmt(nump1, numdeltas))
1770 + fmt % pcfmt(nump1, numdeltas))
1771 ui.write(('deltas against p2 : ')
1771 ui.write(('deltas against p2 : ')
1772 + fmt % pcfmt(nump2, numdeltas))
1772 + fmt % pcfmt(nump2, numdeltas))
1773 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1773 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1774 numdeltas))
1774 numdeltas))
1775
1775
1776 @command('debugrevspec',
1776 @command('debugrevspec',
1777 [('', 'optimize', None,
1777 [('', 'optimize', None,
1778 _('print parsed tree after optimizing (DEPRECATED)')),
1778 _('print parsed tree after optimizing (DEPRECATED)')),
1779 ('p', 'show-stage', [],
1779 ('p', 'show-stage', [],
1780 _('print parsed tree at the given stage'), _('NAME')),
1780 _('print parsed tree at the given stage'), _('NAME')),
1781 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1781 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1782 ('', 'verify-optimized', False, _('verify optimized result')),
1782 ('', 'verify-optimized', False, _('verify optimized result')),
1783 ],
1783 ],
1784 ('REVSPEC'))
1784 ('REVSPEC'))
1785 def debugrevspec(ui, repo, expr, **opts):
1785 def debugrevspec(ui, repo, expr, **opts):
1786 """parse and apply a revision specification
1786 """parse and apply a revision specification
1787
1787
1788 Use -p/--show-stage option to print the parsed tree at the given stages.
1788 Use -p/--show-stage option to print the parsed tree at the given stages.
1789 Use -p all to print tree at every stage.
1789 Use -p all to print tree at every stage.
1790
1790
1791 Use --verify-optimized to compare the optimized result with the unoptimized
1791 Use --verify-optimized to compare the optimized result with the unoptimized
1792 one. Returns 1 if the optimized result differs.
1792 one. Returns 1 if the optimized result differs.
1793 """
1793 """
1794 stages = [
1794 stages = [
1795 ('parsed', lambda tree: tree),
1795 ('parsed', lambda tree: tree),
1796 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1796 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1797 ('concatenated', revset.foldconcat),
1797 ('concatenated', revset.foldconcat),
1798 ('analyzed', revset.analyze),
1798 ('analyzed', revset.analyze),
1799 ('optimized', revset.optimize),
1799 ('optimized', revset.optimize),
1800 ]
1800 ]
1801 if opts['no_optimized']:
1801 if opts['no_optimized']:
1802 stages = stages[:-1]
1802 stages = stages[:-1]
1803 if opts['verify_optimized'] and opts['no_optimized']:
1803 if opts['verify_optimized'] and opts['no_optimized']:
1804 raise error.Abort(_('cannot use --verify-optimized with '
1804 raise error.Abort(_('cannot use --verify-optimized with '
1805 '--no-optimized'))
1805 '--no-optimized'))
1806 stagenames = set(n for n, f in stages)
1806 stagenames = set(n for n, f in stages)
1807
1807
1808 showalways = set()
1808 showalways = set()
1809 showchanged = set()
1809 showchanged = set()
1810 if ui.verbose and not opts['show_stage']:
1810 if ui.verbose and not opts['show_stage']:
1811 # show parsed tree by --verbose (deprecated)
1811 # show parsed tree by --verbose (deprecated)
1812 showalways.add('parsed')
1812 showalways.add('parsed')
1813 showchanged.update(['expanded', 'concatenated'])
1813 showchanged.update(['expanded', 'concatenated'])
1814 if opts['optimize']:
1814 if opts['optimize']:
1815 showalways.add('optimized')
1815 showalways.add('optimized')
1816 if opts['show_stage'] and opts['optimize']:
1816 if opts['show_stage'] and opts['optimize']:
1817 raise error.Abort(_('cannot use --optimize with --show-stage'))
1817 raise error.Abort(_('cannot use --optimize with --show-stage'))
1818 if opts['show_stage'] == ['all']:
1818 if opts['show_stage'] == ['all']:
1819 showalways.update(stagenames)
1819 showalways.update(stagenames)
1820 else:
1820 else:
1821 for n in opts['show_stage']:
1821 for n in opts['show_stage']:
1822 if n not in stagenames:
1822 if n not in stagenames:
1823 raise error.Abort(_('invalid stage name: %s') % n)
1823 raise error.Abort(_('invalid stage name: %s') % n)
1824 showalways.update(opts['show_stage'])
1824 showalways.update(opts['show_stage'])
1825
1825
1826 treebystage = {}
1826 treebystage = {}
1827 printedtree = None
1827 printedtree = None
1828 tree = revset.parse(expr, lookup=repo.__contains__)
1828 tree = revset.parse(expr, lookup=repo.__contains__)
1829 for n, f in stages:
1829 for n, f in stages:
1830 treebystage[n] = tree = f(tree)
1830 treebystage[n] = tree = f(tree)
1831 if n in showalways or (n in showchanged and tree != printedtree):
1831 if n in showalways or (n in showchanged and tree != printedtree):
1832 if opts['show_stage'] or n != 'parsed':
1832 if opts['show_stage'] or n != 'parsed':
1833 ui.write(("* %s:\n") % n)
1833 ui.write(("* %s:\n") % n)
1834 ui.write(revset.prettyformat(tree), "\n")
1834 ui.write(revset.prettyformat(tree), "\n")
1835 printedtree = tree
1835 printedtree = tree
1836
1836
1837 if opts['verify_optimized']:
1837 if opts['verify_optimized']:
1838 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1838 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1839 brevs = revset.makematcher(treebystage['optimized'])(repo)
1839 brevs = revset.makematcher(treebystage['optimized'])(repo)
1840 if ui.verbose:
1840 if ui.verbose:
1841 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1841 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1842 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1842 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1843 arevs = list(arevs)
1843 arevs = list(arevs)
1844 brevs = list(brevs)
1844 brevs = list(brevs)
1845 if arevs == brevs:
1845 if arevs == brevs:
1846 return 0
1846 return 0
1847 ui.write(('--- analyzed\n'), label='diff.file_a')
1847 ui.write(('--- analyzed\n'), label='diff.file_a')
1848 ui.write(('+++ optimized\n'), label='diff.file_b')
1848 ui.write(('+++ optimized\n'), label='diff.file_b')
1849 sm = difflib.SequenceMatcher(None, arevs, brevs)
1849 sm = difflib.SequenceMatcher(None, arevs, brevs)
1850 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1850 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1851 if tag in ('delete', 'replace'):
1851 if tag in ('delete', 'replace'):
1852 for c in arevs[alo:ahi]:
1852 for c in arevs[alo:ahi]:
1853 ui.write('-%s\n' % c, label='diff.deleted')
1853 ui.write('-%s\n' % c, label='diff.deleted')
1854 if tag in ('insert', 'replace'):
1854 if tag in ('insert', 'replace'):
1855 for c in brevs[blo:bhi]:
1855 for c in brevs[blo:bhi]:
1856 ui.write('+%s\n' % c, label='diff.inserted')
1856 ui.write('+%s\n' % c, label='diff.inserted')
1857 if tag == 'equal':
1857 if tag == 'equal':
1858 for c in arevs[alo:ahi]:
1858 for c in arevs[alo:ahi]:
1859 ui.write(' %s\n' % c)
1859 ui.write(' %s\n' % c)
1860 return 1
1860 return 1
1861
1861
1862 func = revset.makematcher(tree)
1862 func = revset.makematcher(tree)
1863 revs = func(repo)
1863 revs = func(repo)
1864 if ui.verbose:
1864 if ui.verbose:
1865 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1865 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1866 for c in revs:
1866 for c in revs:
1867 ui.write("%s\n" % c)
1867 ui.write("%s\n" % c)
1868
1868
1869 @command('debugsetparents', [], _('REV1 [REV2]'))
1869 @command('debugsetparents', [], _('REV1 [REV2]'))
1870 def debugsetparents(ui, repo, rev1, rev2=None):
1870 def debugsetparents(ui, repo, rev1, rev2=None):
1871 """manually set the parents of the current working directory
1871 """manually set the parents of the current working directory
1872
1872
1873 This is useful for writing repository conversion tools, but should
1873 This is useful for writing repository conversion tools, but should
1874 be used with care. For example, neither the working directory nor the
1874 be used with care. For example, neither the working directory nor the
1875 dirstate is updated, so file status may be incorrect after running this
1875 dirstate is updated, so file status may be incorrect after running this
1876 command.
1876 command.
1877
1877
1878 Returns 0 on success.
1878 Returns 0 on success.
1879 """
1879 """
1880
1880
1881 r1 = scmutil.revsingle(repo, rev1).node()
1881 r1 = scmutil.revsingle(repo, rev1).node()
1882 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1882 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1883
1883
1884 with repo.wlock():
1884 with repo.wlock():
1885 repo.setparents(r1, r2)
1885 repo.setparents(r1, r2)
1886
1886
1887 @command('debugsub',
1887 @command('debugsub',
1888 [('r', 'rev', '',
1888 [('r', 'rev', '',
1889 _('revision to check'), _('REV'))],
1889 _('revision to check'), _('REV'))],
1890 _('[-r REV] [REV]'))
1890 _('[-r REV] [REV]'))
1891 def debugsub(ui, repo, rev=None):
1891 def debugsub(ui, repo, rev=None):
1892 ctx = scmutil.revsingle(repo, rev, None)
1892 ctx = scmutil.revsingle(repo, rev, None)
1893 for k, v in sorted(ctx.substate.items()):
1893 for k, v in sorted(ctx.substate.items()):
1894 ui.write(('path %s\n') % k)
1894 ui.write(('path %s\n') % k)
1895 ui.write((' source %s\n') % v[0])
1895 ui.write((' source %s\n') % v[0])
1896 ui.write((' revision %s\n') % v[1])
1896 ui.write((' revision %s\n') % v[1])
1897
1897
1898 @command('debugsuccessorssets',
1899 [],
1900 _('[REV]'))
1901 def debugsuccessorssets(ui, repo, *revs):
1902 """show set of successors for revision
1903
1904 A successors set of changeset A is a consistent group of revisions that
1905 succeed A. It contains non-obsolete changesets only.
1906
1907 In most cases a changeset A has a single successors set containing a single
1908 successor (changeset A replaced by A').
1909
1910 A changeset that is made obsolete with no successors are called "pruned".
1911 Such changesets have no successors sets at all.
1912
1913 A changeset that has been "split" will have a successors set containing
1914 more than one successor.
1915
1916 A changeset that has been rewritten in multiple different ways is called
1917 "divergent". Such changesets have multiple successor sets (each of which
1918 may also be split, i.e. have multiple successors).
1919
1920 Results are displayed as follows::
1921
1922 <rev1>
1923 <successors-1A>
1924 <rev2>
1925 <successors-2A>
1926 <successors-2B1> <successors-2B2> <successors-2B3>
1927
1928 Here rev2 has two possible (i.e. divergent) successors sets. The first
1929 holds one element, whereas the second holds three (i.e. the changeset has
1930 been split).
1931 """
1932 # passed to successorssets caching computation from one call to another
1933 cache = {}
1934 ctx2str = str
1935 node2str = short
1936 if ui.debug():
1937 def ctx2str(ctx):
1938 return ctx.hex()
1939 node2str = hex
1940 for rev in scmutil.revrange(repo, revs):
1941 ctx = repo[rev]
1942 ui.write('%s\n'% ctx2str(ctx))
1943 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
1944 if succsset:
1945 ui.write(' ')
1946 ui.write(node2str(succsset[0]))
1947 for node in succsset[1:]:
1948 ui.write(' ')
1949 ui.write(node2str(node))
1950 ui.write('\n')
1951
1898 @command('debugupgraderepo', [
1952 @command('debugupgraderepo', [
1899 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1953 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1900 ('', 'run', False, _('performs an upgrade')),
1954 ('', 'run', False, _('performs an upgrade')),
1901 ])
1955 ])
1902 def debugupgraderepo(ui, repo, run=False, optimize=None):
1956 def debugupgraderepo(ui, repo, run=False, optimize=None):
1903 """upgrade a repository to use different features
1957 """upgrade a repository to use different features
1904
1958
1905 If no arguments are specified, the repository is evaluated for upgrade
1959 If no arguments are specified, the repository is evaluated for upgrade
1906 and a list of problems and potential optimizations is printed.
1960 and a list of problems and potential optimizations is printed.
1907
1961
1908 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1962 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1909 can be influenced via additional arguments. More details will be provided
1963 can be influenced via additional arguments. More details will be provided
1910 by the command output when run without ``--run``.
1964 by the command output when run without ``--run``.
1911
1965
1912 During the upgrade, the repository will be locked and no writes will be
1966 During the upgrade, the repository will be locked and no writes will be
1913 allowed.
1967 allowed.
1914
1968
1915 At the end of the upgrade, the repository may not be readable while new
1969 At the end of the upgrade, the repository may not be readable while new
1916 repository data is swapped in. This window will be as long as it takes to
1970 repository data is swapped in. This window will be as long as it takes to
1917 rename some directories inside the ``.hg`` directory. On most machines, this
1971 rename some directories inside the ``.hg`` directory. On most machines, this
1918 should complete almost instantaneously and the chances of a consumer being
1972 should complete almost instantaneously and the chances of a consumer being
1919 unable to access the repository should be low.
1973 unable to access the repository should be low.
1920 """
1974 """
1921 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1975 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now