##// END OF EJS Templates
help: remove now-redundant pointer to revsets help...
Martin von Zweigbergk -
r30785:301512fd default
parent child Browse files
Show More
@@ -1,6621 +1,6620 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import socket
14 import socket
15 import string
15 import string
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import time
18 import time
19
19
20 from .i18n import _
20 from .i18n import _
21 from .node import (
21 from .node import (
22 bin,
22 bin,
23 hex,
23 hex,
24 nullhex,
24 nullhex,
25 nullid,
25 nullid,
26 nullrev,
26 nullrev,
27 short,
27 short,
28 )
28 )
29 from . import (
29 from . import (
30 archival,
30 archival,
31 bookmarks,
31 bookmarks,
32 bundle2,
32 bundle2,
33 changegroup,
33 changegroup,
34 cmdutil,
34 cmdutil,
35 copies,
35 copies,
36 destutil,
36 destutil,
37 dirstateguard,
37 dirstateguard,
38 discovery,
38 discovery,
39 encoding,
39 encoding,
40 error,
40 error,
41 exchange,
41 exchange,
42 extensions,
42 extensions,
43 formatter,
43 formatter,
44 graphmod,
44 graphmod,
45 hbisect,
45 hbisect,
46 help,
46 help,
47 hg,
47 hg,
48 lock as lockmod,
48 lock as lockmod,
49 merge as mergemod,
49 merge as mergemod,
50 minirst,
50 minirst,
51 obsolete,
51 obsolete,
52 patch,
52 patch,
53 phases,
53 phases,
54 policy,
54 policy,
55 pvec,
55 pvec,
56 pycompat,
56 pycompat,
57 repair,
57 repair,
58 revlog,
58 revlog,
59 revset,
59 revset,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 sshserver,
62 sshserver,
63 sslutil,
63 sslutil,
64 streamclone,
64 streamclone,
65 templatekw,
65 templatekw,
66 templater,
66 templater,
67 ui as uimod,
67 ui as uimod,
68 util,
68 util,
69 )
69 )
70
70
71 release = lockmod.release
71 release = lockmod.release
72
72
73 table = {}
73 table = {}
74
74
75 command = cmdutil.command(table)
75 command = cmdutil.command(table)
76
76
77 # label constants
77 # label constants
78 # until 3.5, bookmarks.current was the advertised name, not
78 # until 3.5, bookmarks.current was the advertised name, not
79 # bookmarks.active, so we must use both to avoid breaking old
79 # bookmarks.active, so we must use both to avoid breaking old
80 # custom styles
80 # custom styles
81 activebookmarklabel = 'bookmarks.active bookmarks.current'
81 activebookmarklabel = 'bookmarks.active bookmarks.current'
82
82
83 # common command options
83 # common command options
84
84
85 globalopts = [
85 globalopts = [
86 ('R', 'repository', '',
86 ('R', 'repository', '',
87 _('repository root directory or name of overlay bundle file'),
87 _('repository root directory or name of overlay bundle file'),
88 _('REPO')),
88 _('REPO')),
89 ('', 'cwd', '',
89 ('', 'cwd', '',
90 _('change working directory'), _('DIR')),
90 _('change working directory'), _('DIR')),
91 ('y', 'noninteractive', None,
91 ('y', 'noninteractive', None,
92 _('do not prompt, automatically pick the first choice for all prompts')),
92 _('do not prompt, automatically pick the first choice for all prompts')),
93 ('q', 'quiet', None, _('suppress output')),
93 ('q', 'quiet', None, _('suppress output')),
94 ('v', 'verbose', None, _('enable additional output')),
94 ('v', 'verbose', None, _('enable additional output')),
95 ('', 'config', [],
95 ('', 'config', [],
96 _('set/override config option (use \'section.name=value\')'),
96 _('set/override config option (use \'section.name=value\')'),
97 _('CONFIG')),
97 _('CONFIG')),
98 ('', 'debug', None, _('enable debugging output')),
98 ('', 'debug', None, _('enable debugging output')),
99 ('', 'debugger', None, _('start debugger')),
99 ('', 'debugger', None, _('start debugger')),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
100 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
101 _('ENCODE')),
101 _('ENCODE')),
102 ('', 'encodingmode', encoding.encodingmode,
102 ('', 'encodingmode', encoding.encodingmode,
103 _('set the charset encoding mode'), _('MODE')),
103 _('set the charset encoding mode'), _('MODE')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
104 ('', 'traceback', None, _('always print a traceback on exception')),
105 ('', 'time', None, _('time how long the command takes')),
105 ('', 'time', None, _('time how long the command takes')),
106 ('', 'profile', None, _('print command execution profile')),
106 ('', 'profile', None, _('print command execution profile')),
107 ('', 'version', None, _('output version information and exit')),
107 ('', 'version', None, _('output version information and exit')),
108 ('h', 'help', None, _('display help and exit')),
108 ('h', 'help', None, _('display help and exit')),
109 ('', 'hidden', False, _('consider hidden changesets')),
109 ('', 'hidden', False, _('consider hidden changesets')),
110 ]
110 ]
111
111
112 dryrunopts = [('n', 'dry-run', None,
112 dryrunopts = [('n', 'dry-run', None,
113 _('do not perform actions, just print output'))]
113 _('do not perform actions, just print output'))]
114
114
115 remoteopts = [
115 remoteopts = [
116 ('e', 'ssh', '',
116 ('e', 'ssh', '',
117 _('specify ssh command to use'), _('CMD')),
117 _('specify ssh command to use'), _('CMD')),
118 ('', 'remotecmd', '',
118 ('', 'remotecmd', '',
119 _('specify hg command to run on the remote side'), _('CMD')),
119 _('specify hg command to run on the remote side'), _('CMD')),
120 ('', 'insecure', None,
120 ('', 'insecure', None,
121 _('do not verify server certificate (ignoring web.cacerts config)')),
121 _('do not verify server certificate (ignoring web.cacerts config)')),
122 ]
122 ]
123
123
124 walkopts = [
124 walkopts = [
125 ('I', 'include', [],
125 ('I', 'include', [],
126 _('include names matching the given patterns'), _('PATTERN')),
126 _('include names matching the given patterns'), _('PATTERN')),
127 ('X', 'exclude', [],
127 ('X', 'exclude', [],
128 _('exclude names matching the given patterns'), _('PATTERN')),
128 _('exclude names matching the given patterns'), _('PATTERN')),
129 ]
129 ]
130
130
131 commitopts = [
131 commitopts = [
132 ('m', 'message', '',
132 ('m', 'message', '',
133 _('use text as commit message'), _('TEXT')),
133 _('use text as commit message'), _('TEXT')),
134 ('l', 'logfile', '',
134 ('l', 'logfile', '',
135 _('read commit message from file'), _('FILE')),
135 _('read commit message from file'), _('FILE')),
136 ]
136 ]
137
137
138 commitopts2 = [
138 commitopts2 = [
139 ('d', 'date', '',
139 ('d', 'date', '',
140 _('record the specified date as commit date'), _('DATE')),
140 _('record the specified date as commit date'), _('DATE')),
141 ('u', 'user', '',
141 ('u', 'user', '',
142 _('record the specified user as committer'), _('USER')),
142 _('record the specified user as committer'), _('USER')),
143 ]
143 ]
144
144
145 # hidden for now
145 # hidden for now
146 formatteropts = [
146 formatteropts = [
147 ('T', 'template', '',
147 ('T', 'template', '',
148 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
148 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
149 ]
149 ]
150
150
151 templateopts = [
151 templateopts = [
152 ('', 'style', '',
152 ('', 'style', '',
153 _('display using template map file (DEPRECATED)'), _('STYLE')),
153 _('display using template map file (DEPRECATED)'), _('STYLE')),
154 ('T', 'template', '',
154 ('T', 'template', '',
155 _('display with template'), _('TEMPLATE')),
155 _('display with template'), _('TEMPLATE')),
156 ]
156 ]
157
157
158 logopts = [
158 logopts = [
159 ('p', 'patch', None, _('show patch')),
159 ('p', 'patch', None, _('show patch')),
160 ('g', 'git', None, _('use git extended diff format')),
160 ('g', 'git', None, _('use git extended diff format')),
161 ('l', 'limit', '',
161 ('l', 'limit', '',
162 _('limit number of changes displayed'), _('NUM')),
162 _('limit number of changes displayed'), _('NUM')),
163 ('M', 'no-merges', None, _('do not show merges')),
163 ('M', 'no-merges', None, _('do not show merges')),
164 ('', 'stat', None, _('output diffstat-style summary of changes')),
164 ('', 'stat', None, _('output diffstat-style summary of changes')),
165 ('G', 'graph', None, _("show the revision DAG")),
165 ('G', 'graph', None, _("show the revision DAG")),
166 ] + templateopts
166 ] + templateopts
167
167
168 diffopts = [
168 diffopts = [
169 ('a', 'text', None, _('treat all files as text')),
169 ('a', 'text', None, _('treat all files as text')),
170 ('g', 'git', None, _('use git extended diff format')),
170 ('g', 'git', None, _('use git extended diff format')),
171 ('', 'nodates', None, _('omit dates from diff headers'))
171 ('', 'nodates', None, _('omit dates from diff headers'))
172 ]
172 ]
173
173
174 diffwsopts = [
174 diffwsopts = [
175 ('w', 'ignore-all-space', None,
175 ('w', 'ignore-all-space', None,
176 _('ignore white space when comparing lines')),
176 _('ignore white space when comparing lines')),
177 ('b', 'ignore-space-change', None,
177 ('b', 'ignore-space-change', None,
178 _('ignore changes in the amount of white space')),
178 _('ignore changes in the amount of white space')),
179 ('B', 'ignore-blank-lines', None,
179 ('B', 'ignore-blank-lines', None,
180 _('ignore changes whose lines are all blank')),
180 _('ignore changes whose lines are all blank')),
181 ]
181 ]
182
182
183 diffopts2 = [
183 diffopts2 = [
184 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
184 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
185 ('p', 'show-function', None, _('show which function each change is in')),
185 ('p', 'show-function', None, _('show which function each change is in')),
186 ('', 'reverse', None, _('produce a diff that undoes the changes')),
186 ('', 'reverse', None, _('produce a diff that undoes the changes')),
187 ] + diffwsopts + [
187 ] + diffwsopts + [
188 ('U', 'unified', '',
188 ('U', 'unified', '',
189 _('number of lines of context to show'), _('NUM')),
189 _('number of lines of context to show'), _('NUM')),
190 ('', 'stat', None, _('output diffstat-style summary of changes')),
190 ('', 'stat', None, _('output diffstat-style summary of changes')),
191 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
191 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
192 ]
192 ]
193
193
194 mergetoolopts = [
194 mergetoolopts = [
195 ('t', 'tool', '', _('specify merge tool')),
195 ('t', 'tool', '', _('specify merge tool')),
196 ]
196 ]
197
197
198 similarityopts = [
198 similarityopts = [
199 ('s', 'similarity', '',
199 ('s', 'similarity', '',
200 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
200 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
201 ]
201 ]
202
202
203 subrepoopts = [
203 subrepoopts = [
204 ('S', 'subrepos', None,
204 ('S', 'subrepos', None,
205 _('recurse into subrepositories'))
205 _('recurse into subrepositories'))
206 ]
206 ]
207
207
208 debugrevlogopts = [
208 debugrevlogopts = [
209 ('c', 'changelog', False, _('open changelog')),
209 ('c', 'changelog', False, _('open changelog')),
210 ('m', 'manifest', False, _('open manifest')),
210 ('m', 'manifest', False, _('open manifest')),
211 ('', 'dir', '', _('open directory manifest')),
211 ('', 'dir', '', _('open directory manifest')),
212 ]
212 ]
213
213
214 # Commands start here, listed alphabetically
214 # Commands start here, listed alphabetically
215
215
216 @command('^add',
216 @command('^add',
217 walkopts + subrepoopts + dryrunopts,
217 walkopts + subrepoopts + dryrunopts,
218 _('[OPTION]... [FILE]...'),
218 _('[OPTION]... [FILE]...'),
219 inferrepo=True)
219 inferrepo=True)
220 def add(ui, repo, *pats, **opts):
220 def add(ui, repo, *pats, **opts):
221 """add the specified files on the next commit
221 """add the specified files on the next commit
222
222
223 Schedule files to be version controlled and added to the
223 Schedule files to be version controlled and added to the
224 repository.
224 repository.
225
225
226 The files will be added to the repository at the next commit. To
226 The files will be added to the repository at the next commit. To
227 undo an add before that, see :hg:`forget`.
227 undo an add before that, see :hg:`forget`.
228
228
229 If no names are given, add all files to the repository (except
229 If no names are given, add all files to the repository (except
230 files matching ``.hgignore``).
230 files matching ``.hgignore``).
231
231
232 .. container:: verbose
232 .. container:: verbose
233
233
234 Examples:
234 Examples:
235
235
236 - New (unknown) files are added
236 - New (unknown) files are added
237 automatically by :hg:`add`::
237 automatically by :hg:`add`::
238
238
239 $ ls
239 $ ls
240 foo.c
240 foo.c
241 $ hg status
241 $ hg status
242 ? foo.c
242 ? foo.c
243 $ hg add
243 $ hg add
244 adding foo.c
244 adding foo.c
245 $ hg status
245 $ hg status
246 A foo.c
246 A foo.c
247
247
248 - Specific files to be added can be specified::
248 - Specific files to be added can be specified::
249
249
250 $ ls
250 $ ls
251 bar.c foo.c
251 bar.c foo.c
252 $ hg status
252 $ hg status
253 ? bar.c
253 ? bar.c
254 ? foo.c
254 ? foo.c
255 $ hg add bar.c
255 $ hg add bar.c
256 $ hg status
256 $ hg status
257 A bar.c
257 A bar.c
258 ? foo.c
258 ? foo.c
259
259
260 Returns 0 if all files are successfully added.
260 Returns 0 if all files are successfully added.
261 """
261 """
262
262
263 m = scmutil.match(repo[None], pats, opts)
263 m = scmutil.match(repo[None], pats, opts)
264 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
264 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
265 return rejected and 1 or 0
265 return rejected and 1 or 0
266
266
267 @command('addremove',
267 @command('addremove',
268 similarityopts + subrepoopts + walkopts + dryrunopts,
268 similarityopts + subrepoopts + walkopts + dryrunopts,
269 _('[OPTION]... [FILE]...'),
269 _('[OPTION]... [FILE]...'),
270 inferrepo=True)
270 inferrepo=True)
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 try:
333 try:
334 sim = float(opts.get('similarity') or 100)
334 sim = float(opts.get('similarity') or 100)
335 except ValueError:
335 except ValueError:
336 raise error.Abort(_('similarity must be a number'))
336 raise error.Abort(_('similarity must be a number'))
337 if sim < 0 or sim > 100:
337 if sim < 0 or sim > 100:
338 raise error.Abort(_('similarity must be between 0 and 100'))
338 raise error.Abort(_('similarity must be between 0 and 100'))
339 matcher = scmutil.match(repo[None], pats, opts)
339 matcher = scmutil.match(repo[None], pats, opts)
340 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
340 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
341
341
342 @command('^annotate|blame',
342 @command('^annotate|blame',
343 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
343 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
344 ('', 'follow', None,
344 ('', 'follow', None,
345 _('follow copies/renames and list the filename (DEPRECATED)')),
345 _('follow copies/renames and list the filename (DEPRECATED)')),
346 ('', 'no-follow', None, _("don't follow copies and renames")),
346 ('', 'no-follow', None, _("don't follow copies and renames")),
347 ('a', 'text', None, _('treat all files as text')),
347 ('a', 'text', None, _('treat all files as text')),
348 ('u', 'user', None, _('list the author (long with -v)')),
348 ('u', 'user', None, _('list the author (long with -v)')),
349 ('f', 'file', None, _('list the filename')),
349 ('f', 'file', None, _('list the filename')),
350 ('d', 'date', None, _('list the date (short with -q)')),
350 ('d', 'date', None, _('list the date (short with -q)')),
351 ('n', 'number', None, _('list the revision number (default)')),
351 ('n', 'number', None, _('list the revision number (default)')),
352 ('c', 'changeset', None, _('list the changeset')),
352 ('c', 'changeset', None, _('list the changeset')),
353 ('l', 'line-number', None, _('show line number at the first appearance'))
353 ('l', 'line-number', None, _('show line number at the first appearance'))
354 ] + diffwsopts + walkopts + formatteropts,
354 ] + diffwsopts + walkopts + formatteropts,
355 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
355 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
356 inferrepo=True)
356 inferrepo=True)
357 def annotate(ui, repo, *pats, **opts):
357 def annotate(ui, repo, *pats, **opts):
358 """show changeset information by line for each file
358 """show changeset information by line for each file
359
359
360 List changes in files, showing the revision id responsible for
360 List changes in files, showing the revision id responsible for
361 each line.
361 each line.
362
362
363 This command is useful for discovering when a change was made and
363 This command is useful for discovering when a change was made and
364 by whom.
364 by whom.
365
365
366 If you include --file, --user, or --date, the revision number is
366 If you include --file, --user, or --date, the revision number is
367 suppressed unless you also include --number.
367 suppressed unless you also include --number.
368
368
369 Without the -a/--text option, annotate will avoid processing files
369 Without the -a/--text option, annotate will avoid processing files
370 it detects as binary. With -a, annotate will annotate the file
370 it detects as binary. With -a, annotate will annotate the file
371 anyway, although the results will probably be neither useful
371 anyway, although the results will probably be neither useful
372 nor desirable.
372 nor desirable.
373
373
374 Returns 0 on success.
374 Returns 0 on success.
375 """
375 """
376 if not pats:
376 if not pats:
377 raise error.Abort(_('at least one filename or pattern is required'))
377 raise error.Abort(_('at least one filename or pattern is required'))
378
378
379 if opts.get('follow'):
379 if opts.get('follow'):
380 # --follow is deprecated and now just an alias for -f/--file
380 # --follow is deprecated and now just an alias for -f/--file
381 # to mimic the behavior of Mercurial before version 1.5
381 # to mimic the behavior of Mercurial before version 1.5
382 opts['file'] = True
382 opts['file'] = True
383
383
384 ctx = scmutil.revsingle(repo, opts.get('rev'))
384 ctx = scmutil.revsingle(repo, opts.get('rev'))
385
385
386 fm = ui.formatter('annotate', opts)
386 fm = ui.formatter('annotate', opts)
387 if ui.quiet:
387 if ui.quiet:
388 datefunc = util.shortdate
388 datefunc = util.shortdate
389 else:
389 else:
390 datefunc = util.datestr
390 datefunc = util.datestr
391 if ctx.rev() is None:
391 if ctx.rev() is None:
392 def hexfn(node):
392 def hexfn(node):
393 if node is None:
393 if node is None:
394 return None
394 return None
395 else:
395 else:
396 return fm.hexfunc(node)
396 return fm.hexfunc(node)
397 if opts.get('changeset'):
397 if opts.get('changeset'):
398 # omit "+" suffix which is appended to node hex
398 # omit "+" suffix which is appended to node hex
399 def formatrev(rev):
399 def formatrev(rev):
400 if rev is None:
400 if rev is None:
401 return '%d' % ctx.p1().rev()
401 return '%d' % ctx.p1().rev()
402 else:
402 else:
403 return '%d' % rev
403 return '%d' % rev
404 else:
404 else:
405 def formatrev(rev):
405 def formatrev(rev):
406 if rev is None:
406 if rev is None:
407 return '%d+' % ctx.p1().rev()
407 return '%d+' % ctx.p1().rev()
408 else:
408 else:
409 return '%d ' % rev
409 return '%d ' % rev
410 def formathex(hex):
410 def formathex(hex):
411 if hex is None:
411 if hex is None:
412 return '%s+' % fm.hexfunc(ctx.p1().node())
412 return '%s+' % fm.hexfunc(ctx.p1().node())
413 else:
413 else:
414 return '%s ' % hex
414 return '%s ' % hex
415 else:
415 else:
416 hexfn = fm.hexfunc
416 hexfn = fm.hexfunc
417 formatrev = formathex = str
417 formatrev = formathex = str
418
418
419 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
419 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
420 ('number', ' ', lambda x: x[0].rev(), formatrev),
420 ('number', ' ', lambda x: x[0].rev(), formatrev),
421 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
421 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
422 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
422 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
423 ('file', ' ', lambda x: x[0].path(), str),
423 ('file', ' ', lambda x: x[0].path(), str),
424 ('line_number', ':', lambda x: x[1], str),
424 ('line_number', ':', lambda x: x[1], str),
425 ]
425 ]
426 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
426 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
427
427
428 if (not opts.get('user') and not opts.get('changeset')
428 if (not opts.get('user') and not opts.get('changeset')
429 and not opts.get('date') and not opts.get('file')):
429 and not opts.get('date') and not opts.get('file')):
430 opts['number'] = True
430 opts['number'] = True
431
431
432 linenumber = opts.get('line_number') is not None
432 linenumber = opts.get('line_number') is not None
433 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
433 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
434 raise error.Abort(_('at least one of -n/-c is required for -l'))
434 raise error.Abort(_('at least one of -n/-c is required for -l'))
435
435
436 if fm.isplain():
436 if fm.isplain():
437 def makefunc(get, fmt):
437 def makefunc(get, fmt):
438 return lambda x: fmt(get(x))
438 return lambda x: fmt(get(x))
439 else:
439 else:
440 def makefunc(get, fmt):
440 def makefunc(get, fmt):
441 return get
441 return get
442 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
442 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
443 if opts.get(op)]
443 if opts.get(op)]
444 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
444 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
445 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
445 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
446 if opts.get(op))
446 if opts.get(op))
447
447
448 def bad(x, y):
448 def bad(x, y):
449 raise error.Abort("%s: %s" % (x, y))
449 raise error.Abort("%s: %s" % (x, y))
450
450
451 m = scmutil.match(ctx, pats, opts, badfn=bad)
451 m = scmutil.match(ctx, pats, opts, badfn=bad)
452
452
453 follow = not opts.get('no_follow')
453 follow = not opts.get('no_follow')
454 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
454 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
455 whitespace=True)
455 whitespace=True)
456 for abs in ctx.walk(m):
456 for abs in ctx.walk(m):
457 fctx = ctx[abs]
457 fctx = ctx[abs]
458 if not opts.get('text') and util.binary(fctx.data()):
458 if not opts.get('text') and util.binary(fctx.data()):
459 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
459 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
460 continue
460 continue
461
461
462 lines = fctx.annotate(follow=follow, linenumber=linenumber,
462 lines = fctx.annotate(follow=follow, linenumber=linenumber,
463 diffopts=diffopts)
463 diffopts=diffopts)
464 if not lines:
464 if not lines:
465 continue
465 continue
466 formats = []
466 formats = []
467 pieces = []
467 pieces = []
468
468
469 for f, sep in funcmap:
469 for f, sep in funcmap:
470 l = [f(n) for n, dummy in lines]
470 l = [f(n) for n, dummy in lines]
471 if fm.isplain():
471 if fm.isplain():
472 sizes = [encoding.colwidth(x) for x in l]
472 sizes = [encoding.colwidth(x) for x in l]
473 ml = max(sizes)
473 ml = max(sizes)
474 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
474 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
475 else:
475 else:
476 formats.append(['%s' for x in l])
476 formats.append(['%s' for x in l])
477 pieces.append(l)
477 pieces.append(l)
478
478
479 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
479 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
480 fm.startitem()
480 fm.startitem()
481 fm.write(fields, "".join(f), *p)
481 fm.write(fields, "".join(f), *p)
482 fm.write('line', ": %s", l[1])
482 fm.write('line', ": %s", l[1])
483
483
484 if not lines[-1][1].endswith('\n'):
484 if not lines[-1][1].endswith('\n'):
485 fm.plain('\n')
485 fm.plain('\n')
486
486
487 fm.end()
487 fm.end()
488
488
489 @command('archive',
489 @command('archive',
490 [('', 'no-decode', None, _('do not pass files through decoders')),
490 [('', 'no-decode', None, _('do not pass files through decoders')),
491 ('p', 'prefix', '', _('directory prefix for files in archive'),
491 ('p', 'prefix', '', _('directory prefix for files in archive'),
492 _('PREFIX')),
492 _('PREFIX')),
493 ('r', 'rev', '', _('revision to distribute'), _('REV')),
493 ('r', 'rev', '', _('revision to distribute'), _('REV')),
494 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
494 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
495 ] + subrepoopts + walkopts,
495 ] + subrepoopts + walkopts,
496 _('[OPTION]... DEST'))
496 _('[OPTION]... DEST'))
497 def archive(ui, repo, dest, **opts):
497 def archive(ui, repo, dest, **opts):
498 '''create an unversioned archive of a repository revision
498 '''create an unversioned archive of a repository revision
499
499
500 By default, the revision used is the parent of the working
500 By default, the revision used is the parent of the working
501 directory; use -r/--rev to specify a different revision.
501 directory; use -r/--rev to specify a different revision.
502
502
503 The archive type is automatically detected based on file
503 The archive type is automatically detected based on file
504 extension (to override, use -t/--type).
504 extension (to override, use -t/--type).
505
505
506 .. container:: verbose
506 .. container:: verbose
507
507
508 Examples:
508 Examples:
509
509
510 - create a zip file containing the 1.0 release::
510 - create a zip file containing the 1.0 release::
511
511
512 hg archive -r 1.0 project-1.0.zip
512 hg archive -r 1.0 project-1.0.zip
513
513
514 - create a tarball excluding .hg files::
514 - create a tarball excluding .hg files::
515
515
516 hg archive project.tar.gz -X ".hg*"
516 hg archive project.tar.gz -X ".hg*"
517
517
518 Valid types are:
518 Valid types are:
519
519
520 :``files``: a directory full of files (default)
520 :``files``: a directory full of files (default)
521 :``tar``: tar archive, uncompressed
521 :``tar``: tar archive, uncompressed
522 :``tbz2``: tar archive, compressed using bzip2
522 :``tbz2``: tar archive, compressed using bzip2
523 :``tgz``: tar archive, compressed using gzip
523 :``tgz``: tar archive, compressed using gzip
524 :``uzip``: zip archive, uncompressed
524 :``uzip``: zip archive, uncompressed
525 :``zip``: zip archive, compressed using deflate
525 :``zip``: zip archive, compressed using deflate
526
526
527 The exact name of the destination archive or directory is given
527 The exact name of the destination archive or directory is given
528 using a format string; see :hg:`help export` for details.
528 using a format string; see :hg:`help export` for details.
529
529
530 Each member added to an archive file has a directory prefix
530 Each member added to an archive file has a directory prefix
531 prepended. Use -p/--prefix to specify a format string for the
531 prepended. Use -p/--prefix to specify a format string for the
532 prefix. The default is the basename of the archive, with suffixes
532 prefix. The default is the basename of the archive, with suffixes
533 removed.
533 removed.
534
534
535 Returns 0 on success.
535 Returns 0 on success.
536 '''
536 '''
537
537
538 ctx = scmutil.revsingle(repo, opts.get('rev'))
538 ctx = scmutil.revsingle(repo, opts.get('rev'))
539 if not ctx:
539 if not ctx:
540 raise error.Abort(_('no working directory: please specify a revision'))
540 raise error.Abort(_('no working directory: please specify a revision'))
541 node = ctx.node()
541 node = ctx.node()
542 dest = cmdutil.makefilename(repo, dest, node)
542 dest = cmdutil.makefilename(repo, dest, node)
543 if os.path.realpath(dest) == repo.root:
543 if os.path.realpath(dest) == repo.root:
544 raise error.Abort(_('repository root cannot be destination'))
544 raise error.Abort(_('repository root cannot be destination'))
545
545
546 kind = opts.get('type') or archival.guesskind(dest) or 'files'
546 kind = opts.get('type') or archival.guesskind(dest) or 'files'
547 prefix = opts.get('prefix')
547 prefix = opts.get('prefix')
548
548
549 if dest == '-':
549 if dest == '-':
550 if kind == 'files':
550 if kind == 'files':
551 raise error.Abort(_('cannot archive plain files to stdout'))
551 raise error.Abort(_('cannot archive plain files to stdout'))
552 dest = cmdutil.makefileobj(repo, dest)
552 dest = cmdutil.makefileobj(repo, dest)
553 if not prefix:
553 if not prefix:
554 prefix = os.path.basename(repo.root) + '-%h'
554 prefix = os.path.basename(repo.root) + '-%h'
555
555
556 prefix = cmdutil.makefilename(repo, prefix, node)
556 prefix = cmdutil.makefilename(repo, prefix, node)
557 matchfn = scmutil.match(ctx, [], opts)
557 matchfn = scmutil.match(ctx, [], opts)
558 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
558 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
559 matchfn, prefix, subrepos=opts.get('subrepos'))
559 matchfn, prefix, subrepos=opts.get('subrepos'))
560
560
561 @command('backout',
561 @command('backout',
562 [('', 'merge', None, _('merge with old dirstate parent after backout')),
562 [('', 'merge', None, _('merge with old dirstate parent after backout')),
563 ('', 'commit', None,
563 ('', 'commit', None,
564 _('commit if no conflicts were encountered (DEPRECATED)')),
564 _('commit if no conflicts were encountered (DEPRECATED)')),
565 ('', 'no-commit', None, _('do not commit')),
565 ('', 'no-commit', None, _('do not commit')),
566 ('', 'parent', '',
566 ('', 'parent', '',
567 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
567 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
568 ('r', 'rev', '', _('revision to backout'), _('REV')),
568 ('r', 'rev', '', _('revision to backout'), _('REV')),
569 ('e', 'edit', False, _('invoke editor on commit messages')),
569 ('e', 'edit', False, _('invoke editor on commit messages')),
570 ] + mergetoolopts + walkopts + commitopts + commitopts2,
570 ] + mergetoolopts + walkopts + commitopts + commitopts2,
571 _('[OPTION]... [-r] REV'))
571 _('[OPTION]... [-r] REV'))
572 def backout(ui, repo, node=None, rev=None, **opts):
572 def backout(ui, repo, node=None, rev=None, **opts):
573 '''reverse effect of earlier changeset
573 '''reverse effect of earlier changeset
574
574
575 Prepare a new changeset with the effect of REV undone in the
575 Prepare a new changeset with the effect of REV undone in the
576 current working directory. If no conflicts were encountered,
576 current working directory. If no conflicts were encountered,
577 it will be committed immediately.
577 it will be committed immediately.
578
578
579 If REV is the parent of the working directory, then this new changeset
579 If REV is the parent of the working directory, then this new changeset
580 is committed automatically (unless --no-commit is specified).
580 is committed automatically (unless --no-commit is specified).
581
581
582 .. note::
582 .. note::
583
583
584 :hg:`backout` cannot be used to fix either an unwanted or
584 :hg:`backout` cannot be used to fix either an unwanted or
585 incorrect merge.
585 incorrect merge.
586
586
587 .. container:: verbose
587 .. container:: verbose
588
588
589 Examples:
589 Examples:
590
590
591 - Reverse the effect of the parent of the working directory.
591 - Reverse the effect of the parent of the working directory.
592 This backout will be committed immediately::
592 This backout will be committed immediately::
593
593
594 hg backout -r .
594 hg backout -r .
595
595
596 - Reverse the effect of previous bad revision 23::
596 - Reverse the effect of previous bad revision 23::
597
597
598 hg backout -r 23
598 hg backout -r 23
599
599
600 - Reverse the effect of previous bad revision 23 and
600 - Reverse the effect of previous bad revision 23 and
601 leave changes uncommitted::
601 leave changes uncommitted::
602
602
603 hg backout -r 23 --no-commit
603 hg backout -r 23 --no-commit
604 hg commit -m "Backout revision 23"
604 hg commit -m "Backout revision 23"
605
605
606 By default, the pending changeset will have one parent,
606 By default, the pending changeset will have one parent,
607 maintaining a linear history. With --merge, the pending
607 maintaining a linear history. With --merge, the pending
608 changeset will instead have two parents: the old parent of the
608 changeset will instead have two parents: the old parent of the
609 working directory and a new child of REV that simply undoes REV.
609 working directory and a new child of REV that simply undoes REV.
610
610
611 Before version 1.7, the behavior without --merge was equivalent
611 Before version 1.7, the behavior without --merge was equivalent
612 to specifying --merge followed by :hg:`update --clean .` to
612 to specifying --merge followed by :hg:`update --clean .` to
613 cancel the merge and leave the child of REV as a head to be
613 cancel the merge and leave the child of REV as a head to be
614 merged separately.
614 merged separately.
615
615
616 See :hg:`help dates` for a list of formats valid for -d/--date.
616 See :hg:`help dates` for a list of formats valid for -d/--date.
617
617
618 See :hg:`help revert` for a way to restore files to the state
618 See :hg:`help revert` for a way to restore files to the state
619 of another revision.
619 of another revision.
620
620
621 Returns 0 on success, 1 if nothing to backout or there are unresolved
621 Returns 0 on success, 1 if nothing to backout or there are unresolved
622 files.
622 files.
623 '''
623 '''
624 wlock = lock = None
624 wlock = lock = None
625 try:
625 try:
626 wlock = repo.wlock()
626 wlock = repo.wlock()
627 lock = repo.lock()
627 lock = repo.lock()
628 return _dobackout(ui, repo, node, rev, **opts)
628 return _dobackout(ui, repo, node, rev, **opts)
629 finally:
629 finally:
630 release(lock, wlock)
630 release(lock, wlock)
631
631
632 def _dobackout(ui, repo, node=None, rev=None, **opts):
632 def _dobackout(ui, repo, node=None, rev=None, **opts):
633 if opts.get('commit') and opts.get('no_commit'):
633 if opts.get('commit') and opts.get('no_commit'):
634 raise error.Abort(_("cannot use --commit with --no-commit"))
634 raise error.Abort(_("cannot use --commit with --no-commit"))
635 if opts.get('merge') and opts.get('no_commit'):
635 if opts.get('merge') and opts.get('no_commit'):
636 raise error.Abort(_("cannot use --merge with --no-commit"))
636 raise error.Abort(_("cannot use --merge with --no-commit"))
637
637
638 if rev and node:
638 if rev and node:
639 raise error.Abort(_("please specify just one revision"))
639 raise error.Abort(_("please specify just one revision"))
640
640
641 if not rev:
641 if not rev:
642 rev = node
642 rev = node
643
643
644 if not rev:
644 if not rev:
645 raise error.Abort(_("please specify a revision to backout"))
645 raise error.Abort(_("please specify a revision to backout"))
646
646
647 date = opts.get('date')
647 date = opts.get('date')
648 if date:
648 if date:
649 opts['date'] = util.parsedate(date)
649 opts['date'] = util.parsedate(date)
650
650
651 cmdutil.checkunfinished(repo)
651 cmdutil.checkunfinished(repo)
652 cmdutil.bailifchanged(repo)
652 cmdutil.bailifchanged(repo)
653 node = scmutil.revsingle(repo, rev).node()
653 node = scmutil.revsingle(repo, rev).node()
654
654
655 op1, op2 = repo.dirstate.parents()
655 op1, op2 = repo.dirstate.parents()
656 if not repo.changelog.isancestor(node, op1):
656 if not repo.changelog.isancestor(node, op1):
657 raise error.Abort(_('cannot backout change that is not an ancestor'))
657 raise error.Abort(_('cannot backout change that is not an ancestor'))
658
658
659 p1, p2 = repo.changelog.parents(node)
659 p1, p2 = repo.changelog.parents(node)
660 if p1 == nullid:
660 if p1 == nullid:
661 raise error.Abort(_('cannot backout a change with no parents'))
661 raise error.Abort(_('cannot backout a change with no parents'))
662 if p2 != nullid:
662 if p2 != nullid:
663 if not opts.get('parent'):
663 if not opts.get('parent'):
664 raise error.Abort(_('cannot backout a merge changeset'))
664 raise error.Abort(_('cannot backout a merge changeset'))
665 p = repo.lookup(opts['parent'])
665 p = repo.lookup(opts['parent'])
666 if p not in (p1, p2):
666 if p not in (p1, p2):
667 raise error.Abort(_('%s is not a parent of %s') %
667 raise error.Abort(_('%s is not a parent of %s') %
668 (short(p), short(node)))
668 (short(p), short(node)))
669 parent = p
669 parent = p
670 else:
670 else:
671 if opts.get('parent'):
671 if opts.get('parent'):
672 raise error.Abort(_('cannot use --parent on non-merge changeset'))
672 raise error.Abort(_('cannot use --parent on non-merge changeset'))
673 parent = p1
673 parent = p1
674
674
675 # the backout should appear on the same branch
675 # the backout should appear on the same branch
676 branch = repo.dirstate.branch()
676 branch = repo.dirstate.branch()
677 bheads = repo.branchheads(branch)
677 bheads = repo.branchheads(branch)
678 rctx = scmutil.revsingle(repo, hex(parent))
678 rctx = scmutil.revsingle(repo, hex(parent))
679 if not opts.get('merge') and op1 != node:
679 if not opts.get('merge') and op1 != node:
680 dsguard = dirstateguard.dirstateguard(repo, 'backout')
680 dsguard = dirstateguard.dirstateguard(repo, 'backout')
681 try:
681 try:
682 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
682 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
683 'backout')
683 'backout')
684 stats = mergemod.update(repo, parent, True, True, node, False)
684 stats = mergemod.update(repo, parent, True, True, node, False)
685 repo.setparents(op1, op2)
685 repo.setparents(op1, op2)
686 dsguard.close()
686 dsguard.close()
687 hg._showstats(repo, stats)
687 hg._showstats(repo, stats)
688 if stats[3]:
688 if stats[3]:
689 repo.ui.status(_("use 'hg resolve' to retry unresolved "
689 repo.ui.status(_("use 'hg resolve' to retry unresolved "
690 "file merges\n"))
690 "file merges\n"))
691 return 1
691 return 1
692 finally:
692 finally:
693 ui.setconfig('ui', 'forcemerge', '', '')
693 ui.setconfig('ui', 'forcemerge', '', '')
694 lockmod.release(dsguard)
694 lockmod.release(dsguard)
695 else:
695 else:
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 repo.dirstate.setbranch(branch)
697 repo.dirstate.setbranch(branch)
698 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
698 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
699
699
700 if opts.get('no_commit'):
700 if opts.get('no_commit'):
701 msg = _("changeset %s backed out, "
701 msg = _("changeset %s backed out, "
702 "don't forget to commit.\n")
702 "don't forget to commit.\n")
703 ui.status(msg % short(node))
703 ui.status(msg % short(node))
704 return 0
704 return 0
705
705
706 def commitfunc(ui, repo, message, match, opts):
706 def commitfunc(ui, repo, message, match, opts):
707 editform = 'backout'
707 editform = 'backout'
708 e = cmdutil.getcommiteditor(editform=editform, **opts)
708 e = cmdutil.getcommiteditor(editform=editform, **opts)
709 if not message:
709 if not message:
710 # we don't translate commit messages
710 # we don't translate commit messages
711 message = "Backed out changeset %s" % short(node)
711 message = "Backed out changeset %s" % short(node)
712 e = cmdutil.getcommiteditor(edit=True, editform=editform)
712 e = cmdutil.getcommiteditor(edit=True, editform=editform)
713 return repo.commit(message, opts.get('user'), opts.get('date'),
713 return repo.commit(message, opts.get('user'), opts.get('date'),
714 match, editor=e)
714 match, editor=e)
715 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
715 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
716 if not newnode:
716 if not newnode:
717 ui.status(_("nothing changed\n"))
717 ui.status(_("nothing changed\n"))
718 return 1
718 return 1
719 cmdutil.commitstatus(repo, newnode, branch, bheads)
719 cmdutil.commitstatus(repo, newnode, branch, bheads)
720
720
721 def nice(node):
721 def nice(node):
722 return '%d:%s' % (repo.changelog.rev(node), short(node))
722 return '%d:%s' % (repo.changelog.rev(node), short(node))
723 ui.status(_('changeset %s backs out changeset %s\n') %
723 ui.status(_('changeset %s backs out changeset %s\n') %
724 (nice(repo.changelog.tip()), nice(node)))
724 (nice(repo.changelog.tip()), nice(node)))
725 if opts.get('merge') and op1 != node:
725 if opts.get('merge') and op1 != node:
726 hg.clean(repo, op1, show_stats=False)
726 hg.clean(repo, op1, show_stats=False)
727 ui.status(_('merging with changeset %s\n')
727 ui.status(_('merging with changeset %s\n')
728 % nice(repo.changelog.tip()))
728 % nice(repo.changelog.tip()))
729 try:
729 try:
730 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
730 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
731 'backout')
731 'backout')
732 return hg.merge(repo, hex(repo.changelog.tip()))
732 return hg.merge(repo, hex(repo.changelog.tip()))
733 finally:
733 finally:
734 ui.setconfig('ui', 'forcemerge', '', '')
734 ui.setconfig('ui', 'forcemerge', '', '')
735 return 0
735 return 0
736
736
737 @command('bisect',
737 @command('bisect',
738 [('r', 'reset', False, _('reset bisect state')),
738 [('r', 'reset', False, _('reset bisect state')),
739 ('g', 'good', False, _('mark changeset good')),
739 ('g', 'good', False, _('mark changeset good')),
740 ('b', 'bad', False, _('mark changeset bad')),
740 ('b', 'bad', False, _('mark changeset bad')),
741 ('s', 'skip', False, _('skip testing changeset')),
741 ('s', 'skip', False, _('skip testing changeset')),
742 ('e', 'extend', False, _('extend the bisect range')),
742 ('e', 'extend', False, _('extend the bisect range')),
743 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
743 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
744 ('U', 'noupdate', False, _('do not update to target'))],
744 ('U', 'noupdate', False, _('do not update to target'))],
745 _("[-gbsr] [-U] [-c CMD] [REV]"))
745 _("[-gbsr] [-U] [-c CMD] [REV]"))
746 def bisect(ui, repo, rev=None, extra=None, command=None,
746 def bisect(ui, repo, rev=None, extra=None, command=None,
747 reset=None, good=None, bad=None, skip=None, extend=None,
747 reset=None, good=None, bad=None, skip=None, extend=None,
748 noupdate=None):
748 noupdate=None):
749 """subdivision search of changesets
749 """subdivision search of changesets
750
750
751 This command helps to find changesets which introduce problems. To
751 This command helps to find changesets which introduce problems. To
752 use, mark the earliest changeset you know exhibits the problem as
752 use, mark the earliest changeset you know exhibits the problem as
753 bad, then mark the latest changeset which is free from the problem
753 bad, then mark the latest changeset which is free from the problem
754 as good. Bisect will update your working directory to a revision
754 as good. Bisect will update your working directory to a revision
755 for testing (unless the -U/--noupdate option is specified). Once
755 for testing (unless the -U/--noupdate option is specified). Once
756 you have performed tests, mark the working directory as good or
756 you have performed tests, mark the working directory as good or
757 bad, and bisect will either update to another candidate changeset
757 bad, and bisect will either update to another candidate changeset
758 or announce that it has found the bad revision.
758 or announce that it has found the bad revision.
759
759
760 As a shortcut, you can also use the revision argument to mark a
760 As a shortcut, you can also use the revision argument to mark a
761 revision as good or bad without checking it out first.
761 revision as good or bad without checking it out first.
762
762
763 If you supply a command, it will be used for automatic bisection.
763 If you supply a command, it will be used for automatic bisection.
764 The environment variable HG_NODE will contain the ID of the
764 The environment variable HG_NODE will contain the ID of the
765 changeset being tested. The exit status of the command will be
765 changeset being tested. The exit status of the command will be
766 used to mark revisions as good or bad: status 0 means good, 125
766 used to mark revisions as good or bad: status 0 means good, 125
767 means to skip the revision, 127 (command not found) will abort the
767 means to skip the revision, 127 (command not found) will abort the
768 bisection, and any other non-zero exit status means the revision
768 bisection, and any other non-zero exit status means the revision
769 is bad.
769 is bad.
770
770
771 .. container:: verbose
771 .. container:: verbose
772
772
773 Some examples:
773 Some examples:
774
774
775 - start a bisection with known bad revision 34, and good revision 12::
775 - start a bisection with known bad revision 34, and good revision 12::
776
776
777 hg bisect --bad 34
777 hg bisect --bad 34
778 hg bisect --good 12
778 hg bisect --good 12
779
779
780 - advance the current bisection by marking current revision as good or
780 - advance the current bisection by marking current revision as good or
781 bad::
781 bad::
782
782
783 hg bisect --good
783 hg bisect --good
784 hg bisect --bad
784 hg bisect --bad
785
785
786 - mark the current revision, or a known revision, to be skipped (e.g. if
786 - mark the current revision, or a known revision, to be skipped (e.g. if
787 that revision is not usable because of another issue)::
787 that revision is not usable because of another issue)::
788
788
789 hg bisect --skip
789 hg bisect --skip
790 hg bisect --skip 23
790 hg bisect --skip 23
791
791
792 - skip all revisions that do not touch directories ``foo`` or ``bar``::
792 - skip all revisions that do not touch directories ``foo`` or ``bar``::
793
793
794 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
794 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
795
795
796 - forget the current bisection::
796 - forget the current bisection::
797
797
798 hg bisect --reset
798 hg bisect --reset
799
799
800 - use 'make && make tests' to automatically find the first broken
800 - use 'make && make tests' to automatically find the first broken
801 revision::
801 revision::
802
802
803 hg bisect --reset
803 hg bisect --reset
804 hg bisect --bad 34
804 hg bisect --bad 34
805 hg bisect --good 12
805 hg bisect --good 12
806 hg bisect --command "make && make tests"
806 hg bisect --command "make && make tests"
807
807
808 - see all changesets whose states are already known in the current
808 - see all changesets whose states are already known in the current
809 bisection::
809 bisection::
810
810
811 hg log -r "bisect(pruned)"
811 hg log -r "bisect(pruned)"
812
812
813 - see the changeset currently being bisected (especially useful
813 - see the changeset currently being bisected (especially useful
814 if running with -U/--noupdate)::
814 if running with -U/--noupdate)::
815
815
816 hg log -r "bisect(current)"
816 hg log -r "bisect(current)"
817
817
818 - see all changesets that took part in the current bisection::
818 - see all changesets that took part in the current bisection::
819
819
820 hg log -r "bisect(range)"
820 hg log -r "bisect(range)"
821
821
822 - you can even get a nice graph::
822 - you can even get a nice graph::
823
823
824 hg log --graph -r "bisect(range)"
824 hg log --graph -r "bisect(range)"
825
825
826 See :hg:`help revsets` for more about the `bisect()` keyword.
826 See :hg:`help revsets` for more about the `bisect()` keyword.
827
827
828 Returns 0 on success.
828 Returns 0 on success.
829 """
829 """
830 # backward compatibility
830 # backward compatibility
831 if rev in "good bad reset init".split():
831 if rev in "good bad reset init".split():
832 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
832 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
833 cmd, rev, extra = rev, extra, None
833 cmd, rev, extra = rev, extra, None
834 if cmd == "good":
834 if cmd == "good":
835 good = True
835 good = True
836 elif cmd == "bad":
836 elif cmd == "bad":
837 bad = True
837 bad = True
838 else:
838 else:
839 reset = True
839 reset = True
840 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
840 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
841 raise error.Abort(_('incompatible arguments'))
841 raise error.Abort(_('incompatible arguments'))
842
842
843 cmdutil.checkunfinished(repo)
843 cmdutil.checkunfinished(repo)
844
844
845 if reset:
845 if reset:
846 hbisect.resetstate(repo)
846 hbisect.resetstate(repo)
847 return
847 return
848
848
849 state = hbisect.load_state(repo)
849 state = hbisect.load_state(repo)
850
850
851 # update state
851 # update state
852 if good or bad or skip:
852 if good or bad or skip:
853 if rev:
853 if rev:
854 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
854 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
855 else:
855 else:
856 nodes = [repo.lookup('.')]
856 nodes = [repo.lookup('.')]
857 if good:
857 if good:
858 state['good'] += nodes
858 state['good'] += nodes
859 elif bad:
859 elif bad:
860 state['bad'] += nodes
860 state['bad'] += nodes
861 elif skip:
861 elif skip:
862 state['skip'] += nodes
862 state['skip'] += nodes
863 hbisect.save_state(repo, state)
863 hbisect.save_state(repo, state)
864 if not (state['good'] and state['bad']):
864 if not (state['good'] and state['bad']):
865 return
865 return
866
866
867 def mayupdate(repo, node, show_stats=True):
867 def mayupdate(repo, node, show_stats=True):
868 """common used update sequence"""
868 """common used update sequence"""
869 if noupdate:
869 if noupdate:
870 return
870 return
871 cmdutil.bailifchanged(repo)
871 cmdutil.bailifchanged(repo)
872 return hg.clean(repo, node, show_stats=show_stats)
872 return hg.clean(repo, node, show_stats=show_stats)
873
873
874 displayer = cmdutil.show_changeset(ui, repo, {})
874 displayer = cmdutil.show_changeset(ui, repo, {})
875
875
876 if command:
876 if command:
877 changesets = 1
877 changesets = 1
878 if noupdate:
878 if noupdate:
879 try:
879 try:
880 node = state['current'][0]
880 node = state['current'][0]
881 except LookupError:
881 except LookupError:
882 raise error.Abort(_('current bisect revision is unknown - '
882 raise error.Abort(_('current bisect revision is unknown - '
883 'start a new bisect to fix'))
883 'start a new bisect to fix'))
884 else:
884 else:
885 node, p2 = repo.dirstate.parents()
885 node, p2 = repo.dirstate.parents()
886 if p2 != nullid:
886 if p2 != nullid:
887 raise error.Abort(_('current bisect revision is a merge'))
887 raise error.Abort(_('current bisect revision is a merge'))
888 if rev:
888 if rev:
889 node = repo[scmutil.revsingle(repo, rev, node)].node()
889 node = repo[scmutil.revsingle(repo, rev, node)].node()
890 try:
890 try:
891 while changesets:
891 while changesets:
892 # update state
892 # update state
893 state['current'] = [node]
893 state['current'] = [node]
894 hbisect.save_state(repo, state)
894 hbisect.save_state(repo, state)
895 status = ui.system(command, environ={'HG_NODE': hex(node)})
895 status = ui.system(command, environ={'HG_NODE': hex(node)})
896 if status == 125:
896 if status == 125:
897 transition = "skip"
897 transition = "skip"
898 elif status == 0:
898 elif status == 0:
899 transition = "good"
899 transition = "good"
900 # status < 0 means process was killed
900 # status < 0 means process was killed
901 elif status == 127:
901 elif status == 127:
902 raise error.Abort(_("failed to execute %s") % command)
902 raise error.Abort(_("failed to execute %s") % command)
903 elif status < 0:
903 elif status < 0:
904 raise error.Abort(_("%s killed") % command)
904 raise error.Abort(_("%s killed") % command)
905 else:
905 else:
906 transition = "bad"
906 transition = "bad"
907 state[transition].append(node)
907 state[transition].append(node)
908 ctx = repo[node]
908 ctx = repo[node]
909 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
909 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
910 hbisect.checkstate(state)
910 hbisect.checkstate(state)
911 # bisect
911 # bisect
912 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
912 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
913 # update to next check
913 # update to next check
914 node = nodes[0]
914 node = nodes[0]
915 mayupdate(repo, node, show_stats=False)
915 mayupdate(repo, node, show_stats=False)
916 finally:
916 finally:
917 state['current'] = [node]
917 state['current'] = [node]
918 hbisect.save_state(repo, state)
918 hbisect.save_state(repo, state)
919 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
919 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
920 return
920 return
921
921
922 hbisect.checkstate(state)
922 hbisect.checkstate(state)
923
923
924 # actually bisect
924 # actually bisect
925 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
925 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
926 if extend:
926 if extend:
927 if not changesets:
927 if not changesets:
928 extendnode = hbisect.extendrange(repo, state, nodes, good)
928 extendnode = hbisect.extendrange(repo, state, nodes, good)
929 if extendnode is not None:
929 if extendnode is not None:
930 ui.write(_("Extending search to changeset %d:%s\n")
930 ui.write(_("Extending search to changeset %d:%s\n")
931 % (extendnode.rev(), extendnode))
931 % (extendnode.rev(), extendnode))
932 state['current'] = [extendnode.node()]
932 state['current'] = [extendnode.node()]
933 hbisect.save_state(repo, state)
933 hbisect.save_state(repo, state)
934 return mayupdate(repo, extendnode.node())
934 return mayupdate(repo, extendnode.node())
935 raise error.Abort(_("nothing to extend"))
935 raise error.Abort(_("nothing to extend"))
936
936
937 if changesets == 0:
937 if changesets == 0:
938 hbisect.printresult(ui, repo, state, displayer, nodes, good)
938 hbisect.printresult(ui, repo, state, displayer, nodes, good)
939 else:
939 else:
940 assert len(nodes) == 1 # only a single node can be tested next
940 assert len(nodes) == 1 # only a single node can be tested next
941 node = nodes[0]
941 node = nodes[0]
942 # compute the approximate number of remaining tests
942 # compute the approximate number of remaining tests
943 tests, size = 0, 2
943 tests, size = 0, 2
944 while size <= changesets:
944 while size <= changesets:
945 tests, size = tests + 1, size * 2
945 tests, size = tests + 1, size * 2
946 rev = repo.changelog.rev(node)
946 rev = repo.changelog.rev(node)
947 ui.write(_("Testing changeset %d:%s "
947 ui.write(_("Testing changeset %d:%s "
948 "(%d changesets remaining, ~%d tests)\n")
948 "(%d changesets remaining, ~%d tests)\n")
949 % (rev, short(node), changesets, tests))
949 % (rev, short(node), changesets, tests))
950 state['current'] = [node]
950 state['current'] = [node]
951 hbisect.save_state(repo, state)
951 hbisect.save_state(repo, state)
952 return mayupdate(repo, node)
952 return mayupdate(repo, node)
953
953
954 @command('bookmarks|bookmark',
954 @command('bookmarks|bookmark',
955 [('f', 'force', False, _('force')),
955 [('f', 'force', False, _('force')),
956 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
956 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
957 ('d', 'delete', False, _('delete a given bookmark')),
957 ('d', 'delete', False, _('delete a given bookmark')),
958 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
958 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
959 ('i', 'inactive', False, _('mark a bookmark inactive')),
959 ('i', 'inactive', False, _('mark a bookmark inactive')),
960 ] + formatteropts,
960 ] + formatteropts,
961 _('hg bookmarks [OPTIONS]... [NAME]...'))
961 _('hg bookmarks [OPTIONS]... [NAME]...'))
962 def bookmark(ui, repo, *names, **opts):
962 def bookmark(ui, repo, *names, **opts):
963 '''create a new bookmark or list existing bookmarks
963 '''create a new bookmark or list existing bookmarks
964
964
965 Bookmarks are labels on changesets to help track lines of development.
965 Bookmarks are labels on changesets to help track lines of development.
966 Bookmarks are unversioned and can be moved, renamed and deleted.
966 Bookmarks are unversioned and can be moved, renamed and deleted.
967 Deleting or moving a bookmark has no effect on the associated changesets.
967 Deleting or moving a bookmark has no effect on the associated changesets.
968
968
969 Creating or updating to a bookmark causes it to be marked as 'active'.
969 Creating or updating to a bookmark causes it to be marked as 'active'.
970 The active bookmark is indicated with a '*'.
970 The active bookmark is indicated with a '*'.
971 When a commit is made, the active bookmark will advance to the new commit.
971 When a commit is made, the active bookmark will advance to the new commit.
972 A plain :hg:`update` will also advance an active bookmark, if possible.
972 A plain :hg:`update` will also advance an active bookmark, if possible.
973 Updating away from a bookmark will cause it to be deactivated.
973 Updating away from a bookmark will cause it to be deactivated.
974
974
975 Bookmarks can be pushed and pulled between repositories (see
975 Bookmarks can be pushed and pulled between repositories (see
976 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
976 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
977 diverged, a new 'divergent bookmark' of the form 'name@path' will
977 diverged, a new 'divergent bookmark' of the form 'name@path' will
978 be created. Using :hg:`merge` will resolve the divergence.
978 be created. Using :hg:`merge` will resolve the divergence.
979
979
980 A bookmark named '@' has the special property that :hg:`clone` will
980 A bookmark named '@' has the special property that :hg:`clone` will
981 check it out by default if it exists.
981 check it out by default if it exists.
982
982
983 .. container:: verbose
983 .. container:: verbose
984
984
985 Examples:
985 Examples:
986
986
987 - create an active bookmark for a new line of development::
987 - create an active bookmark for a new line of development::
988
988
989 hg book new-feature
989 hg book new-feature
990
990
991 - create an inactive bookmark as a place marker::
991 - create an inactive bookmark as a place marker::
992
992
993 hg book -i reviewed
993 hg book -i reviewed
994
994
995 - create an inactive bookmark on another changeset::
995 - create an inactive bookmark on another changeset::
996
996
997 hg book -r .^ tested
997 hg book -r .^ tested
998
998
999 - rename bookmark turkey to dinner::
999 - rename bookmark turkey to dinner::
1000
1000
1001 hg book -m turkey dinner
1001 hg book -m turkey dinner
1002
1002
1003 - move the '@' bookmark from another branch::
1003 - move the '@' bookmark from another branch::
1004
1004
1005 hg book -f @
1005 hg book -f @
1006 '''
1006 '''
1007 force = opts.get('force')
1007 force = opts.get('force')
1008 rev = opts.get('rev')
1008 rev = opts.get('rev')
1009 delete = opts.get('delete')
1009 delete = opts.get('delete')
1010 rename = opts.get('rename')
1010 rename = opts.get('rename')
1011 inactive = opts.get('inactive')
1011 inactive = opts.get('inactive')
1012
1012
1013 def checkformat(mark):
1013 def checkformat(mark):
1014 mark = mark.strip()
1014 mark = mark.strip()
1015 if not mark:
1015 if not mark:
1016 raise error.Abort(_("bookmark names cannot consist entirely of "
1016 raise error.Abort(_("bookmark names cannot consist entirely of "
1017 "whitespace"))
1017 "whitespace"))
1018 scmutil.checknewlabel(repo, mark, 'bookmark')
1018 scmutil.checknewlabel(repo, mark, 'bookmark')
1019 return mark
1019 return mark
1020
1020
1021 def checkconflict(repo, mark, cur, force=False, target=None):
1021 def checkconflict(repo, mark, cur, force=False, target=None):
1022 if mark in marks and not force:
1022 if mark in marks and not force:
1023 if target:
1023 if target:
1024 if marks[mark] == target and target == cur:
1024 if marks[mark] == target and target == cur:
1025 # re-activating a bookmark
1025 # re-activating a bookmark
1026 return
1026 return
1027 anc = repo.changelog.ancestors([repo[target].rev()])
1027 anc = repo.changelog.ancestors([repo[target].rev()])
1028 bmctx = repo[marks[mark]]
1028 bmctx = repo[marks[mark]]
1029 divs = [repo[b].node() for b in marks
1029 divs = [repo[b].node() for b in marks
1030 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1030 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1031
1031
1032 # allow resolving a single divergent bookmark even if moving
1032 # allow resolving a single divergent bookmark even if moving
1033 # the bookmark across branches when a revision is specified
1033 # the bookmark across branches when a revision is specified
1034 # that contains a divergent bookmark
1034 # that contains a divergent bookmark
1035 if bmctx.rev() not in anc and target in divs:
1035 if bmctx.rev() not in anc and target in divs:
1036 bookmarks.deletedivergent(repo, [target], mark)
1036 bookmarks.deletedivergent(repo, [target], mark)
1037 return
1037 return
1038
1038
1039 deletefrom = [b for b in divs
1039 deletefrom = [b for b in divs
1040 if repo[b].rev() in anc or b == target]
1040 if repo[b].rev() in anc or b == target]
1041 bookmarks.deletedivergent(repo, deletefrom, mark)
1041 bookmarks.deletedivergent(repo, deletefrom, mark)
1042 if bookmarks.validdest(repo, bmctx, repo[target]):
1042 if bookmarks.validdest(repo, bmctx, repo[target]):
1043 ui.status(_("moving bookmark '%s' forward from %s\n") %
1043 ui.status(_("moving bookmark '%s' forward from %s\n") %
1044 (mark, short(bmctx.node())))
1044 (mark, short(bmctx.node())))
1045 return
1045 return
1046 raise error.Abort(_("bookmark '%s' already exists "
1046 raise error.Abort(_("bookmark '%s' already exists "
1047 "(use -f to force)") % mark)
1047 "(use -f to force)") % mark)
1048 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1048 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1049 and not force):
1049 and not force):
1050 raise error.Abort(
1050 raise error.Abort(
1051 _("a bookmark cannot have the name of an existing branch"))
1051 _("a bookmark cannot have the name of an existing branch"))
1052
1052
1053 if delete and rename:
1053 if delete and rename:
1054 raise error.Abort(_("--delete and --rename are incompatible"))
1054 raise error.Abort(_("--delete and --rename are incompatible"))
1055 if delete and rev:
1055 if delete and rev:
1056 raise error.Abort(_("--rev is incompatible with --delete"))
1056 raise error.Abort(_("--rev is incompatible with --delete"))
1057 if rename and rev:
1057 if rename and rev:
1058 raise error.Abort(_("--rev is incompatible with --rename"))
1058 raise error.Abort(_("--rev is incompatible with --rename"))
1059 if not names and (delete or rev):
1059 if not names and (delete or rev):
1060 raise error.Abort(_("bookmark name required"))
1060 raise error.Abort(_("bookmark name required"))
1061
1061
1062 if delete or rename or names or inactive:
1062 if delete or rename or names or inactive:
1063 wlock = lock = tr = None
1063 wlock = lock = tr = None
1064 try:
1064 try:
1065 wlock = repo.wlock()
1065 wlock = repo.wlock()
1066 lock = repo.lock()
1066 lock = repo.lock()
1067 cur = repo.changectx('.').node()
1067 cur = repo.changectx('.').node()
1068 marks = repo._bookmarks
1068 marks = repo._bookmarks
1069 if delete:
1069 if delete:
1070 tr = repo.transaction('bookmark')
1070 tr = repo.transaction('bookmark')
1071 for mark in names:
1071 for mark in names:
1072 if mark not in marks:
1072 if mark not in marks:
1073 raise error.Abort(_("bookmark '%s' does not exist") %
1073 raise error.Abort(_("bookmark '%s' does not exist") %
1074 mark)
1074 mark)
1075 if mark == repo._activebookmark:
1075 if mark == repo._activebookmark:
1076 bookmarks.deactivate(repo)
1076 bookmarks.deactivate(repo)
1077 del marks[mark]
1077 del marks[mark]
1078
1078
1079 elif rename:
1079 elif rename:
1080 tr = repo.transaction('bookmark')
1080 tr = repo.transaction('bookmark')
1081 if not names:
1081 if not names:
1082 raise error.Abort(_("new bookmark name required"))
1082 raise error.Abort(_("new bookmark name required"))
1083 elif len(names) > 1:
1083 elif len(names) > 1:
1084 raise error.Abort(_("only one new bookmark name allowed"))
1084 raise error.Abort(_("only one new bookmark name allowed"))
1085 mark = checkformat(names[0])
1085 mark = checkformat(names[0])
1086 if rename not in marks:
1086 if rename not in marks:
1087 raise error.Abort(_("bookmark '%s' does not exist")
1087 raise error.Abort(_("bookmark '%s' does not exist")
1088 % rename)
1088 % rename)
1089 checkconflict(repo, mark, cur, force)
1089 checkconflict(repo, mark, cur, force)
1090 marks[mark] = marks[rename]
1090 marks[mark] = marks[rename]
1091 if repo._activebookmark == rename and not inactive:
1091 if repo._activebookmark == rename and not inactive:
1092 bookmarks.activate(repo, mark)
1092 bookmarks.activate(repo, mark)
1093 del marks[rename]
1093 del marks[rename]
1094 elif names:
1094 elif names:
1095 tr = repo.transaction('bookmark')
1095 tr = repo.transaction('bookmark')
1096 newact = None
1096 newact = None
1097 for mark in names:
1097 for mark in names:
1098 mark = checkformat(mark)
1098 mark = checkformat(mark)
1099 if newact is None:
1099 if newact is None:
1100 newact = mark
1100 newact = mark
1101 if inactive and mark == repo._activebookmark:
1101 if inactive and mark == repo._activebookmark:
1102 bookmarks.deactivate(repo)
1102 bookmarks.deactivate(repo)
1103 return
1103 return
1104 tgt = cur
1104 tgt = cur
1105 if rev:
1105 if rev:
1106 tgt = scmutil.revsingle(repo, rev).node()
1106 tgt = scmutil.revsingle(repo, rev).node()
1107 checkconflict(repo, mark, cur, force, tgt)
1107 checkconflict(repo, mark, cur, force, tgt)
1108 marks[mark] = tgt
1108 marks[mark] = tgt
1109 if not inactive and cur == marks[newact] and not rev:
1109 if not inactive and cur == marks[newact] and not rev:
1110 bookmarks.activate(repo, newact)
1110 bookmarks.activate(repo, newact)
1111 elif cur != tgt and newact == repo._activebookmark:
1111 elif cur != tgt and newact == repo._activebookmark:
1112 bookmarks.deactivate(repo)
1112 bookmarks.deactivate(repo)
1113 elif inactive:
1113 elif inactive:
1114 if len(marks) == 0:
1114 if len(marks) == 0:
1115 ui.status(_("no bookmarks set\n"))
1115 ui.status(_("no bookmarks set\n"))
1116 elif not repo._activebookmark:
1116 elif not repo._activebookmark:
1117 ui.status(_("no active bookmark\n"))
1117 ui.status(_("no active bookmark\n"))
1118 else:
1118 else:
1119 bookmarks.deactivate(repo)
1119 bookmarks.deactivate(repo)
1120 if tr is not None:
1120 if tr is not None:
1121 marks.recordchange(tr)
1121 marks.recordchange(tr)
1122 tr.close()
1122 tr.close()
1123 finally:
1123 finally:
1124 lockmod.release(tr, lock, wlock)
1124 lockmod.release(tr, lock, wlock)
1125 else: # show bookmarks
1125 else: # show bookmarks
1126 fm = ui.formatter('bookmarks', opts)
1126 fm = ui.formatter('bookmarks', opts)
1127 hexfn = fm.hexfunc
1127 hexfn = fm.hexfunc
1128 marks = repo._bookmarks
1128 marks = repo._bookmarks
1129 if len(marks) == 0 and fm.isplain():
1129 if len(marks) == 0 and fm.isplain():
1130 ui.status(_("no bookmarks set\n"))
1130 ui.status(_("no bookmarks set\n"))
1131 for bmark, n in sorted(marks.iteritems()):
1131 for bmark, n in sorted(marks.iteritems()):
1132 active = repo._activebookmark
1132 active = repo._activebookmark
1133 if bmark == active:
1133 if bmark == active:
1134 prefix, label = '*', activebookmarklabel
1134 prefix, label = '*', activebookmarklabel
1135 else:
1135 else:
1136 prefix, label = ' ', ''
1136 prefix, label = ' ', ''
1137
1137
1138 fm.startitem()
1138 fm.startitem()
1139 if not ui.quiet:
1139 if not ui.quiet:
1140 fm.plain(' %s ' % prefix, label=label)
1140 fm.plain(' %s ' % prefix, label=label)
1141 fm.write('bookmark', '%s', bmark, label=label)
1141 fm.write('bookmark', '%s', bmark, label=label)
1142 pad = " " * (25 - encoding.colwidth(bmark))
1142 pad = " " * (25 - encoding.colwidth(bmark))
1143 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1143 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1144 repo.changelog.rev(n), hexfn(n), label=label)
1144 repo.changelog.rev(n), hexfn(n), label=label)
1145 fm.data(active=(bmark == active))
1145 fm.data(active=(bmark == active))
1146 fm.plain('\n')
1146 fm.plain('\n')
1147 fm.end()
1147 fm.end()
1148
1148
1149 @command('branch',
1149 @command('branch',
1150 [('f', 'force', None,
1150 [('f', 'force', None,
1151 _('set branch name even if it shadows an existing branch')),
1151 _('set branch name even if it shadows an existing branch')),
1152 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1152 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1153 _('[-fC] [NAME]'))
1153 _('[-fC] [NAME]'))
1154 def branch(ui, repo, label=None, **opts):
1154 def branch(ui, repo, label=None, **opts):
1155 """set or show the current branch name
1155 """set or show the current branch name
1156
1156
1157 .. note::
1157 .. note::
1158
1158
1159 Branch names are permanent and global. Use :hg:`bookmark` to create a
1159 Branch names are permanent and global. Use :hg:`bookmark` to create a
1160 light-weight bookmark instead. See :hg:`help glossary` for more
1160 light-weight bookmark instead. See :hg:`help glossary` for more
1161 information about named branches and bookmarks.
1161 information about named branches and bookmarks.
1162
1162
1163 With no argument, show the current branch name. With one argument,
1163 With no argument, show the current branch name. With one argument,
1164 set the working directory branch name (the branch will not exist
1164 set the working directory branch name (the branch will not exist
1165 in the repository until the next commit). Standard practice
1165 in the repository until the next commit). Standard practice
1166 recommends that primary development take place on the 'default'
1166 recommends that primary development take place on the 'default'
1167 branch.
1167 branch.
1168
1168
1169 Unless -f/--force is specified, branch will not let you set a
1169 Unless -f/--force is specified, branch will not let you set a
1170 branch name that already exists.
1170 branch name that already exists.
1171
1171
1172 Use -C/--clean to reset the working directory branch to that of
1172 Use -C/--clean to reset the working directory branch to that of
1173 the parent of the working directory, negating a previous branch
1173 the parent of the working directory, negating a previous branch
1174 change.
1174 change.
1175
1175
1176 Use the command :hg:`update` to switch to an existing branch. Use
1176 Use the command :hg:`update` to switch to an existing branch. Use
1177 :hg:`commit --close-branch` to mark this branch head as closed.
1177 :hg:`commit --close-branch` to mark this branch head as closed.
1178 When all heads of a branch are closed, the branch will be
1178 When all heads of a branch are closed, the branch will be
1179 considered closed.
1179 considered closed.
1180
1180
1181 Returns 0 on success.
1181 Returns 0 on success.
1182 """
1182 """
1183 if label:
1183 if label:
1184 label = label.strip()
1184 label = label.strip()
1185
1185
1186 if not opts.get('clean') and not label:
1186 if not opts.get('clean') and not label:
1187 ui.write("%s\n" % repo.dirstate.branch())
1187 ui.write("%s\n" % repo.dirstate.branch())
1188 return
1188 return
1189
1189
1190 with repo.wlock():
1190 with repo.wlock():
1191 if opts.get('clean'):
1191 if opts.get('clean'):
1192 label = repo[None].p1().branch()
1192 label = repo[None].p1().branch()
1193 repo.dirstate.setbranch(label)
1193 repo.dirstate.setbranch(label)
1194 ui.status(_('reset working directory to branch %s\n') % label)
1194 ui.status(_('reset working directory to branch %s\n') % label)
1195 elif label:
1195 elif label:
1196 if not opts.get('force') and label in repo.branchmap():
1196 if not opts.get('force') and label in repo.branchmap():
1197 if label not in [p.branch() for p in repo[None].parents()]:
1197 if label not in [p.branch() for p in repo[None].parents()]:
1198 raise error.Abort(_('a branch of the same name already'
1198 raise error.Abort(_('a branch of the same name already'
1199 ' exists'),
1199 ' exists'),
1200 # i18n: "it" refers to an existing branch
1200 # i18n: "it" refers to an existing branch
1201 hint=_("use 'hg update' to switch to it"))
1201 hint=_("use 'hg update' to switch to it"))
1202 scmutil.checknewlabel(repo, label, 'branch')
1202 scmutil.checknewlabel(repo, label, 'branch')
1203 repo.dirstate.setbranch(label)
1203 repo.dirstate.setbranch(label)
1204 ui.status(_('marked working directory as branch %s\n') % label)
1204 ui.status(_('marked working directory as branch %s\n') % label)
1205
1205
1206 # find any open named branches aside from default
1206 # find any open named branches aside from default
1207 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1207 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1208 if n != "default" and not c]
1208 if n != "default" and not c]
1209 if not others:
1209 if not others:
1210 ui.status(_('(branches are permanent and global, '
1210 ui.status(_('(branches are permanent and global, '
1211 'did you want a bookmark?)\n'))
1211 'did you want a bookmark?)\n'))
1212
1212
1213 @command('branches',
1213 @command('branches',
1214 [('a', 'active', False,
1214 [('a', 'active', False,
1215 _('show only branches that have unmerged heads (DEPRECATED)')),
1215 _('show only branches that have unmerged heads (DEPRECATED)')),
1216 ('c', 'closed', False, _('show normal and closed branches')),
1216 ('c', 'closed', False, _('show normal and closed branches')),
1217 ] + formatteropts,
1217 ] + formatteropts,
1218 _('[-c]'))
1218 _('[-c]'))
1219 def branches(ui, repo, active=False, closed=False, **opts):
1219 def branches(ui, repo, active=False, closed=False, **opts):
1220 """list repository named branches
1220 """list repository named branches
1221
1221
1222 List the repository's named branches, indicating which ones are
1222 List the repository's named branches, indicating which ones are
1223 inactive. If -c/--closed is specified, also list branches which have
1223 inactive. If -c/--closed is specified, also list branches which have
1224 been marked closed (see :hg:`commit --close-branch`).
1224 been marked closed (see :hg:`commit --close-branch`).
1225
1225
1226 Use the command :hg:`update` to switch to an existing branch.
1226 Use the command :hg:`update` to switch to an existing branch.
1227
1227
1228 Returns 0.
1228 Returns 0.
1229 """
1229 """
1230
1230
1231 fm = ui.formatter('branches', opts)
1231 fm = ui.formatter('branches', opts)
1232 hexfunc = fm.hexfunc
1232 hexfunc = fm.hexfunc
1233
1233
1234 allheads = set(repo.heads())
1234 allheads = set(repo.heads())
1235 branches = []
1235 branches = []
1236 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1236 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1237 isactive = not isclosed and bool(set(heads) & allheads)
1237 isactive = not isclosed and bool(set(heads) & allheads)
1238 branches.append((tag, repo[tip], isactive, not isclosed))
1238 branches.append((tag, repo[tip], isactive, not isclosed))
1239 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1239 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1240 reverse=True)
1240 reverse=True)
1241
1241
1242 for tag, ctx, isactive, isopen in branches:
1242 for tag, ctx, isactive, isopen in branches:
1243 if active and not isactive:
1243 if active and not isactive:
1244 continue
1244 continue
1245 if isactive:
1245 if isactive:
1246 label = 'branches.active'
1246 label = 'branches.active'
1247 notice = ''
1247 notice = ''
1248 elif not isopen:
1248 elif not isopen:
1249 if not closed:
1249 if not closed:
1250 continue
1250 continue
1251 label = 'branches.closed'
1251 label = 'branches.closed'
1252 notice = _(' (closed)')
1252 notice = _(' (closed)')
1253 else:
1253 else:
1254 label = 'branches.inactive'
1254 label = 'branches.inactive'
1255 notice = _(' (inactive)')
1255 notice = _(' (inactive)')
1256 current = (tag == repo.dirstate.branch())
1256 current = (tag == repo.dirstate.branch())
1257 if current:
1257 if current:
1258 label = 'branches.current'
1258 label = 'branches.current'
1259
1259
1260 fm.startitem()
1260 fm.startitem()
1261 fm.write('branch', '%s', tag, label=label)
1261 fm.write('branch', '%s', tag, label=label)
1262 rev = ctx.rev()
1262 rev = ctx.rev()
1263 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1263 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1264 fmt = ' ' * padsize + ' %d:%s'
1264 fmt = ' ' * padsize + ' %d:%s'
1265 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1265 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1266 label='log.changeset changeset.%s' % ctx.phasestr())
1266 label='log.changeset changeset.%s' % ctx.phasestr())
1267 fm.data(active=isactive, closed=not isopen, current=current)
1267 fm.data(active=isactive, closed=not isopen, current=current)
1268 if not ui.quiet:
1268 if not ui.quiet:
1269 fm.plain(notice)
1269 fm.plain(notice)
1270 fm.plain('\n')
1270 fm.plain('\n')
1271 fm.end()
1271 fm.end()
1272
1272
1273 @command('bundle',
1273 @command('bundle',
1274 [('f', 'force', None, _('run even when the destination is unrelated')),
1274 [('f', 'force', None, _('run even when the destination is unrelated')),
1275 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1275 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1276 _('REV')),
1276 _('REV')),
1277 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1277 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1278 _('BRANCH')),
1278 _('BRANCH')),
1279 ('', 'base', [],
1279 ('', 'base', [],
1280 _('a base changeset assumed to be available at the destination'),
1280 _('a base changeset assumed to be available at the destination'),
1281 _('REV')),
1281 _('REV')),
1282 ('a', 'all', None, _('bundle all changesets in the repository')),
1282 ('a', 'all', None, _('bundle all changesets in the repository')),
1283 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1283 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1284 ] + remoteopts,
1284 ] + remoteopts,
1285 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1285 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1286 def bundle(ui, repo, fname, dest=None, **opts):
1286 def bundle(ui, repo, fname, dest=None, **opts):
1287 """create a changegroup file
1287 """create a changegroup file
1288
1288
1289 Generate a changegroup file collecting changesets to be added
1289 Generate a changegroup file collecting changesets to be added
1290 to a repository.
1290 to a repository.
1291
1291
1292 To create a bundle containing all changesets, use -a/--all
1292 To create a bundle containing all changesets, use -a/--all
1293 (or --base null). Otherwise, hg assumes the destination will have
1293 (or --base null). Otherwise, hg assumes the destination will have
1294 all the nodes you specify with --base parameters. Otherwise, hg
1294 all the nodes you specify with --base parameters. Otherwise, hg
1295 will assume the repository has all the nodes in destination, or
1295 will assume the repository has all the nodes in destination, or
1296 default-push/default if no destination is specified.
1296 default-push/default if no destination is specified.
1297
1297
1298 You can change bundle format with the -t/--type option. You can
1298 You can change bundle format with the -t/--type option. You can
1299 specify a compression, a bundle version or both using a dash
1299 specify a compression, a bundle version or both using a dash
1300 (comp-version). The available compression methods are: none, bzip2,
1300 (comp-version). The available compression methods are: none, bzip2,
1301 and gzip (by default, bundles are compressed using bzip2). The
1301 and gzip (by default, bundles are compressed using bzip2). The
1302 available formats are: v1, v2 (default to most suitable).
1302 available formats are: v1, v2 (default to most suitable).
1303
1303
1304 The bundle file can then be transferred using conventional means
1304 The bundle file can then be transferred using conventional means
1305 and applied to another repository with the unbundle or pull
1305 and applied to another repository with the unbundle or pull
1306 command. This is useful when direct push and pull are not
1306 command. This is useful when direct push and pull are not
1307 available or when exporting an entire repository is undesirable.
1307 available or when exporting an entire repository is undesirable.
1308
1308
1309 Applying bundles preserves all changeset contents including
1309 Applying bundles preserves all changeset contents including
1310 permissions, copy/rename information, and revision history.
1310 permissions, copy/rename information, and revision history.
1311
1311
1312 Returns 0 on success, 1 if no changes found.
1312 Returns 0 on success, 1 if no changes found.
1313 """
1313 """
1314 revs = None
1314 revs = None
1315 if 'rev' in opts:
1315 if 'rev' in opts:
1316 revstrings = opts['rev']
1316 revstrings = opts['rev']
1317 revs = scmutil.revrange(repo, revstrings)
1317 revs = scmutil.revrange(repo, revstrings)
1318 if revstrings and not revs:
1318 if revstrings and not revs:
1319 raise error.Abort(_('no commits to bundle'))
1319 raise error.Abort(_('no commits to bundle'))
1320
1320
1321 bundletype = opts.get('type', 'bzip2').lower()
1321 bundletype = opts.get('type', 'bzip2').lower()
1322 try:
1322 try:
1323 bcompression, cgversion, params = exchange.parsebundlespec(
1323 bcompression, cgversion, params = exchange.parsebundlespec(
1324 repo, bundletype, strict=False)
1324 repo, bundletype, strict=False)
1325 except error.UnsupportedBundleSpecification as e:
1325 except error.UnsupportedBundleSpecification as e:
1326 raise error.Abort(str(e),
1326 raise error.Abort(str(e),
1327 hint=_("see 'hg help bundle' for supported "
1327 hint=_("see 'hg help bundle' for supported "
1328 "values for --type"))
1328 "values for --type"))
1329
1329
1330 # Packed bundles are a pseudo bundle format for now.
1330 # Packed bundles are a pseudo bundle format for now.
1331 if cgversion == 's1':
1331 if cgversion == 's1':
1332 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1332 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1333 hint=_("use 'hg debugcreatestreamclonebundle'"))
1333 hint=_("use 'hg debugcreatestreamclonebundle'"))
1334
1334
1335 if opts.get('all'):
1335 if opts.get('all'):
1336 if dest:
1336 if dest:
1337 raise error.Abort(_("--all is incompatible with specifying "
1337 raise error.Abort(_("--all is incompatible with specifying "
1338 "a destination"))
1338 "a destination"))
1339 if opts.get('base'):
1339 if opts.get('base'):
1340 ui.warn(_("ignoring --base because --all was specified\n"))
1340 ui.warn(_("ignoring --base because --all was specified\n"))
1341 base = ['null']
1341 base = ['null']
1342 else:
1342 else:
1343 base = scmutil.revrange(repo, opts.get('base'))
1343 base = scmutil.revrange(repo, opts.get('base'))
1344 # TODO: get desired bundlecaps from command line.
1344 # TODO: get desired bundlecaps from command line.
1345 bundlecaps = None
1345 bundlecaps = None
1346 if cgversion not in changegroup.supportedoutgoingversions(repo):
1346 if cgversion not in changegroup.supportedoutgoingversions(repo):
1347 raise error.Abort(_("repository does not support bundle version %s") %
1347 raise error.Abort(_("repository does not support bundle version %s") %
1348 cgversion)
1348 cgversion)
1349
1349
1350 if base:
1350 if base:
1351 if dest:
1351 if dest:
1352 raise error.Abort(_("--base is incompatible with specifying "
1352 raise error.Abort(_("--base is incompatible with specifying "
1353 "a destination"))
1353 "a destination"))
1354 common = [repo.lookup(rev) for rev in base]
1354 common = [repo.lookup(rev) for rev in base]
1355 heads = revs and map(repo.lookup, revs) or None
1355 heads = revs and map(repo.lookup, revs) or None
1356 outgoing = discovery.outgoing(repo, common, heads)
1356 outgoing = discovery.outgoing(repo, common, heads)
1357 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1357 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1358 bundlecaps=bundlecaps,
1358 bundlecaps=bundlecaps,
1359 version=cgversion)
1359 version=cgversion)
1360 outgoing = None
1360 outgoing = None
1361 else:
1361 else:
1362 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1362 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1363 dest, branches = hg.parseurl(dest, opts.get('branch'))
1363 dest, branches = hg.parseurl(dest, opts.get('branch'))
1364 other = hg.peer(repo, opts, dest)
1364 other = hg.peer(repo, opts, dest)
1365 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1365 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1366 heads = revs and map(repo.lookup, revs) or revs
1366 heads = revs and map(repo.lookup, revs) or revs
1367 outgoing = discovery.findcommonoutgoing(repo, other,
1367 outgoing = discovery.findcommonoutgoing(repo, other,
1368 onlyheads=heads,
1368 onlyheads=heads,
1369 force=opts.get('force'),
1369 force=opts.get('force'),
1370 portable=True)
1370 portable=True)
1371 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1371 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1372 bundlecaps, version=cgversion)
1372 bundlecaps, version=cgversion)
1373 if not cg:
1373 if not cg:
1374 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1374 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1375 return 1
1375 return 1
1376
1376
1377 if cgversion == '01': #bundle1
1377 if cgversion == '01': #bundle1
1378 if bcompression is None:
1378 if bcompression is None:
1379 bcompression = 'UN'
1379 bcompression = 'UN'
1380 bversion = 'HG10' + bcompression
1380 bversion = 'HG10' + bcompression
1381 bcompression = None
1381 bcompression = None
1382 else:
1382 else:
1383 assert cgversion == '02'
1383 assert cgversion == '02'
1384 bversion = 'HG20'
1384 bversion = 'HG20'
1385
1385
1386 # TODO compression options should be derived from bundlespec parsing.
1386 # TODO compression options should be derived from bundlespec parsing.
1387 # This is a temporary hack to allow adjusting bundle compression
1387 # This is a temporary hack to allow adjusting bundle compression
1388 # level without a) formalizing the bundlespec changes to declare it
1388 # level without a) formalizing the bundlespec changes to declare it
1389 # b) introducing a command flag.
1389 # b) introducing a command flag.
1390 compopts = {}
1390 compopts = {}
1391 complevel = ui.configint('experimental', 'bundlecomplevel')
1391 complevel = ui.configint('experimental', 'bundlecomplevel')
1392 if complevel is not None:
1392 if complevel is not None:
1393 compopts['level'] = complevel
1393 compopts['level'] = complevel
1394
1394
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1396 compopts=compopts)
1396 compopts=compopts)
1397
1397
1398 @command('cat',
1398 @command('cat',
1399 [('o', 'output', '',
1399 [('o', 'output', '',
1400 _('print output to file with formatted name'), _('FORMAT')),
1400 _('print output to file with formatted name'), _('FORMAT')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1403 ] + walkopts,
1403 ] + walkopts,
1404 _('[OPTION]... FILE...'),
1404 _('[OPTION]... FILE...'),
1405 inferrepo=True)
1405 inferrepo=True)
1406 def cat(ui, repo, file1, *pats, **opts):
1406 def cat(ui, repo, file1, *pats, **opts):
1407 """output the current or given revision of files
1407 """output the current or given revision of files
1408
1408
1409 Print the specified files as they were at the given revision. If
1409 Print the specified files as they were at the given revision. If
1410 no revision is given, the parent of the working directory is used.
1410 no revision is given, the parent of the working directory is used.
1411
1411
1412 Output may be to a file, in which case the name of the file is
1412 Output may be to a file, in which case the name of the file is
1413 given using a format string. The formatting rules as follows:
1413 given using a format string. The formatting rules as follows:
1414
1414
1415 :``%%``: literal "%" character
1415 :``%%``: literal "%" character
1416 :``%s``: basename of file being printed
1416 :``%s``: basename of file being printed
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%p``: root-relative path name of file being printed
1418 :``%p``: root-relative path name of file being printed
1419 :``%H``: changeset hash (40 hexadecimal digits)
1419 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%R``: changeset revision number
1420 :``%R``: changeset revision number
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%r``: zero-padded changeset revision number
1422 :``%r``: zero-padded changeset revision number
1423 :``%b``: basename of the exporting repository
1423 :``%b``: basename of the exporting repository
1424
1424
1425 Returns 0 on success.
1425 Returns 0 on success.
1426 """
1426 """
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1429
1429
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431
1431
1432 @command('^clone',
1432 @command('^clone',
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 'directory (only a repository)')),
1434 'directory (only a repository)')),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 _('REV')),
1436 _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ] + remoteopts,
1441 ] + remoteopts,
1442 _('[OPTION]... SOURCE [DEST]'),
1442 _('[OPTION]... SOURCE [DEST]'),
1443 norepo=True)
1443 norepo=True)
1444 def clone(ui, source, dest=None, **opts):
1444 def clone(ui, source, dest=None, **opts):
1445 """make a copy of an existing repository
1445 """make a copy of an existing repository
1446
1446
1447 Create a copy of an existing repository in a new directory.
1447 Create a copy of an existing repository in a new directory.
1448
1448
1449 If no destination directory name is specified, it defaults to the
1449 If no destination directory name is specified, it defaults to the
1450 basename of the source.
1450 basename of the source.
1451
1451
1452 The location of the source is added to the new repository's
1452 The location of the source is added to the new repository's
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1453 ``.hg/hgrc`` file, as the default to be used for future pulls.
1454
1454
1455 Only local paths and ``ssh://`` URLs are supported as
1455 Only local paths and ``ssh://`` URLs are supported as
1456 destinations. For ``ssh://`` destinations, no working directory or
1456 destinations. For ``ssh://`` destinations, no working directory or
1457 ``.hg/hgrc`` will be created on the remote side.
1457 ``.hg/hgrc`` will be created on the remote side.
1458
1458
1459 If the source repository has a bookmark called '@' set, that
1459 If the source repository has a bookmark called '@' set, that
1460 revision will be checked out in the new repository by default.
1460 revision will be checked out in the new repository by default.
1461
1461
1462 To check out a particular version, use -u/--update, or
1462 To check out a particular version, use -u/--update, or
1463 -U/--noupdate to create a clone with no working directory.
1463 -U/--noupdate to create a clone with no working directory.
1464
1464
1465 To pull only a subset of changesets, specify one or more revisions
1465 To pull only a subset of changesets, specify one or more revisions
1466 identifiers with -r/--rev or branches with -b/--branch. The
1466 identifiers with -r/--rev or branches with -b/--branch. The
1467 resulting clone will contain only the specified changesets and
1467 resulting clone will contain only the specified changesets and
1468 their ancestors. These options (or 'clone src#rev dest') imply
1468 their ancestors. These options (or 'clone src#rev dest') imply
1469 --pull, even for local source repositories.
1469 --pull, even for local source repositories.
1470
1470
1471 .. note::
1471 .. note::
1472
1472
1473 Specifying a tag will include the tagged changeset but not the
1473 Specifying a tag will include the tagged changeset but not the
1474 changeset containing the tag.
1474 changeset containing the tag.
1475
1475
1476 .. container:: verbose
1476 .. container:: verbose
1477
1477
1478 For efficiency, hardlinks are used for cloning whenever the
1478 For efficiency, hardlinks are used for cloning whenever the
1479 source and destination are on the same filesystem (note this
1479 source and destination are on the same filesystem (note this
1480 applies only to the repository data, not to the working
1480 applies only to the repository data, not to the working
1481 directory). Some filesystems, such as AFS, implement hardlinking
1481 directory). Some filesystems, such as AFS, implement hardlinking
1482 incorrectly, but do not report errors. In these cases, use the
1482 incorrectly, but do not report errors. In these cases, use the
1483 --pull option to avoid hardlinking.
1483 --pull option to avoid hardlinking.
1484
1484
1485 In some cases, you can clone repositories and the working
1485 In some cases, you can clone repositories and the working
1486 directory using full hardlinks with ::
1486 directory using full hardlinks with ::
1487
1487
1488 $ cp -al REPO REPOCLONE
1488 $ cp -al REPO REPOCLONE
1489
1489
1490 This is the fastest way to clone, but it is not always safe. The
1490 This is the fastest way to clone, but it is not always safe. The
1491 operation is not atomic (making sure REPO is not modified during
1491 operation is not atomic (making sure REPO is not modified during
1492 the operation is up to you) and you have to make sure your
1492 the operation is up to you) and you have to make sure your
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 so). Also, this is not compatible with certain extensions that
1494 so). Also, this is not compatible with certain extensions that
1495 place their metadata under the .hg directory, such as mq.
1495 place their metadata under the .hg directory, such as mq.
1496
1496
1497 Mercurial will update the working directory to the first applicable
1497 Mercurial will update the working directory to the first applicable
1498 revision from this list:
1498 revision from this list:
1499
1499
1500 a) null if -U or the source repository has no changesets
1500 a) null if -U or the source repository has no changesets
1501 b) if -u . and the source repository is local, the first parent of
1501 b) if -u . and the source repository is local, the first parent of
1502 the source repository's working directory
1502 the source repository's working directory
1503 c) the changeset specified with -u (if a branch name, this means the
1503 c) the changeset specified with -u (if a branch name, this means the
1504 latest head of that branch)
1504 latest head of that branch)
1505 d) the changeset specified with -r
1505 d) the changeset specified with -r
1506 e) the tipmost head specified with -b
1506 e) the tipmost head specified with -b
1507 f) the tipmost head specified with the url#branch source syntax
1507 f) the tipmost head specified with the url#branch source syntax
1508 g) the revision marked with the '@' bookmark, if present
1508 g) the revision marked with the '@' bookmark, if present
1509 h) the tipmost head of the default branch
1509 h) the tipmost head of the default branch
1510 i) tip
1510 i) tip
1511
1511
1512 When cloning from servers that support it, Mercurial may fetch
1512 When cloning from servers that support it, Mercurial may fetch
1513 pre-generated data from a server-advertised URL. When this is done,
1513 pre-generated data from a server-advertised URL. When this is done,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1515 once for the bundle fetched from the URL and another for any additional
1515 once for the bundle fetched from the URL and another for any additional
1516 data not fetched from this URL. In addition, if an error occurs, the
1516 data not fetched from this URL. In addition, if an error occurs, the
1517 repository may be rolled back to a partial clone. This behavior may
1517 repository may be rolled back to a partial clone. This behavior may
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1519
1519
1520 Examples:
1520 Examples:
1521
1521
1522 - clone a remote repository to a new directory named hg/::
1522 - clone a remote repository to a new directory named hg/::
1523
1523
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1525
1525
1526 - create a lightweight local clone::
1526 - create a lightweight local clone::
1527
1527
1528 hg clone project/ project-feature/
1528 hg clone project/ project-feature/
1529
1529
1530 - clone from an absolute path on an ssh server (note double-slash)::
1530 - clone from an absolute path on an ssh server (note double-slash)::
1531
1531
1532 hg clone ssh://user@server//home/projects/alpha/
1532 hg clone ssh://user@server//home/projects/alpha/
1533
1533
1534 - do a high-speed clone over a LAN while checking out a
1534 - do a high-speed clone over a LAN while checking out a
1535 specified version::
1535 specified version::
1536
1536
1537 hg clone --uncompressed http://server/repo -u 1.5
1537 hg clone --uncompressed http://server/repo -u 1.5
1538
1538
1539 - create a repository without changesets after a particular revision::
1539 - create a repository without changesets after a particular revision::
1540
1540
1541 hg clone -r 04e544 experimental/ good/
1541 hg clone -r 04e544 experimental/ good/
1542
1542
1543 - clone (and track) a particular named branch::
1543 - clone (and track) a particular named branch::
1544
1544
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1546
1546
1547 See :hg:`help urls` for details on specifying URLs.
1547 See :hg:`help urls` for details on specifying URLs.
1548
1548
1549 Returns 0 on success.
1549 Returns 0 on success.
1550 """
1550 """
1551 if opts.get('noupdate') and opts.get('updaterev'):
1551 if opts.get('noupdate') and opts.get('updaterev'):
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1553
1553
1554 r = hg.clone(ui, opts, source, dest,
1554 r = hg.clone(ui, opts, source, dest,
1555 pull=opts.get('pull'),
1555 pull=opts.get('pull'),
1556 stream=opts.get('uncompressed'),
1556 stream=opts.get('uncompressed'),
1557 rev=opts.get('rev'),
1557 rev=opts.get('rev'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1559 branch=opts.get('branch'),
1559 branch=opts.get('branch'),
1560 shareopts=opts.get('shareopts'))
1560 shareopts=opts.get('shareopts'))
1561
1561
1562 return r is None
1562 return r is None
1563
1563
1564 @command('^commit|ci',
1564 @command('^commit|ci',
1565 [('A', 'addremove', None,
1565 [('A', 'addremove', None,
1566 _('mark new/missing files as added/removed before committing')),
1566 _('mark new/missing files as added/removed before committing')),
1567 ('', 'close-branch', None,
1567 ('', 'close-branch', None,
1568 _('mark a branch head as closed')),
1568 _('mark a branch head as closed')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1574 _('[OPTION]... [FILE]...'),
1574 _('[OPTION]... [FILE]...'),
1575 inferrepo=True)
1575 inferrepo=True)
1576 def commit(ui, repo, *pats, **opts):
1576 def commit(ui, repo, *pats, **opts):
1577 """commit the specified files or all outstanding changes
1577 """commit the specified files or all outstanding changes
1578
1578
1579 Commit changes to the given files into the repository. Unlike a
1579 Commit changes to the given files into the repository. Unlike a
1580 centralized SCM, this operation is a local operation. See
1580 centralized SCM, this operation is a local operation. See
1581 :hg:`push` for a way to actively distribute your changes.
1581 :hg:`push` for a way to actively distribute your changes.
1582
1582
1583 If a list of files is omitted, all changes reported by :hg:`status`
1583 If a list of files is omitted, all changes reported by :hg:`status`
1584 will be committed.
1584 will be committed.
1585
1585
1586 If you are committing the result of a merge, do not provide any
1586 If you are committing the result of a merge, do not provide any
1587 filenames or -I/-X filters.
1587 filenames or -I/-X filters.
1588
1588
1589 If no commit message is specified, Mercurial starts your
1589 If no commit message is specified, Mercurial starts your
1590 configured editor where you can enter a message. In case your
1590 configured editor where you can enter a message. In case your
1591 commit fails, you will find a backup of your message in
1591 commit fails, you will find a backup of your message in
1592 ``.hg/last-message.txt``.
1592 ``.hg/last-message.txt``.
1593
1593
1594 The --close-branch flag can be used to mark the current branch
1594 The --close-branch flag can be used to mark the current branch
1595 head closed. When all heads of a branch are closed, the branch
1595 head closed. When all heads of a branch are closed, the branch
1596 will be considered closed and no longer listed.
1596 will be considered closed and no longer listed.
1597
1597
1598 The --amend flag can be used to amend the parent of the
1598 The --amend flag can be used to amend the parent of the
1599 working directory with a new commit that contains the changes
1599 working directory with a new commit that contains the changes
1600 in the parent in addition to those currently reported by :hg:`status`,
1600 in the parent in addition to those currently reported by :hg:`status`,
1601 if there are any. The old commit is stored in a backup bundle in
1601 if there are any. The old commit is stored in a backup bundle in
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 on how to restore it).
1603 on how to restore it).
1604
1604
1605 Message, user and date are taken from the amended commit unless
1605 Message, user and date are taken from the amended commit unless
1606 specified. When a message isn't specified on the command line,
1606 specified. When a message isn't specified on the command line,
1607 the editor will open with the message of the amended commit.
1607 the editor will open with the message of the amended commit.
1608
1608
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1609 It is not possible to amend public changesets (see :hg:`help phases`)
1610 or changesets that have children.
1610 or changesets that have children.
1611
1611
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1612 See :hg:`help dates` for a list of formats valid for -d/--date.
1613
1613
1614 Returns 0 on success, 1 if nothing changed.
1614 Returns 0 on success, 1 if nothing changed.
1615
1615
1616 .. container:: verbose
1616 .. container:: verbose
1617
1617
1618 Examples:
1618 Examples:
1619
1619
1620 - commit all files ending in .py::
1620 - commit all files ending in .py::
1621
1621
1622 hg commit --include "set:**.py"
1622 hg commit --include "set:**.py"
1623
1623
1624 - commit all non-binary files::
1624 - commit all non-binary files::
1625
1625
1626 hg commit --exclude "set:binary()"
1626 hg commit --exclude "set:binary()"
1627
1627
1628 - amend the current commit and set the date to now::
1628 - amend the current commit and set the date to now::
1629
1629
1630 hg commit --amend --date now
1630 hg commit --amend --date now
1631 """
1631 """
1632 wlock = lock = None
1632 wlock = lock = None
1633 try:
1633 try:
1634 wlock = repo.wlock()
1634 wlock = repo.wlock()
1635 lock = repo.lock()
1635 lock = repo.lock()
1636 return _docommit(ui, repo, *pats, **opts)
1636 return _docommit(ui, repo, *pats, **opts)
1637 finally:
1637 finally:
1638 release(lock, wlock)
1638 release(lock, wlock)
1639
1639
1640 def _docommit(ui, repo, *pats, **opts):
1640 def _docommit(ui, repo, *pats, **opts):
1641 if opts.get('interactive'):
1641 if opts.get('interactive'):
1642 opts.pop('interactive')
1642 opts.pop('interactive')
1643 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1643 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1644 cmdutil.recordfilter, *pats, **opts)
1644 cmdutil.recordfilter, *pats, **opts)
1645 # ret can be 0 (no changes to record) or the value returned by
1645 # ret can be 0 (no changes to record) or the value returned by
1646 # commit(), 1 if nothing changed or None on success.
1646 # commit(), 1 if nothing changed or None on success.
1647 return 1 if ret == 0 else ret
1647 return 1 if ret == 0 else ret
1648
1648
1649 if opts.get('subrepos'):
1649 if opts.get('subrepos'):
1650 if opts.get('amend'):
1650 if opts.get('amend'):
1651 raise error.Abort(_('cannot amend with --subrepos'))
1651 raise error.Abort(_('cannot amend with --subrepos'))
1652 # Let --subrepos on the command line override config setting.
1652 # Let --subrepos on the command line override config setting.
1653 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1653 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1654
1654
1655 cmdutil.checkunfinished(repo, commit=True)
1655 cmdutil.checkunfinished(repo, commit=True)
1656
1656
1657 branch = repo[None].branch()
1657 branch = repo[None].branch()
1658 bheads = repo.branchheads(branch)
1658 bheads = repo.branchheads(branch)
1659
1659
1660 extra = {}
1660 extra = {}
1661 if opts.get('close_branch'):
1661 if opts.get('close_branch'):
1662 extra['close'] = 1
1662 extra['close'] = 1
1663
1663
1664 if not bheads:
1664 if not bheads:
1665 raise error.Abort(_('can only close branch heads'))
1665 raise error.Abort(_('can only close branch heads'))
1666 elif opts.get('amend'):
1666 elif opts.get('amend'):
1667 if repo[None].parents()[0].p1().branch() != branch and \
1667 if repo[None].parents()[0].p1().branch() != branch and \
1668 repo[None].parents()[0].p2().branch() != branch:
1668 repo[None].parents()[0].p2().branch() != branch:
1669 raise error.Abort(_('can only close branch heads'))
1669 raise error.Abort(_('can only close branch heads'))
1670
1670
1671 if opts.get('amend'):
1671 if opts.get('amend'):
1672 if ui.configbool('ui', 'commitsubrepos'):
1672 if ui.configbool('ui', 'commitsubrepos'):
1673 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1673 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1674
1674
1675 old = repo['.']
1675 old = repo['.']
1676 if not old.mutable():
1676 if not old.mutable():
1677 raise error.Abort(_('cannot amend public changesets'))
1677 raise error.Abort(_('cannot amend public changesets'))
1678 if len(repo[None].parents()) > 1:
1678 if len(repo[None].parents()) > 1:
1679 raise error.Abort(_('cannot amend while merging'))
1679 raise error.Abort(_('cannot amend while merging'))
1680 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1680 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1681 if not allowunstable and old.children():
1681 if not allowunstable and old.children():
1682 raise error.Abort(_('cannot amend changeset with children'))
1682 raise error.Abort(_('cannot amend changeset with children'))
1683
1683
1684 # Currently histedit gets confused if an amend happens while histedit
1684 # Currently histedit gets confused if an amend happens while histedit
1685 # is in progress. Since we have a checkunfinished command, we are
1685 # is in progress. Since we have a checkunfinished command, we are
1686 # temporarily honoring it.
1686 # temporarily honoring it.
1687 #
1687 #
1688 # Note: eventually this guard will be removed. Please do not expect
1688 # Note: eventually this guard will be removed. Please do not expect
1689 # this behavior to remain.
1689 # this behavior to remain.
1690 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1690 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1691 cmdutil.checkunfinished(repo)
1691 cmdutil.checkunfinished(repo)
1692
1692
1693 # commitfunc is used only for temporary amend commit by cmdutil.amend
1693 # commitfunc is used only for temporary amend commit by cmdutil.amend
1694 def commitfunc(ui, repo, message, match, opts):
1694 def commitfunc(ui, repo, message, match, opts):
1695 return repo.commit(message,
1695 return repo.commit(message,
1696 opts.get('user') or old.user(),
1696 opts.get('user') or old.user(),
1697 opts.get('date') or old.date(),
1697 opts.get('date') or old.date(),
1698 match,
1698 match,
1699 extra=extra)
1699 extra=extra)
1700
1700
1701 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1701 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1702 if node == old.node():
1702 if node == old.node():
1703 ui.status(_("nothing changed\n"))
1703 ui.status(_("nothing changed\n"))
1704 return 1
1704 return 1
1705 else:
1705 else:
1706 def commitfunc(ui, repo, message, match, opts):
1706 def commitfunc(ui, repo, message, match, opts):
1707 backup = ui.backupconfig('phases', 'new-commit')
1707 backup = ui.backupconfig('phases', 'new-commit')
1708 baseui = repo.baseui
1708 baseui = repo.baseui
1709 basebackup = baseui.backupconfig('phases', 'new-commit')
1709 basebackup = baseui.backupconfig('phases', 'new-commit')
1710 try:
1710 try:
1711 if opts.get('secret'):
1711 if opts.get('secret'):
1712 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1712 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1713 # Propagate to subrepos
1713 # Propagate to subrepos
1714 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1714 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1715
1715
1716 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1716 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1717 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1717 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1718 return repo.commit(message, opts.get('user'), opts.get('date'),
1718 return repo.commit(message, opts.get('user'), opts.get('date'),
1719 match,
1719 match,
1720 editor=editor,
1720 editor=editor,
1721 extra=extra)
1721 extra=extra)
1722 finally:
1722 finally:
1723 ui.restoreconfig(backup)
1723 ui.restoreconfig(backup)
1724 repo.baseui.restoreconfig(basebackup)
1724 repo.baseui.restoreconfig(basebackup)
1725
1725
1726
1726
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1728
1728
1729 if not node:
1729 if not node:
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1731 if stat[3]:
1731 if stat[3]:
1732 ui.status(_("nothing changed (%d missing files, see "
1732 ui.status(_("nothing changed (%d missing files, see "
1733 "'hg status')\n") % len(stat[3]))
1733 "'hg status')\n") % len(stat[3]))
1734 else:
1734 else:
1735 ui.status(_("nothing changed\n"))
1735 ui.status(_("nothing changed\n"))
1736 return 1
1736 return 1
1737
1737
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1739
1739
1740 @command('config|showconfig|debugconfig',
1740 @command('config|showconfig|debugconfig',
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1742 ('e', 'edit', None, _('edit user config')),
1742 ('e', 'edit', None, _('edit user config')),
1743 ('l', 'local', None, _('edit repository config')),
1743 ('l', 'local', None, _('edit repository config')),
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1745 _('[-u] [NAME]...'),
1745 _('[-u] [NAME]...'),
1746 optionalrepo=True)
1746 optionalrepo=True)
1747 def config(ui, repo, *values, **opts):
1747 def config(ui, repo, *values, **opts):
1748 """show combined config settings from all hgrc files
1748 """show combined config settings from all hgrc files
1749
1749
1750 With no arguments, print names and values of all config items.
1750 With no arguments, print names and values of all config items.
1751
1751
1752 With one argument of the form section.name, print just the value
1752 With one argument of the form section.name, print just the value
1753 of that config item.
1753 of that config item.
1754
1754
1755 With multiple arguments, print names and values of all config
1755 With multiple arguments, print names and values of all config
1756 items with matching section names.
1756 items with matching section names.
1757
1757
1758 With --edit, start an editor on the user-level config file. With
1758 With --edit, start an editor on the user-level config file. With
1759 --global, edit the system-wide config file. With --local, edit the
1759 --global, edit the system-wide config file. With --local, edit the
1760 repository-level config file.
1760 repository-level config file.
1761
1761
1762 With --debug, the source (filename and line number) is printed
1762 With --debug, the source (filename and line number) is printed
1763 for each config item.
1763 for each config item.
1764
1764
1765 See :hg:`help config` for more information about config files.
1765 See :hg:`help config` for more information about config files.
1766
1766
1767 Returns 0 on success, 1 if NAME does not exist.
1767 Returns 0 on success, 1 if NAME does not exist.
1768
1768
1769 """
1769 """
1770
1770
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1771 if opts.get('edit') or opts.get('local') or opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1772 if opts.get('local') and opts.get('global'):
1773 raise error.Abort(_("can't use --local and --global together"))
1773 raise error.Abort(_("can't use --local and --global together"))
1774
1774
1775 if opts.get('local'):
1775 if opts.get('local'):
1776 if not repo:
1776 if not repo:
1777 raise error.Abort(_("can't use --local outside a repository"))
1777 raise error.Abort(_("can't use --local outside a repository"))
1778 paths = [repo.join('hgrc')]
1778 paths = [repo.join('hgrc')]
1779 elif opts.get('global'):
1779 elif opts.get('global'):
1780 paths = scmutil.systemrcpath()
1780 paths = scmutil.systemrcpath()
1781 else:
1781 else:
1782 paths = scmutil.userrcpath()
1782 paths = scmutil.userrcpath()
1783
1783
1784 for f in paths:
1784 for f in paths:
1785 if os.path.exists(f):
1785 if os.path.exists(f):
1786 break
1786 break
1787 else:
1787 else:
1788 if opts.get('global'):
1788 if opts.get('global'):
1789 samplehgrc = uimod.samplehgrcs['global']
1789 samplehgrc = uimod.samplehgrcs['global']
1790 elif opts.get('local'):
1790 elif opts.get('local'):
1791 samplehgrc = uimod.samplehgrcs['local']
1791 samplehgrc = uimod.samplehgrcs['local']
1792 else:
1792 else:
1793 samplehgrc = uimod.samplehgrcs['user']
1793 samplehgrc = uimod.samplehgrcs['user']
1794
1794
1795 f = paths[0]
1795 f = paths[0]
1796 fp = open(f, "w")
1796 fp = open(f, "w")
1797 fp.write(samplehgrc)
1797 fp.write(samplehgrc)
1798 fp.close()
1798 fp.close()
1799
1799
1800 editor = ui.geteditor()
1800 editor = ui.geteditor()
1801 ui.system("%s \"%s\"" % (editor, f),
1801 ui.system("%s \"%s\"" % (editor, f),
1802 onerr=error.Abort, errprefix=_("edit failed"))
1802 onerr=error.Abort, errprefix=_("edit failed"))
1803 return
1803 return
1804
1804
1805 fm = ui.formatter('config', opts)
1805 fm = ui.formatter('config', opts)
1806 for f in scmutil.rcpath():
1806 for f in scmutil.rcpath():
1807 ui.debug('read config from: %s\n' % f)
1807 ui.debug('read config from: %s\n' % f)
1808 untrusted = bool(opts.get('untrusted'))
1808 untrusted = bool(opts.get('untrusted'))
1809 if values:
1809 if values:
1810 sections = [v for v in values if '.' not in v]
1810 sections = [v for v in values if '.' not in v]
1811 items = [v for v in values if '.' in v]
1811 items = [v for v in values if '.' in v]
1812 if len(items) > 1 or items and sections:
1812 if len(items) > 1 or items and sections:
1813 raise error.Abort(_('only one config item permitted'))
1813 raise error.Abort(_('only one config item permitted'))
1814 matched = False
1814 matched = False
1815 for section, name, value in ui.walkconfig(untrusted=untrusted):
1815 for section, name, value in ui.walkconfig(untrusted=untrusted):
1816 source = ui.configsource(section, name, untrusted)
1816 source = ui.configsource(section, name, untrusted)
1817 value = str(value)
1817 value = str(value)
1818 if fm.isplain():
1818 if fm.isplain():
1819 source = source or 'none'
1819 source = source or 'none'
1820 value = value.replace('\n', '\\n')
1820 value = value.replace('\n', '\\n')
1821 entryname = section + '.' + name
1821 entryname = section + '.' + name
1822 if values:
1822 if values:
1823 for v in values:
1823 for v in values:
1824 if v == section:
1824 if v == section:
1825 fm.startitem()
1825 fm.startitem()
1826 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1826 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1827 fm.write('name value', '%s=%s\n', entryname, value)
1827 fm.write('name value', '%s=%s\n', entryname, value)
1828 matched = True
1828 matched = True
1829 elif v == entryname:
1829 elif v == entryname:
1830 fm.startitem()
1830 fm.startitem()
1831 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1831 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1832 fm.write('value', '%s\n', value)
1832 fm.write('value', '%s\n', value)
1833 fm.data(name=entryname)
1833 fm.data(name=entryname)
1834 matched = True
1834 matched = True
1835 else:
1835 else:
1836 fm.startitem()
1836 fm.startitem()
1837 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1837 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1838 fm.write('name value', '%s=%s\n', entryname, value)
1838 fm.write('name value', '%s=%s\n', entryname, value)
1839 matched = True
1839 matched = True
1840 fm.end()
1840 fm.end()
1841 if matched:
1841 if matched:
1842 return 0
1842 return 0
1843 return 1
1843 return 1
1844
1844
1845 @command('copy|cp',
1845 @command('copy|cp',
1846 [('A', 'after', None, _('record a copy that has already occurred')),
1846 [('A', 'after', None, _('record a copy that has already occurred')),
1847 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1847 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1848 ] + walkopts + dryrunopts,
1848 ] + walkopts + dryrunopts,
1849 _('[OPTION]... [SOURCE]... DEST'))
1849 _('[OPTION]... [SOURCE]... DEST'))
1850 def copy(ui, repo, *pats, **opts):
1850 def copy(ui, repo, *pats, **opts):
1851 """mark files as copied for the next commit
1851 """mark files as copied for the next commit
1852
1852
1853 Mark dest as having copies of source files. If dest is a
1853 Mark dest as having copies of source files. If dest is a
1854 directory, copies are put in that directory. If dest is a file,
1854 directory, copies are put in that directory. If dest is a file,
1855 the source must be a single file.
1855 the source must be a single file.
1856
1856
1857 By default, this command copies the contents of files as they
1857 By default, this command copies the contents of files as they
1858 exist in the working directory. If invoked with -A/--after, the
1858 exist in the working directory. If invoked with -A/--after, the
1859 operation is recorded, but no copying is performed.
1859 operation is recorded, but no copying is performed.
1860
1860
1861 This command takes effect with the next commit. To undo a copy
1861 This command takes effect with the next commit. To undo a copy
1862 before that, see :hg:`revert`.
1862 before that, see :hg:`revert`.
1863
1863
1864 Returns 0 on success, 1 if errors are encountered.
1864 Returns 0 on success, 1 if errors are encountered.
1865 """
1865 """
1866 with repo.wlock(False):
1866 with repo.wlock(False):
1867 return cmdutil.copy(ui, repo, pats, opts)
1867 return cmdutil.copy(ui, repo, pats, opts)
1868
1868
1869 @command('debuginstall', [] + formatteropts, '', norepo=True)
1869 @command('debuginstall', [] + formatteropts, '', norepo=True)
1870 def debuginstall(ui, **opts):
1870 def debuginstall(ui, **opts):
1871 '''test Mercurial installation
1871 '''test Mercurial installation
1872
1872
1873 Returns 0 on success.
1873 Returns 0 on success.
1874 '''
1874 '''
1875
1875
1876 def writetemp(contents):
1876 def writetemp(contents):
1877 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1877 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1878 f = os.fdopen(fd, "wb")
1878 f = os.fdopen(fd, "wb")
1879 f.write(contents)
1879 f.write(contents)
1880 f.close()
1880 f.close()
1881 return name
1881 return name
1882
1882
1883 problems = 0
1883 problems = 0
1884
1884
1885 fm = ui.formatter('debuginstall', opts)
1885 fm = ui.formatter('debuginstall', opts)
1886 fm.startitem()
1886 fm.startitem()
1887
1887
1888 # encoding
1888 # encoding
1889 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1889 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1890 err = None
1890 err = None
1891 try:
1891 try:
1892 encoding.fromlocal("test")
1892 encoding.fromlocal("test")
1893 except error.Abort as inst:
1893 except error.Abort as inst:
1894 err = inst
1894 err = inst
1895 problems += 1
1895 problems += 1
1896 fm.condwrite(err, 'encodingerror', _(" %s\n"
1896 fm.condwrite(err, 'encodingerror', _(" %s\n"
1897 " (check that your locale is properly set)\n"), err)
1897 " (check that your locale is properly set)\n"), err)
1898
1898
1899 # Python
1899 # Python
1900 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1900 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1901 pycompat.sysexecutable)
1901 pycompat.sysexecutable)
1902 fm.write('pythonver', _("checking Python version (%s)\n"),
1902 fm.write('pythonver', _("checking Python version (%s)\n"),
1903 ("%d.%d.%d" % sys.version_info[:3]))
1903 ("%d.%d.%d" % sys.version_info[:3]))
1904 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1904 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1905 os.path.dirname(os.__file__))
1905 os.path.dirname(os.__file__))
1906
1906
1907 security = set(sslutil.supportedprotocols)
1907 security = set(sslutil.supportedprotocols)
1908 if sslutil.hassni:
1908 if sslutil.hassni:
1909 security.add('sni')
1909 security.add('sni')
1910
1910
1911 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1911 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1912 fm.formatlist(sorted(security), name='protocol',
1912 fm.formatlist(sorted(security), name='protocol',
1913 fmt='%s', sep=','))
1913 fmt='%s', sep=','))
1914
1914
1915 # These are warnings, not errors. So don't increment problem count. This
1915 # These are warnings, not errors. So don't increment problem count. This
1916 # may change in the future.
1916 # may change in the future.
1917 if 'tls1.2' not in security:
1917 if 'tls1.2' not in security:
1918 fm.plain(_(' TLS 1.2 not supported by Python install; '
1918 fm.plain(_(' TLS 1.2 not supported by Python install; '
1919 'network connections lack modern security\n'))
1919 'network connections lack modern security\n'))
1920 if 'sni' not in security:
1920 if 'sni' not in security:
1921 fm.plain(_(' SNI not supported by Python install; may have '
1921 fm.plain(_(' SNI not supported by Python install; may have '
1922 'connectivity issues with some servers\n'))
1922 'connectivity issues with some servers\n'))
1923
1923
1924 # TODO print CA cert info
1924 # TODO print CA cert info
1925
1925
1926 # hg version
1926 # hg version
1927 hgver = util.version()
1927 hgver = util.version()
1928 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1928 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1929 hgver.split('+')[0])
1929 hgver.split('+')[0])
1930 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1930 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1931 '+'.join(hgver.split('+')[1:]))
1931 '+'.join(hgver.split('+')[1:]))
1932
1932
1933 # compiled modules
1933 # compiled modules
1934 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1934 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1935 policy.policy)
1935 policy.policy)
1936 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1936 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1937 os.path.dirname(__file__))
1937 os.path.dirname(__file__))
1938
1938
1939 err = None
1939 err = None
1940 try:
1940 try:
1941 from . import (
1941 from . import (
1942 base85,
1942 base85,
1943 bdiff,
1943 bdiff,
1944 mpatch,
1944 mpatch,
1945 osutil,
1945 osutil,
1946 )
1946 )
1947 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1947 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1948 except Exception as inst:
1948 except Exception as inst:
1949 err = inst
1949 err = inst
1950 problems += 1
1950 problems += 1
1951 fm.condwrite(err, 'extensionserror', " %s\n", err)
1951 fm.condwrite(err, 'extensionserror', " %s\n", err)
1952
1952
1953 compengines = util.compengines._engines.values()
1953 compengines = util.compengines._engines.values()
1954 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1954 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1955 fm.formatlist(sorted(e.name() for e in compengines),
1955 fm.formatlist(sorted(e.name() for e in compengines),
1956 name='compengine', fmt='%s', sep=', '))
1956 name='compengine', fmt='%s', sep=', '))
1957 fm.write('compenginesavail', _('checking available compression engines '
1957 fm.write('compenginesavail', _('checking available compression engines '
1958 '(%s)\n'),
1958 '(%s)\n'),
1959 fm.formatlist(sorted(e.name() for e in compengines
1959 fm.formatlist(sorted(e.name() for e in compengines
1960 if e.available()),
1960 if e.available()),
1961 name='compengine', fmt='%s', sep=', '))
1961 name='compengine', fmt='%s', sep=', '))
1962 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1962 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1963 fm.write('compenginesserver', _('checking available compression engines '
1963 fm.write('compenginesserver', _('checking available compression engines '
1964 'for wire protocol (%s)\n'),
1964 'for wire protocol (%s)\n'),
1965 fm.formatlist([e.name() for e in wirecompengines
1965 fm.formatlist([e.name() for e in wirecompengines
1966 if e.wireprotosupport()],
1966 if e.wireprotosupport()],
1967 name='compengine', fmt='%s', sep=', '))
1967 name='compengine', fmt='%s', sep=', '))
1968
1968
1969 # templates
1969 # templates
1970 p = templater.templatepaths()
1970 p = templater.templatepaths()
1971 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1971 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1972 fm.condwrite(not p, '', _(" no template directories found\n"))
1972 fm.condwrite(not p, '', _(" no template directories found\n"))
1973 if p:
1973 if p:
1974 m = templater.templatepath("map-cmdline.default")
1974 m = templater.templatepath("map-cmdline.default")
1975 if m:
1975 if m:
1976 # template found, check if it is working
1976 # template found, check if it is working
1977 err = None
1977 err = None
1978 try:
1978 try:
1979 templater.templater.frommapfile(m)
1979 templater.templater.frommapfile(m)
1980 except Exception as inst:
1980 except Exception as inst:
1981 err = inst
1981 err = inst
1982 p = None
1982 p = None
1983 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1983 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1984 else:
1984 else:
1985 p = None
1985 p = None
1986 fm.condwrite(p, 'defaulttemplate',
1986 fm.condwrite(p, 'defaulttemplate',
1987 _("checking default template (%s)\n"), m)
1987 _("checking default template (%s)\n"), m)
1988 fm.condwrite(not m, 'defaulttemplatenotfound',
1988 fm.condwrite(not m, 'defaulttemplatenotfound',
1989 _(" template '%s' not found\n"), "default")
1989 _(" template '%s' not found\n"), "default")
1990 if not p:
1990 if not p:
1991 problems += 1
1991 problems += 1
1992 fm.condwrite(not p, '',
1992 fm.condwrite(not p, '',
1993 _(" (templates seem to have been installed incorrectly)\n"))
1993 _(" (templates seem to have been installed incorrectly)\n"))
1994
1994
1995 # editor
1995 # editor
1996 editor = ui.geteditor()
1996 editor = ui.geteditor()
1997 editor = util.expandpath(editor)
1997 editor = util.expandpath(editor)
1998 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1998 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1999 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1999 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
2000 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2000 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2001 _(" No commit editor set and can't find %s in PATH\n"
2001 _(" No commit editor set and can't find %s in PATH\n"
2002 " (specify a commit editor in your configuration"
2002 " (specify a commit editor in your configuration"
2003 " file)\n"), not cmdpath and editor == 'vi' and editor)
2003 " file)\n"), not cmdpath and editor == 'vi' and editor)
2004 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2004 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2005 _(" Can't find editor '%s' in PATH\n"
2005 _(" Can't find editor '%s' in PATH\n"
2006 " (specify a commit editor in your configuration"
2006 " (specify a commit editor in your configuration"
2007 " file)\n"), not cmdpath and editor)
2007 " file)\n"), not cmdpath and editor)
2008 if not cmdpath and editor != 'vi':
2008 if not cmdpath and editor != 'vi':
2009 problems += 1
2009 problems += 1
2010
2010
2011 # check username
2011 # check username
2012 username = None
2012 username = None
2013 err = None
2013 err = None
2014 try:
2014 try:
2015 username = ui.username()
2015 username = ui.username()
2016 except error.Abort as e:
2016 except error.Abort as e:
2017 err = e
2017 err = e
2018 problems += 1
2018 problems += 1
2019
2019
2020 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2020 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2021 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2021 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2022 " (specify a username in your configuration file)\n"), err)
2022 " (specify a username in your configuration file)\n"), err)
2023
2023
2024 fm.condwrite(not problems, '',
2024 fm.condwrite(not problems, '',
2025 _("no problems detected\n"))
2025 _("no problems detected\n"))
2026 if not problems:
2026 if not problems:
2027 fm.data(problems=problems)
2027 fm.data(problems=problems)
2028 fm.condwrite(problems, 'problems',
2028 fm.condwrite(problems, 'problems',
2029 _("%d problems detected,"
2029 _("%d problems detected,"
2030 " please check your install!\n"), problems)
2030 " please check your install!\n"), problems)
2031 fm.end()
2031 fm.end()
2032
2032
2033 return problems
2033 return problems
2034
2034
2035 @command('debugknown', [], _('REPO ID...'), norepo=True)
2035 @command('debugknown', [], _('REPO ID...'), norepo=True)
2036 def debugknown(ui, repopath, *ids, **opts):
2036 def debugknown(ui, repopath, *ids, **opts):
2037 """test whether node ids are known to a repo
2037 """test whether node ids are known to a repo
2038
2038
2039 Every ID must be a full-length hex node id string. Returns a list of 0s
2039 Every ID must be a full-length hex node id string. Returns a list of 0s
2040 and 1s indicating unknown/known.
2040 and 1s indicating unknown/known.
2041 """
2041 """
2042 repo = hg.peer(ui, opts, repopath)
2042 repo = hg.peer(ui, opts, repopath)
2043 if not repo.capable('known'):
2043 if not repo.capable('known'):
2044 raise error.Abort("known() not supported by target repository")
2044 raise error.Abort("known() not supported by target repository")
2045 flags = repo.known([bin(s) for s in ids])
2045 flags = repo.known([bin(s) for s in ids])
2046 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2046 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2047
2047
2048 @command('debuglabelcomplete', [], _('LABEL...'))
2048 @command('debuglabelcomplete', [], _('LABEL...'))
2049 def debuglabelcomplete(ui, repo, *args):
2049 def debuglabelcomplete(ui, repo, *args):
2050 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2050 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2051 debugnamecomplete(ui, repo, *args)
2051 debugnamecomplete(ui, repo, *args)
2052
2052
2053 @command('debugmergestate', [], '')
2053 @command('debugmergestate', [], '')
2054 def debugmergestate(ui, repo, *args):
2054 def debugmergestate(ui, repo, *args):
2055 """print merge state
2055 """print merge state
2056
2056
2057 Use --verbose to print out information about whether v1 or v2 merge state
2057 Use --verbose to print out information about whether v1 or v2 merge state
2058 was chosen."""
2058 was chosen."""
2059 def _hashornull(h):
2059 def _hashornull(h):
2060 if h == nullhex:
2060 if h == nullhex:
2061 return 'null'
2061 return 'null'
2062 else:
2062 else:
2063 return h
2063 return h
2064
2064
2065 def printrecords(version):
2065 def printrecords(version):
2066 ui.write(('* version %s records\n') % version)
2066 ui.write(('* version %s records\n') % version)
2067 if version == 1:
2067 if version == 1:
2068 records = v1records
2068 records = v1records
2069 else:
2069 else:
2070 records = v2records
2070 records = v2records
2071
2071
2072 for rtype, record in records:
2072 for rtype, record in records:
2073 # pretty print some record types
2073 # pretty print some record types
2074 if rtype == 'L':
2074 if rtype == 'L':
2075 ui.write(('local: %s\n') % record)
2075 ui.write(('local: %s\n') % record)
2076 elif rtype == 'O':
2076 elif rtype == 'O':
2077 ui.write(('other: %s\n') % record)
2077 ui.write(('other: %s\n') % record)
2078 elif rtype == 'm':
2078 elif rtype == 'm':
2079 driver, mdstate = record.split('\0', 1)
2079 driver, mdstate = record.split('\0', 1)
2080 ui.write(('merge driver: %s (state "%s")\n')
2080 ui.write(('merge driver: %s (state "%s")\n')
2081 % (driver, mdstate))
2081 % (driver, mdstate))
2082 elif rtype in 'FDC':
2082 elif rtype in 'FDC':
2083 r = record.split('\0')
2083 r = record.split('\0')
2084 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2084 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2085 if version == 1:
2085 if version == 1:
2086 onode = 'not stored in v1 format'
2086 onode = 'not stored in v1 format'
2087 flags = r[7]
2087 flags = r[7]
2088 else:
2088 else:
2089 onode, flags = r[7:9]
2089 onode, flags = r[7:9]
2090 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2090 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2091 % (f, rtype, state, _hashornull(hash)))
2091 % (f, rtype, state, _hashornull(hash)))
2092 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2092 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2093 ui.write((' ancestor path: %s (node %s)\n')
2093 ui.write((' ancestor path: %s (node %s)\n')
2094 % (afile, _hashornull(anode)))
2094 % (afile, _hashornull(anode)))
2095 ui.write((' other path: %s (node %s)\n')
2095 ui.write((' other path: %s (node %s)\n')
2096 % (ofile, _hashornull(onode)))
2096 % (ofile, _hashornull(onode)))
2097 elif rtype == 'f':
2097 elif rtype == 'f':
2098 filename, rawextras = record.split('\0', 1)
2098 filename, rawextras = record.split('\0', 1)
2099 extras = rawextras.split('\0')
2099 extras = rawextras.split('\0')
2100 i = 0
2100 i = 0
2101 extrastrings = []
2101 extrastrings = []
2102 while i < len(extras):
2102 while i < len(extras):
2103 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2103 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2104 i += 2
2104 i += 2
2105
2105
2106 ui.write(('file extras: %s (%s)\n')
2106 ui.write(('file extras: %s (%s)\n')
2107 % (filename, ', '.join(extrastrings)))
2107 % (filename, ', '.join(extrastrings)))
2108 elif rtype == 'l':
2108 elif rtype == 'l':
2109 labels = record.split('\0', 2)
2109 labels = record.split('\0', 2)
2110 labels = [l for l in labels if len(l) > 0]
2110 labels = [l for l in labels if len(l) > 0]
2111 ui.write(('labels:\n'))
2111 ui.write(('labels:\n'))
2112 ui.write((' local: %s\n' % labels[0]))
2112 ui.write((' local: %s\n' % labels[0]))
2113 ui.write((' other: %s\n' % labels[1]))
2113 ui.write((' other: %s\n' % labels[1]))
2114 if len(labels) > 2:
2114 if len(labels) > 2:
2115 ui.write((' base: %s\n' % labels[2]))
2115 ui.write((' base: %s\n' % labels[2]))
2116 else:
2116 else:
2117 ui.write(('unrecognized entry: %s\t%s\n')
2117 ui.write(('unrecognized entry: %s\t%s\n')
2118 % (rtype, record.replace('\0', '\t')))
2118 % (rtype, record.replace('\0', '\t')))
2119
2119
2120 # Avoid mergestate.read() since it may raise an exception for unsupported
2120 # Avoid mergestate.read() since it may raise an exception for unsupported
2121 # merge state records. We shouldn't be doing this, but this is OK since this
2121 # merge state records. We shouldn't be doing this, but this is OK since this
2122 # command is pretty low-level.
2122 # command is pretty low-level.
2123 ms = mergemod.mergestate(repo)
2123 ms = mergemod.mergestate(repo)
2124
2124
2125 # sort so that reasonable information is on top
2125 # sort so that reasonable information is on top
2126 v1records = ms._readrecordsv1()
2126 v1records = ms._readrecordsv1()
2127 v2records = ms._readrecordsv2()
2127 v2records = ms._readrecordsv2()
2128 order = 'LOml'
2128 order = 'LOml'
2129 def key(r):
2129 def key(r):
2130 idx = order.find(r[0])
2130 idx = order.find(r[0])
2131 if idx == -1:
2131 if idx == -1:
2132 return (1, r[1])
2132 return (1, r[1])
2133 else:
2133 else:
2134 return (0, idx)
2134 return (0, idx)
2135 v1records.sort(key=key)
2135 v1records.sort(key=key)
2136 v2records.sort(key=key)
2136 v2records.sort(key=key)
2137
2137
2138 if not v1records and not v2records:
2138 if not v1records and not v2records:
2139 ui.write(('no merge state found\n'))
2139 ui.write(('no merge state found\n'))
2140 elif not v2records:
2140 elif not v2records:
2141 ui.note(('no version 2 merge state\n'))
2141 ui.note(('no version 2 merge state\n'))
2142 printrecords(1)
2142 printrecords(1)
2143 elif ms._v1v2match(v1records, v2records):
2143 elif ms._v1v2match(v1records, v2records):
2144 ui.note(('v1 and v2 states match: using v2\n'))
2144 ui.note(('v1 and v2 states match: using v2\n'))
2145 printrecords(2)
2145 printrecords(2)
2146 else:
2146 else:
2147 ui.note(('v1 and v2 states mismatch: using v1\n'))
2147 ui.note(('v1 and v2 states mismatch: using v1\n'))
2148 printrecords(1)
2148 printrecords(1)
2149 if ui.verbose:
2149 if ui.verbose:
2150 printrecords(2)
2150 printrecords(2)
2151
2151
2152 @command('debugnamecomplete', [], _('NAME...'))
2152 @command('debugnamecomplete', [], _('NAME...'))
2153 def debugnamecomplete(ui, repo, *args):
2153 def debugnamecomplete(ui, repo, *args):
2154 '''complete "names" - tags, open branch names, bookmark names'''
2154 '''complete "names" - tags, open branch names, bookmark names'''
2155
2155
2156 names = set()
2156 names = set()
2157 # since we previously only listed open branches, we will handle that
2157 # since we previously only listed open branches, we will handle that
2158 # specially (after this for loop)
2158 # specially (after this for loop)
2159 for name, ns in repo.names.iteritems():
2159 for name, ns in repo.names.iteritems():
2160 if name != 'branches':
2160 if name != 'branches':
2161 names.update(ns.listnames(repo))
2161 names.update(ns.listnames(repo))
2162 names.update(tag for (tag, heads, tip, closed)
2162 names.update(tag for (tag, heads, tip, closed)
2163 in repo.branchmap().iterbranches() if not closed)
2163 in repo.branchmap().iterbranches() if not closed)
2164 completions = set()
2164 completions = set()
2165 if not args:
2165 if not args:
2166 args = ['']
2166 args = ['']
2167 for a in args:
2167 for a in args:
2168 completions.update(n for n in names if n.startswith(a))
2168 completions.update(n for n in names if n.startswith(a))
2169 ui.write('\n'.join(sorted(completions)))
2169 ui.write('\n'.join(sorted(completions)))
2170 ui.write('\n')
2170 ui.write('\n')
2171
2171
2172 @command('debuglocks',
2172 @command('debuglocks',
2173 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2173 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2174 ('W', 'force-wlock', None,
2174 ('W', 'force-wlock', None,
2175 _('free the working state lock (DANGEROUS)'))],
2175 _('free the working state lock (DANGEROUS)'))],
2176 _('[OPTION]...'))
2176 _('[OPTION]...'))
2177 def debuglocks(ui, repo, **opts):
2177 def debuglocks(ui, repo, **opts):
2178 """show or modify state of locks
2178 """show or modify state of locks
2179
2179
2180 By default, this command will show which locks are held. This
2180 By default, this command will show which locks are held. This
2181 includes the user and process holding the lock, the amount of time
2181 includes the user and process holding the lock, the amount of time
2182 the lock has been held, and the machine name where the process is
2182 the lock has been held, and the machine name where the process is
2183 running if it's not local.
2183 running if it's not local.
2184
2184
2185 Locks protect the integrity of Mercurial's data, so should be
2185 Locks protect the integrity of Mercurial's data, so should be
2186 treated with care. System crashes or other interruptions may cause
2186 treated with care. System crashes or other interruptions may cause
2187 locks to not be properly released, though Mercurial will usually
2187 locks to not be properly released, though Mercurial will usually
2188 detect and remove such stale locks automatically.
2188 detect and remove such stale locks automatically.
2189
2189
2190 However, detecting stale locks may not always be possible (for
2190 However, detecting stale locks may not always be possible (for
2191 instance, on a shared filesystem). Removing locks may also be
2191 instance, on a shared filesystem). Removing locks may also be
2192 blocked by filesystem permissions.
2192 blocked by filesystem permissions.
2193
2193
2194 Returns 0 if no locks are held.
2194 Returns 0 if no locks are held.
2195
2195
2196 """
2196 """
2197
2197
2198 if opts.get('force_lock'):
2198 if opts.get('force_lock'):
2199 repo.svfs.unlink('lock')
2199 repo.svfs.unlink('lock')
2200 if opts.get('force_wlock'):
2200 if opts.get('force_wlock'):
2201 repo.vfs.unlink('wlock')
2201 repo.vfs.unlink('wlock')
2202 if opts.get('force_lock') or opts.get('force_lock'):
2202 if opts.get('force_lock') or opts.get('force_lock'):
2203 return 0
2203 return 0
2204
2204
2205 now = time.time()
2205 now = time.time()
2206 held = 0
2206 held = 0
2207
2207
2208 def report(vfs, name, method):
2208 def report(vfs, name, method):
2209 # this causes stale locks to get reaped for more accurate reporting
2209 # this causes stale locks to get reaped for more accurate reporting
2210 try:
2210 try:
2211 l = method(False)
2211 l = method(False)
2212 except error.LockHeld:
2212 except error.LockHeld:
2213 l = None
2213 l = None
2214
2214
2215 if l:
2215 if l:
2216 l.release()
2216 l.release()
2217 else:
2217 else:
2218 try:
2218 try:
2219 stat = vfs.lstat(name)
2219 stat = vfs.lstat(name)
2220 age = now - stat.st_mtime
2220 age = now - stat.st_mtime
2221 user = util.username(stat.st_uid)
2221 user = util.username(stat.st_uid)
2222 locker = vfs.readlock(name)
2222 locker = vfs.readlock(name)
2223 if ":" in locker:
2223 if ":" in locker:
2224 host, pid = locker.split(':')
2224 host, pid = locker.split(':')
2225 if host == socket.gethostname():
2225 if host == socket.gethostname():
2226 locker = 'user %s, process %s' % (user, pid)
2226 locker = 'user %s, process %s' % (user, pid)
2227 else:
2227 else:
2228 locker = 'user %s, process %s, host %s' \
2228 locker = 'user %s, process %s, host %s' \
2229 % (user, pid, host)
2229 % (user, pid, host)
2230 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2230 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2231 return 1
2231 return 1
2232 except OSError as e:
2232 except OSError as e:
2233 if e.errno != errno.ENOENT:
2233 if e.errno != errno.ENOENT:
2234 raise
2234 raise
2235
2235
2236 ui.write(("%-6s free\n") % (name + ":"))
2236 ui.write(("%-6s free\n") % (name + ":"))
2237 return 0
2237 return 0
2238
2238
2239 held += report(repo.svfs, "lock", repo.lock)
2239 held += report(repo.svfs, "lock", repo.lock)
2240 held += report(repo.vfs, "wlock", repo.wlock)
2240 held += report(repo.vfs, "wlock", repo.wlock)
2241
2241
2242 return held
2242 return held
2243
2243
2244 @command('debugobsolete',
2244 @command('debugobsolete',
2245 [('', 'flags', 0, _('markers flag')),
2245 [('', 'flags', 0, _('markers flag')),
2246 ('', 'record-parents', False,
2246 ('', 'record-parents', False,
2247 _('record parent information for the precursor')),
2247 _('record parent information for the precursor')),
2248 ('r', 'rev', [], _('display markers relevant to REV')),
2248 ('r', 'rev', [], _('display markers relevant to REV')),
2249 ('', 'index', False, _('display index of the marker')),
2249 ('', 'index', False, _('display index of the marker')),
2250 ('', 'delete', [], _('delete markers specified by indices')),
2250 ('', 'delete', [], _('delete markers specified by indices')),
2251 ] + commitopts2 + formatteropts,
2251 ] + commitopts2 + formatteropts,
2252 _('[OBSOLETED [REPLACEMENT ...]]'))
2252 _('[OBSOLETED [REPLACEMENT ...]]'))
2253 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2253 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2254 """create arbitrary obsolete marker
2254 """create arbitrary obsolete marker
2255
2255
2256 With no arguments, displays the list of obsolescence markers."""
2256 With no arguments, displays the list of obsolescence markers."""
2257
2257
2258 def parsenodeid(s):
2258 def parsenodeid(s):
2259 try:
2259 try:
2260 # We do not use revsingle/revrange functions here to accept
2260 # We do not use revsingle/revrange functions here to accept
2261 # arbitrary node identifiers, possibly not present in the
2261 # arbitrary node identifiers, possibly not present in the
2262 # local repository.
2262 # local repository.
2263 n = bin(s)
2263 n = bin(s)
2264 if len(n) != len(nullid):
2264 if len(n) != len(nullid):
2265 raise TypeError()
2265 raise TypeError()
2266 return n
2266 return n
2267 except TypeError:
2267 except TypeError:
2268 raise error.Abort('changeset references must be full hexadecimal '
2268 raise error.Abort('changeset references must be full hexadecimal '
2269 'node identifiers')
2269 'node identifiers')
2270
2270
2271 if opts.get('delete'):
2271 if opts.get('delete'):
2272 indices = []
2272 indices = []
2273 for v in opts.get('delete'):
2273 for v in opts.get('delete'):
2274 try:
2274 try:
2275 indices.append(int(v))
2275 indices.append(int(v))
2276 except ValueError:
2276 except ValueError:
2277 raise error.Abort(_('invalid index value: %r') % v,
2277 raise error.Abort(_('invalid index value: %r') % v,
2278 hint=_('use integers for indices'))
2278 hint=_('use integers for indices'))
2279
2279
2280 if repo.currenttransaction():
2280 if repo.currenttransaction():
2281 raise error.Abort(_('cannot delete obsmarkers in the middle '
2281 raise error.Abort(_('cannot delete obsmarkers in the middle '
2282 'of transaction.'))
2282 'of transaction.'))
2283
2283
2284 with repo.lock():
2284 with repo.lock():
2285 n = repair.deleteobsmarkers(repo.obsstore, indices)
2285 n = repair.deleteobsmarkers(repo.obsstore, indices)
2286 ui.write(_('deleted %i obsolescence markers\n') % n)
2286 ui.write(_('deleted %i obsolescence markers\n') % n)
2287
2287
2288 return
2288 return
2289
2289
2290 if precursor is not None:
2290 if precursor is not None:
2291 if opts['rev']:
2291 if opts['rev']:
2292 raise error.Abort('cannot select revision when creating marker')
2292 raise error.Abort('cannot select revision when creating marker')
2293 metadata = {}
2293 metadata = {}
2294 metadata['user'] = opts['user'] or ui.username()
2294 metadata['user'] = opts['user'] or ui.username()
2295 succs = tuple(parsenodeid(succ) for succ in successors)
2295 succs = tuple(parsenodeid(succ) for succ in successors)
2296 l = repo.lock()
2296 l = repo.lock()
2297 try:
2297 try:
2298 tr = repo.transaction('debugobsolete')
2298 tr = repo.transaction('debugobsolete')
2299 try:
2299 try:
2300 date = opts.get('date')
2300 date = opts.get('date')
2301 if date:
2301 if date:
2302 date = util.parsedate(date)
2302 date = util.parsedate(date)
2303 else:
2303 else:
2304 date = None
2304 date = None
2305 prec = parsenodeid(precursor)
2305 prec = parsenodeid(precursor)
2306 parents = None
2306 parents = None
2307 if opts['record_parents']:
2307 if opts['record_parents']:
2308 if prec not in repo.unfiltered():
2308 if prec not in repo.unfiltered():
2309 raise error.Abort('cannot used --record-parents on '
2309 raise error.Abort('cannot used --record-parents on '
2310 'unknown changesets')
2310 'unknown changesets')
2311 parents = repo.unfiltered()[prec].parents()
2311 parents = repo.unfiltered()[prec].parents()
2312 parents = tuple(p.node() for p in parents)
2312 parents = tuple(p.node() for p in parents)
2313 repo.obsstore.create(tr, prec, succs, opts['flags'],
2313 repo.obsstore.create(tr, prec, succs, opts['flags'],
2314 parents=parents, date=date,
2314 parents=parents, date=date,
2315 metadata=metadata)
2315 metadata=metadata)
2316 tr.close()
2316 tr.close()
2317 except ValueError as exc:
2317 except ValueError as exc:
2318 raise error.Abort(_('bad obsmarker input: %s') % exc)
2318 raise error.Abort(_('bad obsmarker input: %s') % exc)
2319 finally:
2319 finally:
2320 tr.release()
2320 tr.release()
2321 finally:
2321 finally:
2322 l.release()
2322 l.release()
2323 else:
2323 else:
2324 if opts['rev']:
2324 if opts['rev']:
2325 revs = scmutil.revrange(repo, opts['rev'])
2325 revs = scmutil.revrange(repo, opts['rev'])
2326 nodes = [repo[r].node() for r in revs]
2326 nodes = [repo[r].node() for r in revs]
2327 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2327 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2328 markers.sort(key=lambda x: x._data)
2328 markers.sort(key=lambda x: x._data)
2329 else:
2329 else:
2330 markers = obsolete.getmarkers(repo)
2330 markers = obsolete.getmarkers(repo)
2331
2331
2332 markerstoiter = markers
2332 markerstoiter = markers
2333 isrelevant = lambda m: True
2333 isrelevant = lambda m: True
2334 if opts.get('rev') and opts.get('index'):
2334 if opts.get('rev') and opts.get('index'):
2335 markerstoiter = obsolete.getmarkers(repo)
2335 markerstoiter = obsolete.getmarkers(repo)
2336 markerset = set(markers)
2336 markerset = set(markers)
2337 isrelevant = lambda m: m in markerset
2337 isrelevant = lambda m: m in markerset
2338
2338
2339 fm = ui.formatter('debugobsolete', opts)
2339 fm = ui.formatter('debugobsolete', opts)
2340 for i, m in enumerate(markerstoiter):
2340 for i, m in enumerate(markerstoiter):
2341 if not isrelevant(m):
2341 if not isrelevant(m):
2342 # marker can be irrelevant when we're iterating over a set
2342 # marker can be irrelevant when we're iterating over a set
2343 # of markers (markerstoiter) which is bigger than the set
2343 # of markers (markerstoiter) which is bigger than the set
2344 # of markers we want to display (markers)
2344 # of markers we want to display (markers)
2345 # this can happen if both --index and --rev options are
2345 # this can happen if both --index and --rev options are
2346 # provided and thus we need to iterate over all of the markers
2346 # provided and thus we need to iterate over all of the markers
2347 # to get the correct indices, but only display the ones that
2347 # to get the correct indices, but only display the ones that
2348 # are relevant to --rev value
2348 # are relevant to --rev value
2349 continue
2349 continue
2350 fm.startitem()
2350 fm.startitem()
2351 ind = i if opts.get('index') else None
2351 ind = i if opts.get('index') else None
2352 cmdutil.showmarker(fm, m, index=ind)
2352 cmdutil.showmarker(fm, m, index=ind)
2353 fm.end()
2353 fm.end()
2354
2354
2355 @command('debugpathcomplete',
2355 @command('debugpathcomplete',
2356 [('f', 'full', None, _('complete an entire path')),
2356 [('f', 'full', None, _('complete an entire path')),
2357 ('n', 'normal', None, _('show only normal files')),
2357 ('n', 'normal', None, _('show only normal files')),
2358 ('a', 'added', None, _('show only added files')),
2358 ('a', 'added', None, _('show only added files')),
2359 ('r', 'removed', None, _('show only removed files'))],
2359 ('r', 'removed', None, _('show only removed files'))],
2360 _('FILESPEC...'))
2360 _('FILESPEC...'))
2361 def debugpathcomplete(ui, repo, *specs, **opts):
2361 def debugpathcomplete(ui, repo, *specs, **opts):
2362 '''complete part or all of a tracked path
2362 '''complete part or all of a tracked path
2363
2363
2364 This command supports shells that offer path name completion. It
2364 This command supports shells that offer path name completion. It
2365 currently completes only files already known to the dirstate.
2365 currently completes only files already known to the dirstate.
2366
2366
2367 Completion extends only to the next path segment unless
2367 Completion extends only to the next path segment unless
2368 --full is specified, in which case entire paths are used.'''
2368 --full is specified, in which case entire paths are used.'''
2369
2369
2370 def complete(path, acceptable):
2370 def complete(path, acceptable):
2371 dirstate = repo.dirstate
2371 dirstate = repo.dirstate
2372 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2372 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
2373 rootdir = repo.root + pycompat.ossep
2373 rootdir = repo.root + pycompat.ossep
2374 if spec != repo.root and not spec.startswith(rootdir):
2374 if spec != repo.root and not spec.startswith(rootdir):
2375 return [], []
2375 return [], []
2376 if os.path.isdir(spec):
2376 if os.path.isdir(spec):
2377 spec += '/'
2377 spec += '/'
2378 spec = spec[len(rootdir):]
2378 spec = spec[len(rootdir):]
2379 fixpaths = pycompat.ossep != '/'
2379 fixpaths = pycompat.ossep != '/'
2380 if fixpaths:
2380 if fixpaths:
2381 spec = spec.replace(pycompat.ossep, '/')
2381 spec = spec.replace(pycompat.ossep, '/')
2382 speclen = len(spec)
2382 speclen = len(spec)
2383 fullpaths = opts['full']
2383 fullpaths = opts['full']
2384 files, dirs = set(), set()
2384 files, dirs = set(), set()
2385 adddir, addfile = dirs.add, files.add
2385 adddir, addfile = dirs.add, files.add
2386 for f, st in dirstate.iteritems():
2386 for f, st in dirstate.iteritems():
2387 if f.startswith(spec) and st[0] in acceptable:
2387 if f.startswith(spec) and st[0] in acceptable:
2388 if fixpaths:
2388 if fixpaths:
2389 f = f.replace('/', pycompat.ossep)
2389 f = f.replace('/', pycompat.ossep)
2390 if fullpaths:
2390 if fullpaths:
2391 addfile(f)
2391 addfile(f)
2392 continue
2392 continue
2393 s = f.find(pycompat.ossep, speclen)
2393 s = f.find(pycompat.ossep, speclen)
2394 if s >= 0:
2394 if s >= 0:
2395 adddir(f[:s])
2395 adddir(f[:s])
2396 else:
2396 else:
2397 addfile(f)
2397 addfile(f)
2398 return files, dirs
2398 return files, dirs
2399
2399
2400 acceptable = ''
2400 acceptable = ''
2401 if opts['normal']:
2401 if opts['normal']:
2402 acceptable += 'nm'
2402 acceptable += 'nm'
2403 if opts['added']:
2403 if opts['added']:
2404 acceptable += 'a'
2404 acceptable += 'a'
2405 if opts['removed']:
2405 if opts['removed']:
2406 acceptable += 'r'
2406 acceptable += 'r'
2407 cwd = repo.getcwd()
2407 cwd = repo.getcwd()
2408 if not specs:
2408 if not specs:
2409 specs = ['.']
2409 specs = ['.']
2410
2410
2411 files, dirs = set(), set()
2411 files, dirs = set(), set()
2412 for spec in specs:
2412 for spec in specs:
2413 f, d = complete(spec, acceptable or 'nmar')
2413 f, d = complete(spec, acceptable or 'nmar')
2414 files.update(f)
2414 files.update(f)
2415 dirs.update(d)
2415 dirs.update(d)
2416 files.update(dirs)
2416 files.update(dirs)
2417 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2417 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2418 ui.write('\n')
2418 ui.write('\n')
2419
2419
2420 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2420 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2421 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2421 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2422 '''access the pushkey key/value protocol
2422 '''access the pushkey key/value protocol
2423
2423
2424 With two args, list the keys in the given namespace.
2424 With two args, list the keys in the given namespace.
2425
2425
2426 With five args, set a key to new if it currently is set to old.
2426 With five args, set a key to new if it currently is set to old.
2427 Reports success or failure.
2427 Reports success or failure.
2428 '''
2428 '''
2429
2429
2430 target = hg.peer(ui, {}, repopath)
2430 target = hg.peer(ui, {}, repopath)
2431 if keyinfo:
2431 if keyinfo:
2432 key, old, new = keyinfo
2432 key, old, new = keyinfo
2433 r = target.pushkey(namespace, key, old, new)
2433 r = target.pushkey(namespace, key, old, new)
2434 ui.status(str(r) + '\n')
2434 ui.status(str(r) + '\n')
2435 return not r
2435 return not r
2436 else:
2436 else:
2437 for k, v in sorted(target.listkeys(namespace).iteritems()):
2437 for k, v in sorted(target.listkeys(namespace).iteritems()):
2438 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2438 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2439 v.encode('string-escape')))
2439 v.encode('string-escape')))
2440
2440
2441 @command('debugpvec', [], _('A B'))
2441 @command('debugpvec', [], _('A B'))
2442 def debugpvec(ui, repo, a, b=None):
2442 def debugpvec(ui, repo, a, b=None):
2443 ca = scmutil.revsingle(repo, a)
2443 ca = scmutil.revsingle(repo, a)
2444 cb = scmutil.revsingle(repo, b)
2444 cb = scmutil.revsingle(repo, b)
2445 pa = pvec.ctxpvec(ca)
2445 pa = pvec.ctxpvec(ca)
2446 pb = pvec.ctxpvec(cb)
2446 pb = pvec.ctxpvec(cb)
2447 if pa == pb:
2447 if pa == pb:
2448 rel = "="
2448 rel = "="
2449 elif pa > pb:
2449 elif pa > pb:
2450 rel = ">"
2450 rel = ">"
2451 elif pa < pb:
2451 elif pa < pb:
2452 rel = "<"
2452 rel = "<"
2453 elif pa | pb:
2453 elif pa | pb:
2454 rel = "|"
2454 rel = "|"
2455 ui.write(_("a: %s\n") % pa)
2455 ui.write(_("a: %s\n") % pa)
2456 ui.write(_("b: %s\n") % pb)
2456 ui.write(_("b: %s\n") % pb)
2457 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2457 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2458 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2458 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2459 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2459 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2460 pa.distance(pb), rel))
2460 pa.distance(pb), rel))
2461
2461
2462 @command('debugrebuilddirstate|debugrebuildstate',
2462 @command('debugrebuilddirstate|debugrebuildstate',
2463 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2463 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2464 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2464 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2465 'the working copy parent')),
2465 'the working copy parent')),
2466 ],
2466 ],
2467 _('[-r REV]'))
2467 _('[-r REV]'))
2468 def debugrebuilddirstate(ui, repo, rev, **opts):
2468 def debugrebuilddirstate(ui, repo, rev, **opts):
2469 """rebuild the dirstate as it would look like for the given revision
2469 """rebuild the dirstate as it would look like for the given revision
2470
2470
2471 If no revision is specified the first current parent will be used.
2471 If no revision is specified the first current parent will be used.
2472
2472
2473 The dirstate will be set to the files of the given revision.
2473 The dirstate will be set to the files of the given revision.
2474 The actual working directory content or existing dirstate
2474 The actual working directory content or existing dirstate
2475 information such as adds or removes is not considered.
2475 information such as adds or removes is not considered.
2476
2476
2477 ``minimal`` will only rebuild the dirstate status for files that claim to be
2477 ``minimal`` will only rebuild the dirstate status for files that claim to be
2478 tracked but are not in the parent manifest, or that exist in the parent
2478 tracked but are not in the parent manifest, or that exist in the parent
2479 manifest but are not in the dirstate. It will not change adds, removes, or
2479 manifest but are not in the dirstate. It will not change adds, removes, or
2480 modified files that are in the working copy parent.
2480 modified files that are in the working copy parent.
2481
2481
2482 One use of this command is to make the next :hg:`status` invocation
2482 One use of this command is to make the next :hg:`status` invocation
2483 check the actual file content.
2483 check the actual file content.
2484 """
2484 """
2485 ctx = scmutil.revsingle(repo, rev)
2485 ctx = scmutil.revsingle(repo, rev)
2486 with repo.wlock():
2486 with repo.wlock():
2487 dirstate = repo.dirstate
2487 dirstate = repo.dirstate
2488 changedfiles = None
2488 changedfiles = None
2489 # See command doc for what minimal does.
2489 # See command doc for what minimal does.
2490 if opts.get('minimal'):
2490 if opts.get('minimal'):
2491 manifestfiles = set(ctx.manifest().keys())
2491 manifestfiles = set(ctx.manifest().keys())
2492 dirstatefiles = set(dirstate)
2492 dirstatefiles = set(dirstate)
2493 manifestonly = manifestfiles - dirstatefiles
2493 manifestonly = manifestfiles - dirstatefiles
2494 dsonly = dirstatefiles - manifestfiles
2494 dsonly = dirstatefiles - manifestfiles
2495 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2495 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2496 changedfiles = manifestonly | dsnotadded
2496 changedfiles = manifestonly | dsnotadded
2497
2497
2498 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2498 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2499
2499
2500 @command('debugrebuildfncache', [], '')
2500 @command('debugrebuildfncache', [], '')
2501 def debugrebuildfncache(ui, repo):
2501 def debugrebuildfncache(ui, repo):
2502 """rebuild the fncache file"""
2502 """rebuild the fncache file"""
2503 repair.rebuildfncache(ui, repo)
2503 repair.rebuildfncache(ui, repo)
2504
2504
2505 @command('debugrename',
2505 @command('debugrename',
2506 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2506 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2507 _('[-r REV] FILE'))
2507 _('[-r REV] FILE'))
2508 def debugrename(ui, repo, file1, *pats, **opts):
2508 def debugrename(ui, repo, file1, *pats, **opts):
2509 """dump rename information"""
2509 """dump rename information"""
2510
2510
2511 ctx = scmutil.revsingle(repo, opts.get('rev'))
2511 ctx = scmutil.revsingle(repo, opts.get('rev'))
2512 m = scmutil.match(ctx, (file1,) + pats, opts)
2512 m = scmutil.match(ctx, (file1,) + pats, opts)
2513 for abs in ctx.walk(m):
2513 for abs in ctx.walk(m):
2514 fctx = ctx[abs]
2514 fctx = ctx[abs]
2515 o = fctx.filelog().renamed(fctx.filenode())
2515 o = fctx.filelog().renamed(fctx.filenode())
2516 rel = m.rel(abs)
2516 rel = m.rel(abs)
2517 if o:
2517 if o:
2518 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2518 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2519 else:
2519 else:
2520 ui.write(_("%s not renamed\n") % rel)
2520 ui.write(_("%s not renamed\n") % rel)
2521
2521
2522 @command('debugrevlog', debugrevlogopts +
2522 @command('debugrevlog', debugrevlogopts +
2523 [('d', 'dump', False, _('dump index data'))],
2523 [('d', 'dump', False, _('dump index data'))],
2524 _('-c|-m|FILE'),
2524 _('-c|-m|FILE'),
2525 optionalrepo=True)
2525 optionalrepo=True)
2526 def debugrevlog(ui, repo, file_=None, **opts):
2526 def debugrevlog(ui, repo, file_=None, **opts):
2527 """show data and statistics about a revlog"""
2527 """show data and statistics about a revlog"""
2528 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2528 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2529
2529
2530 if opts.get("dump"):
2530 if opts.get("dump"):
2531 numrevs = len(r)
2531 numrevs = len(r)
2532 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2532 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
2533 " rawsize totalsize compression heads chainlen\n"))
2533 " rawsize totalsize compression heads chainlen\n"))
2534 ts = 0
2534 ts = 0
2535 heads = set()
2535 heads = set()
2536
2536
2537 for rev in xrange(numrevs):
2537 for rev in xrange(numrevs):
2538 dbase = r.deltaparent(rev)
2538 dbase = r.deltaparent(rev)
2539 if dbase == -1:
2539 if dbase == -1:
2540 dbase = rev
2540 dbase = rev
2541 cbase = r.chainbase(rev)
2541 cbase = r.chainbase(rev)
2542 clen = r.chainlen(rev)
2542 clen = r.chainlen(rev)
2543 p1, p2 = r.parentrevs(rev)
2543 p1, p2 = r.parentrevs(rev)
2544 rs = r.rawsize(rev)
2544 rs = r.rawsize(rev)
2545 ts = ts + rs
2545 ts = ts + rs
2546 heads -= set(r.parentrevs(rev))
2546 heads -= set(r.parentrevs(rev))
2547 heads.add(rev)
2547 heads.add(rev)
2548 try:
2548 try:
2549 compression = ts / r.end(rev)
2549 compression = ts / r.end(rev)
2550 except ZeroDivisionError:
2550 except ZeroDivisionError:
2551 compression = 0
2551 compression = 0
2552 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2552 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2553 "%11d %5d %8d\n" %
2553 "%11d %5d %8d\n" %
2554 (rev, p1, p2, r.start(rev), r.end(rev),
2554 (rev, p1, p2, r.start(rev), r.end(rev),
2555 r.start(dbase), r.start(cbase),
2555 r.start(dbase), r.start(cbase),
2556 r.start(p1), r.start(p2),
2556 r.start(p1), r.start(p2),
2557 rs, ts, compression, len(heads), clen))
2557 rs, ts, compression, len(heads), clen))
2558 return 0
2558 return 0
2559
2559
2560 v = r.version
2560 v = r.version
2561 format = v & 0xFFFF
2561 format = v & 0xFFFF
2562 flags = []
2562 flags = []
2563 gdelta = False
2563 gdelta = False
2564 if v & revlog.REVLOGNGINLINEDATA:
2564 if v & revlog.REVLOGNGINLINEDATA:
2565 flags.append('inline')
2565 flags.append('inline')
2566 if v & revlog.REVLOGGENERALDELTA:
2566 if v & revlog.REVLOGGENERALDELTA:
2567 gdelta = True
2567 gdelta = True
2568 flags.append('generaldelta')
2568 flags.append('generaldelta')
2569 if not flags:
2569 if not flags:
2570 flags = ['(none)']
2570 flags = ['(none)']
2571
2571
2572 nummerges = 0
2572 nummerges = 0
2573 numfull = 0
2573 numfull = 0
2574 numprev = 0
2574 numprev = 0
2575 nump1 = 0
2575 nump1 = 0
2576 nump2 = 0
2576 nump2 = 0
2577 numother = 0
2577 numother = 0
2578 nump1prev = 0
2578 nump1prev = 0
2579 nump2prev = 0
2579 nump2prev = 0
2580 chainlengths = []
2580 chainlengths = []
2581
2581
2582 datasize = [None, 0, 0]
2582 datasize = [None, 0, 0]
2583 fullsize = [None, 0, 0]
2583 fullsize = [None, 0, 0]
2584 deltasize = [None, 0, 0]
2584 deltasize = [None, 0, 0]
2585 chunktypecounts = {}
2585 chunktypecounts = {}
2586 chunktypesizes = {}
2586 chunktypesizes = {}
2587
2587
2588 def addsize(size, l):
2588 def addsize(size, l):
2589 if l[0] is None or size < l[0]:
2589 if l[0] is None or size < l[0]:
2590 l[0] = size
2590 l[0] = size
2591 if size > l[1]:
2591 if size > l[1]:
2592 l[1] = size
2592 l[1] = size
2593 l[2] += size
2593 l[2] += size
2594
2594
2595 numrevs = len(r)
2595 numrevs = len(r)
2596 for rev in xrange(numrevs):
2596 for rev in xrange(numrevs):
2597 p1, p2 = r.parentrevs(rev)
2597 p1, p2 = r.parentrevs(rev)
2598 delta = r.deltaparent(rev)
2598 delta = r.deltaparent(rev)
2599 if format > 0:
2599 if format > 0:
2600 addsize(r.rawsize(rev), datasize)
2600 addsize(r.rawsize(rev), datasize)
2601 if p2 != nullrev:
2601 if p2 != nullrev:
2602 nummerges += 1
2602 nummerges += 1
2603 size = r.length(rev)
2603 size = r.length(rev)
2604 if delta == nullrev:
2604 if delta == nullrev:
2605 chainlengths.append(0)
2605 chainlengths.append(0)
2606 numfull += 1
2606 numfull += 1
2607 addsize(size, fullsize)
2607 addsize(size, fullsize)
2608 else:
2608 else:
2609 chainlengths.append(chainlengths[delta] + 1)
2609 chainlengths.append(chainlengths[delta] + 1)
2610 addsize(size, deltasize)
2610 addsize(size, deltasize)
2611 if delta == rev - 1:
2611 if delta == rev - 1:
2612 numprev += 1
2612 numprev += 1
2613 if delta == p1:
2613 if delta == p1:
2614 nump1prev += 1
2614 nump1prev += 1
2615 elif delta == p2:
2615 elif delta == p2:
2616 nump2prev += 1
2616 nump2prev += 1
2617 elif delta == p1:
2617 elif delta == p1:
2618 nump1 += 1
2618 nump1 += 1
2619 elif delta == p2:
2619 elif delta == p2:
2620 nump2 += 1
2620 nump2 += 1
2621 elif delta != nullrev:
2621 elif delta != nullrev:
2622 numother += 1
2622 numother += 1
2623
2623
2624 # Obtain data on the raw chunks in the revlog.
2624 # Obtain data on the raw chunks in the revlog.
2625 chunk = r._chunkraw(rev, rev)[1]
2625 chunk = r._chunkraw(rev, rev)[1]
2626 if chunk:
2626 if chunk:
2627 chunktype = chunk[0]
2627 chunktype = chunk[0]
2628 else:
2628 else:
2629 chunktype = 'empty'
2629 chunktype = 'empty'
2630
2630
2631 if chunktype not in chunktypecounts:
2631 if chunktype not in chunktypecounts:
2632 chunktypecounts[chunktype] = 0
2632 chunktypecounts[chunktype] = 0
2633 chunktypesizes[chunktype] = 0
2633 chunktypesizes[chunktype] = 0
2634
2634
2635 chunktypecounts[chunktype] += 1
2635 chunktypecounts[chunktype] += 1
2636 chunktypesizes[chunktype] += size
2636 chunktypesizes[chunktype] += size
2637
2637
2638 # Adjust size min value for empty cases
2638 # Adjust size min value for empty cases
2639 for size in (datasize, fullsize, deltasize):
2639 for size in (datasize, fullsize, deltasize):
2640 if size[0] is None:
2640 if size[0] is None:
2641 size[0] = 0
2641 size[0] = 0
2642
2642
2643 numdeltas = numrevs - numfull
2643 numdeltas = numrevs - numfull
2644 numoprev = numprev - nump1prev - nump2prev
2644 numoprev = numprev - nump1prev - nump2prev
2645 totalrawsize = datasize[2]
2645 totalrawsize = datasize[2]
2646 datasize[2] /= numrevs
2646 datasize[2] /= numrevs
2647 fulltotal = fullsize[2]
2647 fulltotal = fullsize[2]
2648 fullsize[2] /= numfull
2648 fullsize[2] /= numfull
2649 deltatotal = deltasize[2]
2649 deltatotal = deltasize[2]
2650 if numrevs - numfull > 0:
2650 if numrevs - numfull > 0:
2651 deltasize[2] /= numrevs - numfull
2651 deltasize[2] /= numrevs - numfull
2652 totalsize = fulltotal + deltatotal
2652 totalsize = fulltotal + deltatotal
2653 avgchainlen = sum(chainlengths) / numrevs
2653 avgchainlen = sum(chainlengths) / numrevs
2654 maxchainlen = max(chainlengths)
2654 maxchainlen = max(chainlengths)
2655 compratio = 1
2655 compratio = 1
2656 if totalsize:
2656 if totalsize:
2657 compratio = totalrawsize / totalsize
2657 compratio = totalrawsize / totalsize
2658
2658
2659 basedfmtstr = '%%%dd\n'
2659 basedfmtstr = '%%%dd\n'
2660 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2660 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2661
2661
2662 def dfmtstr(max):
2662 def dfmtstr(max):
2663 return basedfmtstr % len(str(max))
2663 return basedfmtstr % len(str(max))
2664 def pcfmtstr(max, padding=0):
2664 def pcfmtstr(max, padding=0):
2665 return basepcfmtstr % (len(str(max)), ' ' * padding)
2665 return basepcfmtstr % (len(str(max)), ' ' * padding)
2666
2666
2667 def pcfmt(value, total):
2667 def pcfmt(value, total):
2668 if total:
2668 if total:
2669 return (value, 100 * float(value) / total)
2669 return (value, 100 * float(value) / total)
2670 else:
2670 else:
2671 return value, 100.0
2671 return value, 100.0
2672
2672
2673 ui.write(('format : %d\n') % format)
2673 ui.write(('format : %d\n') % format)
2674 ui.write(('flags : %s\n') % ', '.join(flags))
2674 ui.write(('flags : %s\n') % ', '.join(flags))
2675
2675
2676 ui.write('\n')
2676 ui.write('\n')
2677 fmt = pcfmtstr(totalsize)
2677 fmt = pcfmtstr(totalsize)
2678 fmt2 = dfmtstr(totalsize)
2678 fmt2 = dfmtstr(totalsize)
2679 ui.write(('revisions : ') + fmt2 % numrevs)
2679 ui.write(('revisions : ') + fmt2 % numrevs)
2680 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2680 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2681 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2681 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2682 ui.write(('revisions : ') + fmt2 % numrevs)
2682 ui.write(('revisions : ') + fmt2 % numrevs)
2683 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2683 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2684 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2684 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2685 ui.write(('revision size : ') + fmt2 % totalsize)
2685 ui.write(('revision size : ') + fmt2 % totalsize)
2686 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2686 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2687 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2687 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2688
2688
2689 def fmtchunktype(chunktype):
2689 def fmtchunktype(chunktype):
2690 if chunktype == 'empty':
2690 if chunktype == 'empty':
2691 return ' %s : ' % chunktype
2691 return ' %s : ' % chunktype
2692 elif chunktype in string.ascii_letters:
2692 elif chunktype in string.ascii_letters:
2693 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2693 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2694 else:
2694 else:
2695 return ' 0x%s : ' % hex(chunktype)
2695 return ' 0x%s : ' % hex(chunktype)
2696
2696
2697 ui.write('\n')
2697 ui.write('\n')
2698 ui.write(('chunks : ') + fmt2 % numrevs)
2698 ui.write(('chunks : ') + fmt2 % numrevs)
2699 for chunktype in sorted(chunktypecounts):
2699 for chunktype in sorted(chunktypecounts):
2700 ui.write(fmtchunktype(chunktype))
2700 ui.write(fmtchunktype(chunktype))
2701 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2701 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2702 ui.write(('chunks size : ') + fmt2 % totalsize)
2702 ui.write(('chunks size : ') + fmt2 % totalsize)
2703 for chunktype in sorted(chunktypecounts):
2703 for chunktype in sorted(chunktypecounts):
2704 ui.write(fmtchunktype(chunktype))
2704 ui.write(fmtchunktype(chunktype))
2705 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2705 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2706
2706
2707 ui.write('\n')
2707 ui.write('\n')
2708 fmt = dfmtstr(max(avgchainlen, compratio))
2708 fmt = dfmtstr(max(avgchainlen, compratio))
2709 ui.write(('avg chain length : ') + fmt % avgchainlen)
2709 ui.write(('avg chain length : ') + fmt % avgchainlen)
2710 ui.write(('max chain length : ') + fmt % maxchainlen)
2710 ui.write(('max chain length : ') + fmt % maxchainlen)
2711 ui.write(('compression ratio : ') + fmt % compratio)
2711 ui.write(('compression ratio : ') + fmt % compratio)
2712
2712
2713 if format > 0:
2713 if format > 0:
2714 ui.write('\n')
2714 ui.write('\n')
2715 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2715 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2716 % tuple(datasize))
2716 % tuple(datasize))
2717 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2717 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2718 % tuple(fullsize))
2718 % tuple(fullsize))
2719 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2719 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2720 % tuple(deltasize))
2720 % tuple(deltasize))
2721
2721
2722 if numdeltas > 0:
2722 if numdeltas > 0:
2723 ui.write('\n')
2723 ui.write('\n')
2724 fmt = pcfmtstr(numdeltas)
2724 fmt = pcfmtstr(numdeltas)
2725 fmt2 = pcfmtstr(numdeltas, 4)
2725 fmt2 = pcfmtstr(numdeltas, 4)
2726 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2726 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2727 if numprev > 0:
2727 if numprev > 0:
2728 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2728 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2729 numprev))
2729 numprev))
2730 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2730 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2731 numprev))
2731 numprev))
2732 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2732 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2733 numprev))
2733 numprev))
2734 if gdelta:
2734 if gdelta:
2735 ui.write(('deltas against p1 : ')
2735 ui.write(('deltas against p1 : ')
2736 + fmt % pcfmt(nump1, numdeltas))
2736 + fmt % pcfmt(nump1, numdeltas))
2737 ui.write(('deltas against p2 : ')
2737 ui.write(('deltas against p2 : ')
2738 + fmt % pcfmt(nump2, numdeltas))
2738 + fmt % pcfmt(nump2, numdeltas))
2739 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2739 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2740 numdeltas))
2740 numdeltas))
2741
2741
2742 @command('debugrevspec',
2742 @command('debugrevspec',
2743 [('', 'optimize', None,
2743 [('', 'optimize', None,
2744 _('print parsed tree after optimizing (DEPRECATED)')),
2744 _('print parsed tree after optimizing (DEPRECATED)')),
2745 ('p', 'show-stage', [],
2745 ('p', 'show-stage', [],
2746 _('print parsed tree at the given stage'), _('NAME')),
2746 _('print parsed tree at the given stage'), _('NAME')),
2747 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2747 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2748 ('', 'verify-optimized', False, _('verify optimized result')),
2748 ('', 'verify-optimized', False, _('verify optimized result')),
2749 ],
2749 ],
2750 ('REVSPEC'))
2750 ('REVSPEC'))
2751 def debugrevspec(ui, repo, expr, **opts):
2751 def debugrevspec(ui, repo, expr, **opts):
2752 """parse and apply a revision specification
2752 """parse and apply a revision specification
2753
2753
2754 Use -p/--show-stage option to print the parsed tree at the given stages.
2754 Use -p/--show-stage option to print the parsed tree at the given stages.
2755 Use -p all to print tree at every stage.
2755 Use -p all to print tree at every stage.
2756
2756
2757 Use --verify-optimized to compare the optimized result with the unoptimized
2757 Use --verify-optimized to compare the optimized result with the unoptimized
2758 one. Returns 1 if the optimized result differs.
2758 one. Returns 1 if the optimized result differs.
2759 """
2759 """
2760 stages = [
2760 stages = [
2761 ('parsed', lambda tree: tree),
2761 ('parsed', lambda tree: tree),
2762 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2762 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
2763 ('concatenated', revset.foldconcat),
2763 ('concatenated', revset.foldconcat),
2764 ('analyzed', revset.analyze),
2764 ('analyzed', revset.analyze),
2765 ('optimized', revset.optimize),
2765 ('optimized', revset.optimize),
2766 ]
2766 ]
2767 if opts['no_optimized']:
2767 if opts['no_optimized']:
2768 stages = stages[:-1]
2768 stages = stages[:-1]
2769 if opts['verify_optimized'] and opts['no_optimized']:
2769 if opts['verify_optimized'] and opts['no_optimized']:
2770 raise error.Abort(_('cannot use --verify-optimized with '
2770 raise error.Abort(_('cannot use --verify-optimized with '
2771 '--no-optimized'))
2771 '--no-optimized'))
2772 stagenames = set(n for n, f in stages)
2772 stagenames = set(n for n, f in stages)
2773
2773
2774 showalways = set()
2774 showalways = set()
2775 showchanged = set()
2775 showchanged = set()
2776 if ui.verbose and not opts['show_stage']:
2776 if ui.verbose and not opts['show_stage']:
2777 # show parsed tree by --verbose (deprecated)
2777 # show parsed tree by --verbose (deprecated)
2778 showalways.add('parsed')
2778 showalways.add('parsed')
2779 showchanged.update(['expanded', 'concatenated'])
2779 showchanged.update(['expanded', 'concatenated'])
2780 if opts['optimize']:
2780 if opts['optimize']:
2781 showalways.add('optimized')
2781 showalways.add('optimized')
2782 if opts['show_stage'] and opts['optimize']:
2782 if opts['show_stage'] and opts['optimize']:
2783 raise error.Abort(_('cannot use --optimize with --show-stage'))
2783 raise error.Abort(_('cannot use --optimize with --show-stage'))
2784 if opts['show_stage'] == ['all']:
2784 if opts['show_stage'] == ['all']:
2785 showalways.update(stagenames)
2785 showalways.update(stagenames)
2786 else:
2786 else:
2787 for n in opts['show_stage']:
2787 for n in opts['show_stage']:
2788 if n not in stagenames:
2788 if n not in stagenames:
2789 raise error.Abort(_('invalid stage name: %s') % n)
2789 raise error.Abort(_('invalid stage name: %s') % n)
2790 showalways.update(opts['show_stage'])
2790 showalways.update(opts['show_stage'])
2791
2791
2792 treebystage = {}
2792 treebystage = {}
2793 printedtree = None
2793 printedtree = None
2794 tree = revset.parse(expr, lookup=repo.__contains__)
2794 tree = revset.parse(expr, lookup=repo.__contains__)
2795 for n, f in stages:
2795 for n, f in stages:
2796 treebystage[n] = tree = f(tree)
2796 treebystage[n] = tree = f(tree)
2797 if n in showalways or (n in showchanged and tree != printedtree):
2797 if n in showalways or (n in showchanged and tree != printedtree):
2798 if opts['show_stage'] or n != 'parsed':
2798 if opts['show_stage'] or n != 'parsed':
2799 ui.write(("* %s:\n") % n)
2799 ui.write(("* %s:\n") % n)
2800 ui.write(revset.prettyformat(tree), "\n")
2800 ui.write(revset.prettyformat(tree), "\n")
2801 printedtree = tree
2801 printedtree = tree
2802
2802
2803 if opts['verify_optimized']:
2803 if opts['verify_optimized']:
2804 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2804 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2805 brevs = revset.makematcher(treebystage['optimized'])(repo)
2805 brevs = revset.makematcher(treebystage['optimized'])(repo)
2806 if ui.verbose:
2806 if ui.verbose:
2807 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
2807 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
2808 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
2808 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
2809 arevs = list(arevs)
2809 arevs = list(arevs)
2810 brevs = list(brevs)
2810 brevs = list(brevs)
2811 if arevs == brevs:
2811 if arevs == brevs:
2812 return 0
2812 return 0
2813 ui.write(('--- analyzed\n'), label='diff.file_a')
2813 ui.write(('--- analyzed\n'), label='diff.file_a')
2814 ui.write(('+++ optimized\n'), label='diff.file_b')
2814 ui.write(('+++ optimized\n'), label='diff.file_b')
2815 sm = difflib.SequenceMatcher(None, arevs, brevs)
2815 sm = difflib.SequenceMatcher(None, arevs, brevs)
2816 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2816 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2817 if tag in ('delete', 'replace'):
2817 if tag in ('delete', 'replace'):
2818 for c in arevs[alo:ahi]:
2818 for c in arevs[alo:ahi]:
2819 ui.write('-%s\n' % c, label='diff.deleted')
2819 ui.write('-%s\n' % c, label='diff.deleted')
2820 if tag in ('insert', 'replace'):
2820 if tag in ('insert', 'replace'):
2821 for c in brevs[blo:bhi]:
2821 for c in brevs[blo:bhi]:
2822 ui.write('+%s\n' % c, label='diff.inserted')
2822 ui.write('+%s\n' % c, label='diff.inserted')
2823 if tag == 'equal':
2823 if tag == 'equal':
2824 for c in arevs[alo:ahi]:
2824 for c in arevs[alo:ahi]:
2825 ui.write(' %s\n' % c)
2825 ui.write(' %s\n' % c)
2826 return 1
2826 return 1
2827
2827
2828 func = revset.makematcher(tree)
2828 func = revset.makematcher(tree)
2829 revs = func(repo)
2829 revs = func(repo)
2830 if ui.verbose:
2830 if ui.verbose:
2831 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
2831 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
2832 for c in revs:
2832 for c in revs:
2833 ui.write("%s\n" % c)
2833 ui.write("%s\n" % c)
2834
2834
2835 @command('debugsetparents', [], _('REV1 [REV2]'))
2835 @command('debugsetparents', [], _('REV1 [REV2]'))
2836 def debugsetparents(ui, repo, rev1, rev2=None):
2836 def debugsetparents(ui, repo, rev1, rev2=None):
2837 """manually set the parents of the current working directory
2837 """manually set the parents of the current working directory
2838
2838
2839 This is useful for writing repository conversion tools, but should
2839 This is useful for writing repository conversion tools, but should
2840 be used with care. For example, neither the working directory nor the
2840 be used with care. For example, neither the working directory nor the
2841 dirstate is updated, so file status may be incorrect after running this
2841 dirstate is updated, so file status may be incorrect after running this
2842 command.
2842 command.
2843
2843
2844 Returns 0 on success.
2844 Returns 0 on success.
2845 """
2845 """
2846
2846
2847 r1 = scmutil.revsingle(repo, rev1).node()
2847 r1 = scmutil.revsingle(repo, rev1).node()
2848 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2848 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2849
2849
2850 with repo.wlock():
2850 with repo.wlock():
2851 repo.setparents(r1, r2)
2851 repo.setparents(r1, r2)
2852
2852
2853 @command('debugdirstate|debugstate',
2853 @command('debugdirstate|debugstate',
2854 [('', 'nodates', None, _('do not display the saved mtime')),
2854 [('', 'nodates', None, _('do not display the saved mtime')),
2855 ('', 'datesort', None, _('sort by saved mtime'))],
2855 ('', 'datesort', None, _('sort by saved mtime'))],
2856 _('[OPTION]...'))
2856 _('[OPTION]...'))
2857 def debugstate(ui, repo, **opts):
2857 def debugstate(ui, repo, **opts):
2858 """show the contents of the current dirstate"""
2858 """show the contents of the current dirstate"""
2859
2859
2860 nodates = opts.get('nodates')
2860 nodates = opts.get('nodates')
2861 datesort = opts.get('datesort')
2861 datesort = opts.get('datesort')
2862
2862
2863 timestr = ""
2863 timestr = ""
2864 if datesort:
2864 if datesort:
2865 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2865 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2866 else:
2866 else:
2867 keyfunc = None # sort by filename
2867 keyfunc = None # sort by filename
2868 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2868 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2869 if ent[3] == -1:
2869 if ent[3] == -1:
2870 timestr = 'unset '
2870 timestr = 'unset '
2871 elif nodates:
2871 elif nodates:
2872 timestr = 'set '
2872 timestr = 'set '
2873 else:
2873 else:
2874 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2874 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2875 time.localtime(ent[3]))
2875 time.localtime(ent[3]))
2876 if ent[1] & 0o20000:
2876 if ent[1] & 0o20000:
2877 mode = 'lnk'
2877 mode = 'lnk'
2878 else:
2878 else:
2879 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2879 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
2880 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2880 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2881 for f in repo.dirstate.copies():
2881 for f in repo.dirstate.copies():
2882 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2882 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2883
2883
2884 @command('debugsub',
2884 @command('debugsub',
2885 [('r', 'rev', '',
2885 [('r', 'rev', '',
2886 _('revision to check'), _('REV'))],
2886 _('revision to check'), _('REV'))],
2887 _('[-r REV] [REV]'))
2887 _('[-r REV] [REV]'))
2888 def debugsub(ui, repo, rev=None):
2888 def debugsub(ui, repo, rev=None):
2889 ctx = scmutil.revsingle(repo, rev, None)
2889 ctx = scmutil.revsingle(repo, rev, None)
2890 for k, v in sorted(ctx.substate.items()):
2890 for k, v in sorted(ctx.substate.items()):
2891 ui.write(('path %s\n') % k)
2891 ui.write(('path %s\n') % k)
2892 ui.write((' source %s\n') % v[0])
2892 ui.write((' source %s\n') % v[0])
2893 ui.write((' revision %s\n') % v[1])
2893 ui.write((' revision %s\n') % v[1])
2894
2894
2895 @command('debugsuccessorssets',
2895 @command('debugsuccessorssets',
2896 [],
2896 [],
2897 _('[REV]'))
2897 _('[REV]'))
2898 def debugsuccessorssets(ui, repo, *revs):
2898 def debugsuccessorssets(ui, repo, *revs):
2899 """show set of successors for revision
2899 """show set of successors for revision
2900
2900
2901 A successors set of changeset A is a consistent group of revisions that
2901 A successors set of changeset A is a consistent group of revisions that
2902 succeed A. It contains non-obsolete changesets only.
2902 succeed A. It contains non-obsolete changesets only.
2903
2903
2904 In most cases a changeset A has a single successors set containing a single
2904 In most cases a changeset A has a single successors set containing a single
2905 successor (changeset A replaced by A').
2905 successor (changeset A replaced by A').
2906
2906
2907 A changeset that is made obsolete with no successors are called "pruned".
2907 A changeset that is made obsolete with no successors are called "pruned".
2908 Such changesets have no successors sets at all.
2908 Such changesets have no successors sets at all.
2909
2909
2910 A changeset that has been "split" will have a successors set containing
2910 A changeset that has been "split" will have a successors set containing
2911 more than one successor.
2911 more than one successor.
2912
2912
2913 A changeset that has been rewritten in multiple different ways is called
2913 A changeset that has been rewritten in multiple different ways is called
2914 "divergent". Such changesets have multiple successor sets (each of which
2914 "divergent". Such changesets have multiple successor sets (each of which
2915 may also be split, i.e. have multiple successors).
2915 may also be split, i.e. have multiple successors).
2916
2916
2917 Results are displayed as follows::
2917 Results are displayed as follows::
2918
2918
2919 <rev1>
2919 <rev1>
2920 <successors-1A>
2920 <successors-1A>
2921 <rev2>
2921 <rev2>
2922 <successors-2A>
2922 <successors-2A>
2923 <successors-2B1> <successors-2B2> <successors-2B3>
2923 <successors-2B1> <successors-2B2> <successors-2B3>
2924
2924
2925 Here rev2 has two possible (i.e. divergent) successors sets. The first
2925 Here rev2 has two possible (i.e. divergent) successors sets. The first
2926 holds one element, whereas the second holds three (i.e. the changeset has
2926 holds one element, whereas the second holds three (i.e. the changeset has
2927 been split).
2927 been split).
2928 """
2928 """
2929 # passed to successorssets caching computation from one call to another
2929 # passed to successorssets caching computation from one call to another
2930 cache = {}
2930 cache = {}
2931 ctx2str = str
2931 ctx2str = str
2932 node2str = short
2932 node2str = short
2933 if ui.debug():
2933 if ui.debug():
2934 def ctx2str(ctx):
2934 def ctx2str(ctx):
2935 return ctx.hex()
2935 return ctx.hex()
2936 node2str = hex
2936 node2str = hex
2937 for rev in scmutil.revrange(repo, revs):
2937 for rev in scmutil.revrange(repo, revs):
2938 ctx = repo[rev]
2938 ctx = repo[rev]
2939 ui.write('%s\n'% ctx2str(ctx))
2939 ui.write('%s\n'% ctx2str(ctx))
2940 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2940 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2941 if succsset:
2941 if succsset:
2942 ui.write(' ')
2942 ui.write(' ')
2943 ui.write(node2str(succsset[0]))
2943 ui.write(node2str(succsset[0]))
2944 for node in succsset[1:]:
2944 for node in succsset[1:]:
2945 ui.write(' ')
2945 ui.write(' ')
2946 ui.write(node2str(node))
2946 ui.write(node2str(node))
2947 ui.write('\n')
2947 ui.write('\n')
2948
2948
2949 @command('debugtemplate',
2949 @command('debugtemplate',
2950 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2950 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2951 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2951 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2952 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2952 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2953 optionalrepo=True)
2953 optionalrepo=True)
2954 def debugtemplate(ui, repo, tmpl, **opts):
2954 def debugtemplate(ui, repo, tmpl, **opts):
2955 """parse and apply a template
2955 """parse and apply a template
2956
2956
2957 If -r/--rev is given, the template is processed as a log template and
2957 If -r/--rev is given, the template is processed as a log template and
2958 applied to the given changesets. Otherwise, it is processed as a generic
2958 applied to the given changesets. Otherwise, it is processed as a generic
2959 template.
2959 template.
2960
2960
2961 Use --verbose to print the parsed tree.
2961 Use --verbose to print the parsed tree.
2962 """
2962 """
2963 revs = None
2963 revs = None
2964 if opts['rev']:
2964 if opts['rev']:
2965 if repo is None:
2965 if repo is None:
2966 raise error.RepoError(_('there is no Mercurial repository here '
2966 raise error.RepoError(_('there is no Mercurial repository here '
2967 '(.hg not found)'))
2967 '(.hg not found)'))
2968 revs = scmutil.revrange(repo, opts['rev'])
2968 revs = scmutil.revrange(repo, opts['rev'])
2969
2969
2970 props = {}
2970 props = {}
2971 for d in opts['define']:
2971 for d in opts['define']:
2972 try:
2972 try:
2973 k, v = (e.strip() for e in d.split('=', 1))
2973 k, v = (e.strip() for e in d.split('=', 1))
2974 if not k:
2974 if not k:
2975 raise ValueError
2975 raise ValueError
2976 props[k] = v
2976 props[k] = v
2977 except ValueError:
2977 except ValueError:
2978 raise error.Abort(_('malformed keyword definition: %s') % d)
2978 raise error.Abort(_('malformed keyword definition: %s') % d)
2979
2979
2980 if ui.verbose:
2980 if ui.verbose:
2981 aliases = ui.configitems('templatealias')
2981 aliases = ui.configitems('templatealias')
2982 tree = templater.parse(tmpl)
2982 tree = templater.parse(tmpl)
2983 ui.note(templater.prettyformat(tree), '\n')
2983 ui.note(templater.prettyformat(tree), '\n')
2984 newtree = templater.expandaliases(tree, aliases)
2984 newtree = templater.expandaliases(tree, aliases)
2985 if newtree != tree:
2985 if newtree != tree:
2986 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2986 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2987
2987
2988 mapfile = None
2988 mapfile = None
2989 if revs is None:
2989 if revs is None:
2990 k = 'debugtemplate'
2990 k = 'debugtemplate'
2991 t = formatter.maketemplater(ui, k, tmpl)
2991 t = formatter.maketemplater(ui, k, tmpl)
2992 ui.write(templater.stringify(t(k, **props)))
2992 ui.write(templater.stringify(t(k, **props)))
2993 else:
2993 else:
2994 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2994 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2995 mapfile, buffered=False)
2995 mapfile, buffered=False)
2996 for r in revs:
2996 for r in revs:
2997 displayer.show(repo[r], **props)
2997 displayer.show(repo[r], **props)
2998 displayer.close()
2998 displayer.close()
2999
2999
3000 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3000 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3001 def debugwalk(ui, repo, *pats, **opts):
3001 def debugwalk(ui, repo, *pats, **opts):
3002 """show how files match on given patterns"""
3002 """show how files match on given patterns"""
3003 m = scmutil.match(repo[None], pats, opts)
3003 m = scmutil.match(repo[None], pats, opts)
3004 items = list(repo.walk(m))
3004 items = list(repo.walk(m))
3005 if not items:
3005 if not items:
3006 return
3006 return
3007 f = lambda fn: fn
3007 f = lambda fn: fn
3008 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3008 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3009 f = lambda fn: util.normpath(fn)
3009 f = lambda fn: util.normpath(fn)
3010 fmt = 'f %%-%ds %%-%ds %%s' % (
3010 fmt = 'f %%-%ds %%-%ds %%s' % (
3011 max([len(abs) for abs in items]),
3011 max([len(abs) for abs in items]),
3012 max([len(m.rel(abs)) for abs in items]))
3012 max([len(m.rel(abs)) for abs in items]))
3013 for abs in items:
3013 for abs in items:
3014 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3014 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3015 ui.write("%s\n" % line.rstrip())
3015 ui.write("%s\n" % line.rstrip())
3016
3016
3017 @command('debugwireargs',
3017 @command('debugwireargs',
3018 [('', 'three', '', 'three'),
3018 [('', 'three', '', 'three'),
3019 ('', 'four', '', 'four'),
3019 ('', 'four', '', 'four'),
3020 ('', 'five', '', 'five'),
3020 ('', 'five', '', 'five'),
3021 ] + remoteopts,
3021 ] + remoteopts,
3022 _('REPO [OPTIONS]... [ONE [TWO]]'),
3022 _('REPO [OPTIONS]... [ONE [TWO]]'),
3023 norepo=True)
3023 norepo=True)
3024 def debugwireargs(ui, repopath, *vals, **opts):
3024 def debugwireargs(ui, repopath, *vals, **opts):
3025 repo = hg.peer(ui, opts, repopath)
3025 repo = hg.peer(ui, opts, repopath)
3026 for opt in remoteopts:
3026 for opt in remoteopts:
3027 del opts[opt[1]]
3027 del opts[opt[1]]
3028 args = {}
3028 args = {}
3029 for k, v in opts.iteritems():
3029 for k, v in opts.iteritems():
3030 if v:
3030 if v:
3031 args[k] = v
3031 args[k] = v
3032 # run twice to check that we don't mess up the stream for the next command
3032 # run twice to check that we don't mess up the stream for the next command
3033 res1 = repo.debugwireargs(*vals, **args)
3033 res1 = repo.debugwireargs(*vals, **args)
3034 res2 = repo.debugwireargs(*vals, **args)
3034 res2 = repo.debugwireargs(*vals, **args)
3035 ui.write("%s\n" % res1)
3035 ui.write("%s\n" % res1)
3036 if res1 != res2:
3036 if res1 != res2:
3037 ui.warn("%s\n" % res2)
3037 ui.warn("%s\n" % res2)
3038
3038
3039 @command('^diff',
3039 @command('^diff',
3040 [('r', 'rev', [], _('revision'), _('REV')),
3040 [('r', 'rev', [], _('revision'), _('REV')),
3041 ('c', 'change', '', _('change made by revision'), _('REV'))
3041 ('c', 'change', '', _('change made by revision'), _('REV'))
3042 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3042 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3043 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3043 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3044 inferrepo=True)
3044 inferrepo=True)
3045 def diff(ui, repo, *pats, **opts):
3045 def diff(ui, repo, *pats, **opts):
3046 """diff repository (or selected files)
3046 """diff repository (or selected files)
3047
3047
3048 Show differences between revisions for the specified files.
3048 Show differences between revisions for the specified files.
3049
3049
3050 Differences between files are shown using the unified diff format.
3050 Differences between files are shown using the unified diff format.
3051
3051
3052 .. note::
3052 .. note::
3053
3053
3054 :hg:`diff` may generate unexpected results for merges, as it will
3054 :hg:`diff` may generate unexpected results for merges, as it will
3055 default to comparing against the working directory's first
3055 default to comparing against the working directory's first
3056 parent changeset if no revisions are specified.
3056 parent changeset if no revisions are specified.
3057
3057
3058 When two revision arguments are given, then changes are shown
3058 When two revision arguments are given, then changes are shown
3059 between those revisions. If only one revision is specified then
3059 between those revisions. If only one revision is specified then
3060 that revision is compared to the working directory, and, when no
3060 that revision is compared to the working directory, and, when no
3061 revisions are specified, the working directory files are compared
3061 revisions are specified, the working directory files are compared
3062 to its first parent.
3062 to its first parent.
3063
3063
3064 Alternatively you can specify -c/--change with a revision to see
3064 Alternatively you can specify -c/--change with a revision to see
3065 the changes in that changeset relative to its first parent.
3065 the changes in that changeset relative to its first parent.
3066
3066
3067 Without the -a/--text option, diff will avoid generating diffs of
3067 Without the -a/--text option, diff will avoid generating diffs of
3068 files it detects as binary. With -a, diff will generate a diff
3068 files it detects as binary. With -a, diff will generate a diff
3069 anyway, probably with undesirable results.
3069 anyway, probably with undesirable results.
3070
3070
3071 Use the -g/--git option to generate diffs in the git extended diff
3071 Use the -g/--git option to generate diffs in the git extended diff
3072 format. For more information, read :hg:`help diffs`.
3072 format. For more information, read :hg:`help diffs`.
3073
3073
3074 .. container:: verbose
3074 .. container:: verbose
3075
3075
3076 Examples:
3076 Examples:
3077
3077
3078 - compare a file in the current working directory to its parent::
3078 - compare a file in the current working directory to its parent::
3079
3079
3080 hg diff foo.c
3080 hg diff foo.c
3081
3081
3082 - compare two historical versions of a directory, with rename info::
3082 - compare two historical versions of a directory, with rename info::
3083
3083
3084 hg diff --git -r 1.0:1.2 lib/
3084 hg diff --git -r 1.0:1.2 lib/
3085
3085
3086 - get change stats relative to the last change on some date::
3086 - get change stats relative to the last change on some date::
3087
3087
3088 hg diff --stat -r "date('may 2')"
3088 hg diff --stat -r "date('may 2')"
3089
3089
3090 - diff all newly-added files that contain a keyword::
3090 - diff all newly-added files that contain a keyword::
3091
3091
3092 hg diff "set:added() and grep(GNU)"
3092 hg diff "set:added() and grep(GNU)"
3093
3093
3094 - compare a revision and its parents::
3094 - compare a revision and its parents::
3095
3095
3096 hg diff -c 9353 # compare against first parent
3096 hg diff -c 9353 # compare against first parent
3097 hg diff -r 9353^:9353 # same using revset syntax
3097 hg diff -r 9353^:9353 # same using revset syntax
3098 hg diff -r 9353^2:9353 # compare against the second parent
3098 hg diff -r 9353^2:9353 # compare against the second parent
3099
3099
3100 Returns 0 on success.
3100 Returns 0 on success.
3101 """
3101 """
3102
3102
3103 revs = opts.get('rev')
3103 revs = opts.get('rev')
3104 change = opts.get('change')
3104 change = opts.get('change')
3105 stat = opts.get('stat')
3105 stat = opts.get('stat')
3106 reverse = opts.get('reverse')
3106 reverse = opts.get('reverse')
3107
3107
3108 if revs and change:
3108 if revs and change:
3109 msg = _('cannot specify --rev and --change at the same time')
3109 msg = _('cannot specify --rev and --change at the same time')
3110 raise error.Abort(msg)
3110 raise error.Abort(msg)
3111 elif change:
3111 elif change:
3112 node2 = scmutil.revsingle(repo, change, None).node()
3112 node2 = scmutil.revsingle(repo, change, None).node()
3113 node1 = repo[node2].p1().node()
3113 node1 = repo[node2].p1().node()
3114 else:
3114 else:
3115 node1, node2 = scmutil.revpair(repo, revs)
3115 node1, node2 = scmutil.revpair(repo, revs)
3116
3116
3117 if reverse:
3117 if reverse:
3118 node1, node2 = node2, node1
3118 node1, node2 = node2, node1
3119
3119
3120 diffopts = patch.diffallopts(ui, opts)
3120 diffopts = patch.diffallopts(ui, opts)
3121 m = scmutil.match(repo[node2], pats, opts)
3121 m = scmutil.match(repo[node2], pats, opts)
3122 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3122 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3123 listsubrepos=opts.get('subrepos'),
3123 listsubrepos=opts.get('subrepos'),
3124 root=opts.get('root'))
3124 root=opts.get('root'))
3125
3125
3126 @command('^export',
3126 @command('^export',
3127 [('o', 'output', '',
3127 [('o', 'output', '',
3128 _('print output to file with formatted name'), _('FORMAT')),
3128 _('print output to file with formatted name'), _('FORMAT')),
3129 ('', 'switch-parent', None, _('diff against the second parent')),
3129 ('', 'switch-parent', None, _('diff against the second parent')),
3130 ('r', 'rev', [], _('revisions to export'), _('REV')),
3130 ('r', 'rev', [], _('revisions to export'), _('REV')),
3131 ] + diffopts,
3131 ] + diffopts,
3132 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3132 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3133 def export(ui, repo, *changesets, **opts):
3133 def export(ui, repo, *changesets, **opts):
3134 """dump the header and diffs for one or more changesets
3134 """dump the header and diffs for one or more changesets
3135
3135
3136 Print the changeset header and diffs for one or more revisions.
3136 Print the changeset header and diffs for one or more revisions.
3137 If no revision is given, the parent of the working directory is used.
3137 If no revision is given, the parent of the working directory is used.
3138
3138
3139 The information shown in the changeset header is: author, date,
3139 The information shown in the changeset header is: author, date,
3140 branch name (if non-default), changeset hash, parent(s) and commit
3140 branch name (if non-default), changeset hash, parent(s) and commit
3141 comment.
3141 comment.
3142
3142
3143 .. note::
3143 .. note::
3144
3144
3145 :hg:`export` may generate unexpected diff output for merge
3145 :hg:`export` may generate unexpected diff output for merge
3146 changesets, as it will compare the merge changeset against its
3146 changesets, as it will compare the merge changeset against its
3147 first parent only.
3147 first parent only.
3148
3148
3149 Output may be to a file, in which case the name of the file is
3149 Output may be to a file, in which case the name of the file is
3150 given using a format string. The formatting rules are as follows:
3150 given using a format string. The formatting rules are as follows:
3151
3151
3152 :``%%``: literal "%" character
3152 :``%%``: literal "%" character
3153 :``%H``: changeset hash (40 hexadecimal digits)
3153 :``%H``: changeset hash (40 hexadecimal digits)
3154 :``%N``: number of patches being generated
3154 :``%N``: number of patches being generated
3155 :``%R``: changeset revision number
3155 :``%R``: changeset revision number
3156 :``%b``: basename of the exporting repository
3156 :``%b``: basename of the exporting repository
3157 :``%h``: short-form changeset hash (12 hexadecimal digits)
3157 :``%h``: short-form changeset hash (12 hexadecimal digits)
3158 :``%m``: first line of the commit message (only alphanumeric characters)
3158 :``%m``: first line of the commit message (only alphanumeric characters)
3159 :``%n``: zero-padded sequence number, starting at 1
3159 :``%n``: zero-padded sequence number, starting at 1
3160 :``%r``: zero-padded changeset revision number
3160 :``%r``: zero-padded changeset revision number
3161
3161
3162 Without the -a/--text option, export will avoid generating diffs
3162 Without the -a/--text option, export will avoid generating diffs
3163 of files it detects as binary. With -a, export will generate a
3163 of files it detects as binary. With -a, export will generate a
3164 diff anyway, probably with undesirable results.
3164 diff anyway, probably with undesirable results.
3165
3165
3166 Use the -g/--git option to generate diffs in the git extended diff
3166 Use the -g/--git option to generate diffs in the git extended diff
3167 format. See :hg:`help diffs` for more information.
3167 format. See :hg:`help diffs` for more information.
3168
3168
3169 With the --switch-parent option, the diff will be against the
3169 With the --switch-parent option, the diff will be against the
3170 second parent. It can be useful to review a merge.
3170 second parent. It can be useful to review a merge.
3171
3171
3172 .. container:: verbose
3172 .. container:: verbose
3173
3173
3174 Examples:
3174 Examples:
3175
3175
3176 - use export and import to transplant a bugfix to the current
3176 - use export and import to transplant a bugfix to the current
3177 branch::
3177 branch::
3178
3178
3179 hg export -r 9353 | hg import -
3179 hg export -r 9353 | hg import -
3180
3180
3181 - export all the changesets between two revisions to a file with
3181 - export all the changesets between two revisions to a file with
3182 rename information::
3182 rename information::
3183
3183
3184 hg export --git -r 123:150 > changes.txt
3184 hg export --git -r 123:150 > changes.txt
3185
3185
3186 - split outgoing changes into a series of patches with
3186 - split outgoing changes into a series of patches with
3187 descriptive names::
3187 descriptive names::
3188
3188
3189 hg export -r "outgoing()" -o "%n-%m.patch"
3189 hg export -r "outgoing()" -o "%n-%m.patch"
3190
3190
3191 Returns 0 on success.
3191 Returns 0 on success.
3192 """
3192 """
3193 changesets += tuple(opts.get('rev', []))
3193 changesets += tuple(opts.get('rev', []))
3194 if not changesets:
3194 if not changesets:
3195 changesets = ['.']
3195 changesets = ['.']
3196 revs = scmutil.revrange(repo, changesets)
3196 revs = scmutil.revrange(repo, changesets)
3197 if not revs:
3197 if not revs:
3198 raise error.Abort(_("export requires at least one changeset"))
3198 raise error.Abort(_("export requires at least one changeset"))
3199 if len(revs) > 1:
3199 if len(revs) > 1:
3200 ui.note(_('exporting patches:\n'))
3200 ui.note(_('exporting patches:\n'))
3201 else:
3201 else:
3202 ui.note(_('exporting patch:\n'))
3202 ui.note(_('exporting patch:\n'))
3203 cmdutil.export(repo, revs, template=opts.get('output'),
3203 cmdutil.export(repo, revs, template=opts.get('output'),
3204 switch_parent=opts.get('switch_parent'),
3204 switch_parent=opts.get('switch_parent'),
3205 opts=patch.diffallopts(ui, opts))
3205 opts=patch.diffallopts(ui, opts))
3206
3206
3207 @command('files',
3207 @command('files',
3208 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3208 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3209 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3209 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3210 ] + walkopts + formatteropts + subrepoopts,
3210 ] + walkopts + formatteropts + subrepoopts,
3211 _('[OPTION]... [FILE]...'))
3211 _('[OPTION]... [FILE]...'))
3212 def files(ui, repo, *pats, **opts):
3212 def files(ui, repo, *pats, **opts):
3213 """list tracked files
3213 """list tracked files
3214
3214
3215 Print files under Mercurial control in the working directory or
3215 Print files under Mercurial control in the working directory or
3216 specified revision for given files (excluding removed files).
3216 specified revision for given files (excluding removed files).
3217 Files can be specified as filenames or filesets.
3217 Files can be specified as filenames or filesets.
3218
3218
3219 If no files are given to match, this command prints the names
3219 If no files are given to match, this command prints the names
3220 of all files under Mercurial control.
3220 of all files under Mercurial control.
3221
3221
3222 .. container:: verbose
3222 .. container:: verbose
3223
3223
3224 Examples:
3224 Examples:
3225
3225
3226 - list all files under the current directory::
3226 - list all files under the current directory::
3227
3227
3228 hg files .
3228 hg files .
3229
3229
3230 - shows sizes and flags for current revision::
3230 - shows sizes and flags for current revision::
3231
3231
3232 hg files -vr .
3232 hg files -vr .
3233
3233
3234 - list all files named README::
3234 - list all files named README::
3235
3235
3236 hg files -I "**/README"
3236 hg files -I "**/README"
3237
3237
3238 - list all binary files::
3238 - list all binary files::
3239
3239
3240 hg files "set:binary()"
3240 hg files "set:binary()"
3241
3241
3242 - find files containing a regular expression::
3242 - find files containing a regular expression::
3243
3243
3244 hg files "set:grep('bob')"
3244 hg files "set:grep('bob')"
3245
3245
3246 - search tracked file contents with xargs and grep::
3246 - search tracked file contents with xargs and grep::
3247
3247
3248 hg files -0 | xargs -0 grep foo
3248 hg files -0 | xargs -0 grep foo
3249
3249
3250 See :hg:`help patterns` and :hg:`help filesets` for more information
3250 See :hg:`help patterns` and :hg:`help filesets` for more information
3251 on specifying file patterns.
3251 on specifying file patterns.
3252
3252
3253 Returns 0 if a match is found, 1 otherwise.
3253 Returns 0 if a match is found, 1 otherwise.
3254
3254
3255 """
3255 """
3256 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3256 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3257
3257
3258 end = '\n'
3258 end = '\n'
3259 if opts.get('print0'):
3259 if opts.get('print0'):
3260 end = '\0'
3260 end = '\0'
3261 fmt = '%s' + end
3261 fmt = '%s' + end
3262
3262
3263 m = scmutil.match(ctx, pats, opts)
3263 m = scmutil.match(ctx, pats, opts)
3264 with ui.formatter('files', opts) as fm:
3264 with ui.formatter('files', opts) as fm:
3265 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3265 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3266
3266
3267 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3267 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3268 def forget(ui, repo, *pats, **opts):
3268 def forget(ui, repo, *pats, **opts):
3269 """forget the specified files on the next commit
3269 """forget the specified files on the next commit
3270
3270
3271 Mark the specified files so they will no longer be tracked
3271 Mark the specified files so they will no longer be tracked
3272 after the next commit.
3272 after the next commit.
3273
3273
3274 This only removes files from the current branch, not from the
3274 This only removes files from the current branch, not from the
3275 entire project history, and it does not delete them from the
3275 entire project history, and it does not delete them from the
3276 working directory.
3276 working directory.
3277
3277
3278 To delete the file from the working directory, see :hg:`remove`.
3278 To delete the file from the working directory, see :hg:`remove`.
3279
3279
3280 To undo a forget before the next commit, see :hg:`add`.
3280 To undo a forget before the next commit, see :hg:`add`.
3281
3281
3282 .. container:: verbose
3282 .. container:: verbose
3283
3283
3284 Examples:
3284 Examples:
3285
3285
3286 - forget newly-added binary files::
3286 - forget newly-added binary files::
3287
3287
3288 hg forget "set:added() and binary()"
3288 hg forget "set:added() and binary()"
3289
3289
3290 - forget files that would be excluded by .hgignore::
3290 - forget files that would be excluded by .hgignore::
3291
3291
3292 hg forget "set:hgignore()"
3292 hg forget "set:hgignore()"
3293
3293
3294 Returns 0 on success.
3294 Returns 0 on success.
3295 """
3295 """
3296
3296
3297 if not pats:
3297 if not pats:
3298 raise error.Abort(_('no files specified'))
3298 raise error.Abort(_('no files specified'))
3299
3299
3300 m = scmutil.match(repo[None], pats, opts)
3300 m = scmutil.match(repo[None], pats, opts)
3301 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3301 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3302 return rejected and 1 or 0
3302 return rejected and 1 or 0
3303
3303
3304 @command(
3304 @command(
3305 'graft',
3305 'graft',
3306 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3306 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3307 ('c', 'continue', False, _('resume interrupted graft')),
3307 ('c', 'continue', False, _('resume interrupted graft')),
3308 ('e', 'edit', False, _('invoke editor on commit messages')),
3308 ('e', 'edit', False, _('invoke editor on commit messages')),
3309 ('', 'log', None, _('append graft info to log message')),
3309 ('', 'log', None, _('append graft info to log message')),
3310 ('f', 'force', False, _('force graft')),
3310 ('f', 'force', False, _('force graft')),
3311 ('D', 'currentdate', False,
3311 ('D', 'currentdate', False,
3312 _('record the current date as commit date')),
3312 _('record the current date as commit date')),
3313 ('U', 'currentuser', False,
3313 ('U', 'currentuser', False,
3314 _('record the current user as committer'), _('DATE'))]
3314 _('record the current user as committer'), _('DATE'))]
3315 + commitopts2 + mergetoolopts + dryrunopts,
3315 + commitopts2 + mergetoolopts + dryrunopts,
3316 _('[OPTION]... [-r REV]... REV...'))
3316 _('[OPTION]... [-r REV]... REV...'))
3317 def graft(ui, repo, *revs, **opts):
3317 def graft(ui, repo, *revs, **opts):
3318 '''copy changes from other branches onto the current branch
3318 '''copy changes from other branches onto the current branch
3319
3319
3320 This command uses Mercurial's merge logic to copy individual
3320 This command uses Mercurial's merge logic to copy individual
3321 changes from other branches without merging branches in the
3321 changes from other branches without merging branches in the
3322 history graph. This is sometimes known as 'backporting' or
3322 history graph. This is sometimes known as 'backporting' or
3323 'cherry-picking'. By default, graft will copy user, date, and
3323 'cherry-picking'. By default, graft will copy user, date, and
3324 description from the source changesets.
3324 description from the source changesets.
3325
3325
3326 Changesets that are ancestors of the current revision, that have
3326 Changesets that are ancestors of the current revision, that have
3327 already been grafted, or that are merges will be skipped.
3327 already been grafted, or that are merges will be skipped.
3328
3328
3329 If --log is specified, log messages will have a comment appended
3329 If --log is specified, log messages will have a comment appended
3330 of the form::
3330 of the form::
3331
3331
3332 (grafted from CHANGESETHASH)
3332 (grafted from CHANGESETHASH)
3333
3333
3334 If --force is specified, revisions will be grafted even if they
3334 If --force is specified, revisions will be grafted even if they
3335 are already ancestors of or have been grafted to the destination.
3335 are already ancestors of or have been grafted to the destination.
3336 This is useful when the revisions have since been backed out.
3336 This is useful when the revisions have since been backed out.
3337
3337
3338 If a graft merge results in conflicts, the graft process is
3338 If a graft merge results in conflicts, the graft process is
3339 interrupted so that the current merge can be manually resolved.
3339 interrupted so that the current merge can be manually resolved.
3340 Once all conflicts are addressed, the graft process can be
3340 Once all conflicts are addressed, the graft process can be
3341 continued with the -c/--continue option.
3341 continued with the -c/--continue option.
3342
3342
3343 .. note::
3343 .. note::
3344
3344
3345 The -c/--continue option does not reapply earlier options, except
3345 The -c/--continue option does not reapply earlier options, except
3346 for --force.
3346 for --force.
3347
3347
3348 .. container:: verbose
3348 .. container:: verbose
3349
3349
3350 Examples:
3350 Examples:
3351
3351
3352 - copy a single change to the stable branch and edit its description::
3352 - copy a single change to the stable branch and edit its description::
3353
3353
3354 hg update stable
3354 hg update stable
3355 hg graft --edit 9393
3355 hg graft --edit 9393
3356
3356
3357 - graft a range of changesets with one exception, updating dates::
3357 - graft a range of changesets with one exception, updating dates::
3358
3358
3359 hg graft -D "2085::2093 and not 2091"
3359 hg graft -D "2085::2093 and not 2091"
3360
3360
3361 - continue a graft after resolving conflicts::
3361 - continue a graft after resolving conflicts::
3362
3362
3363 hg graft -c
3363 hg graft -c
3364
3364
3365 - show the source of a grafted changeset::
3365 - show the source of a grafted changeset::
3366
3366
3367 hg log --debug -r .
3367 hg log --debug -r .
3368
3368
3369 - show revisions sorted by date::
3369 - show revisions sorted by date::
3370
3370
3371 hg log -r "sort(all(), date)"
3371 hg log -r "sort(all(), date)"
3372
3372
3373 See :hg:`help revisions` and :hg:`help revsets` for more about
3373 See :hg:`help revisions` for more about specifying revisions.
3374 specifying revisions.
3375
3374
3376 Returns 0 on successful completion.
3375 Returns 0 on successful completion.
3377 '''
3376 '''
3378 with repo.wlock():
3377 with repo.wlock():
3379 return _dograft(ui, repo, *revs, **opts)
3378 return _dograft(ui, repo, *revs, **opts)
3380
3379
3381 def _dograft(ui, repo, *revs, **opts):
3380 def _dograft(ui, repo, *revs, **opts):
3382 if revs and opts.get('rev'):
3381 if revs and opts.get('rev'):
3383 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3382 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3384 'revision ordering!\n'))
3383 'revision ordering!\n'))
3385
3384
3386 revs = list(revs)
3385 revs = list(revs)
3387 revs.extend(opts.get('rev'))
3386 revs.extend(opts.get('rev'))
3388
3387
3389 if not opts.get('user') and opts.get('currentuser'):
3388 if not opts.get('user') and opts.get('currentuser'):
3390 opts['user'] = ui.username()
3389 opts['user'] = ui.username()
3391 if not opts.get('date') and opts.get('currentdate'):
3390 if not opts.get('date') and opts.get('currentdate'):
3392 opts['date'] = "%d %d" % util.makedate()
3391 opts['date'] = "%d %d" % util.makedate()
3393
3392
3394 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3393 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3395
3394
3396 cont = False
3395 cont = False
3397 if opts.get('continue'):
3396 if opts.get('continue'):
3398 cont = True
3397 cont = True
3399 if revs:
3398 if revs:
3400 raise error.Abort(_("can't specify --continue and revisions"))
3399 raise error.Abort(_("can't specify --continue and revisions"))
3401 # read in unfinished revisions
3400 # read in unfinished revisions
3402 try:
3401 try:
3403 nodes = repo.vfs.read('graftstate').splitlines()
3402 nodes = repo.vfs.read('graftstate').splitlines()
3404 revs = [repo[node].rev() for node in nodes]
3403 revs = [repo[node].rev() for node in nodes]
3405 except IOError as inst:
3404 except IOError as inst:
3406 if inst.errno != errno.ENOENT:
3405 if inst.errno != errno.ENOENT:
3407 raise
3406 raise
3408 cmdutil.wrongtooltocontinue(repo, _('graft'))
3407 cmdutil.wrongtooltocontinue(repo, _('graft'))
3409 else:
3408 else:
3410 cmdutil.checkunfinished(repo)
3409 cmdutil.checkunfinished(repo)
3411 cmdutil.bailifchanged(repo)
3410 cmdutil.bailifchanged(repo)
3412 if not revs:
3411 if not revs:
3413 raise error.Abort(_('no revisions specified'))
3412 raise error.Abort(_('no revisions specified'))
3414 revs = scmutil.revrange(repo, revs)
3413 revs = scmutil.revrange(repo, revs)
3415
3414
3416 skipped = set()
3415 skipped = set()
3417 # check for merges
3416 # check for merges
3418 for rev in repo.revs('%ld and merge()', revs):
3417 for rev in repo.revs('%ld and merge()', revs):
3419 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3418 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3420 skipped.add(rev)
3419 skipped.add(rev)
3421 revs = [r for r in revs if r not in skipped]
3420 revs = [r for r in revs if r not in skipped]
3422 if not revs:
3421 if not revs:
3423 return -1
3422 return -1
3424
3423
3425 # Don't check in the --continue case, in effect retaining --force across
3424 # Don't check in the --continue case, in effect retaining --force across
3426 # --continues. That's because without --force, any revisions we decided to
3425 # --continues. That's because without --force, any revisions we decided to
3427 # skip would have been filtered out here, so they wouldn't have made their
3426 # skip would have been filtered out here, so they wouldn't have made their
3428 # way to the graftstate. With --force, any revisions we would have otherwise
3427 # way to the graftstate. With --force, any revisions we would have otherwise
3429 # skipped would not have been filtered out, and if they hadn't been applied
3428 # skipped would not have been filtered out, and if they hadn't been applied
3430 # already, they'd have been in the graftstate.
3429 # already, they'd have been in the graftstate.
3431 if not (cont or opts.get('force')):
3430 if not (cont or opts.get('force')):
3432 # check for ancestors of dest branch
3431 # check for ancestors of dest branch
3433 crev = repo['.'].rev()
3432 crev = repo['.'].rev()
3434 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3433 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3435 # XXX make this lazy in the future
3434 # XXX make this lazy in the future
3436 # don't mutate while iterating, create a copy
3435 # don't mutate while iterating, create a copy
3437 for rev in list(revs):
3436 for rev in list(revs):
3438 if rev in ancestors:
3437 if rev in ancestors:
3439 ui.warn(_('skipping ancestor revision %d:%s\n') %
3438 ui.warn(_('skipping ancestor revision %d:%s\n') %
3440 (rev, repo[rev]))
3439 (rev, repo[rev]))
3441 # XXX remove on list is slow
3440 # XXX remove on list is slow
3442 revs.remove(rev)
3441 revs.remove(rev)
3443 if not revs:
3442 if not revs:
3444 return -1
3443 return -1
3445
3444
3446 # analyze revs for earlier grafts
3445 # analyze revs for earlier grafts
3447 ids = {}
3446 ids = {}
3448 for ctx in repo.set("%ld", revs):
3447 for ctx in repo.set("%ld", revs):
3449 ids[ctx.hex()] = ctx.rev()
3448 ids[ctx.hex()] = ctx.rev()
3450 n = ctx.extra().get('source')
3449 n = ctx.extra().get('source')
3451 if n:
3450 if n:
3452 ids[n] = ctx.rev()
3451 ids[n] = ctx.rev()
3453
3452
3454 # check ancestors for earlier grafts
3453 # check ancestors for earlier grafts
3455 ui.debug('scanning for duplicate grafts\n')
3454 ui.debug('scanning for duplicate grafts\n')
3456
3455
3457 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3456 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3458 ctx = repo[rev]
3457 ctx = repo[rev]
3459 n = ctx.extra().get('source')
3458 n = ctx.extra().get('source')
3460 if n in ids:
3459 if n in ids:
3461 try:
3460 try:
3462 r = repo[n].rev()
3461 r = repo[n].rev()
3463 except error.RepoLookupError:
3462 except error.RepoLookupError:
3464 r = None
3463 r = None
3465 if r in revs:
3464 if r in revs:
3466 ui.warn(_('skipping revision %d:%s '
3465 ui.warn(_('skipping revision %d:%s '
3467 '(already grafted to %d:%s)\n')
3466 '(already grafted to %d:%s)\n')
3468 % (r, repo[r], rev, ctx))
3467 % (r, repo[r], rev, ctx))
3469 revs.remove(r)
3468 revs.remove(r)
3470 elif ids[n] in revs:
3469 elif ids[n] in revs:
3471 if r is None:
3470 if r is None:
3472 ui.warn(_('skipping already grafted revision %d:%s '
3471 ui.warn(_('skipping already grafted revision %d:%s '
3473 '(%d:%s also has unknown origin %s)\n')
3472 '(%d:%s also has unknown origin %s)\n')
3474 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3473 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3475 else:
3474 else:
3476 ui.warn(_('skipping already grafted revision %d:%s '
3475 ui.warn(_('skipping already grafted revision %d:%s '
3477 '(%d:%s also has origin %d:%s)\n')
3476 '(%d:%s also has origin %d:%s)\n')
3478 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3477 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3479 revs.remove(ids[n])
3478 revs.remove(ids[n])
3480 elif ctx.hex() in ids:
3479 elif ctx.hex() in ids:
3481 r = ids[ctx.hex()]
3480 r = ids[ctx.hex()]
3482 ui.warn(_('skipping already grafted revision %d:%s '
3481 ui.warn(_('skipping already grafted revision %d:%s '
3483 '(was grafted from %d:%s)\n') %
3482 '(was grafted from %d:%s)\n') %
3484 (r, repo[r], rev, ctx))
3483 (r, repo[r], rev, ctx))
3485 revs.remove(r)
3484 revs.remove(r)
3486 if not revs:
3485 if not revs:
3487 return -1
3486 return -1
3488
3487
3489 for pos, ctx in enumerate(repo.set("%ld", revs)):
3488 for pos, ctx in enumerate(repo.set("%ld", revs)):
3490 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3489 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3491 ctx.description().split('\n', 1)[0])
3490 ctx.description().split('\n', 1)[0])
3492 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3491 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3493 if names:
3492 if names:
3494 desc += ' (%s)' % ' '.join(names)
3493 desc += ' (%s)' % ' '.join(names)
3495 ui.status(_('grafting %s\n') % desc)
3494 ui.status(_('grafting %s\n') % desc)
3496 if opts.get('dry_run'):
3495 if opts.get('dry_run'):
3497 continue
3496 continue
3498
3497
3499 source = ctx.extra().get('source')
3498 source = ctx.extra().get('source')
3500 extra = {}
3499 extra = {}
3501 if source:
3500 if source:
3502 extra['source'] = source
3501 extra['source'] = source
3503 extra['intermediate-source'] = ctx.hex()
3502 extra['intermediate-source'] = ctx.hex()
3504 else:
3503 else:
3505 extra['source'] = ctx.hex()
3504 extra['source'] = ctx.hex()
3506 user = ctx.user()
3505 user = ctx.user()
3507 if opts.get('user'):
3506 if opts.get('user'):
3508 user = opts['user']
3507 user = opts['user']
3509 date = ctx.date()
3508 date = ctx.date()
3510 if opts.get('date'):
3509 if opts.get('date'):
3511 date = opts['date']
3510 date = opts['date']
3512 message = ctx.description()
3511 message = ctx.description()
3513 if opts.get('log'):
3512 if opts.get('log'):
3514 message += '\n(grafted from %s)' % ctx.hex()
3513 message += '\n(grafted from %s)' % ctx.hex()
3515
3514
3516 # we don't merge the first commit when continuing
3515 # we don't merge the first commit when continuing
3517 if not cont:
3516 if not cont:
3518 # perform the graft merge with p1(rev) as 'ancestor'
3517 # perform the graft merge with p1(rev) as 'ancestor'
3519 try:
3518 try:
3520 # ui.forcemerge is an internal variable, do not document
3519 # ui.forcemerge is an internal variable, do not document
3521 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3520 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3522 'graft')
3521 'graft')
3523 stats = mergemod.graft(repo, ctx, ctx.p1(),
3522 stats = mergemod.graft(repo, ctx, ctx.p1(),
3524 ['local', 'graft'])
3523 ['local', 'graft'])
3525 finally:
3524 finally:
3526 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3525 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3527 # report any conflicts
3526 # report any conflicts
3528 if stats and stats[3] > 0:
3527 if stats and stats[3] > 0:
3529 # write out state for --continue
3528 # write out state for --continue
3530 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3529 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3531 repo.vfs.write('graftstate', ''.join(nodelines))
3530 repo.vfs.write('graftstate', ''.join(nodelines))
3532 extra = ''
3531 extra = ''
3533 if opts.get('user'):
3532 if opts.get('user'):
3534 extra += ' --user %s' % util.shellquote(opts['user'])
3533 extra += ' --user %s' % util.shellquote(opts['user'])
3535 if opts.get('date'):
3534 if opts.get('date'):
3536 extra += ' --date %s' % util.shellquote(opts['date'])
3535 extra += ' --date %s' % util.shellquote(opts['date'])
3537 if opts.get('log'):
3536 if opts.get('log'):
3538 extra += ' --log'
3537 extra += ' --log'
3539 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3538 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
3540 raise error.Abort(
3539 raise error.Abort(
3541 _("unresolved conflicts, can't continue"),
3540 _("unresolved conflicts, can't continue"),
3542 hint=hint)
3541 hint=hint)
3543 else:
3542 else:
3544 cont = False
3543 cont = False
3545
3544
3546 # commit
3545 # commit
3547 node = repo.commit(text=message, user=user,
3546 node = repo.commit(text=message, user=user,
3548 date=date, extra=extra, editor=editor)
3547 date=date, extra=extra, editor=editor)
3549 if node is None:
3548 if node is None:
3550 ui.warn(
3549 ui.warn(
3551 _('note: graft of %d:%s created no changes to commit\n') %
3550 _('note: graft of %d:%s created no changes to commit\n') %
3552 (ctx.rev(), ctx))
3551 (ctx.rev(), ctx))
3553
3552
3554 # remove state when we complete successfully
3553 # remove state when we complete successfully
3555 if not opts.get('dry_run'):
3554 if not opts.get('dry_run'):
3556 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3555 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3557
3556
3558 return 0
3557 return 0
3559
3558
3560 @command('grep',
3559 @command('grep',
3561 [('0', 'print0', None, _('end fields with NUL')),
3560 [('0', 'print0', None, _('end fields with NUL')),
3562 ('', 'all', None, _('print all revisions that match')),
3561 ('', 'all', None, _('print all revisions that match')),
3563 ('a', 'text', None, _('treat all files as text')),
3562 ('a', 'text', None, _('treat all files as text')),
3564 ('f', 'follow', None,
3563 ('f', 'follow', None,
3565 _('follow changeset history,'
3564 _('follow changeset history,'
3566 ' or file history across copies and renames')),
3565 ' or file history across copies and renames')),
3567 ('i', 'ignore-case', None, _('ignore case when matching')),
3566 ('i', 'ignore-case', None, _('ignore case when matching')),
3568 ('l', 'files-with-matches', None,
3567 ('l', 'files-with-matches', None,
3569 _('print only filenames and revisions that match')),
3568 _('print only filenames and revisions that match')),
3570 ('n', 'line-number', None, _('print matching line numbers')),
3569 ('n', 'line-number', None, _('print matching line numbers')),
3571 ('r', 'rev', [],
3570 ('r', 'rev', [],
3572 _('only search files changed within revision range'), _('REV')),
3571 _('only search files changed within revision range'), _('REV')),
3573 ('u', 'user', None, _('list the author (long with -v)')),
3572 ('u', 'user', None, _('list the author (long with -v)')),
3574 ('d', 'date', None, _('list the date (short with -q)')),
3573 ('d', 'date', None, _('list the date (short with -q)')),
3575 ] + formatteropts + walkopts,
3574 ] + formatteropts + walkopts,
3576 _('[OPTION]... PATTERN [FILE]...'),
3575 _('[OPTION]... PATTERN [FILE]...'),
3577 inferrepo=True)
3576 inferrepo=True)
3578 def grep(ui, repo, pattern, *pats, **opts):
3577 def grep(ui, repo, pattern, *pats, **opts):
3579 """search revision history for a pattern in specified files
3578 """search revision history for a pattern in specified files
3580
3579
3581 Search revision history for a regular expression in the specified
3580 Search revision history for a regular expression in the specified
3582 files or the entire project.
3581 files or the entire project.
3583
3582
3584 By default, grep prints the most recent revision number for each
3583 By default, grep prints the most recent revision number for each
3585 file in which it finds a match. To get it to print every revision
3584 file in which it finds a match. To get it to print every revision
3586 that contains a change in match status ("-" for a match that becomes
3585 that contains a change in match status ("-" for a match that becomes
3587 a non-match, or "+" for a non-match that becomes a match), use the
3586 a non-match, or "+" for a non-match that becomes a match), use the
3588 --all flag.
3587 --all flag.
3589
3588
3590 PATTERN can be any Python (roughly Perl-compatible) regular
3589 PATTERN can be any Python (roughly Perl-compatible) regular
3591 expression.
3590 expression.
3592
3591
3593 If no FILEs are specified (and -f/--follow isn't set), all files in
3592 If no FILEs are specified (and -f/--follow isn't set), all files in
3594 the repository are searched, including those that don't exist in the
3593 the repository are searched, including those that don't exist in the
3595 current branch or have been deleted in a prior changeset.
3594 current branch or have been deleted in a prior changeset.
3596
3595
3597 Returns 0 if a match is found, 1 otherwise.
3596 Returns 0 if a match is found, 1 otherwise.
3598 """
3597 """
3599 reflags = re.M
3598 reflags = re.M
3600 if opts.get('ignore_case'):
3599 if opts.get('ignore_case'):
3601 reflags |= re.I
3600 reflags |= re.I
3602 try:
3601 try:
3603 regexp = util.re.compile(pattern, reflags)
3602 regexp = util.re.compile(pattern, reflags)
3604 except re.error as inst:
3603 except re.error as inst:
3605 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3604 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3606 return 1
3605 return 1
3607 sep, eol = ':', '\n'
3606 sep, eol = ':', '\n'
3608 if opts.get('print0'):
3607 if opts.get('print0'):
3609 sep = eol = '\0'
3608 sep = eol = '\0'
3610
3609
3611 getfile = util.lrucachefunc(repo.file)
3610 getfile = util.lrucachefunc(repo.file)
3612
3611
3613 def matchlines(body):
3612 def matchlines(body):
3614 begin = 0
3613 begin = 0
3615 linenum = 0
3614 linenum = 0
3616 while begin < len(body):
3615 while begin < len(body):
3617 match = regexp.search(body, begin)
3616 match = regexp.search(body, begin)
3618 if not match:
3617 if not match:
3619 break
3618 break
3620 mstart, mend = match.span()
3619 mstart, mend = match.span()
3621 linenum += body.count('\n', begin, mstart) + 1
3620 linenum += body.count('\n', begin, mstart) + 1
3622 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3621 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3623 begin = body.find('\n', mend) + 1 or len(body) + 1
3622 begin = body.find('\n', mend) + 1 or len(body) + 1
3624 lend = begin - 1
3623 lend = begin - 1
3625 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3624 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3626
3625
3627 class linestate(object):
3626 class linestate(object):
3628 def __init__(self, line, linenum, colstart, colend):
3627 def __init__(self, line, linenum, colstart, colend):
3629 self.line = line
3628 self.line = line
3630 self.linenum = linenum
3629 self.linenum = linenum
3631 self.colstart = colstart
3630 self.colstart = colstart
3632 self.colend = colend
3631 self.colend = colend
3633
3632
3634 def __hash__(self):
3633 def __hash__(self):
3635 return hash((self.linenum, self.line))
3634 return hash((self.linenum, self.line))
3636
3635
3637 def __eq__(self, other):
3636 def __eq__(self, other):
3638 return self.line == other.line
3637 return self.line == other.line
3639
3638
3640 def findpos(self):
3639 def findpos(self):
3641 """Iterate all (start, end) indices of matches"""
3640 """Iterate all (start, end) indices of matches"""
3642 yield self.colstart, self.colend
3641 yield self.colstart, self.colend
3643 p = self.colend
3642 p = self.colend
3644 while p < len(self.line):
3643 while p < len(self.line):
3645 m = regexp.search(self.line, p)
3644 m = regexp.search(self.line, p)
3646 if not m:
3645 if not m:
3647 break
3646 break
3648 yield m.span()
3647 yield m.span()
3649 p = m.end()
3648 p = m.end()
3650
3649
3651 matches = {}
3650 matches = {}
3652 copies = {}
3651 copies = {}
3653 def grepbody(fn, rev, body):
3652 def grepbody(fn, rev, body):
3654 matches[rev].setdefault(fn, [])
3653 matches[rev].setdefault(fn, [])
3655 m = matches[rev][fn]
3654 m = matches[rev][fn]
3656 for lnum, cstart, cend, line in matchlines(body):
3655 for lnum, cstart, cend, line in matchlines(body):
3657 s = linestate(line, lnum, cstart, cend)
3656 s = linestate(line, lnum, cstart, cend)
3658 m.append(s)
3657 m.append(s)
3659
3658
3660 def difflinestates(a, b):
3659 def difflinestates(a, b):
3661 sm = difflib.SequenceMatcher(None, a, b)
3660 sm = difflib.SequenceMatcher(None, a, b)
3662 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3661 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3663 if tag == 'insert':
3662 if tag == 'insert':
3664 for i in xrange(blo, bhi):
3663 for i in xrange(blo, bhi):
3665 yield ('+', b[i])
3664 yield ('+', b[i])
3666 elif tag == 'delete':
3665 elif tag == 'delete':
3667 for i in xrange(alo, ahi):
3666 for i in xrange(alo, ahi):
3668 yield ('-', a[i])
3667 yield ('-', a[i])
3669 elif tag == 'replace':
3668 elif tag == 'replace':
3670 for i in xrange(alo, ahi):
3669 for i in xrange(alo, ahi):
3671 yield ('-', a[i])
3670 yield ('-', a[i])
3672 for i in xrange(blo, bhi):
3671 for i in xrange(blo, bhi):
3673 yield ('+', b[i])
3672 yield ('+', b[i])
3674
3673
3675 def display(fm, fn, ctx, pstates, states):
3674 def display(fm, fn, ctx, pstates, states):
3676 rev = ctx.rev()
3675 rev = ctx.rev()
3677 if fm.isplain():
3676 if fm.isplain():
3678 formatuser = ui.shortuser
3677 formatuser = ui.shortuser
3679 else:
3678 else:
3680 formatuser = str
3679 formatuser = str
3681 if ui.quiet:
3680 if ui.quiet:
3682 datefmt = '%Y-%m-%d'
3681 datefmt = '%Y-%m-%d'
3683 else:
3682 else:
3684 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3683 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
3685 found = False
3684 found = False
3686 @util.cachefunc
3685 @util.cachefunc
3687 def binary():
3686 def binary():
3688 flog = getfile(fn)
3687 flog = getfile(fn)
3689 return util.binary(flog.read(ctx.filenode(fn)))
3688 return util.binary(flog.read(ctx.filenode(fn)))
3690
3689
3691 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3690 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
3692 if opts.get('all'):
3691 if opts.get('all'):
3693 iter = difflinestates(pstates, states)
3692 iter = difflinestates(pstates, states)
3694 else:
3693 else:
3695 iter = [('', l) for l in states]
3694 iter = [('', l) for l in states]
3696 for change, l in iter:
3695 for change, l in iter:
3697 fm.startitem()
3696 fm.startitem()
3698 fm.data(node=fm.hexfunc(ctx.node()))
3697 fm.data(node=fm.hexfunc(ctx.node()))
3699 cols = [
3698 cols = [
3700 ('filename', fn, True),
3699 ('filename', fn, True),
3701 ('rev', rev, True),
3700 ('rev', rev, True),
3702 ('linenumber', l.linenum, opts.get('line_number')),
3701 ('linenumber', l.linenum, opts.get('line_number')),
3703 ]
3702 ]
3704 if opts.get('all'):
3703 if opts.get('all'):
3705 cols.append(('change', change, True))
3704 cols.append(('change', change, True))
3706 cols.extend([
3705 cols.extend([
3707 ('user', formatuser(ctx.user()), opts.get('user')),
3706 ('user', formatuser(ctx.user()), opts.get('user')),
3708 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3707 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
3709 ])
3708 ])
3710 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3709 lastcol = next(name for name, data, cond in reversed(cols) if cond)
3711 for name, data, cond in cols:
3710 for name, data, cond in cols:
3712 field = fieldnamemap.get(name, name)
3711 field = fieldnamemap.get(name, name)
3713 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3712 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
3714 if cond and name != lastcol:
3713 if cond and name != lastcol:
3715 fm.plain(sep, label='grep.sep')
3714 fm.plain(sep, label='grep.sep')
3716 if not opts.get('files_with_matches'):
3715 if not opts.get('files_with_matches'):
3717 fm.plain(sep, label='grep.sep')
3716 fm.plain(sep, label='grep.sep')
3718 if not opts.get('text') and binary():
3717 if not opts.get('text') and binary():
3719 fm.plain(_(" Binary file matches"))
3718 fm.plain(_(" Binary file matches"))
3720 else:
3719 else:
3721 displaymatches(fm.nested('texts'), l)
3720 displaymatches(fm.nested('texts'), l)
3722 fm.plain(eol)
3721 fm.plain(eol)
3723 found = True
3722 found = True
3724 if opts.get('files_with_matches'):
3723 if opts.get('files_with_matches'):
3725 break
3724 break
3726 return found
3725 return found
3727
3726
3728 def displaymatches(fm, l):
3727 def displaymatches(fm, l):
3729 p = 0
3728 p = 0
3730 for s, e in l.findpos():
3729 for s, e in l.findpos():
3731 if p < s:
3730 if p < s:
3732 fm.startitem()
3731 fm.startitem()
3733 fm.write('text', '%s', l.line[p:s])
3732 fm.write('text', '%s', l.line[p:s])
3734 fm.data(matched=False)
3733 fm.data(matched=False)
3735 fm.startitem()
3734 fm.startitem()
3736 fm.write('text', '%s', l.line[s:e], label='grep.match')
3735 fm.write('text', '%s', l.line[s:e], label='grep.match')
3737 fm.data(matched=True)
3736 fm.data(matched=True)
3738 p = e
3737 p = e
3739 if p < len(l.line):
3738 if p < len(l.line):
3740 fm.startitem()
3739 fm.startitem()
3741 fm.write('text', '%s', l.line[p:])
3740 fm.write('text', '%s', l.line[p:])
3742 fm.data(matched=False)
3741 fm.data(matched=False)
3743 fm.end()
3742 fm.end()
3744
3743
3745 skip = {}
3744 skip = {}
3746 revfiles = {}
3745 revfiles = {}
3747 matchfn = scmutil.match(repo[None], pats, opts)
3746 matchfn = scmutil.match(repo[None], pats, opts)
3748 found = False
3747 found = False
3749 follow = opts.get('follow')
3748 follow = opts.get('follow')
3750
3749
3751 def prep(ctx, fns):
3750 def prep(ctx, fns):
3752 rev = ctx.rev()
3751 rev = ctx.rev()
3753 pctx = ctx.p1()
3752 pctx = ctx.p1()
3754 parent = pctx.rev()
3753 parent = pctx.rev()
3755 matches.setdefault(rev, {})
3754 matches.setdefault(rev, {})
3756 matches.setdefault(parent, {})
3755 matches.setdefault(parent, {})
3757 files = revfiles.setdefault(rev, [])
3756 files = revfiles.setdefault(rev, [])
3758 for fn in fns:
3757 for fn in fns:
3759 flog = getfile(fn)
3758 flog = getfile(fn)
3760 try:
3759 try:
3761 fnode = ctx.filenode(fn)
3760 fnode = ctx.filenode(fn)
3762 except error.LookupError:
3761 except error.LookupError:
3763 continue
3762 continue
3764
3763
3765 copied = flog.renamed(fnode)
3764 copied = flog.renamed(fnode)
3766 copy = follow and copied and copied[0]
3765 copy = follow and copied and copied[0]
3767 if copy:
3766 if copy:
3768 copies.setdefault(rev, {})[fn] = copy
3767 copies.setdefault(rev, {})[fn] = copy
3769 if fn in skip:
3768 if fn in skip:
3770 if copy:
3769 if copy:
3771 skip[copy] = True
3770 skip[copy] = True
3772 continue
3771 continue
3773 files.append(fn)
3772 files.append(fn)
3774
3773
3775 if fn not in matches[rev]:
3774 if fn not in matches[rev]:
3776 grepbody(fn, rev, flog.read(fnode))
3775 grepbody(fn, rev, flog.read(fnode))
3777
3776
3778 pfn = copy or fn
3777 pfn = copy or fn
3779 if pfn not in matches[parent]:
3778 if pfn not in matches[parent]:
3780 try:
3779 try:
3781 fnode = pctx.filenode(pfn)
3780 fnode = pctx.filenode(pfn)
3782 grepbody(pfn, parent, flog.read(fnode))
3781 grepbody(pfn, parent, flog.read(fnode))
3783 except error.LookupError:
3782 except error.LookupError:
3784 pass
3783 pass
3785
3784
3786 fm = ui.formatter('grep', opts)
3785 fm = ui.formatter('grep', opts)
3787 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3786 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3788 rev = ctx.rev()
3787 rev = ctx.rev()
3789 parent = ctx.p1().rev()
3788 parent = ctx.p1().rev()
3790 for fn in sorted(revfiles.get(rev, [])):
3789 for fn in sorted(revfiles.get(rev, [])):
3791 states = matches[rev][fn]
3790 states = matches[rev][fn]
3792 copy = copies.get(rev, {}).get(fn)
3791 copy = copies.get(rev, {}).get(fn)
3793 if fn in skip:
3792 if fn in skip:
3794 if copy:
3793 if copy:
3795 skip[copy] = True
3794 skip[copy] = True
3796 continue
3795 continue
3797 pstates = matches.get(parent, {}).get(copy or fn, [])
3796 pstates = matches.get(parent, {}).get(copy or fn, [])
3798 if pstates or states:
3797 if pstates or states:
3799 r = display(fm, fn, ctx, pstates, states)
3798 r = display(fm, fn, ctx, pstates, states)
3800 found = found or r
3799 found = found or r
3801 if r and not opts.get('all'):
3800 if r and not opts.get('all'):
3802 skip[fn] = True
3801 skip[fn] = True
3803 if copy:
3802 if copy:
3804 skip[copy] = True
3803 skip[copy] = True
3805 del matches[rev]
3804 del matches[rev]
3806 del revfiles[rev]
3805 del revfiles[rev]
3807 fm.end()
3806 fm.end()
3808
3807
3809 return not found
3808 return not found
3810
3809
3811 @command('heads',
3810 @command('heads',
3812 [('r', 'rev', '',
3811 [('r', 'rev', '',
3813 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3812 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3814 ('t', 'topo', False, _('show topological heads only')),
3813 ('t', 'topo', False, _('show topological heads only')),
3815 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3814 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3816 ('c', 'closed', False, _('show normal and closed branch heads')),
3815 ('c', 'closed', False, _('show normal and closed branch heads')),
3817 ] + templateopts,
3816 ] + templateopts,
3818 _('[-ct] [-r STARTREV] [REV]...'))
3817 _('[-ct] [-r STARTREV] [REV]...'))
3819 def heads(ui, repo, *branchrevs, **opts):
3818 def heads(ui, repo, *branchrevs, **opts):
3820 """show branch heads
3819 """show branch heads
3821
3820
3822 With no arguments, show all open branch heads in the repository.
3821 With no arguments, show all open branch heads in the repository.
3823 Branch heads are changesets that have no descendants on the
3822 Branch heads are changesets that have no descendants on the
3824 same branch. They are where development generally takes place and
3823 same branch. They are where development generally takes place and
3825 are the usual targets for update and merge operations.
3824 are the usual targets for update and merge operations.
3826
3825
3827 If one or more REVs are given, only open branch heads on the
3826 If one or more REVs are given, only open branch heads on the
3828 branches associated with the specified changesets are shown. This
3827 branches associated with the specified changesets are shown. This
3829 means that you can use :hg:`heads .` to see the heads on the
3828 means that you can use :hg:`heads .` to see the heads on the
3830 currently checked-out branch.
3829 currently checked-out branch.
3831
3830
3832 If -c/--closed is specified, also show branch heads marked closed
3831 If -c/--closed is specified, also show branch heads marked closed
3833 (see :hg:`commit --close-branch`).
3832 (see :hg:`commit --close-branch`).
3834
3833
3835 If STARTREV is specified, only those heads that are descendants of
3834 If STARTREV is specified, only those heads that are descendants of
3836 STARTREV will be displayed.
3835 STARTREV will be displayed.
3837
3836
3838 If -t/--topo is specified, named branch mechanics will be ignored and only
3837 If -t/--topo is specified, named branch mechanics will be ignored and only
3839 topological heads (changesets with no children) will be shown.
3838 topological heads (changesets with no children) will be shown.
3840
3839
3841 Returns 0 if matching heads are found, 1 if not.
3840 Returns 0 if matching heads are found, 1 if not.
3842 """
3841 """
3843
3842
3844 start = None
3843 start = None
3845 if 'rev' in opts:
3844 if 'rev' in opts:
3846 start = scmutil.revsingle(repo, opts['rev'], None).node()
3845 start = scmutil.revsingle(repo, opts['rev'], None).node()
3847
3846
3848 if opts.get('topo'):
3847 if opts.get('topo'):
3849 heads = [repo[h] for h in repo.heads(start)]
3848 heads = [repo[h] for h in repo.heads(start)]
3850 else:
3849 else:
3851 heads = []
3850 heads = []
3852 for branch in repo.branchmap():
3851 for branch in repo.branchmap():
3853 heads += repo.branchheads(branch, start, opts.get('closed'))
3852 heads += repo.branchheads(branch, start, opts.get('closed'))
3854 heads = [repo[h] for h in heads]
3853 heads = [repo[h] for h in heads]
3855
3854
3856 if branchrevs:
3855 if branchrevs:
3857 branches = set(repo[br].branch() for br in branchrevs)
3856 branches = set(repo[br].branch() for br in branchrevs)
3858 heads = [h for h in heads if h.branch() in branches]
3857 heads = [h for h in heads if h.branch() in branches]
3859
3858
3860 if opts.get('active') and branchrevs:
3859 if opts.get('active') and branchrevs:
3861 dagheads = repo.heads(start)
3860 dagheads = repo.heads(start)
3862 heads = [h for h in heads if h.node() in dagheads]
3861 heads = [h for h in heads if h.node() in dagheads]
3863
3862
3864 if branchrevs:
3863 if branchrevs:
3865 haveheads = set(h.branch() for h in heads)
3864 haveheads = set(h.branch() for h in heads)
3866 if branches - haveheads:
3865 if branches - haveheads:
3867 headless = ', '.join(b for b in branches - haveheads)
3866 headless = ', '.join(b for b in branches - haveheads)
3868 msg = _('no open branch heads found on branches %s')
3867 msg = _('no open branch heads found on branches %s')
3869 if opts.get('rev'):
3868 if opts.get('rev'):
3870 msg += _(' (started at %s)') % opts['rev']
3869 msg += _(' (started at %s)') % opts['rev']
3871 ui.warn((msg + '\n') % headless)
3870 ui.warn((msg + '\n') % headless)
3872
3871
3873 if not heads:
3872 if not heads:
3874 return 1
3873 return 1
3875
3874
3876 heads = sorted(heads, key=lambda x: -x.rev())
3875 heads = sorted(heads, key=lambda x: -x.rev())
3877 displayer = cmdutil.show_changeset(ui, repo, opts)
3876 displayer = cmdutil.show_changeset(ui, repo, opts)
3878 for ctx in heads:
3877 for ctx in heads:
3879 displayer.show(ctx)
3878 displayer.show(ctx)
3880 displayer.close()
3879 displayer.close()
3881
3880
3882 @command('help',
3881 @command('help',
3883 [('e', 'extension', None, _('show only help for extensions')),
3882 [('e', 'extension', None, _('show only help for extensions')),
3884 ('c', 'command', None, _('show only help for commands')),
3883 ('c', 'command', None, _('show only help for commands')),
3885 ('k', 'keyword', None, _('show topics matching keyword')),
3884 ('k', 'keyword', None, _('show topics matching keyword')),
3886 ('s', 'system', [], _('show help for specific platform(s)')),
3885 ('s', 'system', [], _('show help for specific platform(s)')),
3887 ],
3886 ],
3888 _('[-ecks] [TOPIC]'),
3887 _('[-ecks] [TOPIC]'),
3889 norepo=True)
3888 norepo=True)
3890 def help_(ui, name=None, **opts):
3889 def help_(ui, name=None, **opts):
3891 """show help for a given topic or a help overview
3890 """show help for a given topic or a help overview
3892
3891
3893 With no arguments, print a list of commands with short help messages.
3892 With no arguments, print a list of commands with short help messages.
3894
3893
3895 Given a topic, extension, or command name, print help for that
3894 Given a topic, extension, or command name, print help for that
3896 topic.
3895 topic.
3897
3896
3898 Returns 0 if successful.
3897 Returns 0 if successful.
3899 """
3898 """
3900
3899
3901 textwidth = ui.configint('ui', 'textwidth', 78)
3900 textwidth = ui.configint('ui', 'textwidth', 78)
3902 termwidth = ui.termwidth() - 2
3901 termwidth = ui.termwidth() - 2
3903 if textwidth <= 0 or termwidth < textwidth:
3902 if textwidth <= 0 or termwidth < textwidth:
3904 textwidth = termwidth
3903 textwidth = termwidth
3905
3904
3906 keep = opts.get('system') or []
3905 keep = opts.get('system') or []
3907 if len(keep) == 0:
3906 if len(keep) == 0:
3908 if pycompat.sysplatform.startswith('win'):
3907 if pycompat.sysplatform.startswith('win'):
3909 keep.append('windows')
3908 keep.append('windows')
3910 elif pycompat.sysplatform == 'OpenVMS':
3909 elif pycompat.sysplatform == 'OpenVMS':
3911 keep.append('vms')
3910 keep.append('vms')
3912 elif pycompat.sysplatform == 'plan9':
3911 elif pycompat.sysplatform == 'plan9':
3913 keep.append('plan9')
3912 keep.append('plan9')
3914 else:
3913 else:
3915 keep.append('unix')
3914 keep.append('unix')
3916 keep.append(pycompat.sysplatform.lower())
3915 keep.append(pycompat.sysplatform.lower())
3917 if ui.verbose:
3916 if ui.verbose:
3918 keep.append('verbose')
3917 keep.append('verbose')
3919
3918
3920 section = None
3919 section = None
3921 subtopic = None
3920 subtopic = None
3922 if name and '.' in name:
3921 if name and '.' in name:
3923 name, remaining = name.split('.', 1)
3922 name, remaining = name.split('.', 1)
3924 remaining = encoding.lower(remaining)
3923 remaining = encoding.lower(remaining)
3925 if '.' in remaining:
3924 if '.' in remaining:
3926 subtopic, section = remaining.split('.', 1)
3925 subtopic, section = remaining.split('.', 1)
3927 else:
3926 else:
3928 if name in help.subtopics:
3927 if name in help.subtopics:
3929 subtopic = remaining
3928 subtopic = remaining
3930 else:
3929 else:
3931 section = remaining
3930 section = remaining
3932
3931
3933 text = help.help_(ui, name, subtopic=subtopic, **opts)
3932 text = help.help_(ui, name, subtopic=subtopic, **opts)
3934
3933
3935 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3934 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3936 section=section)
3935 section=section)
3937
3936
3938 # We could have been given a weird ".foo" section without a name
3937 # We could have been given a weird ".foo" section without a name
3939 # to look for, or we could have simply failed to found "foo.bar"
3938 # to look for, or we could have simply failed to found "foo.bar"
3940 # because bar isn't a section of foo
3939 # because bar isn't a section of foo
3941 if section and not (formatted and name):
3940 if section and not (formatted and name):
3942 raise error.Abort(_("help section not found"))
3941 raise error.Abort(_("help section not found"))
3943
3942
3944 if 'verbose' in pruned:
3943 if 'verbose' in pruned:
3945 keep.append('omitted')
3944 keep.append('omitted')
3946 else:
3945 else:
3947 keep.append('notomitted')
3946 keep.append('notomitted')
3948 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3947 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3949 section=section)
3948 section=section)
3950 ui.write(formatted)
3949 ui.write(formatted)
3951
3950
3952
3951
3953 @command('identify|id',
3952 @command('identify|id',
3954 [('r', 'rev', '',
3953 [('r', 'rev', '',
3955 _('identify the specified revision'), _('REV')),
3954 _('identify the specified revision'), _('REV')),
3956 ('n', 'num', None, _('show local revision number')),
3955 ('n', 'num', None, _('show local revision number')),
3957 ('i', 'id', None, _('show global revision id')),
3956 ('i', 'id', None, _('show global revision id')),
3958 ('b', 'branch', None, _('show branch')),
3957 ('b', 'branch', None, _('show branch')),
3959 ('t', 'tags', None, _('show tags')),
3958 ('t', 'tags', None, _('show tags')),
3960 ('B', 'bookmarks', None, _('show bookmarks')),
3959 ('B', 'bookmarks', None, _('show bookmarks')),
3961 ] + remoteopts,
3960 ] + remoteopts,
3962 _('[-nibtB] [-r REV] [SOURCE]'),
3961 _('[-nibtB] [-r REV] [SOURCE]'),
3963 optionalrepo=True)
3962 optionalrepo=True)
3964 def identify(ui, repo, source=None, rev=None,
3963 def identify(ui, repo, source=None, rev=None,
3965 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3964 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3966 """identify the working directory or specified revision
3965 """identify the working directory or specified revision
3967
3966
3968 Print a summary identifying the repository state at REV using one or
3967 Print a summary identifying the repository state at REV using one or
3969 two parent hash identifiers, followed by a "+" if the working
3968 two parent hash identifiers, followed by a "+" if the working
3970 directory has uncommitted changes, the branch name (if not default),
3969 directory has uncommitted changes, the branch name (if not default),
3971 a list of tags, and a list of bookmarks.
3970 a list of tags, and a list of bookmarks.
3972
3971
3973 When REV is not given, print a summary of the current state of the
3972 When REV is not given, print a summary of the current state of the
3974 repository.
3973 repository.
3975
3974
3976 Specifying a path to a repository root or Mercurial bundle will
3975 Specifying a path to a repository root or Mercurial bundle will
3977 cause lookup to operate on that repository/bundle.
3976 cause lookup to operate on that repository/bundle.
3978
3977
3979 .. container:: verbose
3978 .. container:: verbose
3980
3979
3981 Examples:
3980 Examples:
3982
3981
3983 - generate a build identifier for the working directory::
3982 - generate a build identifier for the working directory::
3984
3983
3985 hg id --id > build-id.dat
3984 hg id --id > build-id.dat
3986
3985
3987 - find the revision corresponding to a tag::
3986 - find the revision corresponding to a tag::
3988
3987
3989 hg id -n -r 1.3
3988 hg id -n -r 1.3
3990
3989
3991 - check the most recent revision of a remote repository::
3990 - check the most recent revision of a remote repository::
3992
3991
3993 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3992 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3994
3993
3995 See :hg:`log` for generating more information about specific revisions,
3994 See :hg:`log` for generating more information about specific revisions,
3996 including full hash identifiers.
3995 including full hash identifiers.
3997
3996
3998 Returns 0 if successful.
3997 Returns 0 if successful.
3999 """
3998 """
4000
3999
4001 if not repo and not source:
4000 if not repo and not source:
4002 raise error.Abort(_("there is no Mercurial repository here "
4001 raise error.Abort(_("there is no Mercurial repository here "
4003 "(.hg not found)"))
4002 "(.hg not found)"))
4004
4003
4005 if ui.debugflag:
4004 if ui.debugflag:
4006 hexfunc = hex
4005 hexfunc = hex
4007 else:
4006 else:
4008 hexfunc = short
4007 hexfunc = short
4009 default = not (num or id or branch or tags or bookmarks)
4008 default = not (num or id or branch or tags or bookmarks)
4010 output = []
4009 output = []
4011 revs = []
4010 revs = []
4012
4011
4013 if source:
4012 if source:
4014 source, branches = hg.parseurl(ui.expandpath(source))
4013 source, branches = hg.parseurl(ui.expandpath(source))
4015 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4014 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4016 repo = peer.local()
4015 repo = peer.local()
4017 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4016 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4018
4017
4019 if not repo:
4018 if not repo:
4020 if num or branch or tags:
4019 if num or branch or tags:
4021 raise error.Abort(
4020 raise error.Abort(
4022 _("can't query remote revision number, branch, or tags"))
4021 _("can't query remote revision number, branch, or tags"))
4023 if not rev and revs:
4022 if not rev and revs:
4024 rev = revs[0]
4023 rev = revs[0]
4025 if not rev:
4024 if not rev:
4026 rev = "tip"
4025 rev = "tip"
4027
4026
4028 remoterev = peer.lookup(rev)
4027 remoterev = peer.lookup(rev)
4029 if default or id:
4028 if default or id:
4030 output = [hexfunc(remoterev)]
4029 output = [hexfunc(remoterev)]
4031
4030
4032 def getbms():
4031 def getbms():
4033 bms = []
4032 bms = []
4034
4033
4035 if 'bookmarks' in peer.listkeys('namespaces'):
4034 if 'bookmarks' in peer.listkeys('namespaces'):
4036 hexremoterev = hex(remoterev)
4035 hexremoterev = hex(remoterev)
4037 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4036 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4038 if bmr == hexremoterev]
4037 if bmr == hexremoterev]
4039
4038
4040 return sorted(bms)
4039 return sorted(bms)
4041
4040
4042 if bookmarks:
4041 if bookmarks:
4043 output.extend(getbms())
4042 output.extend(getbms())
4044 elif default and not ui.quiet:
4043 elif default and not ui.quiet:
4045 # multiple bookmarks for a single parent separated by '/'
4044 # multiple bookmarks for a single parent separated by '/'
4046 bm = '/'.join(getbms())
4045 bm = '/'.join(getbms())
4047 if bm:
4046 if bm:
4048 output.append(bm)
4047 output.append(bm)
4049 else:
4048 else:
4050 ctx = scmutil.revsingle(repo, rev, None)
4049 ctx = scmutil.revsingle(repo, rev, None)
4051
4050
4052 if ctx.rev() is None:
4051 if ctx.rev() is None:
4053 ctx = repo[None]
4052 ctx = repo[None]
4054 parents = ctx.parents()
4053 parents = ctx.parents()
4055 taglist = []
4054 taglist = []
4056 for p in parents:
4055 for p in parents:
4057 taglist.extend(p.tags())
4056 taglist.extend(p.tags())
4058
4057
4059 changed = ""
4058 changed = ""
4060 if default or id or num:
4059 if default or id or num:
4061 if (any(repo.status())
4060 if (any(repo.status())
4062 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4061 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4063 changed = '+'
4062 changed = '+'
4064 if default or id:
4063 if default or id:
4065 output = ["%s%s" %
4064 output = ["%s%s" %
4066 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4065 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4067 if num:
4066 if num:
4068 output.append("%s%s" %
4067 output.append("%s%s" %
4069 ('+'.join([str(p.rev()) for p in parents]), changed))
4068 ('+'.join([str(p.rev()) for p in parents]), changed))
4070 else:
4069 else:
4071 if default or id:
4070 if default or id:
4072 output = [hexfunc(ctx.node())]
4071 output = [hexfunc(ctx.node())]
4073 if num:
4072 if num:
4074 output.append(str(ctx.rev()))
4073 output.append(str(ctx.rev()))
4075 taglist = ctx.tags()
4074 taglist = ctx.tags()
4076
4075
4077 if default and not ui.quiet:
4076 if default and not ui.quiet:
4078 b = ctx.branch()
4077 b = ctx.branch()
4079 if b != 'default':
4078 if b != 'default':
4080 output.append("(%s)" % b)
4079 output.append("(%s)" % b)
4081
4080
4082 # multiple tags for a single parent separated by '/'
4081 # multiple tags for a single parent separated by '/'
4083 t = '/'.join(taglist)
4082 t = '/'.join(taglist)
4084 if t:
4083 if t:
4085 output.append(t)
4084 output.append(t)
4086
4085
4087 # multiple bookmarks for a single parent separated by '/'
4086 # multiple bookmarks for a single parent separated by '/'
4088 bm = '/'.join(ctx.bookmarks())
4087 bm = '/'.join(ctx.bookmarks())
4089 if bm:
4088 if bm:
4090 output.append(bm)
4089 output.append(bm)
4091 else:
4090 else:
4092 if branch:
4091 if branch:
4093 output.append(ctx.branch())
4092 output.append(ctx.branch())
4094
4093
4095 if tags:
4094 if tags:
4096 output.extend(taglist)
4095 output.extend(taglist)
4097
4096
4098 if bookmarks:
4097 if bookmarks:
4099 output.extend(ctx.bookmarks())
4098 output.extend(ctx.bookmarks())
4100
4099
4101 ui.write("%s\n" % ' '.join(output))
4100 ui.write("%s\n" % ' '.join(output))
4102
4101
4103 @command('import|patch',
4102 @command('import|patch',
4104 [('p', 'strip', 1,
4103 [('p', 'strip', 1,
4105 _('directory strip option for patch. This has the same '
4104 _('directory strip option for patch. This has the same '
4106 'meaning as the corresponding patch option'), _('NUM')),
4105 'meaning as the corresponding patch option'), _('NUM')),
4107 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4106 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4108 ('e', 'edit', False, _('invoke editor on commit messages')),
4107 ('e', 'edit', False, _('invoke editor on commit messages')),
4109 ('f', 'force', None,
4108 ('f', 'force', None,
4110 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4109 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4111 ('', 'no-commit', None,
4110 ('', 'no-commit', None,
4112 _("don't commit, just update the working directory")),
4111 _("don't commit, just update the working directory")),
4113 ('', 'bypass', None,
4112 ('', 'bypass', None,
4114 _("apply patch without touching the working directory")),
4113 _("apply patch without touching the working directory")),
4115 ('', 'partial', None,
4114 ('', 'partial', None,
4116 _('commit even if some hunks fail')),
4115 _('commit even if some hunks fail')),
4117 ('', 'exact', None,
4116 ('', 'exact', None,
4118 _('abort if patch would apply lossily')),
4117 _('abort if patch would apply lossily')),
4119 ('', 'prefix', '',
4118 ('', 'prefix', '',
4120 _('apply patch to subdirectory'), _('DIR')),
4119 _('apply patch to subdirectory'), _('DIR')),
4121 ('', 'import-branch', None,
4120 ('', 'import-branch', None,
4122 _('use any branch information in patch (implied by --exact)'))] +
4121 _('use any branch information in patch (implied by --exact)'))] +
4123 commitopts + commitopts2 + similarityopts,
4122 commitopts + commitopts2 + similarityopts,
4124 _('[OPTION]... PATCH...'))
4123 _('[OPTION]... PATCH...'))
4125 def import_(ui, repo, patch1=None, *patches, **opts):
4124 def import_(ui, repo, patch1=None, *patches, **opts):
4126 """import an ordered set of patches
4125 """import an ordered set of patches
4127
4126
4128 Import a list of patches and commit them individually (unless
4127 Import a list of patches and commit them individually (unless
4129 --no-commit is specified).
4128 --no-commit is specified).
4130
4129
4131 To read a patch from standard input, use "-" as the patch name. If
4130 To read a patch from standard input, use "-" as the patch name. If
4132 a URL is specified, the patch will be downloaded from there.
4131 a URL is specified, the patch will be downloaded from there.
4133
4132
4134 Import first applies changes to the working directory (unless
4133 Import first applies changes to the working directory (unless
4135 --bypass is specified), import will abort if there are outstanding
4134 --bypass is specified), import will abort if there are outstanding
4136 changes.
4135 changes.
4137
4136
4138 Use --bypass to apply and commit patches directly to the
4137 Use --bypass to apply and commit patches directly to the
4139 repository, without affecting the working directory. Without
4138 repository, without affecting the working directory. Without
4140 --exact, patches will be applied on top of the working directory
4139 --exact, patches will be applied on top of the working directory
4141 parent revision.
4140 parent revision.
4142
4141
4143 You can import a patch straight from a mail message. Even patches
4142 You can import a patch straight from a mail message. Even patches
4144 as attachments work (to use the body part, it must have type
4143 as attachments work (to use the body part, it must have type
4145 text/plain or text/x-patch). From and Subject headers of email
4144 text/plain or text/x-patch). From and Subject headers of email
4146 message are used as default committer and commit message. All
4145 message are used as default committer and commit message. All
4147 text/plain body parts before first diff are added to the commit
4146 text/plain body parts before first diff are added to the commit
4148 message.
4147 message.
4149
4148
4150 If the imported patch was generated by :hg:`export`, user and
4149 If the imported patch was generated by :hg:`export`, user and
4151 description from patch override values from message headers and
4150 description from patch override values from message headers and
4152 body. Values given on command line with -m/--message and -u/--user
4151 body. Values given on command line with -m/--message and -u/--user
4153 override these.
4152 override these.
4154
4153
4155 If --exact is specified, import will set the working directory to
4154 If --exact is specified, import will set the working directory to
4156 the parent of each patch before applying it, and will abort if the
4155 the parent of each patch before applying it, and will abort if the
4157 resulting changeset has a different ID than the one recorded in
4156 resulting changeset has a different ID than the one recorded in
4158 the patch. This will guard against various ways that portable
4157 the patch. This will guard against various ways that portable
4159 patch formats and mail systems might fail to transfer Mercurial
4158 patch formats and mail systems might fail to transfer Mercurial
4160 data or metadata. See :hg:`bundle` for lossless transmission.
4159 data or metadata. See :hg:`bundle` for lossless transmission.
4161
4160
4162 Use --partial to ensure a changeset will be created from the patch
4161 Use --partial to ensure a changeset will be created from the patch
4163 even if some hunks fail to apply. Hunks that fail to apply will be
4162 even if some hunks fail to apply. Hunks that fail to apply will be
4164 written to a <target-file>.rej file. Conflicts can then be resolved
4163 written to a <target-file>.rej file. Conflicts can then be resolved
4165 by hand before :hg:`commit --amend` is run to update the created
4164 by hand before :hg:`commit --amend` is run to update the created
4166 changeset. This flag exists to let people import patches that
4165 changeset. This flag exists to let people import patches that
4167 partially apply without losing the associated metadata (author,
4166 partially apply without losing the associated metadata (author,
4168 date, description, ...).
4167 date, description, ...).
4169
4168
4170 .. note::
4169 .. note::
4171
4170
4172 When no hunks apply cleanly, :hg:`import --partial` will create
4171 When no hunks apply cleanly, :hg:`import --partial` will create
4173 an empty changeset, importing only the patch metadata.
4172 an empty changeset, importing only the patch metadata.
4174
4173
4175 With -s/--similarity, hg will attempt to discover renames and
4174 With -s/--similarity, hg will attempt to discover renames and
4176 copies in the patch in the same way as :hg:`addremove`.
4175 copies in the patch in the same way as :hg:`addremove`.
4177
4176
4178 It is possible to use external patch programs to perform the patch
4177 It is possible to use external patch programs to perform the patch
4179 by setting the ``ui.patch`` configuration option. For the default
4178 by setting the ``ui.patch`` configuration option. For the default
4180 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4179 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4181 See :hg:`help config` for more information about configuration
4180 See :hg:`help config` for more information about configuration
4182 files and how to use these options.
4181 files and how to use these options.
4183
4182
4184 See :hg:`help dates` for a list of formats valid for -d/--date.
4183 See :hg:`help dates` for a list of formats valid for -d/--date.
4185
4184
4186 .. container:: verbose
4185 .. container:: verbose
4187
4186
4188 Examples:
4187 Examples:
4189
4188
4190 - import a traditional patch from a website and detect renames::
4189 - import a traditional patch from a website and detect renames::
4191
4190
4192 hg import -s 80 http://example.com/bugfix.patch
4191 hg import -s 80 http://example.com/bugfix.patch
4193
4192
4194 - import a changeset from an hgweb server::
4193 - import a changeset from an hgweb server::
4195
4194
4196 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4195 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4197
4196
4198 - import all the patches in an Unix-style mbox::
4197 - import all the patches in an Unix-style mbox::
4199
4198
4200 hg import incoming-patches.mbox
4199 hg import incoming-patches.mbox
4201
4200
4202 - attempt to exactly restore an exported changeset (not always
4201 - attempt to exactly restore an exported changeset (not always
4203 possible)::
4202 possible)::
4204
4203
4205 hg import --exact proposed-fix.patch
4204 hg import --exact proposed-fix.patch
4206
4205
4207 - use an external tool to apply a patch which is too fuzzy for
4206 - use an external tool to apply a patch which is too fuzzy for
4208 the default internal tool.
4207 the default internal tool.
4209
4208
4210 hg import --config ui.patch="patch --merge" fuzzy.patch
4209 hg import --config ui.patch="patch --merge" fuzzy.patch
4211
4210
4212 - change the default fuzzing from 2 to a less strict 7
4211 - change the default fuzzing from 2 to a less strict 7
4213
4212
4214 hg import --config ui.fuzz=7 fuzz.patch
4213 hg import --config ui.fuzz=7 fuzz.patch
4215
4214
4216 Returns 0 on success, 1 on partial success (see --partial).
4215 Returns 0 on success, 1 on partial success (see --partial).
4217 """
4216 """
4218
4217
4219 if not patch1:
4218 if not patch1:
4220 raise error.Abort(_('need at least one patch to import'))
4219 raise error.Abort(_('need at least one patch to import'))
4221
4220
4222 patches = (patch1,) + patches
4221 patches = (patch1,) + patches
4223
4222
4224 date = opts.get('date')
4223 date = opts.get('date')
4225 if date:
4224 if date:
4226 opts['date'] = util.parsedate(date)
4225 opts['date'] = util.parsedate(date)
4227
4226
4228 exact = opts.get('exact')
4227 exact = opts.get('exact')
4229 update = not opts.get('bypass')
4228 update = not opts.get('bypass')
4230 if not update and opts.get('no_commit'):
4229 if not update and opts.get('no_commit'):
4231 raise error.Abort(_('cannot use --no-commit with --bypass'))
4230 raise error.Abort(_('cannot use --no-commit with --bypass'))
4232 try:
4231 try:
4233 sim = float(opts.get('similarity') or 0)
4232 sim = float(opts.get('similarity') or 0)
4234 except ValueError:
4233 except ValueError:
4235 raise error.Abort(_('similarity must be a number'))
4234 raise error.Abort(_('similarity must be a number'))
4236 if sim < 0 or sim > 100:
4235 if sim < 0 or sim > 100:
4237 raise error.Abort(_('similarity must be between 0 and 100'))
4236 raise error.Abort(_('similarity must be between 0 and 100'))
4238 if sim and not update:
4237 if sim and not update:
4239 raise error.Abort(_('cannot use --similarity with --bypass'))
4238 raise error.Abort(_('cannot use --similarity with --bypass'))
4240 if exact:
4239 if exact:
4241 if opts.get('edit'):
4240 if opts.get('edit'):
4242 raise error.Abort(_('cannot use --exact with --edit'))
4241 raise error.Abort(_('cannot use --exact with --edit'))
4243 if opts.get('prefix'):
4242 if opts.get('prefix'):
4244 raise error.Abort(_('cannot use --exact with --prefix'))
4243 raise error.Abort(_('cannot use --exact with --prefix'))
4245
4244
4246 base = opts["base"]
4245 base = opts["base"]
4247 wlock = dsguard = lock = tr = None
4246 wlock = dsguard = lock = tr = None
4248 msgs = []
4247 msgs = []
4249 ret = 0
4248 ret = 0
4250
4249
4251
4250
4252 try:
4251 try:
4253 wlock = repo.wlock()
4252 wlock = repo.wlock()
4254
4253
4255 if update:
4254 if update:
4256 cmdutil.checkunfinished(repo)
4255 cmdutil.checkunfinished(repo)
4257 if (exact or not opts.get('force')):
4256 if (exact or not opts.get('force')):
4258 cmdutil.bailifchanged(repo)
4257 cmdutil.bailifchanged(repo)
4259
4258
4260 if not opts.get('no_commit'):
4259 if not opts.get('no_commit'):
4261 lock = repo.lock()
4260 lock = repo.lock()
4262 tr = repo.transaction('import')
4261 tr = repo.transaction('import')
4263 else:
4262 else:
4264 dsguard = dirstateguard.dirstateguard(repo, 'import')
4263 dsguard = dirstateguard.dirstateguard(repo, 'import')
4265 parents = repo[None].parents()
4264 parents = repo[None].parents()
4266 for patchurl in patches:
4265 for patchurl in patches:
4267 if patchurl == '-':
4266 if patchurl == '-':
4268 ui.status(_('applying patch from stdin\n'))
4267 ui.status(_('applying patch from stdin\n'))
4269 patchfile = ui.fin
4268 patchfile = ui.fin
4270 patchurl = 'stdin' # for error message
4269 patchurl = 'stdin' # for error message
4271 else:
4270 else:
4272 patchurl = os.path.join(base, patchurl)
4271 patchurl = os.path.join(base, patchurl)
4273 ui.status(_('applying %s\n') % patchurl)
4272 ui.status(_('applying %s\n') % patchurl)
4274 patchfile = hg.openpath(ui, patchurl)
4273 patchfile = hg.openpath(ui, patchurl)
4275
4274
4276 haspatch = False
4275 haspatch = False
4277 for hunk in patch.split(patchfile):
4276 for hunk in patch.split(patchfile):
4278 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4277 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4279 parents, opts,
4278 parents, opts,
4280 msgs, hg.clean)
4279 msgs, hg.clean)
4281 if msg:
4280 if msg:
4282 haspatch = True
4281 haspatch = True
4283 ui.note(msg + '\n')
4282 ui.note(msg + '\n')
4284 if update or exact:
4283 if update or exact:
4285 parents = repo[None].parents()
4284 parents = repo[None].parents()
4286 else:
4285 else:
4287 parents = [repo[node]]
4286 parents = [repo[node]]
4288 if rej:
4287 if rej:
4289 ui.write_err(_("patch applied partially\n"))
4288 ui.write_err(_("patch applied partially\n"))
4290 ui.write_err(_("(fix the .rej files and run "
4289 ui.write_err(_("(fix the .rej files and run "
4291 "`hg commit --amend`)\n"))
4290 "`hg commit --amend`)\n"))
4292 ret = 1
4291 ret = 1
4293 break
4292 break
4294
4293
4295 if not haspatch:
4294 if not haspatch:
4296 raise error.Abort(_('%s: no diffs found') % patchurl)
4295 raise error.Abort(_('%s: no diffs found') % patchurl)
4297
4296
4298 if tr:
4297 if tr:
4299 tr.close()
4298 tr.close()
4300 if msgs:
4299 if msgs:
4301 repo.savecommitmessage('\n* * *\n'.join(msgs))
4300 repo.savecommitmessage('\n* * *\n'.join(msgs))
4302 if dsguard:
4301 if dsguard:
4303 dsguard.close()
4302 dsguard.close()
4304 return ret
4303 return ret
4305 finally:
4304 finally:
4306 if tr:
4305 if tr:
4307 tr.release()
4306 tr.release()
4308 release(lock, dsguard, wlock)
4307 release(lock, dsguard, wlock)
4309
4308
4310 @command('incoming|in',
4309 @command('incoming|in',
4311 [('f', 'force', None,
4310 [('f', 'force', None,
4312 _('run even if remote repository is unrelated')),
4311 _('run even if remote repository is unrelated')),
4313 ('n', 'newest-first', None, _('show newest record first')),
4312 ('n', 'newest-first', None, _('show newest record first')),
4314 ('', 'bundle', '',
4313 ('', 'bundle', '',
4315 _('file to store the bundles into'), _('FILE')),
4314 _('file to store the bundles into'), _('FILE')),
4316 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4315 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4317 ('B', 'bookmarks', False, _("compare bookmarks")),
4316 ('B', 'bookmarks', False, _("compare bookmarks")),
4318 ('b', 'branch', [],
4317 ('b', 'branch', [],
4319 _('a specific branch you would like to pull'), _('BRANCH')),
4318 _('a specific branch you would like to pull'), _('BRANCH')),
4320 ] + logopts + remoteopts + subrepoopts,
4319 ] + logopts + remoteopts + subrepoopts,
4321 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4320 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4322 def incoming(ui, repo, source="default", **opts):
4321 def incoming(ui, repo, source="default", **opts):
4323 """show new changesets found in source
4322 """show new changesets found in source
4324
4323
4325 Show new changesets found in the specified path/URL or the default
4324 Show new changesets found in the specified path/URL or the default
4326 pull location. These are the changesets that would have been pulled
4325 pull location. These are the changesets that would have been pulled
4327 if a pull at the time you issued this command.
4326 if a pull at the time you issued this command.
4328
4327
4329 See pull for valid source format details.
4328 See pull for valid source format details.
4330
4329
4331 .. container:: verbose
4330 .. container:: verbose
4332
4331
4333 With -B/--bookmarks, the result of bookmark comparison between
4332 With -B/--bookmarks, the result of bookmark comparison between
4334 local and remote repositories is displayed. With -v/--verbose,
4333 local and remote repositories is displayed. With -v/--verbose,
4335 status is also displayed for each bookmark like below::
4334 status is also displayed for each bookmark like below::
4336
4335
4337 BM1 01234567890a added
4336 BM1 01234567890a added
4338 BM2 1234567890ab advanced
4337 BM2 1234567890ab advanced
4339 BM3 234567890abc diverged
4338 BM3 234567890abc diverged
4340 BM4 34567890abcd changed
4339 BM4 34567890abcd changed
4341
4340
4342 The action taken locally when pulling depends on the
4341 The action taken locally when pulling depends on the
4343 status of each bookmark:
4342 status of each bookmark:
4344
4343
4345 :``added``: pull will create it
4344 :``added``: pull will create it
4346 :``advanced``: pull will update it
4345 :``advanced``: pull will update it
4347 :``diverged``: pull will create a divergent bookmark
4346 :``diverged``: pull will create a divergent bookmark
4348 :``changed``: result depends on remote changesets
4347 :``changed``: result depends on remote changesets
4349
4348
4350 From the point of view of pulling behavior, bookmark
4349 From the point of view of pulling behavior, bookmark
4351 existing only in the remote repository are treated as ``added``,
4350 existing only in the remote repository are treated as ``added``,
4352 even if it is in fact locally deleted.
4351 even if it is in fact locally deleted.
4353
4352
4354 .. container:: verbose
4353 .. container:: verbose
4355
4354
4356 For remote repository, using --bundle avoids downloading the
4355 For remote repository, using --bundle avoids downloading the
4357 changesets twice if the incoming is followed by a pull.
4356 changesets twice if the incoming is followed by a pull.
4358
4357
4359 Examples:
4358 Examples:
4360
4359
4361 - show incoming changes with patches and full description::
4360 - show incoming changes with patches and full description::
4362
4361
4363 hg incoming -vp
4362 hg incoming -vp
4364
4363
4365 - show incoming changes excluding merges, store a bundle::
4364 - show incoming changes excluding merges, store a bundle::
4366
4365
4367 hg in -vpM --bundle incoming.hg
4366 hg in -vpM --bundle incoming.hg
4368 hg pull incoming.hg
4367 hg pull incoming.hg
4369
4368
4370 - briefly list changes inside a bundle::
4369 - briefly list changes inside a bundle::
4371
4370
4372 hg in changes.hg -T "{desc|firstline}\\n"
4371 hg in changes.hg -T "{desc|firstline}\\n"
4373
4372
4374 Returns 0 if there are incoming changes, 1 otherwise.
4373 Returns 0 if there are incoming changes, 1 otherwise.
4375 """
4374 """
4376 if opts.get('graph'):
4375 if opts.get('graph'):
4377 cmdutil.checkunsupportedgraphflags([], opts)
4376 cmdutil.checkunsupportedgraphflags([], opts)
4378 def display(other, chlist, displayer):
4377 def display(other, chlist, displayer):
4379 revdag = cmdutil.graphrevs(other, chlist, opts)
4378 revdag = cmdutil.graphrevs(other, chlist, opts)
4380 cmdutil.displaygraph(ui, repo, revdag, displayer,
4379 cmdutil.displaygraph(ui, repo, revdag, displayer,
4381 graphmod.asciiedges)
4380 graphmod.asciiedges)
4382
4381
4383 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4382 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4384 return 0
4383 return 0
4385
4384
4386 if opts.get('bundle') and opts.get('subrepos'):
4385 if opts.get('bundle') and opts.get('subrepos'):
4387 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4386 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4388
4387
4389 if opts.get('bookmarks'):
4388 if opts.get('bookmarks'):
4390 source, branches = hg.parseurl(ui.expandpath(source),
4389 source, branches = hg.parseurl(ui.expandpath(source),
4391 opts.get('branch'))
4390 opts.get('branch'))
4392 other = hg.peer(repo, opts, source)
4391 other = hg.peer(repo, opts, source)
4393 if 'bookmarks' not in other.listkeys('namespaces'):
4392 if 'bookmarks' not in other.listkeys('namespaces'):
4394 ui.warn(_("remote doesn't support bookmarks\n"))
4393 ui.warn(_("remote doesn't support bookmarks\n"))
4395 return 0
4394 return 0
4396 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4395 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4397 return bookmarks.incoming(ui, repo, other)
4396 return bookmarks.incoming(ui, repo, other)
4398
4397
4399 repo._subtoppath = ui.expandpath(source)
4398 repo._subtoppath = ui.expandpath(source)
4400 try:
4399 try:
4401 return hg.incoming(ui, repo, source, opts)
4400 return hg.incoming(ui, repo, source, opts)
4402 finally:
4401 finally:
4403 del repo._subtoppath
4402 del repo._subtoppath
4404
4403
4405
4404
4406 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4405 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4407 norepo=True)
4406 norepo=True)
4408 def init(ui, dest=".", **opts):
4407 def init(ui, dest=".", **opts):
4409 """create a new repository in the given directory
4408 """create a new repository in the given directory
4410
4409
4411 Initialize a new repository in the given directory. If the given
4410 Initialize a new repository in the given directory. If the given
4412 directory does not exist, it will be created.
4411 directory does not exist, it will be created.
4413
4412
4414 If no directory is given, the current directory is used.
4413 If no directory is given, the current directory is used.
4415
4414
4416 It is possible to specify an ``ssh://`` URL as the destination.
4415 It is possible to specify an ``ssh://`` URL as the destination.
4417 See :hg:`help urls` for more information.
4416 See :hg:`help urls` for more information.
4418
4417
4419 Returns 0 on success.
4418 Returns 0 on success.
4420 """
4419 """
4421 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4420 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4422
4421
4423 @command('locate',
4422 @command('locate',
4424 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4423 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4425 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4424 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4426 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4425 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4427 ] + walkopts,
4426 ] + walkopts,
4428 _('[OPTION]... [PATTERN]...'))
4427 _('[OPTION]... [PATTERN]...'))
4429 def locate(ui, repo, *pats, **opts):
4428 def locate(ui, repo, *pats, **opts):
4430 """locate files matching specific patterns (DEPRECATED)
4429 """locate files matching specific patterns (DEPRECATED)
4431
4430
4432 Print files under Mercurial control in the working directory whose
4431 Print files under Mercurial control in the working directory whose
4433 names match the given patterns.
4432 names match the given patterns.
4434
4433
4435 By default, this command searches all directories in the working
4434 By default, this command searches all directories in the working
4436 directory. To search just the current directory and its
4435 directory. To search just the current directory and its
4437 subdirectories, use "--include .".
4436 subdirectories, use "--include .".
4438
4437
4439 If no patterns are given to match, this command prints the names
4438 If no patterns are given to match, this command prints the names
4440 of all files under Mercurial control in the working directory.
4439 of all files under Mercurial control in the working directory.
4441
4440
4442 If you want to feed the output of this command into the "xargs"
4441 If you want to feed the output of this command into the "xargs"
4443 command, use the -0 option to both this command and "xargs". This
4442 command, use the -0 option to both this command and "xargs". This
4444 will avoid the problem of "xargs" treating single filenames that
4443 will avoid the problem of "xargs" treating single filenames that
4445 contain whitespace as multiple filenames.
4444 contain whitespace as multiple filenames.
4446
4445
4447 See :hg:`help files` for a more versatile command.
4446 See :hg:`help files` for a more versatile command.
4448
4447
4449 Returns 0 if a match is found, 1 otherwise.
4448 Returns 0 if a match is found, 1 otherwise.
4450 """
4449 """
4451 if opts.get('print0'):
4450 if opts.get('print0'):
4452 end = '\0'
4451 end = '\0'
4453 else:
4452 else:
4454 end = '\n'
4453 end = '\n'
4455 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4454 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4456
4455
4457 ret = 1
4456 ret = 1
4458 ctx = repo[rev]
4457 ctx = repo[rev]
4459 m = scmutil.match(ctx, pats, opts, default='relglob',
4458 m = scmutil.match(ctx, pats, opts, default='relglob',
4460 badfn=lambda x, y: False)
4459 badfn=lambda x, y: False)
4461
4460
4462 for abs in ctx.matches(m):
4461 for abs in ctx.matches(m):
4463 if opts.get('fullpath'):
4462 if opts.get('fullpath'):
4464 ui.write(repo.wjoin(abs), end)
4463 ui.write(repo.wjoin(abs), end)
4465 else:
4464 else:
4466 ui.write(((pats and m.rel(abs)) or abs), end)
4465 ui.write(((pats and m.rel(abs)) or abs), end)
4467 ret = 0
4466 ret = 0
4468
4467
4469 return ret
4468 return ret
4470
4469
4471 @command('^log|history',
4470 @command('^log|history',
4472 [('f', 'follow', None,
4471 [('f', 'follow', None,
4473 _('follow changeset history, or file history across copies and renames')),
4472 _('follow changeset history, or file history across copies and renames')),
4474 ('', 'follow-first', None,
4473 ('', 'follow-first', None,
4475 _('only follow the first parent of merge changesets (DEPRECATED)')),
4474 _('only follow the first parent of merge changesets (DEPRECATED)')),
4476 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4475 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4477 ('C', 'copies', None, _('show copied files')),
4476 ('C', 'copies', None, _('show copied files')),
4478 ('k', 'keyword', [],
4477 ('k', 'keyword', [],
4479 _('do case-insensitive search for a given text'), _('TEXT')),
4478 _('do case-insensitive search for a given text'), _('TEXT')),
4480 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4479 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4481 ('', 'removed', None, _('include revisions where files were removed')),
4480 ('', 'removed', None, _('include revisions where files were removed')),
4482 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4481 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4483 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4482 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4484 ('', 'only-branch', [],
4483 ('', 'only-branch', [],
4485 _('show only changesets within the given named branch (DEPRECATED)'),
4484 _('show only changesets within the given named branch (DEPRECATED)'),
4486 _('BRANCH')),
4485 _('BRANCH')),
4487 ('b', 'branch', [],
4486 ('b', 'branch', [],
4488 _('show changesets within the given named branch'), _('BRANCH')),
4487 _('show changesets within the given named branch'), _('BRANCH')),
4489 ('P', 'prune', [],
4488 ('P', 'prune', [],
4490 _('do not display revision or any of its ancestors'), _('REV')),
4489 _('do not display revision or any of its ancestors'), _('REV')),
4491 ] + logopts + walkopts,
4490 ] + logopts + walkopts,
4492 _('[OPTION]... [FILE]'),
4491 _('[OPTION]... [FILE]'),
4493 inferrepo=True)
4492 inferrepo=True)
4494 def log(ui, repo, *pats, **opts):
4493 def log(ui, repo, *pats, **opts):
4495 """show revision history of entire repository or files
4494 """show revision history of entire repository or files
4496
4495
4497 Print the revision history of the specified files or the entire
4496 Print the revision history of the specified files or the entire
4498 project.
4497 project.
4499
4498
4500 If no revision range is specified, the default is ``tip:0`` unless
4499 If no revision range is specified, the default is ``tip:0`` unless
4501 --follow is set, in which case the working directory parent is
4500 --follow is set, in which case the working directory parent is
4502 used as the starting revision.
4501 used as the starting revision.
4503
4502
4504 File history is shown without following rename or copy history of
4503 File history is shown without following rename or copy history of
4505 files. Use -f/--follow with a filename to follow history across
4504 files. Use -f/--follow with a filename to follow history across
4506 renames and copies. --follow without a filename will only show
4505 renames and copies. --follow without a filename will only show
4507 ancestors or descendants of the starting revision.
4506 ancestors or descendants of the starting revision.
4508
4507
4509 By default this command prints revision number and changeset id,
4508 By default this command prints revision number and changeset id,
4510 tags, non-trivial parents, user, date and time, and a summary for
4509 tags, non-trivial parents, user, date and time, and a summary for
4511 each commit. When the -v/--verbose switch is used, the list of
4510 each commit. When the -v/--verbose switch is used, the list of
4512 changed files and full commit message are shown.
4511 changed files and full commit message are shown.
4513
4512
4514 With --graph the revisions are shown as an ASCII art DAG with the most
4513 With --graph the revisions are shown as an ASCII art DAG with the most
4515 recent changeset at the top.
4514 recent changeset at the top.
4516 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4515 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4517 and '+' represents a fork where the changeset from the lines below is a
4516 and '+' represents a fork where the changeset from the lines below is a
4518 parent of the 'o' merge on the same line.
4517 parent of the 'o' merge on the same line.
4519
4518
4520 .. note::
4519 .. note::
4521
4520
4522 :hg:`log --patch` may generate unexpected diff output for merge
4521 :hg:`log --patch` may generate unexpected diff output for merge
4523 changesets, as it will only compare the merge changeset against
4522 changesets, as it will only compare the merge changeset against
4524 its first parent. Also, only files different from BOTH parents
4523 its first parent. Also, only files different from BOTH parents
4525 will appear in files:.
4524 will appear in files:.
4526
4525
4527 .. note::
4526 .. note::
4528
4527
4529 For performance reasons, :hg:`log FILE` may omit duplicate changes
4528 For performance reasons, :hg:`log FILE` may omit duplicate changes
4530 made on branches and will not show removals or mode changes. To
4529 made on branches and will not show removals or mode changes. To
4531 see all such changes, use the --removed switch.
4530 see all such changes, use the --removed switch.
4532
4531
4533 .. container:: verbose
4532 .. container:: verbose
4534
4533
4535 Some examples:
4534 Some examples:
4536
4535
4537 - changesets with full descriptions and file lists::
4536 - changesets with full descriptions and file lists::
4538
4537
4539 hg log -v
4538 hg log -v
4540
4539
4541 - changesets ancestral to the working directory::
4540 - changesets ancestral to the working directory::
4542
4541
4543 hg log -f
4542 hg log -f
4544
4543
4545 - last 10 commits on the current branch::
4544 - last 10 commits on the current branch::
4546
4545
4547 hg log -l 10 -b .
4546 hg log -l 10 -b .
4548
4547
4549 - changesets showing all modifications of a file, including removals::
4548 - changesets showing all modifications of a file, including removals::
4550
4549
4551 hg log --removed file.c
4550 hg log --removed file.c
4552
4551
4553 - all changesets that touch a directory, with diffs, excluding merges::
4552 - all changesets that touch a directory, with diffs, excluding merges::
4554
4553
4555 hg log -Mp lib/
4554 hg log -Mp lib/
4556
4555
4557 - all revision numbers that match a keyword::
4556 - all revision numbers that match a keyword::
4558
4557
4559 hg log -k bug --template "{rev}\\n"
4558 hg log -k bug --template "{rev}\\n"
4560
4559
4561 - the full hash identifier of the working directory parent::
4560 - the full hash identifier of the working directory parent::
4562
4561
4563 hg log -r . --template "{node}\\n"
4562 hg log -r . --template "{node}\\n"
4564
4563
4565 - list available log templates::
4564 - list available log templates::
4566
4565
4567 hg log -T list
4566 hg log -T list
4568
4567
4569 - check if a given changeset is included in a tagged release::
4568 - check if a given changeset is included in a tagged release::
4570
4569
4571 hg log -r "a21ccf and ancestor(1.9)"
4570 hg log -r "a21ccf and ancestor(1.9)"
4572
4571
4573 - find all changesets by some user in a date range::
4572 - find all changesets by some user in a date range::
4574
4573
4575 hg log -k alice -d "may 2008 to jul 2008"
4574 hg log -k alice -d "may 2008 to jul 2008"
4576
4575
4577 - summary of all changesets after the last tag::
4576 - summary of all changesets after the last tag::
4578
4577
4579 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4578 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4580
4579
4581 See :hg:`help dates` for a list of formats valid for -d/--date.
4580 See :hg:`help dates` for a list of formats valid for -d/--date.
4582
4581
4583 See :hg:`help revisions` and :hg:`help revsets` for more about
4582 See :hg:`help revisions` for more about specifying and ordering
4584 specifying and ordering revisions.
4583 revisions.
4585
4584
4586 See :hg:`help templates` for more about pre-packaged styles and
4585 See :hg:`help templates` for more about pre-packaged styles and
4587 specifying custom templates.
4586 specifying custom templates.
4588
4587
4589 Returns 0 on success.
4588 Returns 0 on success.
4590
4589
4591 """
4590 """
4592 if opts.get('follow') and opts.get('rev'):
4591 if opts.get('follow') and opts.get('rev'):
4593 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4592 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4594 del opts['follow']
4593 del opts['follow']
4595
4594
4596 if opts.get('graph'):
4595 if opts.get('graph'):
4597 return cmdutil.graphlog(ui, repo, *pats, **opts)
4596 return cmdutil.graphlog(ui, repo, *pats, **opts)
4598
4597
4599 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4598 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4600 limit = cmdutil.loglimit(opts)
4599 limit = cmdutil.loglimit(opts)
4601 count = 0
4600 count = 0
4602
4601
4603 getrenamed = None
4602 getrenamed = None
4604 if opts.get('copies'):
4603 if opts.get('copies'):
4605 endrev = None
4604 endrev = None
4606 if opts.get('rev'):
4605 if opts.get('rev'):
4607 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4606 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4608 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4607 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4609
4608
4610 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4609 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4611 for rev in revs:
4610 for rev in revs:
4612 if count == limit:
4611 if count == limit:
4613 break
4612 break
4614 ctx = repo[rev]
4613 ctx = repo[rev]
4615 copies = None
4614 copies = None
4616 if getrenamed is not None and rev:
4615 if getrenamed is not None and rev:
4617 copies = []
4616 copies = []
4618 for fn in ctx.files():
4617 for fn in ctx.files():
4619 rename = getrenamed(fn, rev)
4618 rename = getrenamed(fn, rev)
4620 if rename:
4619 if rename:
4621 copies.append((fn, rename[0]))
4620 copies.append((fn, rename[0]))
4622 if filematcher:
4621 if filematcher:
4623 revmatchfn = filematcher(ctx.rev())
4622 revmatchfn = filematcher(ctx.rev())
4624 else:
4623 else:
4625 revmatchfn = None
4624 revmatchfn = None
4626 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4625 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4627 if displayer.flush(ctx):
4626 if displayer.flush(ctx):
4628 count += 1
4627 count += 1
4629
4628
4630 displayer.close()
4629 displayer.close()
4631
4630
4632 @command('manifest',
4631 @command('manifest',
4633 [('r', 'rev', '', _('revision to display'), _('REV')),
4632 [('r', 'rev', '', _('revision to display'), _('REV')),
4634 ('', 'all', False, _("list files from all revisions"))]
4633 ('', 'all', False, _("list files from all revisions"))]
4635 + formatteropts,
4634 + formatteropts,
4636 _('[-r REV]'))
4635 _('[-r REV]'))
4637 def manifest(ui, repo, node=None, rev=None, **opts):
4636 def manifest(ui, repo, node=None, rev=None, **opts):
4638 """output the current or given revision of the project manifest
4637 """output the current or given revision of the project manifest
4639
4638
4640 Print a list of version controlled files for the given revision.
4639 Print a list of version controlled files for the given revision.
4641 If no revision is given, the first parent of the working directory
4640 If no revision is given, the first parent of the working directory
4642 is used, or the null revision if no revision is checked out.
4641 is used, or the null revision if no revision is checked out.
4643
4642
4644 With -v, print file permissions, symlink and executable bits.
4643 With -v, print file permissions, symlink and executable bits.
4645 With --debug, print file revision hashes.
4644 With --debug, print file revision hashes.
4646
4645
4647 If option --all is specified, the list of all files from all revisions
4646 If option --all is specified, the list of all files from all revisions
4648 is printed. This includes deleted and renamed files.
4647 is printed. This includes deleted and renamed files.
4649
4648
4650 Returns 0 on success.
4649 Returns 0 on success.
4651 """
4650 """
4652
4651
4653 fm = ui.formatter('manifest', opts)
4652 fm = ui.formatter('manifest', opts)
4654
4653
4655 if opts.get('all'):
4654 if opts.get('all'):
4656 if rev or node:
4655 if rev or node:
4657 raise error.Abort(_("can't specify a revision with --all"))
4656 raise error.Abort(_("can't specify a revision with --all"))
4658
4657
4659 res = []
4658 res = []
4660 prefix = "data/"
4659 prefix = "data/"
4661 suffix = ".i"
4660 suffix = ".i"
4662 plen = len(prefix)
4661 plen = len(prefix)
4663 slen = len(suffix)
4662 slen = len(suffix)
4664 with repo.lock():
4663 with repo.lock():
4665 for fn, b, size in repo.store.datafiles():
4664 for fn, b, size in repo.store.datafiles():
4666 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4665 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4667 res.append(fn[plen:-slen])
4666 res.append(fn[plen:-slen])
4668 for f in res:
4667 for f in res:
4669 fm.startitem()
4668 fm.startitem()
4670 fm.write("path", '%s\n', f)
4669 fm.write("path", '%s\n', f)
4671 fm.end()
4670 fm.end()
4672 return
4671 return
4673
4672
4674 if rev and node:
4673 if rev and node:
4675 raise error.Abort(_("please specify just one revision"))
4674 raise error.Abort(_("please specify just one revision"))
4676
4675
4677 if not node:
4676 if not node:
4678 node = rev
4677 node = rev
4679
4678
4680 char = {'l': '@', 'x': '*', '': ''}
4679 char = {'l': '@', 'x': '*', '': ''}
4681 mode = {'l': '644', 'x': '755', '': '644'}
4680 mode = {'l': '644', 'x': '755', '': '644'}
4682 ctx = scmutil.revsingle(repo, node)
4681 ctx = scmutil.revsingle(repo, node)
4683 mf = ctx.manifest()
4682 mf = ctx.manifest()
4684 for f in ctx:
4683 for f in ctx:
4685 fm.startitem()
4684 fm.startitem()
4686 fl = ctx[f].flags()
4685 fl = ctx[f].flags()
4687 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4686 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4688 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4687 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4689 fm.write('path', '%s\n', f)
4688 fm.write('path', '%s\n', f)
4690 fm.end()
4689 fm.end()
4691
4690
4692 @command('^merge',
4691 @command('^merge',
4693 [('f', 'force', None,
4692 [('f', 'force', None,
4694 _('force a merge including outstanding changes (DEPRECATED)')),
4693 _('force a merge including outstanding changes (DEPRECATED)')),
4695 ('r', 'rev', '', _('revision to merge'), _('REV')),
4694 ('r', 'rev', '', _('revision to merge'), _('REV')),
4696 ('P', 'preview', None,
4695 ('P', 'preview', None,
4697 _('review revisions to merge (no merge is performed)'))
4696 _('review revisions to merge (no merge is performed)'))
4698 ] + mergetoolopts,
4697 ] + mergetoolopts,
4699 _('[-P] [[-r] REV]'))
4698 _('[-P] [[-r] REV]'))
4700 def merge(ui, repo, node=None, **opts):
4699 def merge(ui, repo, node=None, **opts):
4701 """merge another revision into working directory
4700 """merge another revision into working directory
4702
4701
4703 The current working directory is updated with all changes made in
4702 The current working directory is updated with all changes made in
4704 the requested revision since the last common predecessor revision.
4703 the requested revision since the last common predecessor revision.
4705
4704
4706 Files that changed between either parent are marked as changed for
4705 Files that changed between either parent are marked as changed for
4707 the next commit and a commit must be performed before any further
4706 the next commit and a commit must be performed before any further
4708 updates to the repository are allowed. The next commit will have
4707 updates to the repository are allowed. The next commit will have
4709 two parents.
4708 two parents.
4710
4709
4711 ``--tool`` can be used to specify the merge tool used for file
4710 ``--tool`` can be used to specify the merge tool used for file
4712 merges. It overrides the HGMERGE environment variable and your
4711 merges. It overrides the HGMERGE environment variable and your
4713 configuration files. See :hg:`help merge-tools` for options.
4712 configuration files. See :hg:`help merge-tools` for options.
4714
4713
4715 If no revision is specified, the working directory's parent is a
4714 If no revision is specified, the working directory's parent is a
4716 head revision, and the current branch contains exactly one other
4715 head revision, and the current branch contains exactly one other
4717 head, the other head is merged with by default. Otherwise, an
4716 head, the other head is merged with by default. Otherwise, an
4718 explicit revision with which to merge with must be provided.
4717 explicit revision with which to merge with must be provided.
4719
4718
4720 See :hg:`help resolve` for information on handling file conflicts.
4719 See :hg:`help resolve` for information on handling file conflicts.
4721
4720
4722 To undo an uncommitted merge, use :hg:`update --clean .` which
4721 To undo an uncommitted merge, use :hg:`update --clean .` which
4723 will check out a clean copy of the original merge parent, losing
4722 will check out a clean copy of the original merge parent, losing
4724 all changes.
4723 all changes.
4725
4724
4726 Returns 0 on success, 1 if there are unresolved files.
4725 Returns 0 on success, 1 if there are unresolved files.
4727 """
4726 """
4728
4727
4729 if opts.get('rev') and node:
4728 if opts.get('rev') and node:
4730 raise error.Abort(_("please specify just one revision"))
4729 raise error.Abort(_("please specify just one revision"))
4731 if not node:
4730 if not node:
4732 node = opts.get('rev')
4731 node = opts.get('rev')
4733
4732
4734 if node:
4733 if node:
4735 node = scmutil.revsingle(repo, node).node()
4734 node = scmutil.revsingle(repo, node).node()
4736
4735
4737 if not node:
4736 if not node:
4738 node = repo[destutil.destmerge(repo)].node()
4737 node = repo[destutil.destmerge(repo)].node()
4739
4738
4740 if opts.get('preview'):
4739 if opts.get('preview'):
4741 # find nodes that are ancestors of p2 but not of p1
4740 # find nodes that are ancestors of p2 but not of p1
4742 p1 = repo.lookup('.')
4741 p1 = repo.lookup('.')
4743 p2 = repo.lookup(node)
4742 p2 = repo.lookup(node)
4744 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4743 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4745
4744
4746 displayer = cmdutil.show_changeset(ui, repo, opts)
4745 displayer = cmdutil.show_changeset(ui, repo, opts)
4747 for node in nodes:
4746 for node in nodes:
4748 displayer.show(repo[node])
4747 displayer.show(repo[node])
4749 displayer.close()
4748 displayer.close()
4750 return 0
4749 return 0
4751
4750
4752 try:
4751 try:
4753 # ui.forcemerge is an internal variable, do not document
4752 # ui.forcemerge is an internal variable, do not document
4754 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4753 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4755 force = opts.get('force')
4754 force = opts.get('force')
4756 labels = ['working copy', 'merge rev']
4755 labels = ['working copy', 'merge rev']
4757 return hg.merge(repo, node, force=force, mergeforce=force,
4756 return hg.merge(repo, node, force=force, mergeforce=force,
4758 labels=labels)
4757 labels=labels)
4759 finally:
4758 finally:
4760 ui.setconfig('ui', 'forcemerge', '', 'merge')
4759 ui.setconfig('ui', 'forcemerge', '', 'merge')
4761
4760
4762 @command('outgoing|out',
4761 @command('outgoing|out',
4763 [('f', 'force', None, _('run even when the destination is unrelated')),
4762 [('f', 'force', None, _('run even when the destination is unrelated')),
4764 ('r', 'rev', [],
4763 ('r', 'rev', [],
4765 _('a changeset intended to be included in the destination'), _('REV')),
4764 _('a changeset intended to be included in the destination'), _('REV')),
4766 ('n', 'newest-first', None, _('show newest record first')),
4765 ('n', 'newest-first', None, _('show newest record first')),
4767 ('B', 'bookmarks', False, _('compare bookmarks')),
4766 ('B', 'bookmarks', False, _('compare bookmarks')),
4768 ('b', 'branch', [], _('a specific branch you would like to push'),
4767 ('b', 'branch', [], _('a specific branch you would like to push'),
4769 _('BRANCH')),
4768 _('BRANCH')),
4770 ] + logopts + remoteopts + subrepoopts,
4769 ] + logopts + remoteopts + subrepoopts,
4771 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4770 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4772 def outgoing(ui, repo, dest=None, **opts):
4771 def outgoing(ui, repo, dest=None, **opts):
4773 """show changesets not found in the destination
4772 """show changesets not found in the destination
4774
4773
4775 Show changesets not found in the specified destination repository
4774 Show changesets not found in the specified destination repository
4776 or the default push location. These are the changesets that would
4775 or the default push location. These are the changesets that would
4777 be pushed if a push was requested.
4776 be pushed if a push was requested.
4778
4777
4779 See pull for details of valid destination formats.
4778 See pull for details of valid destination formats.
4780
4779
4781 .. container:: verbose
4780 .. container:: verbose
4782
4781
4783 With -B/--bookmarks, the result of bookmark comparison between
4782 With -B/--bookmarks, the result of bookmark comparison between
4784 local and remote repositories is displayed. With -v/--verbose,
4783 local and remote repositories is displayed. With -v/--verbose,
4785 status is also displayed for each bookmark like below::
4784 status is also displayed for each bookmark like below::
4786
4785
4787 BM1 01234567890a added
4786 BM1 01234567890a added
4788 BM2 deleted
4787 BM2 deleted
4789 BM3 234567890abc advanced
4788 BM3 234567890abc advanced
4790 BM4 34567890abcd diverged
4789 BM4 34567890abcd diverged
4791 BM5 4567890abcde changed
4790 BM5 4567890abcde changed
4792
4791
4793 The action taken when pushing depends on the
4792 The action taken when pushing depends on the
4794 status of each bookmark:
4793 status of each bookmark:
4795
4794
4796 :``added``: push with ``-B`` will create it
4795 :``added``: push with ``-B`` will create it
4797 :``deleted``: push with ``-B`` will delete it
4796 :``deleted``: push with ``-B`` will delete it
4798 :``advanced``: push will update it
4797 :``advanced``: push will update it
4799 :``diverged``: push with ``-B`` will update it
4798 :``diverged``: push with ``-B`` will update it
4800 :``changed``: push with ``-B`` will update it
4799 :``changed``: push with ``-B`` will update it
4801
4800
4802 From the point of view of pushing behavior, bookmarks
4801 From the point of view of pushing behavior, bookmarks
4803 existing only in the remote repository are treated as
4802 existing only in the remote repository are treated as
4804 ``deleted``, even if it is in fact added remotely.
4803 ``deleted``, even if it is in fact added remotely.
4805
4804
4806 Returns 0 if there are outgoing changes, 1 otherwise.
4805 Returns 0 if there are outgoing changes, 1 otherwise.
4807 """
4806 """
4808 if opts.get('graph'):
4807 if opts.get('graph'):
4809 cmdutil.checkunsupportedgraphflags([], opts)
4808 cmdutil.checkunsupportedgraphflags([], opts)
4810 o, other = hg._outgoing(ui, repo, dest, opts)
4809 o, other = hg._outgoing(ui, repo, dest, opts)
4811 if not o:
4810 if not o:
4812 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4811 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4813 return
4812 return
4814
4813
4815 revdag = cmdutil.graphrevs(repo, o, opts)
4814 revdag = cmdutil.graphrevs(repo, o, opts)
4816 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4815 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4817 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4816 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
4818 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4817 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4819 return 0
4818 return 0
4820
4819
4821 if opts.get('bookmarks'):
4820 if opts.get('bookmarks'):
4822 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4821 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4823 dest, branches = hg.parseurl(dest, opts.get('branch'))
4822 dest, branches = hg.parseurl(dest, opts.get('branch'))
4824 other = hg.peer(repo, opts, dest)
4823 other = hg.peer(repo, opts, dest)
4825 if 'bookmarks' not in other.listkeys('namespaces'):
4824 if 'bookmarks' not in other.listkeys('namespaces'):
4826 ui.warn(_("remote doesn't support bookmarks\n"))
4825 ui.warn(_("remote doesn't support bookmarks\n"))
4827 return 0
4826 return 0
4828 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4827 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4829 return bookmarks.outgoing(ui, repo, other)
4828 return bookmarks.outgoing(ui, repo, other)
4830
4829
4831 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4830 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4832 try:
4831 try:
4833 return hg.outgoing(ui, repo, dest, opts)
4832 return hg.outgoing(ui, repo, dest, opts)
4834 finally:
4833 finally:
4835 del repo._subtoppath
4834 del repo._subtoppath
4836
4835
4837 @command('parents',
4836 @command('parents',
4838 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4837 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4839 ] + templateopts,
4838 ] + templateopts,
4840 _('[-r REV] [FILE]'),
4839 _('[-r REV] [FILE]'),
4841 inferrepo=True)
4840 inferrepo=True)
4842 def parents(ui, repo, file_=None, **opts):
4841 def parents(ui, repo, file_=None, **opts):
4843 """show the parents of the working directory or revision (DEPRECATED)
4842 """show the parents of the working directory or revision (DEPRECATED)
4844
4843
4845 Print the working directory's parent revisions. If a revision is
4844 Print the working directory's parent revisions. If a revision is
4846 given via -r/--rev, the parent of that revision will be printed.
4845 given via -r/--rev, the parent of that revision will be printed.
4847 If a file argument is given, the revision in which the file was
4846 If a file argument is given, the revision in which the file was
4848 last changed (before the working directory revision or the
4847 last changed (before the working directory revision or the
4849 argument to --rev if given) is printed.
4848 argument to --rev if given) is printed.
4850
4849
4851 This command is equivalent to::
4850 This command is equivalent to::
4852
4851
4853 hg log -r "p1()+p2()" or
4852 hg log -r "p1()+p2()" or
4854 hg log -r "p1(REV)+p2(REV)" or
4853 hg log -r "p1(REV)+p2(REV)" or
4855 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4854 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4856 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4855 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4857
4856
4858 See :hg:`summary` and :hg:`help revsets` for related information.
4857 See :hg:`summary` and :hg:`help revsets` for related information.
4859
4858
4860 Returns 0 on success.
4859 Returns 0 on success.
4861 """
4860 """
4862
4861
4863 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4862 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4864
4863
4865 if file_:
4864 if file_:
4866 m = scmutil.match(ctx, (file_,), opts)
4865 m = scmutil.match(ctx, (file_,), opts)
4867 if m.anypats() or len(m.files()) != 1:
4866 if m.anypats() or len(m.files()) != 1:
4868 raise error.Abort(_('can only specify an explicit filename'))
4867 raise error.Abort(_('can only specify an explicit filename'))
4869 file_ = m.files()[0]
4868 file_ = m.files()[0]
4870 filenodes = []
4869 filenodes = []
4871 for cp in ctx.parents():
4870 for cp in ctx.parents():
4872 if not cp:
4871 if not cp:
4873 continue
4872 continue
4874 try:
4873 try:
4875 filenodes.append(cp.filenode(file_))
4874 filenodes.append(cp.filenode(file_))
4876 except error.LookupError:
4875 except error.LookupError:
4877 pass
4876 pass
4878 if not filenodes:
4877 if not filenodes:
4879 raise error.Abort(_("'%s' not found in manifest!") % file_)
4878 raise error.Abort(_("'%s' not found in manifest!") % file_)
4880 p = []
4879 p = []
4881 for fn in filenodes:
4880 for fn in filenodes:
4882 fctx = repo.filectx(file_, fileid=fn)
4881 fctx = repo.filectx(file_, fileid=fn)
4883 p.append(fctx.node())
4882 p.append(fctx.node())
4884 else:
4883 else:
4885 p = [cp.node() for cp in ctx.parents()]
4884 p = [cp.node() for cp in ctx.parents()]
4886
4885
4887 displayer = cmdutil.show_changeset(ui, repo, opts)
4886 displayer = cmdutil.show_changeset(ui, repo, opts)
4888 for n in p:
4887 for n in p:
4889 if n != nullid:
4888 if n != nullid:
4890 displayer.show(repo[n])
4889 displayer.show(repo[n])
4891 displayer.close()
4890 displayer.close()
4892
4891
4893 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4892 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
4894 def paths(ui, repo, search=None, **opts):
4893 def paths(ui, repo, search=None, **opts):
4895 """show aliases for remote repositories
4894 """show aliases for remote repositories
4896
4895
4897 Show definition of symbolic path name NAME. If no name is given,
4896 Show definition of symbolic path name NAME. If no name is given,
4898 show definition of all available names.
4897 show definition of all available names.
4899
4898
4900 Option -q/--quiet suppresses all output when searching for NAME
4899 Option -q/--quiet suppresses all output when searching for NAME
4901 and shows only the path names when listing all definitions.
4900 and shows only the path names when listing all definitions.
4902
4901
4903 Path names are defined in the [paths] section of your
4902 Path names are defined in the [paths] section of your
4904 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4903 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4905 repository, ``.hg/hgrc`` is used, too.
4904 repository, ``.hg/hgrc`` is used, too.
4906
4905
4907 The path names ``default`` and ``default-push`` have a special
4906 The path names ``default`` and ``default-push`` have a special
4908 meaning. When performing a push or pull operation, they are used
4907 meaning. When performing a push or pull operation, they are used
4909 as fallbacks if no location is specified on the command-line.
4908 as fallbacks if no location is specified on the command-line.
4910 When ``default-push`` is set, it will be used for push and
4909 When ``default-push`` is set, it will be used for push and
4911 ``default`` will be used for pull; otherwise ``default`` is used
4910 ``default`` will be used for pull; otherwise ``default`` is used
4912 as the fallback for both. When cloning a repository, the clone
4911 as the fallback for both. When cloning a repository, the clone
4913 source is written as ``default`` in ``.hg/hgrc``.
4912 source is written as ``default`` in ``.hg/hgrc``.
4914
4913
4915 .. note::
4914 .. note::
4916
4915
4917 ``default`` and ``default-push`` apply to all inbound (e.g.
4916 ``default`` and ``default-push`` apply to all inbound (e.g.
4918 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4917 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4919 and :hg:`bundle`) operations.
4918 and :hg:`bundle`) operations.
4920
4919
4921 See :hg:`help urls` for more information.
4920 See :hg:`help urls` for more information.
4922
4921
4923 Returns 0 on success.
4922 Returns 0 on success.
4924 """
4923 """
4925 if search:
4924 if search:
4926 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4925 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4927 if name == search]
4926 if name == search]
4928 else:
4927 else:
4929 pathitems = sorted(ui.paths.iteritems())
4928 pathitems = sorted(ui.paths.iteritems())
4930
4929
4931 fm = ui.formatter('paths', opts)
4930 fm = ui.formatter('paths', opts)
4932 if fm.isplain():
4931 if fm.isplain():
4933 hidepassword = util.hidepassword
4932 hidepassword = util.hidepassword
4934 else:
4933 else:
4935 hidepassword = str
4934 hidepassword = str
4936 if ui.quiet:
4935 if ui.quiet:
4937 namefmt = '%s\n'
4936 namefmt = '%s\n'
4938 else:
4937 else:
4939 namefmt = '%s = '
4938 namefmt = '%s = '
4940 showsubopts = not search and not ui.quiet
4939 showsubopts = not search and not ui.quiet
4941
4940
4942 for name, path in pathitems:
4941 for name, path in pathitems:
4943 fm.startitem()
4942 fm.startitem()
4944 fm.condwrite(not search, 'name', namefmt, name)
4943 fm.condwrite(not search, 'name', namefmt, name)
4945 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4944 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4946 for subopt, value in sorted(path.suboptions.items()):
4945 for subopt, value in sorted(path.suboptions.items()):
4947 assert subopt not in ('name', 'url')
4946 assert subopt not in ('name', 'url')
4948 if showsubopts:
4947 if showsubopts:
4949 fm.plain('%s:%s = ' % (name, subopt))
4948 fm.plain('%s:%s = ' % (name, subopt))
4950 fm.condwrite(showsubopts, subopt, '%s\n', value)
4949 fm.condwrite(showsubopts, subopt, '%s\n', value)
4951
4950
4952 fm.end()
4951 fm.end()
4953
4952
4954 if search and not pathitems:
4953 if search and not pathitems:
4955 if not ui.quiet:
4954 if not ui.quiet:
4956 ui.warn(_("not found!\n"))
4955 ui.warn(_("not found!\n"))
4957 return 1
4956 return 1
4958 else:
4957 else:
4959 return 0
4958 return 0
4960
4959
4961 @command('phase',
4960 @command('phase',
4962 [('p', 'public', False, _('set changeset phase to public')),
4961 [('p', 'public', False, _('set changeset phase to public')),
4963 ('d', 'draft', False, _('set changeset phase to draft')),
4962 ('d', 'draft', False, _('set changeset phase to draft')),
4964 ('s', 'secret', False, _('set changeset phase to secret')),
4963 ('s', 'secret', False, _('set changeset phase to secret')),
4965 ('f', 'force', False, _('allow to move boundary backward')),
4964 ('f', 'force', False, _('allow to move boundary backward')),
4966 ('r', 'rev', [], _('target revision'), _('REV')),
4965 ('r', 'rev', [], _('target revision'), _('REV')),
4967 ],
4966 ],
4968 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4967 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4969 def phase(ui, repo, *revs, **opts):
4968 def phase(ui, repo, *revs, **opts):
4970 """set or show the current phase name
4969 """set or show the current phase name
4971
4970
4972 With no argument, show the phase name of the current revision(s).
4971 With no argument, show the phase name of the current revision(s).
4973
4972
4974 With one of -p/--public, -d/--draft or -s/--secret, change the
4973 With one of -p/--public, -d/--draft or -s/--secret, change the
4975 phase value of the specified revisions.
4974 phase value of the specified revisions.
4976
4975
4977 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4976 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4978 lower phase to an higher phase. Phases are ordered as follows::
4977 lower phase to an higher phase. Phases are ordered as follows::
4979
4978
4980 public < draft < secret
4979 public < draft < secret
4981
4980
4982 Returns 0 on success, 1 if some phases could not be changed.
4981 Returns 0 on success, 1 if some phases could not be changed.
4983
4982
4984 (For more information about the phases concept, see :hg:`help phases`.)
4983 (For more information about the phases concept, see :hg:`help phases`.)
4985 """
4984 """
4986 # search for a unique phase argument
4985 # search for a unique phase argument
4987 targetphase = None
4986 targetphase = None
4988 for idx, name in enumerate(phases.phasenames):
4987 for idx, name in enumerate(phases.phasenames):
4989 if opts[name]:
4988 if opts[name]:
4990 if targetphase is not None:
4989 if targetphase is not None:
4991 raise error.Abort(_('only one phase can be specified'))
4990 raise error.Abort(_('only one phase can be specified'))
4992 targetphase = idx
4991 targetphase = idx
4993
4992
4994 # look for specified revision
4993 # look for specified revision
4995 revs = list(revs)
4994 revs = list(revs)
4996 revs.extend(opts['rev'])
4995 revs.extend(opts['rev'])
4997 if not revs:
4996 if not revs:
4998 # display both parents as the second parent phase can influence
4997 # display both parents as the second parent phase can influence
4999 # the phase of a merge commit
4998 # the phase of a merge commit
5000 revs = [c.rev() for c in repo[None].parents()]
4999 revs = [c.rev() for c in repo[None].parents()]
5001
5000
5002 revs = scmutil.revrange(repo, revs)
5001 revs = scmutil.revrange(repo, revs)
5003
5002
5004 lock = None
5003 lock = None
5005 ret = 0
5004 ret = 0
5006 if targetphase is None:
5005 if targetphase is None:
5007 # display
5006 # display
5008 for r in revs:
5007 for r in revs:
5009 ctx = repo[r]
5008 ctx = repo[r]
5010 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5009 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5011 else:
5010 else:
5012 tr = None
5011 tr = None
5013 lock = repo.lock()
5012 lock = repo.lock()
5014 try:
5013 try:
5015 tr = repo.transaction("phase")
5014 tr = repo.transaction("phase")
5016 # set phase
5015 # set phase
5017 if not revs:
5016 if not revs:
5018 raise error.Abort(_('empty revision set'))
5017 raise error.Abort(_('empty revision set'))
5019 nodes = [repo[r].node() for r in revs]
5018 nodes = [repo[r].node() for r in revs]
5020 # moving revision from public to draft may hide them
5019 # moving revision from public to draft may hide them
5021 # We have to check result on an unfiltered repository
5020 # We have to check result on an unfiltered repository
5022 unfi = repo.unfiltered()
5021 unfi = repo.unfiltered()
5023 getphase = unfi._phasecache.phase
5022 getphase = unfi._phasecache.phase
5024 olddata = [getphase(unfi, r) for r in unfi]
5023 olddata = [getphase(unfi, r) for r in unfi]
5025 phases.advanceboundary(repo, tr, targetphase, nodes)
5024 phases.advanceboundary(repo, tr, targetphase, nodes)
5026 if opts['force']:
5025 if opts['force']:
5027 phases.retractboundary(repo, tr, targetphase, nodes)
5026 phases.retractboundary(repo, tr, targetphase, nodes)
5028 tr.close()
5027 tr.close()
5029 finally:
5028 finally:
5030 if tr is not None:
5029 if tr is not None:
5031 tr.release()
5030 tr.release()
5032 lock.release()
5031 lock.release()
5033 getphase = unfi._phasecache.phase
5032 getphase = unfi._phasecache.phase
5034 newdata = [getphase(unfi, r) for r in unfi]
5033 newdata = [getphase(unfi, r) for r in unfi]
5035 changes = sum(newdata[r] != olddata[r] for r in unfi)
5034 changes = sum(newdata[r] != olddata[r] for r in unfi)
5036 cl = unfi.changelog
5035 cl = unfi.changelog
5037 rejected = [n for n in nodes
5036 rejected = [n for n in nodes
5038 if newdata[cl.rev(n)] < targetphase]
5037 if newdata[cl.rev(n)] < targetphase]
5039 if rejected:
5038 if rejected:
5040 ui.warn(_('cannot move %i changesets to a higher '
5039 ui.warn(_('cannot move %i changesets to a higher '
5041 'phase, use --force\n') % len(rejected))
5040 'phase, use --force\n') % len(rejected))
5042 ret = 1
5041 ret = 1
5043 if changes:
5042 if changes:
5044 msg = _('phase changed for %i changesets\n') % changes
5043 msg = _('phase changed for %i changesets\n') % changes
5045 if ret:
5044 if ret:
5046 ui.status(msg)
5045 ui.status(msg)
5047 else:
5046 else:
5048 ui.note(msg)
5047 ui.note(msg)
5049 else:
5048 else:
5050 ui.warn(_('no phases changed\n'))
5049 ui.warn(_('no phases changed\n'))
5051 return ret
5050 return ret
5052
5051
5053 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5052 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5054 """Run after a changegroup has been added via pull/unbundle
5053 """Run after a changegroup has been added via pull/unbundle
5055
5054
5056 This takes arguments below:
5055 This takes arguments below:
5057
5056
5058 :modheads: change of heads by pull/unbundle
5057 :modheads: change of heads by pull/unbundle
5059 :optupdate: updating working directory is needed or not
5058 :optupdate: updating working directory is needed or not
5060 :checkout: update destination revision (or None to default destination)
5059 :checkout: update destination revision (or None to default destination)
5061 :brev: a name, which might be a bookmark to be activated after updating
5060 :brev: a name, which might be a bookmark to be activated after updating
5062 """
5061 """
5063 if modheads == 0:
5062 if modheads == 0:
5064 return
5063 return
5065 if optupdate:
5064 if optupdate:
5066 try:
5065 try:
5067 return hg.updatetotally(ui, repo, checkout, brev)
5066 return hg.updatetotally(ui, repo, checkout, brev)
5068 except error.UpdateAbort as inst:
5067 except error.UpdateAbort as inst:
5069 msg = _("not updating: %s") % str(inst)
5068 msg = _("not updating: %s") % str(inst)
5070 hint = inst.hint
5069 hint = inst.hint
5071 raise error.UpdateAbort(msg, hint=hint)
5070 raise error.UpdateAbort(msg, hint=hint)
5072 if modheads > 1:
5071 if modheads > 1:
5073 currentbranchheads = len(repo.branchheads())
5072 currentbranchheads = len(repo.branchheads())
5074 if currentbranchheads == modheads:
5073 if currentbranchheads == modheads:
5075 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5074 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5076 elif currentbranchheads > 1:
5075 elif currentbranchheads > 1:
5077 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5076 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5078 "merge)\n"))
5077 "merge)\n"))
5079 else:
5078 else:
5080 ui.status(_("(run 'hg heads' to see heads)\n"))
5079 ui.status(_("(run 'hg heads' to see heads)\n"))
5081 else:
5080 else:
5082 ui.status(_("(run 'hg update' to get a working copy)\n"))
5081 ui.status(_("(run 'hg update' to get a working copy)\n"))
5083
5082
5084 @command('^pull',
5083 @command('^pull',
5085 [('u', 'update', None,
5084 [('u', 'update', None,
5086 _('update to new branch head if changesets were pulled')),
5085 _('update to new branch head if changesets were pulled')),
5087 ('f', 'force', None, _('run even when remote repository is unrelated')),
5086 ('f', 'force', None, _('run even when remote repository is unrelated')),
5088 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5087 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5089 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5088 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5090 ('b', 'branch', [], _('a specific branch you would like to pull'),
5089 ('b', 'branch', [], _('a specific branch you would like to pull'),
5091 _('BRANCH')),
5090 _('BRANCH')),
5092 ] + remoteopts,
5091 ] + remoteopts,
5093 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5092 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5094 def pull(ui, repo, source="default", **opts):
5093 def pull(ui, repo, source="default", **opts):
5095 """pull changes from the specified source
5094 """pull changes from the specified source
5096
5095
5097 Pull changes from a remote repository to a local one.
5096 Pull changes from a remote repository to a local one.
5098
5097
5099 This finds all changes from the repository at the specified path
5098 This finds all changes from the repository at the specified path
5100 or URL and adds them to a local repository (the current one unless
5099 or URL and adds them to a local repository (the current one unless
5101 -R is specified). By default, this does not update the copy of the
5100 -R is specified). By default, this does not update the copy of the
5102 project in the working directory.
5101 project in the working directory.
5103
5102
5104 Use :hg:`incoming` if you want to see what would have been added
5103 Use :hg:`incoming` if you want to see what would have been added
5105 by a pull at the time you issued this command. If you then decide
5104 by a pull at the time you issued this command. If you then decide
5106 to add those changes to the repository, you should use :hg:`pull
5105 to add those changes to the repository, you should use :hg:`pull
5107 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5106 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5108
5107
5109 If SOURCE is omitted, the 'default' path will be used.
5108 If SOURCE is omitted, the 'default' path will be used.
5110 See :hg:`help urls` for more information.
5109 See :hg:`help urls` for more information.
5111
5110
5112 Specifying bookmark as ``.`` is equivalent to specifying the active
5111 Specifying bookmark as ``.`` is equivalent to specifying the active
5113 bookmark's name.
5112 bookmark's name.
5114
5113
5115 Returns 0 on success, 1 if an update had unresolved files.
5114 Returns 0 on success, 1 if an update had unresolved files.
5116 """
5115 """
5117 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5116 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5118 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5117 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5119 other = hg.peer(repo, opts, source)
5118 other = hg.peer(repo, opts, source)
5120 try:
5119 try:
5121 revs, checkout = hg.addbranchrevs(repo, other, branches,
5120 revs, checkout = hg.addbranchrevs(repo, other, branches,
5122 opts.get('rev'))
5121 opts.get('rev'))
5123
5122
5124
5123
5125 pullopargs = {}
5124 pullopargs = {}
5126 if opts.get('bookmark'):
5125 if opts.get('bookmark'):
5127 if not revs:
5126 if not revs:
5128 revs = []
5127 revs = []
5129 # The list of bookmark used here is not the one used to actually
5128 # The list of bookmark used here is not the one used to actually
5130 # update the bookmark name. This can result in the revision pulled
5129 # update the bookmark name. This can result in the revision pulled
5131 # not ending up with the name of the bookmark because of a race
5130 # not ending up with the name of the bookmark because of a race
5132 # condition on the server. (See issue 4689 for details)
5131 # condition on the server. (See issue 4689 for details)
5133 remotebookmarks = other.listkeys('bookmarks')
5132 remotebookmarks = other.listkeys('bookmarks')
5134 pullopargs['remotebookmarks'] = remotebookmarks
5133 pullopargs['remotebookmarks'] = remotebookmarks
5135 for b in opts['bookmark']:
5134 for b in opts['bookmark']:
5136 b = repo._bookmarks.expandname(b)
5135 b = repo._bookmarks.expandname(b)
5137 if b not in remotebookmarks:
5136 if b not in remotebookmarks:
5138 raise error.Abort(_('remote bookmark %s not found!') % b)
5137 raise error.Abort(_('remote bookmark %s not found!') % b)
5139 revs.append(remotebookmarks[b])
5138 revs.append(remotebookmarks[b])
5140
5139
5141 if revs:
5140 if revs:
5142 try:
5141 try:
5143 # When 'rev' is a bookmark name, we cannot guarantee that it
5142 # When 'rev' is a bookmark name, we cannot guarantee that it
5144 # will be updated with that name because of a race condition
5143 # will be updated with that name because of a race condition
5145 # server side. (See issue 4689 for details)
5144 # server side. (See issue 4689 for details)
5146 oldrevs = revs
5145 oldrevs = revs
5147 revs = [] # actually, nodes
5146 revs = [] # actually, nodes
5148 for r in oldrevs:
5147 for r in oldrevs:
5149 node = other.lookup(r)
5148 node = other.lookup(r)
5150 revs.append(node)
5149 revs.append(node)
5151 if r == checkout:
5150 if r == checkout:
5152 checkout = node
5151 checkout = node
5153 except error.CapabilityError:
5152 except error.CapabilityError:
5154 err = _("other repository doesn't support revision lookup, "
5153 err = _("other repository doesn't support revision lookup, "
5155 "so a rev cannot be specified.")
5154 "so a rev cannot be specified.")
5156 raise error.Abort(err)
5155 raise error.Abort(err)
5157
5156
5158 pullopargs.update(opts.get('opargs', {}))
5157 pullopargs.update(opts.get('opargs', {}))
5159 modheads = exchange.pull(repo, other, heads=revs,
5158 modheads = exchange.pull(repo, other, heads=revs,
5160 force=opts.get('force'),
5159 force=opts.get('force'),
5161 bookmarks=opts.get('bookmark', ()),
5160 bookmarks=opts.get('bookmark', ()),
5162 opargs=pullopargs).cgresult
5161 opargs=pullopargs).cgresult
5163
5162
5164 # brev is a name, which might be a bookmark to be activated at
5163 # brev is a name, which might be a bookmark to be activated at
5165 # the end of the update. In other words, it is an explicit
5164 # the end of the update. In other words, it is an explicit
5166 # destination of the update
5165 # destination of the update
5167 brev = None
5166 brev = None
5168
5167
5169 if checkout:
5168 if checkout:
5170 checkout = str(repo.changelog.rev(checkout))
5169 checkout = str(repo.changelog.rev(checkout))
5171
5170
5172 # order below depends on implementation of
5171 # order below depends on implementation of
5173 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5172 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5174 # because 'checkout' is determined without it.
5173 # because 'checkout' is determined without it.
5175 if opts.get('rev'):
5174 if opts.get('rev'):
5176 brev = opts['rev'][0]
5175 brev = opts['rev'][0]
5177 elif opts.get('branch'):
5176 elif opts.get('branch'):
5178 brev = opts['branch'][0]
5177 brev = opts['branch'][0]
5179 else:
5178 else:
5180 brev = branches[0]
5179 brev = branches[0]
5181 repo._subtoppath = source
5180 repo._subtoppath = source
5182 try:
5181 try:
5183 ret = postincoming(ui, repo, modheads, opts.get('update'),
5182 ret = postincoming(ui, repo, modheads, opts.get('update'),
5184 checkout, brev)
5183 checkout, brev)
5185
5184
5186 finally:
5185 finally:
5187 del repo._subtoppath
5186 del repo._subtoppath
5188
5187
5189 finally:
5188 finally:
5190 other.close()
5189 other.close()
5191 return ret
5190 return ret
5192
5191
5193 @command('^push',
5192 @command('^push',
5194 [('f', 'force', None, _('force push')),
5193 [('f', 'force', None, _('force push')),
5195 ('r', 'rev', [],
5194 ('r', 'rev', [],
5196 _('a changeset intended to be included in the destination'),
5195 _('a changeset intended to be included in the destination'),
5197 _('REV')),
5196 _('REV')),
5198 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5197 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5199 ('b', 'branch', [],
5198 ('b', 'branch', [],
5200 _('a specific branch you would like to push'), _('BRANCH')),
5199 _('a specific branch you would like to push'), _('BRANCH')),
5201 ('', 'new-branch', False, _('allow pushing a new branch')),
5200 ('', 'new-branch', False, _('allow pushing a new branch')),
5202 ] + remoteopts,
5201 ] + remoteopts,
5203 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5202 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5204 def push(ui, repo, dest=None, **opts):
5203 def push(ui, repo, dest=None, **opts):
5205 """push changes to the specified destination
5204 """push changes to the specified destination
5206
5205
5207 Push changesets from the local repository to the specified
5206 Push changesets from the local repository to the specified
5208 destination.
5207 destination.
5209
5208
5210 This operation is symmetrical to pull: it is identical to a pull
5209 This operation is symmetrical to pull: it is identical to a pull
5211 in the destination repository from the current one.
5210 in the destination repository from the current one.
5212
5211
5213 By default, push will not allow creation of new heads at the
5212 By default, push will not allow creation of new heads at the
5214 destination, since multiple heads would make it unclear which head
5213 destination, since multiple heads would make it unclear which head
5215 to use. In this situation, it is recommended to pull and merge
5214 to use. In this situation, it is recommended to pull and merge
5216 before pushing.
5215 before pushing.
5217
5216
5218 Use --new-branch if you want to allow push to create a new named
5217 Use --new-branch if you want to allow push to create a new named
5219 branch that is not present at the destination. This allows you to
5218 branch that is not present at the destination. This allows you to
5220 only create a new branch without forcing other changes.
5219 only create a new branch without forcing other changes.
5221
5220
5222 .. note::
5221 .. note::
5223
5222
5224 Extra care should be taken with the -f/--force option,
5223 Extra care should be taken with the -f/--force option,
5225 which will push all new heads on all branches, an action which will
5224 which will push all new heads on all branches, an action which will
5226 almost always cause confusion for collaborators.
5225 almost always cause confusion for collaborators.
5227
5226
5228 If -r/--rev is used, the specified revision and all its ancestors
5227 If -r/--rev is used, the specified revision and all its ancestors
5229 will be pushed to the remote repository.
5228 will be pushed to the remote repository.
5230
5229
5231 If -B/--bookmark is used, the specified bookmarked revision, its
5230 If -B/--bookmark is used, the specified bookmarked revision, its
5232 ancestors, and the bookmark will be pushed to the remote
5231 ancestors, and the bookmark will be pushed to the remote
5233 repository. Specifying ``.`` is equivalent to specifying the active
5232 repository. Specifying ``.`` is equivalent to specifying the active
5234 bookmark's name.
5233 bookmark's name.
5235
5234
5236 Please see :hg:`help urls` for important details about ``ssh://``
5235 Please see :hg:`help urls` for important details about ``ssh://``
5237 URLs. If DESTINATION is omitted, a default path will be used.
5236 URLs. If DESTINATION is omitted, a default path will be used.
5238
5237
5239 Returns 0 if push was successful, 1 if nothing to push.
5238 Returns 0 if push was successful, 1 if nothing to push.
5240 """
5239 """
5241
5240
5242 if opts.get('bookmark'):
5241 if opts.get('bookmark'):
5243 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5242 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5244 for b in opts['bookmark']:
5243 for b in opts['bookmark']:
5245 # translate -B options to -r so changesets get pushed
5244 # translate -B options to -r so changesets get pushed
5246 b = repo._bookmarks.expandname(b)
5245 b = repo._bookmarks.expandname(b)
5247 if b in repo._bookmarks:
5246 if b in repo._bookmarks:
5248 opts.setdefault('rev', []).append(b)
5247 opts.setdefault('rev', []).append(b)
5249 else:
5248 else:
5250 # if we try to push a deleted bookmark, translate it to null
5249 # if we try to push a deleted bookmark, translate it to null
5251 # this lets simultaneous -r, -b options continue working
5250 # this lets simultaneous -r, -b options continue working
5252 opts.setdefault('rev', []).append("null")
5251 opts.setdefault('rev', []).append("null")
5253
5252
5254 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5253 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5255 if not path:
5254 if not path:
5256 raise error.Abort(_('default repository not configured!'),
5255 raise error.Abort(_('default repository not configured!'),
5257 hint=_("see 'hg help config.paths'"))
5256 hint=_("see 'hg help config.paths'"))
5258 dest = path.pushloc or path.loc
5257 dest = path.pushloc or path.loc
5259 branches = (path.branch, opts.get('branch') or [])
5258 branches = (path.branch, opts.get('branch') or [])
5260 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5259 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5261 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5260 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5262 other = hg.peer(repo, opts, dest)
5261 other = hg.peer(repo, opts, dest)
5263
5262
5264 if revs:
5263 if revs:
5265 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5264 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5266 if not revs:
5265 if not revs:
5267 raise error.Abort(_("specified revisions evaluate to an empty set"),
5266 raise error.Abort(_("specified revisions evaluate to an empty set"),
5268 hint=_("use different revision arguments"))
5267 hint=_("use different revision arguments"))
5269 elif path.pushrev:
5268 elif path.pushrev:
5270 # It doesn't make any sense to specify ancestor revisions. So limit
5269 # It doesn't make any sense to specify ancestor revisions. So limit
5271 # to DAG heads to make discovery simpler.
5270 # to DAG heads to make discovery simpler.
5272 expr = revset.formatspec('heads(%r)', path.pushrev)
5271 expr = revset.formatspec('heads(%r)', path.pushrev)
5273 revs = scmutil.revrange(repo, [expr])
5272 revs = scmutil.revrange(repo, [expr])
5274 revs = [repo[rev].node() for rev in revs]
5273 revs = [repo[rev].node() for rev in revs]
5275 if not revs:
5274 if not revs:
5276 raise error.Abort(_('default push revset for path evaluates to an '
5275 raise error.Abort(_('default push revset for path evaluates to an '
5277 'empty set'))
5276 'empty set'))
5278
5277
5279 repo._subtoppath = dest
5278 repo._subtoppath = dest
5280 try:
5279 try:
5281 # push subrepos depth-first for coherent ordering
5280 # push subrepos depth-first for coherent ordering
5282 c = repo['']
5281 c = repo['']
5283 subs = c.substate # only repos that are committed
5282 subs = c.substate # only repos that are committed
5284 for s in sorted(subs):
5283 for s in sorted(subs):
5285 result = c.sub(s).push(opts)
5284 result = c.sub(s).push(opts)
5286 if result == 0:
5285 if result == 0:
5287 return not result
5286 return not result
5288 finally:
5287 finally:
5289 del repo._subtoppath
5288 del repo._subtoppath
5290 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5289 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5291 newbranch=opts.get('new_branch'),
5290 newbranch=opts.get('new_branch'),
5292 bookmarks=opts.get('bookmark', ()),
5291 bookmarks=opts.get('bookmark', ()),
5293 opargs=opts.get('opargs'))
5292 opargs=opts.get('opargs'))
5294
5293
5295 result = not pushop.cgresult
5294 result = not pushop.cgresult
5296
5295
5297 if pushop.bkresult is not None:
5296 if pushop.bkresult is not None:
5298 if pushop.bkresult == 2:
5297 if pushop.bkresult == 2:
5299 result = 2
5298 result = 2
5300 elif not result and pushop.bkresult:
5299 elif not result and pushop.bkresult:
5301 result = 2
5300 result = 2
5302
5301
5303 return result
5302 return result
5304
5303
5305 @command('recover', [])
5304 @command('recover', [])
5306 def recover(ui, repo):
5305 def recover(ui, repo):
5307 """roll back an interrupted transaction
5306 """roll back an interrupted transaction
5308
5307
5309 Recover from an interrupted commit or pull.
5308 Recover from an interrupted commit or pull.
5310
5309
5311 This command tries to fix the repository status after an
5310 This command tries to fix the repository status after an
5312 interrupted operation. It should only be necessary when Mercurial
5311 interrupted operation. It should only be necessary when Mercurial
5313 suggests it.
5312 suggests it.
5314
5313
5315 Returns 0 if successful, 1 if nothing to recover or verify fails.
5314 Returns 0 if successful, 1 if nothing to recover or verify fails.
5316 """
5315 """
5317 if repo.recover():
5316 if repo.recover():
5318 return hg.verify(repo)
5317 return hg.verify(repo)
5319 return 1
5318 return 1
5320
5319
5321 @command('^remove|rm',
5320 @command('^remove|rm',
5322 [('A', 'after', None, _('record delete for missing files')),
5321 [('A', 'after', None, _('record delete for missing files')),
5323 ('f', 'force', None,
5322 ('f', 'force', None,
5324 _('forget added files, delete modified files')),
5323 _('forget added files, delete modified files')),
5325 ] + subrepoopts + walkopts,
5324 ] + subrepoopts + walkopts,
5326 _('[OPTION]... FILE...'),
5325 _('[OPTION]... FILE...'),
5327 inferrepo=True)
5326 inferrepo=True)
5328 def remove(ui, repo, *pats, **opts):
5327 def remove(ui, repo, *pats, **opts):
5329 """remove the specified files on the next commit
5328 """remove the specified files on the next commit
5330
5329
5331 Schedule the indicated files for removal from the current branch.
5330 Schedule the indicated files for removal from the current branch.
5332
5331
5333 This command schedules the files to be removed at the next commit.
5332 This command schedules the files to be removed at the next commit.
5334 To undo a remove before that, see :hg:`revert`. To undo added
5333 To undo a remove before that, see :hg:`revert`. To undo added
5335 files, see :hg:`forget`.
5334 files, see :hg:`forget`.
5336
5335
5337 .. container:: verbose
5336 .. container:: verbose
5338
5337
5339 -A/--after can be used to remove only files that have already
5338 -A/--after can be used to remove only files that have already
5340 been deleted, -f/--force can be used to force deletion, and -Af
5339 been deleted, -f/--force can be used to force deletion, and -Af
5341 can be used to remove files from the next revision without
5340 can be used to remove files from the next revision without
5342 deleting them from the working directory.
5341 deleting them from the working directory.
5343
5342
5344 The following table details the behavior of remove for different
5343 The following table details the behavior of remove for different
5345 file states (columns) and option combinations (rows). The file
5344 file states (columns) and option combinations (rows). The file
5346 states are Added [A], Clean [C], Modified [M] and Missing [!]
5345 states are Added [A], Clean [C], Modified [M] and Missing [!]
5347 (as reported by :hg:`status`). The actions are Warn, Remove
5346 (as reported by :hg:`status`). The actions are Warn, Remove
5348 (from branch) and Delete (from disk):
5347 (from branch) and Delete (from disk):
5349
5348
5350 ========= == == == ==
5349 ========= == == == ==
5351 opt/state A C M !
5350 opt/state A C M !
5352 ========= == == == ==
5351 ========= == == == ==
5353 none W RD W R
5352 none W RD W R
5354 -f R RD RD R
5353 -f R RD RD R
5355 -A W W W R
5354 -A W W W R
5356 -Af R R R R
5355 -Af R R R R
5357 ========= == == == ==
5356 ========= == == == ==
5358
5357
5359 .. note::
5358 .. note::
5360
5359
5361 :hg:`remove` never deletes files in Added [A] state from the
5360 :hg:`remove` never deletes files in Added [A] state from the
5362 working directory, not even if ``--force`` is specified.
5361 working directory, not even if ``--force`` is specified.
5363
5362
5364 Returns 0 on success, 1 if any warnings encountered.
5363 Returns 0 on success, 1 if any warnings encountered.
5365 """
5364 """
5366
5365
5367 after, force = opts.get('after'), opts.get('force')
5366 after, force = opts.get('after'), opts.get('force')
5368 if not pats and not after:
5367 if not pats and not after:
5369 raise error.Abort(_('no files specified'))
5368 raise error.Abort(_('no files specified'))
5370
5369
5371 m = scmutil.match(repo[None], pats, opts)
5370 m = scmutil.match(repo[None], pats, opts)
5372 subrepos = opts.get('subrepos')
5371 subrepos = opts.get('subrepos')
5373 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5372 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5374
5373
5375 @command('rename|move|mv',
5374 @command('rename|move|mv',
5376 [('A', 'after', None, _('record a rename that has already occurred')),
5375 [('A', 'after', None, _('record a rename that has already occurred')),
5377 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5376 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5378 ] + walkopts + dryrunopts,
5377 ] + walkopts + dryrunopts,
5379 _('[OPTION]... SOURCE... DEST'))
5378 _('[OPTION]... SOURCE... DEST'))
5380 def rename(ui, repo, *pats, **opts):
5379 def rename(ui, repo, *pats, **opts):
5381 """rename files; equivalent of copy + remove
5380 """rename files; equivalent of copy + remove
5382
5381
5383 Mark dest as copies of sources; mark sources for deletion. If dest
5382 Mark dest as copies of sources; mark sources for deletion. If dest
5384 is a directory, copies are put in that directory. If dest is a
5383 is a directory, copies are put in that directory. If dest is a
5385 file, there can only be one source.
5384 file, there can only be one source.
5386
5385
5387 By default, this command copies the contents of files as they
5386 By default, this command copies the contents of files as they
5388 exist in the working directory. If invoked with -A/--after, the
5387 exist in the working directory. If invoked with -A/--after, the
5389 operation is recorded, but no copying is performed.
5388 operation is recorded, but no copying is performed.
5390
5389
5391 This command takes effect at the next commit. To undo a rename
5390 This command takes effect at the next commit. To undo a rename
5392 before that, see :hg:`revert`.
5391 before that, see :hg:`revert`.
5393
5392
5394 Returns 0 on success, 1 if errors are encountered.
5393 Returns 0 on success, 1 if errors are encountered.
5395 """
5394 """
5396 with repo.wlock(False):
5395 with repo.wlock(False):
5397 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5396 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5398
5397
5399 @command('resolve',
5398 @command('resolve',
5400 [('a', 'all', None, _('select all unresolved files')),
5399 [('a', 'all', None, _('select all unresolved files')),
5401 ('l', 'list', None, _('list state of files needing merge')),
5400 ('l', 'list', None, _('list state of files needing merge')),
5402 ('m', 'mark', None, _('mark files as resolved')),
5401 ('m', 'mark', None, _('mark files as resolved')),
5403 ('u', 'unmark', None, _('mark files as unresolved')),
5402 ('u', 'unmark', None, _('mark files as unresolved')),
5404 ('n', 'no-status', None, _('hide status prefix'))]
5403 ('n', 'no-status', None, _('hide status prefix'))]
5405 + mergetoolopts + walkopts + formatteropts,
5404 + mergetoolopts + walkopts + formatteropts,
5406 _('[OPTION]... [FILE]...'),
5405 _('[OPTION]... [FILE]...'),
5407 inferrepo=True)
5406 inferrepo=True)
5408 def resolve(ui, repo, *pats, **opts):
5407 def resolve(ui, repo, *pats, **opts):
5409 """redo merges or set/view the merge status of files
5408 """redo merges or set/view the merge status of files
5410
5409
5411 Merges with unresolved conflicts are often the result of
5410 Merges with unresolved conflicts are often the result of
5412 non-interactive merging using the ``internal:merge`` configuration
5411 non-interactive merging using the ``internal:merge`` configuration
5413 setting, or a command-line merge tool like ``diff3``. The resolve
5412 setting, or a command-line merge tool like ``diff3``. The resolve
5414 command is used to manage the files involved in a merge, after
5413 command is used to manage the files involved in a merge, after
5415 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5414 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5416 working directory must have two parents). See :hg:`help
5415 working directory must have two parents). See :hg:`help
5417 merge-tools` for information on configuring merge tools.
5416 merge-tools` for information on configuring merge tools.
5418
5417
5419 The resolve command can be used in the following ways:
5418 The resolve command can be used in the following ways:
5420
5419
5421 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5420 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5422 files, discarding any previous merge attempts. Re-merging is not
5421 files, discarding any previous merge attempts. Re-merging is not
5423 performed for files already marked as resolved. Use ``--all/-a``
5422 performed for files already marked as resolved. Use ``--all/-a``
5424 to select all unresolved files. ``--tool`` can be used to specify
5423 to select all unresolved files. ``--tool`` can be used to specify
5425 the merge tool used for the given files. It overrides the HGMERGE
5424 the merge tool used for the given files. It overrides the HGMERGE
5426 environment variable and your configuration files. Previous file
5425 environment variable and your configuration files. Previous file
5427 contents are saved with a ``.orig`` suffix.
5426 contents are saved with a ``.orig`` suffix.
5428
5427
5429 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5428 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5430 (e.g. after having manually fixed-up the files). The default is
5429 (e.g. after having manually fixed-up the files). The default is
5431 to mark all unresolved files.
5430 to mark all unresolved files.
5432
5431
5433 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5432 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5434 default is to mark all resolved files.
5433 default is to mark all resolved files.
5435
5434
5436 - :hg:`resolve -l`: list files which had or still have conflicts.
5435 - :hg:`resolve -l`: list files which had or still have conflicts.
5437 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5436 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5438
5437
5439 .. note::
5438 .. note::
5440
5439
5441 Mercurial will not let you commit files with unresolved merge
5440 Mercurial will not let you commit files with unresolved merge
5442 conflicts. You must use :hg:`resolve -m ...` before you can
5441 conflicts. You must use :hg:`resolve -m ...` before you can
5443 commit after a conflicting merge.
5442 commit after a conflicting merge.
5444
5443
5445 Returns 0 on success, 1 if any files fail a resolve attempt.
5444 Returns 0 on success, 1 if any files fail a resolve attempt.
5446 """
5445 """
5447
5446
5448 flaglist = 'all mark unmark list no_status'.split()
5447 flaglist = 'all mark unmark list no_status'.split()
5449 all, mark, unmark, show, nostatus = \
5448 all, mark, unmark, show, nostatus = \
5450 [opts.get(o) for o in flaglist]
5449 [opts.get(o) for o in flaglist]
5451
5450
5452 if (show and (mark or unmark)) or (mark and unmark):
5451 if (show and (mark or unmark)) or (mark and unmark):
5453 raise error.Abort(_("too many options specified"))
5452 raise error.Abort(_("too many options specified"))
5454 if pats and all:
5453 if pats and all:
5455 raise error.Abort(_("can't specify --all and patterns"))
5454 raise error.Abort(_("can't specify --all and patterns"))
5456 if not (all or pats or show or mark or unmark):
5455 if not (all or pats or show or mark or unmark):
5457 raise error.Abort(_('no files or directories specified'),
5456 raise error.Abort(_('no files or directories specified'),
5458 hint=('use --all to re-merge all unresolved files'))
5457 hint=('use --all to re-merge all unresolved files'))
5459
5458
5460 if show:
5459 if show:
5461 fm = ui.formatter('resolve', opts)
5460 fm = ui.formatter('resolve', opts)
5462 ms = mergemod.mergestate.read(repo)
5461 ms = mergemod.mergestate.read(repo)
5463 m = scmutil.match(repo[None], pats, opts)
5462 m = scmutil.match(repo[None], pats, opts)
5464 for f in ms:
5463 for f in ms:
5465 if not m(f):
5464 if not m(f):
5466 continue
5465 continue
5467 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5466 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5468 'd': 'driverresolved'}[ms[f]]
5467 'd': 'driverresolved'}[ms[f]]
5469 fm.startitem()
5468 fm.startitem()
5470 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5469 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5471 fm.write('path', '%s\n', f, label=l)
5470 fm.write('path', '%s\n', f, label=l)
5472 fm.end()
5471 fm.end()
5473 return 0
5472 return 0
5474
5473
5475 with repo.wlock():
5474 with repo.wlock():
5476 ms = mergemod.mergestate.read(repo)
5475 ms = mergemod.mergestate.read(repo)
5477
5476
5478 if not (ms.active() or repo.dirstate.p2() != nullid):
5477 if not (ms.active() or repo.dirstate.p2() != nullid):
5479 raise error.Abort(
5478 raise error.Abort(
5480 _('resolve command not applicable when not merging'))
5479 _('resolve command not applicable when not merging'))
5481
5480
5482 wctx = repo[None]
5481 wctx = repo[None]
5483
5482
5484 if ms.mergedriver and ms.mdstate() == 'u':
5483 if ms.mergedriver and ms.mdstate() == 'u':
5485 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5484 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5486 ms.commit()
5485 ms.commit()
5487 # allow mark and unmark to go through
5486 # allow mark and unmark to go through
5488 if not mark and not unmark and not proceed:
5487 if not mark and not unmark and not proceed:
5489 return 1
5488 return 1
5490
5489
5491 m = scmutil.match(wctx, pats, opts)
5490 m = scmutil.match(wctx, pats, opts)
5492 ret = 0
5491 ret = 0
5493 didwork = False
5492 didwork = False
5494 runconclude = False
5493 runconclude = False
5495
5494
5496 tocomplete = []
5495 tocomplete = []
5497 for f in ms:
5496 for f in ms:
5498 if not m(f):
5497 if not m(f):
5499 continue
5498 continue
5500
5499
5501 didwork = True
5500 didwork = True
5502
5501
5503 # don't let driver-resolved files be marked, and run the conclude
5502 # don't let driver-resolved files be marked, and run the conclude
5504 # step if asked to resolve
5503 # step if asked to resolve
5505 if ms[f] == "d":
5504 if ms[f] == "d":
5506 exact = m.exact(f)
5505 exact = m.exact(f)
5507 if mark:
5506 if mark:
5508 if exact:
5507 if exact:
5509 ui.warn(_('not marking %s as it is driver-resolved\n')
5508 ui.warn(_('not marking %s as it is driver-resolved\n')
5510 % f)
5509 % f)
5511 elif unmark:
5510 elif unmark:
5512 if exact:
5511 if exact:
5513 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5512 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5514 % f)
5513 % f)
5515 else:
5514 else:
5516 runconclude = True
5515 runconclude = True
5517 continue
5516 continue
5518
5517
5519 if mark:
5518 if mark:
5520 ms.mark(f, "r")
5519 ms.mark(f, "r")
5521 elif unmark:
5520 elif unmark:
5522 ms.mark(f, "u")
5521 ms.mark(f, "u")
5523 else:
5522 else:
5524 # backup pre-resolve (merge uses .orig for its own purposes)
5523 # backup pre-resolve (merge uses .orig for its own purposes)
5525 a = repo.wjoin(f)
5524 a = repo.wjoin(f)
5526 try:
5525 try:
5527 util.copyfile(a, a + ".resolve")
5526 util.copyfile(a, a + ".resolve")
5528 except (IOError, OSError) as inst:
5527 except (IOError, OSError) as inst:
5529 if inst.errno != errno.ENOENT:
5528 if inst.errno != errno.ENOENT:
5530 raise
5529 raise
5531
5530
5532 try:
5531 try:
5533 # preresolve file
5532 # preresolve file
5534 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5533 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5535 'resolve')
5534 'resolve')
5536 complete, r = ms.preresolve(f, wctx)
5535 complete, r = ms.preresolve(f, wctx)
5537 if not complete:
5536 if not complete:
5538 tocomplete.append(f)
5537 tocomplete.append(f)
5539 elif r:
5538 elif r:
5540 ret = 1
5539 ret = 1
5541 finally:
5540 finally:
5542 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5541 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5543 ms.commit()
5542 ms.commit()
5544
5543
5545 # replace filemerge's .orig file with our resolve file, but only
5544 # replace filemerge's .orig file with our resolve file, but only
5546 # for merges that are complete
5545 # for merges that are complete
5547 if complete:
5546 if complete:
5548 try:
5547 try:
5549 util.rename(a + ".resolve",
5548 util.rename(a + ".resolve",
5550 scmutil.origpath(ui, repo, a))
5549 scmutil.origpath(ui, repo, a))
5551 except OSError as inst:
5550 except OSError as inst:
5552 if inst.errno != errno.ENOENT:
5551 if inst.errno != errno.ENOENT:
5553 raise
5552 raise
5554
5553
5555 for f in tocomplete:
5554 for f in tocomplete:
5556 try:
5555 try:
5557 # resolve file
5556 # resolve file
5558 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5557 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5559 'resolve')
5558 'resolve')
5560 r = ms.resolve(f, wctx)
5559 r = ms.resolve(f, wctx)
5561 if r:
5560 if r:
5562 ret = 1
5561 ret = 1
5563 finally:
5562 finally:
5564 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5563 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5565 ms.commit()
5564 ms.commit()
5566
5565
5567 # replace filemerge's .orig file with our resolve file
5566 # replace filemerge's .orig file with our resolve file
5568 a = repo.wjoin(f)
5567 a = repo.wjoin(f)
5569 try:
5568 try:
5570 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5569 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5571 except OSError as inst:
5570 except OSError as inst:
5572 if inst.errno != errno.ENOENT:
5571 if inst.errno != errno.ENOENT:
5573 raise
5572 raise
5574
5573
5575 ms.commit()
5574 ms.commit()
5576 ms.recordactions()
5575 ms.recordactions()
5577
5576
5578 if not didwork and pats:
5577 if not didwork and pats:
5579 hint = None
5578 hint = None
5580 if not any([p for p in pats if p.find(':') >= 0]):
5579 if not any([p for p in pats if p.find(':') >= 0]):
5581 pats = ['path:%s' % p for p in pats]
5580 pats = ['path:%s' % p for p in pats]
5582 m = scmutil.match(wctx, pats, opts)
5581 m = scmutil.match(wctx, pats, opts)
5583 for f in ms:
5582 for f in ms:
5584 if not m(f):
5583 if not m(f):
5585 continue
5584 continue
5586 flags = ''.join(['-%s ' % o[0] for o in flaglist
5585 flags = ''.join(['-%s ' % o[0] for o in flaglist
5587 if opts.get(o)])
5586 if opts.get(o)])
5588 hint = _("(try: hg resolve %s%s)\n") % (
5587 hint = _("(try: hg resolve %s%s)\n") % (
5589 flags,
5588 flags,
5590 ' '.join(pats))
5589 ' '.join(pats))
5591 break
5590 break
5592 ui.warn(_("arguments do not match paths that need resolving\n"))
5591 ui.warn(_("arguments do not match paths that need resolving\n"))
5593 if hint:
5592 if hint:
5594 ui.warn(hint)
5593 ui.warn(hint)
5595 elif ms.mergedriver and ms.mdstate() != 's':
5594 elif ms.mergedriver and ms.mdstate() != 's':
5596 # run conclude step when either a driver-resolved file is requested
5595 # run conclude step when either a driver-resolved file is requested
5597 # or there are no driver-resolved files
5596 # or there are no driver-resolved files
5598 # we can't use 'ret' to determine whether any files are unresolved
5597 # we can't use 'ret' to determine whether any files are unresolved
5599 # because we might not have tried to resolve some
5598 # because we might not have tried to resolve some
5600 if ((runconclude or not list(ms.driverresolved()))
5599 if ((runconclude or not list(ms.driverresolved()))
5601 and not list(ms.unresolved())):
5600 and not list(ms.unresolved())):
5602 proceed = mergemod.driverconclude(repo, ms, wctx)
5601 proceed = mergemod.driverconclude(repo, ms, wctx)
5603 ms.commit()
5602 ms.commit()
5604 if not proceed:
5603 if not proceed:
5605 return 1
5604 return 1
5606
5605
5607 # Nudge users into finishing an unfinished operation
5606 # Nudge users into finishing an unfinished operation
5608 unresolvedf = list(ms.unresolved())
5607 unresolvedf = list(ms.unresolved())
5609 driverresolvedf = list(ms.driverresolved())
5608 driverresolvedf = list(ms.driverresolved())
5610 if not unresolvedf and not driverresolvedf:
5609 if not unresolvedf and not driverresolvedf:
5611 ui.status(_('(no more unresolved files)\n'))
5610 ui.status(_('(no more unresolved files)\n'))
5612 cmdutil.checkafterresolved(repo)
5611 cmdutil.checkafterresolved(repo)
5613 elif not unresolvedf:
5612 elif not unresolvedf:
5614 ui.status(_('(no more unresolved files -- '
5613 ui.status(_('(no more unresolved files -- '
5615 'run "hg resolve --all" to conclude)\n'))
5614 'run "hg resolve --all" to conclude)\n'))
5616
5615
5617 return ret
5616 return ret
5618
5617
5619 @command('revert',
5618 @command('revert',
5620 [('a', 'all', None, _('revert all changes when no arguments given')),
5619 [('a', 'all', None, _('revert all changes when no arguments given')),
5621 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5620 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5622 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5621 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5623 ('C', 'no-backup', None, _('do not save backup copies of files')),
5622 ('C', 'no-backup', None, _('do not save backup copies of files')),
5624 ('i', 'interactive', None,
5623 ('i', 'interactive', None,
5625 _('interactively select the changes (EXPERIMENTAL)')),
5624 _('interactively select the changes (EXPERIMENTAL)')),
5626 ] + walkopts + dryrunopts,
5625 ] + walkopts + dryrunopts,
5627 _('[OPTION]... [-r REV] [NAME]...'))
5626 _('[OPTION]... [-r REV] [NAME]...'))
5628 def revert(ui, repo, *pats, **opts):
5627 def revert(ui, repo, *pats, **opts):
5629 """restore files to their checkout state
5628 """restore files to their checkout state
5630
5629
5631 .. note::
5630 .. note::
5632
5631
5633 To check out earlier revisions, you should use :hg:`update REV`.
5632 To check out earlier revisions, you should use :hg:`update REV`.
5634 To cancel an uncommitted merge (and lose your changes),
5633 To cancel an uncommitted merge (and lose your changes),
5635 use :hg:`update --clean .`.
5634 use :hg:`update --clean .`.
5636
5635
5637 With no revision specified, revert the specified files or directories
5636 With no revision specified, revert the specified files or directories
5638 to the contents they had in the parent of the working directory.
5637 to the contents they had in the parent of the working directory.
5639 This restores the contents of files to an unmodified
5638 This restores the contents of files to an unmodified
5640 state and unschedules adds, removes, copies, and renames. If the
5639 state and unschedules adds, removes, copies, and renames. If the
5641 working directory has two parents, you must explicitly specify a
5640 working directory has two parents, you must explicitly specify a
5642 revision.
5641 revision.
5643
5642
5644 Using the -r/--rev or -d/--date options, revert the given files or
5643 Using the -r/--rev or -d/--date options, revert the given files or
5645 directories to their states as of a specific revision. Because
5644 directories to their states as of a specific revision. Because
5646 revert does not change the working directory parents, this will
5645 revert does not change the working directory parents, this will
5647 cause these files to appear modified. This can be helpful to "back
5646 cause these files to appear modified. This can be helpful to "back
5648 out" some or all of an earlier change. See :hg:`backout` for a
5647 out" some or all of an earlier change. See :hg:`backout` for a
5649 related method.
5648 related method.
5650
5649
5651 Modified files are saved with a .orig suffix before reverting.
5650 Modified files are saved with a .orig suffix before reverting.
5652 To disable these backups, use --no-backup. It is possible to store
5651 To disable these backups, use --no-backup. It is possible to store
5653 the backup files in a custom directory relative to the root of the
5652 the backup files in a custom directory relative to the root of the
5654 repository by setting the ``ui.origbackuppath`` configuration
5653 repository by setting the ``ui.origbackuppath`` configuration
5655 option.
5654 option.
5656
5655
5657 See :hg:`help dates` for a list of formats valid for -d/--date.
5656 See :hg:`help dates` for a list of formats valid for -d/--date.
5658
5657
5659 See :hg:`help backout` for a way to reverse the effect of an
5658 See :hg:`help backout` for a way to reverse the effect of an
5660 earlier changeset.
5659 earlier changeset.
5661
5660
5662 Returns 0 on success.
5661 Returns 0 on success.
5663 """
5662 """
5664
5663
5665 if opts.get("date"):
5664 if opts.get("date"):
5666 if opts.get("rev"):
5665 if opts.get("rev"):
5667 raise error.Abort(_("you can't specify a revision and a date"))
5666 raise error.Abort(_("you can't specify a revision and a date"))
5668 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5667 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5669
5668
5670 parent, p2 = repo.dirstate.parents()
5669 parent, p2 = repo.dirstate.parents()
5671 if not opts.get('rev') and p2 != nullid:
5670 if not opts.get('rev') and p2 != nullid:
5672 # revert after merge is a trap for new users (issue2915)
5671 # revert after merge is a trap for new users (issue2915)
5673 raise error.Abort(_('uncommitted merge with no revision specified'),
5672 raise error.Abort(_('uncommitted merge with no revision specified'),
5674 hint=_("use 'hg update' or see 'hg help revert'"))
5673 hint=_("use 'hg update' or see 'hg help revert'"))
5675
5674
5676 ctx = scmutil.revsingle(repo, opts.get('rev'))
5675 ctx = scmutil.revsingle(repo, opts.get('rev'))
5677
5676
5678 if (not (pats or opts.get('include') or opts.get('exclude') or
5677 if (not (pats or opts.get('include') or opts.get('exclude') or
5679 opts.get('all') or opts.get('interactive'))):
5678 opts.get('all') or opts.get('interactive'))):
5680 msg = _("no files or directories specified")
5679 msg = _("no files or directories specified")
5681 if p2 != nullid:
5680 if p2 != nullid:
5682 hint = _("uncommitted merge, use --all to discard all changes,"
5681 hint = _("uncommitted merge, use --all to discard all changes,"
5683 " or 'hg update -C .' to abort the merge")
5682 " or 'hg update -C .' to abort the merge")
5684 raise error.Abort(msg, hint=hint)
5683 raise error.Abort(msg, hint=hint)
5685 dirty = any(repo.status())
5684 dirty = any(repo.status())
5686 node = ctx.node()
5685 node = ctx.node()
5687 if node != parent:
5686 if node != parent:
5688 if dirty:
5687 if dirty:
5689 hint = _("uncommitted changes, use --all to discard all"
5688 hint = _("uncommitted changes, use --all to discard all"
5690 " changes, or 'hg update %s' to update") % ctx.rev()
5689 " changes, or 'hg update %s' to update") % ctx.rev()
5691 else:
5690 else:
5692 hint = _("use --all to revert all files,"
5691 hint = _("use --all to revert all files,"
5693 " or 'hg update %s' to update") % ctx.rev()
5692 " or 'hg update %s' to update") % ctx.rev()
5694 elif dirty:
5693 elif dirty:
5695 hint = _("uncommitted changes, use --all to discard all changes")
5694 hint = _("uncommitted changes, use --all to discard all changes")
5696 else:
5695 else:
5697 hint = _("use --all to revert all files")
5696 hint = _("use --all to revert all files")
5698 raise error.Abort(msg, hint=hint)
5697 raise error.Abort(msg, hint=hint)
5699
5698
5700 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5699 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5701
5700
5702 @command('rollback', dryrunopts +
5701 @command('rollback', dryrunopts +
5703 [('f', 'force', False, _('ignore safety measures'))])
5702 [('f', 'force', False, _('ignore safety measures'))])
5704 def rollback(ui, repo, **opts):
5703 def rollback(ui, repo, **opts):
5705 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5704 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5706
5705
5707 Please use :hg:`commit --amend` instead of rollback to correct
5706 Please use :hg:`commit --amend` instead of rollback to correct
5708 mistakes in the last commit.
5707 mistakes in the last commit.
5709
5708
5710 This command should be used with care. There is only one level of
5709 This command should be used with care. There is only one level of
5711 rollback, and there is no way to undo a rollback. It will also
5710 rollback, and there is no way to undo a rollback. It will also
5712 restore the dirstate at the time of the last transaction, losing
5711 restore the dirstate at the time of the last transaction, losing
5713 any dirstate changes since that time. This command does not alter
5712 any dirstate changes since that time. This command does not alter
5714 the working directory.
5713 the working directory.
5715
5714
5716 Transactions are used to encapsulate the effects of all commands
5715 Transactions are used to encapsulate the effects of all commands
5717 that create new changesets or propagate existing changesets into a
5716 that create new changesets or propagate existing changesets into a
5718 repository.
5717 repository.
5719
5718
5720 .. container:: verbose
5719 .. container:: verbose
5721
5720
5722 For example, the following commands are transactional, and their
5721 For example, the following commands are transactional, and their
5723 effects can be rolled back:
5722 effects can be rolled back:
5724
5723
5725 - commit
5724 - commit
5726 - import
5725 - import
5727 - pull
5726 - pull
5728 - push (with this repository as the destination)
5727 - push (with this repository as the destination)
5729 - unbundle
5728 - unbundle
5730
5729
5731 To avoid permanent data loss, rollback will refuse to rollback a
5730 To avoid permanent data loss, rollback will refuse to rollback a
5732 commit transaction if it isn't checked out. Use --force to
5731 commit transaction if it isn't checked out. Use --force to
5733 override this protection.
5732 override this protection.
5734
5733
5735 The rollback command can be entirely disabled by setting the
5734 The rollback command can be entirely disabled by setting the
5736 ``ui.rollback`` configuration setting to false. If you're here
5735 ``ui.rollback`` configuration setting to false. If you're here
5737 because you want to use rollback and it's disabled, you can
5736 because you want to use rollback and it's disabled, you can
5738 re-enable the command by setting ``ui.rollback`` to true.
5737 re-enable the command by setting ``ui.rollback`` to true.
5739
5738
5740 This command is not intended for use on public repositories. Once
5739 This command is not intended for use on public repositories. Once
5741 changes are visible for pull by other users, rolling a transaction
5740 changes are visible for pull by other users, rolling a transaction
5742 back locally is ineffective (someone else may already have pulled
5741 back locally is ineffective (someone else may already have pulled
5743 the changes). Furthermore, a race is possible with readers of the
5742 the changes). Furthermore, a race is possible with readers of the
5744 repository; for example an in-progress pull from the repository
5743 repository; for example an in-progress pull from the repository
5745 may fail if a rollback is performed.
5744 may fail if a rollback is performed.
5746
5745
5747 Returns 0 on success, 1 if no rollback data is available.
5746 Returns 0 on success, 1 if no rollback data is available.
5748 """
5747 """
5749 if not ui.configbool('ui', 'rollback', True):
5748 if not ui.configbool('ui', 'rollback', True):
5750 raise error.Abort(_('rollback is disabled because it is unsafe'),
5749 raise error.Abort(_('rollback is disabled because it is unsafe'),
5751 hint=('see `hg help -v rollback` for information'))
5750 hint=('see `hg help -v rollback` for information'))
5752 return repo.rollback(dryrun=opts.get('dry_run'),
5751 return repo.rollback(dryrun=opts.get('dry_run'),
5753 force=opts.get('force'))
5752 force=opts.get('force'))
5754
5753
5755 @command('root', [])
5754 @command('root', [])
5756 def root(ui, repo):
5755 def root(ui, repo):
5757 """print the root (top) of the current working directory
5756 """print the root (top) of the current working directory
5758
5757
5759 Print the root directory of the current repository.
5758 Print the root directory of the current repository.
5760
5759
5761 Returns 0 on success.
5760 Returns 0 on success.
5762 """
5761 """
5763 ui.write(repo.root + "\n")
5762 ui.write(repo.root + "\n")
5764
5763
5765 @command('^serve',
5764 @command('^serve',
5766 [('A', 'accesslog', '', _('name of access log file to write to'),
5765 [('A', 'accesslog', '', _('name of access log file to write to'),
5767 _('FILE')),
5766 _('FILE')),
5768 ('d', 'daemon', None, _('run server in background')),
5767 ('d', 'daemon', None, _('run server in background')),
5769 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5768 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5770 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5769 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5771 # use string type, then we can check if something was passed
5770 # use string type, then we can check if something was passed
5772 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5771 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5773 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5772 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5774 _('ADDR')),
5773 _('ADDR')),
5775 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5774 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5776 _('PREFIX')),
5775 _('PREFIX')),
5777 ('n', 'name', '',
5776 ('n', 'name', '',
5778 _('name to show in web pages (default: working directory)'), _('NAME')),
5777 _('name to show in web pages (default: working directory)'), _('NAME')),
5779 ('', 'web-conf', '',
5778 ('', 'web-conf', '',
5780 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5779 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5781 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5780 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5782 _('FILE')),
5781 _('FILE')),
5783 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5782 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5784 ('', 'stdio', None, _('for remote clients')),
5783 ('', 'stdio', None, _('for remote clients')),
5785 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5784 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5786 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5785 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5787 ('', 'style', '', _('template style to use'), _('STYLE')),
5786 ('', 'style', '', _('template style to use'), _('STYLE')),
5788 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5787 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5789 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5788 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5790 _('[OPTION]...'),
5789 _('[OPTION]...'),
5791 optionalrepo=True)
5790 optionalrepo=True)
5792 def serve(ui, repo, **opts):
5791 def serve(ui, repo, **opts):
5793 """start stand-alone webserver
5792 """start stand-alone webserver
5794
5793
5795 Start a local HTTP repository browser and pull server. You can use
5794 Start a local HTTP repository browser and pull server. You can use
5796 this for ad-hoc sharing and browsing of repositories. It is
5795 this for ad-hoc sharing and browsing of repositories. It is
5797 recommended to use a real web server to serve a repository for
5796 recommended to use a real web server to serve a repository for
5798 longer periods of time.
5797 longer periods of time.
5799
5798
5800 Please note that the server does not implement access control.
5799 Please note that the server does not implement access control.
5801 This means that, by default, anybody can read from the server and
5800 This means that, by default, anybody can read from the server and
5802 nobody can write to it by default. Set the ``web.allow_push``
5801 nobody can write to it by default. Set the ``web.allow_push``
5803 option to ``*`` to allow everybody to push to the server. You
5802 option to ``*`` to allow everybody to push to the server. You
5804 should use a real web server if you need to authenticate users.
5803 should use a real web server if you need to authenticate users.
5805
5804
5806 By default, the server logs accesses to stdout and errors to
5805 By default, the server logs accesses to stdout and errors to
5807 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5806 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5808 files.
5807 files.
5809
5808
5810 To have the server choose a free port number to listen on, specify
5809 To have the server choose a free port number to listen on, specify
5811 a port number of 0; in this case, the server will print the port
5810 a port number of 0; in this case, the server will print the port
5812 number it uses.
5811 number it uses.
5813
5812
5814 Returns 0 on success.
5813 Returns 0 on success.
5815 """
5814 """
5816
5815
5817 if opts["stdio"] and opts["cmdserver"]:
5816 if opts["stdio"] and opts["cmdserver"]:
5818 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5817 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5819
5818
5820 if opts["stdio"]:
5819 if opts["stdio"]:
5821 if repo is None:
5820 if repo is None:
5822 raise error.RepoError(_("there is no Mercurial repository here"
5821 raise error.RepoError(_("there is no Mercurial repository here"
5823 " (.hg not found)"))
5822 " (.hg not found)"))
5824 s = sshserver.sshserver(ui, repo)
5823 s = sshserver.sshserver(ui, repo)
5825 s.serve_forever()
5824 s.serve_forever()
5826
5825
5827 service = server.createservice(ui, repo, opts)
5826 service = server.createservice(ui, repo, opts)
5828 return server.runservice(opts, initfn=service.init, runfn=service.run)
5827 return server.runservice(opts, initfn=service.init, runfn=service.run)
5829
5828
5830 @command('^status|st',
5829 @command('^status|st',
5831 [('A', 'all', None, _('show status of all files')),
5830 [('A', 'all', None, _('show status of all files')),
5832 ('m', 'modified', None, _('show only modified files')),
5831 ('m', 'modified', None, _('show only modified files')),
5833 ('a', 'added', None, _('show only added files')),
5832 ('a', 'added', None, _('show only added files')),
5834 ('r', 'removed', None, _('show only removed files')),
5833 ('r', 'removed', None, _('show only removed files')),
5835 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5834 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5836 ('c', 'clean', None, _('show only files without changes')),
5835 ('c', 'clean', None, _('show only files without changes')),
5837 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5836 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5838 ('i', 'ignored', None, _('show only ignored files')),
5837 ('i', 'ignored', None, _('show only ignored files')),
5839 ('n', 'no-status', None, _('hide status prefix')),
5838 ('n', 'no-status', None, _('hide status prefix')),
5840 ('C', 'copies', None, _('show source of copied files')),
5839 ('C', 'copies', None, _('show source of copied files')),
5841 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5840 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5842 ('', 'rev', [], _('show difference from revision'), _('REV')),
5841 ('', 'rev', [], _('show difference from revision'), _('REV')),
5843 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5842 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5844 ] + walkopts + subrepoopts + formatteropts,
5843 ] + walkopts + subrepoopts + formatteropts,
5845 _('[OPTION]... [FILE]...'),
5844 _('[OPTION]... [FILE]...'),
5846 inferrepo=True)
5845 inferrepo=True)
5847 def status(ui, repo, *pats, **opts):
5846 def status(ui, repo, *pats, **opts):
5848 """show changed files in the working directory
5847 """show changed files in the working directory
5849
5848
5850 Show status of files in the repository. If names are given, only
5849 Show status of files in the repository. If names are given, only
5851 files that match are shown. Files that are clean or ignored or
5850 files that match are shown. Files that are clean or ignored or
5852 the source of a copy/move operation, are not listed unless
5851 the source of a copy/move operation, are not listed unless
5853 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5852 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5854 Unless options described with "show only ..." are given, the
5853 Unless options described with "show only ..." are given, the
5855 options -mardu are used.
5854 options -mardu are used.
5856
5855
5857 Option -q/--quiet hides untracked (unknown and ignored) files
5856 Option -q/--quiet hides untracked (unknown and ignored) files
5858 unless explicitly requested with -u/--unknown or -i/--ignored.
5857 unless explicitly requested with -u/--unknown or -i/--ignored.
5859
5858
5860 .. note::
5859 .. note::
5861
5860
5862 :hg:`status` may appear to disagree with diff if permissions have
5861 :hg:`status` may appear to disagree with diff if permissions have
5863 changed or a merge has occurred. The standard diff format does
5862 changed or a merge has occurred. The standard diff format does
5864 not report permission changes and diff only reports changes
5863 not report permission changes and diff only reports changes
5865 relative to one merge parent.
5864 relative to one merge parent.
5866
5865
5867 If one revision is given, it is used as the base revision.
5866 If one revision is given, it is used as the base revision.
5868 If two revisions are given, the differences between them are
5867 If two revisions are given, the differences between them are
5869 shown. The --change option can also be used as a shortcut to list
5868 shown. The --change option can also be used as a shortcut to list
5870 the changed files of a revision from its first parent.
5869 the changed files of a revision from its first parent.
5871
5870
5872 The codes used to show the status of files are::
5871 The codes used to show the status of files are::
5873
5872
5874 M = modified
5873 M = modified
5875 A = added
5874 A = added
5876 R = removed
5875 R = removed
5877 C = clean
5876 C = clean
5878 ! = missing (deleted by non-hg command, but still tracked)
5877 ! = missing (deleted by non-hg command, but still tracked)
5879 ? = not tracked
5878 ? = not tracked
5880 I = ignored
5879 I = ignored
5881 = origin of the previous file (with --copies)
5880 = origin of the previous file (with --copies)
5882
5881
5883 .. container:: verbose
5882 .. container:: verbose
5884
5883
5885 Examples:
5884 Examples:
5886
5885
5887 - show changes in the working directory relative to a
5886 - show changes in the working directory relative to a
5888 changeset::
5887 changeset::
5889
5888
5890 hg status --rev 9353
5889 hg status --rev 9353
5891
5890
5892 - show changes in the working directory relative to the
5891 - show changes in the working directory relative to the
5893 current directory (see :hg:`help patterns` for more information)::
5892 current directory (see :hg:`help patterns` for more information)::
5894
5893
5895 hg status re:
5894 hg status re:
5896
5895
5897 - show all changes including copies in an existing changeset::
5896 - show all changes including copies in an existing changeset::
5898
5897
5899 hg status --copies --change 9353
5898 hg status --copies --change 9353
5900
5899
5901 - get a NUL separated list of added files, suitable for xargs::
5900 - get a NUL separated list of added files, suitable for xargs::
5902
5901
5903 hg status -an0
5902 hg status -an0
5904
5903
5905 Returns 0 on success.
5904 Returns 0 on success.
5906 """
5905 """
5907
5906
5908 revs = opts.get('rev')
5907 revs = opts.get('rev')
5909 change = opts.get('change')
5908 change = opts.get('change')
5910
5909
5911 if revs and change:
5910 if revs and change:
5912 msg = _('cannot specify --rev and --change at the same time')
5911 msg = _('cannot specify --rev and --change at the same time')
5913 raise error.Abort(msg)
5912 raise error.Abort(msg)
5914 elif change:
5913 elif change:
5915 node2 = scmutil.revsingle(repo, change, None).node()
5914 node2 = scmutil.revsingle(repo, change, None).node()
5916 node1 = repo[node2].p1().node()
5915 node1 = repo[node2].p1().node()
5917 else:
5916 else:
5918 node1, node2 = scmutil.revpair(repo, revs)
5917 node1, node2 = scmutil.revpair(repo, revs)
5919
5918
5920 if pats:
5919 if pats:
5921 cwd = repo.getcwd()
5920 cwd = repo.getcwd()
5922 else:
5921 else:
5923 cwd = ''
5922 cwd = ''
5924
5923
5925 if opts.get('print0'):
5924 if opts.get('print0'):
5926 end = '\0'
5925 end = '\0'
5927 else:
5926 else:
5928 end = '\n'
5927 end = '\n'
5929 copy = {}
5928 copy = {}
5930 states = 'modified added removed deleted unknown ignored clean'.split()
5929 states = 'modified added removed deleted unknown ignored clean'.split()
5931 show = [k for k in states if opts.get(k)]
5930 show = [k for k in states if opts.get(k)]
5932 if opts.get('all'):
5931 if opts.get('all'):
5933 show += ui.quiet and (states[:4] + ['clean']) or states
5932 show += ui.quiet and (states[:4] + ['clean']) or states
5934 if not show:
5933 if not show:
5935 if ui.quiet:
5934 if ui.quiet:
5936 show = states[:4]
5935 show = states[:4]
5937 else:
5936 else:
5938 show = states[:5]
5937 show = states[:5]
5939
5938
5940 m = scmutil.match(repo[node2], pats, opts)
5939 m = scmutil.match(repo[node2], pats, opts)
5941 stat = repo.status(node1, node2, m,
5940 stat = repo.status(node1, node2, m,
5942 'ignored' in show, 'clean' in show, 'unknown' in show,
5941 'ignored' in show, 'clean' in show, 'unknown' in show,
5943 opts.get('subrepos'))
5942 opts.get('subrepos'))
5944 changestates = zip(states, 'MAR!?IC', stat)
5943 changestates = zip(states, 'MAR!?IC', stat)
5945
5944
5946 if (opts.get('all') or opts.get('copies')
5945 if (opts.get('all') or opts.get('copies')
5947 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5946 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5948 copy = copies.pathcopies(repo[node1], repo[node2], m)
5947 copy = copies.pathcopies(repo[node1], repo[node2], m)
5949
5948
5950 fm = ui.formatter('status', opts)
5949 fm = ui.formatter('status', opts)
5951 fmt = '%s' + end
5950 fmt = '%s' + end
5952 showchar = not opts.get('no_status')
5951 showchar = not opts.get('no_status')
5953
5952
5954 for state, char, files in changestates:
5953 for state, char, files in changestates:
5955 if state in show:
5954 if state in show:
5956 label = 'status.' + state
5955 label = 'status.' + state
5957 for f in files:
5956 for f in files:
5958 fm.startitem()
5957 fm.startitem()
5959 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5958 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5960 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5959 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5961 if f in copy:
5960 if f in copy:
5962 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5961 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5963 label='status.copied')
5962 label='status.copied')
5964 fm.end()
5963 fm.end()
5965
5964
5966 @command('^summary|sum',
5965 @command('^summary|sum',
5967 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5966 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5968 def summary(ui, repo, **opts):
5967 def summary(ui, repo, **opts):
5969 """summarize working directory state
5968 """summarize working directory state
5970
5969
5971 This generates a brief summary of the working directory state,
5970 This generates a brief summary of the working directory state,
5972 including parents, branch, commit status, phase and available updates.
5971 including parents, branch, commit status, phase and available updates.
5973
5972
5974 With the --remote option, this will check the default paths for
5973 With the --remote option, this will check the default paths for
5975 incoming and outgoing changes. This can be time-consuming.
5974 incoming and outgoing changes. This can be time-consuming.
5976
5975
5977 Returns 0 on success.
5976 Returns 0 on success.
5978 """
5977 """
5979
5978
5980 ctx = repo[None]
5979 ctx = repo[None]
5981 parents = ctx.parents()
5980 parents = ctx.parents()
5982 pnode = parents[0].node()
5981 pnode = parents[0].node()
5983 marks = []
5982 marks = []
5984
5983
5985 ms = None
5984 ms = None
5986 try:
5985 try:
5987 ms = mergemod.mergestate.read(repo)
5986 ms = mergemod.mergestate.read(repo)
5988 except error.UnsupportedMergeRecords as e:
5987 except error.UnsupportedMergeRecords as e:
5989 s = ' '.join(e.recordtypes)
5988 s = ' '.join(e.recordtypes)
5990 ui.warn(
5989 ui.warn(
5991 _('warning: merge state has unsupported record types: %s\n') % s)
5990 _('warning: merge state has unsupported record types: %s\n') % s)
5992 unresolved = 0
5991 unresolved = 0
5993 else:
5992 else:
5994 unresolved = [f for f in ms if ms[f] == 'u']
5993 unresolved = [f for f in ms if ms[f] == 'u']
5995
5994
5996 for p in parents:
5995 for p in parents:
5997 # label with log.changeset (instead of log.parent) since this
5996 # label with log.changeset (instead of log.parent) since this
5998 # shows a working directory parent *changeset*:
5997 # shows a working directory parent *changeset*:
5999 # i18n: column positioning for "hg summary"
5998 # i18n: column positioning for "hg summary"
6000 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5999 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6001 label=cmdutil._changesetlabels(p))
6000 label=cmdutil._changesetlabels(p))
6002 ui.write(' '.join(p.tags()), label='log.tag')
6001 ui.write(' '.join(p.tags()), label='log.tag')
6003 if p.bookmarks():
6002 if p.bookmarks():
6004 marks.extend(p.bookmarks())
6003 marks.extend(p.bookmarks())
6005 if p.rev() == -1:
6004 if p.rev() == -1:
6006 if not len(repo):
6005 if not len(repo):
6007 ui.write(_(' (empty repository)'))
6006 ui.write(_(' (empty repository)'))
6008 else:
6007 else:
6009 ui.write(_(' (no revision checked out)'))
6008 ui.write(_(' (no revision checked out)'))
6010 if p.troubled():
6009 if p.troubled():
6011 ui.write(' ('
6010 ui.write(' ('
6012 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
6011 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
6013 for trouble in p.troubles())
6012 for trouble in p.troubles())
6014 + ')')
6013 + ')')
6015 ui.write('\n')
6014 ui.write('\n')
6016 if p.description():
6015 if p.description():
6017 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6016 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6018 label='log.summary')
6017 label='log.summary')
6019
6018
6020 branch = ctx.branch()
6019 branch = ctx.branch()
6021 bheads = repo.branchheads(branch)
6020 bheads = repo.branchheads(branch)
6022 # i18n: column positioning for "hg summary"
6021 # i18n: column positioning for "hg summary"
6023 m = _('branch: %s\n') % branch
6022 m = _('branch: %s\n') % branch
6024 if branch != 'default':
6023 if branch != 'default':
6025 ui.write(m, label='log.branch')
6024 ui.write(m, label='log.branch')
6026 else:
6025 else:
6027 ui.status(m, label='log.branch')
6026 ui.status(m, label='log.branch')
6028
6027
6029 if marks:
6028 if marks:
6030 active = repo._activebookmark
6029 active = repo._activebookmark
6031 # i18n: column positioning for "hg summary"
6030 # i18n: column positioning for "hg summary"
6032 ui.write(_('bookmarks:'), label='log.bookmark')
6031 ui.write(_('bookmarks:'), label='log.bookmark')
6033 if active is not None:
6032 if active is not None:
6034 if active in marks:
6033 if active in marks:
6035 ui.write(' *' + active, label=activebookmarklabel)
6034 ui.write(' *' + active, label=activebookmarklabel)
6036 marks.remove(active)
6035 marks.remove(active)
6037 else:
6036 else:
6038 ui.write(' [%s]' % active, label=activebookmarklabel)
6037 ui.write(' [%s]' % active, label=activebookmarklabel)
6039 for m in marks:
6038 for m in marks:
6040 ui.write(' ' + m, label='log.bookmark')
6039 ui.write(' ' + m, label='log.bookmark')
6041 ui.write('\n', label='log.bookmark')
6040 ui.write('\n', label='log.bookmark')
6042
6041
6043 status = repo.status(unknown=True)
6042 status = repo.status(unknown=True)
6044
6043
6045 c = repo.dirstate.copies()
6044 c = repo.dirstate.copies()
6046 copied, renamed = [], []
6045 copied, renamed = [], []
6047 for d, s in c.iteritems():
6046 for d, s in c.iteritems():
6048 if s in status.removed:
6047 if s in status.removed:
6049 status.removed.remove(s)
6048 status.removed.remove(s)
6050 renamed.append(d)
6049 renamed.append(d)
6051 else:
6050 else:
6052 copied.append(d)
6051 copied.append(d)
6053 if d in status.added:
6052 if d in status.added:
6054 status.added.remove(d)
6053 status.added.remove(d)
6055
6054
6056 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6055 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6057
6056
6058 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6057 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6059 (ui.label(_('%d added'), 'status.added'), status.added),
6058 (ui.label(_('%d added'), 'status.added'), status.added),
6060 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6059 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6061 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6060 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6062 (ui.label(_('%d copied'), 'status.copied'), copied),
6061 (ui.label(_('%d copied'), 'status.copied'), copied),
6063 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6062 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6064 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6063 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6065 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6064 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6066 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6065 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6067 t = []
6066 t = []
6068 for l, s in labels:
6067 for l, s in labels:
6069 if s:
6068 if s:
6070 t.append(l % len(s))
6069 t.append(l % len(s))
6071
6070
6072 t = ', '.join(t)
6071 t = ', '.join(t)
6073 cleanworkdir = False
6072 cleanworkdir = False
6074
6073
6075 if repo.vfs.exists('graftstate'):
6074 if repo.vfs.exists('graftstate'):
6076 t += _(' (graft in progress)')
6075 t += _(' (graft in progress)')
6077 if repo.vfs.exists('updatestate'):
6076 if repo.vfs.exists('updatestate'):
6078 t += _(' (interrupted update)')
6077 t += _(' (interrupted update)')
6079 elif len(parents) > 1:
6078 elif len(parents) > 1:
6080 t += _(' (merge)')
6079 t += _(' (merge)')
6081 elif branch != parents[0].branch():
6080 elif branch != parents[0].branch():
6082 t += _(' (new branch)')
6081 t += _(' (new branch)')
6083 elif (parents[0].closesbranch() and
6082 elif (parents[0].closesbranch() and
6084 pnode in repo.branchheads(branch, closed=True)):
6083 pnode in repo.branchheads(branch, closed=True)):
6085 t += _(' (head closed)')
6084 t += _(' (head closed)')
6086 elif not (status.modified or status.added or status.removed or renamed or
6085 elif not (status.modified or status.added or status.removed or renamed or
6087 copied or subs):
6086 copied or subs):
6088 t += _(' (clean)')
6087 t += _(' (clean)')
6089 cleanworkdir = True
6088 cleanworkdir = True
6090 elif pnode not in bheads:
6089 elif pnode not in bheads:
6091 t += _(' (new branch head)')
6090 t += _(' (new branch head)')
6092
6091
6093 if parents:
6092 if parents:
6094 pendingphase = max(p.phase() for p in parents)
6093 pendingphase = max(p.phase() for p in parents)
6095 else:
6094 else:
6096 pendingphase = phases.public
6095 pendingphase = phases.public
6097
6096
6098 if pendingphase > phases.newcommitphase(ui):
6097 if pendingphase > phases.newcommitphase(ui):
6099 t += ' (%s)' % phases.phasenames[pendingphase]
6098 t += ' (%s)' % phases.phasenames[pendingphase]
6100
6099
6101 if cleanworkdir:
6100 if cleanworkdir:
6102 # i18n: column positioning for "hg summary"
6101 # i18n: column positioning for "hg summary"
6103 ui.status(_('commit: %s\n') % t.strip())
6102 ui.status(_('commit: %s\n') % t.strip())
6104 else:
6103 else:
6105 # i18n: column positioning for "hg summary"
6104 # i18n: column positioning for "hg summary"
6106 ui.write(_('commit: %s\n') % t.strip())
6105 ui.write(_('commit: %s\n') % t.strip())
6107
6106
6108 # all ancestors of branch heads - all ancestors of parent = new csets
6107 # all ancestors of branch heads - all ancestors of parent = new csets
6109 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6108 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6110 bheads))
6109 bheads))
6111
6110
6112 if new == 0:
6111 if new == 0:
6113 # i18n: column positioning for "hg summary"
6112 # i18n: column positioning for "hg summary"
6114 ui.status(_('update: (current)\n'))
6113 ui.status(_('update: (current)\n'))
6115 elif pnode not in bheads:
6114 elif pnode not in bheads:
6116 # i18n: column positioning for "hg summary"
6115 # i18n: column positioning for "hg summary"
6117 ui.write(_('update: %d new changesets (update)\n') % new)
6116 ui.write(_('update: %d new changesets (update)\n') % new)
6118 else:
6117 else:
6119 # i18n: column positioning for "hg summary"
6118 # i18n: column positioning for "hg summary"
6120 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6119 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6121 (new, len(bheads)))
6120 (new, len(bheads)))
6122
6121
6123 t = []
6122 t = []
6124 draft = len(repo.revs('draft()'))
6123 draft = len(repo.revs('draft()'))
6125 if draft:
6124 if draft:
6126 t.append(_('%d draft') % draft)
6125 t.append(_('%d draft') % draft)
6127 secret = len(repo.revs('secret()'))
6126 secret = len(repo.revs('secret()'))
6128 if secret:
6127 if secret:
6129 t.append(_('%d secret') % secret)
6128 t.append(_('%d secret') % secret)
6130
6129
6131 if draft or secret:
6130 if draft or secret:
6132 ui.status(_('phases: %s\n') % ', '.join(t))
6131 ui.status(_('phases: %s\n') % ', '.join(t))
6133
6132
6134 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6133 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6135 for trouble in ("unstable", "divergent", "bumped"):
6134 for trouble in ("unstable", "divergent", "bumped"):
6136 numtrouble = len(repo.revs(trouble + "()"))
6135 numtrouble = len(repo.revs(trouble + "()"))
6137 # We write all the possibilities to ease translation
6136 # We write all the possibilities to ease translation
6138 troublemsg = {
6137 troublemsg = {
6139 "unstable": _("unstable: %d changesets"),
6138 "unstable": _("unstable: %d changesets"),
6140 "divergent": _("divergent: %d changesets"),
6139 "divergent": _("divergent: %d changesets"),
6141 "bumped": _("bumped: %d changesets"),
6140 "bumped": _("bumped: %d changesets"),
6142 }
6141 }
6143 if numtrouble > 0:
6142 if numtrouble > 0:
6144 ui.status(troublemsg[trouble] % numtrouble + "\n")
6143 ui.status(troublemsg[trouble] % numtrouble + "\n")
6145
6144
6146 cmdutil.summaryhooks(ui, repo)
6145 cmdutil.summaryhooks(ui, repo)
6147
6146
6148 if opts.get('remote'):
6147 if opts.get('remote'):
6149 needsincoming, needsoutgoing = True, True
6148 needsincoming, needsoutgoing = True, True
6150 else:
6149 else:
6151 needsincoming, needsoutgoing = False, False
6150 needsincoming, needsoutgoing = False, False
6152 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6151 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6153 if i:
6152 if i:
6154 needsincoming = True
6153 needsincoming = True
6155 if o:
6154 if o:
6156 needsoutgoing = True
6155 needsoutgoing = True
6157 if not needsincoming and not needsoutgoing:
6156 if not needsincoming and not needsoutgoing:
6158 return
6157 return
6159
6158
6160 def getincoming():
6159 def getincoming():
6161 source, branches = hg.parseurl(ui.expandpath('default'))
6160 source, branches = hg.parseurl(ui.expandpath('default'))
6162 sbranch = branches[0]
6161 sbranch = branches[0]
6163 try:
6162 try:
6164 other = hg.peer(repo, {}, source)
6163 other = hg.peer(repo, {}, source)
6165 except error.RepoError:
6164 except error.RepoError:
6166 if opts.get('remote'):
6165 if opts.get('remote'):
6167 raise
6166 raise
6168 return source, sbranch, None, None, None
6167 return source, sbranch, None, None, None
6169 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6168 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6170 if revs:
6169 if revs:
6171 revs = [other.lookup(rev) for rev in revs]
6170 revs = [other.lookup(rev) for rev in revs]
6172 ui.debug('comparing with %s\n' % util.hidepassword(source))
6171 ui.debug('comparing with %s\n' % util.hidepassword(source))
6173 repo.ui.pushbuffer()
6172 repo.ui.pushbuffer()
6174 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6173 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6175 repo.ui.popbuffer()
6174 repo.ui.popbuffer()
6176 return source, sbranch, other, commoninc, commoninc[1]
6175 return source, sbranch, other, commoninc, commoninc[1]
6177
6176
6178 if needsincoming:
6177 if needsincoming:
6179 source, sbranch, sother, commoninc, incoming = getincoming()
6178 source, sbranch, sother, commoninc, incoming = getincoming()
6180 else:
6179 else:
6181 source = sbranch = sother = commoninc = incoming = None
6180 source = sbranch = sother = commoninc = incoming = None
6182
6181
6183 def getoutgoing():
6182 def getoutgoing():
6184 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6183 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6185 dbranch = branches[0]
6184 dbranch = branches[0]
6186 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6185 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6187 if source != dest:
6186 if source != dest:
6188 try:
6187 try:
6189 dother = hg.peer(repo, {}, dest)
6188 dother = hg.peer(repo, {}, dest)
6190 except error.RepoError:
6189 except error.RepoError:
6191 if opts.get('remote'):
6190 if opts.get('remote'):
6192 raise
6191 raise
6193 return dest, dbranch, None, None
6192 return dest, dbranch, None, None
6194 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6193 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6195 elif sother is None:
6194 elif sother is None:
6196 # there is no explicit destination peer, but source one is invalid
6195 # there is no explicit destination peer, but source one is invalid
6197 return dest, dbranch, None, None
6196 return dest, dbranch, None, None
6198 else:
6197 else:
6199 dother = sother
6198 dother = sother
6200 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6199 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6201 common = None
6200 common = None
6202 else:
6201 else:
6203 common = commoninc
6202 common = commoninc
6204 if revs:
6203 if revs:
6205 revs = [repo.lookup(rev) for rev in revs]
6204 revs = [repo.lookup(rev) for rev in revs]
6206 repo.ui.pushbuffer()
6205 repo.ui.pushbuffer()
6207 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6206 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6208 commoninc=common)
6207 commoninc=common)
6209 repo.ui.popbuffer()
6208 repo.ui.popbuffer()
6210 return dest, dbranch, dother, outgoing
6209 return dest, dbranch, dother, outgoing
6211
6210
6212 if needsoutgoing:
6211 if needsoutgoing:
6213 dest, dbranch, dother, outgoing = getoutgoing()
6212 dest, dbranch, dother, outgoing = getoutgoing()
6214 else:
6213 else:
6215 dest = dbranch = dother = outgoing = None
6214 dest = dbranch = dother = outgoing = None
6216
6215
6217 if opts.get('remote'):
6216 if opts.get('remote'):
6218 t = []
6217 t = []
6219 if incoming:
6218 if incoming:
6220 t.append(_('1 or more incoming'))
6219 t.append(_('1 or more incoming'))
6221 o = outgoing.missing
6220 o = outgoing.missing
6222 if o:
6221 if o:
6223 t.append(_('%d outgoing') % len(o))
6222 t.append(_('%d outgoing') % len(o))
6224 other = dother or sother
6223 other = dother or sother
6225 if 'bookmarks' in other.listkeys('namespaces'):
6224 if 'bookmarks' in other.listkeys('namespaces'):
6226 counts = bookmarks.summary(repo, other)
6225 counts = bookmarks.summary(repo, other)
6227 if counts[0] > 0:
6226 if counts[0] > 0:
6228 t.append(_('%d incoming bookmarks') % counts[0])
6227 t.append(_('%d incoming bookmarks') % counts[0])
6229 if counts[1] > 0:
6228 if counts[1] > 0:
6230 t.append(_('%d outgoing bookmarks') % counts[1])
6229 t.append(_('%d outgoing bookmarks') % counts[1])
6231
6230
6232 if t:
6231 if t:
6233 # i18n: column positioning for "hg summary"
6232 # i18n: column positioning for "hg summary"
6234 ui.write(_('remote: %s\n') % (', '.join(t)))
6233 ui.write(_('remote: %s\n') % (', '.join(t)))
6235 else:
6234 else:
6236 # i18n: column positioning for "hg summary"
6235 # i18n: column positioning for "hg summary"
6237 ui.status(_('remote: (synced)\n'))
6236 ui.status(_('remote: (synced)\n'))
6238
6237
6239 cmdutil.summaryremotehooks(ui, repo, opts,
6238 cmdutil.summaryremotehooks(ui, repo, opts,
6240 ((source, sbranch, sother, commoninc),
6239 ((source, sbranch, sother, commoninc),
6241 (dest, dbranch, dother, outgoing)))
6240 (dest, dbranch, dother, outgoing)))
6242
6241
6243 @command('tag',
6242 @command('tag',
6244 [('f', 'force', None, _('force tag')),
6243 [('f', 'force', None, _('force tag')),
6245 ('l', 'local', None, _('make the tag local')),
6244 ('l', 'local', None, _('make the tag local')),
6246 ('r', 'rev', '', _('revision to tag'), _('REV')),
6245 ('r', 'rev', '', _('revision to tag'), _('REV')),
6247 ('', 'remove', None, _('remove a tag')),
6246 ('', 'remove', None, _('remove a tag')),
6248 # -l/--local is already there, commitopts cannot be used
6247 # -l/--local is already there, commitopts cannot be used
6249 ('e', 'edit', None, _('invoke editor on commit messages')),
6248 ('e', 'edit', None, _('invoke editor on commit messages')),
6250 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6249 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6251 ] + commitopts2,
6250 ] + commitopts2,
6252 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6251 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6253 def tag(ui, repo, name1, *names, **opts):
6252 def tag(ui, repo, name1, *names, **opts):
6254 """add one or more tags for the current or given revision
6253 """add one or more tags for the current or given revision
6255
6254
6256 Name a particular revision using <name>.
6255 Name a particular revision using <name>.
6257
6256
6258 Tags are used to name particular revisions of the repository and are
6257 Tags are used to name particular revisions of the repository and are
6259 very useful to compare different revisions, to go back to significant
6258 very useful to compare different revisions, to go back to significant
6260 earlier versions or to mark branch points as releases, etc. Changing
6259 earlier versions or to mark branch points as releases, etc. Changing
6261 an existing tag is normally disallowed; use -f/--force to override.
6260 an existing tag is normally disallowed; use -f/--force to override.
6262
6261
6263 If no revision is given, the parent of the working directory is
6262 If no revision is given, the parent of the working directory is
6264 used.
6263 used.
6265
6264
6266 To facilitate version control, distribution, and merging of tags,
6265 To facilitate version control, distribution, and merging of tags,
6267 they are stored as a file named ".hgtags" which is managed similarly
6266 they are stored as a file named ".hgtags" which is managed similarly
6268 to other project files and can be hand-edited if necessary. This
6267 to other project files and can be hand-edited if necessary. This
6269 also means that tagging creates a new commit. The file
6268 also means that tagging creates a new commit. The file
6270 ".hg/localtags" is used for local tags (not shared among
6269 ".hg/localtags" is used for local tags (not shared among
6271 repositories).
6270 repositories).
6272
6271
6273 Tag commits are usually made at the head of a branch. If the parent
6272 Tag commits are usually made at the head of a branch. If the parent
6274 of the working directory is not a branch head, :hg:`tag` aborts; use
6273 of the working directory is not a branch head, :hg:`tag` aborts; use
6275 -f/--force to force the tag commit to be based on a non-head
6274 -f/--force to force the tag commit to be based on a non-head
6276 changeset.
6275 changeset.
6277
6276
6278 See :hg:`help dates` for a list of formats valid for -d/--date.
6277 See :hg:`help dates` for a list of formats valid for -d/--date.
6279
6278
6280 Since tag names have priority over branch names during revision
6279 Since tag names have priority over branch names during revision
6281 lookup, using an existing branch name as a tag name is discouraged.
6280 lookup, using an existing branch name as a tag name is discouraged.
6282
6281
6283 Returns 0 on success.
6282 Returns 0 on success.
6284 """
6283 """
6285 wlock = lock = None
6284 wlock = lock = None
6286 try:
6285 try:
6287 wlock = repo.wlock()
6286 wlock = repo.wlock()
6288 lock = repo.lock()
6287 lock = repo.lock()
6289 rev_ = "."
6288 rev_ = "."
6290 names = [t.strip() for t in (name1,) + names]
6289 names = [t.strip() for t in (name1,) + names]
6291 if len(names) != len(set(names)):
6290 if len(names) != len(set(names)):
6292 raise error.Abort(_('tag names must be unique'))
6291 raise error.Abort(_('tag names must be unique'))
6293 for n in names:
6292 for n in names:
6294 scmutil.checknewlabel(repo, n, 'tag')
6293 scmutil.checknewlabel(repo, n, 'tag')
6295 if not n:
6294 if not n:
6296 raise error.Abort(_('tag names cannot consist entirely of '
6295 raise error.Abort(_('tag names cannot consist entirely of '
6297 'whitespace'))
6296 'whitespace'))
6298 if opts.get('rev') and opts.get('remove'):
6297 if opts.get('rev') and opts.get('remove'):
6299 raise error.Abort(_("--rev and --remove are incompatible"))
6298 raise error.Abort(_("--rev and --remove are incompatible"))
6300 if opts.get('rev'):
6299 if opts.get('rev'):
6301 rev_ = opts['rev']
6300 rev_ = opts['rev']
6302 message = opts.get('message')
6301 message = opts.get('message')
6303 if opts.get('remove'):
6302 if opts.get('remove'):
6304 if opts.get('local'):
6303 if opts.get('local'):
6305 expectedtype = 'local'
6304 expectedtype = 'local'
6306 else:
6305 else:
6307 expectedtype = 'global'
6306 expectedtype = 'global'
6308
6307
6309 for n in names:
6308 for n in names:
6310 if not repo.tagtype(n):
6309 if not repo.tagtype(n):
6311 raise error.Abort(_("tag '%s' does not exist") % n)
6310 raise error.Abort(_("tag '%s' does not exist") % n)
6312 if repo.tagtype(n) != expectedtype:
6311 if repo.tagtype(n) != expectedtype:
6313 if expectedtype == 'global':
6312 if expectedtype == 'global':
6314 raise error.Abort(_("tag '%s' is not a global tag") % n)
6313 raise error.Abort(_("tag '%s' is not a global tag") % n)
6315 else:
6314 else:
6316 raise error.Abort(_("tag '%s' is not a local tag") % n)
6315 raise error.Abort(_("tag '%s' is not a local tag") % n)
6317 rev_ = 'null'
6316 rev_ = 'null'
6318 if not message:
6317 if not message:
6319 # we don't translate commit messages
6318 # we don't translate commit messages
6320 message = 'Removed tag %s' % ', '.join(names)
6319 message = 'Removed tag %s' % ', '.join(names)
6321 elif not opts.get('force'):
6320 elif not opts.get('force'):
6322 for n in names:
6321 for n in names:
6323 if n in repo.tags():
6322 if n in repo.tags():
6324 raise error.Abort(_("tag '%s' already exists "
6323 raise error.Abort(_("tag '%s' already exists "
6325 "(use -f to force)") % n)
6324 "(use -f to force)") % n)
6326 if not opts.get('local'):
6325 if not opts.get('local'):
6327 p1, p2 = repo.dirstate.parents()
6326 p1, p2 = repo.dirstate.parents()
6328 if p2 != nullid:
6327 if p2 != nullid:
6329 raise error.Abort(_('uncommitted merge'))
6328 raise error.Abort(_('uncommitted merge'))
6330 bheads = repo.branchheads()
6329 bheads = repo.branchheads()
6331 if not opts.get('force') and bheads and p1 not in bheads:
6330 if not opts.get('force') and bheads and p1 not in bheads:
6332 raise error.Abort(_('working directory is not at a branch head '
6331 raise error.Abort(_('working directory is not at a branch head '
6333 '(use -f to force)'))
6332 '(use -f to force)'))
6334 r = scmutil.revsingle(repo, rev_).node()
6333 r = scmutil.revsingle(repo, rev_).node()
6335
6334
6336 if not message:
6335 if not message:
6337 # we don't translate commit messages
6336 # we don't translate commit messages
6338 message = ('Added tag %s for changeset %s' %
6337 message = ('Added tag %s for changeset %s' %
6339 (', '.join(names), short(r)))
6338 (', '.join(names), short(r)))
6340
6339
6341 date = opts.get('date')
6340 date = opts.get('date')
6342 if date:
6341 if date:
6343 date = util.parsedate(date)
6342 date = util.parsedate(date)
6344
6343
6345 if opts.get('remove'):
6344 if opts.get('remove'):
6346 editform = 'tag.remove'
6345 editform = 'tag.remove'
6347 else:
6346 else:
6348 editform = 'tag.add'
6347 editform = 'tag.add'
6349 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6348 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6350
6349
6351 # don't allow tagging the null rev
6350 # don't allow tagging the null rev
6352 if (not opts.get('remove') and
6351 if (not opts.get('remove') and
6353 scmutil.revsingle(repo, rev_).rev() == nullrev):
6352 scmutil.revsingle(repo, rev_).rev() == nullrev):
6354 raise error.Abort(_("cannot tag null revision"))
6353 raise error.Abort(_("cannot tag null revision"))
6355
6354
6356 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6355 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6357 editor=editor)
6356 editor=editor)
6358 finally:
6357 finally:
6359 release(lock, wlock)
6358 release(lock, wlock)
6360
6359
6361 @command('tags', formatteropts, '')
6360 @command('tags', formatteropts, '')
6362 def tags(ui, repo, **opts):
6361 def tags(ui, repo, **opts):
6363 """list repository tags
6362 """list repository tags
6364
6363
6365 This lists both regular and local tags. When the -v/--verbose
6364 This lists both regular and local tags. When the -v/--verbose
6366 switch is used, a third column "local" is printed for local tags.
6365 switch is used, a third column "local" is printed for local tags.
6367 When the -q/--quiet switch is used, only the tag name is printed.
6366 When the -q/--quiet switch is used, only the tag name is printed.
6368
6367
6369 Returns 0 on success.
6368 Returns 0 on success.
6370 """
6369 """
6371
6370
6372 fm = ui.formatter('tags', opts)
6371 fm = ui.formatter('tags', opts)
6373 hexfunc = fm.hexfunc
6372 hexfunc = fm.hexfunc
6374 tagtype = ""
6373 tagtype = ""
6375
6374
6376 for t, n in reversed(repo.tagslist()):
6375 for t, n in reversed(repo.tagslist()):
6377 hn = hexfunc(n)
6376 hn = hexfunc(n)
6378 label = 'tags.normal'
6377 label = 'tags.normal'
6379 tagtype = ''
6378 tagtype = ''
6380 if repo.tagtype(t) == 'local':
6379 if repo.tagtype(t) == 'local':
6381 label = 'tags.local'
6380 label = 'tags.local'
6382 tagtype = 'local'
6381 tagtype = 'local'
6383
6382
6384 fm.startitem()
6383 fm.startitem()
6385 fm.write('tag', '%s', t, label=label)
6384 fm.write('tag', '%s', t, label=label)
6386 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6385 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6387 fm.condwrite(not ui.quiet, 'rev node', fmt,
6386 fm.condwrite(not ui.quiet, 'rev node', fmt,
6388 repo.changelog.rev(n), hn, label=label)
6387 repo.changelog.rev(n), hn, label=label)
6389 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6388 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6390 tagtype, label=label)
6389 tagtype, label=label)
6391 fm.plain('\n')
6390 fm.plain('\n')
6392 fm.end()
6391 fm.end()
6393
6392
6394 @command('tip',
6393 @command('tip',
6395 [('p', 'patch', None, _('show patch')),
6394 [('p', 'patch', None, _('show patch')),
6396 ('g', 'git', None, _('use git extended diff format')),
6395 ('g', 'git', None, _('use git extended diff format')),
6397 ] + templateopts,
6396 ] + templateopts,
6398 _('[-p] [-g]'))
6397 _('[-p] [-g]'))
6399 def tip(ui, repo, **opts):
6398 def tip(ui, repo, **opts):
6400 """show the tip revision (DEPRECATED)
6399 """show the tip revision (DEPRECATED)
6401
6400
6402 The tip revision (usually just called the tip) is the changeset
6401 The tip revision (usually just called the tip) is the changeset
6403 most recently added to the repository (and therefore the most
6402 most recently added to the repository (and therefore the most
6404 recently changed head).
6403 recently changed head).
6405
6404
6406 If you have just made a commit, that commit will be the tip. If
6405 If you have just made a commit, that commit will be the tip. If
6407 you have just pulled changes from another repository, the tip of
6406 you have just pulled changes from another repository, the tip of
6408 that repository becomes the current tip. The "tip" tag is special
6407 that repository becomes the current tip. The "tip" tag is special
6409 and cannot be renamed or assigned to a different changeset.
6408 and cannot be renamed or assigned to a different changeset.
6410
6409
6411 This command is deprecated, please use :hg:`heads` instead.
6410 This command is deprecated, please use :hg:`heads` instead.
6412
6411
6413 Returns 0 on success.
6412 Returns 0 on success.
6414 """
6413 """
6415 displayer = cmdutil.show_changeset(ui, repo, opts)
6414 displayer = cmdutil.show_changeset(ui, repo, opts)
6416 displayer.show(repo['tip'])
6415 displayer.show(repo['tip'])
6417 displayer.close()
6416 displayer.close()
6418
6417
6419 @command('unbundle',
6418 @command('unbundle',
6420 [('u', 'update', None,
6419 [('u', 'update', None,
6421 _('update to new branch head if changesets were unbundled'))],
6420 _('update to new branch head if changesets were unbundled'))],
6422 _('[-u] FILE...'))
6421 _('[-u] FILE...'))
6423 def unbundle(ui, repo, fname1, *fnames, **opts):
6422 def unbundle(ui, repo, fname1, *fnames, **opts):
6424 """apply one or more changegroup files
6423 """apply one or more changegroup files
6425
6424
6426 Apply one or more compressed changegroup files generated by the
6425 Apply one or more compressed changegroup files generated by the
6427 bundle command.
6426 bundle command.
6428
6427
6429 Returns 0 on success, 1 if an update has unresolved files.
6428 Returns 0 on success, 1 if an update has unresolved files.
6430 """
6429 """
6431 fnames = (fname1,) + fnames
6430 fnames = (fname1,) + fnames
6432
6431
6433 with repo.lock():
6432 with repo.lock():
6434 for fname in fnames:
6433 for fname in fnames:
6435 f = hg.openpath(ui, fname)
6434 f = hg.openpath(ui, fname)
6436 gen = exchange.readbundle(ui, f, fname)
6435 gen = exchange.readbundle(ui, f, fname)
6437 if isinstance(gen, bundle2.unbundle20):
6436 if isinstance(gen, bundle2.unbundle20):
6438 tr = repo.transaction('unbundle')
6437 tr = repo.transaction('unbundle')
6439 try:
6438 try:
6440 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6439 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6441 url='bundle:' + fname)
6440 url='bundle:' + fname)
6442 tr.close()
6441 tr.close()
6443 except error.BundleUnknownFeatureError as exc:
6442 except error.BundleUnknownFeatureError as exc:
6444 raise error.Abort(_('%s: unknown bundle feature, %s')
6443 raise error.Abort(_('%s: unknown bundle feature, %s')
6445 % (fname, exc),
6444 % (fname, exc),
6446 hint=_("see https://mercurial-scm.org/"
6445 hint=_("see https://mercurial-scm.org/"
6447 "wiki/BundleFeature for more "
6446 "wiki/BundleFeature for more "
6448 "information"))
6447 "information"))
6449 finally:
6448 finally:
6450 if tr:
6449 if tr:
6451 tr.release()
6450 tr.release()
6452 changes = [r.get('return', 0)
6451 changes = [r.get('return', 0)
6453 for r in op.records['changegroup']]
6452 for r in op.records['changegroup']]
6454 modheads = changegroup.combineresults(changes)
6453 modheads = changegroup.combineresults(changes)
6455 elif isinstance(gen, streamclone.streamcloneapplier):
6454 elif isinstance(gen, streamclone.streamcloneapplier):
6456 raise error.Abort(
6455 raise error.Abort(
6457 _('packed bundles cannot be applied with '
6456 _('packed bundles cannot be applied with '
6458 '"hg unbundle"'),
6457 '"hg unbundle"'),
6459 hint=_('use "hg debugapplystreamclonebundle"'))
6458 hint=_('use "hg debugapplystreamclonebundle"'))
6460 else:
6459 else:
6461 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6460 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6462
6461
6463 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6462 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6464
6463
6465 @command('^update|up|checkout|co',
6464 @command('^update|up|checkout|co',
6466 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6465 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6467 ('c', 'check', None, _('require clean working directory')),
6466 ('c', 'check', None, _('require clean working directory')),
6468 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6467 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6469 ('r', 'rev', '', _('revision'), _('REV'))
6468 ('r', 'rev', '', _('revision'), _('REV'))
6470 ] + mergetoolopts,
6469 ] + mergetoolopts,
6471 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6470 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6472 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6471 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6473 tool=None):
6472 tool=None):
6474 """update working directory (or switch revisions)
6473 """update working directory (or switch revisions)
6475
6474
6476 Update the repository's working directory to the specified
6475 Update the repository's working directory to the specified
6477 changeset. If no changeset is specified, update to the tip of the
6476 changeset. If no changeset is specified, update to the tip of the
6478 current named branch and move the active bookmark (see :hg:`help
6477 current named branch and move the active bookmark (see :hg:`help
6479 bookmarks`).
6478 bookmarks`).
6480
6479
6481 Update sets the working directory's parent revision to the specified
6480 Update sets the working directory's parent revision to the specified
6482 changeset (see :hg:`help parents`).
6481 changeset (see :hg:`help parents`).
6483
6482
6484 If the changeset is not a descendant or ancestor of the working
6483 If the changeset is not a descendant or ancestor of the working
6485 directory's parent, the update is aborted. With the -c/--check
6484 directory's parent, the update is aborted. With the -c/--check
6486 option, the working directory is checked for uncommitted changes; if
6485 option, the working directory is checked for uncommitted changes; if
6487 none are found, the working directory is updated to the specified
6486 none are found, the working directory is updated to the specified
6488 changeset.
6487 changeset.
6489
6488
6490 .. container:: verbose
6489 .. container:: verbose
6491
6490
6492 The following rules apply when the working directory contains
6491 The following rules apply when the working directory contains
6493 uncommitted changes:
6492 uncommitted changes:
6494
6493
6495 1. If neither -c/--check nor -C/--clean is specified, and if
6494 1. If neither -c/--check nor -C/--clean is specified, and if
6496 the requested changeset is an ancestor or descendant of
6495 the requested changeset is an ancestor or descendant of
6497 the working directory's parent, the uncommitted changes
6496 the working directory's parent, the uncommitted changes
6498 are merged into the requested changeset and the merged
6497 are merged into the requested changeset and the merged
6499 result is left uncommitted. If the requested changeset is
6498 result is left uncommitted. If the requested changeset is
6500 not an ancestor or descendant (that is, it is on another
6499 not an ancestor or descendant (that is, it is on another
6501 branch), the update is aborted and the uncommitted changes
6500 branch), the update is aborted and the uncommitted changes
6502 are preserved.
6501 are preserved.
6503
6502
6504 2. With the -c/--check option, the update is aborted and the
6503 2. With the -c/--check option, the update is aborted and the
6505 uncommitted changes are preserved.
6504 uncommitted changes are preserved.
6506
6505
6507 3. With the -C/--clean option, uncommitted changes are discarded and
6506 3. With the -C/--clean option, uncommitted changes are discarded and
6508 the working directory is updated to the requested changeset.
6507 the working directory is updated to the requested changeset.
6509
6508
6510 To cancel an uncommitted merge (and lose your changes), use
6509 To cancel an uncommitted merge (and lose your changes), use
6511 :hg:`update --clean .`.
6510 :hg:`update --clean .`.
6512
6511
6513 Use null as the changeset to remove the working directory (like
6512 Use null as the changeset to remove the working directory (like
6514 :hg:`clone -U`).
6513 :hg:`clone -U`).
6515
6514
6516 If you want to revert just one file to an older revision, use
6515 If you want to revert just one file to an older revision, use
6517 :hg:`revert [-r REV] NAME`.
6516 :hg:`revert [-r REV] NAME`.
6518
6517
6519 See :hg:`help dates` for a list of formats valid for -d/--date.
6518 See :hg:`help dates` for a list of formats valid for -d/--date.
6520
6519
6521 Returns 0 on success, 1 if there are unresolved files.
6520 Returns 0 on success, 1 if there are unresolved files.
6522 """
6521 """
6523 if rev and node:
6522 if rev and node:
6524 raise error.Abort(_("please specify just one revision"))
6523 raise error.Abort(_("please specify just one revision"))
6525
6524
6526 if rev is None or rev == '':
6525 if rev is None or rev == '':
6527 rev = node
6526 rev = node
6528
6527
6529 if date and rev is not None:
6528 if date and rev is not None:
6530 raise error.Abort(_("you can't specify a revision and a date"))
6529 raise error.Abort(_("you can't specify a revision and a date"))
6531
6530
6532 if check and clean:
6531 if check and clean:
6533 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6532 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
6534
6533
6535 with repo.wlock():
6534 with repo.wlock():
6536 cmdutil.clearunfinished(repo)
6535 cmdutil.clearunfinished(repo)
6537
6536
6538 if date:
6537 if date:
6539 rev = cmdutil.finddate(ui, repo, date)
6538 rev = cmdutil.finddate(ui, repo, date)
6540
6539
6541 # if we defined a bookmark, we have to remember the original name
6540 # if we defined a bookmark, we have to remember the original name
6542 brev = rev
6541 brev = rev
6543 rev = scmutil.revsingle(repo, rev, rev).rev()
6542 rev = scmutil.revsingle(repo, rev, rev).rev()
6544
6543
6545 if check:
6544 if check:
6546 cmdutil.bailifchanged(repo, merge=False)
6545 cmdutil.bailifchanged(repo, merge=False)
6547
6546
6548 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6547 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6549
6548
6550 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6549 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
6551
6550
6552 @command('verify', [])
6551 @command('verify', [])
6553 def verify(ui, repo):
6552 def verify(ui, repo):
6554 """verify the integrity of the repository
6553 """verify the integrity of the repository
6555
6554
6556 Verify the integrity of the current repository.
6555 Verify the integrity of the current repository.
6557
6556
6558 This will perform an extensive check of the repository's
6557 This will perform an extensive check of the repository's
6559 integrity, validating the hashes and checksums of each entry in
6558 integrity, validating the hashes and checksums of each entry in
6560 the changelog, manifest, and tracked files, as well as the
6559 the changelog, manifest, and tracked files, as well as the
6561 integrity of their crosslinks and indices.
6560 integrity of their crosslinks and indices.
6562
6561
6563 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6562 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6564 for more information about recovery from corruption of the
6563 for more information about recovery from corruption of the
6565 repository.
6564 repository.
6566
6565
6567 Returns 0 on success, 1 if errors are encountered.
6566 Returns 0 on success, 1 if errors are encountered.
6568 """
6567 """
6569 return hg.verify(repo)
6568 return hg.verify(repo)
6570
6569
6571 @command('version', [] + formatteropts, norepo=True)
6570 @command('version', [] + formatteropts, norepo=True)
6572 def version_(ui, **opts):
6571 def version_(ui, **opts):
6573 """output version and copyright information"""
6572 """output version and copyright information"""
6574 fm = ui.formatter("version", opts)
6573 fm = ui.formatter("version", opts)
6575 fm.startitem()
6574 fm.startitem()
6576 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6575 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6577 util.version())
6576 util.version())
6578 license = _(
6577 license = _(
6579 "(see https://mercurial-scm.org for more information)\n"
6578 "(see https://mercurial-scm.org for more information)\n"
6580 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
6579 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
6581 "This is free software; see the source for copying conditions. "
6580 "This is free software; see the source for copying conditions. "
6582 "There is NO\nwarranty; "
6581 "There is NO\nwarranty; "
6583 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6582 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6584 )
6583 )
6585 if not ui.quiet:
6584 if not ui.quiet:
6586 fm.plain(license)
6585 fm.plain(license)
6587
6586
6588 if ui.verbose:
6587 if ui.verbose:
6589 fm.plain(_("\nEnabled extensions:\n\n"))
6588 fm.plain(_("\nEnabled extensions:\n\n"))
6590 # format names and versions into columns
6589 # format names and versions into columns
6591 names = []
6590 names = []
6592 vers = []
6591 vers = []
6593 isinternals = []
6592 isinternals = []
6594 for name, module in extensions.extensions():
6593 for name, module in extensions.extensions():
6595 names.append(name)
6594 names.append(name)
6596 vers.append(extensions.moduleversion(module) or None)
6595 vers.append(extensions.moduleversion(module) or None)
6597 isinternals.append(extensions.ismoduleinternal(module))
6596 isinternals.append(extensions.ismoduleinternal(module))
6598 fn = fm.nested("extensions")
6597 fn = fm.nested("extensions")
6599 if names:
6598 if names:
6600 namefmt = " %%-%ds " % max(len(n) for n in names)
6599 namefmt = " %%-%ds " % max(len(n) for n in names)
6601 places = [_("external"), _("internal")]
6600 places = [_("external"), _("internal")]
6602 for n, v, p in zip(names, vers, isinternals):
6601 for n, v, p in zip(names, vers, isinternals):
6603 fn.startitem()
6602 fn.startitem()
6604 fn.condwrite(ui.verbose, "name", namefmt, n)
6603 fn.condwrite(ui.verbose, "name", namefmt, n)
6605 if ui.verbose:
6604 if ui.verbose:
6606 fn.plain("%s " % places[p])
6605 fn.plain("%s " % places[p])
6607 fn.data(bundled=p)
6606 fn.data(bundled=p)
6608 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6607 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6609 if ui.verbose:
6608 if ui.verbose:
6610 fn.plain("\n")
6609 fn.plain("\n")
6611 fn.end()
6610 fn.end()
6612 fm.end()
6611 fm.end()
6613
6612
6614 def loadcmdtable(ui, name, cmdtable):
6613 def loadcmdtable(ui, name, cmdtable):
6615 """Load command functions from specified cmdtable
6614 """Load command functions from specified cmdtable
6616 """
6615 """
6617 overrides = [cmd for cmd in cmdtable if cmd in table]
6616 overrides = [cmd for cmd in cmdtable if cmd in table]
6618 if overrides:
6617 if overrides:
6619 ui.warn(_("extension '%s' overrides commands: %s\n")
6618 ui.warn(_("extension '%s' overrides commands: %s\n")
6620 % (name, " ".join(overrides)))
6619 % (name, " ".join(overrides)))
6621 table.update(cmdtable)
6620 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now