##// END OF EJS Templates
py3: make sure opts are passed and used correctly in help command...
Pulkit Goyal -
r32143:964c6be3 default
parent child Browse files
Show More
@@ -1,5520 +1,5520
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 )
21 )
22 from . import (
22 from . import (
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 changegroup,
26 changegroup,
27 cmdutil,
27 cmdutil,
28 copies,
28 copies,
29 destutil,
29 destutil,
30 dirstateguard,
30 dirstateguard,
31 discovery,
31 discovery,
32 encoding,
32 encoding,
33 error,
33 error,
34 exchange,
34 exchange,
35 extensions,
35 extensions,
36 graphmod,
36 graphmod,
37 hbisect,
37 hbisect,
38 help,
38 help,
39 hg,
39 hg,
40 lock as lockmod,
40 lock as lockmod,
41 merge as mergemod,
41 merge as mergemod,
42 obsolete,
42 obsolete,
43 patch,
43 patch,
44 phases,
44 phases,
45 pycompat,
45 pycompat,
46 rcutil,
46 rcutil,
47 revsetlang,
47 revsetlang,
48 scmutil,
48 scmutil,
49 server,
49 server,
50 sshserver,
50 sshserver,
51 streamclone,
51 streamclone,
52 tags as tagsmod,
52 tags as tagsmod,
53 templatekw,
53 templatekw,
54 ui as uimod,
54 ui as uimod,
55 util,
55 util,
56 )
56 )
57
57
58 release = lockmod.release
58 release = lockmod.release
59
59
60 table = {}
60 table = {}
61
61
62 command = cmdutil.command(table)
62 command = cmdutil.command(table)
63
63
64 # label constants
64 # label constants
65 # until 3.5, bookmarks.current was the advertised name, not
65 # until 3.5, bookmarks.current was the advertised name, not
66 # bookmarks.active, so we must use both to avoid breaking old
66 # bookmarks.active, so we must use both to avoid breaking old
67 # custom styles
67 # custom styles
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
69
69
70 # common command options
70 # common command options
71
71
72 globalopts = [
72 globalopts = [
73 ('R', 'repository', '',
73 ('R', 'repository', '',
74 _('repository root directory or name of overlay bundle file'),
74 _('repository root directory or name of overlay bundle file'),
75 _('REPO')),
75 _('REPO')),
76 ('', 'cwd', '',
76 ('', 'cwd', '',
77 _('change working directory'), _('DIR')),
77 _('change working directory'), _('DIR')),
78 ('y', 'noninteractive', None,
78 ('y', 'noninteractive', None,
79 _('do not prompt, automatically pick the first choice for all prompts')),
79 _('do not prompt, automatically pick the first choice for all prompts')),
80 ('q', 'quiet', None, _('suppress output')),
80 ('q', 'quiet', None, _('suppress output')),
81 ('v', 'verbose', None, _('enable additional output')),
81 ('v', 'verbose', None, _('enable additional output')),
82 ('', 'color', '',
82 ('', 'color', '',
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # and should not be translated
84 # and should not be translated
85 _("when to colorize (boolean, always, auto, never, or debug)"),
85 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _('TYPE')),
86 _('TYPE')),
87 ('', 'config', [],
87 ('', 'config', [],
88 _('set/override config option (use \'section.name=value\')'),
88 _('set/override config option (use \'section.name=value\')'),
89 _('CONFIG')),
89 _('CONFIG')),
90 ('', 'debug', None, _('enable debugging output')),
90 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debugger', None, _('start debugger')),
91 ('', 'debugger', None, _('start debugger')),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 _('ENCODE')),
93 _('ENCODE')),
94 ('', 'encodingmode', encoding.encodingmode,
94 ('', 'encodingmode', encoding.encodingmode,
95 _('set the charset encoding mode'), _('MODE')),
95 _('set the charset encoding mode'), _('MODE')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'time', None, _('time how long the command takes')),
97 ('', 'time', None, _('time how long the command takes')),
98 ('', 'profile', None, _('print command execution profile')),
98 ('', 'profile', None, _('print command execution profile')),
99 ('', 'version', None, _('output version information and exit')),
99 ('', 'version', None, _('output version information and exit')),
100 ('h', 'help', None, _('display help and exit')),
100 ('h', 'help', None, _('display help and exit')),
101 ('', 'hidden', False, _('consider hidden changesets')),
101 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'pager', 'auto',
102 ('', 'pager', 'auto',
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 ]
104 ]
105
105
106 dryrunopts = [('n', 'dry-run', None,
106 dryrunopts = [('n', 'dry-run', None,
107 _('do not perform actions, just print output'))]
107 _('do not perform actions, just print output'))]
108
108
109 remoteopts = [
109 remoteopts = [
110 ('e', 'ssh', '',
110 ('e', 'ssh', '',
111 _('specify ssh command to use'), _('CMD')),
111 _('specify ssh command to use'), _('CMD')),
112 ('', 'remotecmd', '',
112 ('', 'remotecmd', '',
113 _('specify hg command to run on the remote side'), _('CMD')),
113 _('specify hg command to run on the remote side'), _('CMD')),
114 ('', 'insecure', None,
114 ('', 'insecure', None,
115 _('do not verify server certificate (ignoring web.cacerts config)')),
115 _('do not verify server certificate (ignoring web.cacerts config)')),
116 ]
116 ]
117
117
118 walkopts = [
118 walkopts = [
119 ('I', 'include', [],
119 ('I', 'include', [],
120 _('include names matching the given patterns'), _('PATTERN')),
120 _('include names matching the given patterns'), _('PATTERN')),
121 ('X', 'exclude', [],
121 ('X', 'exclude', [],
122 _('exclude names matching the given patterns'), _('PATTERN')),
122 _('exclude names matching the given patterns'), _('PATTERN')),
123 ]
123 ]
124
124
125 commitopts = [
125 commitopts = [
126 ('m', 'message', '',
126 ('m', 'message', '',
127 _('use text as commit message'), _('TEXT')),
127 _('use text as commit message'), _('TEXT')),
128 ('l', 'logfile', '',
128 ('l', 'logfile', '',
129 _('read commit message from file'), _('FILE')),
129 _('read commit message from file'), _('FILE')),
130 ]
130 ]
131
131
132 commitopts2 = [
132 commitopts2 = [
133 ('d', 'date', '',
133 ('d', 'date', '',
134 _('record the specified date as commit date'), _('DATE')),
134 _('record the specified date as commit date'), _('DATE')),
135 ('u', 'user', '',
135 ('u', 'user', '',
136 _('record the specified user as committer'), _('USER')),
136 _('record the specified user as committer'), _('USER')),
137 ]
137 ]
138
138
139 # hidden for now
139 # hidden for now
140 formatteropts = [
140 formatteropts = [
141 ('T', 'template', '',
141 ('T', 'template', '',
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
143 ]
143 ]
144
144
145 templateopts = [
145 templateopts = [
146 ('', 'style', '',
146 ('', 'style', '',
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
148 ('T', 'template', '',
148 ('T', 'template', '',
149 _('display with template'), _('TEMPLATE')),
149 _('display with template'), _('TEMPLATE')),
150 ]
150 ]
151
151
152 logopts = [
152 logopts = [
153 ('p', 'patch', None, _('show patch')),
153 ('p', 'patch', None, _('show patch')),
154 ('g', 'git', None, _('use git extended diff format')),
154 ('g', 'git', None, _('use git extended diff format')),
155 ('l', 'limit', '',
155 ('l', 'limit', '',
156 _('limit number of changes displayed'), _('NUM')),
156 _('limit number of changes displayed'), _('NUM')),
157 ('M', 'no-merges', None, _('do not show merges')),
157 ('M', 'no-merges', None, _('do not show merges')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
159 ('G', 'graph', None, _("show the revision DAG")),
159 ('G', 'graph', None, _("show the revision DAG")),
160 ] + templateopts
160 ] + templateopts
161
161
162 diffopts = [
162 diffopts = [
163 ('a', 'text', None, _('treat all files as text')),
163 ('a', 'text', None, _('treat all files as text')),
164 ('g', 'git', None, _('use git extended diff format')),
164 ('g', 'git', None, _('use git extended diff format')),
165 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
165 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
166 ('', 'nodates', None, _('omit dates from diff headers'))
166 ('', 'nodates', None, _('omit dates from diff headers'))
167 ]
167 ]
168
168
169 diffwsopts = [
169 diffwsopts = [
170 ('w', 'ignore-all-space', None,
170 ('w', 'ignore-all-space', None,
171 _('ignore white space when comparing lines')),
171 _('ignore white space when comparing lines')),
172 ('b', 'ignore-space-change', None,
172 ('b', 'ignore-space-change', None,
173 _('ignore changes in the amount of white space')),
173 _('ignore changes in the amount of white space')),
174 ('B', 'ignore-blank-lines', None,
174 ('B', 'ignore-blank-lines', None,
175 _('ignore changes whose lines are all blank')),
175 _('ignore changes whose lines are all blank')),
176 ]
176 ]
177
177
178 diffopts2 = [
178 diffopts2 = [
179 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
179 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
180 ('p', 'show-function', None, _('show which function each change is in')),
180 ('p', 'show-function', None, _('show which function each change is in')),
181 ('', 'reverse', None, _('produce a diff that undoes the changes')),
181 ('', 'reverse', None, _('produce a diff that undoes the changes')),
182 ] + diffwsopts + [
182 ] + diffwsopts + [
183 ('U', 'unified', '',
183 ('U', 'unified', '',
184 _('number of lines of context to show'), _('NUM')),
184 _('number of lines of context to show'), _('NUM')),
185 ('', 'stat', None, _('output diffstat-style summary of changes')),
185 ('', 'stat', None, _('output diffstat-style summary of changes')),
186 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
186 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
187 ]
187 ]
188
188
189 mergetoolopts = [
189 mergetoolopts = [
190 ('t', 'tool', '', _('specify merge tool')),
190 ('t', 'tool', '', _('specify merge tool')),
191 ]
191 ]
192
192
193 similarityopts = [
193 similarityopts = [
194 ('s', 'similarity', '',
194 ('s', 'similarity', '',
195 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
195 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
196 ]
196 ]
197
197
198 subrepoopts = [
198 subrepoopts = [
199 ('S', 'subrepos', None,
199 ('S', 'subrepos', None,
200 _('recurse into subrepositories'))
200 _('recurse into subrepositories'))
201 ]
201 ]
202
202
203 debugrevlogopts = [
203 debugrevlogopts = [
204 ('c', 'changelog', False, _('open changelog')),
204 ('c', 'changelog', False, _('open changelog')),
205 ('m', 'manifest', False, _('open manifest')),
205 ('m', 'manifest', False, _('open manifest')),
206 ('', 'dir', '', _('open directory manifest')),
206 ('', 'dir', '', _('open directory manifest')),
207 ]
207 ]
208
208
209 # Commands start here, listed alphabetically
209 # Commands start here, listed alphabetically
210
210
211 @command('^add',
211 @command('^add',
212 walkopts + subrepoopts + dryrunopts,
212 walkopts + subrepoopts + dryrunopts,
213 _('[OPTION]... [FILE]...'),
213 _('[OPTION]... [FILE]...'),
214 inferrepo=True)
214 inferrepo=True)
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 opts = pycompat.byteskwargs(opts)
258 opts = pycompat.byteskwargs(opts)
259 m = scmutil.match(repo[None], pats, opts)
259 m = scmutil.match(repo[None], pats, opts)
260 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
260 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263 @command('addremove',
263 @command('addremove',
264 similarityopts + subrepoopts + walkopts + dryrunopts,
264 similarityopts + subrepoopts + walkopts + dryrunopts,
265 _('[OPTION]... [FILE]...'),
265 _('[OPTION]... [FILE]...'),
266 inferrepo=True)
266 inferrepo=True)
267 def addremove(ui, repo, *pats, **opts):
267 def addremove(ui, repo, *pats, **opts):
268 """add all new files, delete all missing files
268 """add all new files, delete all missing files
269
269
270 Add all new files and remove all missing files from the
270 Add all new files and remove all missing files from the
271 repository.
271 repository.
272
272
273 Unless names are given, new files are ignored if they match any of
273 Unless names are given, new files are ignored if they match any of
274 the patterns in ``.hgignore``. As with add, these changes take
274 the patterns in ``.hgignore``. As with add, these changes take
275 effect at the next commit.
275 effect at the next commit.
276
276
277 Use the -s/--similarity option to detect renamed files. This
277 Use the -s/--similarity option to detect renamed files. This
278 option takes a percentage between 0 (disabled) and 100 (files must
278 option takes a percentage between 0 (disabled) and 100 (files must
279 be identical) as its parameter. With a parameter greater than 0,
279 be identical) as its parameter. With a parameter greater than 0,
280 this compares every removed file with every added file and records
280 this compares every removed file with every added file and records
281 those similar enough as renames. Detecting renamed files this way
281 those similar enough as renames. Detecting renamed files this way
282 can be expensive. After using this option, :hg:`status -C` can be
282 can be expensive. After using this option, :hg:`status -C` can be
283 used to check which files were identified as moved or renamed. If
283 used to check which files were identified as moved or renamed. If
284 not specified, -s/--similarity defaults to 100 and only renames of
284 not specified, -s/--similarity defaults to 100 and only renames of
285 identical files are detected.
285 identical files are detected.
286
286
287 .. container:: verbose
287 .. container:: verbose
288
288
289 Examples:
289 Examples:
290
290
291 - A number of files (bar.c and foo.c) are new,
291 - A number of files (bar.c and foo.c) are new,
292 while foobar.c has been removed (without using :hg:`remove`)
292 while foobar.c has been removed (without using :hg:`remove`)
293 from the repository::
293 from the repository::
294
294
295 $ ls
295 $ ls
296 bar.c foo.c
296 bar.c foo.c
297 $ hg status
297 $ hg status
298 ! foobar.c
298 ! foobar.c
299 ? bar.c
299 ? bar.c
300 ? foo.c
300 ? foo.c
301 $ hg addremove
301 $ hg addremove
302 adding bar.c
302 adding bar.c
303 adding foo.c
303 adding foo.c
304 removing foobar.c
304 removing foobar.c
305 $ hg status
305 $ hg status
306 A bar.c
306 A bar.c
307 A foo.c
307 A foo.c
308 R foobar.c
308 R foobar.c
309
309
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 Afterwards, it was edited slightly::
311 Afterwards, it was edited slightly::
312
312
313 $ ls
313 $ ls
314 foo.c
314 foo.c
315 $ hg status
315 $ hg status
316 ! foobar.c
316 ! foobar.c
317 ? foo.c
317 ? foo.c
318 $ hg addremove --similarity 90
318 $ hg addremove --similarity 90
319 removing foobar.c
319 removing foobar.c
320 adding foo.c
320 adding foo.c
321 recording removal of foobar.c as rename to foo.c (94% similar)
321 recording removal of foobar.c as rename to foo.c (94% similar)
322 $ hg status -C
322 $ hg status -C
323 A foo.c
323 A foo.c
324 foobar.c
324 foobar.c
325 R foobar.c
325 R foobar.c
326
326
327 Returns 0 if all files are successfully added.
327 Returns 0 if all files are successfully added.
328 """
328 """
329 opts = pycompat.byteskwargs(opts)
329 opts = pycompat.byteskwargs(opts)
330 try:
330 try:
331 sim = float(opts.get('similarity') or 100)
331 sim = float(opts.get('similarity') or 100)
332 except ValueError:
332 except ValueError:
333 raise error.Abort(_('similarity must be a number'))
333 raise error.Abort(_('similarity must be a number'))
334 if sim < 0 or sim > 100:
334 if sim < 0 or sim > 100:
335 raise error.Abort(_('similarity must be between 0 and 100'))
335 raise error.Abort(_('similarity must be between 0 and 100'))
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
337 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
338
338
339 @command('^annotate|blame',
339 @command('^annotate|blame',
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
340 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
341 ('', 'follow', None,
341 ('', 'follow', None,
342 _('follow copies/renames and list the filename (DEPRECATED)')),
342 _('follow copies/renames and list the filename (DEPRECATED)')),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
343 ('', 'no-follow', None, _("don't follow copies and renames")),
344 ('a', 'text', None, _('treat all files as text')),
344 ('a', 'text', None, _('treat all files as text')),
345 ('u', 'user', None, _('list the author (long with -v)')),
345 ('u', 'user', None, _('list the author (long with -v)')),
346 ('f', 'file', None, _('list the filename')),
346 ('f', 'file', None, _('list the filename')),
347 ('d', 'date', None, _('list the date (short with -q)')),
347 ('d', 'date', None, _('list the date (short with -q)')),
348 ('n', 'number', None, _('list the revision number (default)')),
348 ('n', 'number', None, _('list the revision number (default)')),
349 ('c', 'changeset', None, _('list the changeset')),
349 ('c', 'changeset', None, _('list the changeset')),
350 ('l', 'line-number', None, _('show line number at the first appearance'))
350 ('l', 'line-number', None, _('show line number at the first appearance'))
351 ] + diffwsopts + walkopts + formatteropts,
351 ] + diffwsopts + walkopts + formatteropts,
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
352 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
353 inferrepo=True)
353 inferrepo=True)
354 def annotate(ui, repo, *pats, **opts):
354 def annotate(ui, repo, *pats, **opts):
355 """show changeset information by line for each file
355 """show changeset information by line for each file
356
356
357 List changes in files, showing the revision id responsible for
357 List changes in files, showing the revision id responsible for
358 each line.
358 each line.
359
359
360 This command is useful for discovering when a change was made and
360 This command is useful for discovering when a change was made and
361 by whom.
361 by whom.
362
362
363 If you include --file, --user, or --date, the revision number is
363 If you include --file, --user, or --date, the revision number is
364 suppressed unless you also include --number.
364 suppressed unless you also include --number.
365
365
366 Without the -a/--text option, annotate will avoid processing files
366 Without the -a/--text option, annotate will avoid processing files
367 it detects as binary. With -a, annotate will annotate the file
367 it detects as binary. With -a, annotate will annotate the file
368 anyway, although the results will probably be neither useful
368 anyway, although the results will probably be neither useful
369 nor desirable.
369 nor desirable.
370
370
371 Returns 0 on success.
371 Returns 0 on success.
372 """
372 """
373 opts = pycompat.byteskwargs(opts)
373 opts = pycompat.byteskwargs(opts)
374 if not pats:
374 if not pats:
375 raise error.Abort(_('at least one filename or pattern is required'))
375 raise error.Abort(_('at least one filename or pattern is required'))
376
376
377 if opts.get('follow'):
377 if opts.get('follow'):
378 # --follow is deprecated and now just an alias for -f/--file
378 # --follow is deprecated and now just an alias for -f/--file
379 # to mimic the behavior of Mercurial before version 1.5
379 # to mimic the behavior of Mercurial before version 1.5
380 opts['file'] = True
380 opts['file'] = True
381
381
382 ctx = scmutil.revsingle(repo, opts.get('rev'))
382 ctx = scmutil.revsingle(repo, opts.get('rev'))
383
383
384 fm = ui.formatter('annotate', opts)
384 fm = ui.formatter('annotate', opts)
385 if ui.quiet:
385 if ui.quiet:
386 datefunc = util.shortdate
386 datefunc = util.shortdate
387 else:
387 else:
388 datefunc = util.datestr
388 datefunc = util.datestr
389 if ctx.rev() is None:
389 if ctx.rev() is None:
390 def hexfn(node):
390 def hexfn(node):
391 if node is None:
391 if node is None:
392 return None
392 return None
393 else:
393 else:
394 return fm.hexfunc(node)
394 return fm.hexfunc(node)
395 if opts.get('changeset'):
395 if opts.get('changeset'):
396 # omit "+" suffix which is appended to node hex
396 # omit "+" suffix which is appended to node hex
397 def formatrev(rev):
397 def formatrev(rev):
398 if rev is None:
398 if rev is None:
399 return '%d' % ctx.p1().rev()
399 return '%d' % ctx.p1().rev()
400 else:
400 else:
401 return '%d' % rev
401 return '%d' % rev
402 else:
402 else:
403 def formatrev(rev):
403 def formatrev(rev):
404 if rev is None:
404 if rev is None:
405 return '%d+' % ctx.p1().rev()
405 return '%d+' % ctx.p1().rev()
406 else:
406 else:
407 return '%d ' % rev
407 return '%d ' % rev
408 def formathex(hex):
408 def formathex(hex):
409 if hex is None:
409 if hex is None:
410 return '%s+' % fm.hexfunc(ctx.p1().node())
410 return '%s+' % fm.hexfunc(ctx.p1().node())
411 else:
411 else:
412 return '%s ' % hex
412 return '%s ' % hex
413 else:
413 else:
414 hexfn = fm.hexfunc
414 hexfn = fm.hexfunc
415 formatrev = formathex = str
415 formatrev = formathex = str
416
416
417 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
417 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
418 ('number', ' ', lambda x: x[0].rev(), formatrev),
418 ('number', ' ', lambda x: x[0].rev(), formatrev),
419 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
419 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
420 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
420 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
421 ('file', ' ', lambda x: x[0].path(), str),
421 ('file', ' ', lambda x: x[0].path(), str),
422 ('line_number', ':', lambda x: x[1], str),
422 ('line_number', ':', lambda x: x[1], str),
423 ]
423 ]
424 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
424 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
425
425
426 if (not opts.get('user') and not opts.get('changeset')
426 if (not opts.get('user') and not opts.get('changeset')
427 and not opts.get('date') and not opts.get('file')):
427 and not opts.get('date') and not opts.get('file')):
428 opts['number'] = True
428 opts['number'] = True
429
429
430 linenumber = opts.get('line_number') is not None
430 linenumber = opts.get('line_number') is not None
431 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
431 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
432 raise error.Abort(_('at least one of -n/-c is required for -l'))
432 raise error.Abort(_('at least one of -n/-c is required for -l'))
433
433
434 ui.pager('annotate')
434 ui.pager('annotate')
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 fctx.isbinary():
458 if not opts.get('text') and fctx.isbinary():
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 opts = pycompat.byteskwargs(opts)
538 opts = pycompat.byteskwargs(opts)
539 ctx = scmutil.revsingle(repo, opts.get('rev'))
539 ctx = scmutil.revsingle(repo, opts.get('rev'))
540 if not ctx:
540 if not ctx:
541 raise error.Abort(_('no working directory: please specify a revision'))
541 raise error.Abort(_('no working directory: please specify a revision'))
542 node = ctx.node()
542 node = ctx.node()
543 dest = cmdutil.makefilename(repo, dest, node)
543 dest = cmdutil.makefilename(repo, dest, node)
544 if os.path.realpath(dest) == repo.root:
544 if os.path.realpath(dest) == repo.root:
545 raise error.Abort(_('repository root cannot be destination'))
545 raise error.Abort(_('repository root cannot be destination'))
546
546
547 kind = opts.get('type') or archival.guesskind(dest) or 'files'
547 kind = opts.get('type') or archival.guesskind(dest) or 'files'
548 prefix = opts.get('prefix')
548 prefix = opts.get('prefix')
549
549
550 if dest == '-':
550 if dest == '-':
551 if kind == 'files':
551 if kind == 'files':
552 raise error.Abort(_('cannot archive plain files to stdout'))
552 raise error.Abort(_('cannot archive plain files to stdout'))
553 dest = cmdutil.makefileobj(repo, dest)
553 dest = cmdutil.makefileobj(repo, dest)
554 if not prefix:
554 if not prefix:
555 prefix = os.path.basename(repo.root) + '-%h'
555 prefix = os.path.basename(repo.root) + '-%h'
556
556
557 prefix = cmdutil.makefilename(repo, prefix, node)
557 prefix = cmdutil.makefilename(repo, prefix, node)
558 matchfn = scmutil.match(ctx, [], opts)
558 matchfn = scmutil.match(ctx, [], opts)
559 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
559 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
560 matchfn, prefix, subrepos=opts.get('subrepos'))
560 matchfn, prefix, subrepos=opts.get('subrepos'))
561
561
562 @command('backout',
562 @command('backout',
563 [('', 'merge', None, _('merge with old dirstate parent after backout')),
563 [('', 'merge', None, _('merge with old dirstate parent after backout')),
564 ('', 'commit', None,
564 ('', 'commit', None,
565 _('commit if no conflicts were encountered (DEPRECATED)')),
565 _('commit if no conflicts were encountered (DEPRECATED)')),
566 ('', 'no-commit', None, _('do not commit')),
566 ('', 'no-commit', None, _('do not commit')),
567 ('', 'parent', '',
567 ('', 'parent', '',
568 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
568 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
569 ('r', 'rev', '', _('revision to backout'), _('REV')),
569 ('r', 'rev', '', _('revision to backout'), _('REV')),
570 ('e', 'edit', False, _('invoke editor on commit messages')),
570 ('e', 'edit', False, _('invoke editor on commit messages')),
571 ] + mergetoolopts + walkopts + commitopts + commitopts2,
571 ] + mergetoolopts + walkopts + commitopts + commitopts2,
572 _('[OPTION]... [-r] REV'))
572 _('[OPTION]... [-r] REV'))
573 def backout(ui, repo, node=None, rev=None, **opts):
573 def backout(ui, repo, node=None, rev=None, **opts):
574 '''reverse effect of earlier changeset
574 '''reverse effect of earlier changeset
575
575
576 Prepare a new changeset with the effect of REV undone in the
576 Prepare a new changeset with the effect of REV undone in the
577 current working directory. If no conflicts were encountered,
577 current working directory. If no conflicts were encountered,
578 it will be committed immediately.
578 it will be committed immediately.
579
579
580 If REV is the parent of the working directory, then this new changeset
580 If REV is the parent of the working directory, then this new changeset
581 is committed automatically (unless --no-commit is specified).
581 is committed automatically (unless --no-commit is specified).
582
582
583 .. note::
583 .. note::
584
584
585 :hg:`backout` cannot be used to fix either an unwanted or
585 :hg:`backout` cannot be used to fix either an unwanted or
586 incorrect merge.
586 incorrect merge.
587
587
588 .. container:: verbose
588 .. container:: verbose
589
589
590 Examples:
590 Examples:
591
591
592 - Reverse the effect of the parent of the working directory.
592 - Reverse the effect of the parent of the working directory.
593 This backout will be committed immediately::
593 This backout will be committed immediately::
594
594
595 hg backout -r .
595 hg backout -r .
596
596
597 - Reverse the effect of previous bad revision 23::
597 - Reverse the effect of previous bad revision 23::
598
598
599 hg backout -r 23
599 hg backout -r 23
600
600
601 - Reverse the effect of previous bad revision 23 and
601 - Reverse the effect of previous bad revision 23 and
602 leave changes uncommitted::
602 leave changes uncommitted::
603
603
604 hg backout -r 23 --no-commit
604 hg backout -r 23 --no-commit
605 hg commit -m "Backout revision 23"
605 hg commit -m "Backout revision 23"
606
606
607 By default, the pending changeset will have one parent,
607 By default, the pending changeset will have one parent,
608 maintaining a linear history. With --merge, the pending
608 maintaining a linear history. With --merge, the pending
609 changeset will instead have two parents: the old parent of the
609 changeset will instead have two parents: the old parent of the
610 working directory and a new child of REV that simply undoes REV.
610 working directory and a new child of REV that simply undoes REV.
611
611
612 Before version 1.7, the behavior without --merge was equivalent
612 Before version 1.7, the behavior without --merge was equivalent
613 to specifying --merge followed by :hg:`update --clean .` to
613 to specifying --merge followed by :hg:`update --clean .` to
614 cancel the merge and leave the child of REV as a head to be
614 cancel the merge and leave the child of REV as a head to be
615 merged separately.
615 merged separately.
616
616
617 See :hg:`help dates` for a list of formats valid for -d/--date.
617 See :hg:`help dates` for a list of formats valid for -d/--date.
618
618
619 See :hg:`help revert` for a way to restore files to the state
619 See :hg:`help revert` for a way to restore files to the state
620 of another revision.
620 of another revision.
621
621
622 Returns 0 on success, 1 if nothing to backout or there are unresolved
622 Returns 0 on success, 1 if nothing to backout or there are unresolved
623 files.
623 files.
624 '''
624 '''
625 wlock = lock = None
625 wlock = lock = None
626 try:
626 try:
627 wlock = repo.wlock()
627 wlock = repo.wlock()
628 lock = repo.lock()
628 lock = repo.lock()
629 return _dobackout(ui, repo, node, rev, **opts)
629 return _dobackout(ui, repo, node, rev, **opts)
630 finally:
630 finally:
631 release(lock, wlock)
631 release(lock, wlock)
632
632
633 def _dobackout(ui, repo, node=None, rev=None, **opts):
633 def _dobackout(ui, repo, node=None, rev=None, **opts):
634 opts = pycompat.byteskwargs(opts)
634 opts = pycompat.byteskwargs(opts)
635 if opts.get('commit') and opts.get('no_commit'):
635 if opts.get('commit') and opts.get('no_commit'):
636 raise error.Abort(_("cannot use --commit with --no-commit"))
636 raise error.Abort(_("cannot use --commit with --no-commit"))
637 if opts.get('merge') and opts.get('no_commit'):
637 if opts.get('merge') and opts.get('no_commit'):
638 raise error.Abort(_("cannot use --merge with --no-commit"))
638 raise error.Abort(_("cannot use --merge with --no-commit"))
639
639
640 if rev and node:
640 if rev and node:
641 raise error.Abort(_("please specify just one revision"))
641 raise error.Abort(_("please specify just one revision"))
642
642
643 if not rev:
643 if not rev:
644 rev = node
644 rev = node
645
645
646 if not rev:
646 if not rev:
647 raise error.Abort(_("please specify a revision to backout"))
647 raise error.Abort(_("please specify a revision to backout"))
648
648
649 date = opts.get('date')
649 date = opts.get('date')
650 if date:
650 if date:
651 opts['date'] = util.parsedate(date)
651 opts['date'] = util.parsedate(date)
652
652
653 cmdutil.checkunfinished(repo)
653 cmdutil.checkunfinished(repo)
654 cmdutil.bailifchanged(repo)
654 cmdutil.bailifchanged(repo)
655 node = scmutil.revsingle(repo, rev).node()
655 node = scmutil.revsingle(repo, rev).node()
656
656
657 op1, op2 = repo.dirstate.parents()
657 op1, op2 = repo.dirstate.parents()
658 if not repo.changelog.isancestor(node, op1):
658 if not repo.changelog.isancestor(node, op1):
659 raise error.Abort(_('cannot backout change that is not an ancestor'))
659 raise error.Abort(_('cannot backout change that is not an ancestor'))
660
660
661 p1, p2 = repo.changelog.parents(node)
661 p1, p2 = repo.changelog.parents(node)
662 if p1 == nullid:
662 if p1 == nullid:
663 raise error.Abort(_('cannot backout a change with no parents'))
663 raise error.Abort(_('cannot backout a change with no parents'))
664 if p2 != nullid:
664 if p2 != nullid:
665 if not opts.get('parent'):
665 if not opts.get('parent'):
666 raise error.Abort(_('cannot backout a merge changeset'))
666 raise error.Abort(_('cannot backout a merge changeset'))
667 p = repo.lookup(opts['parent'])
667 p = repo.lookup(opts['parent'])
668 if p not in (p1, p2):
668 if p not in (p1, p2):
669 raise error.Abort(_('%s is not a parent of %s') %
669 raise error.Abort(_('%s is not a parent of %s') %
670 (short(p), short(node)))
670 (short(p), short(node)))
671 parent = p
671 parent = p
672 else:
672 else:
673 if opts.get('parent'):
673 if opts.get('parent'):
674 raise error.Abort(_('cannot use --parent on non-merge changeset'))
674 raise error.Abort(_('cannot use --parent on non-merge changeset'))
675 parent = p1
675 parent = p1
676
676
677 # the backout should appear on the same branch
677 # the backout should appear on the same branch
678 branch = repo.dirstate.branch()
678 branch = repo.dirstate.branch()
679 bheads = repo.branchheads(branch)
679 bheads = repo.branchheads(branch)
680 rctx = scmutil.revsingle(repo, hex(parent))
680 rctx = scmutil.revsingle(repo, hex(parent))
681 if not opts.get('merge') and op1 != node:
681 if not opts.get('merge') and op1 != node:
682 dsguard = dirstateguard.dirstateguard(repo, 'backout')
682 dsguard = dirstateguard.dirstateguard(repo, 'backout')
683 try:
683 try:
684 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
684 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
685 'backout')
685 'backout')
686 stats = mergemod.update(repo, parent, True, True, node, False)
686 stats = mergemod.update(repo, parent, True, True, node, False)
687 repo.setparents(op1, op2)
687 repo.setparents(op1, op2)
688 dsguard.close()
688 dsguard.close()
689 hg._showstats(repo, stats)
689 hg._showstats(repo, stats)
690 if stats[3]:
690 if stats[3]:
691 repo.ui.status(_("use 'hg resolve' to retry unresolved "
691 repo.ui.status(_("use 'hg resolve' to retry unresolved "
692 "file merges\n"))
692 "file merges\n"))
693 return 1
693 return 1
694 finally:
694 finally:
695 ui.setconfig('ui', 'forcemerge', '', '')
695 ui.setconfig('ui', 'forcemerge', '', '')
696 lockmod.release(dsguard)
696 lockmod.release(dsguard)
697 else:
697 else:
698 hg.clean(repo, node, show_stats=False)
698 hg.clean(repo, node, show_stats=False)
699 repo.dirstate.setbranch(branch)
699 repo.dirstate.setbranch(branch)
700 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
700 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
701
701
702 if opts.get('no_commit'):
702 if opts.get('no_commit'):
703 msg = _("changeset %s backed out, "
703 msg = _("changeset %s backed out, "
704 "don't forget to commit.\n")
704 "don't forget to commit.\n")
705 ui.status(msg % short(node))
705 ui.status(msg % short(node))
706 return 0
706 return 0
707
707
708 def commitfunc(ui, repo, message, match, opts):
708 def commitfunc(ui, repo, message, match, opts):
709 editform = 'backout'
709 editform = 'backout'
710 e = cmdutil.getcommiteditor(editform=editform, **opts)
710 e = cmdutil.getcommiteditor(editform=editform, **opts)
711 if not message:
711 if not message:
712 # we don't translate commit messages
712 # we don't translate commit messages
713 message = "Backed out changeset %s" % short(node)
713 message = "Backed out changeset %s" % short(node)
714 e = cmdutil.getcommiteditor(edit=True, editform=editform)
714 e = cmdutil.getcommiteditor(edit=True, editform=editform)
715 return repo.commit(message, opts.get('user'), opts.get('date'),
715 return repo.commit(message, opts.get('user'), opts.get('date'),
716 match, editor=e)
716 match, editor=e)
717 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
717 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
718 if not newnode:
718 if not newnode:
719 ui.status(_("nothing changed\n"))
719 ui.status(_("nothing changed\n"))
720 return 1
720 return 1
721 cmdutil.commitstatus(repo, newnode, branch, bheads)
721 cmdutil.commitstatus(repo, newnode, branch, bheads)
722
722
723 def nice(node):
723 def nice(node):
724 return '%d:%s' % (repo.changelog.rev(node), short(node))
724 return '%d:%s' % (repo.changelog.rev(node), short(node))
725 ui.status(_('changeset %s backs out changeset %s\n') %
725 ui.status(_('changeset %s backs out changeset %s\n') %
726 (nice(repo.changelog.tip()), nice(node)))
726 (nice(repo.changelog.tip()), nice(node)))
727 if opts.get('merge') and op1 != node:
727 if opts.get('merge') and op1 != node:
728 hg.clean(repo, op1, show_stats=False)
728 hg.clean(repo, op1, show_stats=False)
729 ui.status(_('merging with changeset %s\n')
729 ui.status(_('merging with changeset %s\n')
730 % nice(repo.changelog.tip()))
730 % nice(repo.changelog.tip()))
731 try:
731 try:
732 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
732 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
733 'backout')
733 'backout')
734 return hg.merge(repo, hex(repo.changelog.tip()))
734 return hg.merge(repo, hex(repo.changelog.tip()))
735 finally:
735 finally:
736 ui.setconfig('ui', 'forcemerge', '', '')
736 ui.setconfig('ui', 'forcemerge', '', '')
737 return 0
737 return 0
738
738
739 @command('bisect',
739 @command('bisect',
740 [('r', 'reset', False, _('reset bisect state')),
740 [('r', 'reset', False, _('reset bisect state')),
741 ('g', 'good', False, _('mark changeset good')),
741 ('g', 'good', False, _('mark changeset good')),
742 ('b', 'bad', False, _('mark changeset bad')),
742 ('b', 'bad', False, _('mark changeset bad')),
743 ('s', 'skip', False, _('skip testing changeset')),
743 ('s', 'skip', False, _('skip testing changeset')),
744 ('e', 'extend', False, _('extend the bisect range')),
744 ('e', 'extend', False, _('extend the bisect range')),
745 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
745 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
746 ('U', 'noupdate', False, _('do not update to target'))],
746 ('U', 'noupdate', False, _('do not update to target'))],
747 _("[-gbsr] [-U] [-c CMD] [REV]"))
747 _("[-gbsr] [-U] [-c CMD] [REV]"))
748 def bisect(ui, repo, rev=None, extra=None, command=None,
748 def bisect(ui, repo, rev=None, extra=None, command=None,
749 reset=None, good=None, bad=None, skip=None, extend=None,
749 reset=None, good=None, bad=None, skip=None, extend=None,
750 noupdate=None):
750 noupdate=None):
751 """subdivision search of changesets
751 """subdivision search of changesets
752
752
753 This command helps to find changesets which introduce problems. To
753 This command helps to find changesets which introduce problems. To
754 use, mark the earliest changeset you know exhibits the problem as
754 use, mark the earliest changeset you know exhibits the problem as
755 bad, then mark the latest changeset which is free from the problem
755 bad, then mark the latest changeset which is free from the problem
756 as good. Bisect will update your working directory to a revision
756 as good. Bisect will update your working directory to a revision
757 for testing (unless the -U/--noupdate option is specified). Once
757 for testing (unless the -U/--noupdate option is specified). Once
758 you have performed tests, mark the working directory as good or
758 you have performed tests, mark the working directory as good or
759 bad, and bisect will either update to another candidate changeset
759 bad, and bisect will either update to another candidate changeset
760 or announce that it has found the bad revision.
760 or announce that it has found the bad revision.
761
761
762 As a shortcut, you can also use the revision argument to mark a
762 As a shortcut, you can also use the revision argument to mark a
763 revision as good or bad without checking it out first.
763 revision as good or bad without checking it out first.
764
764
765 If you supply a command, it will be used for automatic bisection.
765 If you supply a command, it will be used for automatic bisection.
766 The environment variable HG_NODE will contain the ID of the
766 The environment variable HG_NODE will contain the ID of the
767 changeset being tested. The exit status of the command will be
767 changeset being tested. The exit status of the command will be
768 used to mark revisions as good or bad: status 0 means good, 125
768 used to mark revisions as good or bad: status 0 means good, 125
769 means to skip the revision, 127 (command not found) will abort the
769 means to skip the revision, 127 (command not found) will abort the
770 bisection, and any other non-zero exit status means the revision
770 bisection, and any other non-zero exit status means the revision
771 is bad.
771 is bad.
772
772
773 .. container:: verbose
773 .. container:: verbose
774
774
775 Some examples:
775 Some examples:
776
776
777 - start a bisection with known bad revision 34, and good revision 12::
777 - start a bisection with known bad revision 34, and good revision 12::
778
778
779 hg bisect --bad 34
779 hg bisect --bad 34
780 hg bisect --good 12
780 hg bisect --good 12
781
781
782 - advance the current bisection by marking current revision as good or
782 - advance the current bisection by marking current revision as good or
783 bad::
783 bad::
784
784
785 hg bisect --good
785 hg bisect --good
786 hg bisect --bad
786 hg bisect --bad
787
787
788 - mark the current revision, or a known revision, to be skipped (e.g. if
788 - mark the current revision, or a known revision, to be skipped (e.g. if
789 that revision is not usable because of another issue)::
789 that revision is not usable because of another issue)::
790
790
791 hg bisect --skip
791 hg bisect --skip
792 hg bisect --skip 23
792 hg bisect --skip 23
793
793
794 - skip all revisions that do not touch directories ``foo`` or ``bar``::
794 - skip all revisions that do not touch directories ``foo`` or ``bar``::
795
795
796 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
796 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
797
797
798 - forget the current bisection::
798 - forget the current bisection::
799
799
800 hg bisect --reset
800 hg bisect --reset
801
801
802 - use 'make && make tests' to automatically find the first broken
802 - use 'make && make tests' to automatically find the first broken
803 revision::
803 revision::
804
804
805 hg bisect --reset
805 hg bisect --reset
806 hg bisect --bad 34
806 hg bisect --bad 34
807 hg bisect --good 12
807 hg bisect --good 12
808 hg bisect --command "make && make tests"
808 hg bisect --command "make && make tests"
809
809
810 - see all changesets whose states are already known in the current
810 - see all changesets whose states are already known in the current
811 bisection::
811 bisection::
812
812
813 hg log -r "bisect(pruned)"
813 hg log -r "bisect(pruned)"
814
814
815 - see the changeset currently being bisected (especially useful
815 - see the changeset currently being bisected (especially useful
816 if running with -U/--noupdate)::
816 if running with -U/--noupdate)::
817
817
818 hg log -r "bisect(current)"
818 hg log -r "bisect(current)"
819
819
820 - see all changesets that took part in the current bisection::
820 - see all changesets that took part in the current bisection::
821
821
822 hg log -r "bisect(range)"
822 hg log -r "bisect(range)"
823
823
824 - you can even get a nice graph::
824 - you can even get a nice graph::
825
825
826 hg log --graph -r "bisect(range)"
826 hg log --graph -r "bisect(range)"
827
827
828 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
828 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
829
829
830 Returns 0 on success.
830 Returns 0 on success.
831 """
831 """
832 # backward compatibility
832 # backward compatibility
833 if rev in "good bad reset init".split():
833 if rev in "good bad reset init".split():
834 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
834 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
835 cmd, rev, extra = rev, extra, None
835 cmd, rev, extra = rev, extra, None
836 if cmd == "good":
836 if cmd == "good":
837 good = True
837 good = True
838 elif cmd == "bad":
838 elif cmd == "bad":
839 bad = True
839 bad = True
840 else:
840 else:
841 reset = True
841 reset = True
842 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
842 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
843 raise error.Abort(_('incompatible arguments'))
843 raise error.Abort(_('incompatible arguments'))
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.checkunfinished(repo)
871 cmdutil.checkunfinished(repo)
872 cmdutil.bailifchanged(repo)
872 cmdutil.bailifchanged(repo)
873 return hg.clean(repo, node, show_stats=show_stats)
873 return hg.clean(repo, node, show_stats=show_stats)
874
874
875 displayer = cmdutil.show_changeset(ui, repo, {})
875 displayer = cmdutil.show_changeset(ui, repo, {})
876
876
877 if command:
877 if command:
878 changesets = 1
878 changesets = 1
879 if noupdate:
879 if noupdate:
880 try:
880 try:
881 node = state['current'][0]
881 node = state['current'][0]
882 except LookupError:
882 except LookupError:
883 raise error.Abort(_('current bisect revision is unknown - '
883 raise error.Abort(_('current bisect revision is unknown - '
884 'start a new bisect to fix'))
884 'start a new bisect to fix'))
885 else:
885 else:
886 node, p2 = repo.dirstate.parents()
886 node, p2 = repo.dirstate.parents()
887 if p2 != nullid:
887 if p2 != nullid:
888 raise error.Abort(_('current bisect revision is a merge'))
888 raise error.Abort(_('current bisect revision is a merge'))
889 if rev:
889 if rev:
890 node = repo[scmutil.revsingle(repo, rev, node)].node()
890 node = repo[scmutil.revsingle(repo, rev, node)].node()
891 try:
891 try:
892 while changesets:
892 while changesets:
893 # update state
893 # update state
894 state['current'] = [node]
894 state['current'] = [node]
895 hbisect.save_state(repo, state)
895 hbisect.save_state(repo, state)
896 status = ui.system(command, environ={'HG_NODE': hex(node)},
896 status = ui.system(command, environ={'HG_NODE': hex(node)},
897 blockedtag='bisect_check')
897 blockedtag='bisect_check')
898 if status == 125:
898 if status == 125:
899 transition = "skip"
899 transition = "skip"
900 elif status == 0:
900 elif status == 0:
901 transition = "good"
901 transition = "good"
902 # status < 0 means process was killed
902 # status < 0 means process was killed
903 elif status == 127:
903 elif status == 127:
904 raise error.Abort(_("failed to execute %s") % command)
904 raise error.Abort(_("failed to execute %s") % command)
905 elif status < 0:
905 elif status < 0:
906 raise error.Abort(_("%s killed") % command)
906 raise error.Abort(_("%s killed") % command)
907 else:
907 else:
908 transition = "bad"
908 transition = "bad"
909 state[transition].append(node)
909 state[transition].append(node)
910 ctx = repo[node]
910 ctx = repo[node]
911 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
911 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
912 hbisect.checkstate(state)
912 hbisect.checkstate(state)
913 # bisect
913 # bisect
914 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
914 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
915 # update to next check
915 # update to next check
916 node = nodes[0]
916 node = nodes[0]
917 mayupdate(repo, node, show_stats=False)
917 mayupdate(repo, node, show_stats=False)
918 finally:
918 finally:
919 state['current'] = [node]
919 state['current'] = [node]
920 hbisect.save_state(repo, state)
920 hbisect.save_state(repo, state)
921 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
921 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
922 return
922 return
923
923
924 hbisect.checkstate(state)
924 hbisect.checkstate(state)
925
925
926 # actually bisect
926 # actually bisect
927 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
927 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
928 if extend:
928 if extend:
929 if not changesets:
929 if not changesets:
930 extendnode = hbisect.extendrange(repo, state, nodes, good)
930 extendnode = hbisect.extendrange(repo, state, nodes, good)
931 if extendnode is not None:
931 if extendnode is not None:
932 ui.write(_("Extending search to changeset %d:%s\n")
932 ui.write(_("Extending search to changeset %d:%s\n")
933 % (extendnode.rev(), extendnode))
933 % (extendnode.rev(), extendnode))
934 state['current'] = [extendnode.node()]
934 state['current'] = [extendnode.node()]
935 hbisect.save_state(repo, state)
935 hbisect.save_state(repo, state)
936 return mayupdate(repo, extendnode.node())
936 return mayupdate(repo, extendnode.node())
937 raise error.Abort(_("nothing to extend"))
937 raise error.Abort(_("nothing to extend"))
938
938
939 if changesets == 0:
939 if changesets == 0:
940 hbisect.printresult(ui, repo, state, displayer, nodes, good)
940 hbisect.printresult(ui, repo, state, displayer, nodes, good)
941 else:
941 else:
942 assert len(nodes) == 1 # only a single node can be tested next
942 assert len(nodes) == 1 # only a single node can be tested next
943 node = nodes[0]
943 node = nodes[0]
944 # compute the approximate number of remaining tests
944 # compute the approximate number of remaining tests
945 tests, size = 0, 2
945 tests, size = 0, 2
946 while size <= changesets:
946 while size <= changesets:
947 tests, size = tests + 1, size * 2
947 tests, size = tests + 1, size * 2
948 rev = repo.changelog.rev(node)
948 rev = repo.changelog.rev(node)
949 ui.write(_("Testing changeset %d:%s "
949 ui.write(_("Testing changeset %d:%s "
950 "(%d changesets remaining, ~%d tests)\n")
950 "(%d changesets remaining, ~%d tests)\n")
951 % (rev, short(node), changesets, tests))
951 % (rev, short(node), changesets, tests))
952 state['current'] = [node]
952 state['current'] = [node]
953 hbisect.save_state(repo, state)
953 hbisect.save_state(repo, state)
954 return mayupdate(repo, node)
954 return mayupdate(repo, node)
955
955
956 @command('bookmarks|bookmark',
956 @command('bookmarks|bookmark',
957 [('f', 'force', False, _('force')),
957 [('f', 'force', False, _('force')),
958 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
958 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
959 ('d', 'delete', False, _('delete a given bookmark')),
959 ('d', 'delete', False, _('delete a given bookmark')),
960 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
960 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
961 ('i', 'inactive', False, _('mark a bookmark inactive')),
961 ('i', 'inactive', False, _('mark a bookmark inactive')),
962 ] + formatteropts,
962 ] + formatteropts,
963 _('hg bookmarks [OPTIONS]... [NAME]...'))
963 _('hg bookmarks [OPTIONS]... [NAME]...'))
964 def bookmark(ui, repo, *names, **opts):
964 def bookmark(ui, repo, *names, **opts):
965 '''create a new bookmark or list existing bookmarks
965 '''create a new bookmark or list existing bookmarks
966
966
967 Bookmarks are labels on changesets to help track lines of development.
967 Bookmarks are labels on changesets to help track lines of development.
968 Bookmarks are unversioned and can be moved, renamed and deleted.
968 Bookmarks are unversioned and can be moved, renamed and deleted.
969 Deleting or moving a bookmark has no effect on the associated changesets.
969 Deleting or moving a bookmark has no effect on the associated changesets.
970
970
971 Creating or updating to a bookmark causes it to be marked as 'active'.
971 Creating or updating to a bookmark causes it to be marked as 'active'.
972 The active bookmark is indicated with a '*'.
972 The active bookmark is indicated with a '*'.
973 When a commit is made, the active bookmark will advance to the new commit.
973 When a commit is made, the active bookmark will advance to the new commit.
974 A plain :hg:`update` will also advance an active bookmark, if possible.
974 A plain :hg:`update` will also advance an active bookmark, if possible.
975 Updating away from a bookmark will cause it to be deactivated.
975 Updating away from a bookmark will cause it to be deactivated.
976
976
977 Bookmarks can be pushed and pulled between repositories (see
977 Bookmarks can be pushed and pulled between repositories (see
978 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
978 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
979 diverged, a new 'divergent bookmark' of the form 'name@path' will
979 diverged, a new 'divergent bookmark' of the form 'name@path' will
980 be created. Using :hg:`merge` will resolve the divergence.
980 be created. Using :hg:`merge` will resolve the divergence.
981
981
982 A bookmark named '@' has the special property that :hg:`clone` will
982 A bookmark named '@' has the special property that :hg:`clone` will
983 check it out by default if it exists.
983 check it out by default if it exists.
984
984
985 .. container:: verbose
985 .. container:: verbose
986
986
987 Examples:
987 Examples:
988
988
989 - create an active bookmark for a new line of development::
989 - create an active bookmark for a new line of development::
990
990
991 hg book new-feature
991 hg book new-feature
992
992
993 - create an inactive bookmark as a place marker::
993 - create an inactive bookmark as a place marker::
994
994
995 hg book -i reviewed
995 hg book -i reviewed
996
996
997 - create an inactive bookmark on another changeset::
997 - create an inactive bookmark on another changeset::
998
998
999 hg book -r .^ tested
999 hg book -r .^ tested
1000
1000
1001 - rename bookmark turkey to dinner::
1001 - rename bookmark turkey to dinner::
1002
1002
1003 hg book -m turkey dinner
1003 hg book -m turkey dinner
1004
1004
1005 - move the '@' bookmark from another branch::
1005 - move the '@' bookmark from another branch::
1006
1006
1007 hg book -f @
1007 hg book -f @
1008 '''
1008 '''
1009 opts = pycompat.byteskwargs(opts)
1009 opts = pycompat.byteskwargs(opts)
1010 force = opts.get('force')
1010 force = opts.get('force')
1011 rev = opts.get('rev')
1011 rev = opts.get('rev')
1012 delete = opts.get('delete')
1012 delete = opts.get('delete')
1013 rename = opts.get('rename')
1013 rename = opts.get('rename')
1014 inactive = opts.get('inactive')
1014 inactive = opts.get('inactive')
1015
1015
1016 def checkformat(mark):
1016 def checkformat(mark):
1017 mark = mark.strip()
1017 mark = mark.strip()
1018 if not mark:
1018 if not mark:
1019 raise error.Abort(_("bookmark names cannot consist entirely of "
1019 raise error.Abort(_("bookmark names cannot consist entirely of "
1020 "whitespace"))
1020 "whitespace"))
1021 scmutil.checknewlabel(repo, mark, 'bookmark')
1021 scmutil.checknewlabel(repo, mark, 'bookmark')
1022 return mark
1022 return mark
1023
1023
1024 def checkconflict(repo, mark, cur, force=False, target=None):
1024 def checkconflict(repo, mark, cur, force=False, target=None):
1025 if mark in marks and not force:
1025 if mark in marks and not force:
1026 if target:
1026 if target:
1027 if marks[mark] == target and target == cur:
1027 if marks[mark] == target and target == cur:
1028 # re-activating a bookmark
1028 # re-activating a bookmark
1029 return
1029 return
1030 anc = repo.changelog.ancestors([repo[target].rev()])
1030 anc = repo.changelog.ancestors([repo[target].rev()])
1031 bmctx = repo[marks[mark]]
1031 bmctx = repo[marks[mark]]
1032 divs = [repo[b].node() for b in marks
1032 divs = [repo[b].node() for b in marks
1033 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1033 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1034
1034
1035 # allow resolving a single divergent bookmark even if moving
1035 # allow resolving a single divergent bookmark even if moving
1036 # the bookmark across branches when a revision is specified
1036 # the bookmark across branches when a revision is specified
1037 # that contains a divergent bookmark
1037 # that contains a divergent bookmark
1038 if bmctx.rev() not in anc and target in divs:
1038 if bmctx.rev() not in anc and target in divs:
1039 bookmarks.deletedivergent(repo, [target], mark)
1039 bookmarks.deletedivergent(repo, [target], mark)
1040 return
1040 return
1041
1041
1042 deletefrom = [b for b in divs
1042 deletefrom = [b for b in divs
1043 if repo[b].rev() in anc or b == target]
1043 if repo[b].rev() in anc or b == target]
1044 bookmarks.deletedivergent(repo, deletefrom, mark)
1044 bookmarks.deletedivergent(repo, deletefrom, mark)
1045 if bookmarks.validdest(repo, bmctx, repo[target]):
1045 if bookmarks.validdest(repo, bmctx, repo[target]):
1046 ui.status(_("moving bookmark '%s' forward from %s\n") %
1046 ui.status(_("moving bookmark '%s' forward from %s\n") %
1047 (mark, short(bmctx.node())))
1047 (mark, short(bmctx.node())))
1048 return
1048 return
1049 raise error.Abort(_("bookmark '%s' already exists "
1049 raise error.Abort(_("bookmark '%s' already exists "
1050 "(use -f to force)") % mark)
1050 "(use -f to force)") % mark)
1051 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1051 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1052 and not force):
1052 and not force):
1053 raise error.Abort(
1053 raise error.Abort(
1054 _("a bookmark cannot have the name of an existing branch"))
1054 _("a bookmark cannot have the name of an existing branch"))
1055
1055
1056 if delete and rename:
1056 if delete and rename:
1057 raise error.Abort(_("--delete and --rename are incompatible"))
1057 raise error.Abort(_("--delete and --rename are incompatible"))
1058 if delete and rev:
1058 if delete and rev:
1059 raise error.Abort(_("--rev is incompatible with --delete"))
1059 raise error.Abort(_("--rev is incompatible with --delete"))
1060 if rename and rev:
1060 if rename and rev:
1061 raise error.Abort(_("--rev is incompatible with --rename"))
1061 raise error.Abort(_("--rev is incompatible with --rename"))
1062 if not names and (delete or rev):
1062 if not names and (delete or rev):
1063 raise error.Abort(_("bookmark name required"))
1063 raise error.Abort(_("bookmark name required"))
1064
1064
1065 if delete or rename or names or inactive:
1065 if delete or rename or names or inactive:
1066 wlock = lock = tr = None
1066 wlock = lock = tr = None
1067 try:
1067 try:
1068 wlock = repo.wlock()
1068 wlock = repo.wlock()
1069 lock = repo.lock()
1069 lock = repo.lock()
1070 cur = repo.changectx('.').node()
1070 cur = repo.changectx('.').node()
1071 marks = repo._bookmarks
1071 marks = repo._bookmarks
1072 if delete:
1072 if delete:
1073 tr = repo.transaction('bookmark')
1073 tr = repo.transaction('bookmark')
1074 for mark in names:
1074 for mark in names:
1075 if mark not in marks:
1075 if mark not in marks:
1076 raise error.Abort(_("bookmark '%s' does not exist") %
1076 raise error.Abort(_("bookmark '%s' does not exist") %
1077 mark)
1077 mark)
1078 if mark == repo._activebookmark:
1078 if mark == repo._activebookmark:
1079 bookmarks.deactivate(repo)
1079 bookmarks.deactivate(repo)
1080 del marks[mark]
1080 del marks[mark]
1081
1081
1082 elif rename:
1082 elif rename:
1083 tr = repo.transaction('bookmark')
1083 tr = repo.transaction('bookmark')
1084 if not names:
1084 if not names:
1085 raise error.Abort(_("new bookmark name required"))
1085 raise error.Abort(_("new bookmark name required"))
1086 elif len(names) > 1:
1086 elif len(names) > 1:
1087 raise error.Abort(_("only one new bookmark name allowed"))
1087 raise error.Abort(_("only one new bookmark name allowed"))
1088 mark = checkformat(names[0])
1088 mark = checkformat(names[0])
1089 if rename not in marks:
1089 if rename not in marks:
1090 raise error.Abort(_("bookmark '%s' does not exist")
1090 raise error.Abort(_("bookmark '%s' does not exist")
1091 % rename)
1091 % rename)
1092 checkconflict(repo, mark, cur, force)
1092 checkconflict(repo, mark, cur, force)
1093 marks[mark] = marks[rename]
1093 marks[mark] = marks[rename]
1094 if repo._activebookmark == rename and not inactive:
1094 if repo._activebookmark == rename and not inactive:
1095 bookmarks.activate(repo, mark)
1095 bookmarks.activate(repo, mark)
1096 del marks[rename]
1096 del marks[rename]
1097 elif names:
1097 elif names:
1098 tr = repo.transaction('bookmark')
1098 tr = repo.transaction('bookmark')
1099 newact = None
1099 newact = None
1100 for mark in names:
1100 for mark in names:
1101 mark = checkformat(mark)
1101 mark = checkformat(mark)
1102 if newact is None:
1102 if newact is None:
1103 newact = mark
1103 newact = mark
1104 if inactive and mark == repo._activebookmark:
1104 if inactive and mark == repo._activebookmark:
1105 bookmarks.deactivate(repo)
1105 bookmarks.deactivate(repo)
1106 return
1106 return
1107 tgt = cur
1107 tgt = cur
1108 if rev:
1108 if rev:
1109 tgt = scmutil.revsingle(repo, rev).node()
1109 tgt = scmutil.revsingle(repo, rev).node()
1110 checkconflict(repo, mark, cur, force, tgt)
1110 checkconflict(repo, mark, cur, force, tgt)
1111 marks[mark] = tgt
1111 marks[mark] = tgt
1112 if not inactive and cur == marks[newact] and not rev:
1112 if not inactive and cur == marks[newact] and not rev:
1113 bookmarks.activate(repo, newact)
1113 bookmarks.activate(repo, newact)
1114 elif cur != tgt and newact == repo._activebookmark:
1114 elif cur != tgt and newact == repo._activebookmark:
1115 bookmarks.deactivate(repo)
1115 bookmarks.deactivate(repo)
1116 elif inactive:
1116 elif inactive:
1117 if len(marks) == 0:
1117 if len(marks) == 0:
1118 ui.status(_("no bookmarks set\n"))
1118 ui.status(_("no bookmarks set\n"))
1119 elif not repo._activebookmark:
1119 elif not repo._activebookmark:
1120 ui.status(_("no active bookmark\n"))
1120 ui.status(_("no active bookmark\n"))
1121 else:
1121 else:
1122 bookmarks.deactivate(repo)
1122 bookmarks.deactivate(repo)
1123 if tr is not None:
1123 if tr is not None:
1124 marks.recordchange(tr)
1124 marks.recordchange(tr)
1125 tr.close()
1125 tr.close()
1126 finally:
1126 finally:
1127 lockmod.release(tr, lock, wlock)
1127 lockmod.release(tr, lock, wlock)
1128 else: # show bookmarks
1128 else: # show bookmarks
1129 fm = ui.formatter('bookmarks', opts)
1129 fm = ui.formatter('bookmarks', opts)
1130 hexfn = fm.hexfunc
1130 hexfn = fm.hexfunc
1131 marks = repo._bookmarks
1131 marks = repo._bookmarks
1132 if len(marks) == 0 and fm.isplain():
1132 if len(marks) == 0 and fm.isplain():
1133 ui.status(_("no bookmarks set\n"))
1133 ui.status(_("no bookmarks set\n"))
1134 for bmark, n in sorted(marks.iteritems()):
1134 for bmark, n in sorted(marks.iteritems()):
1135 active = repo._activebookmark
1135 active = repo._activebookmark
1136 if bmark == active:
1136 if bmark == active:
1137 prefix, label = '*', activebookmarklabel
1137 prefix, label = '*', activebookmarklabel
1138 else:
1138 else:
1139 prefix, label = ' ', ''
1139 prefix, label = ' ', ''
1140
1140
1141 fm.startitem()
1141 fm.startitem()
1142 if not ui.quiet:
1142 if not ui.quiet:
1143 fm.plain(' %s ' % prefix, label=label)
1143 fm.plain(' %s ' % prefix, label=label)
1144 fm.write('bookmark', '%s', bmark, label=label)
1144 fm.write('bookmark', '%s', bmark, label=label)
1145 pad = " " * (25 - encoding.colwidth(bmark))
1145 pad = " " * (25 - encoding.colwidth(bmark))
1146 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1146 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1147 repo.changelog.rev(n), hexfn(n), label=label)
1147 repo.changelog.rev(n), hexfn(n), label=label)
1148 fm.data(active=(bmark == active))
1148 fm.data(active=(bmark == active))
1149 fm.plain('\n')
1149 fm.plain('\n')
1150 fm.end()
1150 fm.end()
1151
1151
1152 @command('branch',
1152 @command('branch',
1153 [('f', 'force', None,
1153 [('f', 'force', None,
1154 _('set branch name even if it shadows an existing branch')),
1154 _('set branch name even if it shadows an existing branch')),
1155 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1155 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1156 _('[-fC] [NAME]'))
1156 _('[-fC] [NAME]'))
1157 def branch(ui, repo, label=None, **opts):
1157 def branch(ui, repo, label=None, **opts):
1158 """set or show the current branch name
1158 """set or show the current branch name
1159
1159
1160 .. note::
1160 .. note::
1161
1161
1162 Branch names are permanent and global. Use :hg:`bookmark` to create a
1162 Branch names are permanent and global. Use :hg:`bookmark` to create a
1163 light-weight bookmark instead. See :hg:`help glossary` for more
1163 light-weight bookmark instead. See :hg:`help glossary` for more
1164 information about named branches and bookmarks.
1164 information about named branches and bookmarks.
1165
1165
1166 With no argument, show the current branch name. With one argument,
1166 With no argument, show the current branch name. With one argument,
1167 set the working directory branch name (the branch will not exist
1167 set the working directory branch name (the branch will not exist
1168 in the repository until the next commit). Standard practice
1168 in the repository until the next commit). Standard practice
1169 recommends that primary development take place on the 'default'
1169 recommends that primary development take place on the 'default'
1170 branch.
1170 branch.
1171
1171
1172 Unless -f/--force is specified, branch will not let you set a
1172 Unless -f/--force is specified, branch will not let you set a
1173 branch name that already exists.
1173 branch name that already exists.
1174
1174
1175 Use -C/--clean to reset the working directory branch to that of
1175 Use -C/--clean to reset the working directory branch to that of
1176 the parent of the working directory, negating a previous branch
1176 the parent of the working directory, negating a previous branch
1177 change.
1177 change.
1178
1178
1179 Use the command :hg:`update` to switch to an existing branch. Use
1179 Use the command :hg:`update` to switch to an existing branch. Use
1180 :hg:`commit --close-branch` to mark this branch head as closed.
1180 :hg:`commit --close-branch` to mark this branch head as closed.
1181 When all heads of a branch are closed, the branch will be
1181 When all heads of a branch are closed, the branch will be
1182 considered closed.
1182 considered closed.
1183
1183
1184 Returns 0 on success.
1184 Returns 0 on success.
1185 """
1185 """
1186 opts = pycompat.byteskwargs(opts)
1186 opts = pycompat.byteskwargs(opts)
1187 if label:
1187 if label:
1188 label = label.strip()
1188 label = label.strip()
1189
1189
1190 if not opts.get('clean') and not label:
1190 if not opts.get('clean') and not label:
1191 ui.write("%s\n" % repo.dirstate.branch())
1191 ui.write("%s\n" % repo.dirstate.branch())
1192 return
1192 return
1193
1193
1194 with repo.wlock():
1194 with repo.wlock():
1195 if opts.get('clean'):
1195 if opts.get('clean'):
1196 label = repo[None].p1().branch()
1196 label = repo[None].p1().branch()
1197 repo.dirstate.setbranch(label)
1197 repo.dirstate.setbranch(label)
1198 ui.status(_('reset working directory to branch %s\n') % label)
1198 ui.status(_('reset working directory to branch %s\n') % label)
1199 elif label:
1199 elif label:
1200 if not opts.get('force') and label in repo.branchmap():
1200 if not opts.get('force') and label in repo.branchmap():
1201 if label not in [p.branch() for p in repo[None].parents()]:
1201 if label not in [p.branch() for p in repo[None].parents()]:
1202 raise error.Abort(_('a branch of the same name already'
1202 raise error.Abort(_('a branch of the same name already'
1203 ' exists'),
1203 ' exists'),
1204 # i18n: "it" refers to an existing branch
1204 # i18n: "it" refers to an existing branch
1205 hint=_("use 'hg update' to switch to it"))
1205 hint=_("use 'hg update' to switch to it"))
1206 scmutil.checknewlabel(repo, label, 'branch')
1206 scmutil.checknewlabel(repo, label, 'branch')
1207 repo.dirstate.setbranch(label)
1207 repo.dirstate.setbranch(label)
1208 ui.status(_('marked working directory as branch %s\n') % label)
1208 ui.status(_('marked working directory as branch %s\n') % label)
1209
1209
1210 # find any open named branches aside from default
1210 # find any open named branches aside from default
1211 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1211 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1212 if n != "default" and not c]
1212 if n != "default" and not c]
1213 if not others:
1213 if not others:
1214 ui.status(_('(branches are permanent and global, '
1214 ui.status(_('(branches are permanent and global, '
1215 'did you want a bookmark?)\n'))
1215 'did you want a bookmark?)\n'))
1216
1216
1217 @command('branches',
1217 @command('branches',
1218 [('a', 'active', False,
1218 [('a', 'active', False,
1219 _('show only branches that have unmerged heads (DEPRECATED)')),
1219 _('show only branches that have unmerged heads (DEPRECATED)')),
1220 ('c', 'closed', False, _('show normal and closed branches')),
1220 ('c', 'closed', False, _('show normal and closed branches')),
1221 ] + formatteropts,
1221 ] + formatteropts,
1222 _('[-c]'))
1222 _('[-c]'))
1223 def branches(ui, repo, active=False, closed=False, **opts):
1223 def branches(ui, repo, active=False, closed=False, **opts):
1224 """list repository named branches
1224 """list repository named branches
1225
1225
1226 List the repository's named branches, indicating which ones are
1226 List the repository's named branches, indicating which ones are
1227 inactive. If -c/--closed is specified, also list branches which have
1227 inactive. If -c/--closed is specified, also list branches which have
1228 been marked closed (see :hg:`commit --close-branch`).
1228 been marked closed (see :hg:`commit --close-branch`).
1229
1229
1230 Use the command :hg:`update` to switch to an existing branch.
1230 Use the command :hg:`update` to switch to an existing branch.
1231
1231
1232 Returns 0.
1232 Returns 0.
1233 """
1233 """
1234
1234
1235 opts = pycompat.byteskwargs(opts)
1235 opts = pycompat.byteskwargs(opts)
1236 ui.pager('branches')
1236 ui.pager('branches')
1237 fm = ui.formatter('branches', opts)
1237 fm = ui.formatter('branches', opts)
1238 hexfunc = fm.hexfunc
1238 hexfunc = fm.hexfunc
1239
1239
1240 allheads = set(repo.heads())
1240 allheads = set(repo.heads())
1241 branches = []
1241 branches = []
1242 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1242 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1243 isactive = not isclosed and bool(set(heads) & allheads)
1243 isactive = not isclosed and bool(set(heads) & allheads)
1244 branches.append((tag, repo[tip], isactive, not isclosed))
1244 branches.append((tag, repo[tip], isactive, not isclosed))
1245 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1245 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1246 reverse=True)
1246 reverse=True)
1247
1247
1248 for tag, ctx, isactive, isopen in branches:
1248 for tag, ctx, isactive, isopen in branches:
1249 if active and not isactive:
1249 if active and not isactive:
1250 continue
1250 continue
1251 if isactive:
1251 if isactive:
1252 label = 'branches.active'
1252 label = 'branches.active'
1253 notice = ''
1253 notice = ''
1254 elif not isopen:
1254 elif not isopen:
1255 if not closed:
1255 if not closed:
1256 continue
1256 continue
1257 label = 'branches.closed'
1257 label = 'branches.closed'
1258 notice = _(' (closed)')
1258 notice = _(' (closed)')
1259 else:
1259 else:
1260 label = 'branches.inactive'
1260 label = 'branches.inactive'
1261 notice = _(' (inactive)')
1261 notice = _(' (inactive)')
1262 current = (tag == repo.dirstate.branch())
1262 current = (tag == repo.dirstate.branch())
1263 if current:
1263 if current:
1264 label = 'branches.current'
1264 label = 'branches.current'
1265
1265
1266 fm.startitem()
1266 fm.startitem()
1267 fm.write('branch', '%s', tag, label=label)
1267 fm.write('branch', '%s', tag, label=label)
1268 rev = ctx.rev()
1268 rev = ctx.rev()
1269 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1269 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1270 fmt = ' ' * padsize + ' %d:%s'
1270 fmt = ' ' * padsize + ' %d:%s'
1271 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1271 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1272 label='log.changeset changeset.%s' % ctx.phasestr())
1272 label='log.changeset changeset.%s' % ctx.phasestr())
1273 fm.context(ctx=ctx)
1273 fm.context(ctx=ctx)
1274 fm.data(active=isactive, closed=not isopen, current=current)
1274 fm.data(active=isactive, closed=not isopen, current=current)
1275 if not ui.quiet:
1275 if not ui.quiet:
1276 fm.plain(notice)
1276 fm.plain(notice)
1277 fm.plain('\n')
1277 fm.plain('\n')
1278 fm.end()
1278 fm.end()
1279
1279
1280 @command('bundle',
1280 @command('bundle',
1281 [('f', 'force', None, _('run even when the destination is unrelated')),
1281 [('f', 'force', None, _('run even when the destination is unrelated')),
1282 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1282 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1283 _('REV')),
1283 _('REV')),
1284 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1284 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1285 _('BRANCH')),
1285 _('BRANCH')),
1286 ('', 'base', [],
1286 ('', 'base', [],
1287 _('a base changeset assumed to be available at the destination'),
1287 _('a base changeset assumed to be available at the destination'),
1288 _('REV')),
1288 _('REV')),
1289 ('a', 'all', None, _('bundle all changesets in the repository')),
1289 ('a', 'all', None, _('bundle all changesets in the repository')),
1290 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1290 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1291 ] + remoteopts,
1291 ] + remoteopts,
1292 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1292 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1293 def bundle(ui, repo, fname, dest=None, **opts):
1293 def bundle(ui, repo, fname, dest=None, **opts):
1294 """create a bundle file
1294 """create a bundle file
1295
1295
1296 Generate a bundle file containing data to be added to a repository.
1296 Generate a bundle file containing data to be added to a repository.
1297
1297
1298 To create a bundle containing all changesets, use -a/--all
1298 To create a bundle containing all changesets, use -a/--all
1299 (or --base null). Otherwise, hg assumes the destination will have
1299 (or --base null). Otherwise, hg assumes the destination will have
1300 all the nodes you specify with --base parameters. Otherwise, hg
1300 all the nodes you specify with --base parameters. Otherwise, hg
1301 will assume the repository has all the nodes in destination, or
1301 will assume the repository has all the nodes in destination, or
1302 default-push/default if no destination is specified.
1302 default-push/default if no destination is specified.
1303
1303
1304 You can change bundle format with the -t/--type option. See
1304 You can change bundle format with the -t/--type option. See
1305 :hg:`help bundlespec` for documentation on this format. By default,
1305 :hg:`help bundlespec` for documentation on this format. By default,
1306 the most appropriate format is used and compression defaults to
1306 the most appropriate format is used and compression defaults to
1307 bzip2.
1307 bzip2.
1308
1308
1309 The bundle file can then be transferred using conventional means
1309 The bundle file can then be transferred using conventional means
1310 and applied to another repository with the unbundle or pull
1310 and applied to another repository with the unbundle or pull
1311 command. This is useful when direct push and pull are not
1311 command. This is useful when direct push and pull are not
1312 available or when exporting an entire repository is undesirable.
1312 available or when exporting an entire repository is undesirable.
1313
1313
1314 Applying bundles preserves all changeset contents including
1314 Applying bundles preserves all changeset contents including
1315 permissions, copy/rename information, and revision history.
1315 permissions, copy/rename information, and revision history.
1316
1316
1317 Returns 0 on success, 1 if no changes found.
1317 Returns 0 on success, 1 if no changes found.
1318 """
1318 """
1319 opts = pycompat.byteskwargs(opts)
1319 opts = pycompat.byteskwargs(opts)
1320 revs = None
1320 revs = None
1321 if 'rev' in opts:
1321 if 'rev' in opts:
1322 revstrings = opts['rev']
1322 revstrings = opts['rev']
1323 revs = scmutil.revrange(repo, revstrings)
1323 revs = scmutil.revrange(repo, revstrings)
1324 if revstrings and not revs:
1324 if revstrings and not revs:
1325 raise error.Abort(_('no commits to bundle'))
1325 raise error.Abort(_('no commits to bundle'))
1326
1326
1327 bundletype = opts.get('type', 'bzip2').lower()
1327 bundletype = opts.get('type', 'bzip2').lower()
1328 try:
1328 try:
1329 bcompression, cgversion, params = exchange.parsebundlespec(
1329 bcompression, cgversion, params = exchange.parsebundlespec(
1330 repo, bundletype, strict=False)
1330 repo, bundletype, strict=False)
1331 except error.UnsupportedBundleSpecification as e:
1331 except error.UnsupportedBundleSpecification as e:
1332 raise error.Abort(str(e),
1332 raise error.Abort(str(e),
1333 hint=_("see 'hg help bundlespec' for supported "
1333 hint=_("see 'hg help bundlespec' for supported "
1334 "values for --type"))
1334 "values for --type"))
1335
1335
1336 # Packed bundles are a pseudo bundle format for now.
1336 # Packed bundles are a pseudo bundle format for now.
1337 if cgversion == 's1':
1337 if cgversion == 's1':
1338 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1338 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1339 hint=_("use 'hg debugcreatestreamclonebundle'"))
1339 hint=_("use 'hg debugcreatestreamclonebundle'"))
1340
1340
1341 if opts.get('all'):
1341 if opts.get('all'):
1342 if dest:
1342 if dest:
1343 raise error.Abort(_("--all is incompatible with specifying "
1343 raise error.Abort(_("--all is incompatible with specifying "
1344 "a destination"))
1344 "a destination"))
1345 if opts.get('base'):
1345 if opts.get('base'):
1346 ui.warn(_("ignoring --base because --all was specified\n"))
1346 ui.warn(_("ignoring --base because --all was specified\n"))
1347 base = ['null']
1347 base = ['null']
1348 else:
1348 else:
1349 base = scmutil.revrange(repo, opts.get('base'))
1349 base = scmutil.revrange(repo, opts.get('base'))
1350 # TODO: get desired bundlecaps from command line.
1350 # TODO: get desired bundlecaps from command line.
1351 bundlecaps = None
1351 bundlecaps = None
1352 if cgversion not in changegroup.supportedoutgoingversions(repo):
1352 if cgversion not in changegroup.supportedoutgoingversions(repo):
1353 raise error.Abort(_("repository does not support bundle version %s") %
1353 raise error.Abort(_("repository does not support bundle version %s") %
1354 cgversion)
1354 cgversion)
1355
1355
1356 if base:
1356 if base:
1357 if dest:
1357 if dest:
1358 raise error.Abort(_("--base is incompatible with specifying "
1358 raise error.Abort(_("--base is incompatible with specifying "
1359 "a destination"))
1359 "a destination"))
1360 common = [repo.lookup(rev) for rev in base]
1360 common = [repo.lookup(rev) for rev in base]
1361 heads = revs and map(repo.lookup, revs) or None
1361 heads = revs and map(repo.lookup, revs) or None
1362 outgoing = discovery.outgoing(repo, common, heads)
1362 outgoing = discovery.outgoing(repo, common, heads)
1363 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1363 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1364 bundlecaps=bundlecaps,
1364 bundlecaps=bundlecaps,
1365 version=cgversion)
1365 version=cgversion)
1366 outgoing = None
1366 outgoing = None
1367 else:
1367 else:
1368 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1368 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1369 dest, branches = hg.parseurl(dest, opts.get('branch'))
1369 dest, branches = hg.parseurl(dest, opts.get('branch'))
1370 other = hg.peer(repo, opts, dest)
1370 other = hg.peer(repo, opts, dest)
1371 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1371 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1372 heads = revs and map(repo.lookup, revs) or revs
1372 heads = revs and map(repo.lookup, revs) or revs
1373 outgoing = discovery.findcommonoutgoing(repo, other,
1373 outgoing = discovery.findcommonoutgoing(repo, other,
1374 onlyheads=heads,
1374 onlyheads=heads,
1375 force=opts.get('force'),
1375 force=opts.get('force'),
1376 portable=True)
1376 portable=True)
1377 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1377 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1378 bundlecaps, version=cgversion)
1378 bundlecaps, version=cgversion)
1379 if not cg:
1379 if not cg:
1380 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1380 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1381 return 1
1381 return 1
1382
1382
1383 if cgversion == '01': #bundle1
1383 if cgversion == '01': #bundle1
1384 if bcompression is None:
1384 if bcompression is None:
1385 bcompression = 'UN'
1385 bcompression = 'UN'
1386 bversion = 'HG10' + bcompression
1386 bversion = 'HG10' + bcompression
1387 bcompression = None
1387 bcompression = None
1388 elif cgversion in ('02', '03'):
1388 elif cgversion in ('02', '03'):
1389 bversion = 'HG20'
1389 bversion = 'HG20'
1390 else:
1390 else:
1391 raise error.ProgrammingError(
1391 raise error.ProgrammingError(
1392 'bundle: unexpected changegroup version %s' % cgversion)
1392 'bundle: unexpected changegroup version %s' % cgversion)
1393
1393
1394 # TODO compression options should be derived from bundlespec parsing.
1394 # TODO compression options should be derived from bundlespec parsing.
1395 # This is a temporary hack to allow adjusting bundle compression
1395 # This is a temporary hack to allow adjusting bundle compression
1396 # level without a) formalizing the bundlespec changes to declare it
1396 # level without a) formalizing the bundlespec changes to declare it
1397 # b) introducing a command flag.
1397 # b) introducing a command flag.
1398 compopts = {}
1398 compopts = {}
1399 complevel = ui.configint('experimental', 'bundlecomplevel')
1399 complevel = ui.configint('experimental', 'bundlecomplevel')
1400 if complevel is not None:
1400 if complevel is not None:
1401 compopts['level'] = complevel
1401 compopts['level'] = complevel
1402
1402
1403 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1403 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1404 compopts=compopts)
1404 compopts=compopts)
1405
1405
1406 @command('cat',
1406 @command('cat',
1407 [('o', 'output', '',
1407 [('o', 'output', '',
1408 _('print output to file with formatted name'), _('FORMAT')),
1408 _('print output to file with formatted name'), _('FORMAT')),
1409 ('r', 'rev', '', _('print the given revision'), _('REV')),
1409 ('r', 'rev', '', _('print the given revision'), _('REV')),
1410 ('', 'decode', None, _('apply any matching decode filter')),
1410 ('', 'decode', None, _('apply any matching decode filter')),
1411 ] + walkopts,
1411 ] + walkopts,
1412 _('[OPTION]... FILE...'),
1412 _('[OPTION]... FILE...'),
1413 inferrepo=True)
1413 inferrepo=True)
1414 def cat(ui, repo, file1, *pats, **opts):
1414 def cat(ui, repo, file1, *pats, **opts):
1415 """output the current or given revision of files
1415 """output the current or given revision of files
1416
1416
1417 Print the specified files as they were at the given revision. If
1417 Print the specified files as they were at the given revision. If
1418 no revision is given, the parent of the working directory is used.
1418 no revision is given, the parent of the working directory is used.
1419
1419
1420 Output may be to a file, in which case the name of the file is
1420 Output may be to a file, in which case the name of the file is
1421 given using a format string. The formatting rules as follows:
1421 given using a format string. The formatting rules as follows:
1422
1422
1423 :``%%``: literal "%" character
1423 :``%%``: literal "%" character
1424 :``%s``: basename of file being printed
1424 :``%s``: basename of file being printed
1425 :``%d``: dirname of file being printed, or '.' if in repository root
1425 :``%d``: dirname of file being printed, or '.' if in repository root
1426 :``%p``: root-relative path name of file being printed
1426 :``%p``: root-relative path name of file being printed
1427 :``%H``: changeset hash (40 hexadecimal digits)
1427 :``%H``: changeset hash (40 hexadecimal digits)
1428 :``%R``: changeset revision number
1428 :``%R``: changeset revision number
1429 :``%h``: short-form changeset hash (12 hexadecimal digits)
1429 :``%h``: short-form changeset hash (12 hexadecimal digits)
1430 :``%r``: zero-padded changeset revision number
1430 :``%r``: zero-padded changeset revision number
1431 :``%b``: basename of the exporting repository
1431 :``%b``: basename of the exporting repository
1432
1432
1433 Returns 0 on success.
1433 Returns 0 on success.
1434 """
1434 """
1435 ctx = scmutil.revsingle(repo, opts.get('rev'))
1435 ctx = scmutil.revsingle(repo, opts.get('rev'))
1436 m = scmutil.match(ctx, (file1,) + pats, opts)
1436 m = scmutil.match(ctx, (file1,) + pats, opts)
1437
1437
1438 ui.pager('cat')
1438 ui.pager('cat')
1439 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1439 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1440
1440
1441 @command('^clone',
1441 @command('^clone',
1442 [('U', 'noupdate', None, _('the clone will include an empty working '
1442 [('U', 'noupdate', None, _('the clone will include an empty working '
1443 'directory (only a repository)')),
1443 'directory (only a repository)')),
1444 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1444 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1445 _('REV')),
1445 _('REV')),
1446 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1446 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1447 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1447 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1448 ('', 'pull', None, _('use pull protocol to copy metadata')),
1448 ('', 'pull', None, _('use pull protocol to copy metadata')),
1449 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1449 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1450 ] + remoteopts,
1450 ] + remoteopts,
1451 _('[OPTION]... SOURCE [DEST]'),
1451 _('[OPTION]... SOURCE [DEST]'),
1452 norepo=True)
1452 norepo=True)
1453 def clone(ui, source, dest=None, **opts):
1453 def clone(ui, source, dest=None, **opts):
1454 """make a copy of an existing repository
1454 """make a copy of an existing repository
1455
1455
1456 Create a copy of an existing repository in a new directory.
1456 Create a copy of an existing repository in a new directory.
1457
1457
1458 If no destination directory name is specified, it defaults to the
1458 If no destination directory name is specified, it defaults to the
1459 basename of the source.
1459 basename of the source.
1460
1460
1461 The location of the source is added to the new repository's
1461 The location of the source is added to the new repository's
1462 ``.hg/hgrc`` file, as the default to be used for future pulls.
1462 ``.hg/hgrc`` file, as the default to be used for future pulls.
1463
1463
1464 Only local paths and ``ssh://`` URLs are supported as
1464 Only local paths and ``ssh://`` URLs are supported as
1465 destinations. For ``ssh://`` destinations, no working directory or
1465 destinations. For ``ssh://`` destinations, no working directory or
1466 ``.hg/hgrc`` will be created on the remote side.
1466 ``.hg/hgrc`` will be created on the remote side.
1467
1467
1468 If the source repository has a bookmark called '@' set, that
1468 If the source repository has a bookmark called '@' set, that
1469 revision will be checked out in the new repository by default.
1469 revision will be checked out in the new repository by default.
1470
1470
1471 To check out a particular version, use -u/--update, or
1471 To check out a particular version, use -u/--update, or
1472 -U/--noupdate to create a clone with no working directory.
1472 -U/--noupdate to create a clone with no working directory.
1473
1473
1474 To pull only a subset of changesets, specify one or more revisions
1474 To pull only a subset of changesets, specify one or more revisions
1475 identifiers with -r/--rev or branches with -b/--branch. The
1475 identifiers with -r/--rev or branches with -b/--branch. The
1476 resulting clone will contain only the specified changesets and
1476 resulting clone will contain only the specified changesets and
1477 their ancestors. These options (or 'clone src#rev dest') imply
1477 their ancestors. These options (or 'clone src#rev dest') imply
1478 --pull, even for local source repositories.
1478 --pull, even for local source repositories.
1479
1479
1480 .. note::
1480 .. note::
1481
1481
1482 Specifying a tag will include the tagged changeset but not the
1482 Specifying a tag will include the tagged changeset but not the
1483 changeset containing the tag.
1483 changeset containing the tag.
1484
1484
1485 .. container:: verbose
1485 .. container:: verbose
1486
1486
1487 For efficiency, hardlinks are used for cloning whenever the
1487 For efficiency, hardlinks are used for cloning whenever the
1488 source and destination are on the same filesystem (note this
1488 source and destination are on the same filesystem (note this
1489 applies only to the repository data, not to the working
1489 applies only to the repository data, not to the working
1490 directory). Some filesystems, such as AFS, implement hardlinking
1490 directory). Some filesystems, such as AFS, implement hardlinking
1491 incorrectly, but do not report errors. In these cases, use the
1491 incorrectly, but do not report errors. In these cases, use the
1492 --pull option to avoid hardlinking.
1492 --pull option to avoid hardlinking.
1493
1493
1494 In some cases, you can clone repositories and the working
1494 In some cases, you can clone repositories and the working
1495 directory using full hardlinks with ::
1495 directory using full hardlinks with ::
1496
1496
1497 $ cp -al REPO REPOCLONE
1497 $ cp -al REPO REPOCLONE
1498
1498
1499 This is the fastest way to clone, but it is not always safe. The
1499 This is the fastest way to clone, but it is not always safe. The
1500 operation is not atomic (making sure REPO is not modified during
1500 operation is not atomic (making sure REPO is not modified during
1501 the operation is up to you) and you have to make sure your
1501 the operation is up to you) and you have to make sure your
1502 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1502 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1503 so). Also, this is not compatible with certain extensions that
1503 so). Also, this is not compatible with certain extensions that
1504 place their metadata under the .hg directory, such as mq.
1504 place their metadata under the .hg directory, such as mq.
1505
1505
1506 Mercurial will update the working directory to the first applicable
1506 Mercurial will update the working directory to the first applicable
1507 revision from this list:
1507 revision from this list:
1508
1508
1509 a) null if -U or the source repository has no changesets
1509 a) null if -U or the source repository has no changesets
1510 b) if -u . and the source repository is local, the first parent of
1510 b) if -u . and the source repository is local, the first parent of
1511 the source repository's working directory
1511 the source repository's working directory
1512 c) the changeset specified with -u (if a branch name, this means the
1512 c) the changeset specified with -u (if a branch name, this means the
1513 latest head of that branch)
1513 latest head of that branch)
1514 d) the changeset specified with -r
1514 d) the changeset specified with -r
1515 e) the tipmost head specified with -b
1515 e) the tipmost head specified with -b
1516 f) the tipmost head specified with the url#branch source syntax
1516 f) the tipmost head specified with the url#branch source syntax
1517 g) the revision marked with the '@' bookmark, if present
1517 g) the revision marked with the '@' bookmark, if present
1518 h) the tipmost head of the default branch
1518 h) the tipmost head of the default branch
1519 i) tip
1519 i) tip
1520
1520
1521 When cloning from servers that support it, Mercurial may fetch
1521 When cloning from servers that support it, Mercurial may fetch
1522 pre-generated data from a server-advertised URL. When this is done,
1522 pre-generated data from a server-advertised URL. When this is done,
1523 hooks operating on incoming changesets and changegroups may fire twice,
1523 hooks operating on incoming changesets and changegroups may fire twice,
1524 once for the bundle fetched from the URL and another for any additional
1524 once for the bundle fetched from the URL and another for any additional
1525 data not fetched from this URL. In addition, if an error occurs, the
1525 data not fetched from this URL. In addition, if an error occurs, the
1526 repository may be rolled back to a partial clone. This behavior may
1526 repository may be rolled back to a partial clone. This behavior may
1527 change in future releases. See :hg:`help -e clonebundles` for more.
1527 change in future releases. See :hg:`help -e clonebundles` for more.
1528
1528
1529 Examples:
1529 Examples:
1530
1530
1531 - clone a remote repository to a new directory named hg/::
1531 - clone a remote repository to a new directory named hg/::
1532
1532
1533 hg clone https://www.mercurial-scm.org/repo/hg/
1533 hg clone https://www.mercurial-scm.org/repo/hg/
1534
1534
1535 - create a lightweight local clone::
1535 - create a lightweight local clone::
1536
1536
1537 hg clone project/ project-feature/
1537 hg clone project/ project-feature/
1538
1538
1539 - clone from an absolute path on an ssh server (note double-slash)::
1539 - clone from an absolute path on an ssh server (note double-slash)::
1540
1540
1541 hg clone ssh://user@server//home/projects/alpha/
1541 hg clone ssh://user@server//home/projects/alpha/
1542
1542
1543 - do a high-speed clone over a LAN while checking out a
1543 - do a high-speed clone over a LAN while checking out a
1544 specified version::
1544 specified version::
1545
1545
1546 hg clone --uncompressed http://server/repo -u 1.5
1546 hg clone --uncompressed http://server/repo -u 1.5
1547
1547
1548 - create a repository without changesets after a particular revision::
1548 - create a repository without changesets after a particular revision::
1549
1549
1550 hg clone -r 04e544 experimental/ good/
1550 hg clone -r 04e544 experimental/ good/
1551
1551
1552 - clone (and track) a particular named branch::
1552 - clone (and track) a particular named branch::
1553
1553
1554 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1554 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1555
1555
1556 See :hg:`help urls` for details on specifying URLs.
1556 See :hg:`help urls` for details on specifying URLs.
1557
1557
1558 Returns 0 on success.
1558 Returns 0 on success.
1559 """
1559 """
1560 opts = pycompat.byteskwargs(opts)
1560 opts = pycompat.byteskwargs(opts)
1561 if opts.get('noupdate') and opts.get('updaterev'):
1561 if opts.get('noupdate') and opts.get('updaterev'):
1562 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1562 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1563
1563
1564 r = hg.clone(ui, opts, source, dest,
1564 r = hg.clone(ui, opts, source, dest,
1565 pull=opts.get('pull'),
1565 pull=opts.get('pull'),
1566 stream=opts.get('uncompressed'),
1566 stream=opts.get('uncompressed'),
1567 rev=opts.get('rev'),
1567 rev=opts.get('rev'),
1568 update=opts.get('updaterev') or not opts.get('noupdate'),
1568 update=opts.get('updaterev') or not opts.get('noupdate'),
1569 branch=opts.get('branch'),
1569 branch=opts.get('branch'),
1570 shareopts=opts.get('shareopts'))
1570 shareopts=opts.get('shareopts'))
1571
1571
1572 return r is None
1572 return r is None
1573
1573
1574 @command('^commit|ci',
1574 @command('^commit|ci',
1575 [('A', 'addremove', None,
1575 [('A', 'addremove', None,
1576 _('mark new/missing files as added/removed before committing')),
1576 _('mark new/missing files as added/removed before committing')),
1577 ('', 'close-branch', None,
1577 ('', 'close-branch', None,
1578 _('mark a branch head as closed')),
1578 _('mark a branch head as closed')),
1579 ('', 'amend', None, _('amend the parent of the working directory')),
1579 ('', 'amend', None, _('amend the parent of the working directory')),
1580 ('s', 'secret', None, _('use the secret phase for committing')),
1580 ('s', 'secret', None, _('use the secret phase for committing')),
1581 ('e', 'edit', None, _('invoke editor on commit messages')),
1581 ('e', 'edit', None, _('invoke editor on commit messages')),
1582 ('i', 'interactive', None, _('use interactive mode')),
1582 ('i', 'interactive', None, _('use interactive mode')),
1583 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1583 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1584 _('[OPTION]... [FILE]...'),
1584 _('[OPTION]... [FILE]...'),
1585 inferrepo=True)
1585 inferrepo=True)
1586 def commit(ui, repo, *pats, **opts):
1586 def commit(ui, repo, *pats, **opts):
1587 """commit the specified files or all outstanding changes
1587 """commit the specified files or all outstanding changes
1588
1588
1589 Commit changes to the given files into the repository. Unlike a
1589 Commit changes to the given files into the repository. Unlike a
1590 centralized SCM, this operation is a local operation. See
1590 centralized SCM, this operation is a local operation. See
1591 :hg:`push` for a way to actively distribute your changes.
1591 :hg:`push` for a way to actively distribute your changes.
1592
1592
1593 If a list of files is omitted, all changes reported by :hg:`status`
1593 If a list of files is omitted, all changes reported by :hg:`status`
1594 will be committed.
1594 will be committed.
1595
1595
1596 If you are committing the result of a merge, do not provide any
1596 If you are committing the result of a merge, do not provide any
1597 filenames or -I/-X filters.
1597 filenames or -I/-X filters.
1598
1598
1599 If no commit message is specified, Mercurial starts your
1599 If no commit message is specified, Mercurial starts your
1600 configured editor where you can enter a message. In case your
1600 configured editor where you can enter a message. In case your
1601 commit fails, you will find a backup of your message in
1601 commit fails, you will find a backup of your message in
1602 ``.hg/last-message.txt``.
1602 ``.hg/last-message.txt``.
1603
1603
1604 The --close-branch flag can be used to mark the current branch
1604 The --close-branch flag can be used to mark the current branch
1605 head closed. When all heads of a branch are closed, the branch
1605 head closed. When all heads of a branch are closed, the branch
1606 will be considered closed and no longer listed.
1606 will be considered closed and no longer listed.
1607
1607
1608 The --amend flag can be used to amend the parent of the
1608 The --amend flag can be used to amend the parent of the
1609 working directory with a new commit that contains the changes
1609 working directory with a new commit that contains the changes
1610 in the parent in addition to those currently reported by :hg:`status`,
1610 in the parent in addition to those currently reported by :hg:`status`,
1611 if there are any. The old commit is stored in a backup bundle in
1611 if there are any. The old commit is stored in a backup bundle in
1612 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1612 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1613 on how to restore it).
1613 on how to restore it).
1614
1614
1615 Message, user and date are taken from the amended commit unless
1615 Message, user and date are taken from the amended commit unless
1616 specified. When a message isn't specified on the command line,
1616 specified. When a message isn't specified on the command line,
1617 the editor will open with the message of the amended commit.
1617 the editor will open with the message of the amended commit.
1618
1618
1619 It is not possible to amend public changesets (see :hg:`help phases`)
1619 It is not possible to amend public changesets (see :hg:`help phases`)
1620 or changesets that have children.
1620 or changesets that have children.
1621
1621
1622 See :hg:`help dates` for a list of formats valid for -d/--date.
1622 See :hg:`help dates` for a list of formats valid for -d/--date.
1623
1623
1624 Returns 0 on success, 1 if nothing changed.
1624 Returns 0 on success, 1 if nothing changed.
1625
1625
1626 .. container:: verbose
1626 .. container:: verbose
1627
1627
1628 Examples:
1628 Examples:
1629
1629
1630 - commit all files ending in .py::
1630 - commit all files ending in .py::
1631
1631
1632 hg commit --include "set:**.py"
1632 hg commit --include "set:**.py"
1633
1633
1634 - commit all non-binary files::
1634 - commit all non-binary files::
1635
1635
1636 hg commit --exclude "set:binary()"
1636 hg commit --exclude "set:binary()"
1637
1637
1638 - amend the current commit and set the date to now::
1638 - amend the current commit and set the date to now::
1639
1639
1640 hg commit --amend --date now
1640 hg commit --amend --date now
1641 """
1641 """
1642 wlock = lock = None
1642 wlock = lock = None
1643 try:
1643 try:
1644 wlock = repo.wlock()
1644 wlock = repo.wlock()
1645 lock = repo.lock()
1645 lock = repo.lock()
1646 return _docommit(ui, repo, *pats, **opts)
1646 return _docommit(ui, repo, *pats, **opts)
1647 finally:
1647 finally:
1648 release(lock, wlock)
1648 release(lock, wlock)
1649
1649
1650 def _docommit(ui, repo, *pats, **opts):
1650 def _docommit(ui, repo, *pats, **opts):
1651 if opts.get(r'interactive'):
1651 if opts.get(r'interactive'):
1652 opts.pop(r'interactive')
1652 opts.pop(r'interactive')
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1654 cmdutil.recordfilter, *pats,
1654 cmdutil.recordfilter, *pats,
1655 **opts)
1655 **opts)
1656 # ret can be 0 (no changes to record) or the value returned by
1656 # ret can be 0 (no changes to record) or the value returned by
1657 # commit(), 1 if nothing changed or None on success.
1657 # commit(), 1 if nothing changed or None on success.
1658 return 1 if ret == 0 else ret
1658 return 1 if ret == 0 else ret
1659
1659
1660 opts = pycompat.byteskwargs(opts)
1660 opts = pycompat.byteskwargs(opts)
1661 if opts.get('subrepos'):
1661 if opts.get('subrepos'):
1662 if opts.get('amend'):
1662 if opts.get('amend'):
1663 raise error.Abort(_('cannot amend with --subrepos'))
1663 raise error.Abort(_('cannot amend with --subrepos'))
1664 # Let --subrepos on the command line override config setting.
1664 # Let --subrepos on the command line override config setting.
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1666
1666
1667 cmdutil.checkunfinished(repo, commit=True)
1667 cmdutil.checkunfinished(repo, commit=True)
1668
1668
1669 branch = repo[None].branch()
1669 branch = repo[None].branch()
1670 bheads = repo.branchheads(branch)
1670 bheads = repo.branchheads(branch)
1671
1671
1672 extra = {}
1672 extra = {}
1673 if opts.get('close_branch'):
1673 if opts.get('close_branch'):
1674 extra['close'] = 1
1674 extra['close'] = 1
1675
1675
1676 if not bheads:
1676 if not bheads:
1677 raise error.Abort(_('can only close branch heads'))
1677 raise error.Abort(_('can only close branch heads'))
1678 elif opts.get('amend'):
1678 elif opts.get('amend'):
1679 if repo[None].parents()[0].p1().branch() != branch and \
1679 if repo[None].parents()[0].p1().branch() != branch and \
1680 repo[None].parents()[0].p2().branch() != branch:
1680 repo[None].parents()[0].p2().branch() != branch:
1681 raise error.Abort(_('can only close branch heads'))
1681 raise error.Abort(_('can only close branch heads'))
1682
1682
1683 if opts.get('amend'):
1683 if opts.get('amend'):
1684 if ui.configbool('ui', 'commitsubrepos'):
1684 if ui.configbool('ui', 'commitsubrepos'):
1685 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1685 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1686
1686
1687 old = repo['.']
1687 old = repo['.']
1688 if not old.mutable():
1688 if not old.mutable():
1689 raise error.Abort(_('cannot amend public changesets'))
1689 raise error.Abort(_('cannot amend public changesets'))
1690 if len(repo[None].parents()) > 1:
1690 if len(repo[None].parents()) > 1:
1691 raise error.Abort(_('cannot amend while merging'))
1691 raise error.Abort(_('cannot amend while merging'))
1692 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1692 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1693 if not allowunstable and old.children():
1693 if not allowunstable and old.children():
1694 raise error.Abort(_('cannot amend changeset with children'))
1694 raise error.Abort(_('cannot amend changeset with children'))
1695
1695
1696 # Currently histedit gets confused if an amend happens while histedit
1696 # Currently histedit gets confused if an amend happens while histedit
1697 # is in progress. Since we have a checkunfinished command, we are
1697 # is in progress. Since we have a checkunfinished command, we are
1698 # temporarily honoring it.
1698 # temporarily honoring it.
1699 #
1699 #
1700 # Note: eventually this guard will be removed. Please do not expect
1700 # Note: eventually this guard will be removed. Please do not expect
1701 # this behavior to remain.
1701 # this behavior to remain.
1702 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1702 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1703 cmdutil.checkunfinished(repo)
1703 cmdutil.checkunfinished(repo)
1704
1704
1705 # commitfunc is used only for temporary amend commit by cmdutil.amend
1705 # commitfunc is used only for temporary amend commit by cmdutil.amend
1706 def commitfunc(ui, repo, message, match, opts):
1706 def commitfunc(ui, repo, message, match, opts):
1707 return repo.commit(message,
1707 return repo.commit(message,
1708 opts.get('user') or old.user(),
1708 opts.get('user') or old.user(),
1709 opts.get('date') or old.date(),
1709 opts.get('date') or old.date(),
1710 match,
1710 match,
1711 extra=extra)
1711 extra=extra)
1712
1712
1713 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1713 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1714 if node == old.node():
1714 if node == old.node():
1715 ui.status(_("nothing changed\n"))
1715 ui.status(_("nothing changed\n"))
1716 return 1
1716 return 1
1717 else:
1717 else:
1718 def commitfunc(ui, repo, message, match, opts):
1718 def commitfunc(ui, repo, message, match, opts):
1719 overrides = {}
1719 overrides = {}
1720 if opts.get('secret'):
1720 if opts.get('secret'):
1721 overrides[('phases', 'new-commit')] = 'secret'
1721 overrides[('phases', 'new-commit')] = 'secret'
1722
1722
1723 baseui = repo.baseui
1723 baseui = repo.baseui
1724 with baseui.configoverride(overrides, 'commit'):
1724 with baseui.configoverride(overrides, 'commit'):
1725 with ui.configoverride(overrides, 'commit'):
1725 with ui.configoverride(overrides, 'commit'):
1726 editform = cmdutil.mergeeditform(repo[None],
1726 editform = cmdutil.mergeeditform(repo[None],
1727 'commit.normal')
1727 'commit.normal')
1728 editor = cmdutil.getcommiteditor(
1728 editor = cmdutil.getcommiteditor(
1729 editform=editform, **pycompat.strkwargs(opts))
1729 editform=editform, **pycompat.strkwargs(opts))
1730 return repo.commit(message,
1730 return repo.commit(message,
1731 opts.get('user'),
1731 opts.get('user'),
1732 opts.get('date'),
1732 opts.get('date'),
1733 match,
1733 match,
1734 editor=editor,
1734 editor=editor,
1735 extra=extra)
1735 extra=extra)
1736
1736
1737 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1737 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1738
1738
1739 if not node:
1739 if not node:
1740 stat = cmdutil.postcommitstatus(repo, pats, opts)
1740 stat = cmdutil.postcommitstatus(repo, pats, opts)
1741 if stat[3]:
1741 if stat[3]:
1742 ui.status(_("nothing changed (%d missing files, see "
1742 ui.status(_("nothing changed (%d missing files, see "
1743 "'hg status')\n") % len(stat[3]))
1743 "'hg status')\n") % len(stat[3]))
1744 else:
1744 else:
1745 ui.status(_("nothing changed\n"))
1745 ui.status(_("nothing changed\n"))
1746 return 1
1746 return 1
1747
1747
1748 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1748 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1749
1749
1750 @command('config|showconfig|debugconfig',
1750 @command('config|showconfig|debugconfig',
1751 [('u', 'untrusted', None, _('show untrusted configuration options')),
1751 [('u', 'untrusted', None, _('show untrusted configuration options')),
1752 ('e', 'edit', None, _('edit user config')),
1752 ('e', 'edit', None, _('edit user config')),
1753 ('l', 'local', None, _('edit repository config')),
1753 ('l', 'local', None, _('edit repository config')),
1754 ('g', 'global', None, _('edit global config'))] + formatteropts,
1754 ('g', 'global', None, _('edit global config'))] + formatteropts,
1755 _('[-u] [NAME]...'),
1755 _('[-u] [NAME]...'),
1756 optionalrepo=True)
1756 optionalrepo=True)
1757 def config(ui, repo, *values, **opts):
1757 def config(ui, repo, *values, **opts):
1758 """show combined config settings from all hgrc files
1758 """show combined config settings from all hgrc files
1759
1759
1760 With no arguments, print names and values of all config items.
1760 With no arguments, print names and values of all config items.
1761
1761
1762 With one argument of the form section.name, print just the value
1762 With one argument of the form section.name, print just the value
1763 of that config item.
1763 of that config item.
1764
1764
1765 With multiple arguments, print names and values of all config
1765 With multiple arguments, print names and values of all config
1766 items with matching section names.
1766 items with matching section names.
1767
1767
1768 With --edit, start an editor on the user-level config file. With
1768 With --edit, start an editor on the user-level config file. With
1769 --global, edit the system-wide config file. With --local, edit the
1769 --global, edit the system-wide config file. With --local, edit the
1770 repository-level config file.
1770 repository-level config file.
1771
1771
1772 With --debug, the source (filename and line number) is printed
1772 With --debug, the source (filename and line number) is printed
1773 for each config item.
1773 for each config item.
1774
1774
1775 See :hg:`help config` for more information about config files.
1775 See :hg:`help config` for more information about config files.
1776
1776
1777 Returns 0 on success, 1 if NAME does not exist.
1777 Returns 0 on success, 1 if NAME does not exist.
1778
1778
1779 """
1779 """
1780
1780
1781 opts = pycompat.byteskwargs(opts)
1781 opts = pycompat.byteskwargs(opts)
1782 if opts.get('edit') or opts.get('local') or opts.get('global'):
1782 if opts.get('edit') or opts.get('local') or opts.get('global'):
1783 if opts.get('local') and opts.get('global'):
1783 if opts.get('local') and opts.get('global'):
1784 raise error.Abort(_("can't use --local and --global together"))
1784 raise error.Abort(_("can't use --local and --global together"))
1785
1785
1786 if opts.get('local'):
1786 if opts.get('local'):
1787 if not repo:
1787 if not repo:
1788 raise error.Abort(_("can't use --local outside a repository"))
1788 raise error.Abort(_("can't use --local outside a repository"))
1789 paths = [repo.vfs.join('hgrc')]
1789 paths = [repo.vfs.join('hgrc')]
1790 elif opts.get('global'):
1790 elif opts.get('global'):
1791 paths = rcutil.systemrcpath()
1791 paths = rcutil.systemrcpath()
1792 else:
1792 else:
1793 paths = rcutil.userrcpath()
1793 paths = rcutil.userrcpath()
1794
1794
1795 for f in paths:
1795 for f in paths:
1796 if os.path.exists(f):
1796 if os.path.exists(f):
1797 break
1797 break
1798 else:
1798 else:
1799 if opts.get('global'):
1799 if opts.get('global'):
1800 samplehgrc = uimod.samplehgrcs['global']
1800 samplehgrc = uimod.samplehgrcs['global']
1801 elif opts.get('local'):
1801 elif opts.get('local'):
1802 samplehgrc = uimod.samplehgrcs['local']
1802 samplehgrc = uimod.samplehgrcs['local']
1803 else:
1803 else:
1804 samplehgrc = uimod.samplehgrcs['user']
1804 samplehgrc = uimod.samplehgrcs['user']
1805
1805
1806 f = paths[0]
1806 f = paths[0]
1807 fp = open(f, "w")
1807 fp = open(f, "w")
1808 fp.write(samplehgrc)
1808 fp.write(samplehgrc)
1809 fp.close()
1809 fp.close()
1810
1810
1811 editor = ui.geteditor()
1811 editor = ui.geteditor()
1812 ui.system("%s \"%s\"" % (editor, f),
1812 ui.system("%s \"%s\"" % (editor, f),
1813 onerr=error.Abort, errprefix=_("edit failed"),
1813 onerr=error.Abort, errprefix=_("edit failed"),
1814 blockedtag='config_edit')
1814 blockedtag='config_edit')
1815 return
1815 return
1816 ui.pager('config')
1816 ui.pager('config')
1817 fm = ui.formatter('config', opts)
1817 fm = ui.formatter('config', opts)
1818 for t, f in rcutil.rccomponents():
1818 for t, f in rcutil.rccomponents():
1819 if t == 'path':
1819 if t == 'path':
1820 ui.debug('read config from: %s\n' % f)
1820 ui.debug('read config from: %s\n' % f)
1821 elif t == 'items':
1821 elif t == 'items':
1822 for section, name, value, source in f:
1822 for section, name, value, source in f:
1823 ui.debug('set config by: %s\n' % source)
1823 ui.debug('set config by: %s\n' % source)
1824 else:
1824 else:
1825 raise error.ProgrammingError('unknown rctype: %s' % t)
1825 raise error.ProgrammingError('unknown rctype: %s' % t)
1826 untrusted = bool(opts.get('untrusted'))
1826 untrusted = bool(opts.get('untrusted'))
1827 if values:
1827 if values:
1828 sections = [v for v in values if '.' not in v]
1828 sections = [v for v in values if '.' not in v]
1829 items = [v for v in values if '.' in v]
1829 items = [v for v in values if '.' in v]
1830 if len(items) > 1 or items and sections:
1830 if len(items) > 1 or items and sections:
1831 raise error.Abort(_('only one config item permitted'))
1831 raise error.Abort(_('only one config item permitted'))
1832 matched = False
1832 matched = False
1833 for section, name, value in ui.walkconfig(untrusted=untrusted):
1833 for section, name, value in ui.walkconfig(untrusted=untrusted):
1834 source = ui.configsource(section, name, untrusted)
1834 source = ui.configsource(section, name, untrusted)
1835 value = pycompat.bytestr(value)
1835 value = pycompat.bytestr(value)
1836 if fm.isplain():
1836 if fm.isplain():
1837 source = source or 'none'
1837 source = source or 'none'
1838 value = value.replace('\n', '\\n')
1838 value = value.replace('\n', '\\n')
1839 entryname = section + '.' + name
1839 entryname = section + '.' + name
1840 if values:
1840 if values:
1841 for v in values:
1841 for v in values:
1842 if v == section:
1842 if v == section:
1843 fm.startitem()
1843 fm.startitem()
1844 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1844 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1845 fm.write('name value', '%s=%s\n', entryname, value)
1845 fm.write('name value', '%s=%s\n', entryname, value)
1846 matched = True
1846 matched = True
1847 elif v == entryname:
1847 elif v == entryname:
1848 fm.startitem()
1848 fm.startitem()
1849 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1849 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1850 fm.write('value', '%s\n', value)
1850 fm.write('value', '%s\n', value)
1851 fm.data(name=entryname)
1851 fm.data(name=entryname)
1852 matched = True
1852 matched = True
1853 else:
1853 else:
1854 fm.startitem()
1854 fm.startitem()
1855 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1855 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1856 fm.write('name value', '%s=%s\n', entryname, value)
1856 fm.write('name value', '%s=%s\n', entryname, value)
1857 matched = True
1857 matched = True
1858 fm.end()
1858 fm.end()
1859 if matched:
1859 if matched:
1860 return 0
1860 return 0
1861 return 1
1861 return 1
1862
1862
1863 @command('copy|cp',
1863 @command('copy|cp',
1864 [('A', 'after', None, _('record a copy that has already occurred')),
1864 [('A', 'after', None, _('record a copy that has already occurred')),
1865 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1865 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1866 ] + walkopts + dryrunopts,
1866 ] + walkopts + dryrunopts,
1867 _('[OPTION]... [SOURCE]... DEST'))
1867 _('[OPTION]... [SOURCE]... DEST'))
1868 def copy(ui, repo, *pats, **opts):
1868 def copy(ui, repo, *pats, **opts):
1869 """mark files as copied for the next commit
1869 """mark files as copied for the next commit
1870
1870
1871 Mark dest as having copies of source files. If dest is a
1871 Mark dest as having copies of source files. If dest is a
1872 directory, copies are put in that directory. If dest is a file,
1872 directory, copies are put in that directory. If dest is a file,
1873 the source must be a single file.
1873 the source must be a single file.
1874
1874
1875 By default, this command copies the contents of files as they
1875 By default, this command copies the contents of files as they
1876 exist in the working directory. If invoked with -A/--after, the
1876 exist in the working directory. If invoked with -A/--after, the
1877 operation is recorded, but no copying is performed.
1877 operation is recorded, but no copying is performed.
1878
1878
1879 This command takes effect with the next commit. To undo a copy
1879 This command takes effect with the next commit. To undo a copy
1880 before that, see :hg:`revert`.
1880 before that, see :hg:`revert`.
1881
1881
1882 Returns 0 on success, 1 if errors are encountered.
1882 Returns 0 on success, 1 if errors are encountered.
1883 """
1883 """
1884 opts = pycompat.byteskwargs(opts)
1884 opts = pycompat.byteskwargs(opts)
1885 with repo.wlock(False):
1885 with repo.wlock(False):
1886 return cmdutil.copy(ui, repo, pats, opts)
1886 return cmdutil.copy(ui, repo, pats, opts)
1887
1887
1888 @command('^diff',
1888 @command('^diff',
1889 [('r', 'rev', [], _('revision'), _('REV')),
1889 [('r', 'rev', [], _('revision'), _('REV')),
1890 ('c', 'change', '', _('change made by revision'), _('REV'))
1890 ('c', 'change', '', _('change made by revision'), _('REV'))
1891 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1891 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1892 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1892 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1893 inferrepo=True)
1893 inferrepo=True)
1894 def diff(ui, repo, *pats, **opts):
1894 def diff(ui, repo, *pats, **opts):
1895 """diff repository (or selected files)
1895 """diff repository (or selected files)
1896
1896
1897 Show differences between revisions for the specified files.
1897 Show differences between revisions for the specified files.
1898
1898
1899 Differences between files are shown using the unified diff format.
1899 Differences between files are shown using the unified diff format.
1900
1900
1901 .. note::
1901 .. note::
1902
1902
1903 :hg:`diff` may generate unexpected results for merges, as it will
1903 :hg:`diff` may generate unexpected results for merges, as it will
1904 default to comparing against the working directory's first
1904 default to comparing against the working directory's first
1905 parent changeset if no revisions are specified.
1905 parent changeset if no revisions are specified.
1906
1906
1907 When two revision arguments are given, then changes are shown
1907 When two revision arguments are given, then changes are shown
1908 between those revisions. If only one revision is specified then
1908 between those revisions. If only one revision is specified then
1909 that revision is compared to the working directory, and, when no
1909 that revision is compared to the working directory, and, when no
1910 revisions are specified, the working directory files are compared
1910 revisions are specified, the working directory files are compared
1911 to its first parent.
1911 to its first parent.
1912
1912
1913 Alternatively you can specify -c/--change with a revision to see
1913 Alternatively you can specify -c/--change with a revision to see
1914 the changes in that changeset relative to its first parent.
1914 the changes in that changeset relative to its first parent.
1915
1915
1916 Without the -a/--text option, diff will avoid generating diffs of
1916 Without the -a/--text option, diff will avoid generating diffs of
1917 files it detects as binary. With -a, diff will generate a diff
1917 files it detects as binary. With -a, diff will generate a diff
1918 anyway, probably with undesirable results.
1918 anyway, probably with undesirable results.
1919
1919
1920 Use the -g/--git option to generate diffs in the git extended diff
1920 Use the -g/--git option to generate diffs in the git extended diff
1921 format. For more information, read :hg:`help diffs`.
1921 format. For more information, read :hg:`help diffs`.
1922
1922
1923 .. container:: verbose
1923 .. container:: verbose
1924
1924
1925 Examples:
1925 Examples:
1926
1926
1927 - compare a file in the current working directory to its parent::
1927 - compare a file in the current working directory to its parent::
1928
1928
1929 hg diff foo.c
1929 hg diff foo.c
1930
1930
1931 - compare two historical versions of a directory, with rename info::
1931 - compare two historical versions of a directory, with rename info::
1932
1932
1933 hg diff --git -r 1.0:1.2 lib/
1933 hg diff --git -r 1.0:1.2 lib/
1934
1934
1935 - get change stats relative to the last change on some date::
1935 - get change stats relative to the last change on some date::
1936
1936
1937 hg diff --stat -r "date('may 2')"
1937 hg diff --stat -r "date('may 2')"
1938
1938
1939 - diff all newly-added files that contain a keyword::
1939 - diff all newly-added files that contain a keyword::
1940
1940
1941 hg diff "set:added() and grep(GNU)"
1941 hg diff "set:added() and grep(GNU)"
1942
1942
1943 - compare a revision and its parents::
1943 - compare a revision and its parents::
1944
1944
1945 hg diff -c 9353 # compare against first parent
1945 hg diff -c 9353 # compare against first parent
1946 hg diff -r 9353^:9353 # same using revset syntax
1946 hg diff -r 9353^:9353 # same using revset syntax
1947 hg diff -r 9353^2:9353 # compare against the second parent
1947 hg diff -r 9353^2:9353 # compare against the second parent
1948
1948
1949 Returns 0 on success.
1949 Returns 0 on success.
1950 """
1950 """
1951
1951
1952 opts = pycompat.byteskwargs(opts)
1952 opts = pycompat.byteskwargs(opts)
1953 revs = opts.get('rev')
1953 revs = opts.get('rev')
1954 change = opts.get('change')
1954 change = opts.get('change')
1955 stat = opts.get('stat')
1955 stat = opts.get('stat')
1956 reverse = opts.get('reverse')
1956 reverse = opts.get('reverse')
1957
1957
1958 if revs and change:
1958 if revs and change:
1959 msg = _('cannot specify --rev and --change at the same time')
1959 msg = _('cannot specify --rev and --change at the same time')
1960 raise error.Abort(msg)
1960 raise error.Abort(msg)
1961 elif change:
1961 elif change:
1962 node2 = scmutil.revsingle(repo, change, None).node()
1962 node2 = scmutil.revsingle(repo, change, None).node()
1963 node1 = repo[node2].p1().node()
1963 node1 = repo[node2].p1().node()
1964 else:
1964 else:
1965 node1, node2 = scmutil.revpair(repo, revs)
1965 node1, node2 = scmutil.revpair(repo, revs)
1966
1966
1967 if reverse:
1967 if reverse:
1968 node1, node2 = node2, node1
1968 node1, node2 = node2, node1
1969
1969
1970 diffopts = patch.diffallopts(ui, opts)
1970 diffopts = patch.diffallopts(ui, opts)
1971 m = scmutil.match(repo[node2], pats, opts)
1971 m = scmutil.match(repo[node2], pats, opts)
1972 ui.pager('diff')
1972 ui.pager('diff')
1973 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1973 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1974 listsubrepos=opts.get('subrepos'),
1974 listsubrepos=opts.get('subrepos'),
1975 root=opts.get('root'))
1975 root=opts.get('root'))
1976
1976
1977 @command('^export',
1977 @command('^export',
1978 [('o', 'output', '',
1978 [('o', 'output', '',
1979 _('print output to file with formatted name'), _('FORMAT')),
1979 _('print output to file with formatted name'), _('FORMAT')),
1980 ('', 'switch-parent', None, _('diff against the second parent')),
1980 ('', 'switch-parent', None, _('diff against the second parent')),
1981 ('r', 'rev', [], _('revisions to export'), _('REV')),
1981 ('r', 'rev', [], _('revisions to export'), _('REV')),
1982 ] + diffopts,
1982 ] + diffopts,
1983 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1983 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1984 def export(ui, repo, *changesets, **opts):
1984 def export(ui, repo, *changesets, **opts):
1985 """dump the header and diffs for one or more changesets
1985 """dump the header and diffs for one or more changesets
1986
1986
1987 Print the changeset header and diffs for one or more revisions.
1987 Print the changeset header and diffs for one or more revisions.
1988 If no revision is given, the parent of the working directory is used.
1988 If no revision is given, the parent of the working directory is used.
1989
1989
1990 The information shown in the changeset header is: author, date,
1990 The information shown in the changeset header is: author, date,
1991 branch name (if non-default), changeset hash, parent(s) and commit
1991 branch name (if non-default), changeset hash, parent(s) and commit
1992 comment.
1992 comment.
1993
1993
1994 .. note::
1994 .. note::
1995
1995
1996 :hg:`export` may generate unexpected diff output for merge
1996 :hg:`export` may generate unexpected diff output for merge
1997 changesets, as it will compare the merge changeset against its
1997 changesets, as it will compare the merge changeset against its
1998 first parent only.
1998 first parent only.
1999
1999
2000 Output may be to a file, in which case the name of the file is
2000 Output may be to a file, in which case the name of the file is
2001 given using a format string. The formatting rules are as follows:
2001 given using a format string. The formatting rules are as follows:
2002
2002
2003 :``%%``: literal "%" character
2003 :``%%``: literal "%" character
2004 :``%H``: changeset hash (40 hexadecimal digits)
2004 :``%H``: changeset hash (40 hexadecimal digits)
2005 :``%N``: number of patches being generated
2005 :``%N``: number of patches being generated
2006 :``%R``: changeset revision number
2006 :``%R``: changeset revision number
2007 :``%b``: basename of the exporting repository
2007 :``%b``: basename of the exporting repository
2008 :``%h``: short-form changeset hash (12 hexadecimal digits)
2008 :``%h``: short-form changeset hash (12 hexadecimal digits)
2009 :``%m``: first line of the commit message (only alphanumeric characters)
2009 :``%m``: first line of the commit message (only alphanumeric characters)
2010 :``%n``: zero-padded sequence number, starting at 1
2010 :``%n``: zero-padded sequence number, starting at 1
2011 :``%r``: zero-padded changeset revision number
2011 :``%r``: zero-padded changeset revision number
2012
2012
2013 Without the -a/--text option, export will avoid generating diffs
2013 Without the -a/--text option, export will avoid generating diffs
2014 of files it detects as binary. With -a, export will generate a
2014 of files it detects as binary. With -a, export will generate a
2015 diff anyway, probably with undesirable results.
2015 diff anyway, probably with undesirable results.
2016
2016
2017 Use the -g/--git option to generate diffs in the git extended diff
2017 Use the -g/--git option to generate diffs in the git extended diff
2018 format. See :hg:`help diffs` for more information.
2018 format. See :hg:`help diffs` for more information.
2019
2019
2020 With the --switch-parent option, the diff will be against the
2020 With the --switch-parent option, the diff will be against the
2021 second parent. It can be useful to review a merge.
2021 second parent. It can be useful to review a merge.
2022
2022
2023 .. container:: verbose
2023 .. container:: verbose
2024
2024
2025 Examples:
2025 Examples:
2026
2026
2027 - use export and import to transplant a bugfix to the current
2027 - use export and import to transplant a bugfix to the current
2028 branch::
2028 branch::
2029
2029
2030 hg export -r 9353 | hg import -
2030 hg export -r 9353 | hg import -
2031
2031
2032 - export all the changesets between two revisions to a file with
2032 - export all the changesets between two revisions to a file with
2033 rename information::
2033 rename information::
2034
2034
2035 hg export --git -r 123:150 > changes.txt
2035 hg export --git -r 123:150 > changes.txt
2036
2036
2037 - split outgoing changes into a series of patches with
2037 - split outgoing changes into a series of patches with
2038 descriptive names::
2038 descriptive names::
2039
2039
2040 hg export -r "outgoing()" -o "%n-%m.patch"
2040 hg export -r "outgoing()" -o "%n-%m.patch"
2041
2041
2042 Returns 0 on success.
2042 Returns 0 on success.
2043 """
2043 """
2044 opts = pycompat.byteskwargs(opts)
2044 opts = pycompat.byteskwargs(opts)
2045 changesets += tuple(opts.get('rev', []))
2045 changesets += tuple(opts.get('rev', []))
2046 if not changesets:
2046 if not changesets:
2047 changesets = ['.']
2047 changesets = ['.']
2048 revs = scmutil.revrange(repo, changesets)
2048 revs = scmutil.revrange(repo, changesets)
2049 if not revs:
2049 if not revs:
2050 raise error.Abort(_("export requires at least one changeset"))
2050 raise error.Abort(_("export requires at least one changeset"))
2051 if len(revs) > 1:
2051 if len(revs) > 1:
2052 ui.note(_('exporting patches:\n'))
2052 ui.note(_('exporting patches:\n'))
2053 else:
2053 else:
2054 ui.note(_('exporting patch:\n'))
2054 ui.note(_('exporting patch:\n'))
2055 ui.pager('export')
2055 ui.pager('export')
2056 cmdutil.export(repo, revs, template=opts.get('output'),
2056 cmdutil.export(repo, revs, template=opts.get('output'),
2057 switch_parent=opts.get('switch_parent'),
2057 switch_parent=opts.get('switch_parent'),
2058 opts=patch.diffallopts(ui, opts))
2058 opts=patch.diffallopts(ui, opts))
2059
2059
2060 @command('files',
2060 @command('files',
2061 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2061 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2062 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2062 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2063 ] + walkopts + formatteropts + subrepoopts,
2063 ] + walkopts + formatteropts + subrepoopts,
2064 _('[OPTION]... [FILE]...'))
2064 _('[OPTION]... [FILE]...'))
2065 def files(ui, repo, *pats, **opts):
2065 def files(ui, repo, *pats, **opts):
2066 """list tracked files
2066 """list tracked files
2067
2067
2068 Print files under Mercurial control in the working directory or
2068 Print files under Mercurial control in the working directory or
2069 specified revision for given files (excluding removed files).
2069 specified revision for given files (excluding removed files).
2070 Files can be specified as filenames or filesets.
2070 Files can be specified as filenames or filesets.
2071
2071
2072 If no files are given to match, this command prints the names
2072 If no files are given to match, this command prints the names
2073 of all files under Mercurial control.
2073 of all files under Mercurial control.
2074
2074
2075 .. container:: verbose
2075 .. container:: verbose
2076
2076
2077 Examples:
2077 Examples:
2078
2078
2079 - list all files under the current directory::
2079 - list all files under the current directory::
2080
2080
2081 hg files .
2081 hg files .
2082
2082
2083 - shows sizes and flags for current revision::
2083 - shows sizes and flags for current revision::
2084
2084
2085 hg files -vr .
2085 hg files -vr .
2086
2086
2087 - list all files named README::
2087 - list all files named README::
2088
2088
2089 hg files -I "**/README"
2089 hg files -I "**/README"
2090
2090
2091 - list all binary files::
2091 - list all binary files::
2092
2092
2093 hg files "set:binary()"
2093 hg files "set:binary()"
2094
2094
2095 - find files containing a regular expression::
2095 - find files containing a regular expression::
2096
2096
2097 hg files "set:grep('bob')"
2097 hg files "set:grep('bob')"
2098
2098
2099 - search tracked file contents with xargs and grep::
2099 - search tracked file contents with xargs and grep::
2100
2100
2101 hg files -0 | xargs -0 grep foo
2101 hg files -0 | xargs -0 grep foo
2102
2102
2103 See :hg:`help patterns` and :hg:`help filesets` for more information
2103 See :hg:`help patterns` and :hg:`help filesets` for more information
2104 on specifying file patterns.
2104 on specifying file patterns.
2105
2105
2106 Returns 0 if a match is found, 1 otherwise.
2106 Returns 0 if a match is found, 1 otherwise.
2107
2107
2108 """
2108 """
2109
2109
2110 opts = pycompat.byteskwargs(opts)
2110 opts = pycompat.byteskwargs(opts)
2111 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2111 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2112
2112
2113 end = '\n'
2113 end = '\n'
2114 if opts.get('print0'):
2114 if opts.get('print0'):
2115 end = '\0'
2115 end = '\0'
2116 fmt = '%s' + end
2116 fmt = '%s' + end
2117
2117
2118 m = scmutil.match(ctx, pats, opts)
2118 m = scmutil.match(ctx, pats, opts)
2119 ui.pager('files')
2119 ui.pager('files')
2120 with ui.formatter('files', opts) as fm:
2120 with ui.formatter('files', opts) as fm:
2121 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2121 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2122
2122
2123 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2123 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2124 def forget(ui, repo, *pats, **opts):
2124 def forget(ui, repo, *pats, **opts):
2125 """forget the specified files on the next commit
2125 """forget the specified files on the next commit
2126
2126
2127 Mark the specified files so they will no longer be tracked
2127 Mark the specified files so they will no longer be tracked
2128 after the next commit.
2128 after the next commit.
2129
2129
2130 This only removes files from the current branch, not from the
2130 This only removes files from the current branch, not from the
2131 entire project history, and it does not delete them from the
2131 entire project history, and it does not delete them from the
2132 working directory.
2132 working directory.
2133
2133
2134 To delete the file from the working directory, see :hg:`remove`.
2134 To delete the file from the working directory, see :hg:`remove`.
2135
2135
2136 To undo a forget before the next commit, see :hg:`add`.
2136 To undo a forget before the next commit, see :hg:`add`.
2137
2137
2138 .. container:: verbose
2138 .. container:: verbose
2139
2139
2140 Examples:
2140 Examples:
2141
2141
2142 - forget newly-added binary files::
2142 - forget newly-added binary files::
2143
2143
2144 hg forget "set:added() and binary()"
2144 hg forget "set:added() and binary()"
2145
2145
2146 - forget files that would be excluded by .hgignore::
2146 - forget files that would be excluded by .hgignore::
2147
2147
2148 hg forget "set:hgignore()"
2148 hg forget "set:hgignore()"
2149
2149
2150 Returns 0 on success.
2150 Returns 0 on success.
2151 """
2151 """
2152
2152
2153 opts = pycompat.byteskwargs(opts)
2153 opts = pycompat.byteskwargs(opts)
2154 if not pats:
2154 if not pats:
2155 raise error.Abort(_('no files specified'))
2155 raise error.Abort(_('no files specified'))
2156
2156
2157 m = scmutil.match(repo[None], pats, opts)
2157 m = scmutil.match(repo[None], pats, opts)
2158 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2158 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2159 return rejected and 1 or 0
2159 return rejected and 1 or 0
2160
2160
2161 @command(
2161 @command(
2162 'graft',
2162 'graft',
2163 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2163 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2164 ('c', 'continue', False, _('resume interrupted graft')),
2164 ('c', 'continue', False, _('resume interrupted graft')),
2165 ('e', 'edit', False, _('invoke editor on commit messages')),
2165 ('e', 'edit', False, _('invoke editor on commit messages')),
2166 ('', 'log', None, _('append graft info to log message')),
2166 ('', 'log', None, _('append graft info to log message')),
2167 ('f', 'force', False, _('force graft')),
2167 ('f', 'force', False, _('force graft')),
2168 ('D', 'currentdate', False,
2168 ('D', 'currentdate', False,
2169 _('record the current date as commit date')),
2169 _('record the current date as commit date')),
2170 ('U', 'currentuser', False,
2170 ('U', 'currentuser', False,
2171 _('record the current user as committer'), _('DATE'))]
2171 _('record the current user as committer'), _('DATE'))]
2172 + commitopts2 + mergetoolopts + dryrunopts,
2172 + commitopts2 + mergetoolopts + dryrunopts,
2173 _('[OPTION]... [-r REV]... REV...'))
2173 _('[OPTION]... [-r REV]... REV...'))
2174 def graft(ui, repo, *revs, **opts):
2174 def graft(ui, repo, *revs, **opts):
2175 '''copy changes from other branches onto the current branch
2175 '''copy changes from other branches onto the current branch
2176
2176
2177 This command uses Mercurial's merge logic to copy individual
2177 This command uses Mercurial's merge logic to copy individual
2178 changes from other branches without merging branches in the
2178 changes from other branches without merging branches in the
2179 history graph. This is sometimes known as 'backporting' or
2179 history graph. This is sometimes known as 'backporting' or
2180 'cherry-picking'. By default, graft will copy user, date, and
2180 'cherry-picking'. By default, graft will copy user, date, and
2181 description from the source changesets.
2181 description from the source changesets.
2182
2182
2183 Changesets that are ancestors of the current revision, that have
2183 Changesets that are ancestors of the current revision, that have
2184 already been grafted, or that are merges will be skipped.
2184 already been grafted, or that are merges will be skipped.
2185
2185
2186 If --log is specified, log messages will have a comment appended
2186 If --log is specified, log messages will have a comment appended
2187 of the form::
2187 of the form::
2188
2188
2189 (grafted from CHANGESETHASH)
2189 (grafted from CHANGESETHASH)
2190
2190
2191 If --force is specified, revisions will be grafted even if they
2191 If --force is specified, revisions will be grafted even if they
2192 are already ancestors of or have been grafted to the destination.
2192 are already ancestors of or have been grafted to the destination.
2193 This is useful when the revisions have since been backed out.
2193 This is useful when the revisions have since been backed out.
2194
2194
2195 If a graft merge results in conflicts, the graft process is
2195 If a graft merge results in conflicts, the graft process is
2196 interrupted so that the current merge can be manually resolved.
2196 interrupted so that the current merge can be manually resolved.
2197 Once all conflicts are addressed, the graft process can be
2197 Once all conflicts are addressed, the graft process can be
2198 continued with the -c/--continue option.
2198 continued with the -c/--continue option.
2199
2199
2200 .. note::
2200 .. note::
2201
2201
2202 The -c/--continue option does not reapply earlier options, except
2202 The -c/--continue option does not reapply earlier options, except
2203 for --force.
2203 for --force.
2204
2204
2205 .. container:: verbose
2205 .. container:: verbose
2206
2206
2207 Examples:
2207 Examples:
2208
2208
2209 - copy a single change to the stable branch and edit its description::
2209 - copy a single change to the stable branch and edit its description::
2210
2210
2211 hg update stable
2211 hg update stable
2212 hg graft --edit 9393
2212 hg graft --edit 9393
2213
2213
2214 - graft a range of changesets with one exception, updating dates::
2214 - graft a range of changesets with one exception, updating dates::
2215
2215
2216 hg graft -D "2085::2093 and not 2091"
2216 hg graft -D "2085::2093 and not 2091"
2217
2217
2218 - continue a graft after resolving conflicts::
2218 - continue a graft after resolving conflicts::
2219
2219
2220 hg graft -c
2220 hg graft -c
2221
2221
2222 - show the source of a grafted changeset::
2222 - show the source of a grafted changeset::
2223
2223
2224 hg log --debug -r .
2224 hg log --debug -r .
2225
2225
2226 - show revisions sorted by date::
2226 - show revisions sorted by date::
2227
2227
2228 hg log -r "sort(all(), date)"
2228 hg log -r "sort(all(), date)"
2229
2229
2230 See :hg:`help revisions` for more about specifying revisions.
2230 See :hg:`help revisions` for more about specifying revisions.
2231
2231
2232 Returns 0 on successful completion.
2232 Returns 0 on successful completion.
2233 '''
2233 '''
2234 with repo.wlock():
2234 with repo.wlock():
2235 return _dograft(ui, repo, *revs, **opts)
2235 return _dograft(ui, repo, *revs, **opts)
2236
2236
2237 def _dograft(ui, repo, *revs, **opts):
2237 def _dograft(ui, repo, *revs, **opts):
2238 opts = pycompat.byteskwargs(opts)
2238 opts = pycompat.byteskwargs(opts)
2239 if revs and opts.get('rev'):
2239 if revs and opts.get('rev'):
2240 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2240 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2241 'revision ordering!\n'))
2241 'revision ordering!\n'))
2242
2242
2243 revs = list(revs)
2243 revs = list(revs)
2244 revs.extend(opts.get('rev'))
2244 revs.extend(opts.get('rev'))
2245
2245
2246 if not opts.get('user') and opts.get('currentuser'):
2246 if not opts.get('user') and opts.get('currentuser'):
2247 opts['user'] = ui.username()
2247 opts['user'] = ui.username()
2248 if not opts.get('date') and opts.get('currentdate'):
2248 if not opts.get('date') and opts.get('currentdate'):
2249 opts['date'] = "%d %d" % util.makedate()
2249 opts['date'] = "%d %d" % util.makedate()
2250
2250
2251 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2251 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2252
2252
2253 cont = False
2253 cont = False
2254 if opts.get('continue'):
2254 if opts.get('continue'):
2255 cont = True
2255 cont = True
2256 if revs:
2256 if revs:
2257 raise error.Abort(_("can't specify --continue and revisions"))
2257 raise error.Abort(_("can't specify --continue and revisions"))
2258 # read in unfinished revisions
2258 # read in unfinished revisions
2259 try:
2259 try:
2260 nodes = repo.vfs.read('graftstate').splitlines()
2260 nodes = repo.vfs.read('graftstate').splitlines()
2261 revs = [repo[node].rev() for node in nodes]
2261 revs = [repo[node].rev() for node in nodes]
2262 except IOError as inst:
2262 except IOError as inst:
2263 if inst.errno != errno.ENOENT:
2263 if inst.errno != errno.ENOENT:
2264 raise
2264 raise
2265 cmdutil.wrongtooltocontinue(repo, _('graft'))
2265 cmdutil.wrongtooltocontinue(repo, _('graft'))
2266 else:
2266 else:
2267 cmdutil.checkunfinished(repo)
2267 cmdutil.checkunfinished(repo)
2268 cmdutil.bailifchanged(repo)
2268 cmdutil.bailifchanged(repo)
2269 if not revs:
2269 if not revs:
2270 raise error.Abort(_('no revisions specified'))
2270 raise error.Abort(_('no revisions specified'))
2271 revs = scmutil.revrange(repo, revs)
2271 revs = scmutil.revrange(repo, revs)
2272
2272
2273 skipped = set()
2273 skipped = set()
2274 # check for merges
2274 # check for merges
2275 for rev in repo.revs('%ld and merge()', revs):
2275 for rev in repo.revs('%ld and merge()', revs):
2276 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2276 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2277 skipped.add(rev)
2277 skipped.add(rev)
2278 revs = [r for r in revs if r not in skipped]
2278 revs = [r for r in revs if r not in skipped]
2279 if not revs:
2279 if not revs:
2280 return -1
2280 return -1
2281
2281
2282 # Don't check in the --continue case, in effect retaining --force across
2282 # Don't check in the --continue case, in effect retaining --force across
2283 # --continues. That's because without --force, any revisions we decided to
2283 # --continues. That's because without --force, any revisions we decided to
2284 # skip would have been filtered out here, so they wouldn't have made their
2284 # skip would have been filtered out here, so they wouldn't have made their
2285 # way to the graftstate. With --force, any revisions we would have otherwise
2285 # way to the graftstate. With --force, any revisions we would have otherwise
2286 # skipped would not have been filtered out, and if they hadn't been applied
2286 # skipped would not have been filtered out, and if they hadn't been applied
2287 # already, they'd have been in the graftstate.
2287 # already, they'd have been in the graftstate.
2288 if not (cont or opts.get('force')):
2288 if not (cont or opts.get('force')):
2289 # check for ancestors of dest branch
2289 # check for ancestors of dest branch
2290 crev = repo['.'].rev()
2290 crev = repo['.'].rev()
2291 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2291 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2292 # XXX make this lazy in the future
2292 # XXX make this lazy in the future
2293 # don't mutate while iterating, create a copy
2293 # don't mutate while iterating, create a copy
2294 for rev in list(revs):
2294 for rev in list(revs):
2295 if rev in ancestors:
2295 if rev in ancestors:
2296 ui.warn(_('skipping ancestor revision %d:%s\n') %
2296 ui.warn(_('skipping ancestor revision %d:%s\n') %
2297 (rev, repo[rev]))
2297 (rev, repo[rev]))
2298 # XXX remove on list is slow
2298 # XXX remove on list is slow
2299 revs.remove(rev)
2299 revs.remove(rev)
2300 if not revs:
2300 if not revs:
2301 return -1
2301 return -1
2302
2302
2303 # analyze revs for earlier grafts
2303 # analyze revs for earlier grafts
2304 ids = {}
2304 ids = {}
2305 for ctx in repo.set("%ld", revs):
2305 for ctx in repo.set("%ld", revs):
2306 ids[ctx.hex()] = ctx.rev()
2306 ids[ctx.hex()] = ctx.rev()
2307 n = ctx.extra().get('source')
2307 n = ctx.extra().get('source')
2308 if n:
2308 if n:
2309 ids[n] = ctx.rev()
2309 ids[n] = ctx.rev()
2310
2310
2311 # check ancestors for earlier grafts
2311 # check ancestors for earlier grafts
2312 ui.debug('scanning for duplicate grafts\n')
2312 ui.debug('scanning for duplicate grafts\n')
2313
2313
2314 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2314 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2315 ctx = repo[rev]
2315 ctx = repo[rev]
2316 n = ctx.extra().get('source')
2316 n = ctx.extra().get('source')
2317 if n in ids:
2317 if n in ids:
2318 try:
2318 try:
2319 r = repo[n].rev()
2319 r = repo[n].rev()
2320 except error.RepoLookupError:
2320 except error.RepoLookupError:
2321 r = None
2321 r = None
2322 if r in revs:
2322 if r in revs:
2323 ui.warn(_('skipping revision %d:%s '
2323 ui.warn(_('skipping revision %d:%s '
2324 '(already grafted to %d:%s)\n')
2324 '(already grafted to %d:%s)\n')
2325 % (r, repo[r], rev, ctx))
2325 % (r, repo[r], rev, ctx))
2326 revs.remove(r)
2326 revs.remove(r)
2327 elif ids[n] in revs:
2327 elif ids[n] in revs:
2328 if r is None:
2328 if r is None:
2329 ui.warn(_('skipping already grafted revision %d:%s '
2329 ui.warn(_('skipping already grafted revision %d:%s '
2330 '(%d:%s also has unknown origin %s)\n')
2330 '(%d:%s also has unknown origin %s)\n')
2331 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2331 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2332 else:
2332 else:
2333 ui.warn(_('skipping already grafted revision %d:%s '
2333 ui.warn(_('skipping already grafted revision %d:%s '
2334 '(%d:%s also has origin %d:%s)\n')
2334 '(%d:%s also has origin %d:%s)\n')
2335 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2335 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2336 revs.remove(ids[n])
2336 revs.remove(ids[n])
2337 elif ctx.hex() in ids:
2337 elif ctx.hex() in ids:
2338 r = ids[ctx.hex()]
2338 r = ids[ctx.hex()]
2339 ui.warn(_('skipping already grafted revision %d:%s '
2339 ui.warn(_('skipping already grafted revision %d:%s '
2340 '(was grafted from %d:%s)\n') %
2340 '(was grafted from %d:%s)\n') %
2341 (r, repo[r], rev, ctx))
2341 (r, repo[r], rev, ctx))
2342 revs.remove(r)
2342 revs.remove(r)
2343 if not revs:
2343 if not revs:
2344 return -1
2344 return -1
2345
2345
2346 for pos, ctx in enumerate(repo.set("%ld", revs)):
2346 for pos, ctx in enumerate(repo.set("%ld", revs)):
2347 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2347 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2348 ctx.description().split('\n', 1)[0])
2348 ctx.description().split('\n', 1)[0])
2349 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2349 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2350 if names:
2350 if names:
2351 desc += ' (%s)' % ' '.join(names)
2351 desc += ' (%s)' % ' '.join(names)
2352 ui.status(_('grafting %s\n') % desc)
2352 ui.status(_('grafting %s\n') % desc)
2353 if opts.get('dry_run'):
2353 if opts.get('dry_run'):
2354 continue
2354 continue
2355
2355
2356 source = ctx.extra().get('source')
2356 source = ctx.extra().get('source')
2357 extra = {}
2357 extra = {}
2358 if source:
2358 if source:
2359 extra['source'] = source
2359 extra['source'] = source
2360 extra['intermediate-source'] = ctx.hex()
2360 extra['intermediate-source'] = ctx.hex()
2361 else:
2361 else:
2362 extra['source'] = ctx.hex()
2362 extra['source'] = ctx.hex()
2363 user = ctx.user()
2363 user = ctx.user()
2364 if opts.get('user'):
2364 if opts.get('user'):
2365 user = opts['user']
2365 user = opts['user']
2366 date = ctx.date()
2366 date = ctx.date()
2367 if opts.get('date'):
2367 if opts.get('date'):
2368 date = opts['date']
2368 date = opts['date']
2369 message = ctx.description()
2369 message = ctx.description()
2370 if opts.get('log'):
2370 if opts.get('log'):
2371 message += '\n(grafted from %s)' % ctx.hex()
2371 message += '\n(grafted from %s)' % ctx.hex()
2372
2372
2373 # we don't merge the first commit when continuing
2373 # we don't merge the first commit when continuing
2374 if not cont:
2374 if not cont:
2375 # perform the graft merge with p1(rev) as 'ancestor'
2375 # perform the graft merge with p1(rev) as 'ancestor'
2376 try:
2376 try:
2377 # ui.forcemerge is an internal variable, do not document
2377 # ui.forcemerge is an internal variable, do not document
2378 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2378 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2379 'graft')
2379 'graft')
2380 stats = mergemod.graft(repo, ctx, ctx.p1(),
2380 stats = mergemod.graft(repo, ctx, ctx.p1(),
2381 ['local', 'graft'])
2381 ['local', 'graft'])
2382 finally:
2382 finally:
2383 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2383 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2384 # report any conflicts
2384 # report any conflicts
2385 if stats and stats[3] > 0:
2385 if stats and stats[3] > 0:
2386 # write out state for --continue
2386 # write out state for --continue
2387 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2387 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2388 repo.vfs.write('graftstate', ''.join(nodelines))
2388 repo.vfs.write('graftstate', ''.join(nodelines))
2389 extra = ''
2389 extra = ''
2390 if opts.get('user'):
2390 if opts.get('user'):
2391 extra += ' --user %s' % util.shellquote(opts['user'])
2391 extra += ' --user %s' % util.shellquote(opts['user'])
2392 if opts.get('date'):
2392 if opts.get('date'):
2393 extra += ' --date %s' % util.shellquote(opts['date'])
2393 extra += ' --date %s' % util.shellquote(opts['date'])
2394 if opts.get('log'):
2394 if opts.get('log'):
2395 extra += ' --log'
2395 extra += ' --log'
2396 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2396 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2397 raise error.Abort(
2397 raise error.Abort(
2398 _("unresolved conflicts, can't continue"),
2398 _("unresolved conflicts, can't continue"),
2399 hint=hint)
2399 hint=hint)
2400 else:
2400 else:
2401 cont = False
2401 cont = False
2402
2402
2403 # commit
2403 # commit
2404 node = repo.commit(text=message, user=user,
2404 node = repo.commit(text=message, user=user,
2405 date=date, extra=extra, editor=editor)
2405 date=date, extra=extra, editor=editor)
2406 if node is None:
2406 if node is None:
2407 ui.warn(
2407 ui.warn(
2408 _('note: graft of %d:%s created no changes to commit\n') %
2408 _('note: graft of %d:%s created no changes to commit\n') %
2409 (ctx.rev(), ctx))
2409 (ctx.rev(), ctx))
2410
2410
2411 # remove state when we complete successfully
2411 # remove state when we complete successfully
2412 if not opts.get('dry_run'):
2412 if not opts.get('dry_run'):
2413 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2413 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2414
2414
2415 return 0
2415 return 0
2416
2416
2417 @command('grep',
2417 @command('grep',
2418 [('0', 'print0', None, _('end fields with NUL')),
2418 [('0', 'print0', None, _('end fields with NUL')),
2419 ('', 'all', None, _('print all revisions that match')),
2419 ('', 'all', None, _('print all revisions that match')),
2420 ('a', 'text', None, _('treat all files as text')),
2420 ('a', 'text', None, _('treat all files as text')),
2421 ('f', 'follow', None,
2421 ('f', 'follow', None,
2422 _('follow changeset history,'
2422 _('follow changeset history,'
2423 ' or file history across copies and renames')),
2423 ' or file history across copies and renames')),
2424 ('i', 'ignore-case', None, _('ignore case when matching')),
2424 ('i', 'ignore-case', None, _('ignore case when matching')),
2425 ('l', 'files-with-matches', None,
2425 ('l', 'files-with-matches', None,
2426 _('print only filenames and revisions that match')),
2426 _('print only filenames and revisions that match')),
2427 ('n', 'line-number', None, _('print matching line numbers')),
2427 ('n', 'line-number', None, _('print matching line numbers')),
2428 ('r', 'rev', [],
2428 ('r', 'rev', [],
2429 _('only search files changed within revision range'), _('REV')),
2429 _('only search files changed within revision range'), _('REV')),
2430 ('u', 'user', None, _('list the author (long with -v)')),
2430 ('u', 'user', None, _('list the author (long with -v)')),
2431 ('d', 'date', None, _('list the date (short with -q)')),
2431 ('d', 'date', None, _('list the date (short with -q)')),
2432 ] + formatteropts + walkopts,
2432 ] + formatteropts + walkopts,
2433 _('[OPTION]... PATTERN [FILE]...'),
2433 _('[OPTION]... PATTERN [FILE]...'),
2434 inferrepo=True)
2434 inferrepo=True)
2435 def grep(ui, repo, pattern, *pats, **opts):
2435 def grep(ui, repo, pattern, *pats, **opts):
2436 """search revision history for a pattern in specified files
2436 """search revision history for a pattern in specified files
2437
2437
2438 Search revision history for a regular expression in the specified
2438 Search revision history for a regular expression in the specified
2439 files or the entire project.
2439 files or the entire project.
2440
2440
2441 By default, grep prints the most recent revision number for each
2441 By default, grep prints the most recent revision number for each
2442 file in which it finds a match. To get it to print every revision
2442 file in which it finds a match. To get it to print every revision
2443 that contains a change in match status ("-" for a match that becomes
2443 that contains a change in match status ("-" for a match that becomes
2444 a non-match, or "+" for a non-match that becomes a match), use the
2444 a non-match, or "+" for a non-match that becomes a match), use the
2445 --all flag.
2445 --all flag.
2446
2446
2447 PATTERN can be any Python (roughly Perl-compatible) regular
2447 PATTERN can be any Python (roughly Perl-compatible) regular
2448 expression.
2448 expression.
2449
2449
2450 If no FILEs are specified (and -f/--follow isn't set), all files in
2450 If no FILEs are specified (and -f/--follow isn't set), all files in
2451 the repository are searched, including those that don't exist in the
2451 the repository are searched, including those that don't exist in the
2452 current branch or have been deleted in a prior changeset.
2452 current branch or have been deleted in a prior changeset.
2453
2453
2454 Returns 0 if a match is found, 1 otherwise.
2454 Returns 0 if a match is found, 1 otherwise.
2455 """
2455 """
2456 opts = pycompat.byteskwargs(opts)
2456 opts = pycompat.byteskwargs(opts)
2457 reflags = re.M
2457 reflags = re.M
2458 if opts.get('ignore_case'):
2458 if opts.get('ignore_case'):
2459 reflags |= re.I
2459 reflags |= re.I
2460 try:
2460 try:
2461 regexp = util.re.compile(pattern, reflags)
2461 regexp = util.re.compile(pattern, reflags)
2462 except re.error as inst:
2462 except re.error as inst:
2463 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2463 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2464 return 1
2464 return 1
2465 sep, eol = ':', '\n'
2465 sep, eol = ':', '\n'
2466 if opts.get('print0'):
2466 if opts.get('print0'):
2467 sep = eol = '\0'
2467 sep = eol = '\0'
2468
2468
2469 getfile = util.lrucachefunc(repo.file)
2469 getfile = util.lrucachefunc(repo.file)
2470
2470
2471 def matchlines(body):
2471 def matchlines(body):
2472 begin = 0
2472 begin = 0
2473 linenum = 0
2473 linenum = 0
2474 while begin < len(body):
2474 while begin < len(body):
2475 match = regexp.search(body, begin)
2475 match = regexp.search(body, begin)
2476 if not match:
2476 if not match:
2477 break
2477 break
2478 mstart, mend = match.span()
2478 mstart, mend = match.span()
2479 linenum += body.count('\n', begin, mstart) + 1
2479 linenum += body.count('\n', begin, mstart) + 1
2480 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2480 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2481 begin = body.find('\n', mend) + 1 or len(body) + 1
2481 begin = body.find('\n', mend) + 1 or len(body) + 1
2482 lend = begin - 1
2482 lend = begin - 1
2483 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2483 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2484
2484
2485 class linestate(object):
2485 class linestate(object):
2486 def __init__(self, line, linenum, colstart, colend):
2486 def __init__(self, line, linenum, colstart, colend):
2487 self.line = line
2487 self.line = line
2488 self.linenum = linenum
2488 self.linenum = linenum
2489 self.colstart = colstart
2489 self.colstart = colstart
2490 self.colend = colend
2490 self.colend = colend
2491
2491
2492 def __hash__(self):
2492 def __hash__(self):
2493 return hash((self.linenum, self.line))
2493 return hash((self.linenum, self.line))
2494
2494
2495 def __eq__(self, other):
2495 def __eq__(self, other):
2496 return self.line == other.line
2496 return self.line == other.line
2497
2497
2498 def findpos(self):
2498 def findpos(self):
2499 """Iterate all (start, end) indices of matches"""
2499 """Iterate all (start, end) indices of matches"""
2500 yield self.colstart, self.colend
2500 yield self.colstart, self.colend
2501 p = self.colend
2501 p = self.colend
2502 while p < len(self.line):
2502 while p < len(self.line):
2503 m = regexp.search(self.line, p)
2503 m = regexp.search(self.line, p)
2504 if not m:
2504 if not m:
2505 break
2505 break
2506 yield m.span()
2506 yield m.span()
2507 p = m.end()
2507 p = m.end()
2508
2508
2509 matches = {}
2509 matches = {}
2510 copies = {}
2510 copies = {}
2511 def grepbody(fn, rev, body):
2511 def grepbody(fn, rev, body):
2512 matches[rev].setdefault(fn, [])
2512 matches[rev].setdefault(fn, [])
2513 m = matches[rev][fn]
2513 m = matches[rev][fn]
2514 for lnum, cstart, cend, line in matchlines(body):
2514 for lnum, cstart, cend, line in matchlines(body):
2515 s = linestate(line, lnum, cstart, cend)
2515 s = linestate(line, lnum, cstart, cend)
2516 m.append(s)
2516 m.append(s)
2517
2517
2518 def difflinestates(a, b):
2518 def difflinestates(a, b):
2519 sm = difflib.SequenceMatcher(None, a, b)
2519 sm = difflib.SequenceMatcher(None, a, b)
2520 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2520 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2521 if tag == 'insert':
2521 if tag == 'insert':
2522 for i in xrange(blo, bhi):
2522 for i in xrange(blo, bhi):
2523 yield ('+', b[i])
2523 yield ('+', b[i])
2524 elif tag == 'delete':
2524 elif tag == 'delete':
2525 for i in xrange(alo, ahi):
2525 for i in xrange(alo, ahi):
2526 yield ('-', a[i])
2526 yield ('-', a[i])
2527 elif tag == 'replace':
2527 elif tag == 'replace':
2528 for i in xrange(alo, ahi):
2528 for i in xrange(alo, ahi):
2529 yield ('-', a[i])
2529 yield ('-', a[i])
2530 for i in xrange(blo, bhi):
2530 for i in xrange(blo, bhi):
2531 yield ('+', b[i])
2531 yield ('+', b[i])
2532
2532
2533 def display(fm, fn, ctx, pstates, states):
2533 def display(fm, fn, ctx, pstates, states):
2534 rev = ctx.rev()
2534 rev = ctx.rev()
2535 if fm.isplain():
2535 if fm.isplain():
2536 formatuser = ui.shortuser
2536 formatuser = ui.shortuser
2537 else:
2537 else:
2538 formatuser = str
2538 formatuser = str
2539 if ui.quiet:
2539 if ui.quiet:
2540 datefmt = '%Y-%m-%d'
2540 datefmt = '%Y-%m-%d'
2541 else:
2541 else:
2542 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2542 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2543 found = False
2543 found = False
2544 @util.cachefunc
2544 @util.cachefunc
2545 def binary():
2545 def binary():
2546 flog = getfile(fn)
2546 flog = getfile(fn)
2547 return util.binary(flog.read(ctx.filenode(fn)))
2547 return util.binary(flog.read(ctx.filenode(fn)))
2548
2548
2549 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2549 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2550 if opts.get('all'):
2550 if opts.get('all'):
2551 iter = difflinestates(pstates, states)
2551 iter = difflinestates(pstates, states)
2552 else:
2552 else:
2553 iter = [('', l) for l in states]
2553 iter = [('', l) for l in states]
2554 for change, l in iter:
2554 for change, l in iter:
2555 fm.startitem()
2555 fm.startitem()
2556 fm.data(node=fm.hexfunc(ctx.node()))
2556 fm.data(node=fm.hexfunc(ctx.node()))
2557 cols = [
2557 cols = [
2558 ('filename', fn, True),
2558 ('filename', fn, True),
2559 ('rev', rev, True),
2559 ('rev', rev, True),
2560 ('linenumber', l.linenum, opts.get('line_number')),
2560 ('linenumber', l.linenum, opts.get('line_number')),
2561 ]
2561 ]
2562 if opts.get('all'):
2562 if opts.get('all'):
2563 cols.append(('change', change, True))
2563 cols.append(('change', change, True))
2564 cols.extend([
2564 cols.extend([
2565 ('user', formatuser(ctx.user()), opts.get('user')),
2565 ('user', formatuser(ctx.user()), opts.get('user')),
2566 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2566 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2567 ])
2567 ])
2568 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2568 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2569 for name, data, cond in cols:
2569 for name, data, cond in cols:
2570 field = fieldnamemap.get(name, name)
2570 field = fieldnamemap.get(name, name)
2571 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2571 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2572 if cond and name != lastcol:
2572 if cond and name != lastcol:
2573 fm.plain(sep, label='grep.sep')
2573 fm.plain(sep, label='grep.sep')
2574 if not opts.get('files_with_matches'):
2574 if not opts.get('files_with_matches'):
2575 fm.plain(sep, label='grep.sep')
2575 fm.plain(sep, label='grep.sep')
2576 if not opts.get('text') and binary():
2576 if not opts.get('text') and binary():
2577 fm.plain(_(" Binary file matches"))
2577 fm.plain(_(" Binary file matches"))
2578 else:
2578 else:
2579 displaymatches(fm.nested('texts'), l)
2579 displaymatches(fm.nested('texts'), l)
2580 fm.plain(eol)
2580 fm.plain(eol)
2581 found = True
2581 found = True
2582 if opts.get('files_with_matches'):
2582 if opts.get('files_with_matches'):
2583 break
2583 break
2584 return found
2584 return found
2585
2585
2586 def displaymatches(fm, l):
2586 def displaymatches(fm, l):
2587 p = 0
2587 p = 0
2588 for s, e in l.findpos():
2588 for s, e in l.findpos():
2589 if p < s:
2589 if p < s:
2590 fm.startitem()
2590 fm.startitem()
2591 fm.write('text', '%s', l.line[p:s])
2591 fm.write('text', '%s', l.line[p:s])
2592 fm.data(matched=False)
2592 fm.data(matched=False)
2593 fm.startitem()
2593 fm.startitem()
2594 fm.write('text', '%s', l.line[s:e], label='grep.match')
2594 fm.write('text', '%s', l.line[s:e], label='grep.match')
2595 fm.data(matched=True)
2595 fm.data(matched=True)
2596 p = e
2596 p = e
2597 if p < len(l.line):
2597 if p < len(l.line):
2598 fm.startitem()
2598 fm.startitem()
2599 fm.write('text', '%s', l.line[p:])
2599 fm.write('text', '%s', l.line[p:])
2600 fm.data(matched=False)
2600 fm.data(matched=False)
2601 fm.end()
2601 fm.end()
2602
2602
2603 skip = {}
2603 skip = {}
2604 revfiles = {}
2604 revfiles = {}
2605 matchfn = scmutil.match(repo[None], pats, opts)
2605 matchfn = scmutil.match(repo[None], pats, opts)
2606 found = False
2606 found = False
2607 follow = opts.get('follow')
2607 follow = opts.get('follow')
2608
2608
2609 def prep(ctx, fns):
2609 def prep(ctx, fns):
2610 rev = ctx.rev()
2610 rev = ctx.rev()
2611 pctx = ctx.p1()
2611 pctx = ctx.p1()
2612 parent = pctx.rev()
2612 parent = pctx.rev()
2613 matches.setdefault(rev, {})
2613 matches.setdefault(rev, {})
2614 matches.setdefault(parent, {})
2614 matches.setdefault(parent, {})
2615 files = revfiles.setdefault(rev, [])
2615 files = revfiles.setdefault(rev, [])
2616 for fn in fns:
2616 for fn in fns:
2617 flog = getfile(fn)
2617 flog = getfile(fn)
2618 try:
2618 try:
2619 fnode = ctx.filenode(fn)
2619 fnode = ctx.filenode(fn)
2620 except error.LookupError:
2620 except error.LookupError:
2621 continue
2621 continue
2622
2622
2623 copied = flog.renamed(fnode)
2623 copied = flog.renamed(fnode)
2624 copy = follow and copied and copied[0]
2624 copy = follow and copied and copied[0]
2625 if copy:
2625 if copy:
2626 copies.setdefault(rev, {})[fn] = copy
2626 copies.setdefault(rev, {})[fn] = copy
2627 if fn in skip:
2627 if fn in skip:
2628 if copy:
2628 if copy:
2629 skip[copy] = True
2629 skip[copy] = True
2630 continue
2630 continue
2631 files.append(fn)
2631 files.append(fn)
2632
2632
2633 if fn not in matches[rev]:
2633 if fn not in matches[rev]:
2634 grepbody(fn, rev, flog.read(fnode))
2634 grepbody(fn, rev, flog.read(fnode))
2635
2635
2636 pfn = copy or fn
2636 pfn = copy or fn
2637 if pfn not in matches[parent]:
2637 if pfn not in matches[parent]:
2638 try:
2638 try:
2639 fnode = pctx.filenode(pfn)
2639 fnode = pctx.filenode(pfn)
2640 grepbody(pfn, parent, flog.read(fnode))
2640 grepbody(pfn, parent, flog.read(fnode))
2641 except error.LookupError:
2641 except error.LookupError:
2642 pass
2642 pass
2643
2643
2644 ui.pager('grep')
2644 ui.pager('grep')
2645 fm = ui.formatter('grep', opts)
2645 fm = ui.formatter('grep', opts)
2646 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2646 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2647 rev = ctx.rev()
2647 rev = ctx.rev()
2648 parent = ctx.p1().rev()
2648 parent = ctx.p1().rev()
2649 for fn in sorted(revfiles.get(rev, [])):
2649 for fn in sorted(revfiles.get(rev, [])):
2650 states = matches[rev][fn]
2650 states = matches[rev][fn]
2651 copy = copies.get(rev, {}).get(fn)
2651 copy = copies.get(rev, {}).get(fn)
2652 if fn in skip:
2652 if fn in skip:
2653 if copy:
2653 if copy:
2654 skip[copy] = True
2654 skip[copy] = True
2655 continue
2655 continue
2656 pstates = matches.get(parent, {}).get(copy or fn, [])
2656 pstates = matches.get(parent, {}).get(copy or fn, [])
2657 if pstates or states:
2657 if pstates or states:
2658 r = display(fm, fn, ctx, pstates, states)
2658 r = display(fm, fn, ctx, pstates, states)
2659 found = found or r
2659 found = found or r
2660 if r and not opts.get('all'):
2660 if r and not opts.get('all'):
2661 skip[fn] = True
2661 skip[fn] = True
2662 if copy:
2662 if copy:
2663 skip[copy] = True
2663 skip[copy] = True
2664 del matches[rev]
2664 del matches[rev]
2665 del revfiles[rev]
2665 del revfiles[rev]
2666 fm.end()
2666 fm.end()
2667
2667
2668 return not found
2668 return not found
2669
2669
2670 @command('heads',
2670 @command('heads',
2671 [('r', 'rev', '',
2671 [('r', 'rev', '',
2672 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2672 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2673 ('t', 'topo', False, _('show topological heads only')),
2673 ('t', 'topo', False, _('show topological heads only')),
2674 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2674 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2675 ('c', 'closed', False, _('show normal and closed branch heads')),
2675 ('c', 'closed', False, _('show normal and closed branch heads')),
2676 ] + templateopts,
2676 ] + templateopts,
2677 _('[-ct] [-r STARTREV] [REV]...'))
2677 _('[-ct] [-r STARTREV] [REV]...'))
2678 def heads(ui, repo, *branchrevs, **opts):
2678 def heads(ui, repo, *branchrevs, **opts):
2679 """show branch heads
2679 """show branch heads
2680
2680
2681 With no arguments, show all open branch heads in the repository.
2681 With no arguments, show all open branch heads in the repository.
2682 Branch heads are changesets that have no descendants on the
2682 Branch heads are changesets that have no descendants on the
2683 same branch. They are where development generally takes place and
2683 same branch. They are where development generally takes place and
2684 are the usual targets for update and merge operations.
2684 are the usual targets for update and merge operations.
2685
2685
2686 If one or more REVs are given, only open branch heads on the
2686 If one or more REVs are given, only open branch heads on the
2687 branches associated with the specified changesets are shown. This
2687 branches associated with the specified changesets are shown. This
2688 means that you can use :hg:`heads .` to see the heads on the
2688 means that you can use :hg:`heads .` to see the heads on the
2689 currently checked-out branch.
2689 currently checked-out branch.
2690
2690
2691 If -c/--closed is specified, also show branch heads marked closed
2691 If -c/--closed is specified, also show branch heads marked closed
2692 (see :hg:`commit --close-branch`).
2692 (see :hg:`commit --close-branch`).
2693
2693
2694 If STARTREV is specified, only those heads that are descendants of
2694 If STARTREV is specified, only those heads that are descendants of
2695 STARTREV will be displayed.
2695 STARTREV will be displayed.
2696
2696
2697 If -t/--topo is specified, named branch mechanics will be ignored and only
2697 If -t/--topo is specified, named branch mechanics will be ignored and only
2698 topological heads (changesets with no children) will be shown.
2698 topological heads (changesets with no children) will be shown.
2699
2699
2700 Returns 0 if matching heads are found, 1 if not.
2700 Returns 0 if matching heads are found, 1 if not.
2701 """
2701 """
2702
2702
2703 opts = pycompat.byteskwargs(opts)
2703 opts = pycompat.byteskwargs(opts)
2704 start = None
2704 start = None
2705 if 'rev' in opts:
2705 if 'rev' in opts:
2706 start = scmutil.revsingle(repo, opts['rev'], None).node()
2706 start = scmutil.revsingle(repo, opts['rev'], None).node()
2707
2707
2708 if opts.get('topo'):
2708 if opts.get('topo'):
2709 heads = [repo[h] for h in repo.heads(start)]
2709 heads = [repo[h] for h in repo.heads(start)]
2710 else:
2710 else:
2711 heads = []
2711 heads = []
2712 for branch in repo.branchmap():
2712 for branch in repo.branchmap():
2713 heads += repo.branchheads(branch, start, opts.get('closed'))
2713 heads += repo.branchheads(branch, start, opts.get('closed'))
2714 heads = [repo[h] for h in heads]
2714 heads = [repo[h] for h in heads]
2715
2715
2716 if branchrevs:
2716 if branchrevs:
2717 branches = set(repo[br].branch() for br in branchrevs)
2717 branches = set(repo[br].branch() for br in branchrevs)
2718 heads = [h for h in heads if h.branch() in branches]
2718 heads = [h for h in heads if h.branch() in branches]
2719
2719
2720 if opts.get('active') and branchrevs:
2720 if opts.get('active') and branchrevs:
2721 dagheads = repo.heads(start)
2721 dagheads = repo.heads(start)
2722 heads = [h for h in heads if h.node() in dagheads]
2722 heads = [h for h in heads if h.node() in dagheads]
2723
2723
2724 if branchrevs:
2724 if branchrevs:
2725 haveheads = set(h.branch() for h in heads)
2725 haveheads = set(h.branch() for h in heads)
2726 if branches - haveheads:
2726 if branches - haveheads:
2727 headless = ', '.join(b for b in branches - haveheads)
2727 headless = ', '.join(b for b in branches - haveheads)
2728 msg = _('no open branch heads found on branches %s')
2728 msg = _('no open branch heads found on branches %s')
2729 if opts.get('rev'):
2729 if opts.get('rev'):
2730 msg += _(' (started at %s)') % opts['rev']
2730 msg += _(' (started at %s)') % opts['rev']
2731 ui.warn((msg + '\n') % headless)
2731 ui.warn((msg + '\n') % headless)
2732
2732
2733 if not heads:
2733 if not heads:
2734 return 1
2734 return 1
2735
2735
2736 ui.pager('heads')
2736 ui.pager('heads')
2737 heads = sorted(heads, key=lambda x: -x.rev())
2737 heads = sorted(heads, key=lambda x: -x.rev())
2738 displayer = cmdutil.show_changeset(ui, repo, opts)
2738 displayer = cmdutil.show_changeset(ui, repo, opts)
2739 for ctx in heads:
2739 for ctx in heads:
2740 displayer.show(ctx)
2740 displayer.show(ctx)
2741 displayer.close()
2741 displayer.close()
2742
2742
2743 @command('help',
2743 @command('help',
2744 [('e', 'extension', None, _('show only help for extensions')),
2744 [('e', 'extension', None, _('show only help for extensions')),
2745 ('c', 'command', None, _('show only help for commands')),
2745 ('c', 'command', None, _('show only help for commands')),
2746 ('k', 'keyword', None, _('show topics matching keyword')),
2746 ('k', 'keyword', None, _('show topics matching keyword')),
2747 ('s', 'system', [], _('show help for specific platform(s)')),
2747 ('s', 'system', [], _('show help for specific platform(s)')),
2748 ],
2748 ],
2749 _('[-ecks] [TOPIC]'),
2749 _('[-ecks] [TOPIC]'),
2750 norepo=True)
2750 norepo=True)
2751 def help_(ui, name=None, **opts):
2751 def help_(ui, name=None, **opts):
2752 """show help for a given topic or a help overview
2752 """show help for a given topic or a help overview
2753
2753
2754 With no arguments, print a list of commands with short help messages.
2754 With no arguments, print a list of commands with short help messages.
2755
2755
2756 Given a topic, extension, or command name, print help for that
2756 Given a topic, extension, or command name, print help for that
2757 topic.
2757 topic.
2758
2758
2759 Returns 0 if successful.
2759 Returns 0 if successful.
2760 """
2760 """
2761
2761
2762 keep = opts.get('system') or []
2762 keep = opts.get(r'system') or []
2763 if len(keep) == 0:
2763 if len(keep) == 0:
2764 if pycompat.sysplatform.startswith('win'):
2764 if pycompat.sysplatform.startswith('win'):
2765 keep.append('windows')
2765 keep.append('windows')
2766 elif pycompat.sysplatform == 'OpenVMS':
2766 elif pycompat.sysplatform == 'OpenVMS':
2767 keep.append('vms')
2767 keep.append('vms')
2768 elif pycompat.sysplatform == 'plan9':
2768 elif pycompat.sysplatform == 'plan9':
2769 keep.append('plan9')
2769 keep.append('plan9')
2770 else:
2770 else:
2771 keep.append('unix')
2771 keep.append('unix')
2772 keep.append(pycompat.sysplatform.lower())
2772 keep.append(pycompat.sysplatform.lower())
2773 if ui.verbose:
2773 if ui.verbose:
2774 keep.append('verbose')
2774 keep.append('verbose')
2775
2775
2776 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2776 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2777 ui.pager('help')
2777 ui.pager('help')
2778 ui.write(formatted)
2778 ui.write(formatted)
2779
2779
2780
2780
2781 @command('identify|id',
2781 @command('identify|id',
2782 [('r', 'rev', '',
2782 [('r', 'rev', '',
2783 _('identify the specified revision'), _('REV')),
2783 _('identify the specified revision'), _('REV')),
2784 ('n', 'num', None, _('show local revision number')),
2784 ('n', 'num', None, _('show local revision number')),
2785 ('i', 'id', None, _('show global revision id')),
2785 ('i', 'id', None, _('show global revision id')),
2786 ('b', 'branch', None, _('show branch')),
2786 ('b', 'branch', None, _('show branch')),
2787 ('t', 'tags', None, _('show tags')),
2787 ('t', 'tags', None, _('show tags')),
2788 ('B', 'bookmarks', None, _('show bookmarks')),
2788 ('B', 'bookmarks', None, _('show bookmarks')),
2789 ] + remoteopts,
2789 ] + remoteopts,
2790 _('[-nibtB] [-r REV] [SOURCE]'),
2790 _('[-nibtB] [-r REV] [SOURCE]'),
2791 optionalrepo=True)
2791 optionalrepo=True)
2792 def identify(ui, repo, source=None, rev=None,
2792 def identify(ui, repo, source=None, rev=None,
2793 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2793 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2794 """identify the working directory or specified revision
2794 """identify the working directory or specified revision
2795
2795
2796 Print a summary identifying the repository state at REV using one or
2796 Print a summary identifying the repository state at REV using one or
2797 two parent hash identifiers, followed by a "+" if the working
2797 two parent hash identifiers, followed by a "+" if the working
2798 directory has uncommitted changes, the branch name (if not default),
2798 directory has uncommitted changes, the branch name (if not default),
2799 a list of tags, and a list of bookmarks.
2799 a list of tags, and a list of bookmarks.
2800
2800
2801 When REV is not given, print a summary of the current state of the
2801 When REV is not given, print a summary of the current state of the
2802 repository.
2802 repository.
2803
2803
2804 Specifying a path to a repository root or Mercurial bundle will
2804 Specifying a path to a repository root or Mercurial bundle will
2805 cause lookup to operate on that repository/bundle.
2805 cause lookup to operate on that repository/bundle.
2806
2806
2807 .. container:: verbose
2807 .. container:: verbose
2808
2808
2809 Examples:
2809 Examples:
2810
2810
2811 - generate a build identifier for the working directory::
2811 - generate a build identifier for the working directory::
2812
2812
2813 hg id --id > build-id.dat
2813 hg id --id > build-id.dat
2814
2814
2815 - find the revision corresponding to a tag::
2815 - find the revision corresponding to a tag::
2816
2816
2817 hg id -n -r 1.3
2817 hg id -n -r 1.3
2818
2818
2819 - check the most recent revision of a remote repository::
2819 - check the most recent revision of a remote repository::
2820
2820
2821 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2821 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2822
2822
2823 See :hg:`log` for generating more information about specific revisions,
2823 See :hg:`log` for generating more information about specific revisions,
2824 including full hash identifiers.
2824 including full hash identifiers.
2825
2825
2826 Returns 0 if successful.
2826 Returns 0 if successful.
2827 """
2827 """
2828
2828
2829 opts = pycompat.byteskwargs(opts)
2829 opts = pycompat.byteskwargs(opts)
2830 if not repo and not source:
2830 if not repo and not source:
2831 raise error.Abort(_("there is no Mercurial repository here "
2831 raise error.Abort(_("there is no Mercurial repository here "
2832 "(.hg not found)"))
2832 "(.hg not found)"))
2833
2833
2834 if ui.debugflag:
2834 if ui.debugflag:
2835 hexfunc = hex
2835 hexfunc = hex
2836 else:
2836 else:
2837 hexfunc = short
2837 hexfunc = short
2838 default = not (num or id or branch or tags or bookmarks)
2838 default = not (num or id or branch or tags or bookmarks)
2839 output = []
2839 output = []
2840 revs = []
2840 revs = []
2841
2841
2842 if source:
2842 if source:
2843 source, branches = hg.parseurl(ui.expandpath(source))
2843 source, branches = hg.parseurl(ui.expandpath(source))
2844 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2844 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2845 repo = peer.local()
2845 repo = peer.local()
2846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2847
2847
2848 if not repo:
2848 if not repo:
2849 if num or branch or tags:
2849 if num or branch or tags:
2850 raise error.Abort(
2850 raise error.Abort(
2851 _("can't query remote revision number, branch, or tags"))
2851 _("can't query remote revision number, branch, or tags"))
2852 if not rev and revs:
2852 if not rev and revs:
2853 rev = revs[0]
2853 rev = revs[0]
2854 if not rev:
2854 if not rev:
2855 rev = "tip"
2855 rev = "tip"
2856
2856
2857 remoterev = peer.lookup(rev)
2857 remoterev = peer.lookup(rev)
2858 if default or id:
2858 if default or id:
2859 output = [hexfunc(remoterev)]
2859 output = [hexfunc(remoterev)]
2860
2860
2861 def getbms():
2861 def getbms():
2862 bms = []
2862 bms = []
2863
2863
2864 if 'bookmarks' in peer.listkeys('namespaces'):
2864 if 'bookmarks' in peer.listkeys('namespaces'):
2865 hexremoterev = hex(remoterev)
2865 hexremoterev = hex(remoterev)
2866 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2866 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2867 if bmr == hexremoterev]
2867 if bmr == hexremoterev]
2868
2868
2869 return sorted(bms)
2869 return sorted(bms)
2870
2870
2871 if bookmarks:
2871 if bookmarks:
2872 output.extend(getbms())
2872 output.extend(getbms())
2873 elif default and not ui.quiet:
2873 elif default and not ui.quiet:
2874 # multiple bookmarks for a single parent separated by '/'
2874 # multiple bookmarks for a single parent separated by '/'
2875 bm = '/'.join(getbms())
2875 bm = '/'.join(getbms())
2876 if bm:
2876 if bm:
2877 output.append(bm)
2877 output.append(bm)
2878 else:
2878 else:
2879 ctx = scmutil.revsingle(repo, rev, None)
2879 ctx = scmutil.revsingle(repo, rev, None)
2880
2880
2881 if ctx.rev() is None:
2881 if ctx.rev() is None:
2882 ctx = repo[None]
2882 ctx = repo[None]
2883 parents = ctx.parents()
2883 parents = ctx.parents()
2884 taglist = []
2884 taglist = []
2885 for p in parents:
2885 for p in parents:
2886 taglist.extend(p.tags())
2886 taglist.extend(p.tags())
2887
2887
2888 changed = ""
2888 changed = ""
2889 if default or id or num:
2889 if default or id or num:
2890 if (any(repo.status())
2890 if (any(repo.status())
2891 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2891 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2892 changed = '+'
2892 changed = '+'
2893 if default or id:
2893 if default or id:
2894 output = ["%s%s" %
2894 output = ["%s%s" %
2895 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2895 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2896 if num:
2896 if num:
2897 output.append("%s%s" %
2897 output.append("%s%s" %
2898 ('+'.join([str(p.rev()) for p in parents]), changed))
2898 ('+'.join([str(p.rev()) for p in parents]), changed))
2899 else:
2899 else:
2900 if default or id:
2900 if default or id:
2901 output = [hexfunc(ctx.node())]
2901 output = [hexfunc(ctx.node())]
2902 if num:
2902 if num:
2903 output.append(str(ctx.rev()))
2903 output.append(str(ctx.rev()))
2904 taglist = ctx.tags()
2904 taglist = ctx.tags()
2905
2905
2906 if default and not ui.quiet:
2906 if default and not ui.quiet:
2907 b = ctx.branch()
2907 b = ctx.branch()
2908 if b != 'default':
2908 if b != 'default':
2909 output.append("(%s)" % b)
2909 output.append("(%s)" % b)
2910
2910
2911 # multiple tags for a single parent separated by '/'
2911 # multiple tags for a single parent separated by '/'
2912 t = '/'.join(taglist)
2912 t = '/'.join(taglist)
2913 if t:
2913 if t:
2914 output.append(t)
2914 output.append(t)
2915
2915
2916 # multiple bookmarks for a single parent separated by '/'
2916 # multiple bookmarks for a single parent separated by '/'
2917 bm = '/'.join(ctx.bookmarks())
2917 bm = '/'.join(ctx.bookmarks())
2918 if bm:
2918 if bm:
2919 output.append(bm)
2919 output.append(bm)
2920 else:
2920 else:
2921 if branch:
2921 if branch:
2922 output.append(ctx.branch())
2922 output.append(ctx.branch())
2923
2923
2924 if tags:
2924 if tags:
2925 output.extend(taglist)
2925 output.extend(taglist)
2926
2926
2927 if bookmarks:
2927 if bookmarks:
2928 output.extend(ctx.bookmarks())
2928 output.extend(ctx.bookmarks())
2929
2929
2930 ui.write("%s\n" % ' '.join(output))
2930 ui.write("%s\n" % ' '.join(output))
2931
2931
2932 @command('import|patch',
2932 @command('import|patch',
2933 [('p', 'strip', 1,
2933 [('p', 'strip', 1,
2934 _('directory strip option for patch. This has the same '
2934 _('directory strip option for patch. This has the same '
2935 'meaning as the corresponding patch option'), _('NUM')),
2935 'meaning as the corresponding patch option'), _('NUM')),
2936 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2936 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2937 ('e', 'edit', False, _('invoke editor on commit messages')),
2937 ('e', 'edit', False, _('invoke editor on commit messages')),
2938 ('f', 'force', None,
2938 ('f', 'force', None,
2939 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2939 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2940 ('', 'no-commit', None,
2940 ('', 'no-commit', None,
2941 _("don't commit, just update the working directory")),
2941 _("don't commit, just update the working directory")),
2942 ('', 'bypass', None,
2942 ('', 'bypass', None,
2943 _("apply patch without touching the working directory")),
2943 _("apply patch without touching the working directory")),
2944 ('', 'partial', None,
2944 ('', 'partial', None,
2945 _('commit even if some hunks fail')),
2945 _('commit even if some hunks fail')),
2946 ('', 'exact', None,
2946 ('', 'exact', None,
2947 _('abort if patch would apply lossily')),
2947 _('abort if patch would apply lossily')),
2948 ('', 'prefix', '',
2948 ('', 'prefix', '',
2949 _('apply patch to subdirectory'), _('DIR')),
2949 _('apply patch to subdirectory'), _('DIR')),
2950 ('', 'import-branch', None,
2950 ('', 'import-branch', None,
2951 _('use any branch information in patch (implied by --exact)'))] +
2951 _('use any branch information in patch (implied by --exact)'))] +
2952 commitopts + commitopts2 + similarityopts,
2952 commitopts + commitopts2 + similarityopts,
2953 _('[OPTION]... PATCH...'))
2953 _('[OPTION]... PATCH...'))
2954 def import_(ui, repo, patch1=None, *patches, **opts):
2954 def import_(ui, repo, patch1=None, *patches, **opts):
2955 """import an ordered set of patches
2955 """import an ordered set of patches
2956
2956
2957 Import a list of patches and commit them individually (unless
2957 Import a list of patches and commit them individually (unless
2958 --no-commit is specified).
2958 --no-commit is specified).
2959
2959
2960 To read a patch from standard input (stdin), use "-" as the patch
2960 To read a patch from standard input (stdin), use "-" as the patch
2961 name. If a URL is specified, the patch will be downloaded from
2961 name. If a URL is specified, the patch will be downloaded from
2962 there.
2962 there.
2963
2963
2964 Import first applies changes to the working directory (unless
2964 Import first applies changes to the working directory (unless
2965 --bypass is specified), import will abort if there are outstanding
2965 --bypass is specified), import will abort if there are outstanding
2966 changes.
2966 changes.
2967
2967
2968 Use --bypass to apply and commit patches directly to the
2968 Use --bypass to apply and commit patches directly to the
2969 repository, without affecting the working directory. Without
2969 repository, without affecting the working directory. Without
2970 --exact, patches will be applied on top of the working directory
2970 --exact, patches will be applied on top of the working directory
2971 parent revision.
2971 parent revision.
2972
2972
2973 You can import a patch straight from a mail message. Even patches
2973 You can import a patch straight from a mail message. Even patches
2974 as attachments work (to use the body part, it must have type
2974 as attachments work (to use the body part, it must have type
2975 text/plain or text/x-patch). From and Subject headers of email
2975 text/plain or text/x-patch). From and Subject headers of email
2976 message are used as default committer and commit message. All
2976 message are used as default committer and commit message. All
2977 text/plain body parts before first diff are added to the commit
2977 text/plain body parts before first diff are added to the commit
2978 message.
2978 message.
2979
2979
2980 If the imported patch was generated by :hg:`export`, user and
2980 If the imported patch was generated by :hg:`export`, user and
2981 description from patch override values from message headers and
2981 description from patch override values from message headers and
2982 body. Values given on command line with -m/--message and -u/--user
2982 body. Values given on command line with -m/--message and -u/--user
2983 override these.
2983 override these.
2984
2984
2985 If --exact is specified, import will set the working directory to
2985 If --exact is specified, import will set the working directory to
2986 the parent of each patch before applying it, and will abort if the
2986 the parent of each patch before applying it, and will abort if the
2987 resulting changeset has a different ID than the one recorded in
2987 resulting changeset has a different ID than the one recorded in
2988 the patch. This will guard against various ways that portable
2988 the patch. This will guard against various ways that portable
2989 patch formats and mail systems might fail to transfer Mercurial
2989 patch formats and mail systems might fail to transfer Mercurial
2990 data or metadata. See :hg:`bundle` for lossless transmission.
2990 data or metadata. See :hg:`bundle` for lossless transmission.
2991
2991
2992 Use --partial to ensure a changeset will be created from the patch
2992 Use --partial to ensure a changeset will be created from the patch
2993 even if some hunks fail to apply. Hunks that fail to apply will be
2993 even if some hunks fail to apply. Hunks that fail to apply will be
2994 written to a <target-file>.rej file. Conflicts can then be resolved
2994 written to a <target-file>.rej file. Conflicts can then be resolved
2995 by hand before :hg:`commit --amend` is run to update the created
2995 by hand before :hg:`commit --amend` is run to update the created
2996 changeset. This flag exists to let people import patches that
2996 changeset. This flag exists to let people import patches that
2997 partially apply without losing the associated metadata (author,
2997 partially apply without losing the associated metadata (author,
2998 date, description, ...).
2998 date, description, ...).
2999
2999
3000 .. note::
3000 .. note::
3001
3001
3002 When no hunks apply cleanly, :hg:`import --partial` will create
3002 When no hunks apply cleanly, :hg:`import --partial` will create
3003 an empty changeset, importing only the patch metadata.
3003 an empty changeset, importing only the patch metadata.
3004
3004
3005 With -s/--similarity, hg will attempt to discover renames and
3005 With -s/--similarity, hg will attempt to discover renames and
3006 copies in the patch in the same way as :hg:`addremove`.
3006 copies in the patch in the same way as :hg:`addremove`.
3007
3007
3008 It is possible to use external patch programs to perform the patch
3008 It is possible to use external patch programs to perform the patch
3009 by setting the ``ui.patch`` configuration option. For the default
3009 by setting the ``ui.patch`` configuration option. For the default
3010 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3010 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3011 See :hg:`help config` for more information about configuration
3011 See :hg:`help config` for more information about configuration
3012 files and how to use these options.
3012 files and how to use these options.
3013
3013
3014 See :hg:`help dates` for a list of formats valid for -d/--date.
3014 See :hg:`help dates` for a list of formats valid for -d/--date.
3015
3015
3016 .. container:: verbose
3016 .. container:: verbose
3017
3017
3018 Examples:
3018 Examples:
3019
3019
3020 - import a traditional patch from a website and detect renames::
3020 - import a traditional patch from a website and detect renames::
3021
3021
3022 hg import -s 80 http://example.com/bugfix.patch
3022 hg import -s 80 http://example.com/bugfix.patch
3023
3023
3024 - import a changeset from an hgweb server::
3024 - import a changeset from an hgweb server::
3025
3025
3026 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3026 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3027
3027
3028 - import all the patches in an Unix-style mbox::
3028 - import all the patches in an Unix-style mbox::
3029
3029
3030 hg import incoming-patches.mbox
3030 hg import incoming-patches.mbox
3031
3031
3032 - import patches from stdin::
3032 - import patches from stdin::
3033
3033
3034 hg import -
3034 hg import -
3035
3035
3036 - attempt to exactly restore an exported changeset (not always
3036 - attempt to exactly restore an exported changeset (not always
3037 possible)::
3037 possible)::
3038
3038
3039 hg import --exact proposed-fix.patch
3039 hg import --exact proposed-fix.patch
3040
3040
3041 - use an external tool to apply a patch which is too fuzzy for
3041 - use an external tool to apply a patch which is too fuzzy for
3042 the default internal tool.
3042 the default internal tool.
3043
3043
3044 hg import --config ui.patch="patch --merge" fuzzy.patch
3044 hg import --config ui.patch="patch --merge" fuzzy.patch
3045
3045
3046 - change the default fuzzing from 2 to a less strict 7
3046 - change the default fuzzing from 2 to a less strict 7
3047
3047
3048 hg import --config ui.fuzz=7 fuzz.patch
3048 hg import --config ui.fuzz=7 fuzz.patch
3049
3049
3050 Returns 0 on success, 1 on partial success (see --partial).
3050 Returns 0 on success, 1 on partial success (see --partial).
3051 """
3051 """
3052
3052
3053 opts = pycompat.byteskwargs(opts)
3053 opts = pycompat.byteskwargs(opts)
3054 if not patch1:
3054 if not patch1:
3055 raise error.Abort(_('need at least one patch to import'))
3055 raise error.Abort(_('need at least one patch to import'))
3056
3056
3057 patches = (patch1,) + patches
3057 patches = (patch1,) + patches
3058
3058
3059 date = opts.get('date')
3059 date = opts.get('date')
3060 if date:
3060 if date:
3061 opts['date'] = util.parsedate(date)
3061 opts['date'] = util.parsedate(date)
3062
3062
3063 exact = opts.get('exact')
3063 exact = opts.get('exact')
3064 update = not opts.get('bypass')
3064 update = not opts.get('bypass')
3065 if not update and opts.get('no_commit'):
3065 if not update and opts.get('no_commit'):
3066 raise error.Abort(_('cannot use --no-commit with --bypass'))
3066 raise error.Abort(_('cannot use --no-commit with --bypass'))
3067 try:
3067 try:
3068 sim = float(opts.get('similarity') or 0)
3068 sim = float(opts.get('similarity') or 0)
3069 except ValueError:
3069 except ValueError:
3070 raise error.Abort(_('similarity must be a number'))
3070 raise error.Abort(_('similarity must be a number'))
3071 if sim < 0 or sim > 100:
3071 if sim < 0 or sim > 100:
3072 raise error.Abort(_('similarity must be between 0 and 100'))
3072 raise error.Abort(_('similarity must be between 0 and 100'))
3073 if sim and not update:
3073 if sim and not update:
3074 raise error.Abort(_('cannot use --similarity with --bypass'))
3074 raise error.Abort(_('cannot use --similarity with --bypass'))
3075 if exact:
3075 if exact:
3076 if opts.get('edit'):
3076 if opts.get('edit'):
3077 raise error.Abort(_('cannot use --exact with --edit'))
3077 raise error.Abort(_('cannot use --exact with --edit'))
3078 if opts.get('prefix'):
3078 if opts.get('prefix'):
3079 raise error.Abort(_('cannot use --exact with --prefix'))
3079 raise error.Abort(_('cannot use --exact with --prefix'))
3080
3080
3081 base = opts["base"]
3081 base = opts["base"]
3082 wlock = dsguard = lock = tr = None
3082 wlock = dsguard = lock = tr = None
3083 msgs = []
3083 msgs = []
3084 ret = 0
3084 ret = 0
3085
3085
3086
3086
3087 try:
3087 try:
3088 wlock = repo.wlock()
3088 wlock = repo.wlock()
3089
3089
3090 if update:
3090 if update:
3091 cmdutil.checkunfinished(repo)
3091 cmdutil.checkunfinished(repo)
3092 if (exact or not opts.get('force')):
3092 if (exact or not opts.get('force')):
3093 cmdutil.bailifchanged(repo)
3093 cmdutil.bailifchanged(repo)
3094
3094
3095 if not opts.get('no_commit'):
3095 if not opts.get('no_commit'):
3096 lock = repo.lock()
3096 lock = repo.lock()
3097 tr = repo.transaction('import')
3097 tr = repo.transaction('import')
3098 else:
3098 else:
3099 dsguard = dirstateguard.dirstateguard(repo, 'import')
3099 dsguard = dirstateguard.dirstateguard(repo, 'import')
3100 parents = repo[None].parents()
3100 parents = repo[None].parents()
3101 for patchurl in patches:
3101 for patchurl in patches:
3102 if patchurl == '-':
3102 if patchurl == '-':
3103 ui.status(_('applying patch from stdin\n'))
3103 ui.status(_('applying patch from stdin\n'))
3104 patchfile = ui.fin
3104 patchfile = ui.fin
3105 patchurl = 'stdin' # for error message
3105 patchurl = 'stdin' # for error message
3106 else:
3106 else:
3107 patchurl = os.path.join(base, patchurl)
3107 patchurl = os.path.join(base, patchurl)
3108 ui.status(_('applying %s\n') % patchurl)
3108 ui.status(_('applying %s\n') % patchurl)
3109 patchfile = hg.openpath(ui, patchurl)
3109 patchfile = hg.openpath(ui, patchurl)
3110
3110
3111 haspatch = False
3111 haspatch = False
3112 for hunk in patch.split(patchfile):
3112 for hunk in patch.split(patchfile):
3113 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3113 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3114 parents, opts,
3114 parents, opts,
3115 msgs, hg.clean)
3115 msgs, hg.clean)
3116 if msg:
3116 if msg:
3117 haspatch = True
3117 haspatch = True
3118 ui.note(msg + '\n')
3118 ui.note(msg + '\n')
3119 if update or exact:
3119 if update or exact:
3120 parents = repo[None].parents()
3120 parents = repo[None].parents()
3121 else:
3121 else:
3122 parents = [repo[node]]
3122 parents = [repo[node]]
3123 if rej:
3123 if rej:
3124 ui.write_err(_("patch applied partially\n"))
3124 ui.write_err(_("patch applied partially\n"))
3125 ui.write_err(_("(fix the .rej files and run "
3125 ui.write_err(_("(fix the .rej files and run "
3126 "`hg commit --amend`)\n"))
3126 "`hg commit --amend`)\n"))
3127 ret = 1
3127 ret = 1
3128 break
3128 break
3129
3129
3130 if not haspatch:
3130 if not haspatch:
3131 raise error.Abort(_('%s: no diffs found') % patchurl)
3131 raise error.Abort(_('%s: no diffs found') % patchurl)
3132
3132
3133 if tr:
3133 if tr:
3134 tr.close()
3134 tr.close()
3135 if msgs:
3135 if msgs:
3136 repo.savecommitmessage('\n* * *\n'.join(msgs))
3136 repo.savecommitmessage('\n* * *\n'.join(msgs))
3137 if dsguard:
3137 if dsguard:
3138 dsguard.close()
3138 dsguard.close()
3139 return ret
3139 return ret
3140 finally:
3140 finally:
3141 if tr:
3141 if tr:
3142 tr.release()
3142 tr.release()
3143 release(lock, dsguard, wlock)
3143 release(lock, dsguard, wlock)
3144
3144
3145 @command('incoming|in',
3145 @command('incoming|in',
3146 [('f', 'force', None,
3146 [('f', 'force', None,
3147 _('run even if remote repository is unrelated')),
3147 _('run even if remote repository is unrelated')),
3148 ('n', 'newest-first', None, _('show newest record first')),
3148 ('n', 'newest-first', None, _('show newest record first')),
3149 ('', 'bundle', '',
3149 ('', 'bundle', '',
3150 _('file to store the bundles into'), _('FILE')),
3150 _('file to store the bundles into'), _('FILE')),
3151 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3151 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3152 ('B', 'bookmarks', False, _("compare bookmarks")),
3152 ('B', 'bookmarks', False, _("compare bookmarks")),
3153 ('b', 'branch', [],
3153 ('b', 'branch', [],
3154 _('a specific branch you would like to pull'), _('BRANCH')),
3154 _('a specific branch you would like to pull'), _('BRANCH')),
3155 ] + logopts + remoteopts + subrepoopts,
3155 ] + logopts + remoteopts + subrepoopts,
3156 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3156 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3157 def incoming(ui, repo, source="default", **opts):
3157 def incoming(ui, repo, source="default", **opts):
3158 """show new changesets found in source
3158 """show new changesets found in source
3159
3159
3160 Show new changesets found in the specified path/URL or the default
3160 Show new changesets found in the specified path/URL or the default
3161 pull location. These are the changesets that would have been pulled
3161 pull location. These are the changesets that would have been pulled
3162 if a pull at the time you issued this command.
3162 if a pull at the time you issued this command.
3163
3163
3164 See pull for valid source format details.
3164 See pull for valid source format details.
3165
3165
3166 .. container:: verbose
3166 .. container:: verbose
3167
3167
3168 With -B/--bookmarks, the result of bookmark comparison between
3168 With -B/--bookmarks, the result of bookmark comparison between
3169 local and remote repositories is displayed. With -v/--verbose,
3169 local and remote repositories is displayed. With -v/--verbose,
3170 status is also displayed for each bookmark like below::
3170 status is also displayed for each bookmark like below::
3171
3171
3172 BM1 01234567890a added
3172 BM1 01234567890a added
3173 BM2 1234567890ab advanced
3173 BM2 1234567890ab advanced
3174 BM3 234567890abc diverged
3174 BM3 234567890abc diverged
3175 BM4 34567890abcd changed
3175 BM4 34567890abcd changed
3176
3176
3177 The action taken locally when pulling depends on the
3177 The action taken locally when pulling depends on the
3178 status of each bookmark:
3178 status of each bookmark:
3179
3179
3180 :``added``: pull will create it
3180 :``added``: pull will create it
3181 :``advanced``: pull will update it
3181 :``advanced``: pull will update it
3182 :``diverged``: pull will create a divergent bookmark
3182 :``diverged``: pull will create a divergent bookmark
3183 :``changed``: result depends on remote changesets
3183 :``changed``: result depends on remote changesets
3184
3184
3185 From the point of view of pulling behavior, bookmark
3185 From the point of view of pulling behavior, bookmark
3186 existing only in the remote repository are treated as ``added``,
3186 existing only in the remote repository are treated as ``added``,
3187 even if it is in fact locally deleted.
3187 even if it is in fact locally deleted.
3188
3188
3189 .. container:: verbose
3189 .. container:: verbose
3190
3190
3191 For remote repository, using --bundle avoids downloading the
3191 For remote repository, using --bundle avoids downloading the
3192 changesets twice if the incoming is followed by a pull.
3192 changesets twice if the incoming is followed by a pull.
3193
3193
3194 Examples:
3194 Examples:
3195
3195
3196 - show incoming changes with patches and full description::
3196 - show incoming changes with patches and full description::
3197
3197
3198 hg incoming -vp
3198 hg incoming -vp
3199
3199
3200 - show incoming changes excluding merges, store a bundle::
3200 - show incoming changes excluding merges, store a bundle::
3201
3201
3202 hg in -vpM --bundle incoming.hg
3202 hg in -vpM --bundle incoming.hg
3203 hg pull incoming.hg
3203 hg pull incoming.hg
3204
3204
3205 - briefly list changes inside a bundle::
3205 - briefly list changes inside a bundle::
3206
3206
3207 hg in changes.hg -T "{desc|firstline}\\n"
3207 hg in changes.hg -T "{desc|firstline}\\n"
3208
3208
3209 Returns 0 if there are incoming changes, 1 otherwise.
3209 Returns 0 if there are incoming changes, 1 otherwise.
3210 """
3210 """
3211 opts = pycompat.byteskwargs(opts)
3211 opts = pycompat.byteskwargs(opts)
3212 if opts.get('graph'):
3212 if opts.get('graph'):
3213 cmdutil.checkunsupportedgraphflags([], opts)
3213 cmdutil.checkunsupportedgraphflags([], opts)
3214 def display(other, chlist, displayer):
3214 def display(other, chlist, displayer):
3215 revdag = cmdutil.graphrevs(other, chlist, opts)
3215 revdag = cmdutil.graphrevs(other, chlist, opts)
3216 cmdutil.displaygraph(ui, repo, revdag, displayer,
3216 cmdutil.displaygraph(ui, repo, revdag, displayer,
3217 graphmod.asciiedges)
3217 graphmod.asciiedges)
3218
3218
3219 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3219 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3220 return 0
3220 return 0
3221
3221
3222 if opts.get('bundle') and opts.get('subrepos'):
3222 if opts.get('bundle') and opts.get('subrepos'):
3223 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3223 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3224
3224
3225 if opts.get('bookmarks'):
3225 if opts.get('bookmarks'):
3226 source, branches = hg.parseurl(ui.expandpath(source),
3226 source, branches = hg.parseurl(ui.expandpath(source),
3227 opts.get('branch'))
3227 opts.get('branch'))
3228 other = hg.peer(repo, opts, source)
3228 other = hg.peer(repo, opts, source)
3229 if 'bookmarks' not in other.listkeys('namespaces'):
3229 if 'bookmarks' not in other.listkeys('namespaces'):
3230 ui.warn(_("remote doesn't support bookmarks\n"))
3230 ui.warn(_("remote doesn't support bookmarks\n"))
3231 return 0
3231 return 0
3232 ui.pager('incoming')
3232 ui.pager('incoming')
3233 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3233 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3234 return bookmarks.incoming(ui, repo, other)
3234 return bookmarks.incoming(ui, repo, other)
3235
3235
3236 repo._subtoppath = ui.expandpath(source)
3236 repo._subtoppath = ui.expandpath(source)
3237 try:
3237 try:
3238 return hg.incoming(ui, repo, source, opts)
3238 return hg.incoming(ui, repo, source, opts)
3239 finally:
3239 finally:
3240 del repo._subtoppath
3240 del repo._subtoppath
3241
3241
3242
3242
3243 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3243 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3244 norepo=True)
3244 norepo=True)
3245 def init(ui, dest=".", **opts):
3245 def init(ui, dest=".", **opts):
3246 """create a new repository in the given directory
3246 """create a new repository in the given directory
3247
3247
3248 Initialize a new repository in the given directory. If the given
3248 Initialize a new repository in the given directory. If the given
3249 directory does not exist, it will be created.
3249 directory does not exist, it will be created.
3250
3250
3251 If no directory is given, the current directory is used.
3251 If no directory is given, the current directory is used.
3252
3252
3253 It is possible to specify an ``ssh://`` URL as the destination.
3253 It is possible to specify an ``ssh://`` URL as the destination.
3254 See :hg:`help urls` for more information.
3254 See :hg:`help urls` for more information.
3255
3255
3256 Returns 0 on success.
3256 Returns 0 on success.
3257 """
3257 """
3258 opts = pycompat.byteskwargs(opts)
3258 opts = pycompat.byteskwargs(opts)
3259 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3259 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3260
3260
3261 @command('locate',
3261 @command('locate',
3262 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3262 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3263 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3263 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3264 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3264 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3265 ] + walkopts,
3265 ] + walkopts,
3266 _('[OPTION]... [PATTERN]...'))
3266 _('[OPTION]... [PATTERN]...'))
3267 def locate(ui, repo, *pats, **opts):
3267 def locate(ui, repo, *pats, **opts):
3268 """locate files matching specific patterns (DEPRECATED)
3268 """locate files matching specific patterns (DEPRECATED)
3269
3269
3270 Print files under Mercurial control in the working directory whose
3270 Print files under Mercurial control in the working directory whose
3271 names match the given patterns.
3271 names match the given patterns.
3272
3272
3273 By default, this command searches all directories in the working
3273 By default, this command searches all directories in the working
3274 directory. To search just the current directory and its
3274 directory. To search just the current directory and its
3275 subdirectories, use "--include .".
3275 subdirectories, use "--include .".
3276
3276
3277 If no patterns are given to match, this command prints the names
3277 If no patterns are given to match, this command prints the names
3278 of all files under Mercurial control in the working directory.
3278 of all files under Mercurial control in the working directory.
3279
3279
3280 If you want to feed the output of this command into the "xargs"
3280 If you want to feed the output of this command into the "xargs"
3281 command, use the -0 option to both this command and "xargs". This
3281 command, use the -0 option to both this command and "xargs". This
3282 will avoid the problem of "xargs" treating single filenames that
3282 will avoid the problem of "xargs" treating single filenames that
3283 contain whitespace as multiple filenames.
3283 contain whitespace as multiple filenames.
3284
3284
3285 See :hg:`help files` for a more versatile command.
3285 See :hg:`help files` for a more versatile command.
3286
3286
3287 Returns 0 if a match is found, 1 otherwise.
3287 Returns 0 if a match is found, 1 otherwise.
3288 """
3288 """
3289 opts = pycompat.byteskwargs(opts)
3289 opts = pycompat.byteskwargs(opts)
3290 if opts.get('print0'):
3290 if opts.get('print0'):
3291 end = '\0'
3291 end = '\0'
3292 else:
3292 else:
3293 end = '\n'
3293 end = '\n'
3294 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3294 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3295
3295
3296 ret = 1
3296 ret = 1
3297 ctx = repo[rev]
3297 ctx = repo[rev]
3298 m = scmutil.match(ctx, pats, opts, default='relglob',
3298 m = scmutil.match(ctx, pats, opts, default='relglob',
3299 badfn=lambda x, y: False)
3299 badfn=lambda x, y: False)
3300
3300
3301 ui.pager('locate')
3301 ui.pager('locate')
3302 for abs in ctx.matches(m):
3302 for abs in ctx.matches(m):
3303 if opts.get('fullpath'):
3303 if opts.get('fullpath'):
3304 ui.write(repo.wjoin(abs), end)
3304 ui.write(repo.wjoin(abs), end)
3305 else:
3305 else:
3306 ui.write(((pats and m.rel(abs)) or abs), end)
3306 ui.write(((pats and m.rel(abs)) or abs), end)
3307 ret = 0
3307 ret = 0
3308
3308
3309 return ret
3309 return ret
3310
3310
3311 @command('^log|history',
3311 @command('^log|history',
3312 [('f', 'follow', None,
3312 [('f', 'follow', None,
3313 _('follow changeset history, or file history across copies and renames')),
3313 _('follow changeset history, or file history across copies and renames')),
3314 ('', 'follow-first', None,
3314 ('', 'follow-first', None,
3315 _('only follow the first parent of merge changesets (DEPRECATED)')),
3315 _('only follow the first parent of merge changesets (DEPRECATED)')),
3316 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3316 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3317 ('C', 'copies', None, _('show copied files')),
3317 ('C', 'copies', None, _('show copied files')),
3318 ('k', 'keyword', [],
3318 ('k', 'keyword', [],
3319 _('do case-insensitive search for a given text'), _('TEXT')),
3319 _('do case-insensitive search for a given text'), _('TEXT')),
3320 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3320 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3321 ('', 'removed', None, _('include revisions where files were removed')),
3321 ('', 'removed', None, _('include revisions where files were removed')),
3322 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3322 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3323 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3323 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3324 ('', 'only-branch', [],
3324 ('', 'only-branch', [],
3325 _('show only changesets within the given named branch (DEPRECATED)'),
3325 _('show only changesets within the given named branch (DEPRECATED)'),
3326 _('BRANCH')),
3326 _('BRANCH')),
3327 ('b', 'branch', [],
3327 ('b', 'branch', [],
3328 _('show changesets within the given named branch'), _('BRANCH')),
3328 _('show changesets within the given named branch'), _('BRANCH')),
3329 ('P', 'prune', [],
3329 ('P', 'prune', [],
3330 _('do not display revision or any of its ancestors'), _('REV')),
3330 _('do not display revision or any of its ancestors'), _('REV')),
3331 ] + logopts + walkopts,
3331 ] + logopts + walkopts,
3332 _('[OPTION]... [FILE]'),
3332 _('[OPTION]... [FILE]'),
3333 inferrepo=True)
3333 inferrepo=True)
3334 def log(ui, repo, *pats, **opts):
3334 def log(ui, repo, *pats, **opts):
3335 """show revision history of entire repository or files
3335 """show revision history of entire repository or files
3336
3336
3337 Print the revision history of the specified files or the entire
3337 Print the revision history of the specified files or the entire
3338 project.
3338 project.
3339
3339
3340 If no revision range is specified, the default is ``tip:0`` unless
3340 If no revision range is specified, the default is ``tip:0`` unless
3341 --follow is set, in which case the working directory parent is
3341 --follow is set, in which case the working directory parent is
3342 used as the starting revision.
3342 used as the starting revision.
3343
3343
3344 File history is shown without following rename or copy history of
3344 File history is shown without following rename or copy history of
3345 files. Use -f/--follow with a filename to follow history across
3345 files. Use -f/--follow with a filename to follow history across
3346 renames and copies. --follow without a filename will only show
3346 renames and copies. --follow without a filename will only show
3347 ancestors or descendants of the starting revision.
3347 ancestors or descendants of the starting revision.
3348
3348
3349 By default this command prints revision number and changeset id,
3349 By default this command prints revision number and changeset id,
3350 tags, non-trivial parents, user, date and time, and a summary for
3350 tags, non-trivial parents, user, date and time, and a summary for
3351 each commit. When the -v/--verbose switch is used, the list of
3351 each commit. When the -v/--verbose switch is used, the list of
3352 changed files and full commit message are shown.
3352 changed files and full commit message are shown.
3353
3353
3354 With --graph the revisions are shown as an ASCII art DAG with the most
3354 With --graph the revisions are shown as an ASCII art DAG with the most
3355 recent changeset at the top.
3355 recent changeset at the top.
3356 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3356 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3357 and '+' represents a fork where the changeset from the lines below is a
3357 and '+' represents a fork where the changeset from the lines below is a
3358 parent of the 'o' merge on the same line.
3358 parent of the 'o' merge on the same line.
3359 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3359 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3360 of a '|' indicates one or more revisions in a path are omitted.
3360 of a '|' indicates one or more revisions in a path are omitted.
3361
3361
3362 .. note::
3362 .. note::
3363
3363
3364 :hg:`log --patch` may generate unexpected diff output for merge
3364 :hg:`log --patch` may generate unexpected diff output for merge
3365 changesets, as it will only compare the merge changeset against
3365 changesets, as it will only compare the merge changeset against
3366 its first parent. Also, only files different from BOTH parents
3366 its first parent. Also, only files different from BOTH parents
3367 will appear in files:.
3367 will appear in files:.
3368
3368
3369 .. note::
3369 .. note::
3370
3370
3371 For performance reasons, :hg:`log FILE` may omit duplicate changes
3371 For performance reasons, :hg:`log FILE` may omit duplicate changes
3372 made on branches and will not show removals or mode changes. To
3372 made on branches and will not show removals or mode changes. To
3373 see all such changes, use the --removed switch.
3373 see all such changes, use the --removed switch.
3374
3374
3375 .. container:: verbose
3375 .. container:: verbose
3376
3376
3377 Some examples:
3377 Some examples:
3378
3378
3379 - changesets with full descriptions and file lists::
3379 - changesets with full descriptions and file lists::
3380
3380
3381 hg log -v
3381 hg log -v
3382
3382
3383 - changesets ancestral to the working directory::
3383 - changesets ancestral to the working directory::
3384
3384
3385 hg log -f
3385 hg log -f
3386
3386
3387 - last 10 commits on the current branch::
3387 - last 10 commits on the current branch::
3388
3388
3389 hg log -l 10 -b .
3389 hg log -l 10 -b .
3390
3390
3391 - changesets showing all modifications of a file, including removals::
3391 - changesets showing all modifications of a file, including removals::
3392
3392
3393 hg log --removed file.c
3393 hg log --removed file.c
3394
3394
3395 - all changesets that touch a directory, with diffs, excluding merges::
3395 - all changesets that touch a directory, with diffs, excluding merges::
3396
3396
3397 hg log -Mp lib/
3397 hg log -Mp lib/
3398
3398
3399 - all revision numbers that match a keyword::
3399 - all revision numbers that match a keyword::
3400
3400
3401 hg log -k bug --template "{rev}\\n"
3401 hg log -k bug --template "{rev}\\n"
3402
3402
3403 - the full hash identifier of the working directory parent::
3403 - the full hash identifier of the working directory parent::
3404
3404
3405 hg log -r . --template "{node}\\n"
3405 hg log -r . --template "{node}\\n"
3406
3406
3407 - list available log templates::
3407 - list available log templates::
3408
3408
3409 hg log -T list
3409 hg log -T list
3410
3410
3411 - check if a given changeset is included in a tagged release::
3411 - check if a given changeset is included in a tagged release::
3412
3412
3413 hg log -r "a21ccf and ancestor(1.9)"
3413 hg log -r "a21ccf and ancestor(1.9)"
3414
3414
3415 - find all changesets by some user in a date range::
3415 - find all changesets by some user in a date range::
3416
3416
3417 hg log -k alice -d "may 2008 to jul 2008"
3417 hg log -k alice -d "may 2008 to jul 2008"
3418
3418
3419 - summary of all changesets after the last tag::
3419 - summary of all changesets after the last tag::
3420
3420
3421 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3421 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3422
3422
3423 See :hg:`help dates` for a list of formats valid for -d/--date.
3423 See :hg:`help dates` for a list of formats valid for -d/--date.
3424
3424
3425 See :hg:`help revisions` for more about specifying and ordering
3425 See :hg:`help revisions` for more about specifying and ordering
3426 revisions.
3426 revisions.
3427
3427
3428 See :hg:`help templates` for more about pre-packaged styles and
3428 See :hg:`help templates` for more about pre-packaged styles and
3429 specifying custom templates.
3429 specifying custom templates.
3430
3430
3431 Returns 0 on success.
3431 Returns 0 on success.
3432
3432
3433 """
3433 """
3434 opts = pycompat.byteskwargs(opts)
3434 opts = pycompat.byteskwargs(opts)
3435 if opts.get('follow') and opts.get('rev'):
3435 if opts.get('follow') and opts.get('rev'):
3436 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3436 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3437 del opts['follow']
3437 del opts['follow']
3438
3438
3439 if opts.get('graph'):
3439 if opts.get('graph'):
3440 return cmdutil.graphlog(ui, repo, pats, opts)
3440 return cmdutil.graphlog(ui, repo, pats, opts)
3441
3441
3442 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3442 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3443 limit = cmdutil.loglimit(opts)
3443 limit = cmdutil.loglimit(opts)
3444 count = 0
3444 count = 0
3445
3445
3446 getrenamed = None
3446 getrenamed = None
3447 if opts.get('copies'):
3447 if opts.get('copies'):
3448 endrev = None
3448 endrev = None
3449 if opts.get('rev'):
3449 if opts.get('rev'):
3450 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3450 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3451 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3451 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3452
3452
3453 ui.pager('log')
3453 ui.pager('log')
3454 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3454 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3455 for rev in revs:
3455 for rev in revs:
3456 if count == limit:
3456 if count == limit:
3457 break
3457 break
3458 ctx = repo[rev]
3458 ctx = repo[rev]
3459 copies = None
3459 copies = None
3460 if getrenamed is not None and rev:
3460 if getrenamed is not None and rev:
3461 copies = []
3461 copies = []
3462 for fn in ctx.files():
3462 for fn in ctx.files():
3463 rename = getrenamed(fn, rev)
3463 rename = getrenamed(fn, rev)
3464 if rename:
3464 if rename:
3465 copies.append((fn, rename[0]))
3465 copies.append((fn, rename[0]))
3466 if filematcher:
3466 if filematcher:
3467 revmatchfn = filematcher(ctx.rev())
3467 revmatchfn = filematcher(ctx.rev())
3468 else:
3468 else:
3469 revmatchfn = None
3469 revmatchfn = None
3470 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3470 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3471 if displayer.flush(ctx):
3471 if displayer.flush(ctx):
3472 count += 1
3472 count += 1
3473
3473
3474 displayer.close()
3474 displayer.close()
3475
3475
3476 @command('manifest',
3476 @command('manifest',
3477 [('r', 'rev', '', _('revision to display'), _('REV')),
3477 [('r', 'rev', '', _('revision to display'), _('REV')),
3478 ('', 'all', False, _("list files from all revisions"))]
3478 ('', 'all', False, _("list files from all revisions"))]
3479 + formatteropts,
3479 + formatteropts,
3480 _('[-r REV]'))
3480 _('[-r REV]'))
3481 def manifest(ui, repo, node=None, rev=None, **opts):
3481 def manifest(ui, repo, node=None, rev=None, **opts):
3482 """output the current or given revision of the project manifest
3482 """output the current or given revision of the project manifest
3483
3483
3484 Print a list of version controlled files for the given revision.
3484 Print a list of version controlled files for the given revision.
3485 If no revision is given, the first parent of the working directory
3485 If no revision is given, the first parent of the working directory
3486 is used, or the null revision if no revision is checked out.
3486 is used, or the null revision if no revision is checked out.
3487
3487
3488 With -v, print file permissions, symlink and executable bits.
3488 With -v, print file permissions, symlink and executable bits.
3489 With --debug, print file revision hashes.
3489 With --debug, print file revision hashes.
3490
3490
3491 If option --all is specified, the list of all files from all revisions
3491 If option --all is specified, the list of all files from all revisions
3492 is printed. This includes deleted and renamed files.
3492 is printed. This includes deleted and renamed files.
3493
3493
3494 Returns 0 on success.
3494 Returns 0 on success.
3495 """
3495 """
3496 opts = pycompat.byteskwargs(opts)
3496 opts = pycompat.byteskwargs(opts)
3497 fm = ui.formatter('manifest', opts)
3497 fm = ui.formatter('manifest', opts)
3498
3498
3499 if opts.get('all'):
3499 if opts.get('all'):
3500 if rev or node:
3500 if rev or node:
3501 raise error.Abort(_("can't specify a revision with --all"))
3501 raise error.Abort(_("can't specify a revision with --all"))
3502
3502
3503 res = []
3503 res = []
3504 prefix = "data/"
3504 prefix = "data/"
3505 suffix = ".i"
3505 suffix = ".i"
3506 plen = len(prefix)
3506 plen = len(prefix)
3507 slen = len(suffix)
3507 slen = len(suffix)
3508 with repo.lock():
3508 with repo.lock():
3509 for fn, b, size in repo.store.datafiles():
3509 for fn, b, size in repo.store.datafiles():
3510 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3510 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3511 res.append(fn[plen:-slen])
3511 res.append(fn[plen:-slen])
3512 ui.pager('manifest')
3512 ui.pager('manifest')
3513 for f in res:
3513 for f in res:
3514 fm.startitem()
3514 fm.startitem()
3515 fm.write("path", '%s\n', f)
3515 fm.write("path", '%s\n', f)
3516 fm.end()
3516 fm.end()
3517 return
3517 return
3518
3518
3519 if rev and node:
3519 if rev and node:
3520 raise error.Abort(_("please specify just one revision"))
3520 raise error.Abort(_("please specify just one revision"))
3521
3521
3522 if not node:
3522 if not node:
3523 node = rev
3523 node = rev
3524
3524
3525 char = {'l': '@', 'x': '*', '': ''}
3525 char = {'l': '@', 'x': '*', '': ''}
3526 mode = {'l': '644', 'x': '755', '': '644'}
3526 mode = {'l': '644', 'x': '755', '': '644'}
3527 ctx = scmutil.revsingle(repo, node)
3527 ctx = scmutil.revsingle(repo, node)
3528 mf = ctx.manifest()
3528 mf = ctx.manifest()
3529 ui.pager('manifest')
3529 ui.pager('manifest')
3530 for f in ctx:
3530 for f in ctx:
3531 fm.startitem()
3531 fm.startitem()
3532 fl = ctx[f].flags()
3532 fl = ctx[f].flags()
3533 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3533 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3534 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3534 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3535 fm.write('path', '%s\n', f)
3535 fm.write('path', '%s\n', f)
3536 fm.end()
3536 fm.end()
3537
3537
3538 @command('^merge',
3538 @command('^merge',
3539 [('f', 'force', None,
3539 [('f', 'force', None,
3540 _('force a merge including outstanding changes (DEPRECATED)')),
3540 _('force a merge including outstanding changes (DEPRECATED)')),
3541 ('r', 'rev', '', _('revision to merge'), _('REV')),
3541 ('r', 'rev', '', _('revision to merge'), _('REV')),
3542 ('P', 'preview', None,
3542 ('P', 'preview', None,
3543 _('review revisions to merge (no merge is performed)'))
3543 _('review revisions to merge (no merge is performed)'))
3544 ] + mergetoolopts,
3544 ] + mergetoolopts,
3545 _('[-P] [[-r] REV]'))
3545 _('[-P] [[-r] REV]'))
3546 def merge(ui, repo, node=None, **opts):
3546 def merge(ui, repo, node=None, **opts):
3547 """merge another revision into working directory
3547 """merge another revision into working directory
3548
3548
3549 The current working directory is updated with all changes made in
3549 The current working directory is updated with all changes made in
3550 the requested revision since the last common predecessor revision.
3550 the requested revision since the last common predecessor revision.
3551
3551
3552 Files that changed between either parent are marked as changed for
3552 Files that changed between either parent are marked as changed for
3553 the next commit and a commit must be performed before any further
3553 the next commit and a commit must be performed before any further
3554 updates to the repository are allowed. The next commit will have
3554 updates to the repository are allowed. The next commit will have
3555 two parents.
3555 two parents.
3556
3556
3557 ``--tool`` can be used to specify the merge tool used for file
3557 ``--tool`` can be used to specify the merge tool used for file
3558 merges. It overrides the HGMERGE environment variable and your
3558 merges. It overrides the HGMERGE environment variable and your
3559 configuration files. See :hg:`help merge-tools` for options.
3559 configuration files. See :hg:`help merge-tools` for options.
3560
3560
3561 If no revision is specified, the working directory's parent is a
3561 If no revision is specified, the working directory's parent is a
3562 head revision, and the current branch contains exactly one other
3562 head revision, and the current branch contains exactly one other
3563 head, the other head is merged with by default. Otherwise, an
3563 head, the other head is merged with by default. Otherwise, an
3564 explicit revision with which to merge with must be provided.
3564 explicit revision with which to merge with must be provided.
3565
3565
3566 See :hg:`help resolve` for information on handling file conflicts.
3566 See :hg:`help resolve` for information on handling file conflicts.
3567
3567
3568 To undo an uncommitted merge, use :hg:`update --clean .` which
3568 To undo an uncommitted merge, use :hg:`update --clean .` which
3569 will check out a clean copy of the original merge parent, losing
3569 will check out a clean copy of the original merge parent, losing
3570 all changes.
3570 all changes.
3571
3571
3572 Returns 0 on success, 1 if there are unresolved files.
3572 Returns 0 on success, 1 if there are unresolved files.
3573 """
3573 """
3574
3574
3575 opts = pycompat.byteskwargs(opts)
3575 opts = pycompat.byteskwargs(opts)
3576 if opts.get('rev') and node:
3576 if opts.get('rev') and node:
3577 raise error.Abort(_("please specify just one revision"))
3577 raise error.Abort(_("please specify just one revision"))
3578 if not node:
3578 if not node:
3579 node = opts.get('rev')
3579 node = opts.get('rev')
3580
3580
3581 if node:
3581 if node:
3582 node = scmutil.revsingle(repo, node).node()
3582 node = scmutil.revsingle(repo, node).node()
3583
3583
3584 if not node:
3584 if not node:
3585 node = repo[destutil.destmerge(repo)].node()
3585 node = repo[destutil.destmerge(repo)].node()
3586
3586
3587 if opts.get('preview'):
3587 if opts.get('preview'):
3588 # find nodes that are ancestors of p2 but not of p1
3588 # find nodes that are ancestors of p2 but not of p1
3589 p1 = repo.lookup('.')
3589 p1 = repo.lookup('.')
3590 p2 = repo.lookup(node)
3590 p2 = repo.lookup(node)
3591 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3591 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3592
3592
3593 displayer = cmdutil.show_changeset(ui, repo, opts)
3593 displayer = cmdutil.show_changeset(ui, repo, opts)
3594 for node in nodes:
3594 for node in nodes:
3595 displayer.show(repo[node])
3595 displayer.show(repo[node])
3596 displayer.close()
3596 displayer.close()
3597 return 0
3597 return 0
3598
3598
3599 try:
3599 try:
3600 # ui.forcemerge is an internal variable, do not document
3600 # ui.forcemerge is an internal variable, do not document
3601 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3601 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3602 force = opts.get('force')
3602 force = opts.get('force')
3603 labels = ['working copy', 'merge rev']
3603 labels = ['working copy', 'merge rev']
3604 return hg.merge(repo, node, force=force, mergeforce=force,
3604 return hg.merge(repo, node, force=force, mergeforce=force,
3605 labels=labels)
3605 labels=labels)
3606 finally:
3606 finally:
3607 ui.setconfig('ui', 'forcemerge', '', 'merge')
3607 ui.setconfig('ui', 'forcemerge', '', 'merge')
3608
3608
3609 @command('outgoing|out',
3609 @command('outgoing|out',
3610 [('f', 'force', None, _('run even when the destination is unrelated')),
3610 [('f', 'force', None, _('run even when the destination is unrelated')),
3611 ('r', 'rev', [],
3611 ('r', 'rev', [],
3612 _('a changeset intended to be included in the destination'), _('REV')),
3612 _('a changeset intended to be included in the destination'), _('REV')),
3613 ('n', 'newest-first', None, _('show newest record first')),
3613 ('n', 'newest-first', None, _('show newest record first')),
3614 ('B', 'bookmarks', False, _('compare bookmarks')),
3614 ('B', 'bookmarks', False, _('compare bookmarks')),
3615 ('b', 'branch', [], _('a specific branch you would like to push'),
3615 ('b', 'branch', [], _('a specific branch you would like to push'),
3616 _('BRANCH')),
3616 _('BRANCH')),
3617 ] + logopts + remoteopts + subrepoopts,
3617 ] + logopts + remoteopts + subrepoopts,
3618 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3618 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3619 def outgoing(ui, repo, dest=None, **opts):
3619 def outgoing(ui, repo, dest=None, **opts):
3620 """show changesets not found in the destination
3620 """show changesets not found in the destination
3621
3621
3622 Show changesets not found in the specified destination repository
3622 Show changesets not found in the specified destination repository
3623 or the default push location. These are the changesets that would
3623 or the default push location. These are the changesets that would
3624 be pushed if a push was requested.
3624 be pushed if a push was requested.
3625
3625
3626 See pull for details of valid destination formats.
3626 See pull for details of valid destination formats.
3627
3627
3628 .. container:: verbose
3628 .. container:: verbose
3629
3629
3630 With -B/--bookmarks, the result of bookmark comparison between
3630 With -B/--bookmarks, the result of bookmark comparison between
3631 local and remote repositories is displayed. With -v/--verbose,
3631 local and remote repositories is displayed. With -v/--verbose,
3632 status is also displayed for each bookmark like below::
3632 status is also displayed for each bookmark like below::
3633
3633
3634 BM1 01234567890a added
3634 BM1 01234567890a added
3635 BM2 deleted
3635 BM2 deleted
3636 BM3 234567890abc advanced
3636 BM3 234567890abc advanced
3637 BM4 34567890abcd diverged
3637 BM4 34567890abcd diverged
3638 BM5 4567890abcde changed
3638 BM5 4567890abcde changed
3639
3639
3640 The action taken when pushing depends on the
3640 The action taken when pushing depends on the
3641 status of each bookmark:
3641 status of each bookmark:
3642
3642
3643 :``added``: push with ``-B`` will create it
3643 :``added``: push with ``-B`` will create it
3644 :``deleted``: push with ``-B`` will delete it
3644 :``deleted``: push with ``-B`` will delete it
3645 :``advanced``: push will update it
3645 :``advanced``: push will update it
3646 :``diverged``: push with ``-B`` will update it
3646 :``diverged``: push with ``-B`` will update it
3647 :``changed``: push with ``-B`` will update it
3647 :``changed``: push with ``-B`` will update it
3648
3648
3649 From the point of view of pushing behavior, bookmarks
3649 From the point of view of pushing behavior, bookmarks
3650 existing only in the remote repository are treated as
3650 existing only in the remote repository are treated as
3651 ``deleted``, even if it is in fact added remotely.
3651 ``deleted``, even if it is in fact added remotely.
3652
3652
3653 Returns 0 if there are outgoing changes, 1 otherwise.
3653 Returns 0 if there are outgoing changes, 1 otherwise.
3654 """
3654 """
3655 opts = pycompat.byteskwargs(opts)
3655 opts = pycompat.byteskwargs(opts)
3656 if opts.get('graph'):
3656 if opts.get('graph'):
3657 cmdutil.checkunsupportedgraphflags([], opts)
3657 cmdutil.checkunsupportedgraphflags([], opts)
3658 o, other = hg._outgoing(ui, repo, dest, opts)
3658 o, other = hg._outgoing(ui, repo, dest, opts)
3659 if not o:
3659 if not o:
3660 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3660 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3661 return
3661 return
3662
3662
3663 revdag = cmdutil.graphrevs(repo, o, opts)
3663 revdag = cmdutil.graphrevs(repo, o, opts)
3664 ui.pager('outgoing')
3664 ui.pager('outgoing')
3665 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3665 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3666 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3666 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3667 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3667 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3668 return 0
3668 return 0
3669
3669
3670 if opts.get('bookmarks'):
3670 if opts.get('bookmarks'):
3671 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3671 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3672 dest, branches = hg.parseurl(dest, opts.get('branch'))
3672 dest, branches = hg.parseurl(dest, opts.get('branch'))
3673 other = hg.peer(repo, opts, dest)
3673 other = hg.peer(repo, opts, dest)
3674 if 'bookmarks' not in other.listkeys('namespaces'):
3674 if 'bookmarks' not in other.listkeys('namespaces'):
3675 ui.warn(_("remote doesn't support bookmarks\n"))
3675 ui.warn(_("remote doesn't support bookmarks\n"))
3676 return 0
3676 return 0
3677 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3677 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3678 ui.pager('outgoing')
3678 ui.pager('outgoing')
3679 return bookmarks.outgoing(ui, repo, other)
3679 return bookmarks.outgoing(ui, repo, other)
3680
3680
3681 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3681 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3682 try:
3682 try:
3683 return hg.outgoing(ui, repo, dest, opts)
3683 return hg.outgoing(ui, repo, dest, opts)
3684 finally:
3684 finally:
3685 del repo._subtoppath
3685 del repo._subtoppath
3686
3686
3687 @command('parents',
3687 @command('parents',
3688 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3688 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3689 ] + templateopts,
3689 ] + templateopts,
3690 _('[-r REV] [FILE]'),
3690 _('[-r REV] [FILE]'),
3691 inferrepo=True)
3691 inferrepo=True)
3692 def parents(ui, repo, file_=None, **opts):
3692 def parents(ui, repo, file_=None, **opts):
3693 """show the parents of the working directory or revision (DEPRECATED)
3693 """show the parents of the working directory or revision (DEPRECATED)
3694
3694
3695 Print the working directory's parent revisions. If a revision is
3695 Print the working directory's parent revisions. If a revision is
3696 given via -r/--rev, the parent of that revision will be printed.
3696 given via -r/--rev, the parent of that revision will be printed.
3697 If a file argument is given, the revision in which the file was
3697 If a file argument is given, the revision in which the file was
3698 last changed (before the working directory revision or the
3698 last changed (before the working directory revision or the
3699 argument to --rev if given) is printed.
3699 argument to --rev if given) is printed.
3700
3700
3701 This command is equivalent to::
3701 This command is equivalent to::
3702
3702
3703 hg log -r "p1()+p2()" or
3703 hg log -r "p1()+p2()" or
3704 hg log -r "p1(REV)+p2(REV)" or
3704 hg log -r "p1(REV)+p2(REV)" or
3705 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3705 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3706 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3706 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3707
3707
3708 See :hg:`summary` and :hg:`help revsets` for related information.
3708 See :hg:`summary` and :hg:`help revsets` for related information.
3709
3709
3710 Returns 0 on success.
3710 Returns 0 on success.
3711 """
3711 """
3712
3712
3713 opts = pycompat.byteskwargs(opts)
3713 opts = pycompat.byteskwargs(opts)
3714 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3714 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3715
3715
3716 if file_:
3716 if file_:
3717 m = scmutil.match(ctx, (file_,), opts)
3717 m = scmutil.match(ctx, (file_,), opts)
3718 if m.anypats() or len(m.files()) != 1:
3718 if m.anypats() or len(m.files()) != 1:
3719 raise error.Abort(_('can only specify an explicit filename'))
3719 raise error.Abort(_('can only specify an explicit filename'))
3720 file_ = m.files()[0]
3720 file_ = m.files()[0]
3721 filenodes = []
3721 filenodes = []
3722 for cp in ctx.parents():
3722 for cp in ctx.parents():
3723 if not cp:
3723 if not cp:
3724 continue
3724 continue
3725 try:
3725 try:
3726 filenodes.append(cp.filenode(file_))
3726 filenodes.append(cp.filenode(file_))
3727 except error.LookupError:
3727 except error.LookupError:
3728 pass
3728 pass
3729 if not filenodes:
3729 if not filenodes:
3730 raise error.Abort(_("'%s' not found in manifest!") % file_)
3730 raise error.Abort(_("'%s' not found in manifest!") % file_)
3731 p = []
3731 p = []
3732 for fn in filenodes:
3732 for fn in filenodes:
3733 fctx = repo.filectx(file_, fileid=fn)
3733 fctx = repo.filectx(file_, fileid=fn)
3734 p.append(fctx.node())
3734 p.append(fctx.node())
3735 else:
3735 else:
3736 p = [cp.node() for cp in ctx.parents()]
3736 p = [cp.node() for cp in ctx.parents()]
3737
3737
3738 displayer = cmdutil.show_changeset(ui, repo, opts)
3738 displayer = cmdutil.show_changeset(ui, repo, opts)
3739 for n in p:
3739 for n in p:
3740 if n != nullid:
3740 if n != nullid:
3741 displayer.show(repo[n])
3741 displayer.show(repo[n])
3742 displayer.close()
3742 displayer.close()
3743
3743
3744 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3744 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3745 def paths(ui, repo, search=None, **opts):
3745 def paths(ui, repo, search=None, **opts):
3746 """show aliases for remote repositories
3746 """show aliases for remote repositories
3747
3747
3748 Show definition of symbolic path name NAME. If no name is given,
3748 Show definition of symbolic path name NAME. If no name is given,
3749 show definition of all available names.
3749 show definition of all available names.
3750
3750
3751 Option -q/--quiet suppresses all output when searching for NAME
3751 Option -q/--quiet suppresses all output when searching for NAME
3752 and shows only the path names when listing all definitions.
3752 and shows only the path names when listing all definitions.
3753
3753
3754 Path names are defined in the [paths] section of your
3754 Path names are defined in the [paths] section of your
3755 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3755 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3756 repository, ``.hg/hgrc`` is used, too.
3756 repository, ``.hg/hgrc`` is used, too.
3757
3757
3758 The path names ``default`` and ``default-push`` have a special
3758 The path names ``default`` and ``default-push`` have a special
3759 meaning. When performing a push or pull operation, they are used
3759 meaning. When performing a push or pull operation, they are used
3760 as fallbacks if no location is specified on the command-line.
3760 as fallbacks if no location is specified on the command-line.
3761 When ``default-push`` is set, it will be used for push and
3761 When ``default-push`` is set, it will be used for push and
3762 ``default`` will be used for pull; otherwise ``default`` is used
3762 ``default`` will be used for pull; otherwise ``default`` is used
3763 as the fallback for both. When cloning a repository, the clone
3763 as the fallback for both. When cloning a repository, the clone
3764 source is written as ``default`` in ``.hg/hgrc``.
3764 source is written as ``default`` in ``.hg/hgrc``.
3765
3765
3766 .. note::
3766 .. note::
3767
3767
3768 ``default`` and ``default-push`` apply to all inbound (e.g.
3768 ``default`` and ``default-push`` apply to all inbound (e.g.
3769 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3769 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3770 and :hg:`bundle`) operations.
3770 and :hg:`bundle`) operations.
3771
3771
3772 See :hg:`help urls` for more information.
3772 See :hg:`help urls` for more information.
3773
3773
3774 Returns 0 on success.
3774 Returns 0 on success.
3775 """
3775 """
3776
3776
3777 opts = pycompat.byteskwargs(opts)
3777 opts = pycompat.byteskwargs(opts)
3778 ui.pager('paths')
3778 ui.pager('paths')
3779 if search:
3779 if search:
3780 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3780 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3781 if name == search]
3781 if name == search]
3782 else:
3782 else:
3783 pathitems = sorted(ui.paths.iteritems())
3783 pathitems = sorted(ui.paths.iteritems())
3784
3784
3785 fm = ui.formatter('paths', opts)
3785 fm = ui.formatter('paths', opts)
3786 if fm.isplain():
3786 if fm.isplain():
3787 hidepassword = util.hidepassword
3787 hidepassword = util.hidepassword
3788 else:
3788 else:
3789 hidepassword = str
3789 hidepassword = str
3790 if ui.quiet:
3790 if ui.quiet:
3791 namefmt = '%s\n'
3791 namefmt = '%s\n'
3792 else:
3792 else:
3793 namefmt = '%s = '
3793 namefmt = '%s = '
3794 showsubopts = not search and not ui.quiet
3794 showsubopts = not search and not ui.quiet
3795
3795
3796 for name, path in pathitems:
3796 for name, path in pathitems:
3797 fm.startitem()
3797 fm.startitem()
3798 fm.condwrite(not search, 'name', namefmt, name)
3798 fm.condwrite(not search, 'name', namefmt, name)
3799 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3799 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3800 for subopt, value in sorted(path.suboptions.items()):
3800 for subopt, value in sorted(path.suboptions.items()):
3801 assert subopt not in ('name', 'url')
3801 assert subopt not in ('name', 'url')
3802 if showsubopts:
3802 if showsubopts:
3803 fm.plain('%s:%s = ' % (name, subopt))
3803 fm.plain('%s:%s = ' % (name, subopt))
3804 fm.condwrite(showsubopts, subopt, '%s\n', value)
3804 fm.condwrite(showsubopts, subopt, '%s\n', value)
3805
3805
3806 fm.end()
3806 fm.end()
3807
3807
3808 if search and not pathitems:
3808 if search and not pathitems:
3809 if not ui.quiet:
3809 if not ui.quiet:
3810 ui.warn(_("not found!\n"))
3810 ui.warn(_("not found!\n"))
3811 return 1
3811 return 1
3812 else:
3812 else:
3813 return 0
3813 return 0
3814
3814
3815 @command('phase',
3815 @command('phase',
3816 [('p', 'public', False, _('set changeset phase to public')),
3816 [('p', 'public', False, _('set changeset phase to public')),
3817 ('d', 'draft', False, _('set changeset phase to draft')),
3817 ('d', 'draft', False, _('set changeset phase to draft')),
3818 ('s', 'secret', False, _('set changeset phase to secret')),
3818 ('s', 'secret', False, _('set changeset phase to secret')),
3819 ('f', 'force', False, _('allow to move boundary backward')),
3819 ('f', 'force', False, _('allow to move boundary backward')),
3820 ('r', 'rev', [], _('target revision'), _('REV')),
3820 ('r', 'rev', [], _('target revision'), _('REV')),
3821 ],
3821 ],
3822 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3822 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3823 def phase(ui, repo, *revs, **opts):
3823 def phase(ui, repo, *revs, **opts):
3824 """set or show the current phase name
3824 """set or show the current phase name
3825
3825
3826 With no argument, show the phase name of the current revision(s).
3826 With no argument, show the phase name of the current revision(s).
3827
3827
3828 With one of -p/--public, -d/--draft or -s/--secret, change the
3828 With one of -p/--public, -d/--draft or -s/--secret, change the
3829 phase value of the specified revisions.
3829 phase value of the specified revisions.
3830
3830
3831 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3831 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3832 lower phase to an higher phase. Phases are ordered as follows::
3832 lower phase to an higher phase. Phases are ordered as follows::
3833
3833
3834 public < draft < secret
3834 public < draft < secret
3835
3835
3836 Returns 0 on success, 1 if some phases could not be changed.
3836 Returns 0 on success, 1 if some phases could not be changed.
3837
3837
3838 (For more information about the phases concept, see :hg:`help phases`.)
3838 (For more information about the phases concept, see :hg:`help phases`.)
3839 """
3839 """
3840 opts = pycompat.byteskwargs(opts)
3840 opts = pycompat.byteskwargs(opts)
3841 # search for a unique phase argument
3841 # search for a unique phase argument
3842 targetphase = None
3842 targetphase = None
3843 for idx, name in enumerate(phases.phasenames):
3843 for idx, name in enumerate(phases.phasenames):
3844 if opts[name]:
3844 if opts[name]:
3845 if targetphase is not None:
3845 if targetphase is not None:
3846 raise error.Abort(_('only one phase can be specified'))
3846 raise error.Abort(_('only one phase can be specified'))
3847 targetphase = idx
3847 targetphase = idx
3848
3848
3849 # look for specified revision
3849 # look for specified revision
3850 revs = list(revs)
3850 revs = list(revs)
3851 revs.extend(opts['rev'])
3851 revs.extend(opts['rev'])
3852 if not revs:
3852 if not revs:
3853 # display both parents as the second parent phase can influence
3853 # display both parents as the second parent phase can influence
3854 # the phase of a merge commit
3854 # the phase of a merge commit
3855 revs = [c.rev() for c in repo[None].parents()]
3855 revs = [c.rev() for c in repo[None].parents()]
3856
3856
3857 revs = scmutil.revrange(repo, revs)
3857 revs = scmutil.revrange(repo, revs)
3858
3858
3859 lock = None
3859 lock = None
3860 ret = 0
3860 ret = 0
3861 if targetphase is None:
3861 if targetphase is None:
3862 # display
3862 # display
3863 for r in revs:
3863 for r in revs:
3864 ctx = repo[r]
3864 ctx = repo[r]
3865 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3865 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3866 else:
3866 else:
3867 tr = None
3867 tr = None
3868 lock = repo.lock()
3868 lock = repo.lock()
3869 try:
3869 try:
3870 tr = repo.transaction("phase")
3870 tr = repo.transaction("phase")
3871 # set phase
3871 # set phase
3872 if not revs:
3872 if not revs:
3873 raise error.Abort(_('empty revision set'))
3873 raise error.Abort(_('empty revision set'))
3874 nodes = [repo[r].node() for r in revs]
3874 nodes = [repo[r].node() for r in revs]
3875 # moving revision from public to draft may hide them
3875 # moving revision from public to draft may hide them
3876 # We have to check result on an unfiltered repository
3876 # We have to check result on an unfiltered repository
3877 unfi = repo.unfiltered()
3877 unfi = repo.unfiltered()
3878 getphase = unfi._phasecache.phase
3878 getphase = unfi._phasecache.phase
3879 olddata = [getphase(unfi, r) for r in unfi]
3879 olddata = [getphase(unfi, r) for r in unfi]
3880 phases.advanceboundary(repo, tr, targetphase, nodes)
3880 phases.advanceboundary(repo, tr, targetphase, nodes)
3881 if opts['force']:
3881 if opts['force']:
3882 phases.retractboundary(repo, tr, targetphase, nodes)
3882 phases.retractboundary(repo, tr, targetphase, nodes)
3883 tr.close()
3883 tr.close()
3884 finally:
3884 finally:
3885 if tr is not None:
3885 if tr is not None:
3886 tr.release()
3886 tr.release()
3887 lock.release()
3887 lock.release()
3888 getphase = unfi._phasecache.phase
3888 getphase = unfi._phasecache.phase
3889 newdata = [getphase(unfi, r) for r in unfi]
3889 newdata = [getphase(unfi, r) for r in unfi]
3890 changes = sum(newdata[r] != olddata[r] for r in unfi)
3890 changes = sum(newdata[r] != olddata[r] for r in unfi)
3891 cl = unfi.changelog
3891 cl = unfi.changelog
3892 rejected = [n for n in nodes
3892 rejected = [n for n in nodes
3893 if newdata[cl.rev(n)] < targetphase]
3893 if newdata[cl.rev(n)] < targetphase]
3894 if rejected:
3894 if rejected:
3895 ui.warn(_('cannot move %i changesets to a higher '
3895 ui.warn(_('cannot move %i changesets to a higher '
3896 'phase, use --force\n') % len(rejected))
3896 'phase, use --force\n') % len(rejected))
3897 ret = 1
3897 ret = 1
3898 if changes:
3898 if changes:
3899 msg = _('phase changed for %i changesets\n') % changes
3899 msg = _('phase changed for %i changesets\n') % changes
3900 if ret:
3900 if ret:
3901 ui.status(msg)
3901 ui.status(msg)
3902 else:
3902 else:
3903 ui.note(msg)
3903 ui.note(msg)
3904 else:
3904 else:
3905 ui.warn(_('no phases changed\n'))
3905 ui.warn(_('no phases changed\n'))
3906 return ret
3906 return ret
3907
3907
3908 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3908 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3909 """Run after a changegroup has been added via pull/unbundle
3909 """Run after a changegroup has been added via pull/unbundle
3910
3910
3911 This takes arguments below:
3911 This takes arguments below:
3912
3912
3913 :modheads: change of heads by pull/unbundle
3913 :modheads: change of heads by pull/unbundle
3914 :optupdate: updating working directory is needed or not
3914 :optupdate: updating working directory is needed or not
3915 :checkout: update destination revision (or None to default destination)
3915 :checkout: update destination revision (or None to default destination)
3916 :brev: a name, which might be a bookmark to be activated after updating
3916 :brev: a name, which might be a bookmark to be activated after updating
3917 """
3917 """
3918 if modheads == 0:
3918 if modheads == 0:
3919 return
3919 return
3920 if optupdate:
3920 if optupdate:
3921 try:
3921 try:
3922 return hg.updatetotally(ui, repo, checkout, brev)
3922 return hg.updatetotally(ui, repo, checkout, brev)
3923 except error.UpdateAbort as inst:
3923 except error.UpdateAbort as inst:
3924 msg = _("not updating: %s") % str(inst)
3924 msg = _("not updating: %s") % str(inst)
3925 hint = inst.hint
3925 hint = inst.hint
3926 raise error.UpdateAbort(msg, hint=hint)
3926 raise error.UpdateAbort(msg, hint=hint)
3927 if modheads > 1:
3927 if modheads > 1:
3928 currentbranchheads = len(repo.branchheads())
3928 currentbranchheads = len(repo.branchheads())
3929 if currentbranchheads == modheads:
3929 if currentbranchheads == modheads:
3930 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3930 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3931 elif currentbranchheads > 1:
3931 elif currentbranchheads > 1:
3932 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3932 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3933 "merge)\n"))
3933 "merge)\n"))
3934 else:
3934 else:
3935 ui.status(_("(run 'hg heads' to see heads)\n"))
3935 ui.status(_("(run 'hg heads' to see heads)\n"))
3936 else:
3936 else:
3937 ui.status(_("(run 'hg update' to get a working copy)\n"))
3937 ui.status(_("(run 'hg update' to get a working copy)\n"))
3938
3938
3939 @command('^pull',
3939 @command('^pull',
3940 [('u', 'update', None,
3940 [('u', 'update', None,
3941 _('update to new branch head if changesets were pulled')),
3941 _('update to new branch head if changesets were pulled')),
3942 ('f', 'force', None, _('run even when remote repository is unrelated')),
3942 ('f', 'force', None, _('run even when remote repository is unrelated')),
3943 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3943 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3944 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3944 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3945 ('b', 'branch', [], _('a specific branch you would like to pull'),
3945 ('b', 'branch', [], _('a specific branch you would like to pull'),
3946 _('BRANCH')),
3946 _('BRANCH')),
3947 ] + remoteopts,
3947 ] + remoteopts,
3948 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3948 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3949 def pull(ui, repo, source="default", **opts):
3949 def pull(ui, repo, source="default", **opts):
3950 """pull changes from the specified source
3950 """pull changes from the specified source
3951
3951
3952 Pull changes from a remote repository to a local one.
3952 Pull changes from a remote repository to a local one.
3953
3953
3954 This finds all changes from the repository at the specified path
3954 This finds all changes from the repository at the specified path
3955 or URL and adds them to a local repository (the current one unless
3955 or URL and adds them to a local repository (the current one unless
3956 -R is specified). By default, this does not update the copy of the
3956 -R is specified). By default, this does not update the copy of the
3957 project in the working directory.
3957 project in the working directory.
3958
3958
3959 Use :hg:`incoming` if you want to see what would have been added
3959 Use :hg:`incoming` if you want to see what would have been added
3960 by a pull at the time you issued this command. If you then decide
3960 by a pull at the time you issued this command. If you then decide
3961 to add those changes to the repository, you should use :hg:`pull
3961 to add those changes to the repository, you should use :hg:`pull
3962 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3962 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3963
3963
3964 If SOURCE is omitted, the 'default' path will be used.
3964 If SOURCE is omitted, the 'default' path will be used.
3965 See :hg:`help urls` for more information.
3965 See :hg:`help urls` for more information.
3966
3966
3967 Specifying bookmark as ``.`` is equivalent to specifying the active
3967 Specifying bookmark as ``.`` is equivalent to specifying the active
3968 bookmark's name.
3968 bookmark's name.
3969
3969
3970 Returns 0 on success, 1 if an update had unresolved files.
3970 Returns 0 on success, 1 if an update had unresolved files.
3971 """
3971 """
3972
3972
3973 opts = pycompat.byteskwargs(opts)
3973 opts = pycompat.byteskwargs(opts)
3974 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3974 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3975 msg = _('update destination required by configuration')
3975 msg = _('update destination required by configuration')
3976 hint = _('use hg pull followed by hg update DEST')
3976 hint = _('use hg pull followed by hg update DEST')
3977 raise error.Abort(msg, hint=hint)
3977 raise error.Abort(msg, hint=hint)
3978
3978
3979 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3979 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3980 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3980 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3981 other = hg.peer(repo, opts, source)
3981 other = hg.peer(repo, opts, source)
3982 try:
3982 try:
3983 revs, checkout = hg.addbranchrevs(repo, other, branches,
3983 revs, checkout = hg.addbranchrevs(repo, other, branches,
3984 opts.get('rev'))
3984 opts.get('rev'))
3985
3985
3986
3986
3987 pullopargs = {}
3987 pullopargs = {}
3988 if opts.get('bookmark'):
3988 if opts.get('bookmark'):
3989 if not revs:
3989 if not revs:
3990 revs = []
3990 revs = []
3991 # The list of bookmark used here is not the one used to actually
3991 # The list of bookmark used here is not the one used to actually
3992 # update the bookmark name. This can result in the revision pulled
3992 # update the bookmark name. This can result in the revision pulled
3993 # not ending up with the name of the bookmark because of a race
3993 # not ending up with the name of the bookmark because of a race
3994 # condition on the server. (See issue 4689 for details)
3994 # condition on the server. (See issue 4689 for details)
3995 remotebookmarks = other.listkeys('bookmarks')
3995 remotebookmarks = other.listkeys('bookmarks')
3996 pullopargs['remotebookmarks'] = remotebookmarks
3996 pullopargs['remotebookmarks'] = remotebookmarks
3997 for b in opts['bookmark']:
3997 for b in opts['bookmark']:
3998 b = repo._bookmarks.expandname(b)
3998 b = repo._bookmarks.expandname(b)
3999 if b not in remotebookmarks:
3999 if b not in remotebookmarks:
4000 raise error.Abort(_('remote bookmark %s not found!') % b)
4000 raise error.Abort(_('remote bookmark %s not found!') % b)
4001 revs.append(remotebookmarks[b])
4001 revs.append(remotebookmarks[b])
4002
4002
4003 if revs:
4003 if revs:
4004 try:
4004 try:
4005 # When 'rev' is a bookmark name, we cannot guarantee that it
4005 # When 'rev' is a bookmark name, we cannot guarantee that it
4006 # will be updated with that name because of a race condition
4006 # will be updated with that name because of a race condition
4007 # server side. (See issue 4689 for details)
4007 # server side. (See issue 4689 for details)
4008 oldrevs = revs
4008 oldrevs = revs
4009 revs = [] # actually, nodes
4009 revs = [] # actually, nodes
4010 for r in oldrevs:
4010 for r in oldrevs:
4011 node = other.lookup(r)
4011 node = other.lookup(r)
4012 revs.append(node)
4012 revs.append(node)
4013 if r == checkout:
4013 if r == checkout:
4014 checkout = node
4014 checkout = node
4015 except error.CapabilityError:
4015 except error.CapabilityError:
4016 err = _("other repository doesn't support revision lookup, "
4016 err = _("other repository doesn't support revision lookup, "
4017 "so a rev cannot be specified.")
4017 "so a rev cannot be specified.")
4018 raise error.Abort(err)
4018 raise error.Abort(err)
4019
4019
4020 pullopargs.update(opts.get('opargs', {}))
4020 pullopargs.update(opts.get('opargs', {}))
4021 modheads = exchange.pull(repo, other, heads=revs,
4021 modheads = exchange.pull(repo, other, heads=revs,
4022 force=opts.get('force'),
4022 force=opts.get('force'),
4023 bookmarks=opts.get('bookmark', ()),
4023 bookmarks=opts.get('bookmark', ()),
4024 opargs=pullopargs).cgresult
4024 opargs=pullopargs).cgresult
4025
4025
4026 # brev is a name, which might be a bookmark to be activated at
4026 # brev is a name, which might be a bookmark to be activated at
4027 # the end of the update. In other words, it is an explicit
4027 # the end of the update. In other words, it is an explicit
4028 # destination of the update
4028 # destination of the update
4029 brev = None
4029 brev = None
4030
4030
4031 if checkout:
4031 if checkout:
4032 checkout = str(repo.changelog.rev(checkout))
4032 checkout = str(repo.changelog.rev(checkout))
4033
4033
4034 # order below depends on implementation of
4034 # order below depends on implementation of
4035 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4035 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4036 # because 'checkout' is determined without it.
4036 # because 'checkout' is determined without it.
4037 if opts.get('rev'):
4037 if opts.get('rev'):
4038 brev = opts['rev'][0]
4038 brev = opts['rev'][0]
4039 elif opts.get('branch'):
4039 elif opts.get('branch'):
4040 brev = opts['branch'][0]
4040 brev = opts['branch'][0]
4041 else:
4041 else:
4042 brev = branches[0]
4042 brev = branches[0]
4043 repo._subtoppath = source
4043 repo._subtoppath = source
4044 try:
4044 try:
4045 ret = postincoming(ui, repo, modheads, opts.get('update'),
4045 ret = postincoming(ui, repo, modheads, opts.get('update'),
4046 checkout, brev)
4046 checkout, brev)
4047
4047
4048 finally:
4048 finally:
4049 del repo._subtoppath
4049 del repo._subtoppath
4050
4050
4051 finally:
4051 finally:
4052 other.close()
4052 other.close()
4053 return ret
4053 return ret
4054
4054
4055 @command('^push',
4055 @command('^push',
4056 [('f', 'force', None, _('force push')),
4056 [('f', 'force', None, _('force push')),
4057 ('r', 'rev', [],
4057 ('r', 'rev', [],
4058 _('a changeset intended to be included in the destination'),
4058 _('a changeset intended to be included in the destination'),
4059 _('REV')),
4059 _('REV')),
4060 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4060 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4061 ('b', 'branch', [],
4061 ('b', 'branch', [],
4062 _('a specific branch you would like to push'), _('BRANCH')),
4062 _('a specific branch you would like to push'), _('BRANCH')),
4063 ('', 'new-branch', False, _('allow pushing a new branch')),
4063 ('', 'new-branch', False, _('allow pushing a new branch')),
4064 ] + remoteopts,
4064 ] + remoteopts,
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4066 def push(ui, repo, dest=None, **opts):
4066 def push(ui, repo, dest=None, **opts):
4067 """push changes to the specified destination
4067 """push changes to the specified destination
4068
4068
4069 Push changesets from the local repository to the specified
4069 Push changesets from the local repository to the specified
4070 destination.
4070 destination.
4071
4071
4072 This operation is symmetrical to pull: it is identical to a pull
4072 This operation is symmetrical to pull: it is identical to a pull
4073 in the destination repository from the current one.
4073 in the destination repository from the current one.
4074
4074
4075 By default, push will not allow creation of new heads at the
4075 By default, push will not allow creation of new heads at the
4076 destination, since multiple heads would make it unclear which head
4076 destination, since multiple heads would make it unclear which head
4077 to use. In this situation, it is recommended to pull and merge
4077 to use. In this situation, it is recommended to pull and merge
4078 before pushing.
4078 before pushing.
4079
4079
4080 Use --new-branch if you want to allow push to create a new named
4080 Use --new-branch if you want to allow push to create a new named
4081 branch that is not present at the destination. This allows you to
4081 branch that is not present at the destination. This allows you to
4082 only create a new branch without forcing other changes.
4082 only create a new branch without forcing other changes.
4083
4083
4084 .. note::
4084 .. note::
4085
4085
4086 Extra care should be taken with the -f/--force option,
4086 Extra care should be taken with the -f/--force option,
4087 which will push all new heads on all branches, an action which will
4087 which will push all new heads on all branches, an action which will
4088 almost always cause confusion for collaborators.
4088 almost always cause confusion for collaborators.
4089
4089
4090 If -r/--rev is used, the specified revision and all its ancestors
4090 If -r/--rev is used, the specified revision and all its ancestors
4091 will be pushed to the remote repository.
4091 will be pushed to the remote repository.
4092
4092
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4094 ancestors, and the bookmark will be pushed to the remote
4094 ancestors, and the bookmark will be pushed to the remote
4095 repository. Specifying ``.`` is equivalent to specifying the active
4095 repository. Specifying ``.`` is equivalent to specifying the active
4096 bookmark's name.
4096 bookmark's name.
4097
4097
4098 Please see :hg:`help urls` for important details about ``ssh://``
4098 Please see :hg:`help urls` for important details about ``ssh://``
4099 URLs. If DESTINATION is omitted, a default path will be used.
4099 URLs. If DESTINATION is omitted, a default path will be used.
4100
4100
4101 Returns 0 if push was successful, 1 if nothing to push.
4101 Returns 0 if push was successful, 1 if nothing to push.
4102 """
4102 """
4103
4103
4104 opts = pycompat.byteskwargs(opts)
4104 opts = pycompat.byteskwargs(opts)
4105 if opts.get('bookmark'):
4105 if opts.get('bookmark'):
4106 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4106 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4107 for b in opts['bookmark']:
4107 for b in opts['bookmark']:
4108 # translate -B options to -r so changesets get pushed
4108 # translate -B options to -r so changesets get pushed
4109 b = repo._bookmarks.expandname(b)
4109 b = repo._bookmarks.expandname(b)
4110 if b in repo._bookmarks:
4110 if b in repo._bookmarks:
4111 opts.setdefault('rev', []).append(b)
4111 opts.setdefault('rev', []).append(b)
4112 else:
4112 else:
4113 # if we try to push a deleted bookmark, translate it to null
4113 # if we try to push a deleted bookmark, translate it to null
4114 # this lets simultaneous -r, -b options continue working
4114 # this lets simultaneous -r, -b options continue working
4115 opts.setdefault('rev', []).append("null")
4115 opts.setdefault('rev', []).append("null")
4116
4116
4117 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4117 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4118 if not path:
4118 if not path:
4119 raise error.Abort(_('default repository not configured!'),
4119 raise error.Abort(_('default repository not configured!'),
4120 hint=_("see 'hg help config.paths'"))
4120 hint=_("see 'hg help config.paths'"))
4121 dest = path.pushloc or path.loc
4121 dest = path.pushloc or path.loc
4122 branches = (path.branch, opts.get('branch') or [])
4122 branches = (path.branch, opts.get('branch') or [])
4123 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4123 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4124 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4124 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4125 other = hg.peer(repo, opts, dest)
4125 other = hg.peer(repo, opts, dest)
4126
4126
4127 if revs:
4127 if revs:
4128 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4128 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4129 if not revs:
4129 if not revs:
4130 raise error.Abort(_("specified revisions evaluate to an empty set"),
4130 raise error.Abort(_("specified revisions evaluate to an empty set"),
4131 hint=_("use different revision arguments"))
4131 hint=_("use different revision arguments"))
4132 elif path.pushrev:
4132 elif path.pushrev:
4133 # It doesn't make any sense to specify ancestor revisions. So limit
4133 # It doesn't make any sense to specify ancestor revisions. So limit
4134 # to DAG heads to make discovery simpler.
4134 # to DAG heads to make discovery simpler.
4135 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4135 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4136 revs = scmutil.revrange(repo, [expr])
4136 revs = scmutil.revrange(repo, [expr])
4137 revs = [repo[rev].node() for rev in revs]
4137 revs = [repo[rev].node() for rev in revs]
4138 if not revs:
4138 if not revs:
4139 raise error.Abort(_('default push revset for path evaluates to an '
4139 raise error.Abort(_('default push revset for path evaluates to an '
4140 'empty set'))
4140 'empty set'))
4141
4141
4142 repo._subtoppath = dest
4142 repo._subtoppath = dest
4143 try:
4143 try:
4144 # push subrepos depth-first for coherent ordering
4144 # push subrepos depth-first for coherent ordering
4145 c = repo['']
4145 c = repo['']
4146 subs = c.substate # only repos that are committed
4146 subs = c.substate # only repos that are committed
4147 for s in sorted(subs):
4147 for s in sorted(subs):
4148 result = c.sub(s).push(opts)
4148 result = c.sub(s).push(opts)
4149 if result == 0:
4149 if result == 0:
4150 return not result
4150 return not result
4151 finally:
4151 finally:
4152 del repo._subtoppath
4152 del repo._subtoppath
4153 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4153 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4154 newbranch=opts.get('new_branch'),
4154 newbranch=opts.get('new_branch'),
4155 bookmarks=opts.get('bookmark', ()),
4155 bookmarks=opts.get('bookmark', ()),
4156 opargs=opts.get('opargs'))
4156 opargs=opts.get('opargs'))
4157
4157
4158 result = not pushop.cgresult
4158 result = not pushop.cgresult
4159
4159
4160 if pushop.bkresult is not None:
4160 if pushop.bkresult is not None:
4161 if pushop.bkresult == 2:
4161 if pushop.bkresult == 2:
4162 result = 2
4162 result = 2
4163 elif not result and pushop.bkresult:
4163 elif not result and pushop.bkresult:
4164 result = 2
4164 result = 2
4165
4165
4166 return result
4166 return result
4167
4167
4168 @command('recover', [])
4168 @command('recover', [])
4169 def recover(ui, repo):
4169 def recover(ui, repo):
4170 """roll back an interrupted transaction
4170 """roll back an interrupted transaction
4171
4171
4172 Recover from an interrupted commit or pull.
4172 Recover from an interrupted commit or pull.
4173
4173
4174 This command tries to fix the repository status after an
4174 This command tries to fix the repository status after an
4175 interrupted operation. It should only be necessary when Mercurial
4175 interrupted operation. It should only be necessary when Mercurial
4176 suggests it.
4176 suggests it.
4177
4177
4178 Returns 0 if successful, 1 if nothing to recover or verify fails.
4178 Returns 0 if successful, 1 if nothing to recover or verify fails.
4179 """
4179 """
4180 if repo.recover():
4180 if repo.recover():
4181 return hg.verify(repo)
4181 return hg.verify(repo)
4182 return 1
4182 return 1
4183
4183
4184 @command('^remove|rm',
4184 @command('^remove|rm',
4185 [('A', 'after', None, _('record delete for missing files')),
4185 [('A', 'after', None, _('record delete for missing files')),
4186 ('f', 'force', None,
4186 ('f', 'force', None,
4187 _('forget added files, delete modified files')),
4187 _('forget added files, delete modified files')),
4188 ] + subrepoopts + walkopts,
4188 ] + subrepoopts + walkopts,
4189 _('[OPTION]... FILE...'),
4189 _('[OPTION]... FILE...'),
4190 inferrepo=True)
4190 inferrepo=True)
4191 def remove(ui, repo, *pats, **opts):
4191 def remove(ui, repo, *pats, **opts):
4192 """remove the specified files on the next commit
4192 """remove the specified files on the next commit
4193
4193
4194 Schedule the indicated files for removal from the current branch.
4194 Schedule the indicated files for removal from the current branch.
4195
4195
4196 This command schedules the files to be removed at the next commit.
4196 This command schedules the files to be removed at the next commit.
4197 To undo a remove before that, see :hg:`revert`. To undo added
4197 To undo a remove before that, see :hg:`revert`. To undo added
4198 files, see :hg:`forget`.
4198 files, see :hg:`forget`.
4199
4199
4200 .. container:: verbose
4200 .. container:: verbose
4201
4201
4202 -A/--after can be used to remove only files that have already
4202 -A/--after can be used to remove only files that have already
4203 been deleted, -f/--force can be used to force deletion, and -Af
4203 been deleted, -f/--force can be used to force deletion, and -Af
4204 can be used to remove files from the next revision without
4204 can be used to remove files from the next revision without
4205 deleting them from the working directory.
4205 deleting them from the working directory.
4206
4206
4207 The following table details the behavior of remove for different
4207 The following table details the behavior of remove for different
4208 file states (columns) and option combinations (rows). The file
4208 file states (columns) and option combinations (rows). The file
4209 states are Added [A], Clean [C], Modified [M] and Missing [!]
4209 states are Added [A], Clean [C], Modified [M] and Missing [!]
4210 (as reported by :hg:`status`). The actions are Warn, Remove
4210 (as reported by :hg:`status`). The actions are Warn, Remove
4211 (from branch) and Delete (from disk):
4211 (from branch) and Delete (from disk):
4212
4212
4213 ========= == == == ==
4213 ========= == == == ==
4214 opt/state A C M !
4214 opt/state A C M !
4215 ========= == == == ==
4215 ========= == == == ==
4216 none W RD W R
4216 none W RD W R
4217 -f R RD RD R
4217 -f R RD RD R
4218 -A W W W R
4218 -A W W W R
4219 -Af R R R R
4219 -Af R R R R
4220 ========= == == == ==
4220 ========= == == == ==
4221
4221
4222 .. note::
4222 .. note::
4223
4223
4224 :hg:`remove` never deletes files in Added [A] state from the
4224 :hg:`remove` never deletes files in Added [A] state from the
4225 working directory, not even if ``--force`` is specified.
4225 working directory, not even if ``--force`` is specified.
4226
4226
4227 Returns 0 on success, 1 if any warnings encountered.
4227 Returns 0 on success, 1 if any warnings encountered.
4228 """
4228 """
4229
4229
4230 opts = pycompat.byteskwargs(opts)
4230 opts = pycompat.byteskwargs(opts)
4231 after, force = opts.get('after'), opts.get('force')
4231 after, force = opts.get('after'), opts.get('force')
4232 if not pats and not after:
4232 if not pats and not after:
4233 raise error.Abort(_('no files specified'))
4233 raise error.Abort(_('no files specified'))
4234
4234
4235 m = scmutil.match(repo[None], pats, opts)
4235 m = scmutil.match(repo[None], pats, opts)
4236 subrepos = opts.get('subrepos')
4236 subrepos = opts.get('subrepos')
4237 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4237 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4238
4238
4239 @command('rename|move|mv',
4239 @command('rename|move|mv',
4240 [('A', 'after', None, _('record a rename that has already occurred')),
4240 [('A', 'after', None, _('record a rename that has already occurred')),
4241 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4241 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4242 ] + walkopts + dryrunopts,
4242 ] + walkopts + dryrunopts,
4243 _('[OPTION]... SOURCE... DEST'))
4243 _('[OPTION]... SOURCE... DEST'))
4244 def rename(ui, repo, *pats, **opts):
4244 def rename(ui, repo, *pats, **opts):
4245 """rename files; equivalent of copy + remove
4245 """rename files; equivalent of copy + remove
4246
4246
4247 Mark dest as copies of sources; mark sources for deletion. If dest
4247 Mark dest as copies of sources; mark sources for deletion. If dest
4248 is a directory, copies are put in that directory. If dest is a
4248 is a directory, copies are put in that directory. If dest is a
4249 file, there can only be one source.
4249 file, there can only be one source.
4250
4250
4251 By default, this command copies the contents of files as they
4251 By default, this command copies the contents of files as they
4252 exist in the working directory. If invoked with -A/--after, the
4252 exist in the working directory. If invoked with -A/--after, the
4253 operation is recorded, but no copying is performed.
4253 operation is recorded, but no copying is performed.
4254
4254
4255 This command takes effect at the next commit. To undo a rename
4255 This command takes effect at the next commit. To undo a rename
4256 before that, see :hg:`revert`.
4256 before that, see :hg:`revert`.
4257
4257
4258 Returns 0 on success, 1 if errors are encountered.
4258 Returns 0 on success, 1 if errors are encountered.
4259 """
4259 """
4260 opts = pycompat.byteskwargs(opts)
4260 opts = pycompat.byteskwargs(opts)
4261 with repo.wlock(False):
4261 with repo.wlock(False):
4262 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4262 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4263
4263
4264 @command('resolve',
4264 @command('resolve',
4265 [('a', 'all', None, _('select all unresolved files')),
4265 [('a', 'all', None, _('select all unresolved files')),
4266 ('l', 'list', None, _('list state of files needing merge')),
4266 ('l', 'list', None, _('list state of files needing merge')),
4267 ('m', 'mark', None, _('mark files as resolved')),
4267 ('m', 'mark', None, _('mark files as resolved')),
4268 ('u', 'unmark', None, _('mark files as unresolved')),
4268 ('u', 'unmark', None, _('mark files as unresolved')),
4269 ('n', 'no-status', None, _('hide status prefix'))]
4269 ('n', 'no-status', None, _('hide status prefix'))]
4270 + mergetoolopts + walkopts + formatteropts,
4270 + mergetoolopts + walkopts + formatteropts,
4271 _('[OPTION]... [FILE]...'),
4271 _('[OPTION]... [FILE]...'),
4272 inferrepo=True)
4272 inferrepo=True)
4273 def resolve(ui, repo, *pats, **opts):
4273 def resolve(ui, repo, *pats, **opts):
4274 """redo merges or set/view the merge status of files
4274 """redo merges or set/view the merge status of files
4275
4275
4276 Merges with unresolved conflicts are often the result of
4276 Merges with unresolved conflicts are often the result of
4277 non-interactive merging using the ``internal:merge`` configuration
4277 non-interactive merging using the ``internal:merge`` configuration
4278 setting, or a command-line merge tool like ``diff3``. The resolve
4278 setting, or a command-line merge tool like ``diff3``. The resolve
4279 command is used to manage the files involved in a merge, after
4279 command is used to manage the files involved in a merge, after
4280 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4280 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4281 working directory must have two parents). See :hg:`help
4281 working directory must have two parents). See :hg:`help
4282 merge-tools` for information on configuring merge tools.
4282 merge-tools` for information on configuring merge tools.
4283
4283
4284 The resolve command can be used in the following ways:
4284 The resolve command can be used in the following ways:
4285
4285
4286 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4286 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4287 files, discarding any previous merge attempts. Re-merging is not
4287 files, discarding any previous merge attempts. Re-merging is not
4288 performed for files already marked as resolved. Use ``--all/-a``
4288 performed for files already marked as resolved. Use ``--all/-a``
4289 to select all unresolved files. ``--tool`` can be used to specify
4289 to select all unresolved files. ``--tool`` can be used to specify
4290 the merge tool used for the given files. It overrides the HGMERGE
4290 the merge tool used for the given files. It overrides the HGMERGE
4291 environment variable and your configuration files. Previous file
4291 environment variable and your configuration files. Previous file
4292 contents are saved with a ``.orig`` suffix.
4292 contents are saved with a ``.orig`` suffix.
4293
4293
4294 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4294 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4295 (e.g. after having manually fixed-up the files). The default is
4295 (e.g. after having manually fixed-up the files). The default is
4296 to mark all unresolved files.
4296 to mark all unresolved files.
4297
4297
4298 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4298 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4299 default is to mark all resolved files.
4299 default is to mark all resolved files.
4300
4300
4301 - :hg:`resolve -l`: list files which had or still have conflicts.
4301 - :hg:`resolve -l`: list files which had or still have conflicts.
4302 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4302 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4303 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4303 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4304 the list. See :hg:`help filesets` for details.
4304 the list. See :hg:`help filesets` for details.
4305
4305
4306 .. note::
4306 .. note::
4307
4307
4308 Mercurial will not let you commit files with unresolved merge
4308 Mercurial will not let you commit files with unresolved merge
4309 conflicts. You must use :hg:`resolve -m ...` before you can
4309 conflicts. You must use :hg:`resolve -m ...` before you can
4310 commit after a conflicting merge.
4310 commit after a conflicting merge.
4311
4311
4312 Returns 0 on success, 1 if any files fail a resolve attempt.
4312 Returns 0 on success, 1 if any files fail a resolve attempt.
4313 """
4313 """
4314
4314
4315 opts = pycompat.byteskwargs(opts)
4315 opts = pycompat.byteskwargs(opts)
4316 flaglist = 'all mark unmark list no_status'.split()
4316 flaglist = 'all mark unmark list no_status'.split()
4317 all, mark, unmark, show, nostatus = \
4317 all, mark, unmark, show, nostatus = \
4318 [opts.get(o) for o in flaglist]
4318 [opts.get(o) for o in flaglist]
4319
4319
4320 if (show and (mark or unmark)) or (mark and unmark):
4320 if (show and (mark or unmark)) or (mark and unmark):
4321 raise error.Abort(_("too many options specified"))
4321 raise error.Abort(_("too many options specified"))
4322 if pats and all:
4322 if pats and all:
4323 raise error.Abort(_("can't specify --all and patterns"))
4323 raise error.Abort(_("can't specify --all and patterns"))
4324 if not (all or pats or show or mark or unmark):
4324 if not (all or pats or show or mark or unmark):
4325 raise error.Abort(_('no files or directories specified'),
4325 raise error.Abort(_('no files or directories specified'),
4326 hint=('use --all to re-merge all unresolved files'))
4326 hint=('use --all to re-merge all unresolved files'))
4327
4327
4328 if show:
4328 if show:
4329 ui.pager('resolve')
4329 ui.pager('resolve')
4330 fm = ui.formatter('resolve', opts)
4330 fm = ui.formatter('resolve', opts)
4331 ms = mergemod.mergestate.read(repo)
4331 ms = mergemod.mergestate.read(repo)
4332 m = scmutil.match(repo[None], pats, opts)
4332 m = scmutil.match(repo[None], pats, opts)
4333 for f in ms:
4333 for f in ms:
4334 if not m(f):
4334 if not m(f):
4335 continue
4335 continue
4336 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4336 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4337 'd': 'driverresolved'}[ms[f]]
4337 'd': 'driverresolved'}[ms[f]]
4338 fm.startitem()
4338 fm.startitem()
4339 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4339 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4340 fm.write('path', '%s\n', f, label=l)
4340 fm.write('path', '%s\n', f, label=l)
4341 fm.end()
4341 fm.end()
4342 return 0
4342 return 0
4343
4343
4344 with repo.wlock():
4344 with repo.wlock():
4345 ms = mergemod.mergestate.read(repo)
4345 ms = mergemod.mergestate.read(repo)
4346
4346
4347 if not (ms.active() or repo.dirstate.p2() != nullid):
4347 if not (ms.active() or repo.dirstate.p2() != nullid):
4348 raise error.Abort(
4348 raise error.Abort(
4349 _('resolve command not applicable when not merging'))
4349 _('resolve command not applicable when not merging'))
4350
4350
4351 wctx = repo[None]
4351 wctx = repo[None]
4352
4352
4353 if ms.mergedriver and ms.mdstate() == 'u':
4353 if ms.mergedriver and ms.mdstate() == 'u':
4354 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4354 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4355 ms.commit()
4355 ms.commit()
4356 # allow mark and unmark to go through
4356 # allow mark and unmark to go through
4357 if not mark and not unmark and not proceed:
4357 if not mark and not unmark and not proceed:
4358 return 1
4358 return 1
4359
4359
4360 m = scmutil.match(wctx, pats, opts)
4360 m = scmutil.match(wctx, pats, opts)
4361 ret = 0
4361 ret = 0
4362 didwork = False
4362 didwork = False
4363 runconclude = False
4363 runconclude = False
4364
4364
4365 tocomplete = []
4365 tocomplete = []
4366 for f in ms:
4366 for f in ms:
4367 if not m(f):
4367 if not m(f):
4368 continue
4368 continue
4369
4369
4370 didwork = True
4370 didwork = True
4371
4371
4372 # don't let driver-resolved files be marked, and run the conclude
4372 # don't let driver-resolved files be marked, and run the conclude
4373 # step if asked to resolve
4373 # step if asked to resolve
4374 if ms[f] == "d":
4374 if ms[f] == "d":
4375 exact = m.exact(f)
4375 exact = m.exact(f)
4376 if mark:
4376 if mark:
4377 if exact:
4377 if exact:
4378 ui.warn(_('not marking %s as it is driver-resolved\n')
4378 ui.warn(_('not marking %s as it is driver-resolved\n')
4379 % f)
4379 % f)
4380 elif unmark:
4380 elif unmark:
4381 if exact:
4381 if exact:
4382 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4382 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4383 % f)
4383 % f)
4384 else:
4384 else:
4385 runconclude = True
4385 runconclude = True
4386 continue
4386 continue
4387
4387
4388 if mark:
4388 if mark:
4389 ms.mark(f, "r")
4389 ms.mark(f, "r")
4390 elif unmark:
4390 elif unmark:
4391 ms.mark(f, "u")
4391 ms.mark(f, "u")
4392 else:
4392 else:
4393 # backup pre-resolve (merge uses .orig for its own purposes)
4393 # backup pre-resolve (merge uses .orig for its own purposes)
4394 a = repo.wjoin(f)
4394 a = repo.wjoin(f)
4395 try:
4395 try:
4396 util.copyfile(a, a + ".resolve")
4396 util.copyfile(a, a + ".resolve")
4397 except (IOError, OSError) as inst:
4397 except (IOError, OSError) as inst:
4398 if inst.errno != errno.ENOENT:
4398 if inst.errno != errno.ENOENT:
4399 raise
4399 raise
4400
4400
4401 try:
4401 try:
4402 # preresolve file
4402 # preresolve file
4403 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4403 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4404 'resolve')
4404 'resolve')
4405 complete, r = ms.preresolve(f, wctx)
4405 complete, r = ms.preresolve(f, wctx)
4406 if not complete:
4406 if not complete:
4407 tocomplete.append(f)
4407 tocomplete.append(f)
4408 elif r:
4408 elif r:
4409 ret = 1
4409 ret = 1
4410 finally:
4410 finally:
4411 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4411 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4412 ms.commit()
4412 ms.commit()
4413
4413
4414 # replace filemerge's .orig file with our resolve file, but only
4414 # replace filemerge's .orig file with our resolve file, but only
4415 # for merges that are complete
4415 # for merges that are complete
4416 if complete:
4416 if complete:
4417 try:
4417 try:
4418 util.rename(a + ".resolve",
4418 util.rename(a + ".resolve",
4419 scmutil.origpath(ui, repo, a))
4419 scmutil.origpath(ui, repo, a))
4420 except OSError as inst:
4420 except OSError as inst:
4421 if inst.errno != errno.ENOENT:
4421 if inst.errno != errno.ENOENT:
4422 raise
4422 raise
4423
4423
4424 for f in tocomplete:
4424 for f in tocomplete:
4425 try:
4425 try:
4426 # resolve file
4426 # resolve file
4427 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4427 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4428 'resolve')
4428 'resolve')
4429 r = ms.resolve(f, wctx)
4429 r = ms.resolve(f, wctx)
4430 if r:
4430 if r:
4431 ret = 1
4431 ret = 1
4432 finally:
4432 finally:
4433 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4433 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4434 ms.commit()
4434 ms.commit()
4435
4435
4436 # replace filemerge's .orig file with our resolve file
4436 # replace filemerge's .orig file with our resolve file
4437 a = repo.wjoin(f)
4437 a = repo.wjoin(f)
4438 try:
4438 try:
4439 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4439 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4440 except OSError as inst:
4440 except OSError as inst:
4441 if inst.errno != errno.ENOENT:
4441 if inst.errno != errno.ENOENT:
4442 raise
4442 raise
4443
4443
4444 ms.commit()
4444 ms.commit()
4445 ms.recordactions()
4445 ms.recordactions()
4446
4446
4447 if not didwork and pats:
4447 if not didwork and pats:
4448 hint = None
4448 hint = None
4449 if not any([p for p in pats if p.find(':') >= 0]):
4449 if not any([p for p in pats if p.find(':') >= 0]):
4450 pats = ['path:%s' % p for p in pats]
4450 pats = ['path:%s' % p for p in pats]
4451 m = scmutil.match(wctx, pats, opts)
4451 m = scmutil.match(wctx, pats, opts)
4452 for f in ms:
4452 for f in ms:
4453 if not m(f):
4453 if not m(f):
4454 continue
4454 continue
4455 flags = ''.join(['-%s ' % o[0] for o in flaglist
4455 flags = ''.join(['-%s ' % o[0] for o in flaglist
4456 if opts.get(o)])
4456 if opts.get(o)])
4457 hint = _("(try: hg resolve %s%s)\n") % (
4457 hint = _("(try: hg resolve %s%s)\n") % (
4458 flags,
4458 flags,
4459 ' '.join(pats))
4459 ' '.join(pats))
4460 break
4460 break
4461 ui.warn(_("arguments do not match paths that need resolving\n"))
4461 ui.warn(_("arguments do not match paths that need resolving\n"))
4462 if hint:
4462 if hint:
4463 ui.warn(hint)
4463 ui.warn(hint)
4464 elif ms.mergedriver and ms.mdstate() != 's':
4464 elif ms.mergedriver and ms.mdstate() != 's':
4465 # run conclude step when either a driver-resolved file is requested
4465 # run conclude step when either a driver-resolved file is requested
4466 # or there are no driver-resolved files
4466 # or there are no driver-resolved files
4467 # we can't use 'ret' to determine whether any files are unresolved
4467 # we can't use 'ret' to determine whether any files are unresolved
4468 # because we might not have tried to resolve some
4468 # because we might not have tried to resolve some
4469 if ((runconclude or not list(ms.driverresolved()))
4469 if ((runconclude or not list(ms.driverresolved()))
4470 and not list(ms.unresolved())):
4470 and not list(ms.unresolved())):
4471 proceed = mergemod.driverconclude(repo, ms, wctx)
4471 proceed = mergemod.driverconclude(repo, ms, wctx)
4472 ms.commit()
4472 ms.commit()
4473 if not proceed:
4473 if not proceed:
4474 return 1
4474 return 1
4475
4475
4476 # Nudge users into finishing an unfinished operation
4476 # Nudge users into finishing an unfinished operation
4477 unresolvedf = list(ms.unresolved())
4477 unresolvedf = list(ms.unresolved())
4478 driverresolvedf = list(ms.driverresolved())
4478 driverresolvedf = list(ms.driverresolved())
4479 if not unresolvedf and not driverresolvedf:
4479 if not unresolvedf and not driverresolvedf:
4480 ui.status(_('(no more unresolved files)\n'))
4480 ui.status(_('(no more unresolved files)\n'))
4481 cmdutil.checkafterresolved(repo)
4481 cmdutil.checkafterresolved(repo)
4482 elif not unresolvedf:
4482 elif not unresolvedf:
4483 ui.status(_('(no more unresolved files -- '
4483 ui.status(_('(no more unresolved files -- '
4484 'run "hg resolve --all" to conclude)\n'))
4484 'run "hg resolve --all" to conclude)\n'))
4485
4485
4486 return ret
4486 return ret
4487
4487
4488 @command('revert',
4488 @command('revert',
4489 [('a', 'all', None, _('revert all changes when no arguments given')),
4489 [('a', 'all', None, _('revert all changes when no arguments given')),
4490 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4490 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4491 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4491 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4492 ('C', 'no-backup', None, _('do not save backup copies of files')),
4492 ('C', 'no-backup', None, _('do not save backup copies of files')),
4493 ('i', 'interactive', None,
4493 ('i', 'interactive', None,
4494 _('interactively select the changes (EXPERIMENTAL)')),
4494 _('interactively select the changes (EXPERIMENTAL)')),
4495 ] + walkopts + dryrunopts,
4495 ] + walkopts + dryrunopts,
4496 _('[OPTION]... [-r REV] [NAME]...'))
4496 _('[OPTION]... [-r REV] [NAME]...'))
4497 def revert(ui, repo, *pats, **opts):
4497 def revert(ui, repo, *pats, **opts):
4498 """restore files to their checkout state
4498 """restore files to their checkout state
4499
4499
4500 .. note::
4500 .. note::
4501
4501
4502 To check out earlier revisions, you should use :hg:`update REV`.
4502 To check out earlier revisions, you should use :hg:`update REV`.
4503 To cancel an uncommitted merge (and lose your changes),
4503 To cancel an uncommitted merge (and lose your changes),
4504 use :hg:`update --clean .`.
4504 use :hg:`update --clean .`.
4505
4505
4506 With no revision specified, revert the specified files or directories
4506 With no revision specified, revert the specified files or directories
4507 to the contents they had in the parent of the working directory.
4507 to the contents they had in the parent of the working directory.
4508 This restores the contents of files to an unmodified
4508 This restores the contents of files to an unmodified
4509 state and unschedules adds, removes, copies, and renames. If the
4509 state and unschedules adds, removes, copies, and renames. If the
4510 working directory has two parents, you must explicitly specify a
4510 working directory has two parents, you must explicitly specify a
4511 revision.
4511 revision.
4512
4512
4513 Using the -r/--rev or -d/--date options, revert the given files or
4513 Using the -r/--rev or -d/--date options, revert the given files or
4514 directories to their states as of a specific revision. Because
4514 directories to their states as of a specific revision. Because
4515 revert does not change the working directory parents, this will
4515 revert does not change the working directory parents, this will
4516 cause these files to appear modified. This can be helpful to "back
4516 cause these files to appear modified. This can be helpful to "back
4517 out" some or all of an earlier change. See :hg:`backout` for a
4517 out" some or all of an earlier change. See :hg:`backout` for a
4518 related method.
4518 related method.
4519
4519
4520 Modified files are saved with a .orig suffix before reverting.
4520 Modified files are saved with a .orig suffix before reverting.
4521 To disable these backups, use --no-backup. It is possible to store
4521 To disable these backups, use --no-backup. It is possible to store
4522 the backup files in a custom directory relative to the root of the
4522 the backup files in a custom directory relative to the root of the
4523 repository by setting the ``ui.origbackuppath`` configuration
4523 repository by setting the ``ui.origbackuppath`` configuration
4524 option.
4524 option.
4525
4525
4526 See :hg:`help dates` for a list of formats valid for -d/--date.
4526 See :hg:`help dates` for a list of formats valid for -d/--date.
4527
4527
4528 See :hg:`help backout` for a way to reverse the effect of an
4528 See :hg:`help backout` for a way to reverse the effect of an
4529 earlier changeset.
4529 earlier changeset.
4530
4530
4531 Returns 0 on success.
4531 Returns 0 on success.
4532 """
4532 """
4533
4533
4534 if opts.get("date"):
4534 if opts.get("date"):
4535 if opts.get("rev"):
4535 if opts.get("rev"):
4536 raise error.Abort(_("you can't specify a revision and a date"))
4536 raise error.Abort(_("you can't specify a revision and a date"))
4537 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4537 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4538
4538
4539 parent, p2 = repo.dirstate.parents()
4539 parent, p2 = repo.dirstate.parents()
4540 if not opts.get('rev') and p2 != nullid:
4540 if not opts.get('rev') and p2 != nullid:
4541 # revert after merge is a trap for new users (issue2915)
4541 # revert after merge is a trap for new users (issue2915)
4542 raise error.Abort(_('uncommitted merge with no revision specified'),
4542 raise error.Abort(_('uncommitted merge with no revision specified'),
4543 hint=_("use 'hg update' or see 'hg help revert'"))
4543 hint=_("use 'hg update' or see 'hg help revert'"))
4544
4544
4545 ctx = scmutil.revsingle(repo, opts.get('rev'))
4545 ctx = scmutil.revsingle(repo, opts.get('rev'))
4546
4546
4547 if (not (pats or opts.get('include') or opts.get('exclude') or
4547 if (not (pats or opts.get('include') or opts.get('exclude') or
4548 opts.get('all') or opts.get('interactive'))):
4548 opts.get('all') or opts.get('interactive'))):
4549 msg = _("no files or directories specified")
4549 msg = _("no files or directories specified")
4550 if p2 != nullid:
4550 if p2 != nullid:
4551 hint = _("uncommitted merge, use --all to discard all changes,"
4551 hint = _("uncommitted merge, use --all to discard all changes,"
4552 " or 'hg update -C .' to abort the merge")
4552 " or 'hg update -C .' to abort the merge")
4553 raise error.Abort(msg, hint=hint)
4553 raise error.Abort(msg, hint=hint)
4554 dirty = any(repo.status())
4554 dirty = any(repo.status())
4555 node = ctx.node()
4555 node = ctx.node()
4556 if node != parent:
4556 if node != parent:
4557 if dirty:
4557 if dirty:
4558 hint = _("uncommitted changes, use --all to discard all"
4558 hint = _("uncommitted changes, use --all to discard all"
4559 " changes, or 'hg update %s' to update") % ctx.rev()
4559 " changes, or 'hg update %s' to update") % ctx.rev()
4560 else:
4560 else:
4561 hint = _("use --all to revert all files,"
4561 hint = _("use --all to revert all files,"
4562 " or 'hg update %s' to update") % ctx.rev()
4562 " or 'hg update %s' to update") % ctx.rev()
4563 elif dirty:
4563 elif dirty:
4564 hint = _("uncommitted changes, use --all to discard all changes")
4564 hint = _("uncommitted changes, use --all to discard all changes")
4565 else:
4565 else:
4566 hint = _("use --all to revert all files")
4566 hint = _("use --all to revert all files")
4567 raise error.Abort(msg, hint=hint)
4567 raise error.Abort(msg, hint=hint)
4568
4568
4569 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4569 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4570
4570
4571 @command('rollback', dryrunopts +
4571 @command('rollback', dryrunopts +
4572 [('f', 'force', False, _('ignore safety measures'))])
4572 [('f', 'force', False, _('ignore safety measures'))])
4573 def rollback(ui, repo, **opts):
4573 def rollback(ui, repo, **opts):
4574 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4574 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4575
4575
4576 Please use :hg:`commit --amend` instead of rollback to correct
4576 Please use :hg:`commit --amend` instead of rollback to correct
4577 mistakes in the last commit.
4577 mistakes in the last commit.
4578
4578
4579 This command should be used with care. There is only one level of
4579 This command should be used with care. There is only one level of
4580 rollback, and there is no way to undo a rollback. It will also
4580 rollback, and there is no way to undo a rollback. It will also
4581 restore the dirstate at the time of the last transaction, losing
4581 restore the dirstate at the time of the last transaction, losing
4582 any dirstate changes since that time. This command does not alter
4582 any dirstate changes since that time. This command does not alter
4583 the working directory.
4583 the working directory.
4584
4584
4585 Transactions are used to encapsulate the effects of all commands
4585 Transactions are used to encapsulate the effects of all commands
4586 that create new changesets or propagate existing changesets into a
4586 that create new changesets or propagate existing changesets into a
4587 repository.
4587 repository.
4588
4588
4589 .. container:: verbose
4589 .. container:: verbose
4590
4590
4591 For example, the following commands are transactional, and their
4591 For example, the following commands are transactional, and their
4592 effects can be rolled back:
4592 effects can be rolled back:
4593
4593
4594 - commit
4594 - commit
4595 - import
4595 - import
4596 - pull
4596 - pull
4597 - push (with this repository as the destination)
4597 - push (with this repository as the destination)
4598 - unbundle
4598 - unbundle
4599
4599
4600 To avoid permanent data loss, rollback will refuse to rollback a
4600 To avoid permanent data loss, rollback will refuse to rollback a
4601 commit transaction if it isn't checked out. Use --force to
4601 commit transaction if it isn't checked out. Use --force to
4602 override this protection.
4602 override this protection.
4603
4603
4604 The rollback command can be entirely disabled by setting the
4604 The rollback command can be entirely disabled by setting the
4605 ``ui.rollback`` configuration setting to false. If you're here
4605 ``ui.rollback`` configuration setting to false. If you're here
4606 because you want to use rollback and it's disabled, you can
4606 because you want to use rollback and it's disabled, you can
4607 re-enable the command by setting ``ui.rollback`` to true.
4607 re-enable the command by setting ``ui.rollback`` to true.
4608
4608
4609 This command is not intended for use on public repositories. Once
4609 This command is not intended for use on public repositories. Once
4610 changes are visible for pull by other users, rolling a transaction
4610 changes are visible for pull by other users, rolling a transaction
4611 back locally is ineffective (someone else may already have pulled
4611 back locally is ineffective (someone else may already have pulled
4612 the changes). Furthermore, a race is possible with readers of the
4612 the changes). Furthermore, a race is possible with readers of the
4613 repository; for example an in-progress pull from the repository
4613 repository; for example an in-progress pull from the repository
4614 may fail if a rollback is performed.
4614 may fail if a rollback is performed.
4615
4615
4616 Returns 0 on success, 1 if no rollback data is available.
4616 Returns 0 on success, 1 if no rollback data is available.
4617 """
4617 """
4618 if not ui.configbool('ui', 'rollback', True):
4618 if not ui.configbool('ui', 'rollback', True):
4619 raise error.Abort(_('rollback is disabled because it is unsafe'),
4619 raise error.Abort(_('rollback is disabled because it is unsafe'),
4620 hint=('see `hg help -v rollback` for information'))
4620 hint=('see `hg help -v rollback` for information'))
4621 return repo.rollback(dryrun=opts.get('dry_run'),
4621 return repo.rollback(dryrun=opts.get('dry_run'),
4622 force=opts.get('force'))
4622 force=opts.get('force'))
4623
4623
4624 @command('root', [])
4624 @command('root', [])
4625 def root(ui, repo):
4625 def root(ui, repo):
4626 """print the root (top) of the current working directory
4626 """print the root (top) of the current working directory
4627
4627
4628 Print the root directory of the current repository.
4628 Print the root directory of the current repository.
4629
4629
4630 Returns 0 on success.
4630 Returns 0 on success.
4631 """
4631 """
4632 ui.write(repo.root + "\n")
4632 ui.write(repo.root + "\n")
4633
4633
4634 @command('^serve',
4634 @command('^serve',
4635 [('A', 'accesslog', '', _('name of access log file to write to'),
4635 [('A', 'accesslog', '', _('name of access log file to write to'),
4636 _('FILE')),
4636 _('FILE')),
4637 ('d', 'daemon', None, _('run server in background')),
4637 ('d', 'daemon', None, _('run server in background')),
4638 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4638 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4639 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4639 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4640 # use string type, then we can check if something was passed
4640 # use string type, then we can check if something was passed
4641 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4641 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4642 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4642 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4643 _('ADDR')),
4643 _('ADDR')),
4644 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4644 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4645 _('PREFIX')),
4645 _('PREFIX')),
4646 ('n', 'name', '',
4646 ('n', 'name', '',
4647 _('name to show in web pages (default: working directory)'), _('NAME')),
4647 _('name to show in web pages (default: working directory)'), _('NAME')),
4648 ('', 'web-conf', '',
4648 ('', 'web-conf', '',
4649 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4649 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4650 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4650 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4651 _('FILE')),
4651 _('FILE')),
4652 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4652 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4653 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4653 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4654 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4654 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4655 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4655 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4656 ('', 'style', '', _('template style to use'), _('STYLE')),
4656 ('', 'style', '', _('template style to use'), _('STYLE')),
4657 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4657 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4658 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4658 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4659 + subrepoopts,
4659 + subrepoopts,
4660 _('[OPTION]...'),
4660 _('[OPTION]...'),
4661 optionalrepo=True)
4661 optionalrepo=True)
4662 def serve(ui, repo, **opts):
4662 def serve(ui, repo, **opts):
4663 """start stand-alone webserver
4663 """start stand-alone webserver
4664
4664
4665 Start a local HTTP repository browser and pull server. You can use
4665 Start a local HTTP repository browser and pull server. You can use
4666 this for ad-hoc sharing and browsing of repositories. It is
4666 this for ad-hoc sharing and browsing of repositories. It is
4667 recommended to use a real web server to serve a repository for
4667 recommended to use a real web server to serve a repository for
4668 longer periods of time.
4668 longer periods of time.
4669
4669
4670 Please note that the server does not implement access control.
4670 Please note that the server does not implement access control.
4671 This means that, by default, anybody can read from the server and
4671 This means that, by default, anybody can read from the server and
4672 nobody can write to it by default. Set the ``web.allow_push``
4672 nobody can write to it by default. Set the ``web.allow_push``
4673 option to ``*`` to allow everybody to push to the server. You
4673 option to ``*`` to allow everybody to push to the server. You
4674 should use a real web server if you need to authenticate users.
4674 should use a real web server if you need to authenticate users.
4675
4675
4676 By default, the server logs accesses to stdout and errors to
4676 By default, the server logs accesses to stdout and errors to
4677 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4677 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4678 files.
4678 files.
4679
4679
4680 To have the server choose a free port number to listen on, specify
4680 To have the server choose a free port number to listen on, specify
4681 a port number of 0; in this case, the server will print the port
4681 a port number of 0; in this case, the server will print the port
4682 number it uses.
4682 number it uses.
4683
4683
4684 Returns 0 on success.
4684 Returns 0 on success.
4685 """
4685 """
4686
4686
4687 opts = pycompat.byteskwargs(opts)
4687 opts = pycompat.byteskwargs(opts)
4688 if opts["stdio"] and opts["cmdserver"]:
4688 if opts["stdio"] and opts["cmdserver"]:
4689 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4689 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4690
4690
4691 if opts["stdio"]:
4691 if opts["stdio"]:
4692 if repo is None:
4692 if repo is None:
4693 raise error.RepoError(_("there is no Mercurial repository here"
4693 raise error.RepoError(_("there is no Mercurial repository here"
4694 " (.hg not found)"))
4694 " (.hg not found)"))
4695 s = sshserver.sshserver(ui, repo)
4695 s = sshserver.sshserver(ui, repo)
4696 s.serve_forever()
4696 s.serve_forever()
4697
4697
4698 service = server.createservice(ui, repo, opts)
4698 service = server.createservice(ui, repo, opts)
4699 return server.runservice(opts, initfn=service.init, runfn=service.run)
4699 return server.runservice(opts, initfn=service.init, runfn=service.run)
4700
4700
4701 @command('^status|st',
4701 @command('^status|st',
4702 [('A', 'all', None, _('show status of all files')),
4702 [('A', 'all', None, _('show status of all files')),
4703 ('m', 'modified', None, _('show only modified files')),
4703 ('m', 'modified', None, _('show only modified files')),
4704 ('a', 'added', None, _('show only added files')),
4704 ('a', 'added', None, _('show only added files')),
4705 ('r', 'removed', None, _('show only removed files')),
4705 ('r', 'removed', None, _('show only removed files')),
4706 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4706 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4707 ('c', 'clean', None, _('show only files without changes')),
4707 ('c', 'clean', None, _('show only files without changes')),
4708 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4708 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4709 ('i', 'ignored', None, _('show only ignored files')),
4709 ('i', 'ignored', None, _('show only ignored files')),
4710 ('n', 'no-status', None, _('hide status prefix')),
4710 ('n', 'no-status', None, _('hide status prefix')),
4711 ('C', 'copies', None, _('show source of copied files')),
4711 ('C', 'copies', None, _('show source of copied files')),
4712 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4712 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4713 ('', 'rev', [], _('show difference from revision'), _('REV')),
4713 ('', 'rev', [], _('show difference from revision'), _('REV')),
4714 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4714 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4715 ] + walkopts + subrepoopts + formatteropts,
4715 ] + walkopts + subrepoopts + formatteropts,
4716 _('[OPTION]... [FILE]...'),
4716 _('[OPTION]... [FILE]...'),
4717 inferrepo=True)
4717 inferrepo=True)
4718 def status(ui, repo, *pats, **opts):
4718 def status(ui, repo, *pats, **opts):
4719 """show changed files in the working directory
4719 """show changed files in the working directory
4720
4720
4721 Show status of files in the repository. If names are given, only
4721 Show status of files in the repository. If names are given, only
4722 files that match are shown. Files that are clean or ignored or
4722 files that match are shown. Files that are clean or ignored or
4723 the source of a copy/move operation, are not listed unless
4723 the source of a copy/move operation, are not listed unless
4724 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4724 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4725 Unless options described with "show only ..." are given, the
4725 Unless options described with "show only ..." are given, the
4726 options -mardu are used.
4726 options -mardu are used.
4727
4727
4728 Option -q/--quiet hides untracked (unknown and ignored) files
4728 Option -q/--quiet hides untracked (unknown and ignored) files
4729 unless explicitly requested with -u/--unknown or -i/--ignored.
4729 unless explicitly requested with -u/--unknown or -i/--ignored.
4730
4730
4731 .. note::
4731 .. note::
4732
4732
4733 :hg:`status` may appear to disagree with diff if permissions have
4733 :hg:`status` may appear to disagree with diff if permissions have
4734 changed or a merge has occurred. The standard diff format does
4734 changed or a merge has occurred. The standard diff format does
4735 not report permission changes and diff only reports changes
4735 not report permission changes and diff only reports changes
4736 relative to one merge parent.
4736 relative to one merge parent.
4737
4737
4738 If one revision is given, it is used as the base revision.
4738 If one revision is given, it is used as the base revision.
4739 If two revisions are given, the differences between them are
4739 If two revisions are given, the differences between them are
4740 shown. The --change option can also be used as a shortcut to list
4740 shown. The --change option can also be used as a shortcut to list
4741 the changed files of a revision from its first parent.
4741 the changed files of a revision from its first parent.
4742
4742
4743 The codes used to show the status of files are::
4743 The codes used to show the status of files are::
4744
4744
4745 M = modified
4745 M = modified
4746 A = added
4746 A = added
4747 R = removed
4747 R = removed
4748 C = clean
4748 C = clean
4749 ! = missing (deleted by non-hg command, but still tracked)
4749 ! = missing (deleted by non-hg command, but still tracked)
4750 ? = not tracked
4750 ? = not tracked
4751 I = ignored
4751 I = ignored
4752 = origin of the previous file (with --copies)
4752 = origin of the previous file (with --copies)
4753
4753
4754 .. container:: verbose
4754 .. container:: verbose
4755
4755
4756 Examples:
4756 Examples:
4757
4757
4758 - show changes in the working directory relative to a
4758 - show changes in the working directory relative to a
4759 changeset::
4759 changeset::
4760
4760
4761 hg status --rev 9353
4761 hg status --rev 9353
4762
4762
4763 - show changes in the working directory relative to the
4763 - show changes in the working directory relative to the
4764 current directory (see :hg:`help patterns` for more information)::
4764 current directory (see :hg:`help patterns` for more information)::
4765
4765
4766 hg status re:
4766 hg status re:
4767
4767
4768 - show all changes including copies in an existing changeset::
4768 - show all changes including copies in an existing changeset::
4769
4769
4770 hg status --copies --change 9353
4770 hg status --copies --change 9353
4771
4771
4772 - get a NUL separated list of added files, suitable for xargs::
4772 - get a NUL separated list of added files, suitable for xargs::
4773
4773
4774 hg status -an0
4774 hg status -an0
4775
4775
4776 Returns 0 on success.
4776 Returns 0 on success.
4777 """
4777 """
4778
4778
4779 opts = pycompat.byteskwargs(opts)
4779 opts = pycompat.byteskwargs(opts)
4780 revs = opts.get('rev')
4780 revs = opts.get('rev')
4781 change = opts.get('change')
4781 change = opts.get('change')
4782
4782
4783 if revs and change:
4783 if revs and change:
4784 msg = _('cannot specify --rev and --change at the same time')
4784 msg = _('cannot specify --rev and --change at the same time')
4785 raise error.Abort(msg)
4785 raise error.Abort(msg)
4786 elif change:
4786 elif change:
4787 node2 = scmutil.revsingle(repo, change, None).node()
4787 node2 = scmutil.revsingle(repo, change, None).node()
4788 node1 = repo[node2].p1().node()
4788 node1 = repo[node2].p1().node()
4789 else:
4789 else:
4790 node1, node2 = scmutil.revpair(repo, revs)
4790 node1, node2 = scmutil.revpair(repo, revs)
4791
4791
4792 if pats or ui.configbool('commands', 'status.relative'):
4792 if pats or ui.configbool('commands', 'status.relative'):
4793 cwd = repo.getcwd()
4793 cwd = repo.getcwd()
4794 else:
4794 else:
4795 cwd = ''
4795 cwd = ''
4796
4796
4797 if opts.get('print0'):
4797 if opts.get('print0'):
4798 end = '\0'
4798 end = '\0'
4799 else:
4799 else:
4800 end = '\n'
4800 end = '\n'
4801 copy = {}
4801 copy = {}
4802 states = 'modified added removed deleted unknown ignored clean'.split()
4802 states = 'modified added removed deleted unknown ignored clean'.split()
4803 show = [k for k in states if opts.get(k)]
4803 show = [k for k in states if opts.get(k)]
4804 if opts.get('all'):
4804 if opts.get('all'):
4805 show += ui.quiet and (states[:4] + ['clean']) or states
4805 show += ui.quiet and (states[:4] + ['clean']) or states
4806 if not show:
4806 if not show:
4807 if ui.quiet:
4807 if ui.quiet:
4808 show = states[:4]
4808 show = states[:4]
4809 else:
4809 else:
4810 show = states[:5]
4810 show = states[:5]
4811
4811
4812 m = scmutil.match(repo[node2], pats, opts)
4812 m = scmutil.match(repo[node2], pats, opts)
4813 stat = repo.status(node1, node2, m,
4813 stat = repo.status(node1, node2, m,
4814 'ignored' in show, 'clean' in show, 'unknown' in show,
4814 'ignored' in show, 'clean' in show, 'unknown' in show,
4815 opts.get('subrepos'))
4815 opts.get('subrepos'))
4816 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4816 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4817
4817
4818 if (opts.get('all') or opts.get('copies')
4818 if (opts.get('all') or opts.get('copies')
4819 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4819 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4820 copy = copies.pathcopies(repo[node1], repo[node2], m)
4820 copy = copies.pathcopies(repo[node1], repo[node2], m)
4821
4821
4822 ui.pager('status')
4822 ui.pager('status')
4823 fm = ui.formatter('status', opts)
4823 fm = ui.formatter('status', opts)
4824 fmt = '%s' + end
4824 fmt = '%s' + end
4825 showchar = not opts.get('no_status')
4825 showchar = not opts.get('no_status')
4826
4826
4827 for state, char, files in changestates:
4827 for state, char, files in changestates:
4828 if state in show:
4828 if state in show:
4829 label = 'status.' + state
4829 label = 'status.' + state
4830 for f in files:
4830 for f in files:
4831 fm.startitem()
4831 fm.startitem()
4832 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4832 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4833 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4833 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4834 if f in copy:
4834 if f in copy:
4835 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4835 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4836 label='status.copied')
4836 label='status.copied')
4837 fm.end()
4837 fm.end()
4838
4838
4839 @command('^summary|sum',
4839 @command('^summary|sum',
4840 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4840 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4841 def summary(ui, repo, **opts):
4841 def summary(ui, repo, **opts):
4842 """summarize working directory state
4842 """summarize working directory state
4843
4843
4844 This generates a brief summary of the working directory state,
4844 This generates a brief summary of the working directory state,
4845 including parents, branch, commit status, phase and available updates.
4845 including parents, branch, commit status, phase and available updates.
4846
4846
4847 With the --remote option, this will check the default paths for
4847 With the --remote option, this will check the default paths for
4848 incoming and outgoing changes. This can be time-consuming.
4848 incoming and outgoing changes. This can be time-consuming.
4849
4849
4850 Returns 0 on success.
4850 Returns 0 on success.
4851 """
4851 """
4852
4852
4853 opts = pycompat.byteskwargs(opts)
4853 opts = pycompat.byteskwargs(opts)
4854 ui.pager('summary')
4854 ui.pager('summary')
4855 ctx = repo[None]
4855 ctx = repo[None]
4856 parents = ctx.parents()
4856 parents = ctx.parents()
4857 pnode = parents[0].node()
4857 pnode = parents[0].node()
4858 marks = []
4858 marks = []
4859
4859
4860 ms = None
4860 ms = None
4861 try:
4861 try:
4862 ms = mergemod.mergestate.read(repo)
4862 ms = mergemod.mergestate.read(repo)
4863 except error.UnsupportedMergeRecords as e:
4863 except error.UnsupportedMergeRecords as e:
4864 s = ' '.join(e.recordtypes)
4864 s = ' '.join(e.recordtypes)
4865 ui.warn(
4865 ui.warn(
4866 _('warning: merge state has unsupported record types: %s\n') % s)
4866 _('warning: merge state has unsupported record types: %s\n') % s)
4867 unresolved = 0
4867 unresolved = 0
4868 else:
4868 else:
4869 unresolved = [f for f in ms if ms[f] == 'u']
4869 unresolved = [f for f in ms if ms[f] == 'u']
4870
4870
4871 for p in parents:
4871 for p in parents:
4872 # label with log.changeset (instead of log.parent) since this
4872 # label with log.changeset (instead of log.parent) since this
4873 # shows a working directory parent *changeset*:
4873 # shows a working directory parent *changeset*:
4874 # i18n: column positioning for "hg summary"
4874 # i18n: column positioning for "hg summary"
4875 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4875 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4876 label=cmdutil._changesetlabels(p))
4876 label=cmdutil._changesetlabels(p))
4877 ui.write(' '.join(p.tags()), label='log.tag')
4877 ui.write(' '.join(p.tags()), label='log.tag')
4878 if p.bookmarks():
4878 if p.bookmarks():
4879 marks.extend(p.bookmarks())
4879 marks.extend(p.bookmarks())
4880 if p.rev() == -1:
4880 if p.rev() == -1:
4881 if not len(repo):
4881 if not len(repo):
4882 ui.write(_(' (empty repository)'))
4882 ui.write(_(' (empty repository)'))
4883 else:
4883 else:
4884 ui.write(_(' (no revision checked out)'))
4884 ui.write(_(' (no revision checked out)'))
4885 if p.obsolete():
4885 if p.obsolete():
4886 ui.write(_(' (obsolete)'))
4886 ui.write(_(' (obsolete)'))
4887 if p.troubled():
4887 if p.troubled():
4888 ui.write(' ('
4888 ui.write(' ('
4889 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4889 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4890 for trouble in p.troubles())
4890 for trouble in p.troubles())
4891 + ')')
4891 + ')')
4892 ui.write('\n')
4892 ui.write('\n')
4893 if p.description():
4893 if p.description():
4894 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4894 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4895 label='log.summary')
4895 label='log.summary')
4896
4896
4897 branch = ctx.branch()
4897 branch = ctx.branch()
4898 bheads = repo.branchheads(branch)
4898 bheads = repo.branchheads(branch)
4899 # i18n: column positioning for "hg summary"
4899 # i18n: column positioning for "hg summary"
4900 m = _('branch: %s\n') % branch
4900 m = _('branch: %s\n') % branch
4901 if branch != 'default':
4901 if branch != 'default':
4902 ui.write(m, label='log.branch')
4902 ui.write(m, label='log.branch')
4903 else:
4903 else:
4904 ui.status(m, label='log.branch')
4904 ui.status(m, label='log.branch')
4905
4905
4906 if marks:
4906 if marks:
4907 active = repo._activebookmark
4907 active = repo._activebookmark
4908 # i18n: column positioning for "hg summary"
4908 # i18n: column positioning for "hg summary"
4909 ui.write(_('bookmarks:'), label='log.bookmark')
4909 ui.write(_('bookmarks:'), label='log.bookmark')
4910 if active is not None:
4910 if active is not None:
4911 if active in marks:
4911 if active in marks:
4912 ui.write(' *' + active, label=activebookmarklabel)
4912 ui.write(' *' + active, label=activebookmarklabel)
4913 marks.remove(active)
4913 marks.remove(active)
4914 else:
4914 else:
4915 ui.write(' [%s]' % active, label=activebookmarklabel)
4915 ui.write(' [%s]' % active, label=activebookmarklabel)
4916 for m in marks:
4916 for m in marks:
4917 ui.write(' ' + m, label='log.bookmark')
4917 ui.write(' ' + m, label='log.bookmark')
4918 ui.write('\n', label='log.bookmark')
4918 ui.write('\n', label='log.bookmark')
4919
4919
4920 status = repo.status(unknown=True)
4920 status = repo.status(unknown=True)
4921
4921
4922 c = repo.dirstate.copies()
4922 c = repo.dirstate.copies()
4923 copied, renamed = [], []
4923 copied, renamed = [], []
4924 for d, s in c.iteritems():
4924 for d, s in c.iteritems():
4925 if s in status.removed:
4925 if s in status.removed:
4926 status.removed.remove(s)
4926 status.removed.remove(s)
4927 renamed.append(d)
4927 renamed.append(d)
4928 else:
4928 else:
4929 copied.append(d)
4929 copied.append(d)
4930 if d in status.added:
4930 if d in status.added:
4931 status.added.remove(d)
4931 status.added.remove(d)
4932
4932
4933 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4933 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4934
4934
4935 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4935 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4936 (ui.label(_('%d added'), 'status.added'), status.added),
4936 (ui.label(_('%d added'), 'status.added'), status.added),
4937 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4937 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4938 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4938 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4939 (ui.label(_('%d copied'), 'status.copied'), copied),
4939 (ui.label(_('%d copied'), 'status.copied'), copied),
4940 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4940 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4941 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4941 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4942 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4942 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4943 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4943 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4944 t = []
4944 t = []
4945 for l, s in labels:
4945 for l, s in labels:
4946 if s:
4946 if s:
4947 t.append(l % len(s))
4947 t.append(l % len(s))
4948
4948
4949 t = ', '.join(t)
4949 t = ', '.join(t)
4950 cleanworkdir = False
4950 cleanworkdir = False
4951
4951
4952 if repo.vfs.exists('graftstate'):
4952 if repo.vfs.exists('graftstate'):
4953 t += _(' (graft in progress)')
4953 t += _(' (graft in progress)')
4954 if repo.vfs.exists('updatestate'):
4954 if repo.vfs.exists('updatestate'):
4955 t += _(' (interrupted update)')
4955 t += _(' (interrupted update)')
4956 elif len(parents) > 1:
4956 elif len(parents) > 1:
4957 t += _(' (merge)')
4957 t += _(' (merge)')
4958 elif branch != parents[0].branch():
4958 elif branch != parents[0].branch():
4959 t += _(' (new branch)')
4959 t += _(' (new branch)')
4960 elif (parents[0].closesbranch() and
4960 elif (parents[0].closesbranch() and
4961 pnode in repo.branchheads(branch, closed=True)):
4961 pnode in repo.branchheads(branch, closed=True)):
4962 t += _(' (head closed)')
4962 t += _(' (head closed)')
4963 elif not (status.modified or status.added or status.removed or renamed or
4963 elif not (status.modified or status.added or status.removed or renamed or
4964 copied or subs):
4964 copied or subs):
4965 t += _(' (clean)')
4965 t += _(' (clean)')
4966 cleanworkdir = True
4966 cleanworkdir = True
4967 elif pnode not in bheads:
4967 elif pnode not in bheads:
4968 t += _(' (new branch head)')
4968 t += _(' (new branch head)')
4969
4969
4970 if parents:
4970 if parents:
4971 pendingphase = max(p.phase() for p in parents)
4971 pendingphase = max(p.phase() for p in parents)
4972 else:
4972 else:
4973 pendingphase = phases.public
4973 pendingphase = phases.public
4974
4974
4975 if pendingphase > phases.newcommitphase(ui):
4975 if pendingphase > phases.newcommitphase(ui):
4976 t += ' (%s)' % phases.phasenames[pendingphase]
4976 t += ' (%s)' % phases.phasenames[pendingphase]
4977
4977
4978 if cleanworkdir:
4978 if cleanworkdir:
4979 # i18n: column positioning for "hg summary"
4979 # i18n: column positioning for "hg summary"
4980 ui.status(_('commit: %s\n') % t.strip())
4980 ui.status(_('commit: %s\n') % t.strip())
4981 else:
4981 else:
4982 # i18n: column positioning for "hg summary"
4982 # i18n: column positioning for "hg summary"
4983 ui.write(_('commit: %s\n') % t.strip())
4983 ui.write(_('commit: %s\n') % t.strip())
4984
4984
4985 # all ancestors of branch heads - all ancestors of parent = new csets
4985 # all ancestors of branch heads - all ancestors of parent = new csets
4986 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4986 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4987 bheads))
4987 bheads))
4988
4988
4989 if new == 0:
4989 if new == 0:
4990 # i18n: column positioning for "hg summary"
4990 # i18n: column positioning for "hg summary"
4991 ui.status(_('update: (current)\n'))
4991 ui.status(_('update: (current)\n'))
4992 elif pnode not in bheads:
4992 elif pnode not in bheads:
4993 # i18n: column positioning for "hg summary"
4993 # i18n: column positioning for "hg summary"
4994 ui.write(_('update: %d new changesets (update)\n') % new)
4994 ui.write(_('update: %d new changesets (update)\n') % new)
4995 else:
4995 else:
4996 # i18n: column positioning for "hg summary"
4996 # i18n: column positioning for "hg summary"
4997 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4997 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4998 (new, len(bheads)))
4998 (new, len(bheads)))
4999
4999
5000 t = []
5000 t = []
5001 draft = len(repo.revs('draft()'))
5001 draft = len(repo.revs('draft()'))
5002 if draft:
5002 if draft:
5003 t.append(_('%d draft') % draft)
5003 t.append(_('%d draft') % draft)
5004 secret = len(repo.revs('secret()'))
5004 secret = len(repo.revs('secret()'))
5005 if secret:
5005 if secret:
5006 t.append(_('%d secret') % secret)
5006 t.append(_('%d secret') % secret)
5007
5007
5008 if draft or secret:
5008 if draft or secret:
5009 ui.status(_('phases: %s\n') % ', '.join(t))
5009 ui.status(_('phases: %s\n') % ', '.join(t))
5010
5010
5011 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5011 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5012 for trouble in ("unstable", "divergent", "bumped"):
5012 for trouble in ("unstable", "divergent", "bumped"):
5013 numtrouble = len(repo.revs(trouble + "()"))
5013 numtrouble = len(repo.revs(trouble + "()"))
5014 # We write all the possibilities to ease translation
5014 # We write all the possibilities to ease translation
5015 troublemsg = {
5015 troublemsg = {
5016 "unstable": _("unstable: %d changesets"),
5016 "unstable": _("unstable: %d changesets"),
5017 "divergent": _("divergent: %d changesets"),
5017 "divergent": _("divergent: %d changesets"),
5018 "bumped": _("bumped: %d changesets"),
5018 "bumped": _("bumped: %d changesets"),
5019 }
5019 }
5020 if numtrouble > 0:
5020 if numtrouble > 0:
5021 ui.status(troublemsg[trouble] % numtrouble + "\n")
5021 ui.status(troublemsg[trouble] % numtrouble + "\n")
5022
5022
5023 cmdutil.summaryhooks(ui, repo)
5023 cmdutil.summaryhooks(ui, repo)
5024
5024
5025 if opts.get('remote'):
5025 if opts.get('remote'):
5026 needsincoming, needsoutgoing = True, True
5026 needsincoming, needsoutgoing = True, True
5027 else:
5027 else:
5028 needsincoming, needsoutgoing = False, False
5028 needsincoming, needsoutgoing = False, False
5029 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5029 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5030 if i:
5030 if i:
5031 needsincoming = True
5031 needsincoming = True
5032 if o:
5032 if o:
5033 needsoutgoing = True
5033 needsoutgoing = True
5034 if not needsincoming and not needsoutgoing:
5034 if not needsincoming and not needsoutgoing:
5035 return
5035 return
5036
5036
5037 def getincoming():
5037 def getincoming():
5038 source, branches = hg.parseurl(ui.expandpath('default'))
5038 source, branches = hg.parseurl(ui.expandpath('default'))
5039 sbranch = branches[0]
5039 sbranch = branches[0]
5040 try:
5040 try:
5041 other = hg.peer(repo, {}, source)
5041 other = hg.peer(repo, {}, source)
5042 except error.RepoError:
5042 except error.RepoError:
5043 if opts.get('remote'):
5043 if opts.get('remote'):
5044 raise
5044 raise
5045 return source, sbranch, None, None, None
5045 return source, sbranch, None, None, None
5046 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5046 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5047 if revs:
5047 if revs:
5048 revs = [other.lookup(rev) for rev in revs]
5048 revs = [other.lookup(rev) for rev in revs]
5049 ui.debug('comparing with %s\n' % util.hidepassword(source))
5049 ui.debug('comparing with %s\n' % util.hidepassword(source))
5050 repo.ui.pushbuffer()
5050 repo.ui.pushbuffer()
5051 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5051 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5052 repo.ui.popbuffer()
5052 repo.ui.popbuffer()
5053 return source, sbranch, other, commoninc, commoninc[1]
5053 return source, sbranch, other, commoninc, commoninc[1]
5054
5054
5055 if needsincoming:
5055 if needsincoming:
5056 source, sbranch, sother, commoninc, incoming = getincoming()
5056 source, sbranch, sother, commoninc, incoming = getincoming()
5057 else:
5057 else:
5058 source = sbranch = sother = commoninc = incoming = None
5058 source = sbranch = sother = commoninc = incoming = None
5059
5059
5060 def getoutgoing():
5060 def getoutgoing():
5061 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5061 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5062 dbranch = branches[0]
5062 dbranch = branches[0]
5063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5064 if source != dest:
5064 if source != dest:
5065 try:
5065 try:
5066 dother = hg.peer(repo, {}, dest)
5066 dother = hg.peer(repo, {}, dest)
5067 except error.RepoError:
5067 except error.RepoError:
5068 if opts.get('remote'):
5068 if opts.get('remote'):
5069 raise
5069 raise
5070 return dest, dbranch, None, None
5070 return dest, dbranch, None, None
5071 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5071 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5072 elif sother is None:
5072 elif sother is None:
5073 # there is no explicit destination peer, but source one is invalid
5073 # there is no explicit destination peer, but source one is invalid
5074 return dest, dbranch, None, None
5074 return dest, dbranch, None, None
5075 else:
5075 else:
5076 dother = sother
5076 dother = sother
5077 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5077 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5078 common = None
5078 common = None
5079 else:
5079 else:
5080 common = commoninc
5080 common = commoninc
5081 if revs:
5081 if revs:
5082 revs = [repo.lookup(rev) for rev in revs]
5082 revs = [repo.lookup(rev) for rev in revs]
5083 repo.ui.pushbuffer()
5083 repo.ui.pushbuffer()
5084 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5084 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5085 commoninc=common)
5085 commoninc=common)
5086 repo.ui.popbuffer()
5086 repo.ui.popbuffer()
5087 return dest, dbranch, dother, outgoing
5087 return dest, dbranch, dother, outgoing
5088
5088
5089 if needsoutgoing:
5089 if needsoutgoing:
5090 dest, dbranch, dother, outgoing = getoutgoing()
5090 dest, dbranch, dother, outgoing = getoutgoing()
5091 else:
5091 else:
5092 dest = dbranch = dother = outgoing = None
5092 dest = dbranch = dother = outgoing = None
5093
5093
5094 if opts.get('remote'):
5094 if opts.get('remote'):
5095 t = []
5095 t = []
5096 if incoming:
5096 if incoming:
5097 t.append(_('1 or more incoming'))
5097 t.append(_('1 or more incoming'))
5098 o = outgoing.missing
5098 o = outgoing.missing
5099 if o:
5099 if o:
5100 t.append(_('%d outgoing') % len(o))
5100 t.append(_('%d outgoing') % len(o))
5101 other = dother or sother
5101 other = dother or sother
5102 if 'bookmarks' in other.listkeys('namespaces'):
5102 if 'bookmarks' in other.listkeys('namespaces'):
5103 counts = bookmarks.summary(repo, other)
5103 counts = bookmarks.summary(repo, other)
5104 if counts[0] > 0:
5104 if counts[0] > 0:
5105 t.append(_('%d incoming bookmarks') % counts[0])
5105 t.append(_('%d incoming bookmarks') % counts[0])
5106 if counts[1] > 0:
5106 if counts[1] > 0:
5107 t.append(_('%d outgoing bookmarks') % counts[1])
5107 t.append(_('%d outgoing bookmarks') % counts[1])
5108
5108
5109 if t:
5109 if t:
5110 # i18n: column positioning for "hg summary"
5110 # i18n: column positioning for "hg summary"
5111 ui.write(_('remote: %s\n') % (', '.join(t)))
5111 ui.write(_('remote: %s\n') % (', '.join(t)))
5112 else:
5112 else:
5113 # i18n: column positioning for "hg summary"
5113 # i18n: column positioning for "hg summary"
5114 ui.status(_('remote: (synced)\n'))
5114 ui.status(_('remote: (synced)\n'))
5115
5115
5116 cmdutil.summaryremotehooks(ui, repo, opts,
5116 cmdutil.summaryremotehooks(ui, repo, opts,
5117 ((source, sbranch, sother, commoninc),
5117 ((source, sbranch, sother, commoninc),
5118 (dest, dbranch, dother, outgoing)))
5118 (dest, dbranch, dother, outgoing)))
5119
5119
5120 @command('tag',
5120 @command('tag',
5121 [('f', 'force', None, _('force tag')),
5121 [('f', 'force', None, _('force tag')),
5122 ('l', 'local', None, _('make the tag local')),
5122 ('l', 'local', None, _('make the tag local')),
5123 ('r', 'rev', '', _('revision to tag'), _('REV')),
5123 ('r', 'rev', '', _('revision to tag'), _('REV')),
5124 ('', 'remove', None, _('remove a tag')),
5124 ('', 'remove', None, _('remove a tag')),
5125 # -l/--local is already there, commitopts cannot be used
5125 # -l/--local is already there, commitopts cannot be used
5126 ('e', 'edit', None, _('invoke editor on commit messages')),
5126 ('e', 'edit', None, _('invoke editor on commit messages')),
5127 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5127 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5128 ] + commitopts2,
5128 ] + commitopts2,
5129 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5129 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5130 def tag(ui, repo, name1, *names, **opts):
5130 def tag(ui, repo, name1, *names, **opts):
5131 """add one or more tags for the current or given revision
5131 """add one or more tags for the current or given revision
5132
5132
5133 Name a particular revision using <name>.
5133 Name a particular revision using <name>.
5134
5134
5135 Tags are used to name particular revisions of the repository and are
5135 Tags are used to name particular revisions of the repository and are
5136 very useful to compare different revisions, to go back to significant
5136 very useful to compare different revisions, to go back to significant
5137 earlier versions or to mark branch points as releases, etc. Changing
5137 earlier versions or to mark branch points as releases, etc. Changing
5138 an existing tag is normally disallowed; use -f/--force to override.
5138 an existing tag is normally disallowed; use -f/--force to override.
5139
5139
5140 If no revision is given, the parent of the working directory is
5140 If no revision is given, the parent of the working directory is
5141 used.
5141 used.
5142
5142
5143 To facilitate version control, distribution, and merging of tags,
5143 To facilitate version control, distribution, and merging of tags,
5144 they are stored as a file named ".hgtags" which is managed similarly
5144 they are stored as a file named ".hgtags" which is managed similarly
5145 to other project files and can be hand-edited if necessary. This
5145 to other project files and can be hand-edited if necessary. This
5146 also means that tagging creates a new commit. The file
5146 also means that tagging creates a new commit. The file
5147 ".hg/localtags" is used for local tags (not shared among
5147 ".hg/localtags" is used for local tags (not shared among
5148 repositories).
5148 repositories).
5149
5149
5150 Tag commits are usually made at the head of a branch. If the parent
5150 Tag commits are usually made at the head of a branch. If the parent
5151 of the working directory is not a branch head, :hg:`tag` aborts; use
5151 of the working directory is not a branch head, :hg:`tag` aborts; use
5152 -f/--force to force the tag commit to be based on a non-head
5152 -f/--force to force the tag commit to be based on a non-head
5153 changeset.
5153 changeset.
5154
5154
5155 See :hg:`help dates` for a list of formats valid for -d/--date.
5155 See :hg:`help dates` for a list of formats valid for -d/--date.
5156
5156
5157 Since tag names have priority over branch names during revision
5157 Since tag names have priority over branch names during revision
5158 lookup, using an existing branch name as a tag name is discouraged.
5158 lookup, using an existing branch name as a tag name is discouraged.
5159
5159
5160 Returns 0 on success.
5160 Returns 0 on success.
5161 """
5161 """
5162 opts = pycompat.byteskwargs(opts)
5162 opts = pycompat.byteskwargs(opts)
5163 wlock = lock = None
5163 wlock = lock = None
5164 try:
5164 try:
5165 wlock = repo.wlock()
5165 wlock = repo.wlock()
5166 lock = repo.lock()
5166 lock = repo.lock()
5167 rev_ = "."
5167 rev_ = "."
5168 names = [t.strip() for t in (name1,) + names]
5168 names = [t.strip() for t in (name1,) + names]
5169 if len(names) != len(set(names)):
5169 if len(names) != len(set(names)):
5170 raise error.Abort(_('tag names must be unique'))
5170 raise error.Abort(_('tag names must be unique'))
5171 for n in names:
5171 for n in names:
5172 scmutil.checknewlabel(repo, n, 'tag')
5172 scmutil.checknewlabel(repo, n, 'tag')
5173 if not n:
5173 if not n:
5174 raise error.Abort(_('tag names cannot consist entirely of '
5174 raise error.Abort(_('tag names cannot consist entirely of '
5175 'whitespace'))
5175 'whitespace'))
5176 if opts.get('rev') and opts.get('remove'):
5176 if opts.get('rev') and opts.get('remove'):
5177 raise error.Abort(_("--rev and --remove are incompatible"))
5177 raise error.Abort(_("--rev and --remove are incompatible"))
5178 if opts.get('rev'):
5178 if opts.get('rev'):
5179 rev_ = opts['rev']
5179 rev_ = opts['rev']
5180 message = opts.get('message')
5180 message = opts.get('message')
5181 if opts.get('remove'):
5181 if opts.get('remove'):
5182 if opts.get('local'):
5182 if opts.get('local'):
5183 expectedtype = 'local'
5183 expectedtype = 'local'
5184 else:
5184 else:
5185 expectedtype = 'global'
5185 expectedtype = 'global'
5186
5186
5187 for n in names:
5187 for n in names:
5188 if not repo.tagtype(n):
5188 if not repo.tagtype(n):
5189 raise error.Abort(_("tag '%s' does not exist") % n)
5189 raise error.Abort(_("tag '%s' does not exist") % n)
5190 if repo.tagtype(n) != expectedtype:
5190 if repo.tagtype(n) != expectedtype:
5191 if expectedtype == 'global':
5191 if expectedtype == 'global':
5192 raise error.Abort(_("tag '%s' is not a global tag") % n)
5192 raise error.Abort(_("tag '%s' is not a global tag") % n)
5193 else:
5193 else:
5194 raise error.Abort(_("tag '%s' is not a local tag") % n)
5194 raise error.Abort(_("tag '%s' is not a local tag") % n)
5195 rev_ = 'null'
5195 rev_ = 'null'
5196 if not message:
5196 if not message:
5197 # we don't translate commit messages
5197 # we don't translate commit messages
5198 message = 'Removed tag %s' % ', '.join(names)
5198 message = 'Removed tag %s' % ', '.join(names)
5199 elif not opts.get('force'):
5199 elif not opts.get('force'):
5200 for n in names:
5200 for n in names:
5201 if n in repo.tags():
5201 if n in repo.tags():
5202 raise error.Abort(_("tag '%s' already exists "
5202 raise error.Abort(_("tag '%s' already exists "
5203 "(use -f to force)") % n)
5203 "(use -f to force)") % n)
5204 if not opts.get('local'):
5204 if not opts.get('local'):
5205 p1, p2 = repo.dirstate.parents()
5205 p1, p2 = repo.dirstate.parents()
5206 if p2 != nullid:
5206 if p2 != nullid:
5207 raise error.Abort(_('uncommitted merge'))
5207 raise error.Abort(_('uncommitted merge'))
5208 bheads = repo.branchheads()
5208 bheads = repo.branchheads()
5209 if not opts.get('force') and bheads and p1 not in bheads:
5209 if not opts.get('force') and bheads and p1 not in bheads:
5210 raise error.Abort(_('working directory is not at a branch head '
5210 raise error.Abort(_('working directory is not at a branch head '
5211 '(use -f to force)'))
5211 '(use -f to force)'))
5212 r = scmutil.revsingle(repo, rev_).node()
5212 r = scmutil.revsingle(repo, rev_).node()
5213
5213
5214 if not message:
5214 if not message:
5215 # we don't translate commit messages
5215 # we don't translate commit messages
5216 message = ('Added tag %s for changeset %s' %
5216 message = ('Added tag %s for changeset %s' %
5217 (', '.join(names), short(r)))
5217 (', '.join(names), short(r)))
5218
5218
5219 date = opts.get('date')
5219 date = opts.get('date')
5220 if date:
5220 if date:
5221 date = util.parsedate(date)
5221 date = util.parsedate(date)
5222
5222
5223 if opts.get('remove'):
5223 if opts.get('remove'):
5224 editform = 'tag.remove'
5224 editform = 'tag.remove'
5225 else:
5225 else:
5226 editform = 'tag.add'
5226 editform = 'tag.add'
5227 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5227 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5228
5228
5229 # don't allow tagging the null rev
5229 # don't allow tagging the null rev
5230 if (not opts.get('remove') and
5230 if (not opts.get('remove') and
5231 scmutil.revsingle(repo, rev_).rev() == nullrev):
5231 scmutil.revsingle(repo, rev_).rev() == nullrev):
5232 raise error.Abort(_("cannot tag null revision"))
5232 raise error.Abort(_("cannot tag null revision"))
5233
5233
5234 tagsmod.tag(repo, names, r, message, opts.get('local'),
5234 tagsmod.tag(repo, names, r, message, opts.get('local'),
5235 opts.get('user'), date, editor=editor)
5235 opts.get('user'), date, editor=editor)
5236 finally:
5236 finally:
5237 release(lock, wlock)
5237 release(lock, wlock)
5238
5238
5239 @command('tags', formatteropts, '')
5239 @command('tags', formatteropts, '')
5240 def tags(ui, repo, **opts):
5240 def tags(ui, repo, **opts):
5241 """list repository tags
5241 """list repository tags
5242
5242
5243 This lists both regular and local tags. When the -v/--verbose
5243 This lists both regular and local tags. When the -v/--verbose
5244 switch is used, a third column "local" is printed for local tags.
5244 switch is used, a third column "local" is printed for local tags.
5245 When the -q/--quiet switch is used, only the tag name is printed.
5245 When the -q/--quiet switch is used, only the tag name is printed.
5246
5246
5247 Returns 0 on success.
5247 Returns 0 on success.
5248 """
5248 """
5249
5249
5250 opts = pycompat.byteskwargs(opts)
5250 opts = pycompat.byteskwargs(opts)
5251 ui.pager('tags')
5251 ui.pager('tags')
5252 fm = ui.formatter('tags', opts)
5252 fm = ui.formatter('tags', opts)
5253 hexfunc = fm.hexfunc
5253 hexfunc = fm.hexfunc
5254 tagtype = ""
5254 tagtype = ""
5255
5255
5256 for t, n in reversed(repo.tagslist()):
5256 for t, n in reversed(repo.tagslist()):
5257 hn = hexfunc(n)
5257 hn = hexfunc(n)
5258 label = 'tags.normal'
5258 label = 'tags.normal'
5259 tagtype = ''
5259 tagtype = ''
5260 if repo.tagtype(t) == 'local':
5260 if repo.tagtype(t) == 'local':
5261 label = 'tags.local'
5261 label = 'tags.local'
5262 tagtype = 'local'
5262 tagtype = 'local'
5263
5263
5264 fm.startitem()
5264 fm.startitem()
5265 fm.write('tag', '%s', t, label=label)
5265 fm.write('tag', '%s', t, label=label)
5266 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5266 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5267 fm.condwrite(not ui.quiet, 'rev node', fmt,
5267 fm.condwrite(not ui.quiet, 'rev node', fmt,
5268 repo.changelog.rev(n), hn, label=label)
5268 repo.changelog.rev(n), hn, label=label)
5269 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5269 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5270 tagtype, label=label)
5270 tagtype, label=label)
5271 fm.plain('\n')
5271 fm.plain('\n')
5272 fm.end()
5272 fm.end()
5273
5273
5274 @command('tip',
5274 @command('tip',
5275 [('p', 'patch', None, _('show patch')),
5275 [('p', 'patch', None, _('show patch')),
5276 ('g', 'git', None, _('use git extended diff format')),
5276 ('g', 'git', None, _('use git extended diff format')),
5277 ] + templateopts,
5277 ] + templateopts,
5278 _('[-p] [-g]'))
5278 _('[-p] [-g]'))
5279 def tip(ui, repo, **opts):
5279 def tip(ui, repo, **opts):
5280 """show the tip revision (DEPRECATED)
5280 """show the tip revision (DEPRECATED)
5281
5281
5282 The tip revision (usually just called the tip) is the changeset
5282 The tip revision (usually just called the tip) is the changeset
5283 most recently added to the repository (and therefore the most
5283 most recently added to the repository (and therefore the most
5284 recently changed head).
5284 recently changed head).
5285
5285
5286 If you have just made a commit, that commit will be the tip. If
5286 If you have just made a commit, that commit will be the tip. If
5287 you have just pulled changes from another repository, the tip of
5287 you have just pulled changes from another repository, the tip of
5288 that repository becomes the current tip. The "tip" tag is special
5288 that repository becomes the current tip. The "tip" tag is special
5289 and cannot be renamed or assigned to a different changeset.
5289 and cannot be renamed or assigned to a different changeset.
5290
5290
5291 This command is deprecated, please use :hg:`heads` instead.
5291 This command is deprecated, please use :hg:`heads` instead.
5292
5292
5293 Returns 0 on success.
5293 Returns 0 on success.
5294 """
5294 """
5295 opts = pycompat.byteskwargs(opts)
5295 opts = pycompat.byteskwargs(opts)
5296 displayer = cmdutil.show_changeset(ui, repo, opts)
5296 displayer = cmdutil.show_changeset(ui, repo, opts)
5297 displayer.show(repo['tip'])
5297 displayer.show(repo['tip'])
5298 displayer.close()
5298 displayer.close()
5299
5299
5300 @command('unbundle',
5300 @command('unbundle',
5301 [('u', 'update', None,
5301 [('u', 'update', None,
5302 _('update to new branch head if changesets were unbundled'))],
5302 _('update to new branch head if changesets were unbundled'))],
5303 _('[-u] FILE...'))
5303 _('[-u] FILE...'))
5304 def unbundle(ui, repo, fname1, *fnames, **opts):
5304 def unbundle(ui, repo, fname1, *fnames, **opts):
5305 """apply one or more bundle files
5305 """apply one or more bundle files
5306
5306
5307 Apply one or more bundle files generated by :hg:`bundle`.
5307 Apply one or more bundle files generated by :hg:`bundle`.
5308
5308
5309 Returns 0 on success, 1 if an update has unresolved files.
5309 Returns 0 on success, 1 if an update has unresolved files.
5310 """
5310 """
5311 fnames = (fname1,) + fnames
5311 fnames = (fname1,) + fnames
5312
5312
5313 with repo.lock():
5313 with repo.lock():
5314 for fname in fnames:
5314 for fname in fnames:
5315 f = hg.openpath(ui, fname)
5315 f = hg.openpath(ui, fname)
5316 gen = exchange.readbundle(ui, f, fname)
5316 gen = exchange.readbundle(ui, f, fname)
5317 if isinstance(gen, bundle2.unbundle20):
5317 if isinstance(gen, bundle2.unbundle20):
5318 tr = repo.transaction('unbundle')
5318 tr = repo.transaction('unbundle')
5319 try:
5319 try:
5320 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5320 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5321 url='bundle:' + fname)
5321 url='bundle:' + fname)
5322 tr.close()
5322 tr.close()
5323 except error.BundleUnknownFeatureError as exc:
5323 except error.BundleUnknownFeatureError as exc:
5324 raise error.Abort(_('%s: unknown bundle feature, %s')
5324 raise error.Abort(_('%s: unknown bundle feature, %s')
5325 % (fname, exc),
5325 % (fname, exc),
5326 hint=_("see https://mercurial-scm.org/"
5326 hint=_("see https://mercurial-scm.org/"
5327 "wiki/BundleFeature for more "
5327 "wiki/BundleFeature for more "
5328 "information"))
5328 "information"))
5329 finally:
5329 finally:
5330 if tr:
5330 if tr:
5331 tr.release()
5331 tr.release()
5332 changes = [r.get('return', 0)
5332 changes = [r.get('return', 0)
5333 for r in op.records['changegroup']]
5333 for r in op.records['changegroup']]
5334 modheads = changegroup.combineresults(changes)
5334 modheads = changegroup.combineresults(changes)
5335 elif isinstance(gen, streamclone.streamcloneapplier):
5335 elif isinstance(gen, streamclone.streamcloneapplier):
5336 raise error.Abort(
5336 raise error.Abort(
5337 _('packed bundles cannot be applied with '
5337 _('packed bundles cannot be applied with '
5338 '"hg unbundle"'),
5338 '"hg unbundle"'),
5339 hint=_('use "hg debugapplystreamclonebundle"'))
5339 hint=_('use "hg debugapplystreamclonebundle"'))
5340 else:
5340 else:
5341 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5341 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5342
5342
5343 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5343 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5344
5344
5345 @command('^update|up|checkout|co',
5345 @command('^update|up|checkout|co',
5346 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5346 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5347 ('c', 'check', None, _('require clean working directory')),
5347 ('c', 'check', None, _('require clean working directory')),
5348 ('m', 'merge', None, _('merge uncommitted changes')),
5348 ('m', 'merge', None, _('merge uncommitted changes')),
5349 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5349 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5350 ('r', 'rev', '', _('revision'), _('REV'))
5350 ('r', 'rev', '', _('revision'), _('REV'))
5351 ] + mergetoolopts,
5351 ] + mergetoolopts,
5352 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5352 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5353 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5353 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5354 merge=None, tool=None):
5354 merge=None, tool=None):
5355 """update working directory (or switch revisions)
5355 """update working directory (or switch revisions)
5356
5356
5357 Update the repository's working directory to the specified
5357 Update the repository's working directory to the specified
5358 changeset. If no changeset is specified, update to the tip of the
5358 changeset. If no changeset is specified, update to the tip of the
5359 current named branch and move the active bookmark (see :hg:`help
5359 current named branch and move the active bookmark (see :hg:`help
5360 bookmarks`).
5360 bookmarks`).
5361
5361
5362 Update sets the working directory's parent revision to the specified
5362 Update sets the working directory's parent revision to the specified
5363 changeset (see :hg:`help parents`).
5363 changeset (see :hg:`help parents`).
5364
5364
5365 If the changeset is not a descendant or ancestor of the working
5365 If the changeset is not a descendant or ancestor of the working
5366 directory's parent and there are uncommitted changes, the update is
5366 directory's parent and there are uncommitted changes, the update is
5367 aborted. With the -c/--check option, the working directory is checked
5367 aborted. With the -c/--check option, the working directory is checked
5368 for uncommitted changes; if none are found, the working directory is
5368 for uncommitted changes; if none are found, the working directory is
5369 updated to the specified changeset.
5369 updated to the specified changeset.
5370
5370
5371 .. container:: verbose
5371 .. container:: verbose
5372
5372
5373 The -C/--clean, -c/--check, and -m/--merge options control what
5373 The -C/--clean, -c/--check, and -m/--merge options control what
5374 happens if the working directory contains uncommitted changes.
5374 happens if the working directory contains uncommitted changes.
5375 At most of one of them can be specified.
5375 At most of one of them can be specified.
5376
5376
5377 1. If no option is specified, and if
5377 1. If no option is specified, and if
5378 the requested changeset is an ancestor or descendant of
5378 the requested changeset is an ancestor or descendant of
5379 the working directory's parent, the uncommitted changes
5379 the working directory's parent, the uncommitted changes
5380 are merged into the requested changeset and the merged
5380 are merged into the requested changeset and the merged
5381 result is left uncommitted. If the requested changeset is
5381 result is left uncommitted. If the requested changeset is
5382 not an ancestor or descendant (that is, it is on another
5382 not an ancestor or descendant (that is, it is on another
5383 branch), the update is aborted and the uncommitted changes
5383 branch), the update is aborted and the uncommitted changes
5384 are preserved.
5384 are preserved.
5385
5385
5386 2. With the -m/--merge option, the update is allowed even if the
5386 2. With the -m/--merge option, the update is allowed even if the
5387 requested changeset is not an ancestor or descendant of
5387 requested changeset is not an ancestor or descendant of
5388 the working directory's parent.
5388 the working directory's parent.
5389
5389
5390 3. With the -c/--check option, the update is aborted and the
5390 3. With the -c/--check option, the update is aborted and the
5391 uncommitted changes are preserved.
5391 uncommitted changes are preserved.
5392
5392
5393 4. With the -C/--clean option, uncommitted changes are discarded and
5393 4. With the -C/--clean option, uncommitted changes are discarded and
5394 the working directory is updated to the requested changeset.
5394 the working directory is updated to the requested changeset.
5395
5395
5396 To cancel an uncommitted merge (and lose your changes), use
5396 To cancel an uncommitted merge (and lose your changes), use
5397 :hg:`update --clean .`.
5397 :hg:`update --clean .`.
5398
5398
5399 Use null as the changeset to remove the working directory (like
5399 Use null as the changeset to remove the working directory (like
5400 :hg:`clone -U`).
5400 :hg:`clone -U`).
5401
5401
5402 If you want to revert just one file to an older revision, use
5402 If you want to revert just one file to an older revision, use
5403 :hg:`revert [-r REV] NAME`.
5403 :hg:`revert [-r REV] NAME`.
5404
5404
5405 See :hg:`help dates` for a list of formats valid for -d/--date.
5405 See :hg:`help dates` for a list of formats valid for -d/--date.
5406
5406
5407 Returns 0 on success, 1 if there are unresolved files.
5407 Returns 0 on success, 1 if there are unresolved files.
5408 """
5408 """
5409 if rev and node:
5409 if rev and node:
5410 raise error.Abort(_("please specify just one revision"))
5410 raise error.Abort(_("please specify just one revision"))
5411
5411
5412 if ui.configbool('commands', 'update.requiredest'):
5412 if ui.configbool('commands', 'update.requiredest'):
5413 if not node and not rev and not date:
5413 if not node and not rev and not date:
5414 raise error.Abort(_('you must specify a destination'),
5414 raise error.Abort(_('you must specify a destination'),
5415 hint=_('for example: hg update ".::"'))
5415 hint=_('for example: hg update ".::"'))
5416
5416
5417 if rev is None or rev == '':
5417 if rev is None or rev == '':
5418 rev = node
5418 rev = node
5419
5419
5420 if date and rev is not None:
5420 if date and rev is not None:
5421 raise error.Abort(_("you can't specify a revision and a date"))
5421 raise error.Abort(_("you can't specify a revision and a date"))
5422
5422
5423 if len([x for x in (clean, check, merge) if x]) > 1:
5423 if len([x for x in (clean, check, merge) if x]) > 1:
5424 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5424 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5425 "or -m/merge"))
5425 "or -m/merge"))
5426
5426
5427 updatecheck = None
5427 updatecheck = None
5428 if check:
5428 if check:
5429 updatecheck = 'abort'
5429 updatecheck = 'abort'
5430 elif merge:
5430 elif merge:
5431 updatecheck = 'none'
5431 updatecheck = 'none'
5432
5432
5433 with repo.wlock():
5433 with repo.wlock():
5434 cmdutil.clearunfinished(repo)
5434 cmdutil.clearunfinished(repo)
5435
5435
5436 if date:
5436 if date:
5437 rev = cmdutil.finddate(ui, repo, date)
5437 rev = cmdutil.finddate(ui, repo, date)
5438
5438
5439 # if we defined a bookmark, we have to remember the original name
5439 # if we defined a bookmark, we have to remember the original name
5440 brev = rev
5440 brev = rev
5441 rev = scmutil.revsingle(repo, rev, rev).rev()
5441 rev = scmutil.revsingle(repo, rev, rev).rev()
5442
5442
5443 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5443 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5444
5444
5445 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5445 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5446 updatecheck=updatecheck)
5446 updatecheck=updatecheck)
5447
5447
5448 @command('verify', [])
5448 @command('verify', [])
5449 def verify(ui, repo):
5449 def verify(ui, repo):
5450 """verify the integrity of the repository
5450 """verify the integrity of the repository
5451
5451
5452 Verify the integrity of the current repository.
5452 Verify the integrity of the current repository.
5453
5453
5454 This will perform an extensive check of the repository's
5454 This will perform an extensive check of the repository's
5455 integrity, validating the hashes and checksums of each entry in
5455 integrity, validating the hashes and checksums of each entry in
5456 the changelog, manifest, and tracked files, as well as the
5456 the changelog, manifest, and tracked files, as well as the
5457 integrity of their crosslinks and indices.
5457 integrity of their crosslinks and indices.
5458
5458
5459 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5459 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5460 for more information about recovery from corruption of the
5460 for more information about recovery from corruption of the
5461 repository.
5461 repository.
5462
5462
5463 Returns 0 on success, 1 if errors are encountered.
5463 Returns 0 on success, 1 if errors are encountered.
5464 """
5464 """
5465 return hg.verify(repo)
5465 return hg.verify(repo)
5466
5466
5467 @command('version', [] + formatteropts, norepo=True)
5467 @command('version', [] + formatteropts, norepo=True)
5468 def version_(ui, **opts):
5468 def version_(ui, **opts):
5469 """output version and copyright information"""
5469 """output version and copyright information"""
5470 opts = pycompat.byteskwargs(opts)
5470 opts = pycompat.byteskwargs(opts)
5471 if ui.verbose:
5471 if ui.verbose:
5472 ui.pager('version')
5472 ui.pager('version')
5473 fm = ui.formatter("version", opts)
5473 fm = ui.formatter("version", opts)
5474 fm.startitem()
5474 fm.startitem()
5475 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5475 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5476 util.version())
5476 util.version())
5477 license = _(
5477 license = _(
5478 "(see https://mercurial-scm.org for more information)\n"
5478 "(see https://mercurial-scm.org for more information)\n"
5479 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5479 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5480 "This is free software; see the source for copying conditions. "
5480 "This is free software; see the source for copying conditions. "
5481 "There is NO\nwarranty; "
5481 "There is NO\nwarranty; "
5482 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5482 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5483 )
5483 )
5484 if not ui.quiet:
5484 if not ui.quiet:
5485 fm.plain(license)
5485 fm.plain(license)
5486
5486
5487 if ui.verbose:
5487 if ui.verbose:
5488 fm.plain(_("\nEnabled extensions:\n\n"))
5488 fm.plain(_("\nEnabled extensions:\n\n"))
5489 # format names and versions into columns
5489 # format names and versions into columns
5490 names = []
5490 names = []
5491 vers = []
5491 vers = []
5492 isinternals = []
5492 isinternals = []
5493 for name, module in extensions.extensions():
5493 for name, module in extensions.extensions():
5494 names.append(name)
5494 names.append(name)
5495 vers.append(extensions.moduleversion(module) or None)
5495 vers.append(extensions.moduleversion(module) or None)
5496 isinternals.append(extensions.ismoduleinternal(module))
5496 isinternals.append(extensions.ismoduleinternal(module))
5497 fn = fm.nested("extensions")
5497 fn = fm.nested("extensions")
5498 if names:
5498 if names:
5499 namefmt = " %%-%ds " % max(len(n) for n in names)
5499 namefmt = " %%-%ds " % max(len(n) for n in names)
5500 places = [_("external"), _("internal")]
5500 places = [_("external"), _("internal")]
5501 for n, v, p in zip(names, vers, isinternals):
5501 for n, v, p in zip(names, vers, isinternals):
5502 fn.startitem()
5502 fn.startitem()
5503 fn.condwrite(ui.verbose, "name", namefmt, n)
5503 fn.condwrite(ui.verbose, "name", namefmt, n)
5504 if ui.verbose:
5504 if ui.verbose:
5505 fn.plain("%s " % places[p])
5505 fn.plain("%s " % places[p])
5506 fn.data(bundled=p)
5506 fn.data(bundled=p)
5507 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5507 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5508 if ui.verbose:
5508 if ui.verbose:
5509 fn.plain("\n")
5509 fn.plain("\n")
5510 fn.end()
5510 fn.end()
5511 fm.end()
5511 fm.end()
5512
5512
5513 def loadcmdtable(ui, name, cmdtable):
5513 def loadcmdtable(ui, name, cmdtable):
5514 """Load command functions from specified cmdtable
5514 """Load command functions from specified cmdtable
5515 """
5515 """
5516 overrides = [cmd for cmd in cmdtable if cmd in table]
5516 overrides = [cmd for cmd in cmdtable if cmd in table]
5517 if overrides:
5517 if overrides:
5518 ui.warn(_("extension '%s' overrides commands: %s\n")
5518 ui.warn(_("extension '%s' overrides commands: %s\n")
5519 % (name, " ".join(overrides)))
5519 % (name, " ".join(overrides)))
5520 table.update(cmdtable)
5520 table.update(cmdtable)
@@ -1,664 +1,666
1 # help.py - help data for mercurial
1 # help.py - help data for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 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 itertools
10 import itertools
11 import os
11 import os
12 import textwrap
12 import textwrap
13
13
14 from .i18n import (
14 from .i18n import (
15 _,
15 _,
16 gettext,
16 gettext,
17 )
17 )
18 from . import (
18 from . import (
19 cmdutil,
19 cmdutil,
20 encoding,
20 encoding,
21 error,
21 error,
22 extensions,
22 extensions,
23 filemerge,
23 filemerge,
24 fileset,
24 fileset,
25 minirst,
25 minirst,
26 pycompat,
26 revset,
27 revset,
27 templatefilters,
28 templatefilters,
28 templatekw,
29 templatekw,
29 templater,
30 templater,
30 util,
31 util,
31 )
32 )
32 from .hgweb import (
33 from .hgweb import (
33 webcommands,
34 webcommands,
34 )
35 )
35
36
36 _exclkeywords = set([
37 _exclkeywords = set([
37 "(ADVANCED)",
38 "(ADVANCED)",
38 "(DEPRECATED)",
39 "(DEPRECATED)",
39 "(EXPERIMENTAL)",
40 "(EXPERIMENTAL)",
40 # i18n: "(ADVANCED)" is a keyword, must be translated consistently
41 # i18n: "(ADVANCED)" is a keyword, must be translated consistently
41 _("(ADVANCED)"),
42 _("(ADVANCED)"),
42 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
43 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
43 _("(DEPRECATED)"),
44 _("(DEPRECATED)"),
44 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
45 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
45 _("(EXPERIMENTAL)"),
46 _("(EXPERIMENTAL)"),
46 ])
47 ])
47
48
48 def listexts(header, exts, indent=1, showdeprecated=False):
49 def listexts(header, exts, indent=1, showdeprecated=False):
49 '''return a text listing of the given extensions'''
50 '''return a text listing of the given extensions'''
50 rst = []
51 rst = []
51 if exts:
52 if exts:
52 for name, desc in sorted(exts.iteritems()):
53 for name, desc in sorted(exts.iteritems()):
53 if not showdeprecated and any(w in desc for w in _exclkeywords):
54 if not showdeprecated and any(w in desc for w in _exclkeywords):
54 continue
55 continue
55 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
56 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
56 if rst:
57 if rst:
57 rst.insert(0, '\n%s\n\n' % header)
58 rst.insert(0, '\n%s\n\n' % header)
58 return rst
59 return rst
59
60
60 def extshelp(ui):
61 def extshelp(ui):
61 rst = loaddoc('extensions')(ui).splitlines(True)
62 rst = loaddoc('extensions')(ui).splitlines(True)
62 rst.extend(listexts(
63 rst.extend(listexts(
63 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
64 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
64 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
65 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
65 doc = ''.join(rst)
66 doc = ''.join(rst)
66 return doc
67 return doc
67
68
68 def optrst(header, options, verbose):
69 def optrst(header, options, verbose):
69 data = []
70 data = []
70 multioccur = False
71 multioccur = False
71 for option in options:
72 for option in options:
72 if len(option) == 5:
73 if len(option) == 5:
73 shortopt, longopt, default, desc, optlabel = option
74 shortopt, longopt, default, desc, optlabel = option
74 else:
75 else:
75 shortopt, longopt, default, desc = option
76 shortopt, longopt, default, desc = option
76 optlabel = _("VALUE") # default label
77 optlabel = _("VALUE") # default label
77
78
78 if not verbose and any(w in desc for w in _exclkeywords):
79 if not verbose and any(w in desc for w in _exclkeywords):
79 continue
80 continue
80
81
81 so = ''
82 so = ''
82 if shortopt:
83 if shortopt:
83 so = '-' + shortopt
84 so = '-' + shortopt
84 lo = '--' + longopt
85 lo = '--' + longopt
85 if default:
86 if default:
86 desc += _(" (default: %s)") % default
87 desc += _(" (default: %s)") % default
87
88
88 if isinstance(default, list):
89 if isinstance(default, list):
89 lo += " %s [+]" % optlabel
90 lo += " %s [+]" % optlabel
90 multioccur = True
91 multioccur = True
91 elif (default is not None) and not isinstance(default, bool):
92 elif (default is not None) and not isinstance(default, bool):
92 lo += " %s" % optlabel
93 lo += " %s" % optlabel
93
94
94 data.append((so, lo, desc))
95 data.append((so, lo, desc))
95
96
96 if multioccur:
97 if multioccur:
97 header += (_(" ([+] can be repeated)"))
98 header += (_(" ([+] can be repeated)"))
98
99
99 rst = ['\n%s:\n\n' % header]
100 rst = ['\n%s:\n\n' % header]
100 rst.extend(minirst.maketable(data, 1))
101 rst.extend(minirst.maketable(data, 1))
101
102
102 return ''.join(rst)
103 return ''.join(rst)
103
104
104 def indicateomitted(rst, omitted, notomitted=None):
105 def indicateomitted(rst, omitted, notomitted=None):
105 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
106 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
106 if notomitted:
107 if notomitted:
107 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
108 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
108
109
109 def filtercmd(ui, cmd, kw, doc):
110 def filtercmd(ui, cmd, kw, doc):
110 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
111 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
111 return True
112 return True
112 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
113 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
113 return True
114 return True
114 return False
115 return False
115
116
116 def topicmatch(ui, kw):
117 def topicmatch(ui, kw):
117 """Return help topics matching kw.
118 """Return help topics matching kw.
118
119
119 Returns {'section': [(name, summary), ...], ...} where section is
120 Returns {'section': [(name, summary), ...], ...} where section is
120 one of topics, commands, extensions, or extensioncommands.
121 one of topics, commands, extensions, or extensioncommands.
121 """
122 """
122 kw = encoding.lower(kw)
123 kw = encoding.lower(kw)
123 def lowercontains(container):
124 def lowercontains(container):
124 return kw in encoding.lower(container) # translated in helptable
125 return kw in encoding.lower(container) # translated in helptable
125 results = {'topics': [],
126 results = {'topics': [],
126 'commands': [],
127 'commands': [],
127 'extensions': [],
128 'extensions': [],
128 'extensioncommands': [],
129 'extensioncommands': [],
129 }
130 }
130 for names, header, doc in helptable:
131 for names, header, doc in helptable:
131 # Old extensions may use a str as doc.
132 # Old extensions may use a str as doc.
132 if (sum(map(lowercontains, names))
133 if (sum(map(lowercontains, names))
133 or lowercontains(header)
134 or lowercontains(header)
134 or (callable(doc) and lowercontains(doc(ui)))):
135 or (callable(doc) and lowercontains(doc(ui)))):
135 results['topics'].append((names[0], header))
136 results['topics'].append((names[0], header))
136 from . import commands # avoid cycle
137 from . import commands # avoid cycle
137 for cmd, entry in commands.table.iteritems():
138 for cmd, entry in commands.table.iteritems():
138 if len(entry) == 3:
139 if len(entry) == 3:
139 summary = entry[2]
140 summary = entry[2]
140 else:
141 else:
141 summary = ''
142 summary = ''
142 # translate docs *before* searching there
143 # translate docs *before* searching there
143 docs = _(getattr(entry[0], '__doc__', None)) or ''
144 docs = _(getattr(entry[0], '__doc__', None)) or ''
144 if kw in cmd or lowercontains(summary) or lowercontains(docs):
145 if kw in cmd or lowercontains(summary) or lowercontains(docs):
145 doclines = docs.splitlines()
146 doclines = docs.splitlines()
146 if doclines:
147 if doclines:
147 summary = doclines[0]
148 summary = doclines[0]
148 cmdname = cmd.partition('|')[0].lstrip('^')
149 cmdname = cmd.partition('|')[0].lstrip('^')
149 if filtercmd(ui, cmdname, kw, docs):
150 if filtercmd(ui, cmdname, kw, docs):
150 continue
151 continue
151 results['commands'].append((cmdname, summary))
152 results['commands'].append((cmdname, summary))
152 for name, docs in itertools.chain(
153 for name, docs in itertools.chain(
153 extensions.enabled(False).iteritems(),
154 extensions.enabled(False).iteritems(),
154 extensions.disabled().iteritems()):
155 extensions.disabled().iteritems()):
155 if not docs:
156 if not docs:
156 continue
157 continue
157 mod = extensions.load(ui, name, '')
158 mod = extensions.load(ui, name, '')
158 name = name.rpartition('.')[-1]
159 name = name.rpartition('.')[-1]
159 if lowercontains(name) or lowercontains(docs):
160 if lowercontains(name) or lowercontains(docs):
160 # extension docs are already translated
161 # extension docs are already translated
161 results['extensions'].append((name, docs.splitlines()[0]))
162 results['extensions'].append((name, docs.splitlines()[0]))
162 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
163 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
163 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
164 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
164 cmdname = cmd.partition('|')[0].lstrip('^')
165 cmdname = cmd.partition('|')[0].lstrip('^')
165 if entry[0].__doc__:
166 if entry[0].__doc__:
166 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
167 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
167 else:
168 else:
168 cmddoc = _('(no help text available)')
169 cmddoc = _('(no help text available)')
169 if filtercmd(ui, cmdname, kw, cmddoc):
170 if filtercmd(ui, cmdname, kw, cmddoc):
170 continue
171 continue
171 results['extensioncommands'].append((cmdname, cmddoc))
172 results['extensioncommands'].append((cmdname, cmddoc))
172 return results
173 return results
173
174
174 def loaddoc(topic, subdir=None):
175 def loaddoc(topic, subdir=None):
175 """Return a delayed loader for help/topic.txt."""
176 """Return a delayed loader for help/topic.txt."""
176
177
177 def loader(ui):
178 def loader(ui):
178 docdir = os.path.join(util.datapath, 'help')
179 docdir = os.path.join(util.datapath, 'help')
179 if subdir:
180 if subdir:
180 docdir = os.path.join(docdir, subdir)
181 docdir = os.path.join(docdir, subdir)
181 path = os.path.join(docdir, topic + ".txt")
182 path = os.path.join(docdir, topic + ".txt")
182 doc = gettext(util.readfile(path))
183 doc = gettext(util.readfile(path))
183 for rewriter in helphooks.get(topic, []):
184 for rewriter in helphooks.get(topic, []):
184 doc = rewriter(ui, topic, doc)
185 doc = rewriter(ui, topic, doc)
185 return doc
186 return doc
186
187
187 return loader
188 return loader
188
189
189 internalstable = sorted([
190 internalstable = sorted([
190 (['bundles'], _('Bundles'),
191 (['bundles'], _('Bundles'),
191 loaddoc('bundles', subdir='internals')),
192 loaddoc('bundles', subdir='internals')),
192 (['censor'], _('Censor'),
193 (['censor'], _('Censor'),
193 loaddoc('censor', subdir='internals')),
194 loaddoc('censor', subdir='internals')),
194 (['changegroups'], _('Changegroups'),
195 (['changegroups'], _('Changegroups'),
195 loaddoc('changegroups', subdir='internals')),
196 loaddoc('changegroups', subdir='internals')),
196 (['requirements'], _('Repository Requirements'),
197 (['requirements'], _('Repository Requirements'),
197 loaddoc('requirements', subdir='internals')),
198 loaddoc('requirements', subdir='internals')),
198 (['revlogs'], _('Revision Logs'),
199 (['revlogs'], _('Revision Logs'),
199 loaddoc('revlogs', subdir='internals')),
200 loaddoc('revlogs', subdir='internals')),
200 (['wireprotocol'], _('Wire Protocol'),
201 (['wireprotocol'], _('Wire Protocol'),
201 loaddoc('wireprotocol', subdir='internals')),
202 loaddoc('wireprotocol', subdir='internals')),
202 ])
203 ])
203
204
204 def internalshelp(ui):
205 def internalshelp(ui):
205 """Generate the index for the "internals" topic."""
206 """Generate the index for the "internals" topic."""
206 lines = ['To access a subtopic, use "hg help internals.{subtopic-name}"\n',
207 lines = ['To access a subtopic, use "hg help internals.{subtopic-name}"\n',
207 '\n']
208 '\n']
208 for names, header, doc in internalstable:
209 for names, header, doc in internalstable:
209 lines.append(' :%s: %s\n' % (names[0], header))
210 lines.append(' :%s: %s\n' % (names[0], header))
210
211
211 return ''.join(lines)
212 return ''.join(lines)
212
213
213 helptable = sorted([
214 helptable = sorted([
214 (['bundlespec'], _("Bundle File Formats"), loaddoc('bundlespec')),
215 (['bundlespec'], _("Bundle File Formats"), loaddoc('bundlespec')),
215 (['color'], _("Colorizing Outputs"), loaddoc('color')),
216 (['color'], _("Colorizing Outputs"), loaddoc('color')),
216 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
217 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
217 (["dates"], _("Date Formats"), loaddoc('dates')),
218 (["dates"], _("Date Formats"), loaddoc('dates')),
218 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
219 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
219 (['environment', 'env'], _('Environment Variables'),
220 (['environment', 'env'], _('Environment Variables'),
220 loaddoc('environment')),
221 loaddoc('environment')),
221 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
222 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
222 _('Specifying Revisions'), loaddoc('revisions')),
223 _('Specifying Revisions'), loaddoc('revisions')),
223 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
224 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
224 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
225 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
225 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
226 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
226 loaddoc('merge-tools')),
227 loaddoc('merge-tools')),
227 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
228 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
228 loaddoc('templates')),
229 loaddoc('templates')),
229 (['urls'], _('URL Paths'), loaddoc('urls')),
230 (['urls'], _('URL Paths'), loaddoc('urls')),
230 (["extensions"], _("Using Additional Features"), extshelp),
231 (["extensions"], _("Using Additional Features"), extshelp),
231 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
232 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
232 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
233 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
233 (["glossary"], _("Glossary"), loaddoc('glossary')),
234 (["glossary"], _("Glossary"), loaddoc('glossary')),
234 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
235 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
235 loaddoc('hgignore')),
236 loaddoc('hgignore')),
236 (["phases"], _("Working with Phases"), loaddoc('phases')),
237 (["phases"], _("Working with Phases"), loaddoc('phases')),
237 (['scripting'], _('Using Mercurial from scripts and automation'),
238 (['scripting'], _('Using Mercurial from scripts and automation'),
238 loaddoc('scripting')),
239 loaddoc('scripting')),
239 (['internals'], _("Technical implementation topics"),
240 (['internals'], _("Technical implementation topics"),
240 internalshelp),
241 internalshelp),
241 (['pager'], _("Pager Support"), loaddoc('pager')),
242 (['pager'], _("Pager Support"), loaddoc('pager')),
242 ])
243 ])
243
244
244 # Maps topics with sub-topics to a list of their sub-topics.
245 # Maps topics with sub-topics to a list of their sub-topics.
245 subtopics = {
246 subtopics = {
246 'internals': internalstable,
247 'internals': internalstable,
247 }
248 }
248
249
249 # Map topics to lists of callable taking the current topic help and
250 # Map topics to lists of callable taking the current topic help and
250 # returning the updated version
251 # returning the updated version
251 helphooks = {}
252 helphooks = {}
252
253
253 def addtopichook(topic, rewriter):
254 def addtopichook(topic, rewriter):
254 helphooks.setdefault(topic, []).append(rewriter)
255 helphooks.setdefault(topic, []).append(rewriter)
255
256
256 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
257 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
257 """Extract docstring from the items key to function mapping, build a
258 """Extract docstring from the items key to function mapping, build a
258 single documentation block and use it to overwrite the marker in doc.
259 single documentation block and use it to overwrite the marker in doc.
259 """
260 """
260 entries = []
261 entries = []
261 for name in sorted(items):
262 for name in sorted(items):
262 text = (items[name].__doc__ or '').rstrip()
263 text = (items[name].__doc__ or '').rstrip()
263 if (not text
264 if (not text
264 or not ui.verbose and any(w in text for w in _exclkeywords)):
265 or not ui.verbose and any(w in text for w in _exclkeywords)):
265 continue
266 continue
266 text = gettext(text)
267 text = gettext(text)
267 if dedent:
268 if dedent:
268 text = textwrap.dedent(text)
269 text = textwrap.dedent(text)
269 lines = text.splitlines()
270 lines = text.splitlines()
270 doclines = [(lines[0])]
271 doclines = [(lines[0])]
271 for l in lines[1:]:
272 for l in lines[1:]:
272 # Stop once we find some Python doctest
273 # Stop once we find some Python doctest
273 if l.strip().startswith('>>>'):
274 if l.strip().startswith('>>>'):
274 break
275 break
275 if dedent:
276 if dedent:
276 doclines.append(l.rstrip())
277 doclines.append(l.rstrip())
277 else:
278 else:
278 doclines.append(' ' + l.strip())
279 doclines.append(' ' + l.strip())
279 entries.append('\n'.join(doclines))
280 entries.append('\n'.join(doclines))
280 entries = '\n\n'.join(entries)
281 entries = '\n\n'.join(entries)
281 return doc.replace(marker, entries)
282 return doc.replace(marker, entries)
282
283
283 def addtopicsymbols(topic, marker, symbols, dedent=False):
284 def addtopicsymbols(topic, marker, symbols, dedent=False):
284 def add(ui, topic, doc):
285 def add(ui, topic, doc):
285 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
286 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
286 addtopichook(topic, add)
287 addtopichook(topic, add)
287
288
288 addtopicsymbols('bundlespec', '.. bundlecompressionmarker',
289 addtopicsymbols('bundlespec', '.. bundlecompressionmarker',
289 util.bundlecompressiontopics())
290 util.bundlecompressiontopics())
290 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
291 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
291 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
292 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
292 filemerge.internalsdoc)
293 filemerge.internalsdoc)
293 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
294 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
294 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
295 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
295 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
296 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
296 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
297 addtopicsymbols('templates', '.. functionsmarker', templater.funcs)
297 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
298 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
298 dedent=True)
299 dedent=True)
299
300
300 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
301 def help_(ui, name, unknowncmd=False, full=True, subtopic=None, **opts):
301 '''
302 '''
302 Generate the help for 'name' as unformatted restructured text. If
303 Generate the help for 'name' as unformatted restructured text. If
303 'name' is None, describe the commands available.
304 'name' is None, describe the commands available.
304 '''
305 '''
305
306
306 from . import commands # avoid cycle
307 from . import commands # avoid cycle
308 opts = pycompat.byteskwargs(opts)
307
309
308 def helpcmd(name, subtopic=None):
310 def helpcmd(name, subtopic=None):
309 try:
311 try:
310 aliases, entry = cmdutil.findcmd(name, commands.table,
312 aliases, entry = cmdutil.findcmd(name, commands.table,
311 strict=unknowncmd)
313 strict=unknowncmd)
312 except error.AmbiguousCommand as inst:
314 except error.AmbiguousCommand as inst:
313 # py3k fix: except vars can't be used outside the scope of the
315 # py3k fix: except vars can't be used outside the scope of the
314 # except block, nor can be used inside a lambda. python issue4617
316 # except block, nor can be used inside a lambda. python issue4617
315 prefix = inst.args[0]
317 prefix = inst.args[0]
316 select = lambda c: c.lstrip('^').startswith(prefix)
318 select = lambda c: c.lstrip('^').startswith(prefix)
317 rst = helplist(select)
319 rst = helplist(select)
318 return rst
320 return rst
319
321
320 rst = []
322 rst = []
321
323
322 # check if it's an invalid alias and display its error if it is
324 # check if it's an invalid alias and display its error if it is
323 if getattr(entry[0], 'badalias', None):
325 if getattr(entry[0], 'badalias', None):
324 rst.append(entry[0].badalias + '\n')
326 rst.append(entry[0].badalias + '\n')
325 if entry[0].unknowncmd:
327 if entry[0].unknowncmd:
326 try:
328 try:
327 rst.extend(helpextcmd(entry[0].cmdname))
329 rst.extend(helpextcmd(entry[0].cmdname))
328 except error.UnknownCommand:
330 except error.UnknownCommand:
329 pass
331 pass
330 return rst
332 return rst
331
333
332 # synopsis
334 # synopsis
333 if len(entry) > 2:
335 if len(entry) > 2:
334 if entry[2].startswith('hg'):
336 if entry[2].startswith('hg'):
335 rst.append("%s\n" % entry[2])
337 rst.append("%s\n" % entry[2])
336 else:
338 else:
337 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
339 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
338 else:
340 else:
339 rst.append('hg %s\n' % aliases[0])
341 rst.append('hg %s\n' % aliases[0])
340 # aliases
342 # aliases
341 if full and not ui.quiet and len(aliases) > 1:
343 if full and not ui.quiet and len(aliases) > 1:
342 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
344 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
343 rst.append('\n')
345 rst.append('\n')
344
346
345 # description
347 # description
346 doc = gettext(entry[0].__doc__)
348 doc = gettext(entry[0].__doc__)
347 if not doc:
349 if not doc:
348 doc = _("(no help text available)")
350 doc = _("(no help text available)")
349 if util.safehasattr(entry[0], 'definition'): # aliased command
351 if util.safehasattr(entry[0], 'definition'): # aliased command
350 source = entry[0].source
352 source = entry[0].source
351 if entry[0].definition.startswith('!'): # shell alias
353 if entry[0].definition.startswith('!'): # shell alias
352 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
354 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
353 (entry[0].definition[1:], source))
355 (entry[0].definition[1:], source))
354 else:
356 else:
355 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
357 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
356 (entry[0].definition, doc, source))
358 (entry[0].definition, doc, source))
357 doc = doc.splitlines(True)
359 doc = doc.splitlines(True)
358 if ui.quiet or not full:
360 if ui.quiet or not full:
359 rst.append(doc[0])
361 rst.append(doc[0])
360 else:
362 else:
361 rst.extend(doc)
363 rst.extend(doc)
362 rst.append('\n')
364 rst.append('\n')
363
365
364 # check if this command shadows a non-trivial (multi-line)
366 # check if this command shadows a non-trivial (multi-line)
365 # extension help text
367 # extension help text
366 try:
368 try:
367 mod = extensions.find(name)
369 mod = extensions.find(name)
368 doc = gettext(mod.__doc__) or ''
370 doc = gettext(mod.__doc__) or ''
369 if '\n' in doc.strip():
371 if '\n' in doc.strip():
370 msg = _("(use 'hg help -e %s' to show help for "
372 msg = _("(use 'hg help -e %s' to show help for "
371 "the %s extension)") % (name, name)
373 "the %s extension)") % (name, name)
372 rst.append('\n%s\n' % msg)
374 rst.append('\n%s\n' % msg)
373 except KeyError:
375 except KeyError:
374 pass
376 pass
375
377
376 # options
378 # options
377 if not ui.quiet and entry[1]:
379 if not ui.quiet and entry[1]:
378 rst.append(optrst(_("options"), entry[1], ui.verbose))
380 rst.append(optrst(_("options"), entry[1], ui.verbose))
379
381
380 if ui.verbose:
382 if ui.verbose:
381 rst.append(optrst(_("global options"),
383 rst.append(optrst(_("global options"),
382 commands.globalopts, ui.verbose))
384 commands.globalopts, ui.verbose))
383
385
384 if not ui.verbose:
386 if not ui.verbose:
385 if not full:
387 if not full:
386 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
388 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
387 % name)
389 % name)
388 elif not ui.quiet:
390 elif not ui.quiet:
389 rst.append(_('\n(some details hidden, use --verbose '
391 rst.append(_('\n(some details hidden, use --verbose '
390 'to show complete help)'))
392 'to show complete help)'))
391
393
392 return rst
394 return rst
393
395
394
396
395 def helplist(select=None, **opts):
397 def helplist(select=None, **opts):
396 # list of commands
398 # list of commands
397 if name == "shortlist":
399 if name == "shortlist":
398 header = _('basic commands:\n\n')
400 header = _('basic commands:\n\n')
399 elif name == "debug":
401 elif name == "debug":
400 header = _('debug commands (internal and unsupported):\n\n')
402 header = _('debug commands (internal and unsupported):\n\n')
401 else:
403 else:
402 header = _('list of commands:\n\n')
404 header = _('list of commands:\n\n')
403
405
404 h = {}
406 h = {}
405 cmds = {}
407 cmds = {}
406 for c, e in commands.table.iteritems():
408 for c, e in commands.table.iteritems():
407 f = c.partition("|")[0]
409 f = c.partition("|")[0]
408 if select and not select(f):
410 if select and not select(f):
409 continue
411 continue
410 if (not select and name != 'shortlist' and
412 if (not select and name != 'shortlist' and
411 e[0].__module__ != commands.__name__):
413 e[0].__module__ != commands.__name__):
412 continue
414 continue
413 if name == "shortlist" and not f.startswith("^"):
415 if name == "shortlist" and not f.startswith("^"):
414 continue
416 continue
415 f = f.lstrip("^")
417 f = f.lstrip("^")
416 doc = e[0].__doc__
418 doc = e[0].__doc__
417 if filtercmd(ui, f, name, doc):
419 if filtercmd(ui, f, name, doc):
418 continue
420 continue
419 doc = gettext(doc)
421 doc = gettext(doc)
420 if not doc:
422 if not doc:
421 doc = _("(no help text available)")
423 doc = _("(no help text available)")
422 h[f] = doc.splitlines()[0].rstrip()
424 h[f] = doc.splitlines()[0].rstrip()
423 cmds[f] = c.lstrip("^")
425 cmds[f] = c.lstrip("^")
424
426
425 rst = []
427 rst = []
426 if not h:
428 if not h:
427 if not ui.quiet:
429 if not ui.quiet:
428 rst.append(_('no commands defined\n'))
430 rst.append(_('no commands defined\n'))
429 return rst
431 return rst
430
432
431 if not ui.quiet:
433 if not ui.quiet:
432 rst.append(header)
434 rst.append(header)
433 fns = sorted(h)
435 fns = sorted(h)
434 for f in fns:
436 for f in fns:
435 if ui.verbose:
437 if ui.verbose:
436 commacmds = cmds[f].replace("|",", ")
438 commacmds = cmds[f].replace("|",", ")
437 rst.append(" :%s: %s\n" % (commacmds, h[f]))
439 rst.append(" :%s: %s\n" % (commacmds, h[f]))
438 else:
440 else:
439 rst.append(' :%s: %s\n' % (f, h[f]))
441 rst.append(' :%s: %s\n' % (f, h[f]))
440
442
441 ex = opts.get
443 ex = opts.get
442 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
444 anyopts = (ex('keyword') or not (ex('command') or ex('extension')))
443 if not name and anyopts:
445 if not name and anyopts:
444 exts = listexts(_('enabled extensions:'), extensions.enabled())
446 exts = listexts(_('enabled extensions:'), extensions.enabled())
445 if exts:
447 if exts:
446 rst.append('\n')
448 rst.append('\n')
447 rst.extend(exts)
449 rst.extend(exts)
448
450
449 rst.append(_("\nadditional help topics:\n\n"))
451 rst.append(_("\nadditional help topics:\n\n"))
450 topics = []
452 topics = []
451 for names, header, doc in helptable:
453 for names, header, doc in helptable:
452 topics.append((names[0], header))
454 topics.append((names[0], header))
453 for t, desc in topics:
455 for t, desc in topics:
454 rst.append(" :%s: %s\n" % (t, desc))
456 rst.append(" :%s: %s\n" % (t, desc))
455
457
456 if ui.quiet:
458 if ui.quiet:
457 pass
459 pass
458 elif ui.verbose:
460 elif ui.verbose:
459 rst.append('\n%s\n' % optrst(_("global options"),
461 rst.append('\n%s\n' % optrst(_("global options"),
460 commands.globalopts, ui.verbose))
462 commands.globalopts, ui.verbose))
461 if name == 'shortlist':
463 if name == 'shortlist':
462 rst.append(_("\n(use 'hg help' for the full list "
464 rst.append(_("\n(use 'hg help' for the full list "
463 "of commands)\n"))
465 "of commands)\n"))
464 else:
466 else:
465 if name == 'shortlist':
467 if name == 'shortlist':
466 rst.append(_("\n(use 'hg help' for the full list of commands "
468 rst.append(_("\n(use 'hg help' for the full list of commands "
467 "or 'hg -v' for details)\n"))
469 "or 'hg -v' for details)\n"))
468 elif name and not full:
470 elif name and not full:
469 rst.append(_("\n(use 'hg help %s' to show the full help "
471 rst.append(_("\n(use 'hg help %s' to show the full help "
470 "text)\n") % name)
472 "text)\n") % name)
471 elif name and cmds and name in cmds.keys():
473 elif name and cmds and name in cmds.keys():
472 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
474 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
473 "aliases and global options)\n") % name)
475 "aliases and global options)\n") % name)
474 else:
476 else:
475 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
477 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
476 "and global options)\n")
478 "and global options)\n")
477 % (name and " " + name or ""))
479 % (name and " " + name or ""))
478 return rst
480 return rst
479
481
480 def helptopic(name, subtopic=None):
482 def helptopic(name, subtopic=None):
481 # Look for sub-topic entry first.
483 # Look for sub-topic entry first.
482 header, doc = None, None
484 header, doc = None, None
483 if subtopic and name in subtopics:
485 if subtopic and name in subtopics:
484 for names, header, doc in subtopics[name]:
486 for names, header, doc in subtopics[name]:
485 if subtopic in names:
487 if subtopic in names:
486 break
488 break
487
489
488 if not header:
490 if not header:
489 for names, header, doc in helptable:
491 for names, header, doc in helptable:
490 if name in names:
492 if name in names:
491 break
493 break
492 else:
494 else:
493 raise error.UnknownCommand(name)
495 raise error.UnknownCommand(name)
494
496
495 rst = [minirst.section(header)]
497 rst = [minirst.section(header)]
496
498
497 # description
499 # description
498 if not doc:
500 if not doc:
499 rst.append(" %s\n" % _("(no help text available)"))
501 rst.append(" %s\n" % _("(no help text available)"))
500 if callable(doc):
502 if callable(doc):
501 rst += [" %s\n" % l for l in doc(ui).splitlines()]
503 rst += [" %s\n" % l for l in doc(ui).splitlines()]
502
504
503 if not ui.verbose:
505 if not ui.verbose:
504 omitted = _('(some details hidden, use --verbose'
506 omitted = _('(some details hidden, use --verbose'
505 ' to show complete help)')
507 ' to show complete help)')
506 indicateomitted(rst, omitted)
508 indicateomitted(rst, omitted)
507
509
508 try:
510 try:
509 cmdutil.findcmd(name, commands.table)
511 cmdutil.findcmd(name, commands.table)
510 rst.append(_("\nuse 'hg help -c %s' to see help for "
512 rst.append(_("\nuse 'hg help -c %s' to see help for "
511 "the %s command\n") % (name, name))
513 "the %s command\n") % (name, name))
512 except error.UnknownCommand:
514 except error.UnknownCommand:
513 pass
515 pass
514 return rst
516 return rst
515
517
516 def helpext(name, subtopic=None):
518 def helpext(name, subtopic=None):
517 try:
519 try:
518 mod = extensions.find(name)
520 mod = extensions.find(name)
519 doc = gettext(mod.__doc__) or _('no help text available')
521 doc = gettext(mod.__doc__) or _('no help text available')
520 except KeyError:
522 except KeyError:
521 mod = None
523 mod = None
522 doc = extensions.disabledext(name)
524 doc = extensions.disabledext(name)
523 if not doc:
525 if not doc:
524 raise error.UnknownCommand(name)
526 raise error.UnknownCommand(name)
525
527
526 if '\n' not in doc:
528 if '\n' not in doc:
527 head, tail = doc, ""
529 head, tail = doc, ""
528 else:
530 else:
529 head, tail = doc.split('\n', 1)
531 head, tail = doc.split('\n', 1)
530 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
532 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
531 if tail:
533 if tail:
532 rst.extend(tail.splitlines(True))
534 rst.extend(tail.splitlines(True))
533 rst.append('\n')
535 rst.append('\n')
534
536
535 if not ui.verbose:
537 if not ui.verbose:
536 omitted = _('(some details hidden, use --verbose'
538 omitted = _('(some details hidden, use --verbose'
537 ' to show complete help)')
539 ' to show complete help)')
538 indicateomitted(rst, omitted)
540 indicateomitted(rst, omitted)
539
541
540 if mod:
542 if mod:
541 try:
543 try:
542 ct = mod.cmdtable
544 ct = mod.cmdtable
543 except AttributeError:
545 except AttributeError:
544 ct = {}
546 ct = {}
545 modcmds = set([c.partition('|')[0] for c in ct])
547 modcmds = set([c.partition('|')[0] for c in ct])
546 rst.extend(helplist(modcmds.__contains__))
548 rst.extend(helplist(modcmds.__contains__))
547 else:
549 else:
548 rst.append(_("(use 'hg help extensions' for information on enabling"
550 rst.append(_("(use 'hg help extensions' for information on enabling"
549 " extensions)\n"))
551 " extensions)\n"))
550 return rst
552 return rst
551
553
552 def helpextcmd(name, subtopic=None):
554 def helpextcmd(name, subtopic=None):
553 cmd, ext, mod = extensions.disabledcmd(ui, name,
555 cmd, ext, mod = extensions.disabledcmd(ui, name,
554 ui.configbool('ui', 'strict'))
556 ui.configbool('ui', 'strict'))
555 doc = gettext(mod.__doc__).splitlines()[0]
557 doc = gettext(mod.__doc__).splitlines()[0]
556
558
557 rst = listexts(_("'%s' is provided by the following "
559 rst = listexts(_("'%s' is provided by the following "
558 "extension:") % cmd, {ext: doc}, indent=4,
560 "extension:") % cmd, {ext: doc}, indent=4,
559 showdeprecated=True)
561 showdeprecated=True)
560 rst.append('\n')
562 rst.append('\n')
561 rst.append(_("(use 'hg help extensions' for information on enabling "
563 rst.append(_("(use 'hg help extensions' for information on enabling "
562 "extensions)\n"))
564 "extensions)\n"))
563 return rst
565 return rst
564
566
565
567
566 rst = []
568 rst = []
567 kw = opts.get('keyword')
569 kw = opts.get('keyword')
568 if kw or name is None and any(opts[o] for o in opts):
570 if kw or name is None and any(opts[o] for o in opts):
569 matches = topicmatch(ui, name or '')
571 matches = topicmatch(ui, name or '')
570 helpareas = []
572 helpareas = []
571 if opts.get('extension'):
573 if opts.get('extension'):
572 helpareas += [('extensions', _('Extensions'))]
574 helpareas += [('extensions', _('Extensions'))]
573 if opts.get('command'):
575 if opts.get('command'):
574 helpareas += [('commands', _('Commands'))]
576 helpareas += [('commands', _('Commands'))]
575 if not helpareas:
577 if not helpareas:
576 helpareas = [('topics', _('Topics')),
578 helpareas = [('topics', _('Topics')),
577 ('commands', _('Commands')),
579 ('commands', _('Commands')),
578 ('extensions', _('Extensions')),
580 ('extensions', _('Extensions')),
579 ('extensioncommands', _('Extension Commands'))]
581 ('extensioncommands', _('Extension Commands'))]
580 for t, title in helpareas:
582 for t, title in helpareas:
581 if matches[t]:
583 if matches[t]:
582 rst.append('%s:\n\n' % title)
584 rst.append('%s:\n\n' % title)
583 rst.extend(minirst.maketable(sorted(matches[t]), 1))
585 rst.extend(minirst.maketable(sorted(matches[t]), 1))
584 rst.append('\n')
586 rst.append('\n')
585 if not rst:
587 if not rst:
586 msg = _('no matches')
588 msg = _('no matches')
587 hint = _("try 'hg help' for a list of topics")
589 hint = _("try 'hg help' for a list of topics")
588 raise error.Abort(msg, hint=hint)
590 raise error.Abort(msg, hint=hint)
589 elif name and name != 'shortlist':
591 elif name and name != 'shortlist':
590 queries = []
592 queries = []
591 if unknowncmd:
593 if unknowncmd:
592 queries += [helpextcmd]
594 queries += [helpextcmd]
593 if opts.get('extension'):
595 if opts.get('extension'):
594 queries += [helpext]
596 queries += [helpext]
595 if opts.get('command'):
597 if opts.get('command'):
596 queries += [helpcmd]
598 queries += [helpcmd]
597 if not queries:
599 if not queries:
598 queries = (helptopic, helpcmd, helpext, helpextcmd)
600 queries = (helptopic, helpcmd, helpext, helpextcmd)
599 for f in queries:
601 for f in queries:
600 try:
602 try:
601 rst = f(name, subtopic)
603 rst = f(name, subtopic)
602 break
604 break
603 except error.UnknownCommand:
605 except error.UnknownCommand:
604 pass
606 pass
605 else:
607 else:
606 if unknowncmd:
608 if unknowncmd:
607 raise error.UnknownCommand(name)
609 raise error.UnknownCommand(name)
608 else:
610 else:
609 msg = _('no such help topic: %s') % name
611 msg = _('no such help topic: %s') % name
610 hint = _("try 'hg help --keyword %s'") % name
612 hint = _("try 'hg help --keyword %s'") % name
611 raise error.Abort(msg, hint=hint)
613 raise error.Abort(msg, hint=hint)
612 else:
614 else:
613 # program name
615 # program name
614 if not ui.quiet:
616 if not ui.quiet:
615 rst = [_("Mercurial Distributed SCM\n"), '\n']
617 rst = [_("Mercurial Distributed SCM\n"), '\n']
616 rst.extend(helplist(None, **opts))
618 rst.extend(helplist(None, **opts))
617
619
618 return ''.join(rst)
620 return ''.join(rst)
619
621
620 def formattedhelp(ui, name, keep=None, unknowncmd=False, full=True, **opts):
622 def formattedhelp(ui, name, keep=None, unknowncmd=False, full=True, **opts):
621 """get help for a given topic (as a dotted name) as rendered rst
623 """get help for a given topic (as a dotted name) as rendered rst
622
624
623 Either returns the rendered help text or raises an exception.
625 Either returns the rendered help text or raises an exception.
624 """
626 """
625 if keep is None:
627 if keep is None:
626 keep = []
628 keep = []
627 else:
629 else:
628 keep = list(keep) # make a copy so we can mutate this later
630 keep = list(keep) # make a copy so we can mutate this later
629 fullname = name
631 fullname = name
630 section = None
632 section = None
631 subtopic = None
633 subtopic = None
632 if name and '.' in name:
634 if name and '.' in name:
633 name, remaining = name.split('.', 1)
635 name, remaining = name.split('.', 1)
634 remaining = encoding.lower(remaining)
636 remaining = encoding.lower(remaining)
635 if '.' in remaining:
637 if '.' in remaining:
636 subtopic, section = remaining.split('.', 1)
638 subtopic, section = remaining.split('.', 1)
637 else:
639 else:
638 if name in subtopics:
640 if name in subtopics:
639 subtopic = remaining
641 subtopic = remaining
640 else:
642 else:
641 section = remaining
643 section = remaining
642 textwidth = ui.configint('ui', 'textwidth', 78)
644 textwidth = ui.configint('ui', 'textwidth', 78)
643 termwidth = ui.termwidth() - 2
645 termwidth = ui.termwidth() - 2
644 if textwidth <= 0 or termwidth < textwidth:
646 if textwidth <= 0 or termwidth < textwidth:
645 textwidth = termwidth
647 textwidth = termwidth
646 text = help_(ui, name,
648 text = help_(ui, name,
647 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
649 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
648
650
649 formatted, pruned = minirst.format(text, textwidth, keep=keep,
651 formatted, pruned = minirst.format(text, textwidth, keep=keep,
650 section=section)
652 section=section)
651
653
652 # We could have been given a weird ".foo" section without a name
654 # We could have been given a weird ".foo" section without a name
653 # to look for, or we could have simply failed to found "foo.bar"
655 # to look for, or we could have simply failed to found "foo.bar"
654 # because bar isn't a section of foo
656 # because bar isn't a section of foo
655 if section and not (formatted and name):
657 if section and not (formatted and name):
656 raise error.Abort(_("help section not found: %s") % fullname)
658 raise error.Abort(_("help section not found: %s") % fullname)
657
659
658 if 'verbose' in pruned:
660 if 'verbose' in pruned:
659 keep.append('omitted')
661 keep.append('omitted')
660 else:
662 else:
661 keep.append('notomitted')
663 keep.append('notomitted')
662 formatted, pruned = minirst.format(text, textwidth, keep=keep,
664 formatted, pruned = minirst.format(text, textwidth, keep=keep,
663 section=section)
665 section=section)
664 return formatted
666 return formatted
General Comments 0
You need to be logged in to leave comments. Login now