##// END OF EJS Templates
grep: enable all-files by default (BC)...
Sushil khanchi -
r43598:8cb5f96d default
parent child Browse files
Show More
@@ -1,7805 +1,7803 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 (
84 (
85 b'R',
85 b'R',
86 b'repository',
86 b'repository',
87 b'',
87 b'',
88 _(b'repository root directory or name of overlay bundle file'),
88 _(b'repository root directory or name of overlay bundle file'),
89 _(b'REPO'),
89 _(b'REPO'),
90 ),
90 ),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (
92 (
93 b'y',
93 b'y',
94 b'noninteractive',
94 b'noninteractive',
95 None,
95 None,
96 _(
96 _(
97 b'do not prompt, automatically pick the first choice for all prompts'
97 b'do not prompt, automatically pick the first choice for all prompts'
98 ),
98 ),
99 ),
99 ),
100 (b'q', b'quiet', None, _(b'suppress output')),
100 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
102 (
102 (
103 b'',
103 b'',
104 b'color',
104 b'color',
105 b'',
105 b'',
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # and should not be translated
107 # and should not be translated
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b'TYPE'),
109 _(b'TYPE'),
110 ),
110 ),
111 (
111 (
112 b'',
112 b'',
113 b'config',
113 b'config',
114 [],
114 [],
115 _(b'set/override config option (use \'section.name=value\')'),
115 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'CONFIG'),
116 _(b'CONFIG'),
117 ),
117 ),
118 (b'', b'debug', None, _(b'enable debugging output')),
118 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debugger', None, _(b'start debugger')),
119 (b'', b'debugger', None, _(b'start debugger')),
120 (
120 (
121 b'',
121 b'',
122 b'encoding',
122 b'encoding',
123 encoding.encoding,
123 encoding.encoding,
124 _(b'set the charset encoding'),
124 _(b'set the charset encoding'),
125 _(b'ENCODE'),
125 _(b'ENCODE'),
126 ),
126 ),
127 (
127 (
128 b'',
128 b'',
129 b'encodingmode',
129 b'encodingmode',
130 encoding.encodingmode,
130 encoding.encodingmode,
131 _(b'set the charset encoding mode'),
131 _(b'set the charset encoding mode'),
132 _(b'MODE'),
132 _(b'MODE'),
133 ),
133 ),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'time', None, _(b'time how long the command takes')),
135 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'profile', None, _(b'print command execution profile')),
136 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'version', None, _(b'output version information and exit')),
137 (b'', b'version', None, _(b'output version information and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (
140 (
141 b'',
141 b'',
142 b'pager',
142 b'pager',
143 b'auto',
143 b'auto',
144 _(b"when to paginate (boolean, always, auto, or never)"),
144 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b'TYPE'),
145 _(b'TYPE'),
146 ),
146 ),
147 ]
147 ]
148
148
149 dryrunopts = cmdutil.dryrunopts
149 dryrunopts = cmdutil.dryrunopts
150 remoteopts = cmdutil.remoteopts
150 remoteopts = cmdutil.remoteopts
151 walkopts = cmdutil.walkopts
151 walkopts = cmdutil.walkopts
152 commitopts = cmdutil.commitopts
152 commitopts = cmdutil.commitopts
153 commitopts2 = cmdutil.commitopts2
153 commitopts2 = cmdutil.commitopts2
154 commitopts3 = cmdutil.commitopts3
154 commitopts3 = cmdutil.commitopts3
155 formatteropts = cmdutil.formatteropts
155 formatteropts = cmdutil.formatteropts
156 templateopts = cmdutil.templateopts
156 templateopts = cmdutil.templateopts
157 logopts = cmdutil.logopts
157 logopts = cmdutil.logopts
158 diffopts = cmdutil.diffopts
158 diffopts = cmdutil.diffopts
159 diffwsopts = cmdutil.diffwsopts
159 diffwsopts = cmdutil.diffwsopts
160 diffopts2 = cmdutil.diffopts2
160 diffopts2 = cmdutil.diffopts2
161 mergetoolopts = cmdutil.mergetoolopts
161 mergetoolopts = cmdutil.mergetoolopts
162 similarityopts = cmdutil.similarityopts
162 similarityopts = cmdutil.similarityopts
163 subrepoopts = cmdutil.subrepoopts
163 subrepoopts = cmdutil.subrepoopts
164 debugrevlogopts = cmdutil.debugrevlogopts
164 debugrevlogopts = cmdutil.debugrevlogopts
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168
168
169 @command(
169 @command(
170 b'abort',
170 b'abort',
171 dryrunopts,
171 dryrunopts,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpbasic=True,
173 helpbasic=True,
174 )
174 )
175 def abort(ui, repo, **opts):
175 def abort(ui, repo, **opts):
176 """abort an unfinished operation (EXPERIMENTAL)
176 """abort an unfinished operation (EXPERIMENTAL)
177
177
178 Aborts a multistep operation like graft, histedit, rebase, merge,
178 Aborts a multistep operation like graft, histedit, rebase, merge,
179 and unshelve if they are in an unfinished state.
179 and unshelve if they are in an unfinished state.
180
180
181 use --dry-run/-n to dry run the command.
181 use --dry-run/-n to dry run the command.
182 """
182 """
183 dryrun = opts.get(r'dry_run')
183 dryrun = opts.get(r'dry_run')
184 abortstate = cmdutil.getunfinishedstate(repo)
184 abortstate = cmdutil.getunfinishedstate(repo)
185 if not abortstate:
185 if not abortstate:
186 raise error.Abort(_(b'no operation in progress'))
186 raise error.Abort(_(b'no operation in progress'))
187 if not abortstate.abortfunc:
187 if not abortstate.abortfunc:
188 raise error.Abort(
188 raise error.Abort(
189 (
189 (
190 _(b"%s in progress but does not support 'hg abort'")
190 _(b"%s in progress but does not support 'hg abort'")
191 % (abortstate._opname)
191 % (abortstate._opname)
192 ),
192 ),
193 hint=abortstate.hint(),
193 hint=abortstate.hint(),
194 )
194 )
195 if dryrun:
195 if dryrun:
196 ui.status(
196 ui.status(
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 )
198 )
199 return
199 return
200 return abortstate.abortfunc(ui, repo)
200 return abortstate.abortfunc(ui, repo)
201
201
202
202
203 @command(
203 @command(
204 b'add',
204 b'add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _(b'[OPTION]... [FILE]...'),
206 _(b'[OPTION]... [FILE]...'),
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpbasic=True,
208 helpbasic=True,
209 inferrepo=True,
209 inferrepo=True,
210 )
210 )
211 def add(ui, repo, *pats, **opts):
211 def add(ui, repo, *pats, **opts):
212 """add the specified files on the next commit
212 """add the specified files on the next commit
213
213
214 Schedule files to be version controlled and added to the
214 Schedule files to be version controlled and added to the
215 repository.
215 repository.
216
216
217 The files will be added to the repository at the next commit. To
217 The files will be added to the repository at the next commit. To
218 undo an add before that, see :hg:`forget`.
218 undo an add before that, see :hg:`forget`.
219
219
220 If no names are given, add all files to the repository (except
220 If no names are given, add all files to the repository (except
221 files matching ``.hgignore``).
221 files matching ``.hgignore``).
222
222
223 .. container:: verbose
223 .. container:: verbose
224
224
225 Examples:
225 Examples:
226
226
227 - New (unknown) files are added
227 - New (unknown) files are added
228 automatically by :hg:`add`::
228 automatically by :hg:`add`::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ? foo.c
233 ? foo.c
234 $ hg add
234 $ hg add
235 adding foo.c
235 adding foo.c
236 $ hg status
236 $ hg status
237 A foo.c
237 A foo.c
238
238
239 - Specific files to be added can be specified::
239 - Specific files to be added can be specified::
240
240
241 $ ls
241 $ ls
242 bar.c foo.c
242 bar.c foo.c
243 $ hg status
243 $ hg status
244 ? bar.c
244 ? bar.c
245 ? foo.c
245 ? foo.c
246 $ hg add bar.c
246 $ hg add bar.c
247 $ hg status
247 $ hg status
248 A bar.c
248 A bar.c
249 ? foo.c
249 ? foo.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253
253
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259
259
260 @command(
260 @command(
261 b'addremove',
261 b'addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _(b'[OPTION]... [FILE]...'),
263 _(b'[OPTION]... [FILE]...'),
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 inferrepo=True,
265 inferrepo=True,
266 )
266 )
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 if not opts.get(b'similarity'):
330 if not opts.get(b'similarity'):
331 opts[b'similarity'] = b'100'
331 opts[b'similarity'] = b'100'
332 matcher = scmutil.match(repo[None], pats, opts)
332 matcher = scmutil.match(repo[None], pats, opts)
333 relative = scmutil.anypats(pats, opts)
333 relative = scmutil.anypats(pats, opts)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336
336
337
337
338 @command(
338 @command(
339 b'annotate|blame',
339 b'annotate|blame',
340 [
340 [
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (
342 (
343 b'',
343 b'',
344 b'follow',
344 b'follow',
345 None,
345 None,
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 ),
347 ),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'a', b'text', None, _(b'treat all files as text')),
349 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'f', b'file', None, _(b'list the filename')),
351 (b'f', b'file', None, _(b'list the filename')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
355 (
355 (
356 b'l',
356 b'l',
357 b'line-number',
357 b'line-number',
358 None,
358 None,
359 _(b'show line number at the first appearance'),
359 _(b'show line number at the first appearance'),
360 ),
360 ),
361 (
361 (
362 b'',
362 b'',
363 b'skip',
363 b'skip',
364 [],
364 [],
365 _(b'revision to not display (EXPERIMENTAL)'),
365 _(b'revision to not display (EXPERIMENTAL)'),
366 _(b'REV'),
366 _(b'REV'),
367 ),
367 ),
368 ]
368 ]
369 + diffwsopts
369 + diffwsopts
370 + walkopts
370 + walkopts
371 + formatteropts,
371 + formatteropts,
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpbasic=True,
374 helpbasic=True,
375 inferrepo=True,
375 inferrepo=True,
376 )
376 )
377 def annotate(ui, repo, *pats, **opts):
377 def annotate(ui, repo, *pats, **opts):
378 """show changeset information by line for each file
378 """show changeset information by line for each file
379
379
380 List changes in files, showing the revision id responsible for
380 List changes in files, showing the revision id responsible for
381 each line.
381 each line.
382
382
383 This command is useful for discovering when a change was made and
383 This command is useful for discovering when a change was made and
384 by whom.
384 by whom.
385
385
386 If you include --file, --user, or --date, the revision number is
386 If you include --file, --user, or --date, the revision number is
387 suppressed unless you also include --number.
387 suppressed unless you also include --number.
388
388
389 Without the -a/--text option, annotate will avoid processing files
389 Without the -a/--text option, annotate will avoid processing files
390 it detects as binary. With -a, annotate will annotate the file
390 it detects as binary. With -a, annotate will annotate the file
391 anyway, although the results will probably be neither useful
391 anyway, although the results will probably be neither useful
392 nor desirable.
392 nor desirable.
393
393
394 .. container:: verbose
394 .. container:: verbose
395
395
396 Template:
396 Template:
397
397
398 The following keywords are supported in addition to the common template
398 The following keywords are supported in addition to the common template
399 keywords and functions. See also :hg:`help templates`.
399 keywords and functions. See also :hg:`help templates`.
400
400
401 :lines: List of lines with annotation data.
401 :lines: List of lines with annotation data.
402 :path: String. Repository-absolute path of the specified file.
402 :path: String. Repository-absolute path of the specified file.
403
403
404 And each entry of ``{lines}`` provides the following sub-keywords in
404 And each entry of ``{lines}`` provides the following sub-keywords in
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406
406
407 :line: String. Line content.
407 :line: String. Line content.
408 :lineno: Integer. Line number at that revision.
408 :lineno: Integer. Line number at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
410
410
411 See :hg:`help templates.operators` for the list expansion syntax.
411 See :hg:`help templates.operators` for the list expansion syntax.
412
412
413 Returns 0 on success.
413 Returns 0 on success.
414 """
414 """
415 opts = pycompat.byteskwargs(opts)
415 opts = pycompat.byteskwargs(opts)
416 if not pats:
416 if not pats:
417 raise error.Abort(_(b'at least one filename or pattern is required'))
417 raise error.Abort(_(b'at least one filename or pattern is required'))
418
418
419 if opts.get(b'follow'):
419 if opts.get(b'follow'):
420 # --follow is deprecated and now just an alias for -f/--file
420 # --follow is deprecated and now just an alias for -f/--file
421 # to mimic the behavior of Mercurial before version 1.5
421 # to mimic the behavior of Mercurial before version 1.5
422 opts[b'file'] = True
422 opts[b'file'] = True
423
423
424 if (
424 if (
425 not opts.get(b'user')
425 not opts.get(b'user')
426 and not opts.get(b'changeset')
426 and not opts.get(b'changeset')
427 and not opts.get(b'date')
427 and not opts.get(b'date')
428 and not opts.get(b'file')
428 and not opts.get(b'file')
429 ):
429 ):
430 opts[b'number'] = True
430 opts[b'number'] = True
431
431
432 linenumber = opts.get(b'line_number') is not None
432 linenumber = opts.get(b'line_number') is not None
433 if (
433 if (
434 linenumber
434 linenumber
435 and (not opts.get(b'changeset'))
435 and (not opts.get(b'changeset'))
436 and (not opts.get(b'number'))
436 and (not opts.get(b'number'))
437 ):
437 ):
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439
439
440 rev = opts.get(b'rev')
440 rev = opts.get(b'rev')
441 if rev:
441 if rev:
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 ctx = scmutil.revsingle(repo, rev)
443 ctx = scmutil.revsingle(repo, rev)
444
444
445 ui.pager(b'annotate')
445 ui.pager(b'annotate')
446 rootfm = ui.formatter(b'annotate', opts)
446 rootfm = ui.formatter(b'annotate', opts)
447 if ui.debugflag:
447 if ui.debugflag:
448 shorthex = pycompat.identity
448 shorthex = pycompat.identity
449 else:
449 else:
450
450
451 def shorthex(h):
451 def shorthex(h):
452 return h[:12]
452 return h[:12]
453
453
454 if ui.quiet:
454 if ui.quiet:
455 datefunc = dateutil.shortdate
455 datefunc = dateutil.shortdate
456 else:
456 else:
457 datefunc = dateutil.datestr
457 datefunc = dateutil.datestr
458 if ctx.rev() is None:
458 if ctx.rev() is None:
459 if opts.get(b'changeset'):
459 if opts.get(b'changeset'):
460 # omit "+" suffix which is appended to node hex
460 # omit "+" suffix which is appended to node hex
461 def formatrev(rev):
461 def formatrev(rev):
462 if rev == wdirrev:
462 if rev == wdirrev:
463 return b'%d' % ctx.p1().rev()
463 return b'%d' % ctx.p1().rev()
464 else:
464 else:
465 return b'%d' % rev
465 return b'%d' % rev
466
466
467 else:
467 else:
468
468
469 def formatrev(rev):
469 def formatrev(rev):
470 if rev == wdirrev:
470 if rev == wdirrev:
471 return b'%d+' % ctx.p1().rev()
471 return b'%d+' % ctx.p1().rev()
472 else:
472 else:
473 return b'%d ' % rev
473 return b'%d ' % rev
474
474
475 def formathex(h):
475 def formathex(h):
476 if h == wdirhex:
476 if h == wdirhex:
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 else:
478 else:
479 return b'%s ' % shorthex(h)
479 return b'%s ' % shorthex(h)
480
480
481 else:
481 else:
482 formatrev = b'%d'.__mod__
482 formatrev = b'%d'.__mod__
483 formathex = shorthex
483 formathex = shorthex
484
484
485 opmap = [
485 opmap = [
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 ]
492 ]
493 opnamemap = {
493 opnamemap = {
494 b'rev': b'number',
494 b'rev': b'number',
495 b'node': b'changeset',
495 b'node': b'changeset',
496 b'path': b'file',
496 b'path': b'file',
497 b'lineno': b'line_number',
497 b'lineno': b'line_number',
498 }
498 }
499
499
500 if rootfm.isplain():
500 if rootfm.isplain():
501
501
502 def makefunc(get, fmt):
502 def makefunc(get, fmt):
503 return lambda x: fmt(get(x))
503 return lambda x: fmt(get(x))
504
504
505 else:
505 else:
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return get
508 return get
509
509
510 datahint = rootfm.datahint()
510 datahint = rootfm.datahint()
511 funcmap = [
511 funcmap = [
512 (makefunc(get, fmt), sep)
512 (makefunc(get, fmt), sep)
513 for fn, sep, get, fmt in opmap
513 for fn, sep, get, fmt in opmap
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 ]
515 ]
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 fields = b' '.join(
517 fields = b' '.join(
518 fn
518 fn
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 )
521 )
522
522
523 def bad(x, y):
523 def bad(x, y):
524 raise error.Abort(b"%s: %s" % (x, y))
524 raise error.Abort(b"%s: %s" % (x, y))
525
525
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
527
527
528 follow = not opts.get(b'no_follow')
528 follow = not opts.get(b'no_follow')
529 diffopts = patch.difffeatureopts(
529 diffopts = patch.difffeatureopts(
530 ui, opts, section=b'annotate', whitespace=True
530 ui, opts, section=b'annotate', whitespace=True
531 )
531 )
532 skiprevs = opts.get(b'skip')
532 skiprevs = opts.get(b'skip')
533 if skiprevs:
533 if skiprevs:
534 skiprevs = scmutil.revrange(repo, skiprevs)
534 skiprevs = scmutil.revrange(repo, skiprevs)
535
535
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fctx = ctx[abs]
538 fctx = ctx[abs]
539 rootfm.startitem()
539 rootfm.startitem()
540 rootfm.data(path=abs)
540 rootfm.data(path=abs)
541 if not opts.get(b'text') and fctx.isbinary():
541 if not opts.get(b'text') and fctx.isbinary():
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 continue
543 continue
544
544
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 lines = fctx.annotate(
546 lines = fctx.annotate(
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 )
548 )
549 if not lines:
549 if not lines:
550 fm.end()
550 fm.end()
551 continue
551 continue
552 formats = []
552 formats = []
553 pieces = []
553 pieces = []
554
554
555 for f, sep in funcmap:
555 for f, sep in funcmap:
556 l = [f(n) for n in lines]
556 l = [f(n) for n in lines]
557 if fm.isplain():
557 if fm.isplain():
558 sizes = [encoding.colwidth(x) for x in l]
558 sizes = [encoding.colwidth(x) for x in l]
559 ml = max(sizes)
559 ml = max(sizes)
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 else:
561 else:
562 formats.append([b'%s' for x in l])
562 formats.append([b'%s' for x in l])
563 pieces.append(l)
563 pieces.append(l)
564
564
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 fm.startitem()
566 fm.startitem()
567 fm.context(fctx=n.fctx)
567 fm.context(fctx=n.fctx)
568 fm.write(fields, b"".join(f), *p)
568 fm.write(fields, b"".join(f), *p)
569 if n.skip:
569 if n.skip:
570 fmt = b"* %s"
570 fmt = b"* %s"
571 else:
571 else:
572 fmt = b": %s"
572 fmt = b": %s"
573 fm.write(b'line', fmt, n.text)
573 fm.write(b'line', fmt, n.text)
574
574
575 if not lines[-1].text.endswith(b'\n'):
575 if not lines[-1].text.endswith(b'\n'):
576 fm.plain(b'\n')
576 fm.plain(b'\n')
577 fm.end()
577 fm.end()
578
578
579 rootfm.end()
579 rootfm.end()
580
580
581
581
582 @command(
582 @command(
583 b'archive',
583 b'archive',
584 [
584 [
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (
586 (
587 b'p',
587 b'p',
588 b'prefix',
588 b'prefix',
589 b'',
589 b'',
590 _(b'directory prefix for files in archive'),
590 _(b'directory prefix for files in archive'),
591 _(b'PREFIX'),
591 _(b'PREFIX'),
592 ),
592 ),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 ]
595 ]
596 + subrepoopts
596 + subrepoopts
597 + walkopts,
597 + walkopts,
598 _(b'[OPTION]... DEST'),
598 _(b'[OPTION]... DEST'),
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 )
600 )
601 def archive(ui, repo, dest, **opts):
601 def archive(ui, repo, dest, **opts):
602 '''create an unversioned archive of a repository revision
602 '''create an unversioned archive of a repository revision
603
603
604 By default, the revision used is the parent of the working
604 By default, the revision used is the parent of the working
605 directory; use -r/--rev to specify a different revision.
605 directory; use -r/--rev to specify a different revision.
606
606
607 The archive type is automatically detected based on file
607 The archive type is automatically detected based on file
608 extension (to override, use -t/--type).
608 extension (to override, use -t/--type).
609
609
610 .. container:: verbose
610 .. container:: verbose
611
611
612 Examples:
612 Examples:
613
613
614 - create a zip file containing the 1.0 release::
614 - create a zip file containing the 1.0 release::
615
615
616 hg archive -r 1.0 project-1.0.zip
616 hg archive -r 1.0 project-1.0.zip
617
617
618 - create a tarball excluding .hg files::
618 - create a tarball excluding .hg files::
619
619
620 hg archive project.tar.gz -X ".hg*"
620 hg archive project.tar.gz -X ".hg*"
621
621
622 Valid types are:
622 Valid types are:
623
623
624 :``files``: a directory full of files (default)
624 :``files``: a directory full of files (default)
625 :``tar``: tar archive, uncompressed
625 :``tar``: tar archive, uncompressed
626 :``tbz2``: tar archive, compressed using bzip2
626 :``tbz2``: tar archive, compressed using bzip2
627 :``tgz``: tar archive, compressed using gzip
627 :``tgz``: tar archive, compressed using gzip
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``uzip``: zip archive, uncompressed
629 :``uzip``: zip archive, uncompressed
630 :``zip``: zip archive, compressed using deflate
630 :``zip``: zip archive, compressed using deflate
631
631
632 The exact name of the destination archive or directory is given
632 The exact name of the destination archive or directory is given
633 using a format string; see :hg:`help export` for details.
633 using a format string; see :hg:`help export` for details.
634
634
635 Each member added to an archive file has a directory prefix
635 Each member added to an archive file has a directory prefix
636 prepended. Use -p/--prefix to specify a format string for the
636 prepended. Use -p/--prefix to specify a format string for the
637 prefix. The default is the basename of the archive, with suffixes
637 prefix. The default is the basename of the archive, with suffixes
638 removed.
638 removed.
639
639
640 Returns 0 on success.
640 Returns 0 on success.
641 '''
641 '''
642
642
643 opts = pycompat.byteskwargs(opts)
643 opts = pycompat.byteskwargs(opts)
644 rev = opts.get(b'rev')
644 rev = opts.get(b'rev')
645 if rev:
645 if rev:
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
648 if not ctx:
648 if not ctx:
649 raise error.Abort(_(b'no working directory: please specify a revision'))
649 raise error.Abort(_(b'no working directory: please specify a revision'))
650 node = ctx.node()
650 node = ctx.node()
651 dest = cmdutil.makefilename(ctx, dest)
651 dest = cmdutil.makefilename(ctx, dest)
652 if os.path.realpath(dest) == repo.root:
652 if os.path.realpath(dest) == repo.root:
653 raise error.Abort(_(b'repository root cannot be destination'))
653 raise error.Abort(_(b'repository root cannot be destination'))
654
654
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 prefix = opts.get(b'prefix')
656 prefix = opts.get(b'prefix')
657
657
658 if dest == b'-':
658 if dest == b'-':
659 if kind == b'files':
659 if kind == b'files':
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 dest = cmdutil.makefileobj(ctx, dest)
661 dest = cmdutil.makefileobj(ctx, dest)
662 if not prefix:
662 if not prefix:
663 prefix = os.path.basename(repo.root) + b'-%h'
663 prefix = os.path.basename(repo.root) + b'-%h'
664
664
665 prefix = cmdutil.makefilename(ctx, prefix)
665 prefix = cmdutil.makefilename(ctx, prefix)
666 match = scmutil.match(ctx, [], opts)
666 match = scmutil.match(ctx, [], opts)
667 archival.archive(
667 archival.archive(
668 repo,
668 repo,
669 dest,
669 dest,
670 node,
670 node,
671 kind,
671 kind,
672 not opts.get(b'no_decode'),
672 not opts.get(b'no_decode'),
673 match,
673 match,
674 prefix,
674 prefix,
675 subrepos=opts.get(b'subrepos'),
675 subrepos=opts.get(b'subrepos'),
676 )
676 )
677
677
678
678
679 @command(
679 @command(
680 b'backout',
680 b'backout',
681 [
681 [
682 (
682 (
683 b'',
683 b'',
684 b'merge',
684 b'merge',
685 None,
685 None,
686 _(b'merge with old dirstate parent after backout'),
686 _(b'merge with old dirstate parent after backout'),
687 ),
687 ),
688 (
688 (
689 b'',
689 b'',
690 b'commit',
690 b'commit',
691 None,
691 None,
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 ),
693 ),
694 (b'', b'no-commit', None, _(b'do not commit')),
694 (b'', b'no-commit', None, _(b'do not commit')),
695 (
695 (
696 b'',
696 b'',
697 b'parent',
697 b'parent',
698 b'',
698 b'',
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'REV'),
700 _(b'REV'),
701 ),
701 ),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 ]
704 ]
705 + mergetoolopts
705 + mergetoolopts
706 + walkopts
706 + walkopts
707 + commitopts
707 + commitopts
708 + commitopts2,
708 + commitopts2,
709 _(b'[OPTION]... [-r] REV'),
709 _(b'[OPTION]... [-r] REV'),
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 )
711 )
712 def backout(ui, repo, node=None, rev=None, **opts):
712 def backout(ui, repo, node=None, rev=None, **opts):
713 '''reverse effect of earlier changeset
713 '''reverse effect of earlier changeset
714
714
715 Prepare a new changeset with the effect of REV undone in the
715 Prepare a new changeset with the effect of REV undone in the
716 current working directory. If no conflicts were encountered,
716 current working directory. If no conflicts were encountered,
717 it will be committed immediately.
717 it will be committed immediately.
718
718
719 If REV is the parent of the working directory, then this new changeset
719 If REV is the parent of the working directory, then this new changeset
720 is committed automatically (unless --no-commit is specified).
720 is committed automatically (unless --no-commit is specified).
721
721
722 .. note::
722 .. note::
723
723
724 :hg:`backout` cannot be used to fix either an unwanted or
724 :hg:`backout` cannot be used to fix either an unwanted or
725 incorrect merge.
725 incorrect merge.
726
726
727 .. container:: verbose
727 .. container:: verbose
728
728
729 Examples:
729 Examples:
730
730
731 - Reverse the effect of the parent of the working directory.
731 - Reverse the effect of the parent of the working directory.
732 This backout will be committed immediately::
732 This backout will be committed immediately::
733
733
734 hg backout -r .
734 hg backout -r .
735
735
736 - Reverse the effect of previous bad revision 23::
736 - Reverse the effect of previous bad revision 23::
737
737
738 hg backout -r 23
738 hg backout -r 23
739
739
740 - Reverse the effect of previous bad revision 23 and
740 - Reverse the effect of previous bad revision 23 and
741 leave changes uncommitted::
741 leave changes uncommitted::
742
742
743 hg backout -r 23 --no-commit
743 hg backout -r 23 --no-commit
744 hg commit -m "Backout revision 23"
744 hg commit -m "Backout revision 23"
745
745
746 By default, the pending changeset will have one parent,
746 By default, the pending changeset will have one parent,
747 maintaining a linear history. With --merge, the pending
747 maintaining a linear history. With --merge, the pending
748 changeset will instead have two parents: the old parent of the
748 changeset will instead have two parents: the old parent of the
749 working directory and a new child of REV that simply undoes REV.
749 working directory and a new child of REV that simply undoes REV.
750
750
751 Before version 1.7, the behavior without --merge was equivalent
751 Before version 1.7, the behavior without --merge was equivalent
752 to specifying --merge followed by :hg:`update --clean .` to
752 to specifying --merge followed by :hg:`update --clean .` to
753 cancel the merge and leave the child of REV as a head to be
753 cancel the merge and leave the child of REV as a head to be
754 merged separately.
754 merged separately.
755
755
756 See :hg:`help dates` for a list of formats valid for -d/--date.
756 See :hg:`help dates` for a list of formats valid for -d/--date.
757
757
758 See :hg:`help revert` for a way to restore files to the state
758 See :hg:`help revert` for a way to restore files to the state
759 of another revision.
759 of another revision.
760
760
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 files.
762 files.
763 '''
763 '''
764 with repo.wlock(), repo.lock():
764 with repo.wlock(), repo.lock():
765 return _dobackout(ui, repo, node, rev, **opts)
765 return _dobackout(ui, repo, node, rev, **opts)
766
766
767
767
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
770 if opts.get(b'commit') and opts.get(b'no_commit'):
770 if opts.get(b'commit') and opts.get(b'no_commit'):
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 if opts.get(b'merge') and opts.get(b'no_commit'):
772 if opts.get(b'merge') and opts.get(b'no_commit'):
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774
774
775 if rev and node:
775 if rev and node:
776 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
777
777
778 if not rev:
778 if not rev:
779 rev = node
779 rev = node
780
780
781 if not rev:
781 if not rev:
782 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
783
783
784 date = opts.get(b'date')
784 date = opts.get(b'date')
785 if date:
785 if date:
786 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
787
787
788 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
789 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
790 node = scmutil.revsingle(repo, rev).node()
790 node = scmutil.revsingle(repo, rev).node()
791
791
792 op1, op2 = repo.dirstate.parents()
792 op1, op2 = repo.dirstate.parents()
793 if not repo.changelog.isancestor(node, op1):
793 if not repo.changelog.isancestor(node, op1):
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795
795
796 p1, p2 = repo.changelog.parents(node)
796 p1, p2 = repo.changelog.parents(node)
797 if p1 == nullid:
797 if p1 == nullid:
798 raise error.Abort(_(b'cannot backout a change with no parents'))
798 raise error.Abort(_(b'cannot backout a change with no parents'))
799 if p2 != nullid:
799 if p2 != nullid:
800 if not opts.get(b'parent'):
800 if not opts.get(b'parent'):
801 raise error.Abort(_(b'cannot backout a merge changeset'))
801 raise error.Abort(_(b'cannot backout a merge changeset'))
802 p = repo.lookup(opts[b'parent'])
802 p = repo.lookup(opts[b'parent'])
803 if p not in (p1, p2):
803 if p not in (p1, p2):
804 raise error.Abort(
804 raise error.Abort(
805 _(b'%s is not a parent of %s') % (short(p), short(node))
805 _(b'%s is not a parent of %s') % (short(p), short(node))
806 )
806 )
807 parent = p
807 parent = p
808 else:
808 else:
809 if opts.get(b'parent'):
809 if opts.get(b'parent'):
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 parent = p1
811 parent = p1
812
812
813 # the backout should appear on the same branch
813 # the backout should appear on the same branch
814 branch = repo.dirstate.branch()
814 branch = repo.dirstate.branch()
815 bheads = repo.branchheads(branch)
815 bheads = repo.branchheads(branch)
816 rctx = scmutil.revsingle(repo, hex(parent))
816 rctx = scmutil.revsingle(repo, hex(parent))
817 if not opts.get(b'merge') and op1 != node:
817 if not opts.get(b'merge') and op1 != node:
818 with dirstateguard.dirstateguard(repo, b'backout'):
818 with dirstateguard.dirstateguard(repo, b'backout'):
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 with ui.configoverride(overrides, b'backout'):
820 with ui.configoverride(overrides, b'backout'):
821 stats = mergemod.update(
821 stats = mergemod.update(
822 repo,
822 repo,
823 parent,
823 parent,
824 branchmerge=True,
824 branchmerge=True,
825 force=True,
825 force=True,
826 ancestor=node,
826 ancestor=node,
827 mergeancestor=False,
827 mergeancestor=False,
828 )
828 )
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 if not newnode:
860 if not newnode:
861 ui.status(_(b"nothing changed\n"))
861 ui.status(_(b"nothing changed\n"))
862 return 1
862 return 1
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
864
864
865 def nice(node):
865 def nice(node):
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867
867
868 ui.status(
868 ui.status(
869 _(b'changeset %s backs out changeset %s\n')
869 _(b'changeset %s backs out changeset %s\n')
870 % (nice(repo.changelog.tip()), nice(node))
870 % (nice(repo.changelog.tip()), nice(node))
871 )
871 )
872 if opts.get(b'merge') and op1 != node:
872 if opts.get(b'merge') and op1 != node:
873 hg.clean(repo, op1, show_stats=False)
873 hg.clean(repo, op1, show_stats=False)
874 ui.status(
874 ui.status(
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 )
876 )
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 with ui.configoverride(overrides, b'backout'):
878 with ui.configoverride(overrides, b'backout'):
879 return hg.merge(repo, hex(repo.changelog.tip()))
879 return hg.merge(repo, hex(repo.changelog.tip()))
880 return 0
880 return 0
881
881
882
882
883 @command(
883 @command(
884 b'bisect',
884 b'bisect',
885 [
885 [
886 (b'r', b'reset', False, _(b'reset bisect state')),
886 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'g', b'good', False, _(b'mark changeset good')),
887 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (
891 (
892 b'c',
892 b'c',
893 b'command',
893 b'command',
894 b'',
894 b'',
895 _(b'use command to check changeset state'),
895 _(b'use command to check changeset state'),
896 _(b'CMD'),
896 _(b'CMD'),
897 ),
897 ),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
899 ],
899 ],
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 )
902 )
903 def bisect(
903 def bisect(
904 ui,
904 ui,
905 repo,
905 repo,
906 rev=None,
906 rev=None,
907 extra=None,
907 extra=None,
908 command=None,
908 command=None,
909 reset=None,
909 reset=None,
910 good=None,
910 good=None,
911 bad=None,
911 bad=None,
912 skip=None,
912 skip=None,
913 extend=None,
913 extend=None,
914 noupdate=None,
914 noupdate=None,
915 ):
915 ):
916 """subdivision search of changesets
916 """subdivision search of changesets
917
917
918 This command helps to find changesets which introduce problems. To
918 This command helps to find changesets which introduce problems. To
919 use, mark the earliest changeset you know exhibits the problem as
919 use, mark the earliest changeset you know exhibits the problem as
920 bad, then mark the latest changeset which is free from the problem
920 bad, then mark the latest changeset which is free from the problem
921 as good. Bisect will update your working directory to a revision
921 as good. Bisect will update your working directory to a revision
922 for testing (unless the -U/--noupdate option is specified). Once
922 for testing (unless the -U/--noupdate option is specified). Once
923 you have performed tests, mark the working directory as good or
923 you have performed tests, mark the working directory as good or
924 bad, and bisect will either update to another candidate changeset
924 bad, and bisect will either update to another candidate changeset
925 or announce that it has found the bad revision.
925 or announce that it has found the bad revision.
926
926
927 As a shortcut, you can also use the revision argument to mark a
927 As a shortcut, you can also use the revision argument to mark a
928 revision as good or bad without checking it out first.
928 revision as good or bad without checking it out first.
929
929
930 If you supply a command, it will be used for automatic bisection.
930 If you supply a command, it will be used for automatic bisection.
931 The environment variable HG_NODE will contain the ID of the
931 The environment variable HG_NODE will contain the ID of the
932 changeset being tested. The exit status of the command will be
932 changeset being tested. The exit status of the command will be
933 used to mark revisions as good or bad: status 0 means good, 125
933 used to mark revisions as good or bad: status 0 means good, 125
934 means to skip the revision, 127 (command not found) will abort the
934 means to skip the revision, 127 (command not found) will abort the
935 bisection, and any other non-zero exit status means the revision
935 bisection, and any other non-zero exit status means the revision
936 is bad.
936 is bad.
937
937
938 .. container:: verbose
938 .. container:: verbose
939
939
940 Some examples:
940 Some examples:
941
941
942 - start a bisection with known bad revision 34, and good revision 12::
942 - start a bisection with known bad revision 34, and good revision 12::
943
943
944 hg bisect --bad 34
944 hg bisect --bad 34
945 hg bisect --good 12
945 hg bisect --good 12
946
946
947 - advance the current bisection by marking current revision as good or
947 - advance the current bisection by marking current revision as good or
948 bad::
948 bad::
949
949
950 hg bisect --good
950 hg bisect --good
951 hg bisect --bad
951 hg bisect --bad
952
952
953 - mark the current revision, or a known revision, to be skipped (e.g. if
953 - mark the current revision, or a known revision, to be skipped (e.g. if
954 that revision is not usable because of another issue)::
954 that revision is not usable because of another issue)::
955
955
956 hg bisect --skip
956 hg bisect --skip
957 hg bisect --skip 23
957 hg bisect --skip 23
958
958
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960
960
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962
962
963 - forget the current bisection::
963 - forget the current bisection::
964
964
965 hg bisect --reset
965 hg bisect --reset
966
966
967 - use 'make && make tests' to automatically find the first broken
967 - use 'make && make tests' to automatically find the first broken
968 revision::
968 revision::
969
969
970 hg bisect --reset
970 hg bisect --reset
971 hg bisect --bad 34
971 hg bisect --bad 34
972 hg bisect --good 12
972 hg bisect --good 12
973 hg bisect --command "make && make tests"
973 hg bisect --command "make && make tests"
974
974
975 - see all changesets whose states are already known in the current
975 - see all changesets whose states are already known in the current
976 bisection::
976 bisection::
977
977
978 hg log -r "bisect(pruned)"
978 hg log -r "bisect(pruned)"
979
979
980 - see the changeset currently being bisected (especially useful
980 - see the changeset currently being bisected (especially useful
981 if running with -U/--noupdate)::
981 if running with -U/--noupdate)::
982
982
983 hg log -r "bisect(current)"
983 hg log -r "bisect(current)"
984
984
985 - see all changesets that took part in the current bisection::
985 - see all changesets that took part in the current bisection::
986
986
987 hg log -r "bisect(range)"
987 hg log -r "bisect(range)"
988
988
989 - you can even get a nice graph::
989 - you can even get a nice graph::
990
990
991 hg log --graph -r "bisect(range)"
991 hg log --graph -r "bisect(range)"
992
992
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994
994
995 Returns 0 on success.
995 Returns 0 on success.
996 """
996 """
997 # backward compatibility
997 # backward compatibility
998 if rev in b"good bad reset init".split():
998 if rev in b"good bad reset init".split():
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 cmd, rev, extra = rev, extra, None
1000 cmd, rev, extra = rev, extra, None
1001 if cmd == b"good":
1001 if cmd == b"good":
1002 good = True
1002 good = True
1003 elif cmd == b"bad":
1003 elif cmd == b"bad":
1004 bad = True
1004 bad = True
1005 else:
1005 else:
1006 reset = True
1006 reset = True
1007 elif extra:
1007 elif extra:
1008 raise error.Abort(_(b'incompatible arguments'))
1008 raise error.Abort(_(b'incompatible arguments'))
1009
1009
1010 incompatibles = {
1010 incompatibles = {
1011 b'--bad': bad,
1011 b'--bad': bad,
1012 b'--command': bool(command),
1012 b'--command': bool(command),
1013 b'--extend': extend,
1013 b'--extend': extend,
1014 b'--good': good,
1014 b'--good': good,
1015 b'--reset': reset,
1015 b'--reset': reset,
1016 b'--skip': skip,
1016 b'--skip': skip,
1017 }
1017 }
1018
1018
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1020
1020
1021 if len(enabled) > 1:
1021 if len(enabled) > 1:
1022 raise error.Abort(
1022 raise error.Abort(
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 )
1024 )
1025
1025
1026 if reset:
1026 if reset:
1027 hbisect.resetstate(repo)
1027 hbisect.resetstate(repo)
1028 return
1028 return
1029
1029
1030 state = hbisect.load_state(repo)
1030 state = hbisect.load_state(repo)
1031
1031
1032 # update state
1032 # update state
1033 if good or bad or skip:
1033 if good or bad or skip:
1034 if rev:
1034 if rev:
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 else:
1036 else:
1037 nodes = [repo.lookup(b'.')]
1037 nodes = [repo.lookup(b'.')]
1038 if good:
1038 if good:
1039 state[b'good'] += nodes
1039 state[b'good'] += nodes
1040 elif bad:
1040 elif bad:
1041 state[b'bad'] += nodes
1041 state[b'bad'] += nodes
1042 elif skip:
1042 elif skip:
1043 state[b'skip'] += nodes
1043 state[b'skip'] += nodes
1044 hbisect.save_state(repo, state)
1044 hbisect.save_state(repo, state)
1045 if not (state[b'good'] and state[b'bad']):
1045 if not (state[b'good'] and state[b'bad']):
1046 return
1046 return
1047
1047
1048 def mayupdate(repo, node, show_stats=True):
1048 def mayupdate(repo, node, show_stats=True):
1049 """common used update sequence"""
1049 """common used update sequence"""
1050 if noupdate:
1050 if noupdate:
1051 return
1051 return
1052 cmdutil.checkunfinished(repo)
1052 cmdutil.checkunfinished(repo)
1053 cmdutil.bailifchanged(repo)
1053 cmdutil.bailifchanged(repo)
1054 return hg.clean(repo, node, show_stats=show_stats)
1054 return hg.clean(repo, node, show_stats=show_stats)
1055
1055
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057
1057
1058 if command:
1058 if command:
1059 changesets = 1
1059 changesets = 1
1060 if noupdate:
1060 if noupdate:
1061 try:
1061 try:
1062 node = state[b'current'][0]
1062 node = state[b'current'][0]
1063 except LookupError:
1063 except LookupError:
1064 raise error.Abort(
1064 raise error.Abort(
1065 _(
1065 _(
1066 b'current bisect revision is unknown - '
1066 b'current bisect revision is unknown - '
1067 b'start a new bisect to fix'
1067 b'start a new bisect to fix'
1068 )
1068 )
1069 )
1069 )
1070 else:
1070 else:
1071 node, p2 = repo.dirstate.parents()
1071 node, p2 = repo.dirstate.parents()
1072 if p2 != nullid:
1072 if p2 != nullid:
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1074 if rev:
1074 if rev:
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 try:
1076 try:
1077 while changesets:
1077 while changesets:
1078 # update state
1078 # update state
1079 state[b'current'] = [node]
1079 state[b'current'] = [node]
1080 hbisect.save_state(repo, state)
1080 hbisect.save_state(repo, state)
1081 status = ui.system(
1081 status = ui.system(
1082 command,
1082 command,
1083 environ={b'HG_NODE': hex(node)},
1083 environ={b'HG_NODE': hex(node)},
1084 blockedtag=b'bisect_check',
1084 blockedtag=b'bisect_check',
1085 )
1085 )
1086 if status == 125:
1086 if status == 125:
1087 transition = b"skip"
1087 transition = b"skip"
1088 elif status == 0:
1088 elif status == 0:
1089 transition = b"good"
1089 transition = b"good"
1090 # status < 0 means process was killed
1090 # status < 0 means process was killed
1091 elif status == 127:
1091 elif status == 127:
1092 raise error.Abort(_(b"failed to execute %s") % command)
1092 raise error.Abort(_(b"failed to execute %s") % command)
1093 elif status < 0:
1093 elif status < 0:
1094 raise error.Abort(_(b"%s killed") % command)
1094 raise error.Abort(_(b"%s killed") % command)
1095 else:
1095 else:
1096 transition = b"bad"
1096 transition = b"bad"
1097 state[transition].append(node)
1097 state[transition].append(node)
1098 ctx = repo[node]
1098 ctx = repo[node]
1099 ui.status(
1099 ui.status(
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 )
1101 )
1102 hbisect.checkstate(state)
1102 hbisect.checkstate(state)
1103 # bisect
1103 # bisect
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 # update to next check
1105 # update to next check
1106 node = nodes[0]
1106 node = nodes[0]
1107 mayupdate(repo, node, show_stats=False)
1107 mayupdate(repo, node, show_stats=False)
1108 finally:
1108 finally:
1109 state[b'current'] = [node]
1109 state[b'current'] = [node]
1110 hbisect.save_state(repo, state)
1110 hbisect.save_state(repo, state)
1111 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1111 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1112 return
1112 return
1113
1113
1114 hbisect.checkstate(state)
1114 hbisect.checkstate(state)
1115
1115
1116 # actually bisect
1116 # actually bisect
1117 nodes, changesets, good = hbisect.bisect(repo, state)
1117 nodes, changesets, good = hbisect.bisect(repo, state)
1118 if extend:
1118 if extend:
1119 if not changesets:
1119 if not changesets:
1120 extendnode = hbisect.extendrange(repo, state, nodes, good)
1120 extendnode = hbisect.extendrange(repo, state, nodes, good)
1121 if extendnode is not None:
1121 if extendnode is not None:
1122 ui.write(
1122 ui.write(
1123 _(b"Extending search to changeset %d:%s\n")
1123 _(b"Extending search to changeset %d:%s\n")
1124 % (extendnode.rev(), extendnode)
1124 % (extendnode.rev(), extendnode)
1125 )
1125 )
1126 state[b'current'] = [extendnode.node()]
1126 state[b'current'] = [extendnode.node()]
1127 hbisect.save_state(repo, state)
1127 hbisect.save_state(repo, state)
1128 return mayupdate(repo, extendnode.node())
1128 return mayupdate(repo, extendnode.node())
1129 raise error.Abort(_(b"nothing to extend"))
1129 raise error.Abort(_(b"nothing to extend"))
1130
1130
1131 if changesets == 0:
1131 if changesets == 0:
1132 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1132 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1133 else:
1133 else:
1134 assert len(nodes) == 1 # only a single node can be tested next
1134 assert len(nodes) == 1 # only a single node can be tested next
1135 node = nodes[0]
1135 node = nodes[0]
1136 # compute the approximate number of remaining tests
1136 # compute the approximate number of remaining tests
1137 tests, size = 0, 2
1137 tests, size = 0, 2
1138 while size <= changesets:
1138 while size <= changesets:
1139 tests, size = tests + 1, size * 2
1139 tests, size = tests + 1, size * 2
1140 rev = repo.changelog.rev(node)
1140 rev = repo.changelog.rev(node)
1141 ui.write(
1141 ui.write(
1142 _(
1142 _(
1143 b"Testing changeset %d:%s "
1143 b"Testing changeset %d:%s "
1144 b"(%d changesets remaining, ~%d tests)\n"
1144 b"(%d changesets remaining, ~%d tests)\n"
1145 )
1145 )
1146 % (rev, short(node), changesets, tests)
1146 % (rev, short(node), changesets, tests)
1147 )
1147 )
1148 state[b'current'] = [node]
1148 state[b'current'] = [node]
1149 hbisect.save_state(repo, state)
1149 hbisect.save_state(repo, state)
1150 return mayupdate(repo, node)
1150 return mayupdate(repo, node)
1151
1151
1152
1152
1153 @command(
1153 @command(
1154 b'bookmarks|bookmark',
1154 b'bookmarks|bookmark',
1155 [
1155 [
1156 (b'f', b'force', False, _(b'force')),
1156 (b'f', b'force', False, _(b'force')),
1157 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1157 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1158 (b'd', b'delete', False, _(b'delete a given bookmark')),
1158 (b'd', b'delete', False, _(b'delete a given bookmark')),
1159 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1159 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1160 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1160 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1161 (b'l', b'list', False, _(b'list existing bookmarks')),
1161 (b'l', b'list', False, _(b'list existing bookmarks')),
1162 ]
1162 ]
1163 + formatteropts,
1163 + formatteropts,
1164 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1164 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1166 )
1166 )
1167 def bookmark(ui, repo, *names, **opts):
1167 def bookmark(ui, repo, *names, **opts):
1168 '''create a new bookmark or list existing bookmarks
1168 '''create a new bookmark or list existing bookmarks
1169
1169
1170 Bookmarks are labels on changesets to help track lines of development.
1170 Bookmarks are labels on changesets to help track lines of development.
1171 Bookmarks are unversioned and can be moved, renamed and deleted.
1171 Bookmarks are unversioned and can be moved, renamed and deleted.
1172 Deleting or moving a bookmark has no effect on the associated changesets.
1172 Deleting or moving a bookmark has no effect on the associated changesets.
1173
1173
1174 Creating or updating to a bookmark causes it to be marked as 'active'.
1174 Creating or updating to a bookmark causes it to be marked as 'active'.
1175 The active bookmark is indicated with a '*'.
1175 The active bookmark is indicated with a '*'.
1176 When a commit is made, the active bookmark will advance to the new commit.
1176 When a commit is made, the active bookmark will advance to the new commit.
1177 A plain :hg:`update` will also advance an active bookmark, if possible.
1177 A plain :hg:`update` will also advance an active bookmark, if possible.
1178 Updating away from a bookmark will cause it to be deactivated.
1178 Updating away from a bookmark will cause it to be deactivated.
1179
1179
1180 Bookmarks can be pushed and pulled between repositories (see
1180 Bookmarks can be pushed and pulled between repositories (see
1181 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1181 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1182 diverged, a new 'divergent bookmark' of the form 'name@path' will
1182 diverged, a new 'divergent bookmark' of the form 'name@path' will
1183 be created. Using :hg:`merge` will resolve the divergence.
1183 be created. Using :hg:`merge` will resolve the divergence.
1184
1184
1185 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1185 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1186 the active bookmark's name.
1186 the active bookmark's name.
1187
1187
1188 A bookmark named '@' has the special property that :hg:`clone` will
1188 A bookmark named '@' has the special property that :hg:`clone` will
1189 check it out by default if it exists.
1189 check it out by default if it exists.
1190
1190
1191 .. container:: verbose
1191 .. container:: verbose
1192
1192
1193 Template:
1193 Template:
1194
1194
1195 The following keywords are supported in addition to the common template
1195 The following keywords are supported in addition to the common template
1196 keywords and functions such as ``{bookmark}``. See also
1196 keywords and functions such as ``{bookmark}``. See also
1197 :hg:`help templates`.
1197 :hg:`help templates`.
1198
1198
1199 :active: Boolean. True if the bookmark is active.
1199 :active: Boolean. True if the bookmark is active.
1200
1200
1201 Examples:
1201 Examples:
1202
1202
1203 - create an active bookmark for a new line of development::
1203 - create an active bookmark for a new line of development::
1204
1204
1205 hg book new-feature
1205 hg book new-feature
1206
1206
1207 - create an inactive bookmark as a place marker::
1207 - create an inactive bookmark as a place marker::
1208
1208
1209 hg book -i reviewed
1209 hg book -i reviewed
1210
1210
1211 - create an inactive bookmark on another changeset::
1211 - create an inactive bookmark on another changeset::
1212
1212
1213 hg book -r .^ tested
1213 hg book -r .^ tested
1214
1214
1215 - rename bookmark turkey to dinner::
1215 - rename bookmark turkey to dinner::
1216
1216
1217 hg book -m turkey dinner
1217 hg book -m turkey dinner
1218
1218
1219 - move the '@' bookmark from another branch::
1219 - move the '@' bookmark from another branch::
1220
1220
1221 hg book -f @
1221 hg book -f @
1222
1222
1223 - print only the active bookmark name::
1223 - print only the active bookmark name::
1224
1224
1225 hg book -ql .
1225 hg book -ql .
1226 '''
1226 '''
1227 opts = pycompat.byteskwargs(opts)
1227 opts = pycompat.byteskwargs(opts)
1228 force = opts.get(b'force')
1228 force = opts.get(b'force')
1229 rev = opts.get(b'rev')
1229 rev = opts.get(b'rev')
1230 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1230 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1231
1231
1232 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1232 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1233 if len(selactions) > 1:
1233 if len(selactions) > 1:
1234 raise error.Abort(
1234 raise error.Abort(
1235 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1235 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1236 )
1236 )
1237 if selactions:
1237 if selactions:
1238 action = selactions[0]
1238 action = selactions[0]
1239 elif names or rev:
1239 elif names or rev:
1240 action = b'add'
1240 action = b'add'
1241 elif inactive:
1241 elif inactive:
1242 action = b'inactive' # meaning deactivate
1242 action = b'inactive' # meaning deactivate
1243 else:
1243 else:
1244 action = b'list'
1244 action = b'list'
1245
1245
1246 if rev and action in {b'delete', b'rename', b'list'}:
1246 if rev and action in {b'delete', b'rename', b'list'}:
1247 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1247 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1248 if inactive and action in {b'delete', b'list'}:
1248 if inactive and action in {b'delete', b'list'}:
1249 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1249 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1250 if not names and action in {b'add', b'delete'}:
1250 if not names and action in {b'add', b'delete'}:
1251 raise error.Abort(_(b"bookmark name required"))
1251 raise error.Abort(_(b"bookmark name required"))
1252
1252
1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1255 if action == b'delete':
1255 if action == b'delete':
1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1257 bookmarks.delete(repo, tr, names)
1257 bookmarks.delete(repo, tr, names)
1258 elif action == b'rename':
1258 elif action == b'rename':
1259 if not names:
1259 if not names:
1260 raise error.Abort(_(b"new bookmark name required"))
1260 raise error.Abort(_(b"new bookmark name required"))
1261 elif len(names) > 1:
1261 elif len(names) > 1:
1262 raise error.Abort(_(b"only one new bookmark name allowed"))
1262 raise error.Abort(_(b"only one new bookmark name allowed"))
1263 oldname = repo._bookmarks.expandname(opts[b'rename'])
1263 oldname = repo._bookmarks.expandname(opts[b'rename'])
1264 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1264 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1265 elif action == b'add':
1265 elif action == b'add':
1266 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1266 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1267 elif action == b'inactive':
1267 elif action == b'inactive':
1268 if len(repo._bookmarks) == 0:
1268 if len(repo._bookmarks) == 0:
1269 ui.status(_(b"no bookmarks set\n"))
1269 ui.status(_(b"no bookmarks set\n"))
1270 elif not repo._activebookmark:
1270 elif not repo._activebookmark:
1271 ui.status(_(b"no active bookmark\n"))
1271 ui.status(_(b"no active bookmark\n"))
1272 else:
1272 else:
1273 bookmarks.deactivate(repo)
1273 bookmarks.deactivate(repo)
1274 elif action == b'list':
1274 elif action == b'list':
1275 names = pycompat.maplist(repo._bookmarks.expandname, names)
1275 names = pycompat.maplist(repo._bookmarks.expandname, names)
1276 with ui.formatter(b'bookmarks', opts) as fm:
1276 with ui.formatter(b'bookmarks', opts) as fm:
1277 bookmarks.printbookmarks(ui, repo, fm, names)
1277 bookmarks.printbookmarks(ui, repo, fm, names)
1278 else:
1278 else:
1279 raise error.ProgrammingError(b'invalid action: %s' % action)
1279 raise error.ProgrammingError(b'invalid action: %s' % action)
1280
1280
1281
1281
1282 @command(
1282 @command(
1283 b'branch',
1283 b'branch',
1284 [
1284 [
1285 (
1285 (
1286 b'f',
1286 b'f',
1287 b'force',
1287 b'force',
1288 None,
1288 None,
1289 _(b'set branch name even if it shadows an existing branch'),
1289 _(b'set branch name even if it shadows an existing branch'),
1290 ),
1290 ),
1291 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1291 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1292 (
1292 (
1293 b'r',
1293 b'r',
1294 b'rev',
1294 b'rev',
1295 [],
1295 [],
1296 _(b'change branches of the given revs (EXPERIMENTAL)'),
1296 _(b'change branches of the given revs (EXPERIMENTAL)'),
1297 ),
1297 ),
1298 ],
1298 ],
1299 _(b'[-fC] [NAME]'),
1299 _(b'[-fC] [NAME]'),
1300 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1300 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1301 )
1301 )
1302 def branch(ui, repo, label=None, **opts):
1302 def branch(ui, repo, label=None, **opts):
1303 """set or show the current branch name
1303 """set or show the current branch name
1304
1304
1305 .. note::
1305 .. note::
1306
1306
1307 Branch names are permanent and global. Use :hg:`bookmark` to create a
1307 Branch names are permanent and global. Use :hg:`bookmark` to create a
1308 light-weight bookmark instead. See :hg:`help glossary` for more
1308 light-weight bookmark instead. See :hg:`help glossary` for more
1309 information about named branches and bookmarks.
1309 information about named branches and bookmarks.
1310
1310
1311 With no argument, show the current branch name. With one argument,
1311 With no argument, show the current branch name. With one argument,
1312 set the working directory branch name (the branch will not exist
1312 set the working directory branch name (the branch will not exist
1313 in the repository until the next commit). Standard practice
1313 in the repository until the next commit). Standard practice
1314 recommends that primary development take place on the 'default'
1314 recommends that primary development take place on the 'default'
1315 branch.
1315 branch.
1316
1316
1317 Unless -f/--force is specified, branch will not let you set a
1317 Unless -f/--force is specified, branch will not let you set a
1318 branch name that already exists.
1318 branch name that already exists.
1319
1319
1320 Use -C/--clean to reset the working directory branch to that of
1320 Use -C/--clean to reset the working directory branch to that of
1321 the parent of the working directory, negating a previous branch
1321 the parent of the working directory, negating a previous branch
1322 change.
1322 change.
1323
1323
1324 Use the command :hg:`update` to switch to an existing branch. Use
1324 Use the command :hg:`update` to switch to an existing branch. Use
1325 :hg:`commit --close-branch` to mark this branch head as closed.
1325 :hg:`commit --close-branch` to mark this branch head as closed.
1326 When all heads of a branch are closed, the branch will be
1326 When all heads of a branch are closed, the branch will be
1327 considered closed.
1327 considered closed.
1328
1328
1329 Returns 0 on success.
1329 Returns 0 on success.
1330 """
1330 """
1331 opts = pycompat.byteskwargs(opts)
1331 opts = pycompat.byteskwargs(opts)
1332 revs = opts.get(b'rev')
1332 revs = opts.get(b'rev')
1333 if label:
1333 if label:
1334 label = label.strip()
1334 label = label.strip()
1335
1335
1336 if not opts.get(b'clean') and not label:
1336 if not opts.get(b'clean') and not label:
1337 if revs:
1337 if revs:
1338 raise error.Abort(_(b"no branch name specified for the revisions"))
1338 raise error.Abort(_(b"no branch name specified for the revisions"))
1339 ui.write(b"%s\n" % repo.dirstate.branch())
1339 ui.write(b"%s\n" % repo.dirstate.branch())
1340 return
1340 return
1341
1341
1342 with repo.wlock():
1342 with repo.wlock():
1343 if opts.get(b'clean'):
1343 if opts.get(b'clean'):
1344 label = repo[b'.'].branch()
1344 label = repo[b'.'].branch()
1345 repo.dirstate.setbranch(label)
1345 repo.dirstate.setbranch(label)
1346 ui.status(_(b'reset working directory to branch %s\n') % label)
1346 ui.status(_(b'reset working directory to branch %s\n') % label)
1347 elif label:
1347 elif label:
1348
1348
1349 scmutil.checknewlabel(repo, label, b'branch')
1349 scmutil.checknewlabel(repo, label, b'branch')
1350 if revs:
1350 if revs:
1351 return cmdutil.changebranch(ui, repo, revs, label)
1351 return cmdutil.changebranch(ui, repo, revs, label)
1352
1352
1353 if not opts.get(b'force') and label in repo.branchmap():
1353 if not opts.get(b'force') and label in repo.branchmap():
1354 if label not in [p.branch() for p in repo[None].parents()]:
1354 if label not in [p.branch() for p in repo[None].parents()]:
1355 raise error.Abort(
1355 raise error.Abort(
1356 _(b'a branch of the same name already exists'),
1356 _(b'a branch of the same name already exists'),
1357 # i18n: "it" refers to an existing branch
1357 # i18n: "it" refers to an existing branch
1358 hint=_(b"use 'hg update' to switch to it"),
1358 hint=_(b"use 'hg update' to switch to it"),
1359 )
1359 )
1360
1360
1361 repo.dirstate.setbranch(label)
1361 repo.dirstate.setbranch(label)
1362 ui.status(_(b'marked working directory as branch %s\n') % label)
1362 ui.status(_(b'marked working directory as branch %s\n') % label)
1363
1363
1364 # find any open named branches aside from default
1364 # find any open named branches aside from default
1365 for n, h, t, c in repo.branchmap().iterbranches():
1365 for n, h, t, c in repo.branchmap().iterbranches():
1366 if n != b"default" and not c:
1366 if n != b"default" and not c:
1367 return 0
1367 return 0
1368 ui.status(
1368 ui.status(
1369 _(
1369 _(
1370 b'(branches are permanent and global, '
1370 b'(branches are permanent and global, '
1371 b'did you want a bookmark?)\n'
1371 b'did you want a bookmark?)\n'
1372 )
1372 )
1373 )
1373 )
1374
1374
1375
1375
1376 @command(
1376 @command(
1377 b'branches',
1377 b'branches',
1378 [
1378 [
1379 (
1379 (
1380 b'a',
1380 b'a',
1381 b'active',
1381 b'active',
1382 False,
1382 False,
1383 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1383 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1384 ),
1384 ),
1385 (b'c', b'closed', False, _(b'show normal and closed branches')),
1385 (b'c', b'closed', False, _(b'show normal and closed branches')),
1386 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1386 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1387 ]
1387 ]
1388 + formatteropts,
1388 + formatteropts,
1389 _(b'[-c]'),
1389 _(b'[-c]'),
1390 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1390 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1391 intents={INTENT_READONLY},
1391 intents={INTENT_READONLY},
1392 )
1392 )
1393 def branches(ui, repo, active=False, closed=False, **opts):
1393 def branches(ui, repo, active=False, closed=False, **opts):
1394 """list repository named branches
1394 """list repository named branches
1395
1395
1396 List the repository's named branches, indicating which ones are
1396 List the repository's named branches, indicating which ones are
1397 inactive. If -c/--closed is specified, also list branches which have
1397 inactive. If -c/--closed is specified, also list branches which have
1398 been marked closed (see :hg:`commit --close-branch`).
1398 been marked closed (see :hg:`commit --close-branch`).
1399
1399
1400 Use the command :hg:`update` to switch to an existing branch.
1400 Use the command :hg:`update` to switch to an existing branch.
1401
1401
1402 .. container:: verbose
1402 .. container:: verbose
1403
1403
1404 Template:
1404 Template:
1405
1405
1406 The following keywords are supported in addition to the common template
1406 The following keywords are supported in addition to the common template
1407 keywords and functions such as ``{branch}``. See also
1407 keywords and functions such as ``{branch}``. See also
1408 :hg:`help templates`.
1408 :hg:`help templates`.
1409
1409
1410 :active: Boolean. True if the branch is active.
1410 :active: Boolean. True if the branch is active.
1411 :closed: Boolean. True if the branch is closed.
1411 :closed: Boolean. True if the branch is closed.
1412 :current: Boolean. True if it is the current branch.
1412 :current: Boolean. True if it is the current branch.
1413
1413
1414 Returns 0.
1414 Returns 0.
1415 """
1415 """
1416
1416
1417 opts = pycompat.byteskwargs(opts)
1417 opts = pycompat.byteskwargs(opts)
1418 revs = opts.get(b'rev')
1418 revs = opts.get(b'rev')
1419 selectedbranches = None
1419 selectedbranches = None
1420 if revs:
1420 if revs:
1421 revs = scmutil.revrange(repo, revs)
1421 revs = scmutil.revrange(repo, revs)
1422 getbi = repo.revbranchcache().branchinfo
1422 getbi = repo.revbranchcache().branchinfo
1423 selectedbranches = {getbi(r)[0] for r in revs}
1423 selectedbranches = {getbi(r)[0] for r in revs}
1424
1424
1425 ui.pager(b'branches')
1425 ui.pager(b'branches')
1426 fm = ui.formatter(b'branches', opts)
1426 fm = ui.formatter(b'branches', opts)
1427 hexfunc = fm.hexfunc
1427 hexfunc = fm.hexfunc
1428
1428
1429 allheads = set(repo.heads())
1429 allheads = set(repo.heads())
1430 branches = []
1430 branches = []
1431 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1431 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1432 if selectedbranches is not None and tag not in selectedbranches:
1432 if selectedbranches is not None and tag not in selectedbranches:
1433 continue
1433 continue
1434 isactive = False
1434 isactive = False
1435 if not isclosed:
1435 if not isclosed:
1436 openheads = set(repo.branchmap().iteropen(heads))
1436 openheads = set(repo.branchmap().iteropen(heads))
1437 isactive = bool(openheads & allheads)
1437 isactive = bool(openheads & allheads)
1438 branches.append((tag, repo[tip], isactive, not isclosed))
1438 branches.append((tag, repo[tip], isactive, not isclosed))
1439 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1439 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1440
1440
1441 for tag, ctx, isactive, isopen in branches:
1441 for tag, ctx, isactive, isopen in branches:
1442 if active and not isactive:
1442 if active and not isactive:
1443 continue
1443 continue
1444 if isactive:
1444 if isactive:
1445 label = b'branches.active'
1445 label = b'branches.active'
1446 notice = b''
1446 notice = b''
1447 elif not isopen:
1447 elif not isopen:
1448 if not closed:
1448 if not closed:
1449 continue
1449 continue
1450 label = b'branches.closed'
1450 label = b'branches.closed'
1451 notice = _(b' (closed)')
1451 notice = _(b' (closed)')
1452 else:
1452 else:
1453 label = b'branches.inactive'
1453 label = b'branches.inactive'
1454 notice = _(b' (inactive)')
1454 notice = _(b' (inactive)')
1455 current = tag == repo.dirstate.branch()
1455 current = tag == repo.dirstate.branch()
1456 if current:
1456 if current:
1457 label = b'branches.current'
1457 label = b'branches.current'
1458
1458
1459 fm.startitem()
1459 fm.startitem()
1460 fm.write(b'branch', b'%s', tag, label=label)
1460 fm.write(b'branch', b'%s', tag, label=label)
1461 rev = ctx.rev()
1461 rev = ctx.rev()
1462 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1462 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1463 fmt = b' ' * padsize + b' %d:%s'
1463 fmt = b' ' * padsize + b' %d:%s'
1464 fm.condwrite(
1464 fm.condwrite(
1465 not ui.quiet,
1465 not ui.quiet,
1466 b'rev node',
1466 b'rev node',
1467 fmt,
1467 fmt,
1468 rev,
1468 rev,
1469 hexfunc(ctx.node()),
1469 hexfunc(ctx.node()),
1470 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1470 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1471 )
1471 )
1472 fm.context(ctx=ctx)
1472 fm.context(ctx=ctx)
1473 fm.data(active=isactive, closed=not isopen, current=current)
1473 fm.data(active=isactive, closed=not isopen, current=current)
1474 if not ui.quiet:
1474 if not ui.quiet:
1475 fm.plain(notice)
1475 fm.plain(notice)
1476 fm.plain(b'\n')
1476 fm.plain(b'\n')
1477 fm.end()
1477 fm.end()
1478
1478
1479
1479
1480 @command(
1480 @command(
1481 b'bundle',
1481 b'bundle',
1482 [
1482 [
1483 (
1483 (
1484 b'f',
1484 b'f',
1485 b'force',
1485 b'force',
1486 None,
1486 None,
1487 _(b'run even when the destination is unrelated'),
1487 _(b'run even when the destination is unrelated'),
1488 ),
1488 ),
1489 (
1489 (
1490 b'r',
1490 b'r',
1491 b'rev',
1491 b'rev',
1492 [],
1492 [],
1493 _(b'a changeset intended to be added to the destination'),
1493 _(b'a changeset intended to be added to the destination'),
1494 _(b'REV'),
1494 _(b'REV'),
1495 ),
1495 ),
1496 (
1496 (
1497 b'b',
1497 b'b',
1498 b'branch',
1498 b'branch',
1499 [],
1499 [],
1500 _(b'a specific branch you would like to bundle'),
1500 _(b'a specific branch you would like to bundle'),
1501 _(b'BRANCH'),
1501 _(b'BRANCH'),
1502 ),
1502 ),
1503 (
1503 (
1504 b'',
1504 b'',
1505 b'base',
1505 b'base',
1506 [],
1506 [],
1507 _(b'a base changeset assumed to be available at the destination'),
1507 _(b'a base changeset assumed to be available at the destination'),
1508 _(b'REV'),
1508 _(b'REV'),
1509 ),
1509 ),
1510 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1510 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1511 (
1511 (
1512 b't',
1512 b't',
1513 b'type',
1513 b'type',
1514 b'bzip2',
1514 b'bzip2',
1515 _(b'bundle compression type to use'),
1515 _(b'bundle compression type to use'),
1516 _(b'TYPE'),
1516 _(b'TYPE'),
1517 ),
1517 ),
1518 ]
1518 ]
1519 + remoteopts,
1519 + remoteopts,
1520 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1520 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1521 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1521 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1522 )
1522 )
1523 def bundle(ui, repo, fname, dest=None, **opts):
1523 def bundle(ui, repo, fname, dest=None, **opts):
1524 """create a bundle file
1524 """create a bundle file
1525
1525
1526 Generate a bundle file containing data to be transferred to another
1526 Generate a bundle file containing data to be transferred to another
1527 repository.
1527 repository.
1528
1528
1529 To create a bundle containing all changesets, use -a/--all
1529 To create a bundle containing all changesets, use -a/--all
1530 (or --base null). Otherwise, hg assumes the destination will have
1530 (or --base null). Otherwise, hg assumes the destination will have
1531 all the nodes you specify with --base parameters. Otherwise, hg
1531 all the nodes you specify with --base parameters. Otherwise, hg
1532 will assume the repository has all the nodes in destination, or
1532 will assume the repository has all the nodes in destination, or
1533 default-push/default if no destination is specified, where destination
1533 default-push/default if no destination is specified, where destination
1534 is the repository you provide through DEST option.
1534 is the repository you provide through DEST option.
1535
1535
1536 You can change bundle format with the -t/--type option. See
1536 You can change bundle format with the -t/--type option. See
1537 :hg:`help bundlespec` for documentation on this format. By default,
1537 :hg:`help bundlespec` for documentation on this format. By default,
1538 the most appropriate format is used and compression defaults to
1538 the most appropriate format is used and compression defaults to
1539 bzip2.
1539 bzip2.
1540
1540
1541 The bundle file can then be transferred using conventional means
1541 The bundle file can then be transferred using conventional means
1542 and applied to another repository with the unbundle or pull
1542 and applied to another repository with the unbundle or pull
1543 command. This is useful when direct push and pull are not
1543 command. This is useful when direct push and pull are not
1544 available or when exporting an entire repository is undesirable.
1544 available or when exporting an entire repository is undesirable.
1545
1545
1546 Applying bundles preserves all changeset contents including
1546 Applying bundles preserves all changeset contents including
1547 permissions, copy/rename information, and revision history.
1547 permissions, copy/rename information, and revision history.
1548
1548
1549 Returns 0 on success, 1 if no changes found.
1549 Returns 0 on success, 1 if no changes found.
1550 """
1550 """
1551 opts = pycompat.byteskwargs(opts)
1551 opts = pycompat.byteskwargs(opts)
1552 revs = None
1552 revs = None
1553 if b'rev' in opts:
1553 if b'rev' in opts:
1554 revstrings = opts[b'rev']
1554 revstrings = opts[b'rev']
1555 revs = scmutil.revrange(repo, revstrings)
1555 revs = scmutil.revrange(repo, revstrings)
1556 if revstrings and not revs:
1556 if revstrings and not revs:
1557 raise error.Abort(_(b'no commits to bundle'))
1557 raise error.Abort(_(b'no commits to bundle'))
1558
1558
1559 bundletype = opts.get(b'type', b'bzip2').lower()
1559 bundletype = opts.get(b'type', b'bzip2').lower()
1560 try:
1560 try:
1561 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1561 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1562 except error.UnsupportedBundleSpecification as e:
1562 except error.UnsupportedBundleSpecification as e:
1563 raise error.Abort(
1563 raise error.Abort(
1564 pycompat.bytestr(e),
1564 pycompat.bytestr(e),
1565 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1565 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1566 )
1566 )
1567 cgversion = bundlespec.contentopts[b"cg.version"]
1567 cgversion = bundlespec.contentopts[b"cg.version"]
1568
1568
1569 # Packed bundles are a pseudo bundle format for now.
1569 # Packed bundles are a pseudo bundle format for now.
1570 if cgversion == b's1':
1570 if cgversion == b's1':
1571 raise error.Abort(
1571 raise error.Abort(
1572 _(b'packed bundles cannot be produced by "hg bundle"'),
1572 _(b'packed bundles cannot be produced by "hg bundle"'),
1573 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1573 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1574 )
1574 )
1575
1575
1576 if opts.get(b'all'):
1576 if opts.get(b'all'):
1577 if dest:
1577 if dest:
1578 raise error.Abort(
1578 raise error.Abort(
1579 _(b"--all is incompatible with specifying a destination")
1579 _(b"--all is incompatible with specifying a destination")
1580 )
1580 )
1581 if opts.get(b'base'):
1581 if opts.get(b'base'):
1582 ui.warn(_(b"ignoring --base because --all was specified\n"))
1582 ui.warn(_(b"ignoring --base because --all was specified\n"))
1583 base = [nullrev]
1583 base = [nullrev]
1584 else:
1584 else:
1585 base = scmutil.revrange(repo, opts.get(b'base'))
1585 base = scmutil.revrange(repo, opts.get(b'base'))
1586 if cgversion not in changegroup.supportedoutgoingversions(repo):
1586 if cgversion not in changegroup.supportedoutgoingversions(repo):
1587 raise error.Abort(
1587 raise error.Abort(
1588 _(b"repository does not support bundle version %s") % cgversion
1588 _(b"repository does not support bundle version %s") % cgversion
1589 )
1589 )
1590
1590
1591 if base:
1591 if base:
1592 if dest:
1592 if dest:
1593 raise error.Abort(
1593 raise error.Abort(
1594 _(b"--base is incompatible with specifying a destination")
1594 _(b"--base is incompatible with specifying a destination")
1595 )
1595 )
1596 common = [repo[rev].node() for rev in base]
1596 common = [repo[rev].node() for rev in base]
1597 heads = [repo[r].node() for r in revs] if revs else None
1597 heads = [repo[r].node() for r in revs] if revs else None
1598 outgoing = discovery.outgoing(repo, common, heads)
1598 outgoing = discovery.outgoing(repo, common, heads)
1599 else:
1599 else:
1600 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1600 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1601 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1601 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1602 other = hg.peer(repo, opts, dest)
1602 other = hg.peer(repo, opts, dest)
1603 revs = [repo[r].hex() for r in revs]
1603 revs = [repo[r].hex() for r in revs]
1604 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1604 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1605 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1605 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1606 outgoing = discovery.findcommonoutgoing(
1606 outgoing = discovery.findcommonoutgoing(
1607 repo,
1607 repo,
1608 other,
1608 other,
1609 onlyheads=heads,
1609 onlyheads=heads,
1610 force=opts.get(b'force'),
1610 force=opts.get(b'force'),
1611 portable=True,
1611 portable=True,
1612 )
1612 )
1613
1613
1614 if not outgoing.missing:
1614 if not outgoing.missing:
1615 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1615 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1616 return 1
1616 return 1
1617
1617
1618 if cgversion == b'01': # bundle1
1618 if cgversion == b'01': # bundle1
1619 bversion = b'HG10' + bundlespec.wirecompression
1619 bversion = b'HG10' + bundlespec.wirecompression
1620 bcompression = None
1620 bcompression = None
1621 elif cgversion in (b'02', b'03'):
1621 elif cgversion in (b'02', b'03'):
1622 bversion = b'HG20'
1622 bversion = b'HG20'
1623 bcompression = bundlespec.wirecompression
1623 bcompression = bundlespec.wirecompression
1624 else:
1624 else:
1625 raise error.ProgrammingError(
1625 raise error.ProgrammingError(
1626 b'bundle: unexpected changegroup version %s' % cgversion
1626 b'bundle: unexpected changegroup version %s' % cgversion
1627 )
1627 )
1628
1628
1629 # TODO compression options should be derived from bundlespec parsing.
1629 # TODO compression options should be derived from bundlespec parsing.
1630 # This is a temporary hack to allow adjusting bundle compression
1630 # This is a temporary hack to allow adjusting bundle compression
1631 # level without a) formalizing the bundlespec changes to declare it
1631 # level without a) formalizing the bundlespec changes to declare it
1632 # b) introducing a command flag.
1632 # b) introducing a command flag.
1633 compopts = {}
1633 compopts = {}
1634 complevel = ui.configint(
1634 complevel = ui.configint(
1635 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1635 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1636 )
1636 )
1637 if complevel is None:
1637 if complevel is None:
1638 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1638 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1639 if complevel is not None:
1639 if complevel is not None:
1640 compopts[b'level'] = complevel
1640 compopts[b'level'] = complevel
1641
1641
1642 # Allow overriding the bundling of obsmarker in phases through
1642 # Allow overriding the bundling of obsmarker in phases through
1643 # configuration while we don't have a bundle version that include them
1643 # configuration while we don't have a bundle version that include them
1644 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1644 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1645 bundlespec.contentopts[b'obsolescence'] = True
1645 bundlespec.contentopts[b'obsolescence'] = True
1646 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1646 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1647 bundlespec.contentopts[b'phases'] = True
1647 bundlespec.contentopts[b'phases'] = True
1648
1648
1649 bundle2.writenewbundle(
1649 bundle2.writenewbundle(
1650 ui,
1650 ui,
1651 repo,
1651 repo,
1652 b'bundle',
1652 b'bundle',
1653 fname,
1653 fname,
1654 bversion,
1654 bversion,
1655 outgoing,
1655 outgoing,
1656 bundlespec.contentopts,
1656 bundlespec.contentopts,
1657 compression=bcompression,
1657 compression=bcompression,
1658 compopts=compopts,
1658 compopts=compopts,
1659 )
1659 )
1660
1660
1661
1661
1662 @command(
1662 @command(
1663 b'cat',
1663 b'cat',
1664 [
1664 [
1665 (
1665 (
1666 b'o',
1666 b'o',
1667 b'output',
1667 b'output',
1668 b'',
1668 b'',
1669 _(b'print output to file with formatted name'),
1669 _(b'print output to file with formatted name'),
1670 _(b'FORMAT'),
1670 _(b'FORMAT'),
1671 ),
1671 ),
1672 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1672 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1673 (b'', b'decode', None, _(b'apply any matching decode filter')),
1673 (b'', b'decode', None, _(b'apply any matching decode filter')),
1674 ]
1674 ]
1675 + walkopts
1675 + walkopts
1676 + formatteropts,
1676 + formatteropts,
1677 _(b'[OPTION]... FILE...'),
1677 _(b'[OPTION]... FILE...'),
1678 helpcategory=command.CATEGORY_FILE_CONTENTS,
1678 helpcategory=command.CATEGORY_FILE_CONTENTS,
1679 inferrepo=True,
1679 inferrepo=True,
1680 intents={INTENT_READONLY},
1680 intents={INTENT_READONLY},
1681 )
1681 )
1682 def cat(ui, repo, file1, *pats, **opts):
1682 def cat(ui, repo, file1, *pats, **opts):
1683 """output the current or given revision of files
1683 """output the current or given revision of files
1684
1684
1685 Print the specified files as they were at the given revision. If
1685 Print the specified files as they were at the given revision. If
1686 no revision is given, the parent of the working directory is used.
1686 no revision is given, the parent of the working directory is used.
1687
1687
1688 Output may be to a file, in which case the name of the file is
1688 Output may be to a file, in which case the name of the file is
1689 given using a template string. See :hg:`help templates`. In addition
1689 given using a template string. See :hg:`help templates`. In addition
1690 to the common template keywords, the following formatting rules are
1690 to the common template keywords, the following formatting rules are
1691 supported:
1691 supported:
1692
1692
1693 :``%%``: literal "%" character
1693 :``%%``: literal "%" character
1694 :``%s``: basename of file being printed
1694 :``%s``: basename of file being printed
1695 :``%d``: dirname of file being printed, or '.' if in repository root
1695 :``%d``: dirname of file being printed, or '.' if in repository root
1696 :``%p``: root-relative path name of file being printed
1696 :``%p``: root-relative path name of file being printed
1697 :``%H``: changeset hash (40 hexadecimal digits)
1697 :``%H``: changeset hash (40 hexadecimal digits)
1698 :``%R``: changeset revision number
1698 :``%R``: changeset revision number
1699 :``%h``: short-form changeset hash (12 hexadecimal digits)
1699 :``%h``: short-form changeset hash (12 hexadecimal digits)
1700 :``%r``: zero-padded changeset revision number
1700 :``%r``: zero-padded changeset revision number
1701 :``%b``: basename of the exporting repository
1701 :``%b``: basename of the exporting repository
1702 :``\\``: literal "\\" character
1702 :``\\``: literal "\\" character
1703
1703
1704 .. container:: verbose
1704 .. container:: verbose
1705
1705
1706 Template:
1706 Template:
1707
1707
1708 The following keywords are supported in addition to the common template
1708 The following keywords are supported in addition to the common template
1709 keywords and functions. See also :hg:`help templates`.
1709 keywords and functions. See also :hg:`help templates`.
1710
1710
1711 :data: String. File content.
1711 :data: String. File content.
1712 :path: String. Repository-absolute path of the file.
1712 :path: String. Repository-absolute path of the file.
1713
1713
1714 Returns 0 on success.
1714 Returns 0 on success.
1715 """
1715 """
1716 opts = pycompat.byteskwargs(opts)
1716 opts = pycompat.byteskwargs(opts)
1717 rev = opts.get(b'rev')
1717 rev = opts.get(b'rev')
1718 if rev:
1718 if rev:
1719 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1719 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1720 ctx = scmutil.revsingle(repo, rev)
1720 ctx = scmutil.revsingle(repo, rev)
1721 m = scmutil.match(ctx, (file1,) + pats, opts)
1721 m = scmutil.match(ctx, (file1,) + pats, opts)
1722 fntemplate = opts.pop(b'output', b'')
1722 fntemplate = opts.pop(b'output', b'')
1723 if cmdutil.isstdiofilename(fntemplate):
1723 if cmdutil.isstdiofilename(fntemplate):
1724 fntemplate = b''
1724 fntemplate = b''
1725
1725
1726 if fntemplate:
1726 if fntemplate:
1727 fm = formatter.nullformatter(ui, b'cat', opts)
1727 fm = formatter.nullformatter(ui, b'cat', opts)
1728 else:
1728 else:
1729 ui.pager(b'cat')
1729 ui.pager(b'cat')
1730 fm = ui.formatter(b'cat', opts)
1730 fm = ui.formatter(b'cat', opts)
1731 with fm:
1731 with fm:
1732 return cmdutil.cat(
1732 return cmdutil.cat(
1733 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1733 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1734 )
1734 )
1735
1735
1736
1736
1737 @command(
1737 @command(
1738 b'clone',
1738 b'clone',
1739 [
1739 [
1740 (
1740 (
1741 b'U',
1741 b'U',
1742 b'noupdate',
1742 b'noupdate',
1743 None,
1743 None,
1744 _(
1744 _(
1745 b'the clone will include an empty working '
1745 b'the clone will include an empty working '
1746 b'directory (only a repository)'
1746 b'directory (only a repository)'
1747 ),
1747 ),
1748 ),
1748 ),
1749 (
1749 (
1750 b'u',
1750 b'u',
1751 b'updaterev',
1751 b'updaterev',
1752 b'',
1752 b'',
1753 _(b'revision, tag, or branch to check out'),
1753 _(b'revision, tag, or branch to check out'),
1754 _(b'REV'),
1754 _(b'REV'),
1755 ),
1755 ),
1756 (
1756 (
1757 b'r',
1757 b'r',
1758 b'rev',
1758 b'rev',
1759 [],
1759 [],
1760 _(
1760 _(
1761 b'do not clone everything, but include this changeset'
1761 b'do not clone everything, but include this changeset'
1762 b' and its ancestors'
1762 b' and its ancestors'
1763 ),
1763 ),
1764 _(b'REV'),
1764 _(b'REV'),
1765 ),
1765 ),
1766 (
1766 (
1767 b'b',
1767 b'b',
1768 b'branch',
1768 b'branch',
1769 [],
1769 [],
1770 _(
1770 _(
1771 b'do not clone everything, but include this branch\'s'
1771 b'do not clone everything, but include this branch\'s'
1772 b' changesets and their ancestors'
1772 b' changesets and their ancestors'
1773 ),
1773 ),
1774 _(b'BRANCH'),
1774 _(b'BRANCH'),
1775 ),
1775 ),
1776 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1776 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1777 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1777 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1778 (b'', b'stream', None, _(b'clone with minimal data processing')),
1778 (b'', b'stream', None, _(b'clone with minimal data processing')),
1779 ]
1779 ]
1780 + remoteopts,
1780 + remoteopts,
1781 _(b'[OPTION]... SOURCE [DEST]'),
1781 _(b'[OPTION]... SOURCE [DEST]'),
1782 helpcategory=command.CATEGORY_REPO_CREATION,
1782 helpcategory=command.CATEGORY_REPO_CREATION,
1783 helpbasic=True,
1783 helpbasic=True,
1784 norepo=True,
1784 norepo=True,
1785 )
1785 )
1786 def clone(ui, source, dest=None, **opts):
1786 def clone(ui, source, dest=None, **opts):
1787 """make a copy of an existing repository
1787 """make a copy of an existing repository
1788
1788
1789 Create a copy of an existing repository in a new directory.
1789 Create a copy of an existing repository in a new directory.
1790
1790
1791 If no destination directory name is specified, it defaults to the
1791 If no destination directory name is specified, it defaults to the
1792 basename of the source.
1792 basename of the source.
1793
1793
1794 The location of the source is added to the new repository's
1794 The location of the source is added to the new repository's
1795 ``.hg/hgrc`` file, as the default to be used for future pulls.
1795 ``.hg/hgrc`` file, as the default to be used for future pulls.
1796
1796
1797 Only local paths and ``ssh://`` URLs are supported as
1797 Only local paths and ``ssh://`` URLs are supported as
1798 destinations. For ``ssh://`` destinations, no working directory or
1798 destinations. For ``ssh://`` destinations, no working directory or
1799 ``.hg/hgrc`` will be created on the remote side.
1799 ``.hg/hgrc`` will be created on the remote side.
1800
1800
1801 If the source repository has a bookmark called '@' set, that
1801 If the source repository has a bookmark called '@' set, that
1802 revision will be checked out in the new repository by default.
1802 revision will be checked out in the new repository by default.
1803
1803
1804 To check out a particular version, use -u/--update, or
1804 To check out a particular version, use -u/--update, or
1805 -U/--noupdate to create a clone with no working directory.
1805 -U/--noupdate to create a clone with no working directory.
1806
1806
1807 To pull only a subset of changesets, specify one or more revisions
1807 To pull only a subset of changesets, specify one or more revisions
1808 identifiers with -r/--rev or branches with -b/--branch. The
1808 identifiers with -r/--rev or branches with -b/--branch. The
1809 resulting clone will contain only the specified changesets and
1809 resulting clone will contain only the specified changesets and
1810 their ancestors. These options (or 'clone src#rev dest') imply
1810 their ancestors. These options (or 'clone src#rev dest') imply
1811 --pull, even for local source repositories.
1811 --pull, even for local source repositories.
1812
1812
1813 In normal clone mode, the remote normalizes repository data into a common
1813 In normal clone mode, the remote normalizes repository data into a common
1814 exchange format and the receiving end translates this data into its local
1814 exchange format and the receiving end translates this data into its local
1815 storage format. --stream activates a different clone mode that essentially
1815 storage format. --stream activates a different clone mode that essentially
1816 copies repository files from the remote with minimal data processing. This
1816 copies repository files from the remote with minimal data processing. This
1817 significantly reduces the CPU cost of a clone both remotely and locally.
1817 significantly reduces the CPU cost of a clone both remotely and locally.
1818 However, it often increases the transferred data size by 30-40%. This can
1818 However, it often increases the transferred data size by 30-40%. This can
1819 result in substantially faster clones where I/O throughput is plentiful,
1819 result in substantially faster clones where I/O throughput is plentiful,
1820 especially for larger repositories. A side-effect of --stream clones is
1820 especially for larger repositories. A side-effect of --stream clones is
1821 that storage settings and requirements on the remote are applied locally:
1821 that storage settings and requirements on the remote are applied locally:
1822 a modern client may inherit legacy or inefficient storage used by the
1822 a modern client may inherit legacy or inefficient storage used by the
1823 remote or a legacy Mercurial client may not be able to clone from a
1823 remote or a legacy Mercurial client may not be able to clone from a
1824 modern Mercurial remote.
1824 modern Mercurial remote.
1825
1825
1826 .. note::
1826 .. note::
1827
1827
1828 Specifying a tag will include the tagged changeset but not the
1828 Specifying a tag will include the tagged changeset but not the
1829 changeset containing the tag.
1829 changeset containing the tag.
1830
1830
1831 .. container:: verbose
1831 .. container:: verbose
1832
1832
1833 For efficiency, hardlinks are used for cloning whenever the
1833 For efficiency, hardlinks are used for cloning whenever the
1834 source and destination are on the same filesystem (note this
1834 source and destination are on the same filesystem (note this
1835 applies only to the repository data, not to the working
1835 applies only to the repository data, not to the working
1836 directory). Some filesystems, such as AFS, implement hardlinking
1836 directory). Some filesystems, such as AFS, implement hardlinking
1837 incorrectly, but do not report errors. In these cases, use the
1837 incorrectly, but do not report errors. In these cases, use the
1838 --pull option to avoid hardlinking.
1838 --pull option to avoid hardlinking.
1839
1839
1840 Mercurial will update the working directory to the first applicable
1840 Mercurial will update the working directory to the first applicable
1841 revision from this list:
1841 revision from this list:
1842
1842
1843 a) null if -U or the source repository has no changesets
1843 a) null if -U or the source repository has no changesets
1844 b) if -u . and the source repository is local, the first parent of
1844 b) if -u . and the source repository is local, the first parent of
1845 the source repository's working directory
1845 the source repository's working directory
1846 c) the changeset specified with -u (if a branch name, this means the
1846 c) the changeset specified with -u (if a branch name, this means the
1847 latest head of that branch)
1847 latest head of that branch)
1848 d) the changeset specified with -r
1848 d) the changeset specified with -r
1849 e) the tipmost head specified with -b
1849 e) the tipmost head specified with -b
1850 f) the tipmost head specified with the url#branch source syntax
1850 f) the tipmost head specified with the url#branch source syntax
1851 g) the revision marked with the '@' bookmark, if present
1851 g) the revision marked with the '@' bookmark, if present
1852 h) the tipmost head of the default branch
1852 h) the tipmost head of the default branch
1853 i) tip
1853 i) tip
1854
1854
1855 When cloning from servers that support it, Mercurial may fetch
1855 When cloning from servers that support it, Mercurial may fetch
1856 pre-generated data from a server-advertised URL or inline from the
1856 pre-generated data from a server-advertised URL or inline from the
1857 same stream. When this is done, hooks operating on incoming changesets
1857 same stream. When this is done, hooks operating on incoming changesets
1858 and changegroups may fire more than once, once for each pre-generated
1858 and changegroups may fire more than once, once for each pre-generated
1859 bundle and as well as for any additional remaining data. In addition,
1859 bundle and as well as for any additional remaining data. In addition,
1860 if an error occurs, the repository may be rolled back to a partial
1860 if an error occurs, the repository may be rolled back to a partial
1861 clone. This behavior may change in future releases.
1861 clone. This behavior may change in future releases.
1862 See :hg:`help -e clonebundles` for more.
1862 See :hg:`help -e clonebundles` for more.
1863
1863
1864 Examples:
1864 Examples:
1865
1865
1866 - clone a remote repository to a new directory named hg/::
1866 - clone a remote repository to a new directory named hg/::
1867
1867
1868 hg clone https://www.mercurial-scm.org/repo/hg/
1868 hg clone https://www.mercurial-scm.org/repo/hg/
1869
1869
1870 - create a lightweight local clone::
1870 - create a lightweight local clone::
1871
1871
1872 hg clone project/ project-feature/
1872 hg clone project/ project-feature/
1873
1873
1874 - clone from an absolute path on an ssh server (note double-slash)::
1874 - clone from an absolute path on an ssh server (note double-slash)::
1875
1875
1876 hg clone ssh://user@server//home/projects/alpha/
1876 hg clone ssh://user@server//home/projects/alpha/
1877
1877
1878 - do a streaming clone while checking out a specified version::
1878 - do a streaming clone while checking out a specified version::
1879
1879
1880 hg clone --stream http://server/repo -u 1.5
1880 hg clone --stream http://server/repo -u 1.5
1881
1881
1882 - create a repository without changesets after a particular revision::
1882 - create a repository without changesets after a particular revision::
1883
1883
1884 hg clone -r 04e544 experimental/ good/
1884 hg clone -r 04e544 experimental/ good/
1885
1885
1886 - clone (and track) a particular named branch::
1886 - clone (and track) a particular named branch::
1887
1887
1888 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1888 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1889
1889
1890 See :hg:`help urls` for details on specifying URLs.
1890 See :hg:`help urls` for details on specifying URLs.
1891
1891
1892 Returns 0 on success.
1892 Returns 0 on success.
1893 """
1893 """
1894 opts = pycompat.byteskwargs(opts)
1894 opts = pycompat.byteskwargs(opts)
1895 if opts.get(b'noupdate') and opts.get(b'updaterev'):
1895 if opts.get(b'noupdate') and opts.get(b'updaterev'):
1896 raise error.Abort(_(b"cannot specify both --noupdate and --updaterev"))
1896 raise error.Abort(_(b"cannot specify both --noupdate and --updaterev"))
1897
1897
1898 # --include/--exclude can come from narrow or sparse.
1898 # --include/--exclude can come from narrow or sparse.
1899 includepats, excludepats = None, None
1899 includepats, excludepats = None, None
1900
1900
1901 # hg.clone() differentiates between None and an empty set. So make sure
1901 # hg.clone() differentiates between None and an empty set. So make sure
1902 # patterns are sets if narrow is requested without patterns.
1902 # patterns are sets if narrow is requested without patterns.
1903 if opts.get(b'narrow'):
1903 if opts.get(b'narrow'):
1904 includepats = set()
1904 includepats = set()
1905 excludepats = set()
1905 excludepats = set()
1906
1906
1907 if opts.get(b'include'):
1907 if opts.get(b'include'):
1908 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1908 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1909 if opts.get(b'exclude'):
1909 if opts.get(b'exclude'):
1910 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1910 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1911
1911
1912 r = hg.clone(
1912 r = hg.clone(
1913 ui,
1913 ui,
1914 opts,
1914 opts,
1915 source,
1915 source,
1916 dest,
1916 dest,
1917 pull=opts.get(b'pull'),
1917 pull=opts.get(b'pull'),
1918 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1918 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1919 revs=opts.get(b'rev'),
1919 revs=opts.get(b'rev'),
1920 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1920 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1921 branch=opts.get(b'branch'),
1921 branch=opts.get(b'branch'),
1922 shareopts=opts.get(b'shareopts'),
1922 shareopts=opts.get(b'shareopts'),
1923 storeincludepats=includepats,
1923 storeincludepats=includepats,
1924 storeexcludepats=excludepats,
1924 storeexcludepats=excludepats,
1925 depth=opts.get(b'depth') or None,
1925 depth=opts.get(b'depth') or None,
1926 )
1926 )
1927
1927
1928 return r is None
1928 return r is None
1929
1929
1930
1930
1931 @command(
1931 @command(
1932 b'commit|ci',
1932 b'commit|ci',
1933 [
1933 [
1934 (
1934 (
1935 b'A',
1935 b'A',
1936 b'addremove',
1936 b'addremove',
1937 None,
1937 None,
1938 _(b'mark new/missing files as added/removed before committing'),
1938 _(b'mark new/missing files as added/removed before committing'),
1939 ),
1939 ),
1940 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1940 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1941 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1941 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1942 (b's', b'secret', None, _(b'use the secret phase for committing')),
1942 (b's', b'secret', None, _(b'use the secret phase for committing')),
1943 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1943 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1944 (
1944 (
1945 b'',
1945 b'',
1946 b'force-close-branch',
1946 b'force-close-branch',
1947 None,
1947 None,
1948 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1948 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1949 ),
1949 ),
1950 (b'i', b'interactive', None, _(b'use interactive mode')),
1950 (b'i', b'interactive', None, _(b'use interactive mode')),
1951 ]
1951 ]
1952 + walkopts
1952 + walkopts
1953 + commitopts
1953 + commitopts
1954 + commitopts2
1954 + commitopts2
1955 + subrepoopts,
1955 + subrepoopts,
1956 _(b'[OPTION]... [FILE]...'),
1956 _(b'[OPTION]... [FILE]...'),
1957 helpcategory=command.CATEGORY_COMMITTING,
1957 helpcategory=command.CATEGORY_COMMITTING,
1958 helpbasic=True,
1958 helpbasic=True,
1959 inferrepo=True,
1959 inferrepo=True,
1960 )
1960 )
1961 def commit(ui, repo, *pats, **opts):
1961 def commit(ui, repo, *pats, **opts):
1962 """commit the specified files or all outstanding changes
1962 """commit the specified files or all outstanding changes
1963
1963
1964 Commit changes to the given files into the repository. Unlike a
1964 Commit changes to the given files into the repository. Unlike a
1965 centralized SCM, this operation is a local operation. See
1965 centralized SCM, this operation is a local operation. See
1966 :hg:`push` for a way to actively distribute your changes.
1966 :hg:`push` for a way to actively distribute your changes.
1967
1967
1968 If a list of files is omitted, all changes reported by :hg:`status`
1968 If a list of files is omitted, all changes reported by :hg:`status`
1969 will be committed.
1969 will be committed.
1970
1970
1971 If you are committing the result of a merge, do not provide any
1971 If you are committing the result of a merge, do not provide any
1972 filenames or -I/-X filters.
1972 filenames or -I/-X filters.
1973
1973
1974 If no commit message is specified, Mercurial starts your
1974 If no commit message is specified, Mercurial starts your
1975 configured editor where you can enter a message. In case your
1975 configured editor where you can enter a message. In case your
1976 commit fails, you will find a backup of your message in
1976 commit fails, you will find a backup of your message in
1977 ``.hg/last-message.txt``.
1977 ``.hg/last-message.txt``.
1978
1978
1979 The --close-branch flag can be used to mark the current branch
1979 The --close-branch flag can be used to mark the current branch
1980 head closed. When all heads of a branch are closed, the branch
1980 head closed. When all heads of a branch are closed, the branch
1981 will be considered closed and no longer listed.
1981 will be considered closed and no longer listed.
1982
1982
1983 The --amend flag can be used to amend the parent of the
1983 The --amend flag can be used to amend the parent of the
1984 working directory with a new commit that contains the changes
1984 working directory with a new commit that contains the changes
1985 in the parent in addition to those currently reported by :hg:`status`,
1985 in the parent in addition to those currently reported by :hg:`status`,
1986 if there are any. The old commit is stored in a backup bundle in
1986 if there are any. The old commit is stored in a backup bundle in
1987 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1987 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1988 on how to restore it).
1988 on how to restore it).
1989
1989
1990 Message, user and date are taken from the amended commit unless
1990 Message, user and date are taken from the amended commit unless
1991 specified. When a message isn't specified on the command line,
1991 specified. When a message isn't specified on the command line,
1992 the editor will open with the message of the amended commit.
1992 the editor will open with the message of the amended commit.
1993
1993
1994 It is not possible to amend public changesets (see :hg:`help phases`)
1994 It is not possible to amend public changesets (see :hg:`help phases`)
1995 or changesets that have children.
1995 or changesets that have children.
1996
1996
1997 See :hg:`help dates` for a list of formats valid for -d/--date.
1997 See :hg:`help dates` for a list of formats valid for -d/--date.
1998
1998
1999 Returns 0 on success, 1 if nothing changed.
1999 Returns 0 on success, 1 if nothing changed.
2000
2000
2001 .. container:: verbose
2001 .. container:: verbose
2002
2002
2003 Examples:
2003 Examples:
2004
2004
2005 - commit all files ending in .py::
2005 - commit all files ending in .py::
2006
2006
2007 hg commit --include "set:**.py"
2007 hg commit --include "set:**.py"
2008
2008
2009 - commit all non-binary files::
2009 - commit all non-binary files::
2010
2010
2011 hg commit --exclude "set:binary()"
2011 hg commit --exclude "set:binary()"
2012
2012
2013 - amend the current commit and set the date to now::
2013 - amend the current commit and set the date to now::
2014
2014
2015 hg commit --amend --date now
2015 hg commit --amend --date now
2016 """
2016 """
2017 with repo.wlock(), repo.lock():
2017 with repo.wlock(), repo.lock():
2018 return _docommit(ui, repo, *pats, **opts)
2018 return _docommit(ui, repo, *pats, **opts)
2019
2019
2020
2020
2021 def _docommit(ui, repo, *pats, **opts):
2021 def _docommit(ui, repo, *pats, **opts):
2022 if opts.get(r'interactive'):
2022 if opts.get(r'interactive'):
2023 opts.pop(r'interactive')
2023 opts.pop(r'interactive')
2024 ret = cmdutil.dorecord(
2024 ret = cmdutil.dorecord(
2025 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2025 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2026 )
2026 )
2027 # ret can be 0 (no changes to record) or the value returned by
2027 # ret can be 0 (no changes to record) or the value returned by
2028 # commit(), 1 if nothing changed or None on success.
2028 # commit(), 1 if nothing changed or None on success.
2029 return 1 if ret == 0 else ret
2029 return 1 if ret == 0 else ret
2030
2030
2031 opts = pycompat.byteskwargs(opts)
2031 opts = pycompat.byteskwargs(opts)
2032 if opts.get(b'subrepos'):
2032 if opts.get(b'subrepos'):
2033 if opts.get(b'amend'):
2033 if opts.get(b'amend'):
2034 raise error.Abort(_(b'cannot amend with --subrepos'))
2034 raise error.Abort(_(b'cannot amend with --subrepos'))
2035 # Let --subrepos on the command line override config setting.
2035 # Let --subrepos on the command line override config setting.
2036 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2036 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2037
2037
2038 cmdutil.checkunfinished(repo, commit=True)
2038 cmdutil.checkunfinished(repo, commit=True)
2039
2039
2040 branch = repo[None].branch()
2040 branch = repo[None].branch()
2041 bheads = repo.branchheads(branch)
2041 bheads = repo.branchheads(branch)
2042
2042
2043 extra = {}
2043 extra = {}
2044 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2044 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2045 extra[b'close'] = b'1'
2045 extra[b'close'] = b'1'
2046
2046
2047 if repo[b'.'].closesbranch():
2047 if repo[b'.'].closesbranch():
2048 raise error.Abort(
2048 raise error.Abort(
2049 _(b'current revision is already a branch closing head')
2049 _(b'current revision is already a branch closing head')
2050 )
2050 )
2051 elif not bheads:
2051 elif not bheads:
2052 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2052 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2053 elif (
2053 elif (
2054 branch == repo[b'.'].branch()
2054 branch == repo[b'.'].branch()
2055 and repo[b'.'].node() not in bheads
2055 and repo[b'.'].node() not in bheads
2056 and not opts.get(b'force_close_branch')
2056 and not opts.get(b'force_close_branch')
2057 ):
2057 ):
2058 hint = _(
2058 hint = _(
2059 b'use --force-close-branch to close branch from a non-head'
2059 b'use --force-close-branch to close branch from a non-head'
2060 b' changeset'
2060 b' changeset'
2061 )
2061 )
2062 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2062 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2063 elif opts.get(b'amend'):
2063 elif opts.get(b'amend'):
2064 if (
2064 if (
2065 repo[b'.'].p1().branch() != branch
2065 repo[b'.'].p1().branch() != branch
2066 and repo[b'.'].p2().branch() != branch
2066 and repo[b'.'].p2().branch() != branch
2067 ):
2067 ):
2068 raise error.Abort(_(b'can only close branch heads'))
2068 raise error.Abort(_(b'can only close branch heads'))
2069
2069
2070 if opts.get(b'amend'):
2070 if opts.get(b'amend'):
2071 if ui.configbool(b'ui', b'commitsubrepos'):
2071 if ui.configbool(b'ui', b'commitsubrepos'):
2072 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2072 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2073
2073
2074 old = repo[b'.']
2074 old = repo[b'.']
2075 rewriteutil.precheck(repo, [old.rev()], b'amend')
2075 rewriteutil.precheck(repo, [old.rev()], b'amend')
2076
2076
2077 # Currently histedit gets confused if an amend happens while histedit
2077 # Currently histedit gets confused if an amend happens while histedit
2078 # is in progress. Since we have a checkunfinished command, we are
2078 # is in progress. Since we have a checkunfinished command, we are
2079 # temporarily honoring it.
2079 # temporarily honoring it.
2080 #
2080 #
2081 # Note: eventually this guard will be removed. Please do not expect
2081 # Note: eventually this guard will be removed. Please do not expect
2082 # this behavior to remain.
2082 # this behavior to remain.
2083 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2083 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2084 cmdutil.checkunfinished(repo)
2084 cmdutil.checkunfinished(repo)
2085
2085
2086 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2086 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2087 if node == old.node():
2087 if node == old.node():
2088 ui.status(_(b"nothing changed\n"))
2088 ui.status(_(b"nothing changed\n"))
2089 return 1
2089 return 1
2090 else:
2090 else:
2091
2091
2092 def commitfunc(ui, repo, message, match, opts):
2092 def commitfunc(ui, repo, message, match, opts):
2093 overrides = {}
2093 overrides = {}
2094 if opts.get(b'secret'):
2094 if opts.get(b'secret'):
2095 overrides[(b'phases', b'new-commit')] = b'secret'
2095 overrides[(b'phases', b'new-commit')] = b'secret'
2096
2096
2097 baseui = repo.baseui
2097 baseui = repo.baseui
2098 with baseui.configoverride(overrides, b'commit'):
2098 with baseui.configoverride(overrides, b'commit'):
2099 with ui.configoverride(overrides, b'commit'):
2099 with ui.configoverride(overrides, b'commit'):
2100 editform = cmdutil.mergeeditform(
2100 editform = cmdutil.mergeeditform(
2101 repo[None], b'commit.normal'
2101 repo[None], b'commit.normal'
2102 )
2102 )
2103 editor = cmdutil.getcommiteditor(
2103 editor = cmdutil.getcommiteditor(
2104 editform=editform, **pycompat.strkwargs(opts)
2104 editform=editform, **pycompat.strkwargs(opts)
2105 )
2105 )
2106 return repo.commit(
2106 return repo.commit(
2107 message,
2107 message,
2108 opts.get(b'user'),
2108 opts.get(b'user'),
2109 opts.get(b'date'),
2109 opts.get(b'date'),
2110 match,
2110 match,
2111 editor=editor,
2111 editor=editor,
2112 extra=extra,
2112 extra=extra,
2113 )
2113 )
2114
2114
2115 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2115 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2116
2116
2117 if not node:
2117 if not node:
2118 stat = cmdutil.postcommitstatus(repo, pats, opts)
2118 stat = cmdutil.postcommitstatus(repo, pats, opts)
2119 if stat[3]:
2119 if stat[3]:
2120 ui.status(
2120 ui.status(
2121 _(
2121 _(
2122 b"nothing changed (%d missing files, see "
2122 b"nothing changed (%d missing files, see "
2123 b"'hg status')\n"
2123 b"'hg status')\n"
2124 )
2124 )
2125 % len(stat[3])
2125 % len(stat[3])
2126 )
2126 )
2127 else:
2127 else:
2128 ui.status(_(b"nothing changed\n"))
2128 ui.status(_(b"nothing changed\n"))
2129 return 1
2129 return 1
2130
2130
2131 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2131 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2132
2132
2133 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2133 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2134 status(
2134 status(
2135 ui,
2135 ui,
2136 repo,
2136 repo,
2137 modified=True,
2137 modified=True,
2138 added=True,
2138 added=True,
2139 removed=True,
2139 removed=True,
2140 deleted=True,
2140 deleted=True,
2141 unknown=True,
2141 unknown=True,
2142 subrepos=opts.get(b'subrepos'),
2142 subrepos=opts.get(b'subrepos'),
2143 )
2143 )
2144
2144
2145
2145
2146 @command(
2146 @command(
2147 b'config|showconfig|debugconfig',
2147 b'config|showconfig|debugconfig',
2148 [
2148 [
2149 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2149 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2150 (b'e', b'edit', None, _(b'edit user config')),
2150 (b'e', b'edit', None, _(b'edit user config')),
2151 (b'l', b'local', None, _(b'edit repository config')),
2151 (b'l', b'local', None, _(b'edit repository config')),
2152 (b'g', b'global', None, _(b'edit global config')),
2152 (b'g', b'global', None, _(b'edit global config')),
2153 ]
2153 ]
2154 + formatteropts,
2154 + formatteropts,
2155 _(b'[-u] [NAME]...'),
2155 _(b'[-u] [NAME]...'),
2156 helpcategory=command.CATEGORY_HELP,
2156 helpcategory=command.CATEGORY_HELP,
2157 optionalrepo=True,
2157 optionalrepo=True,
2158 intents={INTENT_READONLY},
2158 intents={INTENT_READONLY},
2159 )
2159 )
2160 def config(ui, repo, *values, **opts):
2160 def config(ui, repo, *values, **opts):
2161 """show combined config settings from all hgrc files
2161 """show combined config settings from all hgrc files
2162
2162
2163 With no arguments, print names and values of all config items.
2163 With no arguments, print names and values of all config items.
2164
2164
2165 With one argument of the form section.name, print just the value
2165 With one argument of the form section.name, print just the value
2166 of that config item.
2166 of that config item.
2167
2167
2168 With multiple arguments, print names and values of all config
2168 With multiple arguments, print names and values of all config
2169 items with matching section names or section.names.
2169 items with matching section names or section.names.
2170
2170
2171 With --edit, start an editor on the user-level config file. With
2171 With --edit, start an editor on the user-level config file. With
2172 --global, edit the system-wide config file. With --local, edit the
2172 --global, edit the system-wide config file. With --local, edit the
2173 repository-level config file.
2173 repository-level config file.
2174
2174
2175 With --debug, the source (filename and line number) is printed
2175 With --debug, the source (filename and line number) is printed
2176 for each config item.
2176 for each config item.
2177
2177
2178 See :hg:`help config` for more information about config files.
2178 See :hg:`help config` for more information about config files.
2179
2179
2180 .. container:: verbose
2180 .. container:: verbose
2181
2181
2182 Template:
2182 Template:
2183
2183
2184 The following keywords are supported. See also :hg:`help templates`.
2184 The following keywords are supported. See also :hg:`help templates`.
2185
2185
2186 :name: String. Config name.
2186 :name: String. Config name.
2187 :source: String. Filename and line number where the item is defined.
2187 :source: String. Filename and line number where the item is defined.
2188 :value: String. Config value.
2188 :value: String. Config value.
2189
2189
2190 Returns 0 on success, 1 if NAME does not exist.
2190 Returns 0 on success, 1 if NAME does not exist.
2191
2191
2192 """
2192 """
2193
2193
2194 opts = pycompat.byteskwargs(opts)
2194 opts = pycompat.byteskwargs(opts)
2195 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2195 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2196 if opts.get(b'local') and opts.get(b'global'):
2196 if opts.get(b'local') and opts.get(b'global'):
2197 raise error.Abort(_(b"can't use --local and --global together"))
2197 raise error.Abort(_(b"can't use --local and --global together"))
2198
2198
2199 if opts.get(b'local'):
2199 if opts.get(b'local'):
2200 if not repo:
2200 if not repo:
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2202 paths = [repo.vfs.join(b'hgrc')]
2202 paths = [repo.vfs.join(b'hgrc')]
2203 elif opts.get(b'global'):
2203 elif opts.get(b'global'):
2204 paths = rcutil.systemrcpath()
2204 paths = rcutil.systemrcpath()
2205 else:
2205 else:
2206 paths = rcutil.userrcpath()
2206 paths = rcutil.userrcpath()
2207
2207
2208 for f in paths:
2208 for f in paths:
2209 if os.path.exists(f):
2209 if os.path.exists(f):
2210 break
2210 break
2211 else:
2211 else:
2212 if opts.get(b'global'):
2212 if opts.get(b'global'):
2213 samplehgrc = uimod.samplehgrcs[b'global']
2213 samplehgrc = uimod.samplehgrcs[b'global']
2214 elif opts.get(b'local'):
2214 elif opts.get(b'local'):
2215 samplehgrc = uimod.samplehgrcs[b'local']
2215 samplehgrc = uimod.samplehgrcs[b'local']
2216 else:
2216 else:
2217 samplehgrc = uimod.samplehgrcs[b'user']
2217 samplehgrc = uimod.samplehgrcs[b'user']
2218
2218
2219 f = paths[0]
2219 f = paths[0]
2220 fp = open(f, b"wb")
2220 fp = open(f, b"wb")
2221 fp.write(util.tonativeeol(samplehgrc))
2221 fp.write(util.tonativeeol(samplehgrc))
2222 fp.close()
2222 fp.close()
2223
2223
2224 editor = ui.geteditor()
2224 editor = ui.geteditor()
2225 ui.system(
2225 ui.system(
2226 b"%s \"%s\"" % (editor, f),
2226 b"%s \"%s\"" % (editor, f),
2227 onerr=error.Abort,
2227 onerr=error.Abort,
2228 errprefix=_(b"edit failed"),
2228 errprefix=_(b"edit failed"),
2229 blockedtag=b'config_edit',
2229 blockedtag=b'config_edit',
2230 )
2230 )
2231 return
2231 return
2232 ui.pager(b'config')
2232 ui.pager(b'config')
2233 fm = ui.formatter(b'config', opts)
2233 fm = ui.formatter(b'config', opts)
2234 for t, f in rcutil.rccomponents():
2234 for t, f in rcutil.rccomponents():
2235 if t == b'path':
2235 if t == b'path':
2236 ui.debug(b'read config from: %s\n' % f)
2236 ui.debug(b'read config from: %s\n' % f)
2237 elif t == b'items':
2237 elif t == b'items':
2238 for section, name, value, source in f:
2238 for section, name, value, source in f:
2239 ui.debug(b'set config by: %s\n' % source)
2239 ui.debug(b'set config by: %s\n' % source)
2240 else:
2240 else:
2241 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2241 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2242 untrusted = bool(opts.get(b'untrusted'))
2242 untrusted = bool(opts.get(b'untrusted'))
2243
2243
2244 selsections = selentries = []
2244 selsections = selentries = []
2245 if values:
2245 if values:
2246 selsections = [v for v in values if b'.' not in v]
2246 selsections = [v for v in values if b'.' not in v]
2247 selentries = [v for v in values if b'.' in v]
2247 selentries = [v for v in values if b'.' in v]
2248 uniquesel = len(selentries) == 1 and not selsections
2248 uniquesel = len(selentries) == 1 and not selsections
2249 selsections = set(selsections)
2249 selsections = set(selsections)
2250 selentries = set(selentries)
2250 selentries = set(selentries)
2251
2251
2252 matched = False
2252 matched = False
2253 for section, name, value in ui.walkconfig(untrusted=untrusted):
2253 for section, name, value in ui.walkconfig(untrusted=untrusted):
2254 source = ui.configsource(section, name, untrusted)
2254 source = ui.configsource(section, name, untrusted)
2255 value = pycompat.bytestr(value)
2255 value = pycompat.bytestr(value)
2256 defaultvalue = ui.configdefault(section, name)
2256 defaultvalue = ui.configdefault(section, name)
2257 if fm.isplain():
2257 if fm.isplain():
2258 source = source or b'none'
2258 source = source or b'none'
2259 value = value.replace(b'\n', b'\\n')
2259 value = value.replace(b'\n', b'\\n')
2260 entryname = section + b'.' + name
2260 entryname = section + b'.' + name
2261 if values and not (section in selsections or entryname in selentries):
2261 if values and not (section in selsections or entryname in selentries):
2262 continue
2262 continue
2263 fm.startitem()
2263 fm.startitem()
2264 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2264 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2265 if uniquesel:
2265 if uniquesel:
2266 fm.data(name=entryname)
2266 fm.data(name=entryname)
2267 fm.write(b'value', b'%s\n', value)
2267 fm.write(b'value', b'%s\n', value)
2268 else:
2268 else:
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2269 fm.write(b'name value', b'%s=%s\n', entryname, value)
2270 fm.data(defaultvalue=defaultvalue)
2270 fm.data(defaultvalue=defaultvalue)
2271 matched = True
2271 matched = True
2272 fm.end()
2272 fm.end()
2273 if matched:
2273 if matched:
2274 return 0
2274 return 0
2275 return 1
2275 return 1
2276
2276
2277
2277
2278 @command(
2278 @command(
2279 b'continue',
2279 b'continue',
2280 dryrunopts,
2280 dryrunopts,
2281 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2281 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2282 helpbasic=True,
2282 helpbasic=True,
2283 )
2283 )
2284 def continuecmd(ui, repo, **opts):
2284 def continuecmd(ui, repo, **opts):
2285 """resumes an interrupted operation (EXPERIMENTAL)
2285 """resumes an interrupted operation (EXPERIMENTAL)
2286
2286
2287 Finishes a multistep operation like graft, histedit, rebase, merge,
2287 Finishes a multistep operation like graft, histedit, rebase, merge,
2288 and unshelve if they are in an interrupted state.
2288 and unshelve if they are in an interrupted state.
2289
2289
2290 use --dry-run/-n to dry run the command.
2290 use --dry-run/-n to dry run the command.
2291 """
2291 """
2292 dryrun = opts.get(r'dry_run')
2292 dryrun = opts.get(r'dry_run')
2293 contstate = cmdutil.getunfinishedstate(repo)
2293 contstate = cmdutil.getunfinishedstate(repo)
2294 if not contstate:
2294 if not contstate:
2295 raise error.Abort(_(b'no operation in progress'))
2295 raise error.Abort(_(b'no operation in progress'))
2296 if not contstate.continuefunc:
2296 if not contstate.continuefunc:
2297 raise error.Abort(
2297 raise error.Abort(
2298 (
2298 (
2299 _(b"%s in progress but does not support 'hg continue'")
2299 _(b"%s in progress but does not support 'hg continue'")
2300 % (contstate._opname)
2300 % (contstate._opname)
2301 ),
2301 ),
2302 hint=contstate.continuemsg(),
2302 hint=contstate.continuemsg(),
2303 )
2303 )
2304 if dryrun:
2304 if dryrun:
2305 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2305 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2306 return
2306 return
2307 return contstate.continuefunc(ui, repo)
2307 return contstate.continuefunc(ui, repo)
2308
2308
2309
2309
2310 @command(
2310 @command(
2311 b'copy|cp',
2311 b'copy|cp',
2312 [
2312 [
2313 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2313 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2314 (
2314 (
2315 b'f',
2315 b'f',
2316 b'force',
2316 b'force',
2317 None,
2317 None,
2318 _(b'forcibly copy over an existing managed file'),
2318 _(b'forcibly copy over an existing managed file'),
2319 ),
2319 ),
2320 ]
2320 ]
2321 + walkopts
2321 + walkopts
2322 + dryrunopts,
2322 + dryrunopts,
2323 _(b'[OPTION]... SOURCE... DEST'),
2323 _(b'[OPTION]... SOURCE... DEST'),
2324 helpcategory=command.CATEGORY_FILE_CONTENTS,
2324 helpcategory=command.CATEGORY_FILE_CONTENTS,
2325 )
2325 )
2326 def copy(ui, repo, *pats, **opts):
2326 def copy(ui, repo, *pats, **opts):
2327 """mark files as copied for the next commit
2327 """mark files as copied for the next commit
2328
2328
2329 Mark dest as having copies of source files. If dest is a
2329 Mark dest as having copies of source files. If dest is a
2330 directory, copies are put in that directory. If dest is a file,
2330 directory, copies are put in that directory. If dest is a file,
2331 the source must be a single file.
2331 the source must be a single file.
2332
2332
2333 By default, this command copies the contents of files as they
2333 By default, this command copies the contents of files as they
2334 exist in the working directory. If invoked with -A/--after, the
2334 exist in the working directory. If invoked with -A/--after, the
2335 operation is recorded, but no copying is performed.
2335 operation is recorded, but no copying is performed.
2336
2336
2337 This command takes effect with the next commit. To undo a copy
2337 This command takes effect with the next commit. To undo a copy
2338 before that, see :hg:`revert`.
2338 before that, see :hg:`revert`.
2339
2339
2340 Returns 0 on success, 1 if errors are encountered.
2340 Returns 0 on success, 1 if errors are encountered.
2341 """
2341 """
2342 opts = pycompat.byteskwargs(opts)
2342 opts = pycompat.byteskwargs(opts)
2343 with repo.wlock(False):
2343 with repo.wlock(False):
2344 return cmdutil.copy(ui, repo, pats, opts)
2344 return cmdutil.copy(ui, repo, pats, opts)
2345
2345
2346
2346
2347 @command(
2347 @command(
2348 b'debugcommands',
2348 b'debugcommands',
2349 [],
2349 [],
2350 _(b'[COMMAND]'),
2350 _(b'[COMMAND]'),
2351 helpcategory=command.CATEGORY_HELP,
2351 helpcategory=command.CATEGORY_HELP,
2352 norepo=True,
2352 norepo=True,
2353 )
2353 )
2354 def debugcommands(ui, cmd=b'', *args):
2354 def debugcommands(ui, cmd=b'', *args):
2355 """list all available commands and options"""
2355 """list all available commands and options"""
2356 for cmd, vals in sorted(pycompat.iteritems(table)):
2356 for cmd, vals in sorted(pycompat.iteritems(table)):
2357 cmd = cmd.split(b'|')[0]
2357 cmd = cmd.split(b'|')[0]
2358 opts = b', '.join([i[1] for i in vals[1]])
2358 opts = b', '.join([i[1] for i in vals[1]])
2359 ui.write(b'%s: %s\n' % (cmd, opts))
2359 ui.write(b'%s: %s\n' % (cmd, opts))
2360
2360
2361
2361
2362 @command(
2362 @command(
2363 b'debugcomplete',
2363 b'debugcomplete',
2364 [(b'o', b'options', None, _(b'show the command options'))],
2364 [(b'o', b'options', None, _(b'show the command options'))],
2365 _(b'[-o] CMD'),
2365 _(b'[-o] CMD'),
2366 helpcategory=command.CATEGORY_HELP,
2366 helpcategory=command.CATEGORY_HELP,
2367 norepo=True,
2367 norepo=True,
2368 )
2368 )
2369 def debugcomplete(ui, cmd=b'', **opts):
2369 def debugcomplete(ui, cmd=b'', **opts):
2370 """returns the completion list associated with the given command"""
2370 """returns the completion list associated with the given command"""
2371
2371
2372 if opts.get(r'options'):
2372 if opts.get(r'options'):
2373 options = []
2373 options = []
2374 otables = [globalopts]
2374 otables = [globalopts]
2375 if cmd:
2375 if cmd:
2376 aliases, entry = cmdutil.findcmd(cmd, table, False)
2376 aliases, entry = cmdutil.findcmd(cmd, table, False)
2377 otables.append(entry[1])
2377 otables.append(entry[1])
2378 for t in otables:
2378 for t in otables:
2379 for o in t:
2379 for o in t:
2380 if b"(DEPRECATED)" in o[3]:
2380 if b"(DEPRECATED)" in o[3]:
2381 continue
2381 continue
2382 if o[0]:
2382 if o[0]:
2383 options.append(b'-%s' % o[0])
2383 options.append(b'-%s' % o[0])
2384 options.append(b'--%s' % o[1])
2384 options.append(b'--%s' % o[1])
2385 ui.write(b"%s\n" % b"\n".join(options))
2385 ui.write(b"%s\n" % b"\n".join(options))
2386 return
2386 return
2387
2387
2388 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2388 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2389 if ui.verbose:
2389 if ui.verbose:
2390 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2390 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2391 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2391 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2392
2392
2393
2393
2394 @command(
2394 @command(
2395 b'diff',
2395 b'diff',
2396 [
2396 [
2397 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2397 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2398 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2398 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2399 ]
2399 ]
2400 + diffopts
2400 + diffopts
2401 + diffopts2
2401 + diffopts2
2402 + walkopts
2402 + walkopts
2403 + subrepoopts,
2403 + subrepoopts,
2404 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2404 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2405 helpcategory=command.CATEGORY_FILE_CONTENTS,
2405 helpcategory=command.CATEGORY_FILE_CONTENTS,
2406 helpbasic=True,
2406 helpbasic=True,
2407 inferrepo=True,
2407 inferrepo=True,
2408 intents={INTENT_READONLY},
2408 intents={INTENT_READONLY},
2409 )
2409 )
2410 def diff(ui, repo, *pats, **opts):
2410 def diff(ui, repo, *pats, **opts):
2411 """diff repository (or selected files)
2411 """diff repository (or selected files)
2412
2412
2413 Show differences between revisions for the specified files.
2413 Show differences between revisions for the specified files.
2414
2414
2415 Differences between files are shown using the unified diff format.
2415 Differences between files are shown using the unified diff format.
2416
2416
2417 .. note::
2417 .. note::
2418
2418
2419 :hg:`diff` may generate unexpected results for merges, as it will
2419 :hg:`diff` may generate unexpected results for merges, as it will
2420 default to comparing against the working directory's first
2420 default to comparing against the working directory's first
2421 parent changeset if no revisions are specified.
2421 parent changeset if no revisions are specified.
2422
2422
2423 When two revision arguments are given, then changes are shown
2423 When two revision arguments are given, then changes are shown
2424 between those revisions. If only one revision is specified then
2424 between those revisions. If only one revision is specified then
2425 that revision is compared to the working directory, and, when no
2425 that revision is compared to the working directory, and, when no
2426 revisions are specified, the working directory files are compared
2426 revisions are specified, the working directory files are compared
2427 to its first parent.
2427 to its first parent.
2428
2428
2429 Alternatively you can specify -c/--change with a revision to see
2429 Alternatively you can specify -c/--change with a revision to see
2430 the changes in that changeset relative to its first parent.
2430 the changes in that changeset relative to its first parent.
2431
2431
2432 Without the -a/--text option, diff will avoid generating diffs of
2432 Without the -a/--text option, diff will avoid generating diffs of
2433 files it detects as binary. With -a, diff will generate a diff
2433 files it detects as binary. With -a, diff will generate a diff
2434 anyway, probably with undesirable results.
2434 anyway, probably with undesirable results.
2435
2435
2436 Use the -g/--git option to generate diffs in the git extended diff
2436 Use the -g/--git option to generate diffs in the git extended diff
2437 format. For more information, read :hg:`help diffs`.
2437 format. For more information, read :hg:`help diffs`.
2438
2438
2439 .. container:: verbose
2439 .. container:: verbose
2440
2440
2441 Examples:
2441 Examples:
2442
2442
2443 - compare a file in the current working directory to its parent::
2443 - compare a file in the current working directory to its parent::
2444
2444
2445 hg diff foo.c
2445 hg diff foo.c
2446
2446
2447 - compare two historical versions of a directory, with rename info::
2447 - compare two historical versions of a directory, with rename info::
2448
2448
2449 hg diff --git -r 1.0:1.2 lib/
2449 hg diff --git -r 1.0:1.2 lib/
2450
2450
2451 - get change stats relative to the last change on some date::
2451 - get change stats relative to the last change on some date::
2452
2452
2453 hg diff --stat -r "date('may 2')"
2453 hg diff --stat -r "date('may 2')"
2454
2454
2455 - diff all newly-added files that contain a keyword::
2455 - diff all newly-added files that contain a keyword::
2456
2456
2457 hg diff "set:added() and grep(GNU)"
2457 hg diff "set:added() and grep(GNU)"
2458
2458
2459 - compare a revision and its parents::
2459 - compare a revision and its parents::
2460
2460
2461 hg diff -c 9353 # compare against first parent
2461 hg diff -c 9353 # compare against first parent
2462 hg diff -r 9353^:9353 # same using revset syntax
2462 hg diff -r 9353^:9353 # same using revset syntax
2463 hg diff -r 9353^2:9353 # compare against the second parent
2463 hg diff -r 9353^2:9353 # compare against the second parent
2464
2464
2465 Returns 0 on success.
2465 Returns 0 on success.
2466 """
2466 """
2467
2467
2468 opts = pycompat.byteskwargs(opts)
2468 opts = pycompat.byteskwargs(opts)
2469 revs = opts.get(b'rev')
2469 revs = opts.get(b'rev')
2470 change = opts.get(b'change')
2470 change = opts.get(b'change')
2471 stat = opts.get(b'stat')
2471 stat = opts.get(b'stat')
2472 reverse = opts.get(b'reverse')
2472 reverse = opts.get(b'reverse')
2473
2473
2474 if revs and change:
2474 if revs and change:
2475 msg = _(b'cannot specify --rev and --change at the same time')
2475 msg = _(b'cannot specify --rev and --change at the same time')
2476 raise error.Abort(msg)
2476 raise error.Abort(msg)
2477 elif change:
2477 elif change:
2478 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2478 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2479 ctx2 = scmutil.revsingle(repo, change, None)
2479 ctx2 = scmutil.revsingle(repo, change, None)
2480 ctx1 = ctx2.p1()
2480 ctx1 = ctx2.p1()
2481 else:
2481 else:
2482 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2482 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2483 ctx1, ctx2 = scmutil.revpair(repo, revs)
2483 ctx1, ctx2 = scmutil.revpair(repo, revs)
2484 node1, node2 = ctx1.node(), ctx2.node()
2484 node1, node2 = ctx1.node(), ctx2.node()
2485
2485
2486 if reverse:
2486 if reverse:
2487 node1, node2 = node2, node1
2487 node1, node2 = node2, node1
2488
2488
2489 diffopts = patch.diffallopts(ui, opts)
2489 diffopts = patch.diffallopts(ui, opts)
2490 m = scmutil.match(ctx2, pats, opts)
2490 m = scmutil.match(ctx2, pats, opts)
2491 m = repo.narrowmatch(m)
2491 m = repo.narrowmatch(m)
2492 ui.pager(b'diff')
2492 ui.pager(b'diff')
2493 logcmdutil.diffordiffstat(
2493 logcmdutil.diffordiffstat(
2494 ui,
2494 ui,
2495 repo,
2495 repo,
2496 diffopts,
2496 diffopts,
2497 node1,
2497 node1,
2498 node2,
2498 node2,
2499 m,
2499 m,
2500 stat=stat,
2500 stat=stat,
2501 listsubrepos=opts.get(b'subrepos'),
2501 listsubrepos=opts.get(b'subrepos'),
2502 root=opts.get(b'root'),
2502 root=opts.get(b'root'),
2503 )
2503 )
2504
2504
2505
2505
2506 @command(
2506 @command(
2507 b'export',
2507 b'export',
2508 [
2508 [
2509 (
2509 (
2510 b'B',
2510 b'B',
2511 b'bookmark',
2511 b'bookmark',
2512 b'',
2512 b'',
2513 _(b'export changes only reachable by given bookmark'),
2513 _(b'export changes only reachable by given bookmark'),
2514 _(b'BOOKMARK'),
2514 _(b'BOOKMARK'),
2515 ),
2515 ),
2516 (
2516 (
2517 b'o',
2517 b'o',
2518 b'output',
2518 b'output',
2519 b'',
2519 b'',
2520 _(b'print output to file with formatted name'),
2520 _(b'print output to file with formatted name'),
2521 _(b'FORMAT'),
2521 _(b'FORMAT'),
2522 ),
2522 ),
2523 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2523 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2524 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2524 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2525 ]
2525 ]
2526 + diffopts
2526 + diffopts
2527 + formatteropts,
2527 + formatteropts,
2528 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2528 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2529 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2529 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2530 helpbasic=True,
2530 helpbasic=True,
2531 intents={INTENT_READONLY},
2531 intents={INTENT_READONLY},
2532 )
2532 )
2533 def export(ui, repo, *changesets, **opts):
2533 def export(ui, repo, *changesets, **opts):
2534 """dump the header and diffs for one or more changesets
2534 """dump the header and diffs for one or more changesets
2535
2535
2536 Print the changeset header and diffs for one or more revisions.
2536 Print the changeset header and diffs for one or more revisions.
2537 If no revision is given, the parent of the working directory is used.
2537 If no revision is given, the parent of the working directory is used.
2538
2538
2539 The information shown in the changeset header is: author, date,
2539 The information shown in the changeset header is: author, date,
2540 branch name (if non-default), changeset hash, parent(s) and commit
2540 branch name (if non-default), changeset hash, parent(s) and commit
2541 comment.
2541 comment.
2542
2542
2543 .. note::
2543 .. note::
2544
2544
2545 :hg:`export` may generate unexpected diff output for merge
2545 :hg:`export` may generate unexpected diff output for merge
2546 changesets, as it will compare the merge changeset against its
2546 changesets, as it will compare the merge changeset against its
2547 first parent only.
2547 first parent only.
2548
2548
2549 Output may be to a file, in which case the name of the file is
2549 Output may be to a file, in which case the name of the file is
2550 given using a template string. See :hg:`help templates`. In addition
2550 given using a template string. See :hg:`help templates`. In addition
2551 to the common template keywords, the following formatting rules are
2551 to the common template keywords, the following formatting rules are
2552 supported:
2552 supported:
2553
2553
2554 :``%%``: literal "%" character
2554 :``%%``: literal "%" character
2555 :``%H``: changeset hash (40 hexadecimal digits)
2555 :``%H``: changeset hash (40 hexadecimal digits)
2556 :``%N``: number of patches being generated
2556 :``%N``: number of patches being generated
2557 :``%R``: changeset revision number
2557 :``%R``: changeset revision number
2558 :``%b``: basename of the exporting repository
2558 :``%b``: basename of the exporting repository
2559 :``%h``: short-form changeset hash (12 hexadecimal digits)
2559 :``%h``: short-form changeset hash (12 hexadecimal digits)
2560 :``%m``: first line of the commit message (only alphanumeric characters)
2560 :``%m``: first line of the commit message (only alphanumeric characters)
2561 :``%n``: zero-padded sequence number, starting at 1
2561 :``%n``: zero-padded sequence number, starting at 1
2562 :``%r``: zero-padded changeset revision number
2562 :``%r``: zero-padded changeset revision number
2563 :``\\``: literal "\\" character
2563 :``\\``: literal "\\" character
2564
2564
2565 Without the -a/--text option, export will avoid generating diffs
2565 Without the -a/--text option, export will avoid generating diffs
2566 of files it detects as binary. With -a, export will generate a
2566 of files it detects as binary. With -a, export will generate a
2567 diff anyway, probably with undesirable results.
2567 diff anyway, probably with undesirable results.
2568
2568
2569 With -B/--bookmark changesets reachable by the given bookmark are
2569 With -B/--bookmark changesets reachable by the given bookmark are
2570 selected.
2570 selected.
2571
2571
2572 Use the -g/--git option to generate diffs in the git extended diff
2572 Use the -g/--git option to generate diffs in the git extended diff
2573 format. See :hg:`help diffs` for more information.
2573 format. See :hg:`help diffs` for more information.
2574
2574
2575 With the --switch-parent option, the diff will be against the
2575 With the --switch-parent option, the diff will be against the
2576 second parent. It can be useful to review a merge.
2576 second parent. It can be useful to review a merge.
2577
2577
2578 .. container:: verbose
2578 .. container:: verbose
2579
2579
2580 Template:
2580 Template:
2581
2581
2582 The following keywords are supported in addition to the common template
2582 The following keywords are supported in addition to the common template
2583 keywords and functions. See also :hg:`help templates`.
2583 keywords and functions. See also :hg:`help templates`.
2584
2584
2585 :diff: String. Diff content.
2585 :diff: String. Diff content.
2586 :parents: List of strings. Parent nodes of the changeset.
2586 :parents: List of strings. Parent nodes of the changeset.
2587
2587
2588 Examples:
2588 Examples:
2589
2589
2590 - use export and import to transplant a bugfix to the current
2590 - use export and import to transplant a bugfix to the current
2591 branch::
2591 branch::
2592
2592
2593 hg export -r 9353 | hg import -
2593 hg export -r 9353 | hg import -
2594
2594
2595 - export all the changesets between two revisions to a file with
2595 - export all the changesets between two revisions to a file with
2596 rename information::
2596 rename information::
2597
2597
2598 hg export --git -r 123:150 > changes.txt
2598 hg export --git -r 123:150 > changes.txt
2599
2599
2600 - split outgoing changes into a series of patches with
2600 - split outgoing changes into a series of patches with
2601 descriptive names::
2601 descriptive names::
2602
2602
2603 hg export -r "outgoing()" -o "%n-%m.patch"
2603 hg export -r "outgoing()" -o "%n-%m.patch"
2604
2604
2605 Returns 0 on success.
2605 Returns 0 on success.
2606 """
2606 """
2607 opts = pycompat.byteskwargs(opts)
2607 opts = pycompat.byteskwargs(opts)
2608 bookmark = opts.get(b'bookmark')
2608 bookmark = opts.get(b'bookmark')
2609 changesets += tuple(opts.get(b'rev', []))
2609 changesets += tuple(opts.get(b'rev', []))
2610
2610
2611 if bookmark and changesets:
2611 if bookmark and changesets:
2612 raise error.Abort(_(b"-r and -B are mutually exclusive"))
2612 raise error.Abort(_(b"-r and -B are mutually exclusive"))
2613
2613
2614 if bookmark:
2614 if bookmark:
2615 if bookmark not in repo._bookmarks:
2615 if bookmark not in repo._bookmarks:
2616 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2616 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2617
2617
2618 revs = scmutil.bookmarkrevs(repo, bookmark)
2618 revs = scmutil.bookmarkrevs(repo, bookmark)
2619 else:
2619 else:
2620 if not changesets:
2620 if not changesets:
2621 changesets = [b'.']
2621 changesets = [b'.']
2622
2622
2623 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2623 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2624 revs = scmutil.revrange(repo, changesets)
2624 revs = scmutil.revrange(repo, changesets)
2625
2625
2626 if not revs:
2626 if not revs:
2627 raise error.Abort(_(b"export requires at least one changeset"))
2627 raise error.Abort(_(b"export requires at least one changeset"))
2628 if len(revs) > 1:
2628 if len(revs) > 1:
2629 ui.note(_(b'exporting patches:\n'))
2629 ui.note(_(b'exporting patches:\n'))
2630 else:
2630 else:
2631 ui.note(_(b'exporting patch:\n'))
2631 ui.note(_(b'exporting patch:\n'))
2632
2632
2633 fntemplate = opts.get(b'output')
2633 fntemplate = opts.get(b'output')
2634 if cmdutil.isstdiofilename(fntemplate):
2634 if cmdutil.isstdiofilename(fntemplate):
2635 fntemplate = b''
2635 fntemplate = b''
2636
2636
2637 if fntemplate:
2637 if fntemplate:
2638 fm = formatter.nullformatter(ui, b'export', opts)
2638 fm = formatter.nullformatter(ui, b'export', opts)
2639 else:
2639 else:
2640 ui.pager(b'export')
2640 ui.pager(b'export')
2641 fm = ui.formatter(b'export', opts)
2641 fm = ui.formatter(b'export', opts)
2642 with fm:
2642 with fm:
2643 cmdutil.export(
2643 cmdutil.export(
2644 repo,
2644 repo,
2645 revs,
2645 revs,
2646 fm,
2646 fm,
2647 fntemplate=fntemplate,
2647 fntemplate=fntemplate,
2648 switch_parent=opts.get(b'switch_parent'),
2648 switch_parent=opts.get(b'switch_parent'),
2649 opts=patch.diffallopts(ui, opts),
2649 opts=patch.diffallopts(ui, opts),
2650 )
2650 )
2651
2651
2652
2652
2653 @command(
2653 @command(
2654 b'files',
2654 b'files',
2655 [
2655 [
2656 (
2656 (
2657 b'r',
2657 b'r',
2658 b'rev',
2658 b'rev',
2659 b'',
2659 b'',
2660 _(b'search the repository as it is in REV'),
2660 _(b'search the repository as it is in REV'),
2661 _(b'REV'),
2661 _(b'REV'),
2662 ),
2662 ),
2663 (
2663 (
2664 b'0',
2664 b'0',
2665 b'print0',
2665 b'print0',
2666 None,
2666 None,
2667 _(b'end filenames with NUL, for use with xargs'),
2667 _(b'end filenames with NUL, for use with xargs'),
2668 ),
2668 ),
2669 ]
2669 ]
2670 + walkopts
2670 + walkopts
2671 + formatteropts
2671 + formatteropts
2672 + subrepoopts,
2672 + subrepoopts,
2673 _(b'[OPTION]... [FILE]...'),
2673 _(b'[OPTION]... [FILE]...'),
2674 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2674 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2675 intents={INTENT_READONLY},
2675 intents={INTENT_READONLY},
2676 )
2676 )
2677 def files(ui, repo, *pats, **opts):
2677 def files(ui, repo, *pats, **opts):
2678 """list tracked files
2678 """list tracked files
2679
2679
2680 Print files under Mercurial control in the working directory or
2680 Print files under Mercurial control in the working directory or
2681 specified revision for given files (excluding removed files).
2681 specified revision for given files (excluding removed files).
2682 Files can be specified as filenames or filesets.
2682 Files can be specified as filenames or filesets.
2683
2683
2684 If no files are given to match, this command prints the names
2684 If no files are given to match, this command prints the names
2685 of all files under Mercurial control.
2685 of all files under Mercurial control.
2686
2686
2687 .. container:: verbose
2687 .. container:: verbose
2688
2688
2689 Template:
2689 Template:
2690
2690
2691 The following keywords are supported in addition to the common template
2691 The following keywords are supported in addition to the common template
2692 keywords and functions. See also :hg:`help templates`.
2692 keywords and functions. See also :hg:`help templates`.
2693
2693
2694 :flags: String. Character denoting file's symlink and executable bits.
2694 :flags: String. Character denoting file's symlink and executable bits.
2695 :path: String. Repository-absolute path of the file.
2695 :path: String. Repository-absolute path of the file.
2696 :size: Integer. Size of the file in bytes.
2696 :size: Integer. Size of the file in bytes.
2697
2697
2698 Examples:
2698 Examples:
2699
2699
2700 - list all files under the current directory::
2700 - list all files under the current directory::
2701
2701
2702 hg files .
2702 hg files .
2703
2703
2704 - shows sizes and flags for current revision::
2704 - shows sizes and flags for current revision::
2705
2705
2706 hg files -vr .
2706 hg files -vr .
2707
2707
2708 - list all files named README::
2708 - list all files named README::
2709
2709
2710 hg files -I "**/README"
2710 hg files -I "**/README"
2711
2711
2712 - list all binary files::
2712 - list all binary files::
2713
2713
2714 hg files "set:binary()"
2714 hg files "set:binary()"
2715
2715
2716 - find files containing a regular expression::
2716 - find files containing a regular expression::
2717
2717
2718 hg files "set:grep('bob')"
2718 hg files "set:grep('bob')"
2719
2719
2720 - search tracked file contents with xargs and grep::
2720 - search tracked file contents with xargs and grep::
2721
2721
2722 hg files -0 | xargs -0 grep foo
2722 hg files -0 | xargs -0 grep foo
2723
2723
2724 See :hg:`help patterns` and :hg:`help filesets` for more information
2724 See :hg:`help patterns` and :hg:`help filesets` for more information
2725 on specifying file patterns.
2725 on specifying file patterns.
2726
2726
2727 Returns 0 if a match is found, 1 otherwise.
2727 Returns 0 if a match is found, 1 otherwise.
2728
2728
2729 """
2729 """
2730
2730
2731 opts = pycompat.byteskwargs(opts)
2731 opts = pycompat.byteskwargs(opts)
2732 rev = opts.get(b'rev')
2732 rev = opts.get(b'rev')
2733 if rev:
2733 if rev:
2734 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2734 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2735 ctx = scmutil.revsingle(repo, rev, None)
2735 ctx = scmutil.revsingle(repo, rev, None)
2736
2736
2737 end = b'\n'
2737 end = b'\n'
2738 if opts.get(b'print0'):
2738 if opts.get(b'print0'):
2739 end = b'\0'
2739 end = b'\0'
2740 fmt = b'%s' + end
2740 fmt = b'%s' + end
2741
2741
2742 m = scmutil.match(ctx, pats, opts)
2742 m = scmutil.match(ctx, pats, opts)
2743 ui.pager(b'files')
2743 ui.pager(b'files')
2744 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2744 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2745 with ui.formatter(b'files', opts) as fm:
2745 with ui.formatter(b'files', opts) as fm:
2746 return cmdutil.files(
2746 return cmdutil.files(
2747 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2747 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2748 )
2748 )
2749
2749
2750
2750
2751 @command(
2751 @command(
2752 b'forget',
2752 b'forget',
2753 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2753 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2754 + walkopts
2754 + walkopts
2755 + dryrunopts,
2755 + dryrunopts,
2756 _(b'[OPTION]... FILE...'),
2756 _(b'[OPTION]... FILE...'),
2757 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2757 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2758 helpbasic=True,
2758 helpbasic=True,
2759 inferrepo=True,
2759 inferrepo=True,
2760 )
2760 )
2761 def forget(ui, repo, *pats, **opts):
2761 def forget(ui, repo, *pats, **opts):
2762 """forget the specified files on the next commit
2762 """forget the specified files on the next commit
2763
2763
2764 Mark the specified files so they will no longer be tracked
2764 Mark the specified files so they will no longer be tracked
2765 after the next commit.
2765 after the next commit.
2766
2766
2767 This only removes files from the current branch, not from the
2767 This only removes files from the current branch, not from the
2768 entire project history, and it does not delete them from the
2768 entire project history, and it does not delete them from the
2769 working directory.
2769 working directory.
2770
2770
2771 To delete the file from the working directory, see :hg:`remove`.
2771 To delete the file from the working directory, see :hg:`remove`.
2772
2772
2773 To undo a forget before the next commit, see :hg:`add`.
2773 To undo a forget before the next commit, see :hg:`add`.
2774
2774
2775 .. container:: verbose
2775 .. container:: verbose
2776
2776
2777 Examples:
2777 Examples:
2778
2778
2779 - forget newly-added binary files::
2779 - forget newly-added binary files::
2780
2780
2781 hg forget "set:added() and binary()"
2781 hg forget "set:added() and binary()"
2782
2782
2783 - forget files that would be excluded by .hgignore::
2783 - forget files that would be excluded by .hgignore::
2784
2784
2785 hg forget "set:hgignore()"
2785 hg forget "set:hgignore()"
2786
2786
2787 Returns 0 on success.
2787 Returns 0 on success.
2788 """
2788 """
2789
2789
2790 opts = pycompat.byteskwargs(opts)
2790 opts = pycompat.byteskwargs(opts)
2791 if not pats:
2791 if not pats:
2792 raise error.Abort(_(b'no files specified'))
2792 raise error.Abort(_(b'no files specified'))
2793
2793
2794 m = scmutil.match(repo[None], pats, opts)
2794 m = scmutil.match(repo[None], pats, opts)
2795 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2795 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2796 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2796 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2797 rejected = cmdutil.forget(
2797 rejected = cmdutil.forget(
2798 ui,
2798 ui,
2799 repo,
2799 repo,
2800 m,
2800 m,
2801 prefix=b"",
2801 prefix=b"",
2802 uipathfn=uipathfn,
2802 uipathfn=uipathfn,
2803 explicitonly=False,
2803 explicitonly=False,
2804 dryrun=dryrun,
2804 dryrun=dryrun,
2805 interactive=interactive,
2805 interactive=interactive,
2806 )[0]
2806 )[0]
2807 return rejected and 1 or 0
2807 return rejected and 1 or 0
2808
2808
2809
2809
2810 @command(
2810 @command(
2811 b'graft',
2811 b'graft',
2812 [
2812 [
2813 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2813 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2814 (
2814 (
2815 b'',
2815 b'',
2816 b'base',
2816 b'base',
2817 b'',
2817 b'',
2818 _(b'base revision when doing the graft merge (ADVANCED)'),
2818 _(b'base revision when doing the graft merge (ADVANCED)'),
2819 _(b'REV'),
2819 _(b'REV'),
2820 ),
2820 ),
2821 (b'c', b'continue', False, _(b'resume interrupted graft')),
2821 (b'c', b'continue', False, _(b'resume interrupted graft')),
2822 (b'', b'stop', False, _(b'stop interrupted graft')),
2822 (b'', b'stop', False, _(b'stop interrupted graft')),
2823 (b'', b'abort', False, _(b'abort interrupted graft')),
2823 (b'', b'abort', False, _(b'abort interrupted graft')),
2824 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2824 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2825 (b'', b'log', None, _(b'append graft info to log message')),
2825 (b'', b'log', None, _(b'append graft info to log message')),
2826 (
2826 (
2827 b'',
2827 b'',
2828 b'no-commit',
2828 b'no-commit',
2829 None,
2829 None,
2830 _(b"don't commit, just apply the changes in working directory"),
2830 _(b"don't commit, just apply the changes in working directory"),
2831 ),
2831 ),
2832 (b'f', b'force', False, _(b'force graft')),
2832 (b'f', b'force', False, _(b'force graft')),
2833 (
2833 (
2834 b'D',
2834 b'D',
2835 b'currentdate',
2835 b'currentdate',
2836 False,
2836 False,
2837 _(b'record the current date as commit date'),
2837 _(b'record the current date as commit date'),
2838 ),
2838 ),
2839 (
2839 (
2840 b'U',
2840 b'U',
2841 b'currentuser',
2841 b'currentuser',
2842 False,
2842 False,
2843 _(b'record the current user as committer'),
2843 _(b'record the current user as committer'),
2844 ),
2844 ),
2845 ]
2845 ]
2846 + commitopts2
2846 + commitopts2
2847 + mergetoolopts
2847 + mergetoolopts
2848 + dryrunopts,
2848 + dryrunopts,
2849 _(b'[OPTION]... [-r REV]... REV...'),
2849 _(b'[OPTION]... [-r REV]... REV...'),
2850 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2850 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2851 )
2851 )
2852 def graft(ui, repo, *revs, **opts):
2852 def graft(ui, repo, *revs, **opts):
2853 '''copy changes from other branches onto the current branch
2853 '''copy changes from other branches onto the current branch
2854
2854
2855 This command uses Mercurial's merge logic to copy individual
2855 This command uses Mercurial's merge logic to copy individual
2856 changes from other branches without merging branches in the
2856 changes from other branches without merging branches in the
2857 history graph. This is sometimes known as 'backporting' or
2857 history graph. This is sometimes known as 'backporting' or
2858 'cherry-picking'. By default, graft will copy user, date, and
2858 'cherry-picking'. By default, graft will copy user, date, and
2859 description from the source changesets.
2859 description from the source changesets.
2860
2860
2861 Changesets that are ancestors of the current revision, that have
2861 Changesets that are ancestors of the current revision, that have
2862 already been grafted, or that are merges will be skipped.
2862 already been grafted, or that are merges will be skipped.
2863
2863
2864 If --log is specified, log messages will have a comment appended
2864 If --log is specified, log messages will have a comment appended
2865 of the form::
2865 of the form::
2866
2866
2867 (grafted from CHANGESETHASH)
2867 (grafted from CHANGESETHASH)
2868
2868
2869 If --force is specified, revisions will be grafted even if they
2869 If --force is specified, revisions will be grafted even if they
2870 are already ancestors of, or have been grafted to, the destination.
2870 are already ancestors of, or have been grafted to, the destination.
2871 This is useful when the revisions have since been backed out.
2871 This is useful when the revisions have since been backed out.
2872
2872
2873 If a graft merge results in conflicts, the graft process is
2873 If a graft merge results in conflicts, the graft process is
2874 interrupted so that the current merge can be manually resolved.
2874 interrupted so that the current merge can be manually resolved.
2875 Once all conflicts are addressed, the graft process can be
2875 Once all conflicts are addressed, the graft process can be
2876 continued with the -c/--continue option.
2876 continued with the -c/--continue option.
2877
2877
2878 The -c/--continue option reapplies all the earlier options.
2878 The -c/--continue option reapplies all the earlier options.
2879
2879
2880 .. container:: verbose
2880 .. container:: verbose
2881
2881
2882 The --base option exposes more of how graft internally uses merge with a
2882 The --base option exposes more of how graft internally uses merge with a
2883 custom base revision. --base can be used to specify another ancestor than
2883 custom base revision. --base can be used to specify another ancestor than
2884 the first and only parent.
2884 the first and only parent.
2885
2885
2886 The command::
2886 The command::
2887
2887
2888 hg graft -r 345 --base 234
2888 hg graft -r 345 --base 234
2889
2889
2890 is thus pretty much the same as::
2890 is thus pretty much the same as::
2891
2891
2892 hg diff -r 234 -r 345 | hg import
2892 hg diff -r 234 -r 345 | hg import
2893
2893
2894 but using merge to resolve conflicts and track moved files.
2894 but using merge to resolve conflicts and track moved files.
2895
2895
2896 The result of a merge can thus be backported as a single commit by
2896 The result of a merge can thus be backported as a single commit by
2897 specifying one of the merge parents as base, and thus effectively
2897 specifying one of the merge parents as base, and thus effectively
2898 grafting the changes from the other side.
2898 grafting the changes from the other side.
2899
2899
2900 It is also possible to collapse multiple changesets and clean up history
2900 It is also possible to collapse multiple changesets and clean up history
2901 by specifying another ancestor as base, much like rebase --collapse
2901 by specifying another ancestor as base, much like rebase --collapse
2902 --keep.
2902 --keep.
2903
2903
2904 The commit message can be tweaked after the fact using commit --amend .
2904 The commit message can be tweaked after the fact using commit --amend .
2905
2905
2906 For using non-ancestors as the base to backout changes, see the backout
2906 For using non-ancestors as the base to backout changes, see the backout
2907 command and the hidden --parent option.
2907 command and the hidden --parent option.
2908
2908
2909 .. container:: verbose
2909 .. container:: verbose
2910
2910
2911 Examples:
2911 Examples:
2912
2912
2913 - copy a single change to the stable branch and edit its description::
2913 - copy a single change to the stable branch and edit its description::
2914
2914
2915 hg update stable
2915 hg update stable
2916 hg graft --edit 9393
2916 hg graft --edit 9393
2917
2917
2918 - graft a range of changesets with one exception, updating dates::
2918 - graft a range of changesets with one exception, updating dates::
2919
2919
2920 hg graft -D "2085::2093 and not 2091"
2920 hg graft -D "2085::2093 and not 2091"
2921
2921
2922 - continue a graft after resolving conflicts::
2922 - continue a graft after resolving conflicts::
2923
2923
2924 hg graft -c
2924 hg graft -c
2925
2925
2926 - show the source of a grafted changeset::
2926 - show the source of a grafted changeset::
2927
2927
2928 hg log --debug -r .
2928 hg log --debug -r .
2929
2929
2930 - show revisions sorted by date::
2930 - show revisions sorted by date::
2931
2931
2932 hg log -r "sort(all(), date)"
2932 hg log -r "sort(all(), date)"
2933
2933
2934 - backport the result of a merge as a single commit::
2934 - backport the result of a merge as a single commit::
2935
2935
2936 hg graft -r 123 --base 123^
2936 hg graft -r 123 --base 123^
2937
2937
2938 - land a feature branch as one changeset::
2938 - land a feature branch as one changeset::
2939
2939
2940 hg up -cr default
2940 hg up -cr default
2941 hg graft -r featureX --base "ancestor('featureX', 'default')"
2941 hg graft -r featureX --base "ancestor('featureX', 'default')"
2942
2942
2943 See :hg:`help revisions` for more about specifying revisions.
2943 See :hg:`help revisions` for more about specifying revisions.
2944
2944
2945 Returns 0 on successful completion.
2945 Returns 0 on successful completion.
2946 '''
2946 '''
2947 with repo.wlock():
2947 with repo.wlock():
2948 return _dograft(ui, repo, *revs, **opts)
2948 return _dograft(ui, repo, *revs, **opts)
2949
2949
2950
2950
2951 def _dograft(ui, repo, *revs, **opts):
2951 def _dograft(ui, repo, *revs, **opts):
2952 opts = pycompat.byteskwargs(opts)
2952 opts = pycompat.byteskwargs(opts)
2953 if revs and opts.get(b'rev'):
2953 if revs and opts.get(b'rev'):
2954 ui.warn(
2954 ui.warn(
2955 _(
2955 _(
2956 b'warning: inconsistent use of --rev might give unexpected '
2956 b'warning: inconsistent use of --rev might give unexpected '
2957 b'revision ordering!\n'
2957 b'revision ordering!\n'
2958 )
2958 )
2959 )
2959 )
2960
2960
2961 revs = list(revs)
2961 revs = list(revs)
2962 revs.extend(opts.get(b'rev'))
2962 revs.extend(opts.get(b'rev'))
2963 basectx = None
2963 basectx = None
2964 if opts.get(b'base'):
2964 if opts.get(b'base'):
2965 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2965 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2966 # a dict of data to be stored in state file
2966 # a dict of data to be stored in state file
2967 statedata = {}
2967 statedata = {}
2968 # list of new nodes created by ongoing graft
2968 # list of new nodes created by ongoing graft
2969 statedata[b'newnodes'] = []
2969 statedata[b'newnodes'] = []
2970
2970
2971 if opts.get(b'user') and opts.get(b'currentuser'):
2971 if opts.get(b'user') and opts.get(b'currentuser'):
2972 raise error.Abort(_(b'--user and --currentuser are mutually exclusive'))
2972 raise error.Abort(_(b'--user and --currentuser are mutually exclusive'))
2973 if opts.get(b'date') and opts.get(b'currentdate'):
2973 if opts.get(b'date') and opts.get(b'currentdate'):
2974 raise error.Abort(_(b'--date and --currentdate are mutually exclusive'))
2974 raise error.Abort(_(b'--date and --currentdate are mutually exclusive'))
2975 if not opts.get(b'user') and opts.get(b'currentuser'):
2975 if not opts.get(b'user') and opts.get(b'currentuser'):
2976 opts[b'user'] = ui.username()
2976 opts[b'user'] = ui.username()
2977 if not opts.get(b'date') and opts.get(b'currentdate'):
2977 if not opts.get(b'date') and opts.get(b'currentdate'):
2978 opts[b'date'] = b"%d %d" % dateutil.makedate()
2978 opts[b'date'] = b"%d %d" % dateutil.makedate()
2979
2979
2980 editor = cmdutil.getcommiteditor(
2980 editor = cmdutil.getcommiteditor(
2981 editform=b'graft', **pycompat.strkwargs(opts)
2981 editform=b'graft', **pycompat.strkwargs(opts)
2982 )
2982 )
2983
2983
2984 cont = False
2984 cont = False
2985 if opts.get(b'no_commit'):
2985 if opts.get(b'no_commit'):
2986 if opts.get(b'edit'):
2986 if opts.get(b'edit'):
2987 raise error.Abort(
2987 raise error.Abort(
2988 _(b"cannot specify --no-commit and --edit together")
2988 _(b"cannot specify --no-commit and --edit together")
2989 )
2989 )
2990 if opts.get(b'currentuser'):
2990 if opts.get(b'currentuser'):
2991 raise error.Abort(
2991 raise error.Abort(
2992 _(b"cannot specify --no-commit and --currentuser together")
2992 _(b"cannot specify --no-commit and --currentuser together")
2993 )
2993 )
2994 if opts.get(b'currentdate'):
2994 if opts.get(b'currentdate'):
2995 raise error.Abort(
2995 raise error.Abort(
2996 _(b"cannot specify --no-commit and --currentdate together")
2996 _(b"cannot specify --no-commit and --currentdate together")
2997 )
2997 )
2998 if opts.get(b'log'):
2998 if opts.get(b'log'):
2999 raise error.Abort(
2999 raise error.Abort(
3000 _(b"cannot specify --no-commit and --log together")
3000 _(b"cannot specify --no-commit and --log together")
3001 )
3001 )
3002
3002
3003 graftstate = statemod.cmdstate(repo, b'graftstate')
3003 graftstate = statemod.cmdstate(repo, b'graftstate')
3004
3004
3005 if opts.get(b'stop'):
3005 if opts.get(b'stop'):
3006 if opts.get(b'continue'):
3006 if opts.get(b'continue'):
3007 raise error.Abort(
3007 raise error.Abort(
3008 _(b"cannot use '--continue' and '--stop' together")
3008 _(b"cannot use '--continue' and '--stop' together")
3009 )
3009 )
3010 if opts.get(b'abort'):
3010 if opts.get(b'abort'):
3011 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3011 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3012
3012
3013 if any(
3013 if any(
3014 (
3014 (
3015 opts.get(b'edit'),
3015 opts.get(b'edit'),
3016 opts.get(b'log'),
3016 opts.get(b'log'),
3017 opts.get(b'user'),
3017 opts.get(b'user'),
3018 opts.get(b'date'),
3018 opts.get(b'date'),
3019 opts.get(b'currentdate'),
3019 opts.get(b'currentdate'),
3020 opts.get(b'currentuser'),
3020 opts.get(b'currentuser'),
3021 opts.get(b'rev'),
3021 opts.get(b'rev'),
3022 )
3022 )
3023 ):
3023 ):
3024 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3024 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3025 return _stopgraft(ui, repo, graftstate)
3025 return _stopgraft(ui, repo, graftstate)
3026 elif opts.get(b'abort'):
3026 elif opts.get(b'abort'):
3027 if opts.get(b'continue'):
3027 if opts.get(b'continue'):
3028 raise error.Abort(
3028 raise error.Abort(
3029 _(b"cannot use '--continue' and '--abort' together")
3029 _(b"cannot use '--continue' and '--abort' together")
3030 )
3030 )
3031 if any(
3031 if any(
3032 (
3032 (
3033 opts.get(b'edit'),
3033 opts.get(b'edit'),
3034 opts.get(b'log'),
3034 opts.get(b'log'),
3035 opts.get(b'user'),
3035 opts.get(b'user'),
3036 opts.get(b'date'),
3036 opts.get(b'date'),
3037 opts.get(b'currentdate'),
3037 opts.get(b'currentdate'),
3038 opts.get(b'currentuser'),
3038 opts.get(b'currentuser'),
3039 opts.get(b'rev'),
3039 opts.get(b'rev'),
3040 )
3040 )
3041 ):
3041 ):
3042 raise error.Abort(
3042 raise error.Abort(
3043 _(b"cannot specify any other flag with '--abort'")
3043 _(b"cannot specify any other flag with '--abort'")
3044 )
3044 )
3045
3045
3046 return cmdutil.abortgraft(ui, repo, graftstate)
3046 return cmdutil.abortgraft(ui, repo, graftstate)
3047 elif opts.get(b'continue'):
3047 elif opts.get(b'continue'):
3048 cont = True
3048 cont = True
3049 if revs:
3049 if revs:
3050 raise error.Abort(_(b"can't specify --continue and revisions"))
3050 raise error.Abort(_(b"can't specify --continue and revisions"))
3051 # read in unfinished revisions
3051 # read in unfinished revisions
3052 if graftstate.exists():
3052 if graftstate.exists():
3053 statedata = cmdutil.readgraftstate(repo, graftstate)
3053 statedata = cmdutil.readgraftstate(repo, graftstate)
3054 if statedata.get(b'date'):
3054 if statedata.get(b'date'):
3055 opts[b'date'] = statedata[b'date']
3055 opts[b'date'] = statedata[b'date']
3056 if statedata.get(b'user'):
3056 if statedata.get(b'user'):
3057 opts[b'user'] = statedata[b'user']
3057 opts[b'user'] = statedata[b'user']
3058 if statedata.get(b'log'):
3058 if statedata.get(b'log'):
3059 opts[b'log'] = True
3059 opts[b'log'] = True
3060 if statedata.get(b'no_commit'):
3060 if statedata.get(b'no_commit'):
3061 opts[b'no_commit'] = statedata.get(b'no_commit')
3061 opts[b'no_commit'] = statedata.get(b'no_commit')
3062 nodes = statedata[b'nodes']
3062 nodes = statedata[b'nodes']
3063 revs = [repo[node].rev() for node in nodes]
3063 revs = [repo[node].rev() for node in nodes]
3064 else:
3064 else:
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3066 else:
3066 else:
3067 if not revs:
3067 if not revs:
3068 raise error.Abort(_(b'no revisions specified'))
3068 raise error.Abort(_(b'no revisions specified'))
3069 cmdutil.checkunfinished(repo)
3069 cmdutil.checkunfinished(repo)
3070 cmdutil.bailifchanged(repo)
3070 cmdutil.bailifchanged(repo)
3071 revs = scmutil.revrange(repo, revs)
3071 revs = scmutil.revrange(repo, revs)
3072
3072
3073 skipped = set()
3073 skipped = set()
3074 if basectx is None:
3074 if basectx is None:
3075 # check for merges
3075 # check for merges
3076 for rev in repo.revs(b'%ld and merge()', revs):
3076 for rev in repo.revs(b'%ld and merge()', revs):
3077 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3077 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3078 skipped.add(rev)
3078 skipped.add(rev)
3079 revs = [r for r in revs if r not in skipped]
3079 revs = [r for r in revs if r not in skipped]
3080 if not revs:
3080 if not revs:
3081 return -1
3081 return -1
3082 if basectx is not None and len(revs) != 1:
3082 if basectx is not None and len(revs) != 1:
3083 raise error.Abort(_(b'only one revision allowed with --base '))
3083 raise error.Abort(_(b'only one revision allowed with --base '))
3084
3084
3085 # Don't check in the --continue case, in effect retaining --force across
3085 # Don't check in the --continue case, in effect retaining --force across
3086 # --continues. That's because without --force, any revisions we decided to
3086 # --continues. That's because without --force, any revisions we decided to
3087 # skip would have been filtered out here, so they wouldn't have made their
3087 # skip would have been filtered out here, so they wouldn't have made their
3088 # way to the graftstate. With --force, any revisions we would have otherwise
3088 # way to the graftstate. With --force, any revisions we would have otherwise
3089 # skipped would not have been filtered out, and if they hadn't been applied
3089 # skipped would not have been filtered out, and if they hadn't been applied
3090 # already, they'd have been in the graftstate.
3090 # already, they'd have been in the graftstate.
3091 if not (cont or opts.get(b'force')) and basectx is None:
3091 if not (cont or opts.get(b'force')) and basectx is None:
3092 # check for ancestors of dest branch
3092 # check for ancestors of dest branch
3093 crev = repo[b'.'].rev()
3093 crev = repo[b'.'].rev()
3094 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3094 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3095 # XXX make this lazy in the future
3095 # XXX make this lazy in the future
3096 # don't mutate while iterating, create a copy
3096 # don't mutate while iterating, create a copy
3097 for rev in list(revs):
3097 for rev in list(revs):
3098 if rev in ancestors:
3098 if rev in ancestors:
3099 ui.warn(
3099 ui.warn(
3100 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3100 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3101 )
3101 )
3102 # XXX remove on list is slow
3102 # XXX remove on list is slow
3103 revs.remove(rev)
3103 revs.remove(rev)
3104 if not revs:
3104 if not revs:
3105 return -1
3105 return -1
3106
3106
3107 # analyze revs for earlier grafts
3107 # analyze revs for earlier grafts
3108 ids = {}
3108 ids = {}
3109 for ctx in repo.set(b"%ld", revs):
3109 for ctx in repo.set(b"%ld", revs):
3110 ids[ctx.hex()] = ctx.rev()
3110 ids[ctx.hex()] = ctx.rev()
3111 n = ctx.extra().get(b'source')
3111 n = ctx.extra().get(b'source')
3112 if n:
3112 if n:
3113 ids[n] = ctx.rev()
3113 ids[n] = ctx.rev()
3114
3114
3115 # check ancestors for earlier grafts
3115 # check ancestors for earlier grafts
3116 ui.debug(b'scanning for duplicate grafts\n')
3116 ui.debug(b'scanning for duplicate grafts\n')
3117
3117
3118 # The only changesets we can be sure doesn't contain grafts of any
3118 # The only changesets we can be sure doesn't contain grafts of any
3119 # revs, are the ones that are common ancestors of *all* revs:
3119 # revs, are the ones that are common ancestors of *all* revs:
3120 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3120 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3121 ctx = repo[rev]
3121 ctx = repo[rev]
3122 n = ctx.extra().get(b'source')
3122 n = ctx.extra().get(b'source')
3123 if n in ids:
3123 if n in ids:
3124 try:
3124 try:
3125 r = repo[n].rev()
3125 r = repo[n].rev()
3126 except error.RepoLookupError:
3126 except error.RepoLookupError:
3127 r = None
3127 r = None
3128 if r in revs:
3128 if r in revs:
3129 ui.warn(
3129 ui.warn(
3130 _(
3130 _(
3131 b'skipping revision %d:%s '
3131 b'skipping revision %d:%s '
3132 b'(already grafted to %d:%s)\n'
3132 b'(already grafted to %d:%s)\n'
3133 )
3133 )
3134 % (r, repo[r], rev, ctx)
3134 % (r, repo[r], rev, ctx)
3135 )
3135 )
3136 revs.remove(r)
3136 revs.remove(r)
3137 elif ids[n] in revs:
3137 elif ids[n] in revs:
3138 if r is None:
3138 if r is None:
3139 ui.warn(
3139 ui.warn(
3140 _(
3140 _(
3141 b'skipping already grafted revision %d:%s '
3141 b'skipping already grafted revision %d:%s '
3142 b'(%d:%s also has unknown origin %s)\n'
3142 b'(%d:%s also has unknown origin %s)\n'
3143 )
3143 )
3144 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3144 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3145 )
3145 )
3146 else:
3146 else:
3147 ui.warn(
3147 ui.warn(
3148 _(
3148 _(
3149 b'skipping already grafted revision %d:%s '
3149 b'skipping already grafted revision %d:%s '
3150 b'(%d:%s also has origin %d:%s)\n'
3150 b'(%d:%s also has origin %d:%s)\n'
3151 )
3151 )
3152 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3152 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3153 )
3153 )
3154 revs.remove(ids[n])
3154 revs.remove(ids[n])
3155 elif ctx.hex() in ids:
3155 elif ctx.hex() in ids:
3156 r = ids[ctx.hex()]
3156 r = ids[ctx.hex()]
3157 if r in revs:
3157 if r in revs:
3158 ui.warn(
3158 ui.warn(
3159 _(
3159 _(
3160 b'skipping already grafted revision %d:%s '
3160 b'skipping already grafted revision %d:%s '
3161 b'(was grafted from %d:%s)\n'
3161 b'(was grafted from %d:%s)\n'
3162 )
3162 )
3163 % (r, repo[r], rev, ctx)
3163 % (r, repo[r], rev, ctx)
3164 )
3164 )
3165 revs.remove(r)
3165 revs.remove(r)
3166 if not revs:
3166 if not revs:
3167 return -1
3167 return -1
3168
3168
3169 if opts.get(b'no_commit'):
3169 if opts.get(b'no_commit'):
3170 statedata[b'no_commit'] = True
3170 statedata[b'no_commit'] = True
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3172 desc = b'%d:%s "%s"' % (
3172 desc = b'%d:%s "%s"' % (
3173 ctx.rev(),
3173 ctx.rev(),
3174 ctx,
3174 ctx,
3175 ctx.description().split(b'\n', 1)[0],
3175 ctx.description().split(b'\n', 1)[0],
3176 )
3176 )
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3178 if names:
3178 if names:
3179 desc += b' (%s)' % b' '.join(names)
3179 desc += b' (%s)' % b' '.join(names)
3180 ui.status(_(b'grafting %s\n') % desc)
3180 ui.status(_(b'grafting %s\n') % desc)
3181 if opts.get(b'dry_run'):
3181 if opts.get(b'dry_run'):
3182 continue
3182 continue
3183
3183
3184 source = ctx.extra().get(b'source')
3184 source = ctx.extra().get(b'source')
3185 extra = {}
3185 extra = {}
3186 if source:
3186 if source:
3187 extra[b'source'] = source
3187 extra[b'source'] = source
3188 extra[b'intermediate-source'] = ctx.hex()
3188 extra[b'intermediate-source'] = ctx.hex()
3189 else:
3189 else:
3190 extra[b'source'] = ctx.hex()
3190 extra[b'source'] = ctx.hex()
3191 user = ctx.user()
3191 user = ctx.user()
3192 if opts.get(b'user'):
3192 if opts.get(b'user'):
3193 user = opts[b'user']
3193 user = opts[b'user']
3194 statedata[b'user'] = user
3194 statedata[b'user'] = user
3195 date = ctx.date()
3195 date = ctx.date()
3196 if opts.get(b'date'):
3196 if opts.get(b'date'):
3197 date = opts[b'date']
3197 date = opts[b'date']
3198 statedata[b'date'] = date
3198 statedata[b'date'] = date
3199 message = ctx.description()
3199 message = ctx.description()
3200 if opts.get(b'log'):
3200 if opts.get(b'log'):
3201 message += b'\n(grafted from %s)' % ctx.hex()
3201 message += b'\n(grafted from %s)' % ctx.hex()
3202 statedata[b'log'] = True
3202 statedata[b'log'] = True
3203
3203
3204 # we don't merge the first commit when continuing
3204 # we don't merge the first commit when continuing
3205 if not cont:
3205 if not cont:
3206 # perform the graft merge with p1(rev) as 'ancestor'
3206 # perform the graft merge with p1(rev) as 'ancestor'
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3208 base = ctx.p1() if basectx is None else basectx
3208 base = ctx.p1() if basectx is None else basectx
3209 with ui.configoverride(overrides, b'graft'):
3209 with ui.configoverride(overrides, b'graft'):
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3211 # report any conflicts
3211 # report any conflicts
3212 if stats.unresolvedcount > 0:
3212 if stats.unresolvedcount > 0:
3213 # write out state for --continue
3213 # write out state for --continue
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3215 statedata[b'nodes'] = nodes
3215 statedata[b'nodes'] = nodes
3216 stateversion = 1
3216 stateversion = 1
3217 graftstate.save(stateversion, statedata)
3217 graftstate.save(stateversion, statedata)
3218 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3218 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3219 raise error.Abort(
3219 raise error.Abort(
3220 _(b"unresolved conflicts, can't continue"), hint=hint
3220 _(b"unresolved conflicts, can't continue"), hint=hint
3221 )
3221 )
3222 else:
3222 else:
3223 cont = False
3223 cont = False
3224
3224
3225 # commit if --no-commit is false
3225 # commit if --no-commit is false
3226 if not opts.get(b'no_commit'):
3226 if not opts.get(b'no_commit'):
3227 node = repo.commit(
3227 node = repo.commit(
3228 text=message, user=user, date=date, extra=extra, editor=editor
3228 text=message, user=user, date=date, extra=extra, editor=editor
3229 )
3229 )
3230 if node is None:
3230 if node is None:
3231 ui.warn(
3231 ui.warn(
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3233 % (ctx.rev(), ctx)
3233 % (ctx.rev(), ctx)
3234 )
3234 )
3235 # checking that newnodes exist because old state files won't have it
3235 # checking that newnodes exist because old state files won't have it
3236 elif statedata.get(b'newnodes') is not None:
3236 elif statedata.get(b'newnodes') is not None:
3237 statedata[b'newnodes'].append(node)
3237 statedata[b'newnodes'].append(node)
3238
3238
3239 # remove state when we complete successfully
3239 # remove state when we complete successfully
3240 if not opts.get(b'dry_run'):
3240 if not opts.get(b'dry_run'):
3241 graftstate.delete()
3241 graftstate.delete()
3242
3242
3243 return 0
3243 return 0
3244
3244
3245
3245
3246 def _stopgraft(ui, repo, graftstate):
3246 def _stopgraft(ui, repo, graftstate):
3247 """stop the interrupted graft"""
3247 """stop the interrupted graft"""
3248 if not graftstate.exists():
3248 if not graftstate.exists():
3249 raise error.Abort(_(b"no interrupted graft found"))
3249 raise error.Abort(_(b"no interrupted graft found"))
3250 pctx = repo[b'.']
3250 pctx = repo[b'.']
3251 hg.updaterepo(repo, pctx.node(), overwrite=True)
3251 hg.updaterepo(repo, pctx.node(), overwrite=True)
3252 graftstate.delete()
3252 graftstate.delete()
3253 ui.status(_(b"stopped the interrupted graft\n"))
3253 ui.status(_(b"stopped the interrupted graft\n"))
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3255 return 0
3255 return 0
3256
3256
3257
3257
3258 statemod.addunfinished(
3258 statemod.addunfinished(
3259 b'graft',
3259 b'graft',
3260 fname=b'graftstate',
3260 fname=b'graftstate',
3261 clearable=True,
3261 clearable=True,
3262 stopflag=True,
3262 stopflag=True,
3263 continueflag=True,
3263 continueflag=True,
3264 abortfunc=cmdutil.hgabortgraft,
3264 abortfunc=cmdutil.hgabortgraft,
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3266 )
3266 )
3267
3267
3268
3268
3269 @command(
3269 @command(
3270 b'grep',
3270 b'grep',
3271 [
3271 [
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3273 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3273 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3274 (
3274 (
3275 b'',
3275 b'',
3276 b'diff',
3276 b'diff',
3277 None,
3277 None,
3278 _(
3278 _(
3279 b'print all revisions when the term was introduced '
3279 b'print all revisions when the term was introduced '
3280 b'or removed'
3280 b'or removed'
3281 ),
3281 ),
3282 ),
3282 ),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3284 (
3284 (
3285 b'f',
3285 b'f',
3286 b'follow',
3286 b'follow',
3287 None,
3287 None,
3288 _(
3288 _(
3289 b'follow changeset history,'
3289 b'follow changeset history,'
3290 b' or file history across copies and renames'
3290 b' or file history across copies and renames'
3291 ),
3291 ),
3292 ),
3292 ),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3294 (
3294 (
3295 b'l',
3295 b'l',
3296 b'files-with-matches',
3296 b'files-with-matches',
3297 None,
3297 None,
3298 _(b'print only filenames and revisions that match'),
3298 _(b'print only filenames and revisions that match'),
3299 ),
3299 ),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3301 (
3301 (
3302 b'r',
3302 b'r',
3303 b'rev',
3303 b'rev',
3304 [],
3304 [],
3305 _(b'only search files changed within revision range'),
3305 _(b'only search files changed within revision range'),
3306 _(b'REV'),
3306 _(b'REV'),
3307 ),
3307 ),
3308 (
3308 (
3309 b'',
3309 b'',
3310 b'all-files',
3310 b'all-files',
3311 None,
3311 None,
3312 _(
3312 _(
3313 b'include all files in the changeset while grepping (EXPERIMENTAL)'
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3314 ),
3314 ),
3315 ),
3315 ),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3318 ]
3318 ]
3319 + formatteropts
3319 + formatteropts
3320 + walkopts,
3320 + walkopts,
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3323 inferrepo=True,
3323 inferrepo=True,
3324 intents={INTENT_READONLY},
3324 intents={INTENT_READONLY},
3325 )
3325 )
3326 def grep(ui, repo, pattern, *pats, **opts):
3326 def grep(ui, repo, pattern, *pats, **opts):
3327 """search revision history for a pattern in specified files
3327 """search revision history for a pattern in specified files
3328
3328
3329 Search revision history for a regular expression in the specified
3329 Search revision history for a regular expression in the specified
3330 files or the entire project.
3330 files or the entire project.
3331
3331
3332 By default, grep prints the most recent revision number for each
3332 By default, grep prints the most recent revision number for each
3333 file in which it finds a match. To get it to print every revision
3333 file in which it finds a match. To get it to print every revision
3334 that contains a change in match status ("-" for a match that becomes
3334 that contains a change in match status ("-" for a match that becomes
3335 a non-match, or "+" for a non-match that becomes a match), use the
3335 a non-match, or "+" for a non-match that becomes a match), use the
3336 --diff flag.
3336 --diff flag.
3337
3337
3338 PATTERN can be any Python (roughly Perl-compatible) regular
3338 PATTERN can be any Python (roughly Perl-compatible) regular
3339 expression.
3339 expression.
3340
3340
3341 If no FILEs are specified (and -f/--follow isn't set), all files in
3341 If no FILEs are specified (and -f/--follow isn't set), all files in
3342 the repository are searched, including those that don't exist in the
3342 the repository are searched, including those that don't exist in the
3343 current branch or have been deleted in a prior changeset.
3343 current branch or have been deleted in a prior changeset.
3344
3344
3345 .. container:: verbose
3345 .. container:: verbose
3346
3346
3347 Template:
3347 Template:
3348
3348
3349 The following keywords are supported in addition to the common template
3349 The following keywords are supported in addition to the common template
3350 keywords and functions. See also :hg:`help templates`.
3350 keywords and functions. See also :hg:`help templates`.
3351
3351
3352 :change: String. Character denoting insertion ``+`` or removal ``-``.
3352 :change: String. Character denoting insertion ``+`` or removal ``-``.
3353 Available if ``--diff`` is specified.
3353 Available if ``--diff`` is specified.
3354 :lineno: Integer. Line number of the match.
3354 :lineno: Integer. Line number of the match.
3355 :path: String. Repository-absolute path of the file.
3355 :path: String. Repository-absolute path of the file.
3356 :texts: List of text chunks.
3356 :texts: List of text chunks.
3357
3357
3358 And each entry of ``{texts}`` provides the following sub-keywords.
3358 And each entry of ``{texts}`` provides the following sub-keywords.
3359
3359
3360 :matched: Boolean. True if the chunk matches the specified pattern.
3360 :matched: Boolean. True if the chunk matches the specified pattern.
3361 :text: String. Chunk content.
3361 :text: String. Chunk content.
3362
3362
3363 See :hg:`help templates.operators` for the list expansion syntax.
3363 See :hg:`help templates.operators` for the list expansion syntax.
3364
3364
3365 Returns 0 if a match is found, 1 otherwise.
3365 Returns 0 if a match is found, 1 otherwise.
3366 """
3366 """
3367 opts = pycompat.byteskwargs(opts)
3367 opts = pycompat.byteskwargs(opts)
3368 diff = opts.get(b'all') or opts.get(b'diff')
3368 diff = opts.get(b'all') or opts.get(b'diff')
3369 all_files = opts.get(b'all_files')
3370 if diff and opts.get(b'all_files'):
3369 if diff and opts.get(b'all_files'):
3371 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3370 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3372 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
3371 if opts.get(b'all_files') is None and not diff:
3373 if opts.get(b'all_files') is None and not opts.get(b'rev') and not diff:
3372 opts[b'all_files'] = True
3374 # experimental config: commands.grep.all-files
3375 opts[b'all_files'] = ui.configbool(b'commands', b'grep.all-files')
3376 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3373 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3374 all_files = opts.get(b'all_files')
3377 if plaingrep:
3375 if plaingrep:
3378 opts[b'rev'] = [b'wdir()']
3376 opts[b'rev'] = [b'wdir()']
3379
3377
3380 reflags = re.M
3378 reflags = re.M
3381 if opts.get(b'ignore_case'):
3379 if opts.get(b'ignore_case'):
3382 reflags |= re.I
3380 reflags |= re.I
3383 try:
3381 try:
3384 regexp = util.re.compile(pattern, reflags)
3382 regexp = util.re.compile(pattern, reflags)
3385 except re.error as inst:
3383 except re.error as inst:
3386 ui.warn(
3384 ui.warn(
3387 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3385 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3388 )
3386 )
3389 return 1
3387 return 1
3390 sep, eol = b':', b'\n'
3388 sep, eol = b':', b'\n'
3391 if opts.get(b'print0'):
3389 if opts.get(b'print0'):
3392 sep = eol = b'\0'
3390 sep = eol = b'\0'
3393
3391
3394 getfile = util.lrucachefunc(repo.file)
3392 getfile = util.lrucachefunc(repo.file)
3395
3393
3396 def matchlines(body):
3394 def matchlines(body):
3397 begin = 0
3395 begin = 0
3398 linenum = 0
3396 linenum = 0
3399 while begin < len(body):
3397 while begin < len(body):
3400 match = regexp.search(body, begin)
3398 match = regexp.search(body, begin)
3401 if not match:
3399 if not match:
3402 break
3400 break
3403 mstart, mend = match.span()
3401 mstart, mend = match.span()
3404 linenum += body.count(b'\n', begin, mstart) + 1
3402 linenum += body.count(b'\n', begin, mstart) + 1
3405 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3403 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3406 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3404 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3407 lend = begin - 1
3405 lend = begin - 1
3408 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3406 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3409
3407
3410 class linestate(object):
3408 class linestate(object):
3411 def __init__(self, line, linenum, colstart, colend):
3409 def __init__(self, line, linenum, colstart, colend):
3412 self.line = line
3410 self.line = line
3413 self.linenum = linenum
3411 self.linenum = linenum
3414 self.colstart = colstart
3412 self.colstart = colstart
3415 self.colend = colend
3413 self.colend = colend
3416
3414
3417 def __hash__(self):
3415 def __hash__(self):
3418 return hash((self.linenum, self.line))
3416 return hash((self.linenum, self.line))
3419
3417
3420 def __eq__(self, other):
3418 def __eq__(self, other):
3421 return self.line == other.line
3419 return self.line == other.line
3422
3420
3423 def findpos(self):
3421 def findpos(self):
3424 """Iterate all (start, end) indices of matches"""
3422 """Iterate all (start, end) indices of matches"""
3425 yield self.colstart, self.colend
3423 yield self.colstart, self.colend
3426 p = self.colend
3424 p = self.colend
3427 while p < len(self.line):
3425 while p < len(self.line):
3428 m = regexp.search(self.line, p)
3426 m = regexp.search(self.line, p)
3429 if not m:
3427 if not m:
3430 break
3428 break
3431 yield m.span()
3429 yield m.span()
3432 p = m.end()
3430 p = m.end()
3433
3431
3434 matches = {}
3432 matches = {}
3435 copies = {}
3433 copies = {}
3436
3434
3437 def grepbody(fn, rev, body):
3435 def grepbody(fn, rev, body):
3438 matches[rev].setdefault(fn, [])
3436 matches[rev].setdefault(fn, [])
3439 m = matches[rev][fn]
3437 m = matches[rev][fn]
3440 for lnum, cstart, cend, line in matchlines(body):
3438 for lnum, cstart, cend, line in matchlines(body):
3441 s = linestate(line, lnum, cstart, cend)
3439 s = linestate(line, lnum, cstart, cend)
3442 m.append(s)
3440 m.append(s)
3443
3441
3444 def difflinestates(a, b):
3442 def difflinestates(a, b):
3445 sm = difflib.SequenceMatcher(None, a, b)
3443 sm = difflib.SequenceMatcher(None, a, b)
3446 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3444 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3447 if tag == r'insert':
3445 if tag == r'insert':
3448 for i in pycompat.xrange(blo, bhi):
3446 for i in pycompat.xrange(blo, bhi):
3449 yield (b'+', b[i])
3447 yield (b'+', b[i])
3450 elif tag == r'delete':
3448 elif tag == r'delete':
3451 for i in pycompat.xrange(alo, ahi):
3449 for i in pycompat.xrange(alo, ahi):
3452 yield (b'-', a[i])
3450 yield (b'-', a[i])
3453 elif tag == r'replace':
3451 elif tag == r'replace':
3454 for i in pycompat.xrange(alo, ahi):
3452 for i in pycompat.xrange(alo, ahi):
3455 yield (b'-', a[i])
3453 yield (b'-', a[i])
3456 for i in pycompat.xrange(blo, bhi):
3454 for i in pycompat.xrange(blo, bhi):
3457 yield (b'+', b[i])
3455 yield (b'+', b[i])
3458
3456
3459 uipathfn = scmutil.getuipathfn(repo)
3457 uipathfn = scmutil.getuipathfn(repo)
3460
3458
3461 def display(fm, fn, ctx, pstates, states):
3459 def display(fm, fn, ctx, pstates, states):
3462 rev = scmutil.intrev(ctx)
3460 rev = scmutil.intrev(ctx)
3463 if fm.isplain():
3461 if fm.isplain():
3464 formatuser = ui.shortuser
3462 formatuser = ui.shortuser
3465 else:
3463 else:
3466 formatuser = pycompat.bytestr
3464 formatuser = pycompat.bytestr
3467 if ui.quiet:
3465 if ui.quiet:
3468 datefmt = b'%Y-%m-%d'
3466 datefmt = b'%Y-%m-%d'
3469 else:
3467 else:
3470 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3468 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3471 found = False
3469 found = False
3472
3470
3473 @util.cachefunc
3471 @util.cachefunc
3474 def binary():
3472 def binary():
3475 flog = getfile(fn)
3473 flog = getfile(fn)
3476 try:
3474 try:
3477 return stringutil.binary(flog.read(ctx.filenode(fn)))
3475 return stringutil.binary(flog.read(ctx.filenode(fn)))
3478 except error.WdirUnsupported:
3476 except error.WdirUnsupported:
3479 return ctx[fn].isbinary()
3477 return ctx[fn].isbinary()
3480
3478
3481 fieldnamemap = {b'linenumber': b'lineno'}
3479 fieldnamemap = {b'linenumber': b'lineno'}
3482 if diff:
3480 if diff:
3483 iter = difflinestates(pstates, states)
3481 iter = difflinestates(pstates, states)
3484 else:
3482 else:
3485 iter = [(b'', l) for l in states]
3483 iter = [(b'', l) for l in states]
3486 for change, l in iter:
3484 for change, l in iter:
3487 fm.startitem()
3485 fm.startitem()
3488 fm.context(ctx=ctx)
3486 fm.context(ctx=ctx)
3489 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3487 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3490 fm.plain(uipathfn(fn), label=b'grep.filename')
3488 fm.plain(uipathfn(fn), label=b'grep.filename')
3491
3489
3492 cols = [
3490 cols = [
3493 (b'rev', b'%d', rev, not plaingrep, b''),
3491 (b'rev', b'%d', rev, not plaingrep, b''),
3494 (
3492 (
3495 b'linenumber',
3493 b'linenumber',
3496 b'%d',
3494 b'%d',
3497 l.linenum,
3495 l.linenum,
3498 opts.get(b'line_number'),
3496 opts.get(b'line_number'),
3499 b'',
3497 b'',
3500 ),
3498 ),
3501 ]
3499 ]
3502 if diff:
3500 if diff:
3503 cols.append(
3501 cols.append(
3504 (
3502 (
3505 b'change',
3503 b'change',
3506 b'%s',
3504 b'%s',
3507 change,
3505 change,
3508 True,
3506 True,
3509 b'grep.inserted '
3507 b'grep.inserted '
3510 if change == b'+'
3508 if change == b'+'
3511 else b'grep.deleted ',
3509 else b'grep.deleted ',
3512 )
3510 )
3513 )
3511 )
3514 cols.extend(
3512 cols.extend(
3515 [
3513 [
3516 (
3514 (
3517 b'user',
3515 b'user',
3518 b'%s',
3516 b'%s',
3519 formatuser(ctx.user()),
3517 formatuser(ctx.user()),
3520 opts.get(b'user'),
3518 opts.get(b'user'),
3521 b'',
3519 b'',
3522 ),
3520 ),
3523 (
3521 (
3524 b'date',
3522 b'date',
3525 b'%s',
3523 b'%s',
3526 fm.formatdate(ctx.date(), datefmt),
3524 fm.formatdate(ctx.date(), datefmt),
3527 opts.get(b'date'),
3525 opts.get(b'date'),
3528 b'',
3526 b'',
3529 ),
3527 ),
3530 ]
3528 ]
3531 )
3529 )
3532 for name, fmt, data, cond, extra_label in cols:
3530 for name, fmt, data, cond, extra_label in cols:
3533 if cond:
3531 if cond:
3534 fm.plain(sep, label=b'grep.sep')
3532 fm.plain(sep, label=b'grep.sep')
3535 field = fieldnamemap.get(name, name)
3533 field = fieldnamemap.get(name, name)
3536 label = extra_label + (b'grep.%s' % name)
3534 label = extra_label + (b'grep.%s' % name)
3537 fm.condwrite(cond, field, fmt, data, label=label)
3535 fm.condwrite(cond, field, fmt, data, label=label)
3538 if not opts.get(b'files_with_matches'):
3536 if not opts.get(b'files_with_matches'):
3539 fm.plain(sep, label=b'grep.sep')
3537 fm.plain(sep, label=b'grep.sep')
3540 if not opts.get(b'text') and binary():
3538 if not opts.get(b'text') and binary():
3541 fm.plain(_(b" Binary file matches"))
3539 fm.plain(_(b" Binary file matches"))
3542 else:
3540 else:
3543 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3541 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3544 fm.plain(eol)
3542 fm.plain(eol)
3545 found = True
3543 found = True
3546 if opts.get(b'files_with_matches'):
3544 if opts.get(b'files_with_matches'):
3547 break
3545 break
3548 return found
3546 return found
3549
3547
3550 def displaymatches(fm, l):
3548 def displaymatches(fm, l):
3551 p = 0
3549 p = 0
3552 for s, e in l.findpos():
3550 for s, e in l.findpos():
3553 if p < s:
3551 if p < s:
3554 fm.startitem()
3552 fm.startitem()
3555 fm.write(b'text', b'%s', l.line[p:s])
3553 fm.write(b'text', b'%s', l.line[p:s])
3556 fm.data(matched=False)
3554 fm.data(matched=False)
3557 fm.startitem()
3555 fm.startitem()
3558 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3556 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3559 fm.data(matched=True)
3557 fm.data(matched=True)
3560 p = e
3558 p = e
3561 if p < len(l.line):
3559 if p < len(l.line):
3562 fm.startitem()
3560 fm.startitem()
3563 fm.write(b'text', b'%s', l.line[p:])
3561 fm.write(b'text', b'%s', l.line[p:])
3564 fm.data(matched=False)
3562 fm.data(matched=False)
3565 fm.end()
3563 fm.end()
3566
3564
3567 skip = set()
3565 skip = set()
3568 revfiles = {}
3566 revfiles = {}
3569 match = scmutil.match(repo[None], pats, opts)
3567 match = scmutil.match(repo[None], pats, opts)
3570 found = False
3568 found = False
3571 follow = opts.get(b'follow')
3569 follow = opts.get(b'follow')
3572
3570
3573 getrenamed = scmutil.getrenamedfn(repo)
3571 getrenamed = scmutil.getrenamedfn(repo)
3574
3572
3575 def prep(ctx, fns):
3573 def prep(ctx, fns):
3576 rev = ctx.rev()
3574 rev = ctx.rev()
3577 pctx = ctx.p1()
3575 pctx = ctx.p1()
3578 parent = pctx.rev()
3576 parent = pctx.rev()
3579 matches.setdefault(rev, {})
3577 matches.setdefault(rev, {})
3580 matches.setdefault(parent, {})
3578 matches.setdefault(parent, {})
3581 files = revfiles.setdefault(rev, [])
3579 files = revfiles.setdefault(rev, [])
3582 for fn in fns:
3580 for fn in fns:
3583 flog = getfile(fn)
3581 flog = getfile(fn)
3584 try:
3582 try:
3585 fnode = ctx.filenode(fn)
3583 fnode = ctx.filenode(fn)
3586 except error.LookupError:
3584 except error.LookupError:
3587 continue
3585 continue
3588
3586
3589 copy = None
3587 copy = None
3590 if follow:
3588 if follow:
3591 copy = getrenamed(fn, rev)
3589 copy = getrenamed(fn, rev)
3592 if copy:
3590 if copy:
3593 copies.setdefault(rev, {})[fn] = copy
3591 copies.setdefault(rev, {})[fn] = copy
3594 if fn in skip:
3592 if fn in skip:
3595 skip.add(copy)
3593 skip.add(copy)
3596 if fn in skip:
3594 if fn in skip:
3597 continue
3595 continue
3598 files.append(fn)
3596 files.append(fn)
3599
3597
3600 if fn not in matches[rev]:
3598 if fn not in matches[rev]:
3601 try:
3599 try:
3602 content = flog.read(fnode)
3600 content = flog.read(fnode)
3603 except error.WdirUnsupported:
3601 except error.WdirUnsupported:
3604 content = ctx[fn].data()
3602 content = ctx[fn].data()
3605 grepbody(fn, rev, content)
3603 grepbody(fn, rev, content)
3606
3604
3607 pfn = copy or fn
3605 pfn = copy or fn
3608 if pfn not in matches[parent]:
3606 if pfn not in matches[parent]:
3609 try:
3607 try:
3610 fnode = pctx.filenode(pfn)
3608 fnode = pctx.filenode(pfn)
3611 grepbody(pfn, parent, flog.read(fnode))
3609 grepbody(pfn, parent, flog.read(fnode))
3612 except error.LookupError:
3610 except error.LookupError:
3613 pass
3611 pass
3614
3612
3615 ui.pager(b'grep')
3613 ui.pager(b'grep')
3616 fm = ui.formatter(b'grep', opts)
3614 fm = ui.formatter(b'grep', opts)
3617 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3615 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3618 rev = ctx.rev()
3616 rev = ctx.rev()
3619 parent = ctx.p1().rev()
3617 parent = ctx.p1().rev()
3620 for fn in sorted(revfiles.get(rev, [])):
3618 for fn in sorted(revfiles.get(rev, [])):
3621 states = matches[rev][fn]
3619 states = matches[rev][fn]
3622 copy = copies.get(rev, {}).get(fn)
3620 copy = copies.get(rev, {}).get(fn)
3623 if fn in skip:
3621 if fn in skip:
3624 if copy:
3622 if copy:
3625 skip.add(copy)
3623 skip.add(copy)
3626 continue
3624 continue
3627 pstates = matches.get(parent, {}).get(copy or fn, [])
3625 pstates = matches.get(parent, {}).get(copy or fn, [])
3628 if pstates or states:
3626 if pstates or states:
3629 r = display(fm, fn, ctx, pstates, states)
3627 r = display(fm, fn, ctx, pstates, states)
3630 found = found or r
3628 found = found or r
3631 if r and not diff and not all_files:
3629 if r and not diff and not all_files:
3632 skip.add(fn)
3630 skip.add(fn)
3633 if copy:
3631 if copy:
3634 skip.add(copy)
3632 skip.add(copy)
3635 del revfiles[rev]
3633 del revfiles[rev]
3636 # We will keep the matches dict for the duration of the window
3634 # We will keep the matches dict for the duration of the window
3637 # clear the matches dict once the window is over
3635 # clear the matches dict once the window is over
3638 if not revfiles:
3636 if not revfiles:
3639 matches.clear()
3637 matches.clear()
3640 fm.end()
3638 fm.end()
3641
3639
3642 return not found
3640 return not found
3643
3641
3644
3642
3645 @command(
3643 @command(
3646 b'heads',
3644 b'heads',
3647 [
3645 [
3648 (
3646 (
3649 b'r',
3647 b'r',
3650 b'rev',
3648 b'rev',
3651 b'',
3649 b'',
3652 _(b'show only heads which are descendants of STARTREV'),
3650 _(b'show only heads which are descendants of STARTREV'),
3653 _(b'STARTREV'),
3651 _(b'STARTREV'),
3654 ),
3652 ),
3655 (b't', b'topo', False, _(b'show topological heads only')),
3653 (b't', b'topo', False, _(b'show topological heads only')),
3656 (
3654 (
3657 b'a',
3655 b'a',
3658 b'active',
3656 b'active',
3659 False,
3657 False,
3660 _(b'show active branchheads only (DEPRECATED)'),
3658 _(b'show active branchheads only (DEPRECATED)'),
3661 ),
3659 ),
3662 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3660 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3663 ]
3661 ]
3664 + templateopts,
3662 + templateopts,
3665 _(b'[-ct] [-r STARTREV] [REV]...'),
3663 _(b'[-ct] [-r STARTREV] [REV]...'),
3666 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3664 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3667 intents={INTENT_READONLY},
3665 intents={INTENT_READONLY},
3668 )
3666 )
3669 def heads(ui, repo, *branchrevs, **opts):
3667 def heads(ui, repo, *branchrevs, **opts):
3670 """show branch heads
3668 """show branch heads
3671
3669
3672 With no arguments, show all open branch heads in the repository.
3670 With no arguments, show all open branch heads in the repository.
3673 Branch heads are changesets that have no descendants on the
3671 Branch heads are changesets that have no descendants on the
3674 same branch. They are where development generally takes place and
3672 same branch. They are where development generally takes place and
3675 are the usual targets for update and merge operations.
3673 are the usual targets for update and merge operations.
3676
3674
3677 If one or more REVs are given, only open branch heads on the
3675 If one or more REVs are given, only open branch heads on the
3678 branches associated with the specified changesets are shown. This
3676 branches associated with the specified changesets are shown. This
3679 means that you can use :hg:`heads .` to see the heads on the
3677 means that you can use :hg:`heads .` to see the heads on the
3680 currently checked-out branch.
3678 currently checked-out branch.
3681
3679
3682 If -c/--closed is specified, also show branch heads marked closed
3680 If -c/--closed is specified, also show branch heads marked closed
3683 (see :hg:`commit --close-branch`).
3681 (see :hg:`commit --close-branch`).
3684
3682
3685 If STARTREV is specified, only those heads that are descendants of
3683 If STARTREV is specified, only those heads that are descendants of
3686 STARTREV will be displayed.
3684 STARTREV will be displayed.
3687
3685
3688 If -t/--topo is specified, named branch mechanics will be ignored and only
3686 If -t/--topo is specified, named branch mechanics will be ignored and only
3689 topological heads (changesets with no children) will be shown.
3687 topological heads (changesets with no children) will be shown.
3690
3688
3691 Returns 0 if matching heads are found, 1 if not.
3689 Returns 0 if matching heads are found, 1 if not.
3692 """
3690 """
3693
3691
3694 opts = pycompat.byteskwargs(opts)
3692 opts = pycompat.byteskwargs(opts)
3695 start = None
3693 start = None
3696 rev = opts.get(b'rev')
3694 rev = opts.get(b'rev')
3697 if rev:
3695 if rev:
3698 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3696 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3699 start = scmutil.revsingle(repo, rev, None).node()
3697 start = scmutil.revsingle(repo, rev, None).node()
3700
3698
3701 if opts.get(b'topo'):
3699 if opts.get(b'topo'):
3702 heads = [repo[h] for h in repo.heads(start)]
3700 heads = [repo[h] for h in repo.heads(start)]
3703 else:
3701 else:
3704 heads = []
3702 heads = []
3705 for branch in repo.branchmap():
3703 for branch in repo.branchmap():
3706 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3704 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3707 heads = [repo[h] for h in heads]
3705 heads = [repo[h] for h in heads]
3708
3706
3709 if branchrevs:
3707 if branchrevs:
3710 branches = set(
3708 branches = set(
3711 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3709 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3712 )
3710 )
3713 heads = [h for h in heads if h.branch() in branches]
3711 heads = [h for h in heads if h.branch() in branches]
3714
3712
3715 if opts.get(b'active') and branchrevs:
3713 if opts.get(b'active') and branchrevs:
3716 dagheads = repo.heads(start)
3714 dagheads = repo.heads(start)
3717 heads = [h for h in heads if h.node() in dagheads]
3715 heads = [h for h in heads if h.node() in dagheads]
3718
3716
3719 if branchrevs:
3717 if branchrevs:
3720 haveheads = set(h.branch() for h in heads)
3718 haveheads = set(h.branch() for h in heads)
3721 if branches - haveheads:
3719 if branches - haveheads:
3722 headless = b', '.join(b for b in branches - haveheads)
3720 headless = b', '.join(b for b in branches - haveheads)
3723 msg = _(b'no open branch heads found on branches %s')
3721 msg = _(b'no open branch heads found on branches %s')
3724 if opts.get(b'rev'):
3722 if opts.get(b'rev'):
3725 msg += _(b' (started at %s)') % opts[b'rev']
3723 msg += _(b' (started at %s)') % opts[b'rev']
3726 ui.warn((msg + b'\n') % headless)
3724 ui.warn((msg + b'\n') % headless)
3727
3725
3728 if not heads:
3726 if not heads:
3729 return 1
3727 return 1
3730
3728
3731 ui.pager(b'heads')
3729 ui.pager(b'heads')
3732 heads = sorted(heads, key=lambda x: -(x.rev()))
3730 heads = sorted(heads, key=lambda x: -(x.rev()))
3733 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3731 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3734 for ctx in heads:
3732 for ctx in heads:
3735 displayer.show(ctx)
3733 displayer.show(ctx)
3736 displayer.close()
3734 displayer.close()
3737
3735
3738
3736
3739 @command(
3737 @command(
3740 b'help',
3738 b'help',
3741 [
3739 [
3742 (b'e', b'extension', None, _(b'show only help for extensions')),
3740 (b'e', b'extension', None, _(b'show only help for extensions')),
3743 (b'c', b'command', None, _(b'show only help for commands')),
3741 (b'c', b'command', None, _(b'show only help for commands')),
3744 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3742 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3745 (
3743 (
3746 b's',
3744 b's',
3747 b'system',
3745 b'system',
3748 [],
3746 [],
3749 _(b'show help for specific platform(s)'),
3747 _(b'show help for specific platform(s)'),
3750 _(b'PLATFORM'),
3748 _(b'PLATFORM'),
3751 ),
3749 ),
3752 ],
3750 ],
3753 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3751 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3754 helpcategory=command.CATEGORY_HELP,
3752 helpcategory=command.CATEGORY_HELP,
3755 norepo=True,
3753 norepo=True,
3756 intents={INTENT_READONLY},
3754 intents={INTENT_READONLY},
3757 )
3755 )
3758 def help_(ui, name=None, **opts):
3756 def help_(ui, name=None, **opts):
3759 """show help for a given topic or a help overview
3757 """show help for a given topic or a help overview
3760
3758
3761 With no arguments, print a list of commands with short help messages.
3759 With no arguments, print a list of commands with short help messages.
3762
3760
3763 Given a topic, extension, or command name, print help for that
3761 Given a topic, extension, or command name, print help for that
3764 topic.
3762 topic.
3765
3763
3766 Returns 0 if successful.
3764 Returns 0 if successful.
3767 """
3765 """
3768
3766
3769 keep = opts.get(r'system') or []
3767 keep = opts.get(r'system') or []
3770 if len(keep) == 0:
3768 if len(keep) == 0:
3771 if pycompat.sysplatform.startswith(b'win'):
3769 if pycompat.sysplatform.startswith(b'win'):
3772 keep.append(b'windows')
3770 keep.append(b'windows')
3773 elif pycompat.sysplatform == b'OpenVMS':
3771 elif pycompat.sysplatform == b'OpenVMS':
3774 keep.append(b'vms')
3772 keep.append(b'vms')
3775 elif pycompat.sysplatform == b'plan9':
3773 elif pycompat.sysplatform == b'plan9':
3776 keep.append(b'plan9')
3774 keep.append(b'plan9')
3777 else:
3775 else:
3778 keep.append(b'unix')
3776 keep.append(b'unix')
3779 keep.append(pycompat.sysplatform.lower())
3777 keep.append(pycompat.sysplatform.lower())
3780 if ui.verbose:
3778 if ui.verbose:
3781 keep.append(b'verbose')
3779 keep.append(b'verbose')
3782
3780
3783 commands = sys.modules[__name__]
3781 commands = sys.modules[__name__]
3784 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3782 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3785 ui.pager(b'help')
3783 ui.pager(b'help')
3786 ui.write(formatted)
3784 ui.write(formatted)
3787
3785
3788
3786
3789 @command(
3787 @command(
3790 b'identify|id',
3788 b'identify|id',
3791 [
3789 [
3792 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3790 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3793 (b'n', b'num', None, _(b'show local revision number')),
3791 (b'n', b'num', None, _(b'show local revision number')),
3794 (b'i', b'id', None, _(b'show global revision id')),
3792 (b'i', b'id', None, _(b'show global revision id')),
3795 (b'b', b'branch', None, _(b'show branch')),
3793 (b'b', b'branch', None, _(b'show branch')),
3796 (b't', b'tags', None, _(b'show tags')),
3794 (b't', b'tags', None, _(b'show tags')),
3797 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3795 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3798 ]
3796 ]
3799 + remoteopts
3797 + remoteopts
3800 + formatteropts,
3798 + formatteropts,
3801 _(b'[-nibtB] [-r REV] [SOURCE]'),
3799 _(b'[-nibtB] [-r REV] [SOURCE]'),
3802 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3800 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3803 optionalrepo=True,
3801 optionalrepo=True,
3804 intents={INTENT_READONLY},
3802 intents={INTENT_READONLY},
3805 )
3803 )
3806 def identify(
3804 def identify(
3807 ui,
3805 ui,
3808 repo,
3806 repo,
3809 source=None,
3807 source=None,
3810 rev=None,
3808 rev=None,
3811 num=None,
3809 num=None,
3812 id=None,
3810 id=None,
3813 branch=None,
3811 branch=None,
3814 tags=None,
3812 tags=None,
3815 bookmarks=None,
3813 bookmarks=None,
3816 **opts
3814 **opts
3817 ):
3815 ):
3818 """identify the working directory or specified revision
3816 """identify the working directory or specified revision
3819
3817
3820 Print a summary identifying the repository state at REV using one or
3818 Print a summary identifying the repository state at REV using one or
3821 two parent hash identifiers, followed by a "+" if the working
3819 two parent hash identifiers, followed by a "+" if the working
3822 directory has uncommitted changes, the branch name (if not default),
3820 directory has uncommitted changes, the branch name (if not default),
3823 a list of tags, and a list of bookmarks.
3821 a list of tags, and a list of bookmarks.
3824
3822
3825 When REV is not given, print a summary of the current state of the
3823 When REV is not given, print a summary of the current state of the
3826 repository including the working directory. Specify -r. to get information
3824 repository including the working directory. Specify -r. to get information
3827 of the working directory parent without scanning uncommitted changes.
3825 of the working directory parent without scanning uncommitted changes.
3828
3826
3829 Specifying a path to a repository root or Mercurial bundle will
3827 Specifying a path to a repository root or Mercurial bundle will
3830 cause lookup to operate on that repository/bundle.
3828 cause lookup to operate on that repository/bundle.
3831
3829
3832 .. container:: verbose
3830 .. container:: verbose
3833
3831
3834 Template:
3832 Template:
3835
3833
3836 The following keywords are supported in addition to the common template
3834 The following keywords are supported in addition to the common template
3837 keywords and functions. See also :hg:`help templates`.
3835 keywords and functions. See also :hg:`help templates`.
3838
3836
3839 :dirty: String. Character ``+`` denoting if the working directory has
3837 :dirty: String. Character ``+`` denoting if the working directory has
3840 uncommitted changes.
3838 uncommitted changes.
3841 :id: String. One or two nodes, optionally followed by ``+``.
3839 :id: String. One or two nodes, optionally followed by ``+``.
3842 :parents: List of strings. Parent nodes of the changeset.
3840 :parents: List of strings. Parent nodes of the changeset.
3843
3841
3844 Examples:
3842 Examples:
3845
3843
3846 - generate a build identifier for the working directory::
3844 - generate a build identifier for the working directory::
3847
3845
3848 hg id --id > build-id.dat
3846 hg id --id > build-id.dat
3849
3847
3850 - find the revision corresponding to a tag::
3848 - find the revision corresponding to a tag::
3851
3849
3852 hg id -n -r 1.3
3850 hg id -n -r 1.3
3853
3851
3854 - check the most recent revision of a remote repository::
3852 - check the most recent revision of a remote repository::
3855
3853
3856 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3854 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3857
3855
3858 See :hg:`log` for generating more information about specific revisions,
3856 See :hg:`log` for generating more information about specific revisions,
3859 including full hash identifiers.
3857 including full hash identifiers.
3860
3858
3861 Returns 0 if successful.
3859 Returns 0 if successful.
3862 """
3860 """
3863
3861
3864 opts = pycompat.byteskwargs(opts)
3862 opts = pycompat.byteskwargs(opts)
3865 if not repo and not source:
3863 if not repo and not source:
3866 raise error.Abort(
3864 raise error.Abort(
3867 _(b"there is no Mercurial repository here (.hg not found)")
3865 _(b"there is no Mercurial repository here (.hg not found)")
3868 )
3866 )
3869
3867
3870 default = not (num or id or branch or tags or bookmarks)
3868 default = not (num or id or branch or tags or bookmarks)
3871 output = []
3869 output = []
3872 revs = []
3870 revs = []
3873
3871
3874 if source:
3872 if source:
3875 source, branches = hg.parseurl(ui.expandpath(source))
3873 source, branches = hg.parseurl(ui.expandpath(source))
3876 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3874 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3877 repo = peer.local()
3875 repo = peer.local()
3878 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3876 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3879
3877
3880 fm = ui.formatter(b'identify', opts)
3878 fm = ui.formatter(b'identify', opts)
3881 fm.startitem()
3879 fm.startitem()
3882
3880
3883 if not repo:
3881 if not repo:
3884 if num or branch or tags:
3882 if num or branch or tags:
3885 raise error.Abort(
3883 raise error.Abort(
3886 _(b"can't query remote revision number, branch, or tags")
3884 _(b"can't query remote revision number, branch, or tags")
3887 )
3885 )
3888 if not rev and revs:
3886 if not rev and revs:
3889 rev = revs[0]
3887 rev = revs[0]
3890 if not rev:
3888 if not rev:
3891 rev = b"tip"
3889 rev = b"tip"
3892
3890
3893 remoterev = peer.lookup(rev)
3891 remoterev = peer.lookup(rev)
3894 hexrev = fm.hexfunc(remoterev)
3892 hexrev = fm.hexfunc(remoterev)
3895 if default or id:
3893 if default or id:
3896 output = [hexrev]
3894 output = [hexrev]
3897 fm.data(id=hexrev)
3895 fm.data(id=hexrev)
3898
3896
3899 @util.cachefunc
3897 @util.cachefunc
3900 def getbms():
3898 def getbms():
3901 bms = []
3899 bms = []
3902
3900
3903 if b'bookmarks' in peer.listkeys(b'namespaces'):
3901 if b'bookmarks' in peer.listkeys(b'namespaces'):
3904 hexremoterev = hex(remoterev)
3902 hexremoterev = hex(remoterev)
3905 bms = [
3903 bms = [
3906 bm
3904 bm
3907 for bm, bmr in pycompat.iteritems(
3905 for bm, bmr in pycompat.iteritems(
3908 peer.listkeys(b'bookmarks')
3906 peer.listkeys(b'bookmarks')
3909 )
3907 )
3910 if bmr == hexremoterev
3908 if bmr == hexremoterev
3911 ]
3909 ]
3912
3910
3913 return sorted(bms)
3911 return sorted(bms)
3914
3912
3915 if fm.isplain():
3913 if fm.isplain():
3916 if bookmarks:
3914 if bookmarks:
3917 output.extend(getbms())
3915 output.extend(getbms())
3918 elif default and not ui.quiet:
3916 elif default and not ui.quiet:
3919 # multiple bookmarks for a single parent separated by '/'
3917 # multiple bookmarks for a single parent separated by '/'
3920 bm = b'/'.join(getbms())
3918 bm = b'/'.join(getbms())
3921 if bm:
3919 if bm:
3922 output.append(bm)
3920 output.append(bm)
3923 else:
3921 else:
3924 fm.data(node=hex(remoterev))
3922 fm.data(node=hex(remoterev))
3925 if bookmarks or b'bookmarks' in fm.datahint():
3923 if bookmarks or b'bookmarks' in fm.datahint():
3926 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3924 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3927 else:
3925 else:
3928 if rev:
3926 if rev:
3929 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3927 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3930 ctx = scmutil.revsingle(repo, rev, None)
3928 ctx = scmutil.revsingle(repo, rev, None)
3931
3929
3932 if ctx.rev() is None:
3930 if ctx.rev() is None:
3933 ctx = repo[None]
3931 ctx = repo[None]
3934 parents = ctx.parents()
3932 parents = ctx.parents()
3935 taglist = []
3933 taglist = []
3936 for p in parents:
3934 for p in parents:
3937 taglist.extend(p.tags())
3935 taglist.extend(p.tags())
3938
3936
3939 dirty = b""
3937 dirty = b""
3940 if ctx.dirty(missing=True, merge=False, branch=False):
3938 if ctx.dirty(missing=True, merge=False, branch=False):
3941 dirty = b'+'
3939 dirty = b'+'
3942 fm.data(dirty=dirty)
3940 fm.data(dirty=dirty)
3943
3941
3944 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3942 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3945 if default or id:
3943 if default or id:
3946 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3944 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3947 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3945 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3948
3946
3949 if num:
3947 if num:
3950 numoutput = [b"%d" % p.rev() for p in parents]
3948 numoutput = [b"%d" % p.rev() for p in parents]
3951 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3949 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3952
3950
3953 fm.data(
3951 fm.data(
3954 parents=fm.formatlist(
3952 parents=fm.formatlist(
3955 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3953 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3956 )
3954 )
3957 )
3955 )
3958 else:
3956 else:
3959 hexoutput = fm.hexfunc(ctx.node())
3957 hexoutput = fm.hexfunc(ctx.node())
3960 if default or id:
3958 if default or id:
3961 output = [hexoutput]
3959 output = [hexoutput]
3962 fm.data(id=hexoutput)
3960 fm.data(id=hexoutput)
3963
3961
3964 if num:
3962 if num:
3965 output.append(pycompat.bytestr(ctx.rev()))
3963 output.append(pycompat.bytestr(ctx.rev()))
3966 taglist = ctx.tags()
3964 taglist = ctx.tags()
3967
3965
3968 if default and not ui.quiet:
3966 if default and not ui.quiet:
3969 b = ctx.branch()
3967 b = ctx.branch()
3970 if b != b'default':
3968 if b != b'default':
3971 output.append(b"(%s)" % b)
3969 output.append(b"(%s)" % b)
3972
3970
3973 # multiple tags for a single parent separated by '/'
3971 # multiple tags for a single parent separated by '/'
3974 t = b'/'.join(taglist)
3972 t = b'/'.join(taglist)
3975 if t:
3973 if t:
3976 output.append(t)
3974 output.append(t)
3977
3975
3978 # multiple bookmarks for a single parent separated by '/'
3976 # multiple bookmarks for a single parent separated by '/'
3979 bm = b'/'.join(ctx.bookmarks())
3977 bm = b'/'.join(ctx.bookmarks())
3980 if bm:
3978 if bm:
3981 output.append(bm)
3979 output.append(bm)
3982 else:
3980 else:
3983 if branch:
3981 if branch:
3984 output.append(ctx.branch())
3982 output.append(ctx.branch())
3985
3983
3986 if tags:
3984 if tags:
3987 output.extend(taglist)
3985 output.extend(taglist)
3988
3986
3989 if bookmarks:
3987 if bookmarks:
3990 output.extend(ctx.bookmarks())
3988 output.extend(ctx.bookmarks())
3991
3989
3992 fm.data(node=ctx.hex())
3990 fm.data(node=ctx.hex())
3993 fm.data(branch=ctx.branch())
3991 fm.data(branch=ctx.branch())
3994 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3992 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3995 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3993 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3996 fm.context(ctx=ctx)
3994 fm.context(ctx=ctx)
3997
3995
3998 fm.plain(b"%s\n" % b' '.join(output))
3996 fm.plain(b"%s\n" % b' '.join(output))
3999 fm.end()
3997 fm.end()
4000
3998
4001
3999
4002 @command(
4000 @command(
4003 b'import|patch',
4001 b'import|patch',
4004 [
4002 [
4005 (
4003 (
4006 b'p',
4004 b'p',
4007 b'strip',
4005 b'strip',
4008 1,
4006 1,
4009 _(
4007 _(
4010 b'directory strip option for patch. This has the same '
4008 b'directory strip option for patch. This has the same '
4011 b'meaning as the corresponding patch option'
4009 b'meaning as the corresponding patch option'
4012 ),
4010 ),
4013 _(b'NUM'),
4011 _(b'NUM'),
4014 ),
4012 ),
4015 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4013 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4016 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4014 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4017 (
4015 (
4018 b'f',
4016 b'f',
4019 b'force',
4017 b'force',
4020 None,
4018 None,
4021 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4019 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4022 ),
4020 ),
4023 (
4021 (
4024 b'',
4022 b'',
4025 b'no-commit',
4023 b'no-commit',
4026 None,
4024 None,
4027 _(b"don't commit, just update the working directory"),
4025 _(b"don't commit, just update the working directory"),
4028 ),
4026 ),
4029 (
4027 (
4030 b'',
4028 b'',
4031 b'bypass',
4029 b'bypass',
4032 None,
4030 None,
4033 _(b"apply patch without touching the working directory"),
4031 _(b"apply patch without touching the working directory"),
4034 ),
4032 ),
4035 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4033 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4036 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4034 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4037 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4035 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4038 (
4036 (
4039 b'',
4037 b'',
4040 b'import-branch',
4038 b'import-branch',
4041 None,
4039 None,
4042 _(b'use any branch information in patch (implied by --exact)'),
4040 _(b'use any branch information in patch (implied by --exact)'),
4043 ),
4041 ),
4044 ]
4042 ]
4045 + commitopts
4043 + commitopts
4046 + commitopts2
4044 + commitopts2
4047 + similarityopts,
4045 + similarityopts,
4048 _(b'[OPTION]... PATCH...'),
4046 _(b'[OPTION]... PATCH...'),
4049 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4047 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4050 )
4048 )
4051 def import_(ui, repo, patch1=None, *patches, **opts):
4049 def import_(ui, repo, patch1=None, *patches, **opts):
4052 """import an ordered set of patches
4050 """import an ordered set of patches
4053
4051
4054 Import a list of patches and commit them individually (unless
4052 Import a list of patches and commit them individually (unless
4055 --no-commit is specified).
4053 --no-commit is specified).
4056
4054
4057 To read a patch from standard input (stdin), use "-" as the patch
4055 To read a patch from standard input (stdin), use "-" as the patch
4058 name. If a URL is specified, the patch will be downloaded from
4056 name. If a URL is specified, the patch will be downloaded from
4059 there.
4057 there.
4060
4058
4061 Import first applies changes to the working directory (unless
4059 Import first applies changes to the working directory (unless
4062 --bypass is specified), import will abort if there are outstanding
4060 --bypass is specified), import will abort if there are outstanding
4063 changes.
4061 changes.
4064
4062
4065 Use --bypass to apply and commit patches directly to the
4063 Use --bypass to apply and commit patches directly to the
4066 repository, without affecting the working directory. Without
4064 repository, without affecting the working directory. Without
4067 --exact, patches will be applied on top of the working directory
4065 --exact, patches will be applied on top of the working directory
4068 parent revision.
4066 parent revision.
4069
4067
4070 You can import a patch straight from a mail message. Even patches
4068 You can import a patch straight from a mail message. Even patches
4071 as attachments work (to use the body part, it must have type
4069 as attachments work (to use the body part, it must have type
4072 text/plain or text/x-patch). From and Subject headers of email
4070 text/plain or text/x-patch). From and Subject headers of email
4073 message are used as default committer and commit message. All
4071 message are used as default committer and commit message. All
4074 text/plain body parts before first diff are added to the commit
4072 text/plain body parts before first diff are added to the commit
4075 message.
4073 message.
4076
4074
4077 If the imported patch was generated by :hg:`export`, user and
4075 If the imported patch was generated by :hg:`export`, user and
4078 description from patch override values from message headers and
4076 description from patch override values from message headers and
4079 body. Values given on command line with -m/--message and -u/--user
4077 body. Values given on command line with -m/--message and -u/--user
4080 override these.
4078 override these.
4081
4079
4082 If --exact is specified, import will set the working directory to
4080 If --exact is specified, import will set the working directory to
4083 the parent of each patch before applying it, and will abort if the
4081 the parent of each patch before applying it, and will abort if the
4084 resulting changeset has a different ID than the one recorded in
4082 resulting changeset has a different ID than the one recorded in
4085 the patch. This will guard against various ways that portable
4083 the patch. This will guard against various ways that portable
4086 patch formats and mail systems might fail to transfer Mercurial
4084 patch formats and mail systems might fail to transfer Mercurial
4087 data or metadata. See :hg:`bundle` for lossless transmission.
4085 data or metadata. See :hg:`bundle` for lossless transmission.
4088
4086
4089 Use --partial to ensure a changeset will be created from the patch
4087 Use --partial to ensure a changeset will be created from the patch
4090 even if some hunks fail to apply. Hunks that fail to apply will be
4088 even if some hunks fail to apply. Hunks that fail to apply will be
4091 written to a <target-file>.rej file. Conflicts can then be resolved
4089 written to a <target-file>.rej file. Conflicts can then be resolved
4092 by hand before :hg:`commit --amend` is run to update the created
4090 by hand before :hg:`commit --amend` is run to update the created
4093 changeset. This flag exists to let people import patches that
4091 changeset. This flag exists to let people import patches that
4094 partially apply without losing the associated metadata (author,
4092 partially apply without losing the associated metadata (author,
4095 date, description, ...).
4093 date, description, ...).
4096
4094
4097 .. note::
4095 .. note::
4098
4096
4099 When no hunks apply cleanly, :hg:`import --partial` will create
4097 When no hunks apply cleanly, :hg:`import --partial` will create
4100 an empty changeset, importing only the patch metadata.
4098 an empty changeset, importing only the patch metadata.
4101
4099
4102 With -s/--similarity, hg will attempt to discover renames and
4100 With -s/--similarity, hg will attempt to discover renames and
4103 copies in the patch in the same way as :hg:`addremove`.
4101 copies in the patch in the same way as :hg:`addremove`.
4104
4102
4105 It is possible to use external patch programs to perform the patch
4103 It is possible to use external patch programs to perform the patch
4106 by setting the ``ui.patch`` configuration option. For the default
4104 by setting the ``ui.patch`` configuration option. For the default
4107 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4105 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4108 See :hg:`help config` for more information about configuration
4106 See :hg:`help config` for more information about configuration
4109 files and how to use these options.
4107 files and how to use these options.
4110
4108
4111 See :hg:`help dates` for a list of formats valid for -d/--date.
4109 See :hg:`help dates` for a list of formats valid for -d/--date.
4112
4110
4113 .. container:: verbose
4111 .. container:: verbose
4114
4112
4115 Examples:
4113 Examples:
4116
4114
4117 - import a traditional patch from a website and detect renames::
4115 - import a traditional patch from a website and detect renames::
4118
4116
4119 hg import -s 80 http://example.com/bugfix.patch
4117 hg import -s 80 http://example.com/bugfix.patch
4120
4118
4121 - import a changeset from an hgweb server::
4119 - import a changeset from an hgweb server::
4122
4120
4123 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4121 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4124
4122
4125 - import all the patches in an Unix-style mbox::
4123 - import all the patches in an Unix-style mbox::
4126
4124
4127 hg import incoming-patches.mbox
4125 hg import incoming-patches.mbox
4128
4126
4129 - import patches from stdin::
4127 - import patches from stdin::
4130
4128
4131 hg import -
4129 hg import -
4132
4130
4133 - attempt to exactly restore an exported changeset (not always
4131 - attempt to exactly restore an exported changeset (not always
4134 possible)::
4132 possible)::
4135
4133
4136 hg import --exact proposed-fix.patch
4134 hg import --exact proposed-fix.patch
4137
4135
4138 - use an external tool to apply a patch which is too fuzzy for
4136 - use an external tool to apply a patch which is too fuzzy for
4139 the default internal tool.
4137 the default internal tool.
4140
4138
4141 hg import --config ui.patch="patch --merge" fuzzy.patch
4139 hg import --config ui.patch="patch --merge" fuzzy.patch
4142
4140
4143 - change the default fuzzing from 2 to a less strict 7
4141 - change the default fuzzing from 2 to a less strict 7
4144
4142
4145 hg import --config ui.fuzz=7 fuzz.patch
4143 hg import --config ui.fuzz=7 fuzz.patch
4146
4144
4147 Returns 0 on success, 1 on partial success (see --partial).
4145 Returns 0 on success, 1 on partial success (see --partial).
4148 """
4146 """
4149
4147
4150 opts = pycompat.byteskwargs(opts)
4148 opts = pycompat.byteskwargs(opts)
4151 if not patch1:
4149 if not patch1:
4152 raise error.Abort(_(b'need at least one patch to import'))
4150 raise error.Abort(_(b'need at least one patch to import'))
4153
4151
4154 patches = (patch1,) + patches
4152 patches = (patch1,) + patches
4155
4153
4156 date = opts.get(b'date')
4154 date = opts.get(b'date')
4157 if date:
4155 if date:
4158 opts[b'date'] = dateutil.parsedate(date)
4156 opts[b'date'] = dateutil.parsedate(date)
4159
4157
4160 exact = opts.get(b'exact')
4158 exact = opts.get(b'exact')
4161 update = not opts.get(b'bypass')
4159 update = not opts.get(b'bypass')
4162 if not update and opts.get(b'no_commit'):
4160 if not update and opts.get(b'no_commit'):
4163 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4161 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4164 try:
4162 try:
4165 sim = float(opts.get(b'similarity') or 0)
4163 sim = float(opts.get(b'similarity') or 0)
4166 except ValueError:
4164 except ValueError:
4167 raise error.Abort(_(b'similarity must be a number'))
4165 raise error.Abort(_(b'similarity must be a number'))
4168 if sim < 0 or sim > 100:
4166 if sim < 0 or sim > 100:
4169 raise error.Abort(_(b'similarity must be between 0 and 100'))
4167 raise error.Abort(_(b'similarity must be between 0 and 100'))
4170 if sim and not update:
4168 if sim and not update:
4171 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4169 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4172 if exact:
4170 if exact:
4173 if opts.get(b'edit'):
4171 if opts.get(b'edit'):
4174 raise error.Abort(_(b'cannot use --exact with --edit'))
4172 raise error.Abort(_(b'cannot use --exact with --edit'))
4175 if opts.get(b'prefix'):
4173 if opts.get(b'prefix'):
4176 raise error.Abort(_(b'cannot use --exact with --prefix'))
4174 raise error.Abort(_(b'cannot use --exact with --prefix'))
4177
4175
4178 base = opts[b"base"]
4176 base = opts[b"base"]
4179 msgs = []
4177 msgs = []
4180 ret = 0
4178 ret = 0
4181
4179
4182 with repo.wlock():
4180 with repo.wlock():
4183 if update:
4181 if update:
4184 cmdutil.checkunfinished(repo)
4182 cmdutil.checkunfinished(repo)
4185 if exact or not opts.get(b'force'):
4183 if exact or not opts.get(b'force'):
4186 cmdutil.bailifchanged(repo)
4184 cmdutil.bailifchanged(repo)
4187
4185
4188 if not opts.get(b'no_commit'):
4186 if not opts.get(b'no_commit'):
4189 lock = repo.lock
4187 lock = repo.lock
4190 tr = lambda: repo.transaction(b'import')
4188 tr = lambda: repo.transaction(b'import')
4191 dsguard = util.nullcontextmanager
4189 dsguard = util.nullcontextmanager
4192 else:
4190 else:
4193 lock = util.nullcontextmanager
4191 lock = util.nullcontextmanager
4194 tr = util.nullcontextmanager
4192 tr = util.nullcontextmanager
4195 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4193 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4196 with lock(), tr(), dsguard():
4194 with lock(), tr(), dsguard():
4197 parents = repo[None].parents()
4195 parents = repo[None].parents()
4198 for patchurl in patches:
4196 for patchurl in patches:
4199 if patchurl == b'-':
4197 if patchurl == b'-':
4200 ui.status(_(b'applying patch from stdin\n'))
4198 ui.status(_(b'applying patch from stdin\n'))
4201 patchfile = ui.fin
4199 patchfile = ui.fin
4202 patchurl = b'stdin' # for error message
4200 patchurl = b'stdin' # for error message
4203 else:
4201 else:
4204 patchurl = os.path.join(base, patchurl)
4202 patchurl = os.path.join(base, patchurl)
4205 ui.status(_(b'applying %s\n') % patchurl)
4203 ui.status(_(b'applying %s\n') % patchurl)
4206 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4204 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4207
4205
4208 haspatch = False
4206 haspatch = False
4209 for hunk in patch.split(patchfile):
4207 for hunk in patch.split(patchfile):
4210 with patch.extract(ui, hunk) as patchdata:
4208 with patch.extract(ui, hunk) as patchdata:
4211 msg, node, rej = cmdutil.tryimportone(
4209 msg, node, rej = cmdutil.tryimportone(
4212 ui, repo, patchdata, parents, opts, msgs, hg.clean
4210 ui, repo, patchdata, parents, opts, msgs, hg.clean
4213 )
4211 )
4214 if msg:
4212 if msg:
4215 haspatch = True
4213 haspatch = True
4216 ui.note(msg + b'\n')
4214 ui.note(msg + b'\n')
4217 if update or exact:
4215 if update or exact:
4218 parents = repo[None].parents()
4216 parents = repo[None].parents()
4219 else:
4217 else:
4220 parents = [repo[node]]
4218 parents = [repo[node]]
4221 if rej:
4219 if rej:
4222 ui.write_err(_(b"patch applied partially\n"))
4220 ui.write_err(_(b"patch applied partially\n"))
4223 ui.write_err(
4221 ui.write_err(
4224 _(
4222 _(
4225 b"(fix the .rej files and run "
4223 b"(fix the .rej files and run "
4226 b"`hg commit --amend`)\n"
4224 b"`hg commit --amend`)\n"
4227 )
4225 )
4228 )
4226 )
4229 ret = 1
4227 ret = 1
4230 break
4228 break
4231
4229
4232 if not haspatch:
4230 if not haspatch:
4233 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4231 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4234
4232
4235 if msgs:
4233 if msgs:
4236 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4234 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4237 return ret
4235 return ret
4238
4236
4239
4237
4240 @command(
4238 @command(
4241 b'incoming|in',
4239 b'incoming|in',
4242 [
4240 [
4243 (
4241 (
4244 b'f',
4242 b'f',
4245 b'force',
4243 b'force',
4246 None,
4244 None,
4247 _(b'run even if remote repository is unrelated'),
4245 _(b'run even if remote repository is unrelated'),
4248 ),
4246 ),
4249 (b'n', b'newest-first', None, _(b'show newest record first')),
4247 (b'n', b'newest-first', None, _(b'show newest record first')),
4250 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4248 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4251 (
4249 (
4252 b'r',
4250 b'r',
4253 b'rev',
4251 b'rev',
4254 [],
4252 [],
4255 _(b'a remote changeset intended to be added'),
4253 _(b'a remote changeset intended to be added'),
4256 _(b'REV'),
4254 _(b'REV'),
4257 ),
4255 ),
4258 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4256 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4259 (
4257 (
4260 b'b',
4258 b'b',
4261 b'branch',
4259 b'branch',
4262 [],
4260 [],
4263 _(b'a specific branch you would like to pull'),
4261 _(b'a specific branch you would like to pull'),
4264 _(b'BRANCH'),
4262 _(b'BRANCH'),
4265 ),
4263 ),
4266 ]
4264 ]
4267 + logopts
4265 + logopts
4268 + remoteopts
4266 + remoteopts
4269 + subrepoopts,
4267 + subrepoopts,
4270 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4268 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4271 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4269 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4272 )
4270 )
4273 def incoming(ui, repo, source=b"default", **opts):
4271 def incoming(ui, repo, source=b"default", **opts):
4274 """show new changesets found in source
4272 """show new changesets found in source
4275
4273
4276 Show new changesets found in the specified path/URL or the default
4274 Show new changesets found in the specified path/URL or the default
4277 pull location. These are the changesets that would have been pulled
4275 pull location. These are the changesets that would have been pulled
4278 by :hg:`pull` at the time you issued this command.
4276 by :hg:`pull` at the time you issued this command.
4279
4277
4280 See pull for valid source format details.
4278 See pull for valid source format details.
4281
4279
4282 .. container:: verbose
4280 .. container:: verbose
4283
4281
4284 With -B/--bookmarks, the result of bookmark comparison between
4282 With -B/--bookmarks, the result of bookmark comparison between
4285 local and remote repositories is displayed. With -v/--verbose,
4283 local and remote repositories is displayed. With -v/--verbose,
4286 status is also displayed for each bookmark like below::
4284 status is also displayed for each bookmark like below::
4287
4285
4288 BM1 01234567890a added
4286 BM1 01234567890a added
4289 BM2 1234567890ab advanced
4287 BM2 1234567890ab advanced
4290 BM3 234567890abc diverged
4288 BM3 234567890abc diverged
4291 BM4 34567890abcd changed
4289 BM4 34567890abcd changed
4292
4290
4293 The action taken locally when pulling depends on the
4291 The action taken locally when pulling depends on the
4294 status of each bookmark:
4292 status of each bookmark:
4295
4293
4296 :``added``: pull will create it
4294 :``added``: pull will create it
4297 :``advanced``: pull will update it
4295 :``advanced``: pull will update it
4298 :``diverged``: pull will create a divergent bookmark
4296 :``diverged``: pull will create a divergent bookmark
4299 :``changed``: result depends on remote changesets
4297 :``changed``: result depends on remote changesets
4300
4298
4301 From the point of view of pulling behavior, bookmark
4299 From the point of view of pulling behavior, bookmark
4302 existing only in the remote repository are treated as ``added``,
4300 existing only in the remote repository are treated as ``added``,
4303 even if it is in fact locally deleted.
4301 even if it is in fact locally deleted.
4304
4302
4305 .. container:: verbose
4303 .. container:: verbose
4306
4304
4307 For remote repository, using --bundle avoids downloading the
4305 For remote repository, using --bundle avoids downloading the
4308 changesets twice if the incoming is followed by a pull.
4306 changesets twice if the incoming is followed by a pull.
4309
4307
4310 Examples:
4308 Examples:
4311
4309
4312 - show incoming changes with patches and full description::
4310 - show incoming changes with patches and full description::
4313
4311
4314 hg incoming -vp
4312 hg incoming -vp
4315
4313
4316 - show incoming changes excluding merges, store a bundle::
4314 - show incoming changes excluding merges, store a bundle::
4317
4315
4318 hg in -vpM --bundle incoming.hg
4316 hg in -vpM --bundle incoming.hg
4319 hg pull incoming.hg
4317 hg pull incoming.hg
4320
4318
4321 - briefly list changes inside a bundle::
4319 - briefly list changes inside a bundle::
4322
4320
4323 hg in changes.hg -T "{desc|firstline}\\n"
4321 hg in changes.hg -T "{desc|firstline}\\n"
4324
4322
4325 Returns 0 if there are incoming changes, 1 otherwise.
4323 Returns 0 if there are incoming changes, 1 otherwise.
4326 """
4324 """
4327 opts = pycompat.byteskwargs(opts)
4325 opts = pycompat.byteskwargs(opts)
4328 if opts.get(b'graph'):
4326 if opts.get(b'graph'):
4329 logcmdutil.checkunsupportedgraphflags([], opts)
4327 logcmdutil.checkunsupportedgraphflags([], opts)
4330
4328
4331 def display(other, chlist, displayer):
4329 def display(other, chlist, displayer):
4332 revdag = logcmdutil.graphrevs(other, chlist, opts)
4330 revdag = logcmdutil.graphrevs(other, chlist, opts)
4333 logcmdutil.displaygraph(
4331 logcmdutil.displaygraph(
4334 ui, repo, revdag, displayer, graphmod.asciiedges
4332 ui, repo, revdag, displayer, graphmod.asciiedges
4335 )
4333 )
4336
4334
4337 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4335 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4338 return 0
4336 return 0
4339
4337
4340 if opts.get(b'bundle') and opts.get(b'subrepos'):
4338 if opts.get(b'bundle') and opts.get(b'subrepos'):
4341 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4339 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4342
4340
4343 if opts.get(b'bookmarks'):
4341 if opts.get(b'bookmarks'):
4344 source, branches = hg.parseurl(
4342 source, branches = hg.parseurl(
4345 ui.expandpath(source), opts.get(b'branch')
4343 ui.expandpath(source), opts.get(b'branch')
4346 )
4344 )
4347 other = hg.peer(repo, opts, source)
4345 other = hg.peer(repo, opts, source)
4348 if b'bookmarks' not in other.listkeys(b'namespaces'):
4346 if b'bookmarks' not in other.listkeys(b'namespaces'):
4349 ui.warn(_(b"remote doesn't support bookmarks\n"))
4347 ui.warn(_(b"remote doesn't support bookmarks\n"))
4350 return 0
4348 return 0
4351 ui.pager(b'incoming')
4349 ui.pager(b'incoming')
4352 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4350 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4353 return bookmarks.incoming(ui, repo, other)
4351 return bookmarks.incoming(ui, repo, other)
4354
4352
4355 repo._subtoppath = ui.expandpath(source)
4353 repo._subtoppath = ui.expandpath(source)
4356 try:
4354 try:
4357 return hg.incoming(ui, repo, source, opts)
4355 return hg.incoming(ui, repo, source, opts)
4358 finally:
4356 finally:
4359 del repo._subtoppath
4357 del repo._subtoppath
4360
4358
4361
4359
4362 @command(
4360 @command(
4363 b'init',
4361 b'init',
4364 remoteopts,
4362 remoteopts,
4365 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4363 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4366 helpcategory=command.CATEGORY_REPO_CREATION,
4364 helpcategory=command.CATEGORY_REPO_CREATION,
4367 helpbasic=True,
4365 helpbasic=True,
4368 norepo=True,
4366 norepo=True,
4369 )
4367 )
4370 def init(ui, dest=b".", **opts):
4368 def init(ui, dest=b".", **opts):
4371 """create a new repository in the given directory
4369 """create a new repository in the given directory
4372
4370
4373 Initialize a new repository in the given directory. If the given
4371 Initialize a new repository in the given directory. If the given
4374 directory does not exist, it will be created.
4372 directory does not exist, it will be created.
4375
4373
4376 If no directory is given, the current directory is used.
4374 If no directory is given, the current directory is used.
4377
4375
4378 It is possible to specify an ``ssh://`` URL as the destination.
4376 It is possible to specify an ``ssh://`` URL as the destination.
4379 See :hg:`help urls` for more information.
4377 See :hg:`help urls` for more information.
4380
4378
4381 Returns 0 on success.
4379 Returns 0 on success.
4382 """
4380 """
4383 opts = pycompat.byteskwargs(opts)
4381 opts = pycompat.byteskwargs(opts)
4384 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4382 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4385
4383
4386
4384
4387 @command(
4385 @command(
4388 b'locate',
4386 b'locate',
4389 [
4387 [
4390 (
4388 (
4391 b'r',
4389 b'r',
4392 b'rev',
4390 b'rev',
4393 b'',
4391 b'',
4394 _(b'search the repository as it is in REV'),
4392 _(b'search the repository as it is in REV'),
4395 _(b'REV'),
4393 _(b'REV'),
4396 ),
4394 ),
4397 (
4395 (
4398 b'0',
4396 b'0',
4399 b'print0',
4397 b'print0',
4400 None,
4398 None,
4401 _(b'end filenames with NUL, for use with xargs'),
4399 _(b'end filenames with NUL, for use with xargs'),
4402 ),
4400 ),
4403 (
4401 (
4404 b'f',
4402 b'f',
4405 b'fullpath',
4403 b'fullpath',
4406 None,
4404 None,
4407 _(b'print complete paths from the filesystem root'),
4405 _(b'print complete paths from the filesystem root'),
4408 ),
4406 ),
4409 ]
4407 ]
4410 + walkopts,
4408 + walkopts,
4411 _(b'[OPTION]... [PATTERN]...'),
4409 _(b'[OPTION]... [PATTERN]...'),
4412 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4410 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4413 )
4411 )
4414 def locate(ui, repo, *pats, **opts):
4412 def locate(ui, repo, *pats, **opts):
4415 """locate files matching specific patterns (DEPRECATED)
4413 """locate files matching specific patterns (DEPRECATED)
4416
4414
4417 Print files under Mercurial control in the working directory whose
4415 Print files under Mercurial control in the working directory whose
4418 names match the given patterns.
4416 names match the given patterns.
4419
4417
4420 By default, this command searches all directories in the working
4418 By default, this command searches all directories in the working
4421 directory. To search just the current directory and its
4419 directory. To search just the current directory and its
4422 subdirectories, use "--include .".
4420 subdirectories, use "--include .".
4423
4421
4424 If no patterns are given to match, this command prints the names
4422 If no patterns are given to match, this command prints the names
4425 of all files under Mercurial control in the working directory.
4423 of all files under Mercurial control in the working directory.
4426
4424
4427 If you want to feed the output of this command into the "xargs"
4425 If you want to feed the output of this command into the "xargs"
4428 command, use the -0 option to both this command and "xargs". This
4426 command, use the -0 option to both this command and "xargs". This
4429 will avoid the problem of "xargs" treating single filenames that
4427 will avoid the problem of "xargs" treating single filenames that
4430 contain whitespace as multiple filenames.
4428 contain whitespace as multiple filenames.
4431
4429
4432 See :hg:`help files` for a more versatile command.
4430 See :hg:`help files` for a more versatile command.
4433
4431
4434 Returns 0 if a match is found, 1 otherwise.
4432 Returns 0 if a match is found, 1 otherwise.
4435 """
4433 """
4436 opts = pycompat.byteskwargs(opts)
4434 opts = pycompat.byteskwargs(opts)
4437 if opts.get(b'print0'):
4435 if opts.get(b'print0'):
4438 end = b'\0'
4436 end = b'\0'
4439 else:
4437 else:
4440 end = b'\n'
4438 end = b'\n'
4441 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4439 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4442
4440
4443 ret = 1
4441 ret = 1
4444 m = scmutil.match(
4442 m = scmutil.match(
4445 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4443 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4446 )
4444 )
4447
4445
4448 ui.pager(b'locate')
4446 ui.pager(b'locate')
4449 if ctx.rev() is None:
4447 if ctx.rev() is None:
4450 # When run on the working copy, "locate" includes removed files, so
4448 # When run on the working copy, "locate" includes removed files, so
4451 # we get the list of files from the dirstate.
4449 # we get the list of files from the dirstate.
4452 filesgen = sorted(repo.dirstate.matches(m))
4450 filesgen = sorted(repo.dirstate.matches(m))
4453 else:
4451 else:
4454 filesgen = ctx.matches(m)
4452 filesgen = ctx.matches(m)
4455 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4453 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4456 for abs in filesgen:
4454 for abs in filesgen:
4457 if opts.get(b'fullpath'):
4455 if opts.get(b'fullpath'):
4458 ui.write(repo.wjoin(abs), end)
4456 ui.write(repo.wjoin(abs), end)
4459 else:
4457 else:
4460 ui.write(uipathfn(abs), end)
4458 ui.write(uipathfn(abs), end)
4461 ret = 0
4459 ret = 0
4462
4460
4463 return ret
4461 return ret
4464
4462
4465
4463
4466 @command(
4464 @command(
4467 b'log|history',
4465 b'log|history',
4468 [
4466 [
4469 (
4467 (
4470 b'f',
4468 b'f',
4471 b'follow',
4469 b'follow',
4472 None,
4470 None,
4473 _(
4471 _(
4474 b'follow changeset history, or file history across copies and renames'
4472 b'follow changeset history, or file history across copies and renames'
4475 ),
4473 ),
4476 ),
4474 ),
4477 (
4475 (
4478 b'',
4476 b'',
4479 b'follow-first',
4477 b'follow-first',
4480 None,
4478 None,
4481 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4479 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4482 ),
4480 ),
4483 (
4481 (
4484 b'd',
4482 b'd',
4485 b'date',
4483 b'date',
4486 b'',
4484 b'',
4487 _(b'show revisions matching date spec'),
4485 _(b'show revisions matching date spec'),
4488 _(b'DATE'),
4486 _(b'DATE'),
4489 ),
4487 ),
4490 (b'C', b'copies', None, _(b'show copied files')),
4488 (b'C', b'copies', None, _(b'show copied files')),
4491 (
4489 (
4492 b'k',
4490 b'k',
4493 b'keyword',
4491 b'keyword',
4494 [],
4492 [],
4495 _(b'do case-insensitive search for a given text'),
4493 _(b'do case-insensitive search for a given text'),
4496 _(b'TEXT'),
4494 _(b'TEXT'),
4497 ),
4495 ),
4498 (
4496 (
4499 b'r',
4497 b'r',
4500 b'rev',
4498 b'rev',
4501 [],
4499 [],
4502 _(b'show the specified revision or revset'),
4500 _(b'show the specified revision or revset'),
4503 _(b'REV'),
4501 _(b'REV'),
4504 ),
4502 ),
4505 (
4503 (
4506 b'L',
4504 b'L',
4507 b'line-range',
4505 b'line-range',
4508 [],
4506 [],
4509 _(b'follow line range of specified file (EXPERIMENTAL)'),
4507 _(b'follow line range of specified file (EXPERIMENTAL)'),
4510 _(b'FILE,RANGE'),
4508 _(b'FILE,RANGE'),
4511 ),
4509 ),
4512 (
4510 (
4513 b'',
4511 b'',
4514 b'removed',
4512 b'removed',
4515 None,
4513 None,
4516 _(b'include revisions where files were removed'),
4514 _(b'include revisions where files were removed'),
4517 ),
4515 ),
4518 (
4516 (
4519 b'm',
4517 b'm',
4520 b'only-merges',
4518 b'only-merges',
4521 None,
4519 None,
4522 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4520 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4523 ),
4521 ),
4524 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4522 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4525 (
4523 (
4526 b'',
4524 b'',
4527 b'only-branch',
4525 b'only-branch',
4528 [],
4526 [],
4529 _(
4527 _(
4530 b'show only changesets within the given named branch (DEPRECATED)'
4528 b'show only changesets within the given named branch (DEPRECATED)'
4531 ),
4529 ),
4532 _(b'BRANCH'),
4530 _(b'BRANCH'),
4533 ),
4531 ),
4534 (
4532 (
4535 b'b',
4533 b'b',
4536 b'branch',
4534 b'branch',
4537 [],
4535 [],
4538 _(b'show changesets within the given named branch'),
4536 _(b'show changesets within the given named branch'),
4539 _(b'BRANCH'),
4537 _(b'BRANCH'),
4540 ),
4538 ),
4541 (
4539 (
4542 b'P',
4540 b'P',
4543 b'prune',
4541 b'prune',
4544 [],
4542 [],
4545 _(b'do not display revision or any of its ancestors'),
4543 _(b'do not display revision or any of its ancestors'),
4546 _(b'REV'),
4544 _(b'REV'),
4547 ),
4545 ),
4548 ]
4546 ]
4549 + logopts
4547 + logopts
4550 + walkopts,
4548 + walkopts,
4551 _(b'[OPTION]... [FILE]'),
4549 _(b'[OPTION]... [FILE]'),
4552 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4550 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4553 helpbasic=True,
4551 helpbasic=True,
4554 inferrepo=True,
4552 inferrepo=True,
4555 intents={INTENT_READONLY},
4553 intents={INTENT_READONLY},
4556 )
4554 )
4557 def log(ui, repo, *pats, **opts):
4555 def log(ui, repo, *pats, **opts):
4558 """show revision history of entire repository or files
4556 """show revision history of entire repository or files
4559
4557
4560 Print the revision history of the specified files or the entire
4558 Print the revision history of the specified files or the entire
4561 project.
4559 project.
4562
4560
4563 If no revision range is specified, the default is ``tip:0`` unless
4561 If no revision range is specified, the default is ``tip:0`` unless
4564 --follow is set, in which case the working directory parent is
4562 --follow is set, in which case the working directory parent is
4565 used as the starting revision.
4563 used as the starting revision.
4566
4564
4567 File history is shown without following rename or copy history of
4565 File history is shown without following rename or copy history of
4568 files. Use -f/--follow with a filename to follow history across
4566 files. Use -f/--follow with a filename to follow history across
4569 renames and copies. --follow without a filename will only show
4567 renames and copies. --follow without a filename will only show
4570 ancestors of the starting revision.
4568 ancestors of the starting revision.
4571
4569
4572 By default this command prints revision number and changeset id,
4570 By default this command prints revision number and changeset id,
4573 tags, non-trivial parents, user, date and time, and a summary for
4571 tags, non-trivial parents, user, date and time, and a summary for
4574 each commit. When the -v/--verbose switch is used, the list of
4572 each commit. When the -v/--verbose switch is used, the list of
4575 changed files and full commit message are shown.
4573 changed files and full commit message are shown.
4576
4574
4577 With --graph the revisions are shown as an ASCII art DAG with the most
4575 With --graph the revisions are shown as an ASCII art DAG with the most
4578 recent changeset at the top.
4576 recent changeset at the top.
4579 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4577 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4580 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4578 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4581 changeset from the lines below is a parent of the 'o' merge on the same
4579 changeset from the lines below is a parent of the 'o' merge on the same
4582 line.
4580 line.
4583 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4581 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4584 of a '|' indicates one or more revisions in a path are omitted.
4582 of a '|' indicates one or more revisions in a path are omitted.
4585
4583
4586 .. container:: verbose
4584 .. container:: verbose
4587
4585
4588 Use -L/--line-range FILE,M:N options to follow the history of lines
4586 Use -L/--line-range FILE,M:N options to follow the history of lines
4589 from M to N in FILE. With -p/--patch only diff hunks affecting
4587 from M to N in FILE. With -p/--patch only diff hunks affecting
4590 specified line range will be shown. This option requires --follow;
4588 specified line range will be shown. This option requires --follow;
4591 it can be specified multiple times. Currently, this option is not
4589 it can be specified multiple times. Currently, this option is not
4592 compatible with --graph. This option is experimental.
4590 compatible with --graph. This option is experimental.
4593
4591
4594 .. note::
4592 .. note::
4595
4593
4596 :hg:`log --patch` may generate unexpected diff output for merge
4594 :hg:`log --patch` may generate unexpected diff output for merge
4597 changesets, as it will only compare the merge changeset against
4595 changesets, as it will only compare the merge changeset against
4598 its first parent. Also, only files different from BOTH parents
4596 its first parent. Also, only files different from BOTH parents
4599 will appear in files:.
4597 will appear in files:.
4600
4598
4601 .. note::
4599 .. note::
4602
4600
4603 For performance reasons, :hg:`log FILE` may omit duplicate changes
4601 For performance reasons, :hg:`log FILE` may omit duplicate changes
4604 made on branches and will not show removals or mode changes. To
4602 made on branches and will not show removals or mode changes. To
4605 see all such changes, use the --removed switch.
4603 see all such changes, use the --removed switch.
4606
4604
4607 .. container:: verbose
4605 .. container:: verbose
4608
4606
4609 .. note::
4607 .. note::
4610
4608
4611 The history resulting from -L/--line-range options depends on diff
4609 The history resulting from -L/--line-range options depends on diff
4612 options; for instance if white-spaces are ignored, respective changes
4610 options; for instance if white-spaces are ignored, respective changes
4613 with only white-spaces in specified line range will not be listed.
4611 with only white-spaces in specified line range will not be listed.
4614
4612
4615 .. container:: verbose
4613 .. container:: verbose
4616
4614
4617 Some examples:
4615 Some examples:
4618
4616
4619 - changesets with full descriptions and file lists::
4617 - changesets with full descriptions and file lists::
4620
4618
4621 hg log -v
4619 hg log -v
4622
4620
4623 - changesets ancestral to the working directory::
4621 - changesets ancestral to the working directory::
4624
4622
4625 hg log -f
4623 hg log -f
4626
4624
4627 - last 10 commits on the current branch::
4625 - last 10 commits on the current branch::
4628
4626
4629 hg log -l 10 -b .
4627 hg log -l 10 -b .
4630
4628
4631 - changesets showing all modifications of a file, including removals::
4629 - changesets showing all modifications of a file, including removals::
4632
4630
4633 hg log --removed file.c
4631 hg log --removed file.c
4634
4632
4635 - all changesets that touch a directory, with diffs, excluding merges::
4633 - all changesets that touch a directory, with diffs, excluding merges::
4636
4634
4637 hg log -Mp lib/
4635 hg log -Mp lib/
4638
4636
4639 - all revision numbers that match a keyword::
4637 - all revision numbers that match a keyword::
4640
4638
4641 hg log -k bug --template "{rev}\\n"
4639 hg log -k bug --template "{rev}\\n"
4642
4640
4643 - the full hash identifier of the working directory parent::
4641 - the full hash identifier of the working directory parent::
4644
4642
4645 hg log -r . --template "{node}\\n"
4643 hg log -r . --template "{node}\\n"
4646
4644
4647 - list available log templates::
4645 - list available log templates::
4648
4646
4649 hg log -T list
4647 hg log -T list
4650
4648
4651 - check if a given changeset is included in a tagged release::
4649 - check if a given changeset is included in a tagged release::
4652
4650
4653 hg log -r "a21ccf and ancestor(1.9)"
4651 hg log -r "a21ccf and ancestor(1.9)"
4654
4652
4655 - find all changesets by some user in a date range::
4653 - find all changesets by some user in a date range::
4656
4654
4657 hg log -k alice -d "may 2008 to jul 2008"
4655 hg log -k alice -d "may 2008 to jul 2008"
4658
4656
4659 - summary of all changesets after the last tag::
4657 - summary of all changesets after the last tag::
4660
4658
4661 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4659 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4662
4660
4663 - changesets touching lines 13 to 23 for file.c::
4661 - changesets touching lines 13 to 23 for file.c::
4664
4662
4665 hg log -L file.c,13:23
4663 hg log -L file.c,13:23
4666
4664
4667 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4665 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4668 main.c with patch::
4666 main.c with patch::
4669
4667
4670 hg log -L file.c,13:23 -L main.c,2:6 -p
4668 hg log -L file.c,13:23 -L main.c,2:6 -p
4671
4669
4672 See :hg:`help dates` for a list of formats valid for -d/--date.
4670 See :hg:`help dates` for a list of formats valid for -d/--date.
4673
4671
4674 See :hg:`help revisions` for more about specifying and ordering
4672 See :hg:`help revisions` for more about specifying and ordering
4675 revisions.
4673 revisions.
4676
4674
4677 See :hg:`help templates` for more about pre-packaged styles and
4675 See :hg:`help templates` for more about pre-packaged styles and
4678 specifying custom templates. The default template used by the log
4676 specifying custom templates. The default template used by the log
4679 command can be customized via the ``ui.logtemplate`` configuration
4677 command can be customized via the ``ui.logtemplate`` configuration
4680 setting.
4678 setting.
4681
4679
4682 Returns 0 on success.
4680 Returns 0 on success.
4683
4681
4684 """
4682 """
4685 opts = pycompat.byteskwargs(opts)
4683 opts = pycompat.byteskwargs(opts)
4686 linerange = opts.get(b'line_range')
4684 linerange = opts.get(b'line_range')
4687
4685
4688 if linerange and not opts.get(b'follow'):
4686 if linerange and not opts.get(b'follow'):
4689 raise error.Abort(_(b'--line-range requires --follow'))
4687 raise error.Abort(_(b'--line-range requires --follow'))
4690
4688
4691 if linerange and pats:
4689 if linerange and pats:
4692 # TODO: take pats as patterns with no line-range filter
4690 # TODO: take pats as patterns with no line-range filter
4693 raise error.Abort(
4691 raise error.Abort(
4694 _(b'FILE arguments are not compatible with --line-range option')
4692 _(b'FILE arguments are not compatible with --line-range option')
4695 )
4693 )
4696
4694
4697 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4695 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4698 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4696 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4699 if linerange:
4697 if linerange:
4700 # TODO: should follow file history from logcmdutil._initialrevs(),
4698 # TODO: should follow file history from logcmdutil._initialrevs(),
4701 # then filter the result by logcmdutil._makerevset() and --limit
4699 # then filter the result by logcmdutil._makerevset() and --limit
4702 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4700 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4703
4701
4704 getcopies = None
4702 getcopies = None
4705 if opts.get(b'copies'):
4703 if opts.get(b'copies'):
4706 endrev = None
4704 endrev = None
4707 if revs:
4705 if revs:
4708 endrev = revs.max() + 1
4706 endrev = revs.max() + 1
4709 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4707 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4710
4708
4711 ui.pager(b'log')
4709 ui.pager(b'log')
4712 displayer = logcmdutil.changesetdisplayer(
4710 displayer = logcmdutil.changesetdisplayer(
4713 ui, repo, opts, differ, buffered=True
4711 ui, repo, opts, differ, buffered=True
4714 )
4712 )
4715 if opts.get(b'graph'):
4713 if opts.get(b'graph'):
4716 displayfn = logcmdutil.displaygraphrevs
4714 displayfn = logcmdutil.displaygraphrevs
4717 else:
4715 else:
4718 displayfn = logcmdutil.displayrevs
4716 displayfn = logcmdutil.displayrevs
4719 displayfn(ui, repo, revs, displayer, getcopies)
4717 displayfn(ui, repo, revs, displayer, getcopies)
4720
4718
4721
4719
4722 @command(
4720 @command(
4723 b'manifest',
4721 b'manifest',
4724 [
4722 [
4725 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4723 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4726 (b'', b'all', False, _(b"list files from all revisions")),
4724 (b'', b'all', False, _(b"list files from all revisions")),
4727 ]
4725 ]
4728 + formatteropts,
4726 + formatteropts,
4729 _(b'[-r REV]'),
4727 _(b'[-r REV]'),
4730 helpcategory=command.CATEGORY_MAINTENANCE,
4728 helpcategory=command.CATEGORY_MAINTENANCE,
4731 intents={INTENT_READONLY},
4729 intents={INTENT_READONLY},
4732 )
4730 )
4733 def manifest(ui, repo, node=None, rev=None, **opts):
4731 def manifest(ui, repo, node=None, rev=None, **opts):
4734 """output the current or given revision of the project manifest
4732 """output the current or given revision of the project manifest
4735
4733
4736 Print a list of version controlled files for the given revision.
4734 Print a list of version controlled files for the given revision.
4737 If no revision is given, the first parent of the working directory
4735 If no revision is given, the first parent of the working directory
4738 is used, or the null revision if no revision is checked out.
4736 is used, or the null revision if no revision is checked out.
4739
4737
4740 With -v, print file permissions, symlink and executable bits.
4738 With -v, print file permissions, symlink and executable bits.
4741 With --debug, print file revision hashes.
4739 With --debug, print file revision hashes.
4742
4740
4743 If option --all is specified, the list of all files from all revisions
4741 If option --all is specified, the list of all files from all revisions
4744 is printed. This includes deleted and renamed files.
4742 is printed. This includes deleted and renamed files.
4745
4743
4746 Returns 0 on success.
4744 Returns 0 on success.
4747 """
4745 """
4748 opts = pycompat.byteskwargs(opts)
4746 opts = pycompat.byteskwargs(opts)
4749 fm = ui.formatter(b'manifest', opts)
4747 fm = ui.formatter(b'manifest', opts)
4750
4748
4751 if opts.get(b'all'):
4749 if opts.get(b'all'):
4752 if rev or node:
4750 if rev or node:
4753 raise error.Abort(_(b"can't specify a revision with --all"))
4751 raise error.Abort(_(b"can't specify a revision with --all"))
4754
4752
4755 res = set()
4753 res = set()
4756 for rev in repo:
4754 for rev in repo:
4757 ctx = repo[rev]
4755 ctx = repo[rev]
4758 res |= set(ctx.files())
4756 res |= set(ctx.files())
4759
4757
4760 ui.pager(b'manifest')
4758 ui.pager(b'manifest')
4761 for f in sorted(res):
4759 for f in sorted(res):
4762 fm.startitem()
4760 fm.startitem()
4763 fm.write(b"path", b'%s\n', f)
4761 fm.write(b"path", b'%s\n', f)
4764 fm.end()
4762 fm.end()
4765 return
4763 return
4766
4764
4767 if rev and node:
4765 if rev and node:
4768 raise error.Abort(_(b"please specify just one revision"))
4766 raise error.Abort(_(b"please specify just one revision"))
4769
4767
4770 if not node:
4768 if not node:
4771 node = rev
4769 node = rev
4772
4770
4773 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4771 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4774 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4772 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4775 if node:
4773 if node:
4776 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4774 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4777 ctx = scmutil.revsingle(repo, node)
4775 ctx = scmutil.revsingle(repo, node)
4778 mf = ctx.manifest()
4776 mf = ctx.manifest()
4779 ui.pager(b'manifest')
4777 ui.pager(b'manifest')
4780 for f in ctx:
4778 for f in ctx:
4781 fm.startitem()
4779 fm.startitem()
4782 fm.context(ctx=ctx)
4780 fm.context(ctx=ctx)
4783 fl = ctx[f].flags()
4781 fl = ctx[f].flags()
4784 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4782 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4785 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4783 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4786 fm.write(b'path', b'%s\n', f)
4784 fm.write(b'path', b'%s\n', f)
4787 fm.end()
4785 fm.end()
4788
4786
4789
4787
4790 @command(
4788 @command(
4791 b'merge',
4789 b'merge',
4792 [
4790 [
4793 (
4791 (
4794 b'f',
4792 b'f',
4795 b'force',
4793 b'force',
4796 None,
4794 None,
4797 _(b'force a merge including outstanding changes (DEPRECATED)'),
4795 _(b'force a merge including outstanding changes (DEPRECATED)'),
4798 ),
4796 ),
4799 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4797 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4800 (
4798 (
4801 b'P',
4799 b'P',
4802 b'preview',
4800 b'preview',
4803 None,
4801 None,
4804 _(b'review revisions to merge (no merge is performed)'),
4802 _(b'review revisions to merge (no merge is performed)'),
4805 ),
4803 ),
4806 (b'', b'abort', None, _(b'abort the ongoing merge')),
4804 (b'', b'abort', None, _(b'abort the ongoing merge')),
4807 ]
4805 ]
4808 + mergetoolopts,
4806 + mergetoolopts,
4809 _(b'[-P] [[-r] REV]'),
4807 _(b'[-P] [[-r] REV]'),
4810 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4808 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4811 helpbasic=True,
4809 helpbasic=True,
4812 )
4810 )
4813 def merge(ui, repo, node=None, **opts):
4811 def merge(ui, repo, node=None, **opts):
4814 """merge another revision into working directory
4812 """merge another revision into working directory
4815
4813
4816 The current working directory is updated with all changes made in
4814 The current working directory is updated with all changes made in
4817 the requested revision since the last common predecessor revision.
4815 the requested revision since the last common predecessor revision.
4818
4816
4819 Files that changed between either parent are marked as changed for
4817 Files that changed between either parent are marked as changed for
4820 the next commit and a commit must be performed before any further
4818 the next commit and a commit must be performed before any further
4821 updates to the repository are allowed. The next commit will have
4819 updates to the repository are allowed. The next commit will have
4822 two parents.
4820 two parents.
4823
4821
4824 ``--tool`` can be used to specify the merge tool used for file
4822 ``--tool`` can be used to specify the merge tool used for file
4825 merges. It overrides the HGMERGE environment variable and your
4823 merges. It overrides the HGMERGE environment variable and your
4826 configuration files. See :hg:`help merge-tools` for options.
4824 configuration files. See :hg:`help merge-tools` for options.
4827
4825
4828 If no revision is specified, the working directory's parent is a
4826 If no revision is specified, the working directory's parent is a
4829 head revision, and the current branch contains exactly one other
4827 head revision, and the current branch contains exactly one other
4830 head, the other head is merged with by default. Otherwise, an
4828 head, the other head is merged with by default. Otherwise, an
4831 explicit revision with which to merge must be provided.
4829 explicit revision with which to merge must be provided.
4832
4830
4833 See :hg:`help resolve` for information on handling file conflicts.
4831 See :hg:`help resolve` for information on handling file conflicts.
4834
4832
4835 To undo an uncommitted merge, use :hg:`merge --abort` which
4833 To undo an uncommitted merge, use :hg:`merge --abort` which
4836 will check out a clean copy of the original merge parent, losing
4834 will check out a clean copy of the original merge parent, losing
4837 all changes.
4835 all changes.
4838
4836
4839 Returns 0 on success, 1 if there are unresolved files.
4837 Returns 0 on success, 1 if there are unresolved files.
4840 """
4838 """
4841
4839
4842 opts = pycompat.byteskwargs(opts)
4840 opts = pycompat.byteskwargs(opts)
4843 abort = opts.get(b'abort')
4841 abort = opts.get(b'abort')
4844 if abort and repo.dirstate.p2() == nullid:
4842 if abort and repo.dirstate.p2() == nullid:
4845 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4843 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4846 if abort:
4844 if abort:
4847 state = cmdutil.getunfinishedstate(repo)
4845 state = cmdutil.getunfinishedstate(repo)
4848 if state and state._opname != b'merge':
4846 if state and state._opname != b'merge':
4849 raise error.Abort(
4847 raise error.Abort(
4850 _(b'cannot abort merge with %s in progress') % (state._opname),
4848 _(b'cannot abort merge with %s in progress') % (state._opname),
4851 hint=state.hint(),
4849 hint=state.hint(),
4852 )
4850 )
4853 if node:
4851 if node:
4854 raise error.Abort(_(b"cannot specify a node with --abort"))
4852 raise error.Abort(_(b"cannot specify a node with --abort"))
4855 if opts.get(b'rev'):
4853 if opts.get(b'rev'):
4856 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4854 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4857 if opts.get(b'preview'):
4855 if opts.get(b'preview'):
4858 raise error.Abort(_(b"cannot specify --preview with --abort"))
4856 raise error.Abort(_(b"cannot specify --preview with --abort"))
4859 if opts.get(b'rev') and node:
4857 if opts.get(b'rev') and node:
4860 raise error.Abort(_(b"please specify just one revision"))
4858 raise error.Abort(_(b"please specify just one revision"))
4861 if not node:
4859 if not node:
4862 node = opts.get(b'rev')
4860 node = opts.get(b'rev')
4863
4861
4864 if node:
4862 if node:
4865 node = scmutil.revsingle(repo, node).node()
4863 node = scmutil.revsingle(repo, node).node()
4866
4864
4867 if not node and not abort:
4865 if not node and not abort:
4868 node = repo[destutil.destmerge(repo)].node()
4866 node = repo[destutil.destmerge(repo)].node()
4869
4867
4870 if opts.get(b'preview'):
4868 if opts.get(b'preview'):
4871 # find nodes that are ancestors of p2 but not of p1
4869 # find nodes that are ancestors of p2 but not of p1
4872 p1 = repo.lookup(b'.')
4870 p1 = repo.lookup(b'.')
4873 p2 = node
4871 p2 = node
4874 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4872 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4875
4873
4876 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4874 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4877 for node in nodes:
4875 for node in nodes:
4878 displayer.show(repo[node])
4876 displayer.show(repo[node])
4879 displayer.close()
4877 displayer.close()
4880 return 0
4878 return 0
4881
4879
4882 # ui.forcemerge is an internal variable, do not document
4880 # ui.forcemerge is an internal variable, do not document
4883 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4884 with ui.configoverride(overrides, b'merge'):
4882 with ui.configoverride(overrides, b'merge'):
4885 force = opts.get(b'force')
4883 force = opts.get(b'force')
4886 labels = [b'working copy', b'merge rev']
4884 labels = [b'working copy', b'merge rev']
4887 return hg.merge(
4885 return hg.merge(
4888 repo,
4886 repo,
4889 node,
4887 node,
4890 force=force,
4888 force=force,
4891 mergeforce=force,
4889 mergeforce=force,
4892 labels=labels,
4890 labels=labels,
4893 abort=abort,
4891 abort=abort,
4894 )
4892 )
4895
4893
4896
4894
4897 statemod.addunfinished(
4895 statemod.addunfinished(
4898 b'merge',
4896 b'merge',
4899 fname=None,
4897 fname=None,
4900 clearable=True,
4898 clearable=True,
4901 allowcommit=True,
4899 allowcommit=True,
4902 cmdmsg=_(b'outstanding uncommitted merge'),
4900 cmdmsg=_(b'outstanding uncommitted merge'),
4903 abortfunc=hg.abortmerge,
4901 abortfunc=hg.abortmerge,
4904 statushint=_(
4902 statushint=_(
4905 b'To continue: hg commit\nTo abort: hg merge --abort'
4903 b'To continue: hg commit\nTo abort: hg merge --abort'
4906 ),
4904 ),
4907 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4905 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4908 )
4906 )
4909
4907
4910
4908
4911 @command(
4909 @command(
4912 b'outgoing|out',
4910 b'outgoing|out',
4913 [
4911 [
4914 (
4912 (
4915 b'f',
4913 b'f',
4916 b'force',
4914 b'force',
4917 None,
4915 None,
4918 _(b'run even when the destination is unrelated'),
4916 _(b'run even when the destination is unrelated'),
4919 ),
4917 ),
4920 (
4918 (
4921 b'r',
4919 b'r',
4922 b'rev',
4920 b'rev',
4923 [],
4921 [],
4924 _(b'a changeset intended to be included in the destination'),
4922 _(b'a changeset intended to be included in the destination'),
4925 _(b'REV'),
4923 _(b'REV'),
4926 ),
4924 ),
4927 (b'n', b'newest-first', None, _(b'show newest record first')),
4925 (b'n', b'newest-first', None, _(b'show newest record first')),
4928 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4926 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4929 (
4927 (
4930 b'b',
4928 b'b',
4931 b'branch',
4929 b'branch',
4932 [],
4930 [],
4933 _(b'a specific branch you would like to push'),
4931 _(b'a specific branch you would like to push'),
4934 _(b'BRANCH'),
4932 _(b'BRANCH'),
4935 ),
4933 ),
4936 ]
4934 ]
4937 + logopts
4935 + logopts
4938 + remoteopts
4936 + remoteopts
4939 + subrepoopts,
4937 + subrepoopts,
4940 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4938 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4941 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4939 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4942 )
4940 )
4943 def outgoing(ui, repo, dest=None, **opts):
4941 def outgoing(ui, repo, dest=None, **opts):
4944 """show changesets not found in the destination
4942 """show changesets not found in the destination
4945
4943
4946 Show changesets not found in the specified destination repository
4944 Show changesets not found in the specified destination repository
4947 or the default push location. These are the changesets that would
4945 or the default push location. These are the changesets that would
4948 be pushed if a push was requested.
4946 be pushed if a push was requested.
4949
4947
4950 See pull for details of valid destination formats.
4948 See pull for details of valid destination formats.
4951
4949
4952 .. container:: verbose
4950 .. container:: verbose
4953
4951
4954 With -B/--bookmarks, the result of bookmark comparison between
4952 With -B/--bookmarks, the result of bookmark comparison between
4955 local and remote repositories is displayed. With -v/--verbose,
4953 local and remote repositories is displayed. With -v/--verbose,
4956 status is also displayed for each bookmark like below::
4954 status is also displayed for each bookmark like below::
4957
4955
4958 BM1 01234567890a added
4956 BM1 01234567890a added
4959 BM2 deleted
4957 BM2 deleted
4960 BM3 234567890abc advanced
4958 BM3 234567890abc advanced
4961 BM4 34567890abcd diverged
4959 BM4 34567890abcd diverged
4962 BM5 4567890abcde changed
4960 BM5 4567890abcde changed
4963
4961
4964 The action taken when pushing depends on the
4962 The action taken when pushing depends on the
4965 status of each bookmark:
4963 status of each bookmark:
4966
4964
4967 :``added``: push with ``-B`` will create it
4965 :``added``: push with ``-B`` will create it
4968 :``deleted``: push with ``-B`` will delete it
4966 :``deleted``: push with ``-B`` will delete it
4969 :``advanced``: push will update it
4967 :``advanced``: push will update it
4970 :``diverged``: push with ``-B`` will update it
4968 :``diverged``: push with ``-B`` will update it
4971 :``changed``: push with ``-B`` will update it
4969 :``changed``: push with ``-B`` will update it
4972
4970
4973 From the point of view of pushing behavior, bookmarks
4971 From the point of view of pushing behavior, bookmarks
4974 existing only in the remote repository are treated as
4972 existing only in the remote repository are treated as
4975 ``deleted``, even if it is in fact added remotely.
4973 ``deleted``, even if it is in fact added remotely.
4976
4974
4977 Returns 0 if there are outgoing changes, 1 otherwise.
4975 Returns 0 if there are outgoing changes, 1 otherwise.
4978 """
4976 """
4979 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4977 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4980 # style URLs, so don't overwrite dest.
4978 # style URLs, so don't overwrite dest.
4981 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4979 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4982 if not path:
4980 if not path:
4983 raise error.Abort(
4981 raise error.Abort(
4984 _(b'default repository not configured!'),
4982 _(b'default repository not configured!'),
4985 hint=_(b"see 'hg help config.paths'"),
4983 hint=_(b"see 'hg help config.paths'"),
4986 )
4984 )
4987
4985
4988 opts = pycompat.byteskwargs(opts)
4986 opts = pycompat.byteskwargs(opts)
4989 if opts.get(b'graph'):
4987 if opts.get(b'graph'):
4990 logcmdutil.checkunsupportedgraphflags([], opts)
4988 logcmdutil.checkunsupportedgraphflags([], opts)
4991 o, other = hg._outgoing(ui, repo, dest, opts)
4989 o, other = hg._outgoing(ui, repo, dest, opts)
4992 if not o:
4990 if not o:
4993 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4991 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4994 return
4992 return
4995
4993
4996 revdag = logcmdutil.graphrevs(repo, o, opts)
4994 revdag = logcmdutil.graphrevs(repo, o, opts)
4997 ui.pager(b'outgoing')
4995 ui.pager(b'outgoing')
4998 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4996 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4999 logcmdutil.displaygraph(
4997 logcmdutil.displaygraph(
5000 ui, repo, revdag, displayer, graphmod.asciiedges
4998 ui, repo, revdag, displayer, graphmod.asciiedges
5001 )
4999 )
5002 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5000 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5003 return 0
5001 return 0
5004
5002
5005 if opts.get(b'bookmarks'):
5003 if opts.get(b'bookmarks'):
5006 dest = path.pushloc or path.loc
5004 dest = path.pushloc or path.loc
5007 other = hg.peer(repo, opts, dest)
5005 other = hg.peer(repo, opts, dest)
5008 if b'bookmarks' not in other.listkeys(b'namespaces'):
5006 if b'bookmarks' not in other.listkeys(b'namespaces'):
5009 ui.warn(_(b"remote doesn't support bookmarks\n"))
5007 ui.warn(_(b"remote doesn't support bookmarks\n"))
5010 return 0
5008 return 0
5011 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5009 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5012 ui.pager(b'outgoing')
5010 ui.pager(b'outgoing')
5013 return bookmarks.outgoing(ui, repo, other)
5011 return bookmarks.outgoing(ui, repo, other)
5014
5012
5015 repo._subtoppath = path.pushloc or path.loc
5013 repo._subtoppath = path.pushloc or path.loc
5016 try:
5014 try:
5017 return hg.outgoing(ui, repo, dest, opts)
5015 return hg.outgoing(ui, repo, dest, opts)
5018 finally:
5016 finally:
5019 del repo._subtoppath
5017 del repo._subtoppath
5020
5018
5021
5019
5022 @command(
5020 @command(
5023 b'parents',
5021 b'parents',
5024 [
5022 [
5025 (
5023 (
5026 b'r',
5024 b'r',
5027 b'rev',
5025 b'rev',
5028 b'',
5026 b'',
5029 _(b'show parents of the specified revision'),
5027 _(b'show parents of the specified revision'),
5030 _(b'REV'),
5028 _(b'REV'),
5031 ),
5029 ),
5032 ]
5030 ]
5033 + templateopts,
5031 + templateopts,
5034 _(b'[-r REV] [FILE]'),
5032 _(b'[-r REV] [FILE]'),
5035 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5033 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5036 inferrepo=True,
5034 inferrepo=True,
5037 )
5035 )
5038 def parents(ui, repo, file_=None, **opts):
5036 def parents(ui, repo, file_=None, **opts):
5039 """show the parents of the working directory or revision (DEPRECATED)
5037 """show the parents of the working directory or revision (DEPRECATED)
5040
5038
5041 Print the working directory's parent revisions. If a revision is
5039 Print the working directory's parent revisions. If a revision is
5042 given via -r/--rev, the parent of that revision will be printed.
5040 given via -r/--rev, the parent of that revision will be printed.
5043 If a file argument is given, the revision in which the file was
5041 If a file argument is given, the revision in which the file was
5044 last changed (before the working directory revision or the
5042 last changed (before the working directory revision or the
5045 argument to --rev if given) is printed.
5043 argument to --rev if given) is printed.
5046
5044
5047 This command is equivalent to::
5045 This command is equivalent to::
5048
5046
5049 hg log -r "p1()+p2()" or
5047 hg log -r "p1()+p2()" or
5050 hg log -r "p1(REV)+p2(REV)" or
5048 hg log -r "p1(REV)+p2(REV)" or
5051 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5049 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5052 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5050 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5053
5051
5054 See :hg:`summary` and :hg:`help revsets` for related information.
5052 See :hg:`summary` and :hg:`help revsets` for related information.
5055
5053
5056 Returns 0 on success.
5054 Returns 0 on success.
5057 """
5055 """
5058
5056
5059 opts = pycompat.byteskwargs(opts)
5057 opts = pycompat.byteskwargs(opts)
5060 rev = opts.get(b'rev')
5058 rev = opts.get(b'rev')
5061 if rev:
5059 if rev:
5062 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5060 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5063 ctx = scmutil.revsingle(repo, rev, None)
5061 ctx = scmutil.revsingle(repo, rev, None)
5064
5062
5065 if file_:
5063 if file_:
5066 m = scmutil.match(ctx, (file_,), opts)
5064 m = scmutil.match(ctx, (file_,), opts)
5067 if m.anypats() or len(m.files()) != 1:
5065 if m.anypats() or len(m.files()) != 1:
5068 raise error.Abort(_(b'can only specify an explicit filename'))
5066 raise error.Abort(_(b'can only specify an explicit filename'))
5069 file_ = m.files()[0]
5067 file_ = m.files()[0]
5070 filenodes = []
5068 filenodes = []
5071 for cp in ctx.parents():
5069 for cp in ctx.parents():
5072 if not cp:
5070 if not cp:
5073 continue
5071 continue
5074 try:
5072 try:
5075 filenodes.append(cp.filenode(file_))
5073 filenodes.append(cp.filenode(file_))
5076 except error.LookupError:
5074 except error.LookupError:
5077 pass
5075 pass
5078 if not filenodes:
5076 if not filenodes:
5079 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5077 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5080 p = []
5078 p = []
5081 for fn in filenodes:
5079 for fn in filenodes:
5082 fctx = repo.filectx(file_, fileid=fn)
5080 fctx = repo.filectx(file_, fileid=fn)
5083 p.append(fctx.node())
5081 p.append(fctx.node())
5084 else:
5082 else:
5085 p = [cp.node() for cp in ctx.parents()]
5083 p = [cp.node() for cp in ctx.parents()]
5086
5084
5087 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5085 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5088 for n in p:
5086 for n in p:
5089 if n != nullid:
5087 if n != nullid:
5090 displayer.show(repo[n])
5088 displayer.show(repo[n])
5091 displayer.close()
5089 displayer.close()
5092
5090
5093
5091
5094 @command(
5092 @command(
5095 b'paths',
5093 b'paths',
5096 formatteropts,
5094 formatteropts,
5097 _(b'[NAME]'),
5095 _(b'[NAME]'),
5098 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5096 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5099 optionalrepo=True,
5097 optionalrepo=True,
5100 intents={INTENT_READONLY},
5098 intents={INTENT_READONLY},
5101 )
5099 )
5102 def paths(ui, repo, search=None, **opts):
5100 def paths(ui, repo, search=None, **opts):
5103 """show aliases for remote repositories
5101 """show aliases for remote repositories
5104
5102
5105 Show definition of symbolic path name NAME. If no name is given,
5103 Show definition of symbolic path name NAME. If no name is given,
5106 show definition of all available names.
5104 show definition of all available names.
5107
5105
5108 Option -q/--quiet suppresses all output when searching for NAME
5106 Option -q/--quiet suppresses all output when searching for NAME
5109 and shows only the path names when listing all definitions.
5107 and shows only the path names when listing all definitions.
5110
5108
5111 Path names are defined in the [paths] section of your
5109 Path names are defined in the [paths] section of your
5112 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5110 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5113 repository, ``.hg/hgrc`` is used, too.
5111 repository, ``.hg/hgrc`` is used, too.
5114
5112
5115 The path names ``default`` and ``default-push`` have a special
5113 The path names ``default`` and ``default-push`` have a special
5116 meaning. When performing a push or pull operation, they are used
5114 meaning. When performing a push or pull operation, they are used
5117 as fallbacks if no location is specified on the command-line.
5115 as fallbacks if no location is specified on the command-line.
5118 When ``default-push`` is set, it will be used for push and
5116 When ``default-push`` is set, it will be used for push and
5119 ``default`` will be used for pull; otherwise ``default`` is used
5117 ``default`` will be used for pull; otherwise ``default`` is used
5120 as the fallback for both. When cloning a repository, the clone
5118 as the fallback for both. When cloning a repository, the clone
5121 source is written as ``default`` in ``.hg/hgrc``.
5119 source is written as ``default`` in ``.hg/hgrc``.
5122
5120
5123 .. note::
5121 .. note::
5124
5122
5125 ``default`` and ``default-push`` apply to all inbound (e.g.
5123 ``default`` and ``default-push`` apply to all inbound (e.g.
5126 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5124 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5127 and :hg:`bundle`) operations.
5125 and :hg:`bundle`) operations.
5128
5126
5129 See :hg:`help urls` for more information.
5127 See :hg:`help urls` for more information.
5130
5128
5131 .. container:: verbose
5129 .. container:: verbose
5132
5130
5133 Template:
5131 Template:
5134
5132
5135 The following keywords are supported. See also :hg:`help templates`.
5133 The following keywords are supported. See also :hg:`help templates`.
5136
5134
5137 :name: String. Symbolic name of the path alias.
5135 :name: String. Symbolic name of the path alias.
5138 :pushurl: String. URL for push operations.
5136 :pushurl: String. URL for push operations.
5139 :url: String. URL or directory path for the other operations.
5137 :url: String. URL or directory path for the other operations.
5140
5138
5141 Returns 0 on success.
5139 Returns 0 on success.
5142 """
5140 """
5143
5141
5144 opts = pycompat.byteskwargs(opts)
5142 opts = pycompat.byteskwargs(opts)
5145 ui.pager(b'paths')
5143 ui.pager(b'paths')
5146 if search:
5144 if search:
5147 pathitems = [
5145 pathitems = [
5148 (name, path)
5146 (name, path)
5149 for name, path in pycompat.iteritems(ui.paths)
5147 for name, path in pycompat.iteritems(ui.paths)
5150 if name == search
5148 if name == search
5151 ]
5149 ]
5152 else:
5150 else:
5153 pathitems = sorted(pycompat.iteritems(ui.paths))
5151 pathitems = sorted(pycompat.iteritems(ui.paths))
5154
5152
5155 fm = ui.formatter(b'paths', opts)
5153 fm = ui.formatter(b'paths', opts)
5156 if fm.isplain():
5154 if fm.isplain():
5157 hidepassword = util.hidepassword
5155 hidepassword = util.hidepassword
5158 else:
5156 else:
5159 hidepassword = bytes
5157 hidepassword = bytes
5160 if ui.quiet:
5158 if ui.quiet:
5161 namefmt = b'%s\n'
5159 namefmt = b'%s\n'
5162 else:
5160 else:
5163 namefmt = b'%s = '
5161 namefmt = b'%s = '
5164 showsubopts = not search and not ui.quiet
5162 showsubopts = not search and not ui.quiet
5165
5163
5166 for name, path in pathitems:
5164 for name, path in pathitems:
5167 fm.startitem()
5165 fm.startitem()
5168 fm.condwrite(not search, b'name', namefmt, name)
5166 fm.condwrite(not search, b'name', namefmt, name)
5169 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5167 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5170 for subopt, value in sorted(path.suboptions.items()):
5168 for subopt, value in sorted(path.suboptions.items()):
5171 assert subopt not in (b'name', b'url')
5169 assert subopt not in (b'name', b'url')
5172 if showsubopts:
5170 if showsubopts:
5173 fm.plain(b'%s:%s = ' % (name, subopt))
5171 fm.plain(b'%s:%s = ' % (name, subopt))
5174 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5172 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5175
5173
5176 fm.end()
5174 fm.end()
5177
5175
5178 if search and not pathitems:
5176 if search and not pathitems:
5179 if not ui.quiet:
5177 if not ui.quiet:
5180 ui.warn(_(b"not found!\n"))
5178 ui.warn(_(b"not found!\n"))
5181 return 1
5179 return 1
5182 else:
5180 else:
5183 return 0
5181 return 0
5184
5182
5185
5183
5186 @command(
5184 @command(
5187 b'phase',
5185 b'phase',
5188 [
5186 [
5189 (b'p', b'public', False, _(b'set changeset phase to public')),
5187 (b'p', b'public', False, _(b'set changeset phase to public')),
5190 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5188 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5191 (b's', b'secret', False, _(b'set changeset phase to secret')),
5189 (b's', b'secret', False, _(b'set changeset phase to secret')),
5192 (b'f', b'force', False, _(b'allow to move boundary backward')),
5190 (b'f', b'force', False, _(b'allow to move boundary backward')),
5193 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5191 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5194 ],
5192 ],
5195 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5193 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5196 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5194 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5197 )
5195 )
5198 def phase(ui, repo, *revs, **opts):
5196 def phase(ui, repo, *revs, **opts):
5199 """set or show the current phase name
5197 """set or show the current phase name
5200
5198
5201 With no argument, show the phase name of the current revision(s).
5199 With no argument, show the phase name of the current revision(s).
5202
5200
5203 With one of -p/--public, -d/--draft or -s/--secret, change the
5201 With one of -p/--public, -d/--draft or -s/--secret, change the
5204 phase value of the specified revisions.
5202 phase value of the specified revisions.
5205
5203
5206 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5204 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5207 lower phase to a higher phase. Phases are ordered as follows::
5205 lower phase to a higher phase. Phases are ordered as follows::
5208
5206
5209 public < draft < secret
5207 public < draft < secret
5210
5208
5211 Returns 0 on success, 1 if some phases could not be changed.
5209 Returns 0 on success, 1 if some phases could not be changed.
5212
5210
5213 (For more information about the phases concept, see :hg:`help phases`.)
5211 (For more information about the phases concept, see :hg:`help phases`.)
5214 """
5212 """
5215 opts = pycompat.byteskwargs(opts)
5213 opts = pycompat.byteskwargs(opts)
5216 # search for a unique phase argument
5214 # search for a unique phase argument
5217 targetphase = None
5215 targetphase = None
5218 for idx, name in enumerate(phases.cmdphasenames):
5216 for idx, name in enumerate(phases.cmdphasenames):
5219 if opts[name]:
5217 if opts[name]:
5220 if targetphase is not None:
5218 if targetphase is not None:
5221 raise error.Abort(_(b'only one phase can be specified'))
5219 raise error.Abort(_(b'only one phase can be specified'))
5222 targetphase = idx
5220 targetphase = idx
5223
5221
5224 # look for specified revision
5222 # look for specified revision
5225 revs = list(revs)
5223 revs = list(revs)
5226 revs.extend(opts[b'rev'])
5224 revs.extend(opts[b'rev'])
5227 if not revs:
5225 if not revs:
5228 # display both parents as the second parent phase can influence
5226 # display both parents as the second parent phase can influence
5229 # the phase of a merge commit
5227 # the phase of a merge commit
5230 revs = [c.rev() for c in repo[None].parents()]
5228 revs = [c.rev() for c in repo[None].parents()]
5231
5229
5232 revs = scmutil.revrange(repo, revs)
5230 revs = scmutil.revrange(repo, revs)
5233
5231
5234 ret = 0
5232 ret = 0
5235 if targetphase is None:
5233 if targetphase is None:
5236 # display
5234 # display
5237 for r in revs:
5235 for r in revs:
5238 ctx = repo[r]
5236 ctx = repo[r]
5239 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5237 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5240 else:
5238 else:
5241 with repo.lock(), repo.transaction(b"phase") as tr:
5239 with repo.lock(), repo.transaction(b"phase") as tr:
5242 # set phase
5240 # set phase
5243 if not revs:
5241 if not revs:
5244 raise error.Abort(_(b'empty revision set'))
5242 raise error.Abort(_(b'empty revision set'))
5245 nodes = [repo[r].node() for r in revs]
5243 nodes = [repo[r].node() for r in revs]
5246 # moving revision from public to draft may hide them
5244 # moving revision from public to draft may hide them
5247 # We have to check result on an unfiltered repository
5245 # We have to check result on an unfiltered repository
5248 unfi = repo.unfiltered()
5246 unfi = repo.unfiltered()
5249 getphase = unfi._phasecache.phase
5247 getphase = unfi._phasecache.phase
5250 olddata = [getphase(unfi, r) for r in unfi]
5248 olddata = [getphase(unfi, r) for r in unfi]
5251 phases.advanceboundary(repo, tr, targetphase, nodes)
5249 phases.advanceboundary(repo, tr, targetphase, nodes)
5252 if opts[b'force']:
5250 if opts[b'force']:
5253 phases.retractboundary(repo, tr, targetphase, nodes)
5251 phases.retractboundary(repo, tr, targetphase, nodes)
5254 getphase = unfi._phasecache.phase
5252 getphase = unfi._phasecache.phase
5255 newdata = [getphase(unfi, r) for r in unfi]
5253 newdata = [getphase(unfi, r) for r in unfi]
5256 changes = sum(newdata[r] != olddata[r] for r in unfi)
5254 changes = sum(newdata[r] != olddata[r] for r in unfi)
5257 cl = unfi.changelog
5255 cl = unfi.changelog
5258 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5256 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5259 if rejected:
5257 if rejected:
5260 ui.warn(
5258 ui.warn(
5261 _(
5259 _(
5262 b'cannot move %i changesets to a higher '
5260 b'cannot move %i changesets to a higher '
5263 b'phase, use --force\n'
5261 b'phase, use --force\n'
5264 )
5262 )
5265 % len(rejected)
5263 % len(rejected)
5266 )
5264 )
5267 ret = 1
5265 ret = 1
5268 if changes:
5266 if changes:
5269 msg = _(b'phase changed for %i changesets\n') % changes
5267 msg = _(b'phase changed for %i changesets\n') % changes
5270 if ret:
5268 if ret:
5271 ui.status(msg)
5269 ui.status(msg)
5272 else:
5270 else:
5273 ui.note(msg)
5271 ui.note(msg)
5274 else:
5272 else:
5275 ui.warn(_(b'no phases changed\n'))
5273 ui.warn(_(b'no phases changed\n'))
5276 return ret
5274 return ret
5277
5275
5278
5276
5279 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5277 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5280 """Run after a changegroup has been added via pull/unbundle
5278 """Run after a changegroup has been added via pull/unbundle
5281
5279
5282 This takes arguments below:
5280 This takes arguments below:
5283
5281
5284 :modheads: change of heads by pull/unbundle
5282 :modheads: change of heads by pull/unbundle
5285 :optupdate: updating working directory is needed or not
5283 :optupdate: updating working directory is needed or not
5286 :checkout: update destination revision (or None to default destination)
5284 :checkout: update destination revision (or None to default destination)
5287 :brev: a name, which might be a bookmark to be activated after updating
5285 :brev: a name, which might be a bookmark to be activated after updating
5288 """
5286 """
5289 if modheads == 0:
5287 if modheads == 0:
5290 return
5288 return
5291 if optupdate:
5289 if optupdate:
5292 try:
5290 try:
5293 return hg.updatetotally(ui, repo, checkout, brev)
5291 return hg.updatetotally(ui, repo, checkout, brev)
5294 except error.UpdateAbort as inst:
5292 except error.UpdateAbort as inst:
5295 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5293 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5296 hint = inst.hint
5294 hint = inst.hint
5297 raise error.UpdateAbort(msg, hint=hint)
5295 raise error.UpdateAbort(msg, hint=hint)
5298 if modheads is not None and modheads > 1:
5296 if modheads is not None and modheads > 1:
5299 currentbranchheads = len(repo.branchheads())
5297 currentbranchheads = len(repo.branchheads())
5300 if currentbranchheads == modheads:
5298 if currentbranchheads == modheads:
5301 ui.status(
5299 ui.status(
5302 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5300 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5303 )
5301 )
5304 elif currentbranchheads > 1:
5302 elif currentbranchheads > 1:
5305 ui.status(
5303 ui.status(
5306 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5304 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5307 )
5305 )
5308 else:
5306 else:
5309 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5307 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5310 elif not ui.configbool(b'commands', b'update.requiredest'):
5308 elif not ui.configbool(b'commands', b'update.requiredest'):
5311 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5309 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5312
5310
5313
5311
5314 @command(
5312 @command(
5315 b'pull',
5313 b'pull',
5316 [
5314 [
5317 (
5315 (
5318 b'u',
5316 b'u',
5319 b'update',
5317 b'update',
5320 None,
5318 None,
5321 _(b'update to new branch head if new descendants were pulled'),
5319 _(b'update to new branch head if new descendants were pulled'),
5322 ),
5320 ),
5323 (
5321 (
5324 b'f',
5322 b'f',
5325 b'force',
5323 b'force',
5326 None,
5324 None,
5327 _(b'run even when remote repository is unrelated'),
5325 _(b'run even when remote repository is unrelated'),
5328 ),
5326 ),
5329 (
5327 (
5330 b'r',
5328 b'r',
5331 b'rev',
5329 b'rev',
5332 [],
5330 [],
5333 _(b'a remote changeset intended to be added'),
5331 _(b'a remote changeset intended to be added'),
5334 _(b'REV'),
5332 _(b'REV'),
5335 ),
5333 ),
5336 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5334 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5337 (
5335 (
5338 b'b',
5336 b'b',
5339 b'branch',
5337 b'branch',
5340 [],
5338 [],
5341 _(b'a specific branch you would like to pull'),
5339 _(b'a specific branch you would like to pull'),
5342 _(b'BRANCH'),
5340 _(b'BRANCH'),
5343 ),
5341 ),
5344 ]
5342 ]
5345 + remoteopts,
5343 + remoteopts,
5346 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5344 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5347 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5345 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5348 helpbasic=True,
5346 helpbasic=True,
5349 )
5347 )
5350 def pull(ui, repo, source=b"default", **opts):
5348 def pull(ui, repo, source=b"default", **opts):
5351 """pull changes from the specified source
5349 """pull changes from the specified source
5352
5350
5353 Pull changes from a remote repository to a local one.
5351 Pull changes from a remote repository to a local one.
5354
5352
5355 This finds all changes from the repository at the specified path
5353 This finds all changes from the repository at the specified path
5356 or URL and adds them to a local repository (the current one unless
5354 or URL and adds them to a local repository (the current one unless
5357 -R is specified). By default, this does not update the copy of the
5355 -R is specified). By default, this does not update the copy of the
5358 project in the working directory.
5356 project in the working directory.
5359
5357
5360 When cloning from servers that support it, Mercurial may fetch
5358 When cloning from servers that support it, Mercurial may fetch
5361 pre-generated data. When this is done, hooks operating on incoming
5359 pre-generated data. When this is done, hooks operating on incoming
5362 changesets and changegroups may fire more than once, once for each
5360 changesets and changegroups may fire more than once, once for each
5363 pre-generated bundle and as well as for any additional remaining
5361 pre-generated bundle and as well as for any additional remaining
5364 data. See :hg:`help -e clonebundles` for more.
5362 data. See :hg:`help -e clonebundles` for more.
5365
5363
5366 Use :hg:`incoming` if you want to see what would have been added
5364 Use :hg:`incoming` if you want to see what would have been added
5367 by a pull at the time you issued this command. If you then decide
5365 by a pull at the time you issued this command. If you then decide
5368 to add those changes to the repository, you should use :hg:`pull
5366 to add those changes to the repository, you should use :hg:`pull
5369 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5367 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5370
5368
5371 If SOURCE is omitted, the 'default' path will be used.
5369 If SOURCE is omitted, the 'default' path will be used.
5372 See :hg:`help urls` for more information.
5370 See :hg:`help urls` for more information.
5373
5371
5374 Specifying bookmark as ``.`` is equivalent to specifying the active
5372 Specifying bookmark as ``.`` is equivalent to specifying the active
5375 bookmark's name.
5373 bookmark's name.
5376
5374
5377 Returns 0 on success, 1 if an update had unresolved files.
5375 Returns 0 on success, 1 if an update had unresolved files.
5378 """
5376 """
5379
5377
5380 opts = pycompat.byteskwargs(opts)
5378 opts = pycompat.byteskwargs(opts)
5381 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5379 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5382 b'update'
5380 b'update'
5383 ):
5381 ):
5384 msg = _(b'update destination required by configuration')
5382 msg = _(b'update destination required by configuration')
5385 hint = _(b'use hg pull followed by hg update DEST')
5383 hint = _(b'use hg pull followed by hg update DEST')
5386 raise error.Abort(msg, hint=hint)
5384 raise error.Abort(msg, hint=hint)
5387
5385
5388 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5386 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5389 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5387 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5390 other = hg.peer(repo, opts, source)
5388 other = hg.peer(repo, opts, source)
5391 try:
5389 try:
5392 revs, checkout = hg.addbranchrevs(
5390 revs, checkout = hg.addbranchrevs(
5393 repo, other, branches, opts.get(b'rev')
5391 repo, other, branches, opts.get(b'rev')
5394 )
5392 )
5395
5393
5396 pullopargs = {}
5394 pullopargs = {}
5397
5395
5398 nodes = None
5396 nodes = None
5399 if opts.get(b'bookmark') or revs:
5397 if opts.get(b'bookmark') or revs:
5400 # The list of bookmark used here is the same used to actually update
5398 # The list of bookmark used here is the same used to actually update
5401 # the bookmark names, to avoid the race from issue 4689 and we do
5399 # the bookmark names, to avoid the race from issue 4689 and we do
5402 # all lookup and bookmark queries in one go so they see the same
5400 # all lookup and bookmark queries in one go so they see the same
5403 # version of the server state (issue 4700).
5401 # version of the server state (issue 4700).
5404 nodes = []
5402 nodes = []
5405 fnodes = []
5403 fnodes = []
5406 revs = revs or []
5404 revs = revs or []
5407 if revs and not other.capable(b'lookup'):
5405 if revs and not other.capable(b'lookup'):
5408 err = _(
5406 err = _(
5409 b"other repository doesn't support revision lookup, "
5407 b"other repository doesn't support revision lookup, "
5410 b"so a rev cannot be specified."
5408 b"so a rev cannot be specified."
5411 )
5409 )
5412 raise error.Abort(err)
5410 raise error.Abort(err)
5413 with other.commandexecutor() as e:
5411 with other.commandexecutor() as e:
5414 fremotebookmarks = e.callcommand(
5412 fremotebookmarks = e.callcommand(
5415 b'listkeys', {b'namespace': b'bookmarks'}
5413 b'listkeys', {b'namespace': b'bookmarks'}
5416 )
5414 )
5417 for r in revs:
5415 for r in revs:
5418 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5416 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5419 remotebookmarks = fremotebookmarks.result()
5417 remotebookmarks = fremotebookmarks.result()
5420 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5418 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5421 pullopargs[b'remotebookmarks'] = remotebookmarks
5419 pullopargs[b'remotebookmarks'] = remotebookmarks
5422 for b in opts.get(b'bookmark', []):
5420 for b in opts.get(b'bookmark', []):
5423 b = repo._bookmarks.expandname(b)
5421 b = repo._bookmarks.expandname(b)
5424 if b not in remotebookmarks:
5422 if b not in remotebookmarks:
5425 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5423 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5426 nodes.append(remotebookmarks[b])
5424 nodes.append(remotebookmarks[b])
5427 for i, rev in enumerate(revs):
5425 for i, rev in enumerate(revs):
5428 node = fnodes[i].result()
5426 node = fnodes[i].result()
5429 nodes.append(node)
5427 nodes.append(node)
5430 if rev == checkout:
5428 if rev == checkout:
5431 checkout = node
5429 checkout = node
5432
5430
5433 wlock = util.nullcontextmanager()
5431 wlock = util.nullcontextmanager()
5434 if opts.get(b'update'):
5432 if opts.get(b'update'):
5435 wlock = repo.wlock()
5433 wlock = repo.wlock()
5436 with wlock:
5434 with wlock:
5437 pullopargs.update(opts.get(b'opargs', {}))
5435 pullopargs.update(opts.get(b'opargs', {}))
5438 modheads = exchange.pull(
5436 modheads = exchange.pull(
5439 repo,
5437 repo,
5440 other,
5438 other,
5441 heads=nodes,
5439 heads=nodes,
5442 force=opts.get(b'force'),
5440 force=opts.get(b'force'),
5443 bookmarks=opts.get(b'bookmark', ()),
5441 bookmarks=opts.get(b'bookmark', ()),
5444 opargs=pullopargs,
5442 opargs=pullopargs,
5445 ).cgresult
5443 ).cgresult
5446
5444
5447 # brev is a name, which might be a bookmark to be activated at
5445 # brev is a name, which might be a bookmark to be activated at
5448 # the end of the update. In other words, it is an explicit
5446 # the end of the update. In other words, it is an explicit
5449 # destination of the update
5447 # destination of the update
5450 brev = None
5448 brev = None
5451
5449
5452 if checkout:
5450 if checkout:
5453 checkout = repo.unfiltered().changelog.rev(checkout)
5451 checkout = repo.unfiltered().changelog.rev(checkout)
5454
5452
5455 # order below depends on implementation of
5453 # order below depends on implementation of
5456 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5454 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5457 # because 'checkout' is determined without it.
5455 # because 'checkout' is determined without it.
5458 if opts.get(b'rev'):
5456 if opts.get(b'rev'):
5459 brev = opts[b'rev'][0]
5457 brev = opts[b'rev'][0]
5460 elif opts.get(b'branch'):
5458 elif opts.get(b'branch'):
5461 brev = opts[b'branch'][0]
5459 brev = opts[b'branch'][0]
5462 else:
5460 else:
5463 brev = branches[0]
5461 brev = branches[0]
5464 repo._subtoppath = source
5462 repo._subtoppath = source
5465 try:
5463 try:
5466 ret = postincoming(
5464 ret = postincoming(
5467 ui, repo, modheads, opts.get(b'update'), checkout, brev
5465 ui, repo, modheads, opts.get(b'update'), checkout, brev
5468 )
5466 )
5469 except error.FilteredRepoLookupError as exc:
5467 except error.FilteredRepoLookupError as exc:
5470 msg = _(b'cannot update to target: %s') % exc.args[0]
5468 msg = _(b'cannot update to target: %s') % exc.args[0]
5471 exc.args = (msg,) + exc.args[1:]
5469 exc.args = (msg,) + exc.args[1:]
5472 raise
5470 raise
5473 finally:
5471 finally:
5474 del repo._subtoppath
5472 del repo._subtoppath
5475
5473
5476 finally:
5474 finally:
5477 other.close()
5475 other.close()
5478 return ret
5476 return ret
5479
5477
5480
5478
5481 @command(
5479 @command(
5482 b'push',
5480 b'push',
5483 [
5481 [
5484 (b'f', b'force', None, _(b'force push')),
5482 (b'f', b'force', None, _(b'force push')),
5485 (
5483 (
5486 b'r',
5484 b'r',
5487 b'rev',
5485 b'rev',
5488 [],
5486 [],
5489 _(b'a changeset intended to be included in the destination'),
5487 _(b'a changeset intended to be included in the destination'),
5490 _(b'REV'),
5488 _(b'REV'),
5491 ),
5489 ),
5492 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5490 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5493 (
5491 (
5494 b'b',
5492 b'b',
5495 b'branch',
5493 b'branch',
5496 [],
5494 [],
5497 _(b'a specific branch you would like to push'),
5495 _(b'a specific branch you would like to push'),
5498 _(b'BRANCH'),
5496 _(b'BRANCH'),
5499 ),
5497 ),
5500 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5498 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5501 (
5499 (
5502 b'',
5500 b'',
5503 b'pushvars',
5501 b'pushvars',
5504 [],
5502 [],
5505 _(b'variables that can be sent to server (ADVANCED)'),
5503 _(b'variables that can be sent to server (ADVANCED)'),
5506 ),
5504 ),
5507 (
5505 (
5508 b'',
5506 b'',
5509 b'publish',
5507 b'publish',
5510 False,
5508 False,
5511 _(b'push the changeset as public (EXPERIMENTAL)'),
5509 _(b'push the changeset as public (EXPERIMENTAL)'),
5512 ),
5510 ),
5513 ]
5511 ]
5514 + remoteopts,
5512 + remoteopts,
5515 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5513 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5516 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5514 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5517 helpbasic=True,
5515 helpbasic=True,
5518 )
5516 )
5519 def push(ui, repo, dest=None, **opts):
5517 def push(ui, repo, dest=None, **opts):
5520 """push changes to the specified destination
5518 """push changes to the specified destination
5521
5519
5522 Push changesets from the local repository to the specified
5520 Push changesets from the local repository to the specified
5523 destination.
5521 destination.
5524
5522
5525 This operation is symmetrical to pull: it is identical to a pull
5523 This operation is symmetrical to pull: it is identical to a pull
5526 in the destination repository from the current one.
5524 in the destination repository from the current one.
5527
5525
5528 By default, push will not allow creation of new heads at the
5526 By default, push will not allow creation of new heads at the
5529 destination, since multiple heads would make it unclear which head
5527 destination, since multiple heads would make it unclear which head
5530 to use. In this situation, it is recommended to pull and merge
5528 to use. In this situation, it is recommended to pull and merge
5531 before pushing.
5529 before pushing.
5532
5530
5533 Use --new-branch if you want to allow push to create a new named
5531 Use --new-branch if you want to allow push to create a new named
5534 branch that is not present at the destination. This allows you to
5532 branch that is not present at the destination. This allows you to
5535 only create a new branch without forcing other changes.
5533 only create a new branch without forcing other changes.
5536
5534
5537 .. note::
5535 .. note::
5538
5536
5539 Extra care should be taken with the -f/--force option,
5537 Extra care should be taken with the -f/--force option,
5540 which will push all new heads on all branches, an action which will
5538 which will push all new heads on all branches, an action which will
5541 almost always cause confusion for collaborators.
5539 almost always cause confusion for collaborators.
5542
5540
5543 If -r/--rev is used, the specified revision and all its ancestors
5541 If -r/--rev is used, the specified revision and all its ancestors
5544 will be pushed to the remote repository.
5542 will be pushed to the remote repository.
5545
5543
5546 If -B/--bookmark is used, the specified bookmarked revision, its
5544 If -B/--bookmark is used, the specified bookmarked revision, its
5547 ancestors, and the bookmark will be pushed to the remote
5545 ancestors, and the bookmark will be pushed to the remote
5548 repository. Specifying ``.`` is equivalent to specifying the active
5546 repository. Specifying ``.`` is equivalent to specifying the active
5549 bookmark's name.
5547 bookmark's name.
5550
5548
5551 Please see :hg:`help urls` for important details about ``ssh://``
5549 Please see :hg:`help urls` for important details about ``ssh://``
5552 URLs. If DESTINATION is omitted, a default path will be used.
5550 URLs. If DESTINATION is omitted, a default path will be used.
5553
5551
5554 .. container:: verbose
5552 .. container:: verbose
5555
5553
5556 The --pushvars option sends strings to the server that become
5554 The --pushvars option sends strings to the server that become
5557 environment variables prepended with ``HG_USERVAR_``. For example,
5555 environment variables prepended with ``HG_USERVAR_``. For example,
5558 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5556 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5559 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5557 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5560
5558
5561 pushvars can provide for user-overridable hooks as well as set debug
5559 pushvars can provide for user-overridable hooks as well as set debug
5562 levels. One example is having a hook that blocks commits containing
5560 levels. One example is having a hook that blocks commits containing
5563 conflict markers, but enables the user to override the hook if the file
5561 conflict markers, but enables the user to override the hook if the file
5564 is using conflict markers for testing purposes or the file format has
5562 is using conflict markers for testing purposes or the file format has
5565 strings that look like conflict markers.
5563 strings that look like conflict markers.
5566
5564
5567 By default, servers will ignore `--pushvars`. To enable it add the
5565 By default, servers will ignore `--pushvars`. To enable it add the
5568 following to your configuration file::
5566 following to your configuration file::
5569
5567
5570 [push]
5568 [push]
5571 pushvars.server = true
5569 pushvars.server = true
5572
5570
5573 Returns 0 if push was successful, 1 if nothing to push.
5571 Returns 0 if push was successful, 1 if nothing to push.
5574 """
5572 """
5575
5573
5576 opts = pycompat.byteskwargs(opts)
5574 opts = pycompat.byteskwargs(opts)
5577 if opts.get(b'bookmark'):
5575 if opts.get(b'bookmark'):
5578 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5576 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5579 for b in opts[b'bookmark']:
5577 for b in opts[b'bookmark']:
5580 # translate -B options to -r so changesets get pushed
5578 # translate -B options to -r so changesets get pushed
5581 b = repo._bookmarks.expandname(b)
5579 b = repo._bookmarks.expandname(b)
5582 if b in repo._bookmarks:
5580 if b in repo._bookmarks:
5583 opts.setdefault(b'rev', []).append(b)
5581 opts.setdefault(b'rev', []).append(b)
5584 else:
5582 else:
5585 # if we try to push a deleted bookmark, translate it to null
5583 # if we try to push a deleted bookmark, translate it to null
5586 # this lets simultaneous -r, -b options continue working
5584 # this lets simultaneous -r, -b options continue working
5587 opts.setdefault(b'rev', []).append(b"null")
5585 opts.setdefault(b'rev', []).append(b"null")
5588
5586
5589 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5587 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5590 if not path:
5588 if not path:
5591 raise error.Abort(
5589 raise error.Abort(
5592 _(b'default repository not configured!'),
5590 _(b'default repository not configured!'),
5593 hint=_(b"see 'hg help config.paths'"),
5591 hint=_(b"see 'hg help config.paths'"),
5594 )
5592 )
5595 dest = path.pushloc or path.loc
5593 dest = path.pushloc or path.loc
5596 branches = (path.branch, opts.get(b'branch') or [])
5594 branches = (path.branch, opts.get(b'branch') or [])
5597 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5595 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5598 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5596 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5599 other = hg.peer(repo, opts, dest)
5597 other = hg.peer(repo, opts, dest)
5600
5598
5601 if revs:
5599 if revs:
5602 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5600 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5603 if not revs:
5601 if not revs:
5604 raise error.Abort(
5602 raise error.Abort(
5605 _(b"specified revisions evaluate to an empty set"),
5603 _(b"specified revisions evaluate to an empty set"),
5606 hint=_(b"use different revision arguments"),
5604 hint=_(b"use different revision arguments"),
5607 )
5605 )
5608 elif path.pushrev:
5606 elif path.pushrev:
5609 # It doesn't make any sense to specify ancestor revisions. So limit
5607 # It doesn't make any sense to specify ancestor revisions. So limit
5610 # to DAG heads to make discovery simpler.
5608 # to DAG heads to make discovery simpler.
5611 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5609 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5612 revs = scmutil.revrange(repo, [expr])
5610 revs = scmutil.revrange(repo, [expr])
5613 revs = [repo[rev].node() for rev in revs]
5611 revs = [repo[rev].node() for rev in revs]
5614 if not revs:
5612 if not revs:
5615 raise error.Abort(
5613 raise error.Abort(
5616 _(b'default push revset for path evaluates to an empty set')
5614 _(b'default push revset for path evaluates to an empty set')
5617 )
5615 )
5618 elif ui.configbool(b'commands', b'push.require-revs'):
5616 elif ui.configbool(b'commands', b'push.require-revs'):
5619 raise error.Abort(
5617 raise error.Abort(
5620 _(b'no revisions specified to push'),
5618 _(b'no revisions specified to push'),
5621 hint=_(b'did you mean "hg push -r ."?'),
5619 hint=_(b'did you mean "hg push -r ."?'),
5622 )
5620 )
5623
5621
5624 repo._subtoppath = dest
5622 repo._subtoppath = dest
5625 try:
5623 try:
5626 # push subrepos depth-first for coherent ordering
5624 # push subrepos depth-first for coherent ordering
5627 c = repo[b'.']
5625 c = repo[b'.']
5628 subs = c.substate # only repos that are committed
5626 subs = c.substate # only repos that are committed
5629 for s in sorted(subs):
5627 for s in sorted(subs):
5630 result = c.sub(s).push(opts)
5628 result = c.sub(s).push(opts)
5631 if result == 0:
5629 if result == 0:
5632 return not result
5630 return not result
5633 finally:
5631 finally:
5634 del repo._subtoppath
5632 del repo._subtoppath
5635
5633
5636 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5634 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5637 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5635 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5638
5636
5639 pushop = exchange.push(
5637 pushop = exchange.push(
5640 repo,
5638 repo,
5641 other,
5639 other,
5642 opts.get(b'force'),
5640 opts.get(b'force'),
5643 revs=revs,
5641 revs=revs,
5644 newbranch=opts.get(b'new_branch'),
5642 newbranch=opts.get(b'new_branch'),
5645 bookmarks=opts.get(b'bookmark', ()),
5643 bookmarks=opts.get(b'bookmark', ()),
5646 publish=opts.get(b'publish'),
5644 publish=opts.get(b'publish'),
5647 opargs=opargs,
5645 opargs=opargs,
5648 )
5646 )
5649
5647
5650 result = not pushop.cgresult
5648 result = not pushop.cgresult
5651
5649
5652 if pushop.bkresult is not None:
5650 if pushop.bkresult is not None:
5653 if pushop.bkresult == 2:
5651 if pushop.bkresult == 2:
5654 result = 2
5652 result = 2
5655 elif not result and pushop.bkresult:
5653 elif not result and pushop.bkresult:
5656 result = 2
5654 result = 2
5657
5655
5658 return result
5656 return result
5659
5657
5660
5658
5661 @command(
5659 @command(
5662 b'recover',
5660 b'recover',
5663 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5661 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5664 helpcategory=command.CATEGORY_MAINTENANCE,
5662 helpcategory=command.CATEGORY_MAINTENANCE,
5665 )
5663 )
5666 def recover(ui, repo, **opts):
5664 def recover(ui, repo, **opts):
5667 """roll back an interrupted transaction
5665 """roll back an interrupted transaction
5668
5666
5669 Recover from an interrupted commit or pull.
5667 Recover from an interrupted commit or pull.
5670
5668
5671 This command tries to fix the repository status after an
5669 This command tries to fix the repository status after an
5672 interrupted operation. It should only be necessary when Mercurial
5670 interrupted operation. It should only be necessary when Mercurial
5673 suggests it.
5671 suggests it.
5674
5672
5675 Returns 0 if successful, 1 if nothing to recover or verify fails.
5673 Returns 0 if successful, 1 if nothing to recover or verify fails.
5676 """
5674 """
5677 ret = repo.recover()
5675 ret = repo.recover()
5678 if ret:
5676 if ret:
5679 if opts[r'verify']:
5677 if opts[r'verify']:
5680 return hg.verify(repo)
5678 return hg.verify(repo)
5681 else:
5679 else:
5682 msg = _(
5680 msg = _(
5683 b"(verify step skipped, run `hg verify` to check your "
5681 b"(verify step skipped, run `hg verify` to check your "
5684 b"repository content)\n"
5682 b"repository content)\n"
5685 )
5683 )
5686 ui.warn(msg)
5684 ui.warn(msg)
5687 return 0
5685 return 0
5688 return 1
5686 return 1
5689
5687
5690
5688
5691 @command(
5689 @command(
5692 b'remove|rm',
5690 b'remove|rm',
5693 [
5691 [
5694 (b'A', b'after', None, _(b'record delete for missing files')),
5692 (b'A', b'after', None, _(b'record delete for missing files')),
5695 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5693 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5696 ]
5694 ]
5697 + subrepoopts
5695 + subrepoopts
5698 + walkopts
5696 + walkopts
5699 + dryrunopts,
5697 + dryrunopts,
5700 _(b'[OPTION]... FILE...'),
5698 _(b'[OPTION]... FILE...'),
5701 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5699 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5702 helpbasic=True,
5700 helpbasic=True,
5703 inferrepo=True,
5701 inferrepo=True,
5704 )
5702 )
5705 def remove(ui, repo, *pats, **opts):
5703 def remove(ui, repo, *pats, **opts):
5706 """remove the specified files on the next commit
5704 """remove the specified files on the next commit
5707
5705
5708 Schedule the indicated files for removal from the current branch.
5706 Schedule the indicated files for removal from the current branch.
5709
5707
5710 This command schedules the files to be removed at the next commit.
5708 This command schedules the files to be removed at the next commit.
5711 To undo a remove before that, see :hg:`revert`. To undo added
5709 To undo a remove before that, see :hg:`revert`. To undo added
5712 files, see :hg:`forget`.
5710 files, see :hg:`forget`.
5713
5711
5714 .. container:: verbose
5712 .. container:: verbose
5715
5713
5716 -A/--after can be used to remove only files that have already
5714 -A/--after can be used to remove only files that have already
5717 been deleted, -f/--force can be used to force deletion, and -Af
5715 been deleted, -f/--force can be used to force deletion, and -Af
5718 can be used to remove files from the next revision without
5716 can be used to remove files from the next revision without
5719 deleting them from the working directory.
5717 deleting them from the working directory.
5720
5718
5721 The following table details the behavior of remove for different
5719 The following table details the behavior of remove for different
5722 file states (columns) and option combinations (rows). The file
5720 file states (columns) and option combinations (rows). The file
5723 states are Added [A], Clean [C], Modified [M] and Missing [!]
5721 states are Added [A], Clean [C], Modified [M] and Missing [!]
5724 (as reported by :hg:`status`). The actions are Warn, Remove
5722 (as reported by :hg:`status`). The actions are Warn, Remove
5725 (from branch) and Delete (from disk):
5723 (from branch) and Delete (from disk):
5726
5724
5727 ========= == == == ==
5725 ========= == == == ==
5728 opt/state A C M !
5726 opt/state A C M !
5729 ========= == == == ==
5727 ========= == == == ==
5730 none W RD W R
5728 none W RD W R
5731 -f R RD RD R
5729 -f R RD RD R
5732 -A W W W R
5730 -A W W W R
5733 -Af R R R R
5731 -Af R R R R
5734 ========= == == == ==
5732 ========= == == == ==
5735
5733
5736 .. note::
5734 .. note::
5737
5735
5738 :hg:`remove` never deletes files in Added [A] state from the
5736 :hg:`remove` never deletes files in Added [A] state from the
5739 working directory, not even if ``--force`` is specified.
5737 working directory, not even if ``--force`` is specified.
5740
5738
5741 Returns 0 on success, 1 if any warnings encountered.
5739 Returns 0 on success, 1 if any warnings encountered.
5742 """
5740 """
5743
5741
5744 opts = pycompat.byteskwargs(opts)
5742 opts = pycompat.byteskwargs(opts)
5745 after, force = opts.get(b'after'), opts.get(b'force')
5743 after, force = opts.get(b'after'), opts.get(b'force')
5746 dryrun = opts.get(b'dry_run')
5744 dryrun = opts.get(b'dry_run')
5747 if not pats and not after:
5745 if not pats and not after:
5748 raise error.Abort(_(b'no files specified'))
5746 raise error.Abort(_(b'no files specified'))
5749
5747
5750 m = scmutil.match(repo[None], pats, opts)
5748 m = scmutil.match(repo[None], pats, opts)
5751 subrepos = opts.get(b'subrepos')
5749 subrepos = opts.get(b'subrepos')
5752 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5750 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5753 return cmdutil.remove(
5751 return cmdutil.remove(
5754 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5752 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5755 )
5753 )
5756
5754
5757
5755
5758 @command(
5756 @command(
5759 b'rename|move|mv',
5757 b'rename|move|mv',
5760 [
5758 [
5761 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5759 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5762 (
5760 (
5763 b'f',
5761 b'f',
5764 b'force',
5762 b'force',
5765 None,
5763 None,
5766 _(b'forcibly move over an existing managed file'),
5764 _(b'forcibly move over an existing managed file'),
5767 ),
5765 ),
5768 ]
5766 ]
5769 + walkopts
5767 + walkopts
5770 + dryrunopts,
5768 + dryrunopts,
5771 _(b'[OPTION]... SOURCE... DEST'),
5769 _(b'[OPTION]... SOURCE... DEST'),
5772 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5770 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5773 )
5771 )
5774 def rename(ui, repo, *pats, **opts):
5772 def rename(ui, repo, *pats, **opts):
5775 """rename files; equivalent of copy + remove
5773 """rename files; equivalent of copy + remove
5776
5774
5777 Mark dest as copies of sources; mark sources for deletion. If dest
5775 Mark dest as copies of sources; mark sources for deletion. If dest
5778 is a directory, copies are put in that directory. If dest is a
5776 is a directory, copies are put in that directory. If dest is a
5779 file, there can only be one source.
5777 file, there can only be one source.
5780
5778
5781 By default, this command copies the contents of files as they
5779 By default, this command copies the contents of files as they
5782 exist in the working directory. If invoked with -A/--after, the
5780 exist in the working directory. If invoked with -A/--after, the
5783 operation is recorded, but no copying is performed.
5781 operation is recorded, but no copying is performed.
5784
5782
5785 This command takes effect at the next commit. To undo a rename
5783 This command takes effect at the next commit. To undo a rename
5786 before that, see :hg:`revert`.
5784 before that, see :hg:`revert`.
5787
5785
5788 Returns 0 on success, 1 if errors are encountered.
5786 Returns 0 on success, 1 if errors are encountered.
5789 """
5787 """
5790 opts = pycompat.byteskwargs(opts)
5788 opts = pycompat.byteskwargs(opts)
5791 with repo.wlock(False):
5789 with repo.wlock(False):
5792 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5790 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5793
5791
5794
5792
5795 @command(
5793 @command(
5796 b'resolve',
5794 b'resolve',
5797 [
5795 [
5798 (b'a', b'all', None, _(b'select all unresolved files')),
5796 (b'a', b'all', None, _(b'select all unresolved files')),
5799 (b'l', b'list', None, _(b'list state of files needing merge')),
5797 (b'l', b'list', None, _(b'list state of files needing merge')),
5800 (b'm', b'mark', None, _(b'mark files as resolved')),
5798 (b'm', b'mark', None, _(b'mark files as resolved')),
5801 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5799 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5802 (b'n', b'no-status', None, _(b'hide status prefix')),
5800 (b'n', b'no-status', None, _(b'hide status prefix')),
5803 (b'', b're-merge', None, _(b're-merge files')),
5801 (b'', b're-merge', None, _(b're-merge files')),
5804 ]
5802 ]
5805 + mergetoolopts
5803 + mergetoolopts
5806 + walkopts
5804 + walkopts
5807 + formatteropts,
5805 + formatteropts,
5808 _(b'[OPTION]... [FILE]...'),
5806 _(b'[OPTION]... [FILE]...'),
5809 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5807 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5810 inferrepo=True,
5808 inferrepo=True,
5811 )
5809 )
5812 def resolve(ui, repo, *pats, **opts):
5810 def resolve(ui, repo, *pats, **opts):
5813 """redo merges or set/view the merge status of files
5811 """redo merges or set/view the merge status of files
5814
5812
5815 Merges with unresolved conflicts are often the result of
5813 Merges with unresolved conflicts are often the result of
5816 non-interactive merging using the ``internal:merge`` configuration
5814 non-interactive merging using the ``internal:merge`` configuration
5817 setting, or a command-line merge tool like ``diff3``. The resolve
5815 setting, or a command-line merge tool like ``diff3``. The resolve
5818 command is used to manage the files involved in a merge, after
5816 command is used to manage the files involved in a merge, after
5819 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5817 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5820 working directory must have two parents). See :hg:`help
5818 working directory must have two parents). See :hg:`help
5821 merge-tools` for information on configuring merge tools.
5819 merge-tools` for information on configuring merge tools.
5822
5820
5823 The resolve command can be used in the following ways:
5821 The resolve command can be used in the following ways:
5824
5822
5825 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5823 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5826 the specified files, discarding any previous merge attempts. Re-merging
5824 the specified files, discarding any previous merge attempts. Re-merging
5827 is not performed for files already marked as resolved. Use ``--all/-a``
5825 is not performed for files already marked as resolved. Use ``--all/-a``
5828 to select all unresolved files. ``--tool`` can be used to specify
5826 to select all unresolved files. ``--tool`` can be used to specify
5829 the merge tool used for the given files. It overrides the HGMERGE
5827 the merge tool used for the given files. It overrides the HGMERGE
5830 environment variable and your configuration files. Previous file
5828 environment variable and your configuration files. Previous file
5831 contents are saved with a ``.orig`` suffix.
5829 contents are saved with a ``.orig`` suffix.
5832
5830
5833 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5831 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5834 (e.g. after having manually fixed-up the files). The default is
5832 (e.g. after having manually fixed-up the files). The default is
5835 to mark all unresolved files.
5833 to mark all unresolved files.
5836
5834
5837 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5835 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5838 default is to mark all resolved files.
5836 default is to mark all resolved files.
5839
5837
5840 - :hg:`resolve -l`: list files which had or still have conflicts.
5838 - :hg:`resolve -l`: list files which had or still have conflicts.
5841 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5839 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5842 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5840 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5843 the list. See :hg:`help filesets` for details.
5841 the list. See :hg:`help filesets` for details.
5844
5842
5845 .. note::
5843 .. note::
5846
5844
5847 Mercurial will not let you commit files with unresolved merge
5845 Mercurial will not let you commit files with unresolved merge
5848 conflicts. You must use :hg:`resolve -m ...` before you can
5846 conflicts. You must use :hg:`resolve -m ...` before you can
5849 commit after a conflicting merge.
5847 commit after a conflicting merge.
5850
5848
5851 .. container:: verbose
5849 .. container:: verbose
5852
5850
5853 Template:
5851 Template:
5854
5852
5855 The following keywords are supported in addition to the common template
5853 The following keywords are supported in addition to the common template
5856 keywords and functions. See also :hg:`help templates`.
5854 keywords and functions. See also :hg:`help templates`.
5857
5855
5858 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5856 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5859 :path: String. Repository-absolute path of the file.
5857 :path: String. Repository-absolute path of the file.
5860
5858
5861 Returns 0 on success, 1 if any files fail a resolve attempt.
5859 Returns 0 on success, 1 if any files fail a resolve attempt.
5862 """
5860 """
5863
5861
5864 opts = pycompat.byteskwargs(opts)
5862 opts = pycompat.byteskwargs(opts)
5865 confirm = ui.configbool(b'commands', b'resolve.confirm')
5863 confirm = ui.configbool(b'commands', b'resolve.confirm')
5866 flaglist = b'all mark unmark list no_status re_merge'.split()
5864 flaglist = b'all mark unmark list no_status re_merge'.split()
5867 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5865 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5868
5866
5869 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5867 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5870 if actioncount > 1:
5868 if actioncount > 1:
5871 raise error.Abort(_(b"too many actions specified"))
5869 raise error.Abort(_(b"too many actions specified"))
5872 elif actioncount == 0 and ui.configbool(
5870 elif actioncount == 0 and ui.configbool(
5873 b'commands', b'resolve.explicit-re-merge'
5871 b'commands', b'resolve.explicit-re-merge'
5874 ):
5872 ):
5875 hint = _(b'use --mark, --unmark, --list or --re-merge')
5873 hint = _(b'use --mark, --unmark, --list or --re-merge')
5876 raise error.Abort(_(b'no action specified'), hint=hint)
5874 raise error.Abort(_(b'no action specified'), hint=hint)
5877 if pats and all:
5875 if pats and all:
5878 raise error.Abort(_(b"can't specify --all and patterns"))
5876 raise error.Abort(_(b"can't specify --all and patterns"))
5879 if not (all or pats or show or mark or unmark):
5877 if not (all or pats or show or mark or unmark):
5880 raise error.Abort(
5878 raise error.Abort(
5881 _(b'no files or directories specified'),
5879 _(b'no files or directories specified'),
5882 hint=b'use --all to re-merge all unresolved files',
5880 hint=b'use --all to re-merge all unresolved files',
5883 )
5881 )
5884
5882
5885 if confirm:
5883 if confirm:
5886 if all:
5884 if all:
5887 if ui.promptchoice(
5885 if ui.promptchoice(
5888 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5886 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5889 ):
5887 ):
5890 raise error.Abort(_(b'user quit'))
5888 raise error.Abort(_(b'user quit'))
5891 if mark and not pats:
5889 if mark and not pats:
5892 if ui.promptchoice(
5890 if ui.promptchoice(
5893 _(
5891 _(
5894 b'mark all unresolved files as resolved (yn)?'
5892 b'mark all unresolved files as resolved (yn)?'
5895 b'$$ &Yes $$ &No'
5893 b'$$ &Yes $$ &No'
5896 )
5894 )
5897 ):
5895 ):
5898 raise error.Abort(_(b'user quit'))
5896 raise error.Abort(_(b'user quit'))
5899 if unmark and not pats:
5897 if unmark and not pats:
5900 if ui.promptchoice(
5898 if ui.promptchoice(
5901 _(
5899 _(
5902 b'mark all resolved files as unresolved (yn)?'
5900 b'mark all resolved files as unresolved (yn)?'
5903 b'$$ &Yes $$ &No'
5901 b'$$ &Yes $$ &No'
5904 )
5902 )
5905 ):
5903 ):
5906 raise error.Abort(_(b'user quit'))
5904 raise error.Abort(_(b'user quit'))
5907
5905
5908 uipathfn = scmutil.getuipathfn(repo)
5906 uipathfn = scmutil.getuipathfn(repo)
5909
5907
5910 if show:
5908 if show:
5911 ui.pager(b'resolve')
5909 ui.pager(b'resolve')
5912 fm = ui.formatter(b'resolve', opts)
5910 fm = ui.formatter(b'resolve', opts)
5913 ms = mergemod.mergestate.read(repo)
5911 ms = mergemod.mergestate.read(repo)
5914 wctx = repo[None]
5912 wctx = repo[None]
5915 m = scmutil.match(wctx, pats, opts)
5913 m = scmutil.match(wctx, pats, opts)
5916
5914
5917 # Labels and keys based on merge state. Unresolved path conflicts show
5915 # Labels and keys based on merge state. Unresolved path conflicts show
5918 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5916 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5919 # resolved conflicts.
5917 # resolved conflicts.
5920 mergestateinfo = {
5918 mergestateinfo = {
5921 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5919 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5922 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5920 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5923 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5921 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5924 b'resolve.unresolved',
5922 b'resolve.unresolved',
5925 b'P',
5923 b'P',
5926 ),
5924 ),
5927 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5925 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5928 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5926 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5929 b'resolve.driverresolved',
5927 b'resolve.driverresolved',
5930 b'D',
5928 b'D',
5931 ),
5929 ),
5932 }
5930 }
5933
5931
5934 for f in ms:
5932 for f in ms:
5935 if not m(f):
5933 if not m(f):
5936 continue
5934 continue
5937
5935
5938 label, key = mergestateinfo[ms[f]]
5936 label, key = mergestateinfo[ms[f]]
5939 fm.startitem()
5937 fm.startitem()
5940 fm.context(ctx=wctx)
5938 fm.context(ctx=wctx)
5941 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5939 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5942 fm.data(path=f)
5940 fm.data(path=f)
5943 fm.plain(b'%s\n' % uipathfn(f), label=label)
5941 fm.plain(b'%s\n' % uipathfn(f), label=label)
5944 fm.end()
5942 fm.end()
5945 return 0
5943 return 0
5946
5944
5947 with repo.wlock():
5945 with repo.wlock():
5948 ms = mergemod.mergestate.read(repo)
5946 ms = mergemod.mergestate.read(repo)
5949
5947
5950 if not (ms.active() or repo.dirstate.p2() != nullid):
5948 if not (ms.active() or repo.dirstate.p2() != nullid):
5951 raise error.Abort(
5949 raise error.Abort(
5952 _(b'resolve command not applicable when not merging')
5950 _(b'resolve command not applicable when not merging')
5953 )
5951 )
5954
5952
5955 wctx = repo[None]
5953 wctx = repo[None]
5956
5954
5957 if (
5955 if (
5958 ms.mergedriver
5956 ms.mergedriver
5959 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5957 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5960 ):
5958 ):
5961 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5959 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5962 ms.commit()
5960 ms.commit()
5963 # allow mark and unmark to go through
5961 # allow mark and unmark to go through
5964 if not mark and not unmark and not proceed:
5962 if not mark and not unmark and not proceed:
5965 return 1
5963 return 1
5966
5964
5967 m = scmutil.match(wctx, pats, opts)
5965 m = scmutil.match(wctx, pats, opts)
5968 ret = 0
5966 ret = 0
5969 didwork = False
5967 didwork = False
5970 runconclude = False
5968 runconclude = False
5971
5969
5972 tocomplete = []
5970 tocomplete = []
5973 hasconflictmarkers = []
5971 hasconflictmarkers = []
5974 if mark:
5972 if mark:
5975 markcheck = ui.config(b'commands', b'resolve.mark-check')
5973 markcheck = ui.config(b'commands', b'resolve.mark-check')
5976 if markcheck not in [b'warn', b'abort']:
5974 if markcheck not in [b'warn', b'abort']:
5977 # Treat all invalid / unrecognized values as 'none'.
5975 # Treat all invalid / unrecognized values as 'none'.
5978 markcheck = False
5976 markcheck = False
5979 for f in ms:
5977 for f in ms:
5980 if not m(f):
5978 if not m(f):
5981 continue
5979 continue
5982
5980
5983 didwork = True
5981 didwork = True
5984
5982
5985 # don't let driver-resolved files be marked, and run the conclude
5983 # don't let driver-resolved files be marked, and run the conclude
5986 # step if asked to resolve
5984 # step if asked to resolve
5987 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5985 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5988 exact = m.exact(f)
5986 exact = m.exact(f)
5989 if mark:
5987 if mark:
5990 if exact:
5988 if exact:
5991 ui.warn(
5989 ui.warn(
5992 _(b'not marking %s as it is driver-resolved\n')
5990 _(b'not marking %s as it is driver-resolved\n')
5993 % uipathfn(f)
5991 % uipathfn(f)
5994 )
5992 )
5995 elif unmark:
5993 elif unmark:
5996 if exact:
5994 if exact:
5997 ui.warn(
5995 ui.warn(
5998 _(b'not unmarking %s as it is driver-resolved\n')
5996 _(b'not unmarking %s as it is driver-resolved\n')
5999 % uipathfn(f)
5997 % uipathfn(f)
6000 )
5998 )
6001 else:
5999 else:
6002 runconclude = True
6000 runconclude = True
6003 continue
6001 continue
6004
6002
6005 # path conflicts must be resolved manually
6003 # path conflicts must be resolved manually
6006 if ms[f] in (
6004 if ms[f] in (
6007 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6005 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6008 mergemod.MERGE_RECORD_RESOLVED_PATH,
6006 mergemod.MERGE_RECORD_RESOLVED_PATH,
6009 ):
6007 ):
6010 if mark:
6008 if mark:
6011 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6009 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6012 elif unmark:
6010 elif unmark:
6013 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6011 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6014 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6012 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6015 ui.warn(
6013 ui.warn(
6016 _(b'%s: path conflict must be resolved manually\n')
6014 _(b'%s: path conflict must be resolved manually\n')
6017 % uipathfn(f)
6015 % uipathfn(f)
6018 )
6016 )
6019 continue
6017 continue
6020
6018
6021 if mark:
6019 if mark:
6022 if markcheck:
6020 if markcheck:
6023 fdata = repo.wvfs.tryread(f)
6021 fdata = repo.wvfs.tryread(f)
6024 if (
6022 if (
6025 filemerge.hasconflictmarkers(fdata)
6023 filemerge.hasconflictmarkers(fdata)
6026 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6024 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6027 ):
6025 ):
6028 hasconflictmarkers.append(f)
6026 hasconflictmarkers.append(f)
6029 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6027 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6030 elif unmark:
6028 elif unmark:
6031 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6029 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6032 else:
6030 else:
6033 # backup pre-resolve (merge uses .orig for its own purposes)
6031 # backup pre-resolve (merge uses .orig for its own purposes)
6034 a = repo.wjoin(f)
6032 a = repo.wjoin(f)
6035 try:
6033 try:
6036 util.copyfile(a, a + b".resolve")
6034 util.copyfile(a, a + b".resolve")
6037 except (IOError, OSError) as inst:
6035 except (IOError, OSError) as inst:
6038 if inst.errno != errno.ENOENT:
6036 if inst.errno != errno.ENOENT:
6039 raise
6037 raise
6040
6038
6041 try:
6039 try:
6042 # preresolve file
6040 # preresolve file
6043 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6041 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6044 with ui.configoverride(overrides, b'resolve'):
6042 with ui.configoverride(overrides, b'resolve'):
6045 complete, r = ms.preresolve(f, wctx)
6043 complete, r = ms.preresolve(f, wctx)
6046 if not complete:
6044 if not complete:
6047 tocomplete.append(f)
6045 tocomplete.append(f)
6048 elif r:
6046 elif r:
6049 ret = 1
6047 ret = 1
6050 finally:
6048 finally:
6051 ms.commit()
6049 ms.commit()
6052
6050
6053 # replace filemerge's .orig file with our resolve file, but only
6051 # replace filemerge's .orig file with our resolve file, but only
6054 # for merges that are complete
6052 # for merges that are complete
6055 if complete:
6053 if complete:
6056 try:
6054 try:
6057 util.rename(
6055 util.rename(
6058 a + b".resolve", scmutil.backuppath(ui, repo, f)
6056 a + b".resolve", scmutil.backuppath(ui, repo, f)
6059 )
6057 )
6060 except OSError as inst:
6058 except OSError as inst:
6061 if inst.errno != errno.ENOENT:
6059 if inst.errno != errno.ENOENT:
6062 raise
6060 raise
6063
6061
6064 if hasconflictmarkers:
6062 if hasconflictmarkers:
6065 ui.warn(
6063 ui.warn(
6066 _(
6064 _(
6067 b'warning: the following files still have conflict '
6065 b'warning: the following files still have conflict '
6068 b'markers:\n'
6066 b'markers:\n'
6069 )
6067 )
6070 + b''.join(
6068 + b''.join(
6071 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6069 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6072 )
6070 )
6073 )
6071 )
6074 if markcheck == b'abort' and not all and not pats:
6072 if markcheck == b'abort' and not all and not pats:
6075 raise error.Abort(
6073 raise error.Abort(
6076 _(b'conflict markers detected'),
6074 _(b'conflict markers detected'),
6077 hint=_(b'use --all to mark anyway'),
6075 hint=_(b'use --all to mark anyway'),
6078 )
6076 )
6079
6077
6080 for f in tocomplete:
6078 for f in tocomplete:
6081 try:
6079 try:
6082 # resolve file
6080 # resolve file
6083 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6081 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6084 with ui.configoverride(overrides, b'resolve'):
6082 with ui.configoverride(overrides, b'resolve'):
6085 r = ms.resolve(f, wctx)
6083 r = ms.resolve(f, wctx)
6086 if r:
6084 if r:
6087 ret = 1
6085 ret = 1
6088 finally:
6086 finally:
6089 ms.commit()
6087 ms.commit()
6090
6088
6091 # replace filemerge's .orig file with our resolve file
6089 # replace filemerge's .orig file with our resolve file
6092 a = repo.wjoin(f)
6090 a = repo.wjoin(f)
6093 try:
6091 try:
6094 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6092 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6095 except OSError as inst:
6093 except OSError as inst:
6096 if inst.errno != errno.ENOENT:
6094 if inst.errno != errno.ENOENT:
6097 raise
6095 raise
6098
6096
6099 ms.commit()
6097 ms.commit()
6100 ms.recordactions()
6098 ms.recordactions()
6101
6099
6102 if not didwork and pats:
6100 if not didwork and pats:
6103 hint = None
6101 hint = None
6104 if not any([p for p in pats if p.find(b':') >= 0]):
6102 if not any([p for p in pats if p.find(b':') >= 0]):
6105 pats = [b'path:%s' % p for p in pats]
6103 pats = [b'path:%s' % p for p in pats]
6106 m = scmutil.match(wctx, pats, opts)
6104 m = scmutil.match(wctx, pats, opts)
6107 for f in ms:
6105 for f in ms:
6108 if not m(f):
6106 if not m(f):
6109 continue
6107 continue
6110
6108
6111 def flag(o):
6109 def flag(o):
6112 if o == b're_merge':
6110 if o == b're_merge':
6113 return b'--re-merge '
6111 return b'--re-merge '
6114 return b'-%s ' % o[0:1]
6112 return b'-%s ' % o[0:1]
6115
6113
6116 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6114 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6117 hint = _(b"(try: hg resolve %s%s)\n") % (
6115 hint = _(b"(try: hg resolve %s%s)\n") % (
6118 flags,
6116 flags,
6119 b' '.join(pats),
6117 b' '.join(pats),
6120 )
6118 )
6121 break
6119 break
6122 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6120 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6123 if hint:
6121 if hint:
6124 ui.warn(hint)
6122 ui.warn(hint)
6125 elif ms.mergedriver and ms.mdstate() != b's':
6123 elif ms.mergedriver and ms.mdstate() != b's':
6126 # run conclude step when either a driver-resolved file is requested
6124 # run conclude step when either a driver-resolved file is requested
6127 # or there are no driver-resolved files
6125 # or there are no driver-resolved files
6128 # we can't use 'ret' to determine whether any files are unresolved
6126 # we can't use 'ret' to determine whether any files are unresolved
6129 # because we might not have tried to resolve some
6127 # because we might not have tried to resolve some
6130 if (runconclude or not list(ms.driverresolved())) and not list(
6128 if (runconclude or not list(ms.driverresolved())) and not list(
6131 ms.unresolved()
6129 ms.unresolved()
6132 ):
6130 ):
6133 proceed = mergemod.driverconclude(repo, ms, wctx)
6131 proceed = mergemod.driverconclude(repo, ms, wctx)
6134 ms.commit()
6132 ms.commit()
6135 if not proceed:
6133 if not proceed:
6136 return 1
6134 return 1
6137
6135
6138 # Nudge users into finishing an unfinished operation
6136 # Nudge users into finishing an unfinished operation
6139 unresolvedf = list(ms.unresolved())
6137 unresolvedf = list(ms.unresolved())
6140 driverresolvedf = list(ms.driverresolved())
6138 driverresolvedf = list(ms.driverresolved())
6141 if not unresolvedf and not driverresolvedf:
6139 if not unresolvedf and not driverresolvedf:
6142 ui.status(_(b'(no more unresolved files)\n'))
6140 ui.status(_(b'(no more unresolved files)\n'))
6143 cmdutil.checkafterresolved(repo)
6141 cmdutil.checkafterresolved(repo)
6144 elif not unresolvedf:
6142 elif not unresolvedf:
6145 ui.status(
6143 ui.status(
6146 _(
6144 _(
6147 b'(no more unresolved files -- '
6145 b'(no more unresolved files -- '
6148 b'run "hg resolve --all" to conclude)\n'
6146 b'run "hg resolve --all" to conclude)\n'
6149 )
6147 )
6150 )
6148 )
6151
6149
6152 return ret
6150 return ret
6153
6151
6154
6152
6155 @command(
6153 @command(
6156 b'revert',
6154 b'revert',
6157 [
6155 [
6158 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6156 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6159 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6157 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6160 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6158 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6161 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6159 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6162 (b'i', b'interactive', None, _(b'interactively select the changes')),
6160 (b'i', b'interactive', None, _(b'interactively select the changes')),
6163 ]
6161 ]
6164 + walkopts
6162 + walkopts
6165 + dryrunopts,
6163 + dryrunopts,
6166 _(b'[OPTION]... [-r REV] [NAME]...'),
6164 _(b'[OPTION]... [-r REV] [NAME]...'),
6167 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6165 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6168 )
6166 )
6169 def revert(ui, repo, *pats, **opts):
6167 def revert(ui, repo, *pats, **opts):
6170 """restore files to their checkout state
6168 """restore files to their checkout state
6171
6169
6172 .. note::
6170 .. note::
6173
6171
6174 To check out earlier revisions, you should use :hg:`update REV`.
6172 To check out earlier revisions, you should use :hg:`update REV`.
6175 To cancel an uncommitted merge (and lose your changes),
6173 To cancel an uncommitted merge (and lose your changes),
6176 use :hg:`merge --abort`.
6174 use :hg:`merge --abort`.
6177
6175
6178 With no revision specified, revert the specified files or directories
6176 With no revision specified, revert the specified files or directories
6179 to the contents they had in the parent of the working directory.
6177 to the contents they had in the parent of the working directory.
6180 This restores the contents of files to an unmodified
6178 This restores the contents of files to an unmodified
6181 state and unschedules adds, removes, copies, and renames. If the
6179 state and unschedules adds, removes, copies, and renames. If the
6182 working directory has two parents, you must explicitly specify a
6180 working directory has two parents, you must explicitly specify a
6183 revision.
6181 revision.
6184
6182
6185 Using the -r/--rev or -d/--date options, revert the given files or
6183 Using the -r/--rev or -d/--date options, revert the given files or
6186 directories to their states as of a specific revision. Because
6184 directories to their states as of a specific revision. Because
6187 revert does not change the working directory parents, this will
6185 revert does not change the working directory parents, this will
6188 cause these files to appear modified. This can be helpful to "back
6186 cause these files to appear modified. This can be helpful to "back
6189 out" some or all of an earlier change. See :hg:`backout` for a
6187 out" some or all of an earlier change. See :hg:`backout` for a
6190 related method.
6188 related method.
6191
6189
6192 Modified files are saved with a .orig suffix before reverting.
6190 Modified files are saved with a .orig suffix before reverting.
6193 To disable these backups, use --no-backup. It is possible to store
6191 To disable these backups, use --no-backup. It is possible to store
6194 the backup files in a custom directory relative to the root of the
6192 the backup files in a custom directory relative to the root of the
6195 repository by setting the ``ui.origbackuppath`` configuration
6193 repository by setting the ``ui.origbackuppath`` configuration
6196 option.
6194 option.
6197
6195
6198 See :hg:`help dates` for a list of formats valid for -d/--date.
6196 See :hg:`help dates` for a list of formats valid for -d/--date.
6199
6197
6200 See :hg:`help backout` for a way to reverse the effect of an
6198 See :hg:`help backout` for a way to reverse the effect of an
6201 earlier changeset.
6199 earlier changeset.
6202
6200
6203 Returns 0 on success.
6201 Returns 0 on success.
6204 """
6202 """
6205
6203
6206 opts = pycompat.byteskwargs(opts)
6204 opts = pycompat.byteskwargs(opts)
6207 if opts.get(b"date"):
6205 if opts.get(b"date"):
6208 if opts.get(b"rev"):
6206 if opts.get(b"rev"):
6209 raise error.Abort(_(b"you can't specify a revision and a date"))
6207 raise error.Abort(_(b"you can't specify a revision and a date"))
6210 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6208 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6211
6209
6212 parent, p2 = repo.dirstate.parents()
6210 parent, p2 = repo.dirstate.parents()
6213 if not opts.get(b'rev') and p2 != nullid:
6211 if not opts.get(b'rev') and p2 != nullid:
6214 # revert after merge is a trap for new users (issue2915)
6212 # revert after merge is a trap for new users (issue2915)
6215 raise error.Abort(
6213 raise error.Abort(
6216 _(b'uncommitted merge with no revision specified'),
6214 _(b'uncommitted merge with no revision specified'),
6217 hint=_(b"use 'hg update' or see 'hg help revert'"),
6215 hint=_(b"use 'hg update' or see 'hg help revert'"),
6218 )
6216 )
6219
6217
6220 rev = opts.get(b'rev')
6218 rev = opts.get(b'rev')
6221 if rev:
6219 if rev:
6222 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6220 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6223 ctx = scmutil.revsingle(repo, rev)
6221 ctx = scmutil.revsingle(repo, rev)
6224
6222
6225 if not (
6223 if not (
6226 pats
6224 pats
6227 or opts.get(b'include')
6225 or opts.get(b'include')
6228 or opts.get(b'exclude')
6226 or opts.get(b'exclude')
6229 or opts.get(b'all')
6227 or opts.get(b'all')
6230 or opts.get(b'interactive')
6228 or opts.get(b'interactive')
6231 ):
6229 ):
6232 msg = _(b"no files or directories specified")
6230 msg = _(b"no files or directories specified")
6233 if p2 != nullid:
6231 if p2 != nullid:
6234 hint = _(
6232 hint = _(
6235 b"uncommitted merge, use --all to discard all changes,"
6233 b"uncommitted merge, use --all to discard all changes,"
6236 b" or 'hg update -C .' to abort the merge"
6234 b" or 'hg update -C .' to abort the merge"
6237 )
6235 )
6238 raise error.Abort(msg, hint=hint)
6236 raise error.Abort(msg, hint=hint)
6239 dirty = any(repo.status())
6237 dirty = any(repo.status())
6240 node = ctx.node()
6238 node = ctx.node()
6241 if node != parent:
6239 if node != parent:
6242 if dirty:
6240 if dirty:
6243 hint = (
6241 hint = (
6244 _(
6242 _(
6245 b"uncommitted changes, use --all to discard all"
6243 b"uncommitted changes, use --all to discard all"
6246 b" changes, or 'hg update %d' to update"
6244 b" changes, or 'hg update %d' to update"
6247 )
6245 )
6248 % ctx.rev()
6246 % ctx.rev()
6249 )
6247 )
6250 else:
6248 else:
6251 hint = (
6249 hint = (
6252 _(
6250 _(
6253 b"use --all to revert all files,"
6251 b"use --all to revert all files,"
6254 b" or 'hg update %d' to update"
6252 b" or 'hg update %d' to update"
6255 )
6253 )
6256 % ctx.rev()
6254 % ctx.rev()
6257 )
6255 )
6258 elif dirty:
6256 elif dirty:
6259 hint = _(b"uncommitted changes, use --all to discard all changes")
6257 hint = _(b"uncommitted changes, use --all to discard all changes")
6260 else:
6258 else:
6261 hint = _(b"use --all to revert all files")
6259 hint = _(b"use --all to revert all files")
6262 raise error.Abort(msg, hint=hint)
6260 raise error.Abort(msg, hint=hint)
6263
6261
6264 return cmdutil.revert(
6262 return cmdutil.revert(
6265 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6263 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6266 )
6264 )
6267
6265
6268
6266
6269 @command(
6267 @command(
6270 b'rollback',
6268 b'rollback',
6271 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6269 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6272 helpcategory=command.CATEGORY_MAINTENANCE,
6270 helpcategory=command.CATEGORY_MAINTENANCE,
6273 )
6271 )
6274 def rollback(ui, repo, **opts):
6272 def rollback(ui, repo, **opts):
6275 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6273 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6276
6274
6277 Please use :hg:`commit --amend` instead of rollback to correct
6275 Please use :hg:`commit --amend` instead of rollback to correct
6278 mistakes in the last commit.
6276 mistakes in the last commit.
6279
6277
6280 This command should be used with care. There is only one level of
6278 This command should be used with care. There is only one level of
6281 rollback, and there is no way to undo a rollback. It will also
6279 rollback, and there is no way to undo a rollback. It will also
6282 restore the dirstate at the time of the last transaction, losing
6280 restore the dirstate at the time of the last transaction, losing
6283 any dirstate changes since that time. This command does not alter
6281 any dirstate changes since that time. This command does not alter
6284 the working directory.
6282 the working directory.
6285
6283
6286 Transactions are used to encapsulate the effects of all commands
6284 Transactions are used to encapsulate the effects of all commands
6287 that create new changesets or propagate existing changesets into a
6285 that create new changesets or propagate existing changesets into a
6288 repository.
6286 repository.
6289
6287
6290 .. container:: verbose
6288 .. container:: verbose
6291
6289
6292 For example, the following commands are transactional, and their
6290 For example, the following commands are transactional, and their
6293 effects can be rolled back:
6291 effects can be rolled back:
6294
6292
6295 - commit
6293 - commit
6296 - import
6294 - import
6297 - pull
6295 - pull
6298 - push (with this repository as the destination)
6296 - push (with this repository as the destination)
6299 - unbundle
6297 - unbundle
6300
6298
6301 To avoid permanent data loss, rollback will refuse to rollback a
6299 To avoid permanent data loss, rollback will refuse to rollback a
6302 commit transaction if it isn't checked out. Use --force to
6300 commit transaction if it isn't checked out. Use --force to
6303 override this protection.
6301 override this protection.
6304
6302
6305 The rollback command can be entirely disabled by setting the
6303 The rollback command can be entirely disabled by setting the
6306 ``ui.rollback`` configuration setting to false. If you're here
6304 ``ui.rollback`` configuration setting to false. If you're here
6307 because you want to use rollback and it's disabled, you can
6305 because you want to use rollback and it's disabled, you can
6308 re-enable the command by setting ``ui.rollback`` to true.
6306 re-enable the command by setting ``ui.rollback`` to true.
6309
6307
6310 This command is not intended for use on public repositories. Once
6308 This command is not intended for use on public repositories. Once
6311 changes are visible for pull by other users, rolling a transaction
6309 changes are visible for pull by other users, rolling a transaction
6312 back locally is ineffective (someone else may already have pulled
6310 back locally is ineffective (someone else may already have pulled
6313 the changes). Furthermore, a race is possible with readers of the
6311 the changes). Furthermore, a race is possible with readers of the
6314 repository; for example an in-progress pull from the repository
6312 repository; for example an in-progress pull from the repository
6315 may fail if a rollback is performed.
6313 may fail if a rollback is performed.
6316
6314
6317 Returns 0 on success, 1 if no rollback data is available.
6315 Returns 0 on success, 1 if no rollback data is available.
6318 """
6316 """
6319 if not ui.configbool(b'ui', b'rollback'):
6317 if not ui.configbool(b'ui', b'rollback'):
6320 raise error.Abort(
6318 raise error.Abort(
6321 _(b'rollback is disabled because it is unsafe'),
6319 _(b'rollback is disabled because it is unsafe'),
6322 hint=b'see `hg help -v rollback` for information',
6320 hint=b'see `hg help -v rollback` for information',
6323 )
6321 )
6324 return repo.rollback(dryrun=opts.get(r'dry_run'), force=opts.get(r'force'))
6322 return repo.rollback(dryrun=opts.get(r'dry_run'), force=opts.get(r'force'))
6325
6323
6326
6324
6327 @command(
6325 @command(
6328 b'root',
6326 b'root',
6329 [] + formatteropts,
6327 [] + formatteropts,
6330 intents={INTENT_READONLY},
6328 intents={INTENT_READONLY},
6331 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6329 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6332 )
6330 )
6333 def root(ui, repo, **opts):
6331 def root(ui, repo, **opts):
6334 """print the root (top) of the current working directory
6332 """print the root (top) of the current working directory
6335
6333
6336 Print the root directory of the current repository.
6334 Print the root directory of the current repository.
6337
6335
6338 .. container:: verbose
6336 .. container:: verbose
6339
6337
6340 Template:
6338 Template:
6341
6339
6342 The following keywords are supported in addition to the common template
6340 The following keywords are supported in addition to the common template
6343 keywords and functions. See also :hg:`help templates`.
6341 keywords and functions. See also :hg:`help templates`.
6344
6342
6345 :hgpath: String. Path to the .hg directory.
6343 :hgpath: String. Path to the .hg directory.
6346 :storepath: String. Path to the directory holding versioned data.
6344 :storepath: String. Path to the directory holding versioned data.
6347
6345
6348 Returns 0 on success.
6346 Returns 0 on success.
6349 """
6347 """
6350 opts = pycompat.byteskwargs(opts)
6348 opts = pycompat.byteskwargs(opts)
6351 with ui.formatter(b'root', opts) as fm:
6349 with ui.formatter(b'root', opts) as fm:
6352 fm.startitem()
6350 fm.startitem()
6353 fm.write(b'reporoot', b'%s\n', repo.root)
6351 fm.write(b'reporoot', b'%s\n', repo.root)
6354 fm.data(hgpath=repo.path, storepath=repo.spath)
6352 fm.data(hgpath=repo.path, storepath=repo.spath)
6355
6353
6356
6354
6357 @command(
6355 @command(
6358 b'serve',
6356 b'serve',
6359 [
6357 [
6360 (
6358 (
6361 b'A',
6359 b'A',
6362 b'accesslog',
6360 b'accesslog',
6363 b'',
6361 b'',
6364 _(b'name of access log file to write to'),
6362 _(b'name of access log file to write to'),
6365 _(b'FILE'),
6363 _(b'FILE'),
6366 ),
6364 ),
6367 (b'd', b'daemon', None, _(b'run server in background')),
6365 (b'd', b'daemon', None, _(b'run server in background')),
6368 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6366 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6369 (
6367 (
6370 b'E',
6368 b'E',
6371 b'errorlog',
6369 b'errorlog',
6372 b'',
6370 b'',
6373 _(b'name of error log file to write to'),
6371 _(b'name of error log file to write to'),
6374 _(b'FILE'),
6372 _(b'FILE'),
6375 ),
6373 ),
6376 # use string type, then we can check if something was passed
6374 # use string type, then we can check if something was passed
6377 (
6375 (
6378 b'p',
6376 b'p',
6379 b'port',
6377 b'port',
6380 b'',
6378 b'',
6381 _(b'port to listen on (default: 8000)'),
6379 _(b'port to listen on (default: 8000)'),
6382 _(b'PORT'),
6380 _(b'PORT'),
6383 ),
6381 ),
6384 (
6382 (
6385 b'a',
6383 b'a',
6386 b'address',
6384 b'address',
6387 b'',
6385 b'',
6388 _(b'address to listen on (default: all interfaces)'),
6386 _(b'address to listen on (default: all interfaces)'),
6389 _(b'ADDR'),
6387 _(b'ADDR'),
6390 ),
6388 ),
6391 (
6389 (
6392 b'',
6390 b'',
6393 b'prefix',
6391 b'prefix',
6394 b'',
6392 b'',
6395 _(b'prefix path to serve from (default: server root)'),
6393 _(b'prefix path to serve from (default: server root)'),
6396 _(b'PREFIX'),
6394 _(b'PREFIX'),
6397 ),
6395 ),
6398 (
6396 (
6399 b'n',
6397 b'n',
6400 b'name',
6398 b'name',
6401 b'',
6399 b'',
6402 _(b'name to show in web pages (default: working directory)'),
6400 _(b'name to show in web pages (default: working directory)'),
6403 _(b'NAME'),
6401 _(b'NAME'),
6404 ),
6402 ),
6405 (
6403 (
6406 b'',
6404 b'',
6407 b'web-conf',
6405 b'web-conf',
6408 b'',
6406 b'',
6409 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6407 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6410 _(b'FILE'),
6408 _(b'FILE'),
6411 ),
6409 ),
6412 (
6410 (
6413 b'',
6411 b'',
6414 b'webdir-conf',
6412 b'webdir-conf',
6415 b'',
6413 b'',
6416 _(b'name of the hgweb config file (DEPRECATED)'),
6414 _(b'name of the hgweb config file (DEPRECATED)'),
6417 _(b'FILE'),
6415 _(b'FILE'),
6418 ),
6416 ),
6419 (
6417 (
6420 b'',
6418 b'',
6421 b'pid-file',
6419 b'pid-file',
6422 b'',
6420 b'',
6423 _(b'name of file to write process ID to'),
6421 _(b'name of file to write process ID to'),
6424 _(b'FILE'),
6422 _(b'FILE'),
6425 ),
6423 ),
6426 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6424 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6427 (
6425 (
6428 b'',
6426 b'',
6429 b'cmdserver',
6427 b'cmdserver',
6430 b'',
6428 b'',
6431 _(b'for remote clients (ADVANCED)'),
6429 _(b'for remote clients (ADVANCED)'),
6432 _(b'MODE'),
6430 _(b'MODE'),
6433 ),
6431 ),
6434 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6432 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6435 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6433 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6436 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6434 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6437 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6435 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6438 (b'', b'print-url', None, _(b'start and print only the URL')),
6436 (b'', b'print-url', None, _(b'start and print only the URL')),
6439 ]
6437 ]
6440 + subrepoopts,
6438 + subrepoopts,
6441 _(b'[OPTION]...'),
6439 _(b'[OPTION]...'),
6442 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6440 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6443 helpbasic=True,
6441 helpbasic=True,
6444 optionalrepo=True,
6442 optionalrepo=True,
6445 )
6443 )
6446 def serve(ui, repo, **opts):
6444 def serve(ui, repo, **opts):
6447 """start stand-alone webserver
6445 """start stand-alone webserver
6448
6446
6449 Start a local HTTP repository browser and pull server. You can use
6447 Start a local HTTP repository browser and pull server. You can use
6450 this for ad-hoc sharing and browsing of repositories. It is
6448 this for ad-hoc sharing and browsing of repositories. It is
6451 recommended to use a real web server to serve a repository for
6449 recommended to use a real web server to serve a repository for
6452 longer periods of time.
6450 longer periods of time.
6453
6451
6454 Please note that the server does not implement access control.
6452 Please note that the server does not implement access control.
6455 This means that, by default, anybody can read from the server and
6453 This means that, by default, anybody can read from the server and
6456 nobody can write to it by default. Set the ``web.allow-push``
6454 nobody can write to it by default. Set the ``web.allow-push``
6457 option to ``*`` to allow everybody to push to the server. You
6455 option to ``*`` to allow everybody to push to the server. You
6458 should use a real web server if you need to authenticate users.
6456 should use a real web server if you need to authenticate users.
6459
6457
6460 By default, the server logs accesses to stdout and errors to
6458 By default, the server logs accesses to stdout and errors to
6461 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6459 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6462 files.
6460 files.
6463
6461
6464 To have the server choose a free port number to listen on, specify
6462 To have the server choose a free port number to listen on, specify
6465 a port number of 0; in this case, the server will print the port
6463 a port number of 0; in this case, the server will print the port
6466 number it uses.
6464 number it uses.
6467
6465
6468 Returns 0 on success.
6466 Returns 0 on success.
6469 """
6467 """
6470
6468
6471 opts = pycompat.byteskwargs(opts)
6469 opts = pycompat.byteskwargs(opts)
6472 if opts[b"stdio"] and opts[b"cmdserver"]:
6470 if opts[b"stdio"] and opts[b"cmdserver"]:
6473 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6471 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6474 if opts[b"print_url"] and ui.verbose:
6472 if opts[b"print_url"] and ui.verbose:
6475 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6473 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6476
6474
6477 if opts[b"stdio"]:
6475 if opts[b"stdio"]:
6478 if repo is None:
6476 if repo is None:
6479 raise error.RepoError(
6477 raise error.RepoError(
6480 _(b"there is no Mercurial repository here (.hg not found)")
6478 _(b"there is no Mercurial repository here (.hg not found)")
6481 )
6479 )
6482 s = wireprotoserver.sshserver(ui, repo)
6480 s = wireprotoserver.sshserver(ui, repo)
6483 s.serve_forever()
6481 s.serve_forever()
6484
6482
6485 service = server.createservice(ui, repo, opts)
6483 service = server.createservice(ui, repo, opts)
6486 return server.runservice(opts, initfn=service.init, runfn=service.run)
6484 return server.runservice(opts, initfn=service.init, runfn=service.run)
6487
6485
6488
6486
6489 @command(
6487 @command(
6490 b'shelve',
6488 b'shelve',
6491 [
6489 [
6492 (
6490 (
6493 b'A',
6491 b'A',
6494 b'addremove',
6492 b'addremove',
6495 None,
6493 None,
6496 _(b'mark new/missing files as added/removed before shelving'),
6494 _(b'mark new/missing files as added/removed before shelving'),
6497 ),
6495 ),
6498 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6496 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6499 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6497 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6500 (
6498 (
6501 b'',
6499 b'',
6502 b'date',
6500 b'date',
6503 b'',
6501 b'',
6504 _(b'shelve with the specified commit date'),
6502 _(b'shelve with the specified commit date'),
6505 _(b'DATE'),
6503 _(b'DATE'),
6506 ),
6504 ),
6507 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6505 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6508 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6506 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6509 (
6507 (
6510 b'k',
6508 b'k',
6511 b'keep',
6509 b'keep',
6512 False,
6510 False,
6513 _(b'shelve, but keep changes in the working directory'),
6511 _(b'shelve, but keep changes in the working directory'),
6514 ),
6512 ),
6515 (b'l', b'list', None, _(b'list current shelves')),
6513 (b'l', b'list', None, _(b'list current shelves')),
6516 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6514 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6517 (
6515 (
6518 b'n',
6516 b'n',
6519 b'name',
6517 b'name',
6520 b'',
6518 b'',
6521 _(b'use the given name for the shelved commit'),
6519 _(b'use the given name for the shelved commit'),
6522 _(b'NAME'),
6520 _(b'NAME'),
6523 ),
6521 ),
6524 (
6522 (
6525 b'p',
6523 b'p',
6526 b'patch',
6524 b'patch',
6527 None,
6525 None,
6528 _(
6526 _(
6529 b'output patches for changes (provide the names of the shelved '
6527 b'output patches for changes (provide the names of the shelved '
6530 b'changes as positional arguments)'
6528 b'changes as positional arguments)'
6531 ),
6529 ),
6532 ),
6530 ),
6533 (b'i', b'interactive', None, _(b'interactive mode')),
6531 (b'i', b'interactive', None, _(b'interactive mode')),
6534 (
6532 (
6535 b'',
6533 b'',
6536 b'stat',
6534 b'stat',
6537 None,
6535 None,
6538 _(
6536 _(
6539 b'output diffstat-style summary of changes (provide the names of '
6537 b'output diffstat-style summary of changes (provide the names of '
6540 b'the shelved changes as positional arguments)'
6538 b'the shelved changes as positional arguments)'
6541 ),
6539 ),
6542 ),
6540 ),
6543 ]
6541 ]
6544 + cmdutil.walkopts,
6542 + cmdutil.walkopts,
6545 _(b'hg shelve [OPTION]... [FILE]...'),
6543 _(b'hg shelve [OPTION]... [FILE]...'),
6546 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6544 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6547 )
6545 )
6548 def shelve(ui, repo, *pats, **opts):
6546 def shelve(ui, repo, *pats, **opts):
6549 '''save and set aside changes from the working directory
6547 '''save and set aside changes from the working directory
6550
6548
6551 Shelving takes files that "hg status" reports as not clean, saves
6549 Shelving takes files that "hg status" reports as not clean, saves
6552 the modifications to a bundle (a shelved change), and reverts the
6550 the modifications to a bundle (a shelved change), and reverts the
6553 files so that their state in the working directory becomes clean.
6551 files so that their state in the working directory becomes clean.
6554
6552
6555 To restore these changes to the working directory, using "hg
6553 To restore these changes to the working directory, using "hg
6556 unshelve"; this will work even if you switch to a different
6554 unshelve"; this will work even if you switch to a different
6557 commit.
6555 commit.
6558
6556
6559 When no files are specified, "hg shelve" saves all not-clean
6557 When no files are specified, "hg shelve" saves all not-clean
6560 files. If specific files or directories are named, only changes to
6558 files. If specific files or directories are named, only changes to
6561 those files are shelved.
6559 those files are shelved.
6562
6560
6563 In bare shelve (when no files are specified, without interactive,
6561 In bare shelve (when no files are specified, without interactive,
6564 include and exclude option), shelving remembers information if the
6562 include and exclude option), shelving remembers information if the
6565 working directory was on newly created branch, in other words working
6563 working directory was on newly created branch, in other words working
6566 directory was on different branch than its first parent. In this
6564 directory was on different branch than its first parent. In this
6567 situation unshelving restores branch information to the working directory.
6565 situation unshelving restores branch information to the working directory.
6568
6566
6569 Each shelved change has a name that makes it easier to find later.
6567 Each shelved change has a name that makes it easier to find later.
6570 The name of a shelved change defaults to being based on the active
6568 The name of a shelved change defaults to being based on the active
6571 bookmark, or if there is no active bookmark, the current named
6569 bookmark, or if there is no active bookmark, the current named
6572 branch. To specify a different name, use ``--name``.
6570 branch. To specify a different name, use ``--name``.
6573
6571
6574 To see a list of existing shelved changes, use the ``--list``
6572 To see a list of existing shelved changes, use the ``--list``
6575 option. For each shelved change, this will print its name, age,
6573 option. For each shelved change, this will print its name, age,
6576 and description; use ``--patch`` or ``--stat`` for more details.
6574 and description; use ``--patch`` or ``--stat`` for more details.
6577
6575
6578 To delete specific shelved changes, use ``--delete``. To delete
6576 To delete specific shelved changes, use ``--delete``. To delete
6579 all shelved changes, use ``--cleanup``.
6577 all shelved changes, use ``--cleanup``.
6580 '''
6578 '''
6581 opts = pycompat.byteskwargs(opts)
6579 opts = pycompat.byteskwargs(opts)
6582 allowables = [
6580 allowables = [
6583 (b'addremove', {b'create'}), # 'create' is pseudo action
6581 (b'addremove', {b'create'}), # 'create' is pseudo action
6584 (b'unknown', {b'create'}),
6582 (b'unknown', {b'create'}),
6585 (b'cleanup', {b'cleanup'}),
6583 (b'cleanup', {b'cleanup'}),
6586 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6584 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6587 (b'delete', {b'delete'}),
6585 (b'delete', {b'delete'}),
6588 (b'edit', {b'create'}),
6586 (b'edit', {b'create'}),
6589 (b'keep', {b'create'}),
6587 (b'keep', {b'create'}),
6590 (b'list', {b'list'}),
6588 (b'list', {b'list'}),
6591 (b'message', {b'create'}),
6589 (b'message', {b'create'}),
6592 (b'name', {b'create'}),
6590 (b'name', {b'create'}),
6593 (b'patch', {b'patch', b'list'}),
6591 (b'patch', {b'patch', b'list'}),
6594 (b'stat', {b'stat', b'list'}),
6592 (b'stat', {b'stat', b'list'}),
6595 ]
6593 ]
6596
6594
6597 def checkopt(opt):
6595 def checkopt(opt):
6598 if opts.get(opt):
6596 if opts.get(opt):
6599 for i, allowable in allowables:
6597 for i, allowable in allowables:
6600 if opts[i] and opt not in allowable:
6598 if opts[i] and opt not in allowable:
6601 raise error.Abort(
6599 raise error.Abort(
6602 _(
6600 _(
6603 b"options '--%s' and '--%s' may not be "
6601 b"options '--%s' and '--%s' may not be "
6604 b"used together"
6602 b"used together"
6605 )
6603 )
6606 % (opt, i)
6604 % (opt, i)
6607 )
6605 )
6608 return True
6606 return True
6609
6607
6610 if checkopt(b'cleanup'):
6608 if checkopt(b'cleanup'):
6611 if pats:
6609 if pats:
6612 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6610 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6613 return shelvemod.cleanupcmd(ui, repo)
6611 return shelvemod.cleanupcmd(ui, repo)
6614 elif checkopt(b'delete'):
6612 elif checkopt(b'delete'):
6615 return shelvemod.deletecmd(ui, repo, pats)
6613 return shelvemod.deletecmd(ui, repo, pats)
6616 elif checkopt(b'list'):
6614 elif checkopt(b'list'):
6617 return shelvemod.listcmd(ui, repo, pats, opts)
6615 return shelvemod.listcmd(ui, repo, pats, opts)
6618 elif checkopt(b'patch') or checkopt(b'stat'):
6616 elif checkopt(b'patch') or checkopt(b'stat'):
6619 return shelvemod.patchcmds(ui, repo, pats, opts)
6617 return shelvemod.patchcmds(ui, repo, pats, opts)
6620 else:
6618 else:
6621 return shelvemod.createcmd(ui, repo, pats, opts)
6619 return shelvemod.createcmd(ui, repo, pats, opts)
6622
6620
6623
6621
6624 _NOTTERSE = b'nothing'
6622 _NOTTERSE = b'nothing'
6625
6623
6626
6624
6627 @command(
6625 @command(
6628 b'status|st',
6626 b'status|st',
6629 [
6627 [
6630 (b'A', b'all', None, _(b'show status of all files')),
6628 (b'A', b'all', None, _(b'show status of all files')),
6631 (b'm', b'modified', None, _(b'show only modified files')),
6629 (b'm', b'modified', None, _(b'show only modified files')),
6632 (b'a', b'added', None, _(b'show only added files')),
6630 (b'a', b'added', None, _(b'show only added files')),
6633 (b'r', b'removed', None, _(b'show only removed files')),
6631 (b'r', b'removed', None, _(b'show only removed files')),
6634 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6632 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6635 (b'c', b'clean', None, _(b'show only files without changes')),
6633 (b'c', b'clean', None, _(b'show only files without changes')),
6636 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6634 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6637 (b'i', b'ignored', None, _(b'show only ignored files')),
6635 (b'i', b'ignored', None, _(b'show only ignored files')),
6638 (b'n', b'no-status', None, _(b'hide status prefix')),
6636 (b'n', b'no-status', None, _(b'hide status prefix')),
6639 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6637 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6640 (b'C', b'copies', None, _(b'show source of copied files')),
6638 (b'C', b'copies', None, _(b'show source of copied files')),
6641 (
6639 (
6642 b'0',
6640 b'0',
6643 b'print0',
6641 b'print0',
6644 None,
6642 None,
6645 _(b'end filenames with NUL, for use with xargs'),
6643 _(b'end filenames with NUL, for use with xargs'),
6646 ),
6644 ),
6647 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6645 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6648 (
6646 (
6649 b'',
6647 b'',
6650 b'change',
6648 b'change',
6651 b'',
6649 b'',
6652 _(b'list the changed files of a revision'),
6650 _(b'list the changed files of a revision'),
6653 _(b'REV'),
6651 _(b'REV'),
6654 ),
6652 ),
6655 ]
6653 ]
6656 + walkopts
6654 + walkopts
6657 + subrepoopts
6655 + subrepoopts
6658 + formatteropts,
6656 + formatteropts,
6659 _(b'[OPTION]... [FILE]...'),
6657 _(b'[OPTION]... [FILE]...'),
6660 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6658 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6661 helpbasic=True,
6659 helpbasic=True,
6662 inferrepo=True,
6660 inferrepo=True,
6663 intents={INTENT_READONLY},
6661 intents={INTENT_READONLY},
6664 )
6662 )
6665 def status(ui, repo, *pats, **opts):
6663 def status(ui, repo, *pats, **opts):
6666 """show changed files in the working directory
6664 """show changed files in the working directory
6667
6665
6668 Show status of files in the repository. If names are given, only
6666 Show status of files in the repository. If names are given, only
6669 files that match are shown. Files that are clean or ignored or
6667 files that match are shown. Files that are clean or ignored or
6670 the source of a copy/move operation, are not listed unless
6668 the source of a copy/move operation, are not listed unless
6671 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6669 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6672 Unless options described with "show only ..." are given, the
6670 Unless options described with "show only ..." are given, the
6673 options -mardu are used.
6671 options -mardu are used.
6674
6672
6675 Option -q/--quiet hides untracked (unknown and ignored) files
6673 Option -q/--quiet hides untracked (unknown and ignored) files
6676 unless explicitly requested with -u/--unknown or -i/--ignored.
6674 unless explicitly requested with -u/--unknown or -i/--ignored.
6677
6675
6678 .. note::
6676 .. note::
6679
6677
6680 :hg:`status` may appear to disagree with diff if permissions have
6678 :hg:`status` may appear to disagree with diff if permissions have
6681 changed or a merge has occurred. The standard diff format does
6679 changed or a merge has occurred. The standard diff format does
6682 not report permission changes and diff only reports changes
6680 not report permission changes and diff only reports changes
6683 relative to one merge parent.
6681 relative to one merge parent.
6684
6682
6685 If one revision is given, it is used as the base revision.
6683 If one revision is given, it is used as the base revision.
6686 If two revisions are given, the differences between them are
6684 If two revisions are given, the differences between them are
6687 shown. The --change option can also be used as a shortcut to list
6685 shown. The --change option can also be used as a shortcut to list
6688 the changed files of a revision from its first parent.
6686 the changed files of a revision from its first parent.
6689
6687
6690 The codes used to show the status of files are::
6688 The codes used to show the status of files are::
6691
6689
6692 M = modified
6690 M = modified
6693 A = added
6691 A = added
6694 R = removed
6692 R = removed
6695 C = clean
6693 C = clean
6696 ! = missing (deleted by non-hg command, but still tracked)
6694 ! = missing (deleted by non-hg command, but still tracked)
6697 ? = not tracked
6695 ? = not tracked
6698 I = ignored
6696 I = ignored
6699 = origin of the previous file (with --copies)
6697 = origin of the previous file (with --copies)
6700
6698
6701 .. container:: verbose
6699 .. container:: verbose
6702
6700
6703 The -t/--terse option abbreviates the output by showing only the directory
6701 The -t/--terse option abbreviates the output by showing only the directory
6704 name if all the files in it share the same status. The option takes an
6702 name if all the files in it share the same status. The option takes an
6705 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6703 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6706 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6704 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6707 for 'ignored' and 'c' for clean.
6705 for 'ignored' and 'c' for clean.
6708
6706
6709 It abbreviates only those statuses which are passed. Note that clean and
6707 It abbreviates only those statuses which are passed. Note that clean and
6710 ignored files are not displayed with '--terse ic' unless the -c/--clean
6708 ignored files are not displayed with '--terse ic' unless the -c/--clean
6711 and -i/--ignored options are also used.
6709 and -i/--ignored options are also used.
6712
6710
6713 The -v/--verbose option shows information when the repository is in an
6711 The -v/--verbose option shows information when the repository is in an
6714 unfinished merge, shelve, rebase state etc. You can have this behavior
6712 unfinished merge, shelve, rebase state etc. You can have this behavior
6715 turned on by default by enabling the ``commands.status.verbose`` option.
6713 turned on by default by enabling the ``commands.status.verbose`` option.
6716
6714
6717 You can skip displaying some of these states by setting
6715 You can skip displaying some of these states by setting
6718 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6716 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6719 'histedit', 'merge', 'rebase', or 'unshelve'.
6717 'histedit', 'merge', 'rebase', or 'unshelve'.
6720
6718
6721 Template:
6719 Template:
6722
6720
6723 The following keywords are supported in addition to the common template
6721 The following keywords are supported in addition to the common template
6724 keywords and functions. See also :hg:`help templates`.
6722 keywords and functions. See also :hg:`help templates`.
6725
6723
6726 :path: String. Repository-absolute path of the file.
6724 :path: String. Repository-absolute path of the file.
6727 :source: String. Repository-absolute path of the file originated from.
6725 :source: String. Repository-absolute path of the file originated from.
6728 Available if ``--copies`` is specified.
6726 Available if ``--copies`` is specified.
6729 :status: String. Character denoting file's status.
6727 :status: String. Character denoting file's status.
6730
6728
6731 Examples:
6729 Examples:
6732
6730
6733 - show changes in the working directory relative to a
6731 - show changes in the working directory relative to a
6734 changeset::
6732 changeset::
6735
6733
6736 hg status --rev 9353
6734 hg status --rev 9353
6737
6735
6738 - show changes in the working directory relative to the
6736 - show changes in the working directory relative to the
6739 current directory (see :hg:`help patterns` for more information)::
6737 current directory (see :hg:`help patterns` for more information)::
6740
6738
6741 hg status re:
6739 hg status re:
6742
6740
6743 - show all changes including copies in an existing changeset::
6741 - show all changes including copies in an existing changeset::
6744
6742
6745 hg status --copies --change 9353
6743 hg status --copies --change 9353
6746
6744
6747 - get a NUL separated list of added files, suitable for xargs::
6745 - get a NUL separated list of added files, suitable for xargs::
6748
6746
6749 hg status -an0
6747 hg status -an0
6750
6748
6751 - show more information about the repository status, abbreviating
6749 - show more information about the repository status, abbreviating
6752 added, removed, modified, deleted, and untracked paths::
6750 added, removed, modified, deleted, and untracked paths::
6753
6751
6754 hg status -v -t mardu
6752 hg status -v -t mardu
6755
6753
6756 Returns 0 on success.
6754 Returns 0 on success.
6757
6755
6758 """
6756 """
6759
6757
6760 opts = pycompat.byteskwargs(opts)
6758 opts = pycompat.byteskwargs(opts)
6761 revs = opts.get(b'rev')
6759 revs = opts.get(b'rev')
6762 change = opts.get(b'change')
6760 change = opts.get(b'change')
6763 terse = opts.get(b'terse')
6761 terse = opts.get(b'terse')
6764 if terse is _NOTTERSE:
6762 if terse is _NOTTERSE:
6765 if revs:
6763 if revs:
6766 terse = b''
6764 terse = b''
6767 else:
6765 else:
6768 terse = ui.config(b'commands', b'status.terse')
6766 terse = ui.config(b'commands', b'status.terse')
6769
6767
6770 if revs and change:
6768 if revs and change:
6771 msg = _(b'cannot specify --rev and --change at the same time')
6769 msg = _(b'cannot specify --rev and --change at the same time')
6772 raise error.Abort(msg)
6770 raise error.Abort(msg)
6773 elif revs and terse:
6771 elif revs and terse:
6774 msg = _(b'cannot use --terse with --rev')
6772 msg = _(b'cannot use --terse with --rev')
6775 raise error.Abort(msg)
6773 raise error.Abort(msg)
6776 elif change:
6774 elif change:
6777 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6775 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6778 ctx2 = scmutil.revsingle(repo, change, None)
6776 ctx2 = scmutil.revsingle(repo, change, None)
6779 ctx1 = ctx2.p1()
6777 ctx1 = ctx2.p1()
6780 else:
6778 else:
6781 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6779 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6782 ctx1, ctx2 = scmutil.revpair(repo, revs)
6780 ctx1, ctx2 = scmutil.revpair(repo, revs)
6783
6781
6784 forcerelativevalue = None
6782 forcerelativevalue = None
6785 if ui.hasconfig(b'commands', b'status.relative'):
6783 if ui.hasconfig(b'commands', b'status.relative'):
6786 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6784 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6787 uipathfn = scmutil.getuipathfn(
6785 uipathfn = scmutil.getuipathfn(
6788 repo,
6786 repo,
6789 legacyrelativevalue=bool(pats),
6787 legacyrelativevalue=bool(pats),
6790 forcerelativevalue=forcerelativevalue,
6788 forcerelativevalue=forcerelativevalue,
6791 )
6789 )
6792
6790
6793 if opts.get(b'print0'):
6791 if opts.get(b'print0'):
6794 end = b'\0'
6792 end = b'\0'
6795 else:
6793 else:
6796 end = b'\n'
6794 end = b'\n'
6797 copy = {}
6795 copy = {}
6798 states = b'modified added removed deleted unknown ignored clean'.split()
6796 states = b'modified added removed deleted unknown ignored clean'.split()
6799 show = [k for k in states if opts.get(k)]
6797 show = [k for k in states if opts.get(k)]
6800 if opts.get(b'all'):
6798 if opts.get(b'all'):
6801 show += ui.quiet and (states[:4] + [b'clean']) or states
6799 show += ui.quiet and (states[:4] + [b'clean']) or states
6802
6800
6803 if not show:
6801 if not show:
6804 if ui.quiet:
6802 if ui.quiet:
6805 show = states[:4]
6803 show = states[:4]
6806 else:
6804 else:
6807 show = states[:5]
6805 show = states[:5]
6808
6806
6809 m = scmutil.match(ctx2, pats, opts)
6807 m = scmutil.match(ctx2, pats, opts)
6810 if terse:
6808 if terse:
6811 # we need to compute clean and unknown to terse
6809 # we need to compute clean and unknown to terse
6812 stat = repo.status(
6810 stat = repo.status(
6813 ctx1.node(),
6811 ctx1.node(),
6814 ctx2.node(),
6812 ctx2.node(),
6815 m,
6813 m,
6816 b'ignored' in show or b'i' in terse,
6814 b'ignored' in show or b'i' in terse,
6817 clean=True,
6815 clean=True,
6818 unknown=True,
6816 unknown=True,
6819 listsubrepos=opts.get(b'subrepos'),
6817 listsubrepos=opts.get(b'subrepos'),
6820 )
6818 )
6821
6819
6822 stat = cmdutil.tersedir(stat, terse)
6820 stat = cmdutil.tersedir(stat, terse)
6823 else:
6821 else:
6824 stat = repo.status(
6822 stat = repo.status(
6825 ctx1.node(),
6823 ctx1.node(),
6826 ctx2.node(),
6824 ctx2.node(),
6827 m,
6825 m,
6828 b'ignored' in show,
6826 b'ignored' in show,
6829 b'clean' in show,
6827 b'clean' in show,
6830 b'unknown' in show,
6828 b'unknown' in show,
6831 opts.get(b'subrepos'),
6829 opts.get(b'subrepos'),
6832 )
6830 )
6833
6831
6834 changestates = zip(states, pycompat.iterbytestr(b'MAR!?IC'), stat)
6832 changestates = zip(states, pycompat.iterbytestr(b'MAR!?IC'), stat)
6835
6833
6836 if (
6834 if (
6837 opts.get(b'all')
6835 opts.get(b'all')
6838 or opts.get(b'copies')
6836 or opts.get(b'copies')
6839 or ui.configbool(b'ui', b'statuscopies')
6837 or ui.configbool(b'ui', b'statuscopies')
6840 ) and not opts.get(b'no_status'):
6838 ) and not opts.get(b'no_status'):
6841 copy = copies.pathcopies(ctx1, ctx2, m)
6839 copy = copies.pathcopies(ctx1, ctx2, m)
6842
6840
6843 ui.pager(b'status')
6841 ui.pager(b'status')
6844 fm = ui.formatter(b'status', opts)
6842 fm = ui.formatter(b'status', opts)
6845 fmt = b'%s' + end
6843 fmt = b'%s' + end
6846 showchar = not opts.get(b'no_status')
6844 showchar = not opts.get(b'no_status')
6847
6845
6848 for state, char, files in changestates:
6846 for state, char, files in changestates:
6849 if state in show:
6847 if state in show:
6850 label = b'status.' + state
6848 label = b'status.' + state
6851 for f in files:
6849 for f in files:
6852 fm.startitem()
6850 fm.startitem()
6853 fm.context(ctx=ctx2)
6851 fm.context(ctx=ctx2)
6854 fm.data(path=f)
6852 fm.data(path=f)
6855 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6853 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6856 fm.plain(fmt % uipathfn(f), label=label)
6854 fm.plain(fmt % uipathfn(f), label=label)
6857 if f in copy:
6855 if f in copy:
6858 fm.data(source=copy[f])
6856 fm.data(source=copy[f])
6859 fm.plain(
6857 fm.plain(
6860 (b' %s' + end) % uipathfn(copy[f]),
6858 (b' %s' + end) % uipathfn(copy[f]),
6861 label=b'status.copied',
6859 label=b'status.copied',
6862 )
6860 )
6863
6861
6864 if (
6862 if (
6865 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6863 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6866 ) and not ui.plain():
6864 ) and not ui.plain():
6867 cmdutil.morestatus(repo, fm)
6865 cmdutil.morestatus(repo, fm)
6868 fm.end()
6866 fm.end()
6869
6867
6870
6868
6871 @command(
6869 @command(
6872 b'summary|sum',
6870 b'summary|sum',
6873 [(b'', b'remote', None, _(b'check for push and pull'))],
6871 [(b'', b'remote', None, _(b'check for push and pull'))],
6874 b'[--remote]',
6872 b'[--remote]',
6875 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6873 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6876 helpbasic=True,
6874 helpbasic=True,
6877 intents={INTENT_READONLY},
6875 intents={INTENT_READONLY},
6878 )
6876 )
6879 def summary(ui, repo, **opts):
6877 def summary(ui, repo, **opts):
6880 """summarize working directory state
6878 """summarize working directory state
6881
6879
6882 This generates a brief summary of the working directory state,
6880 This generates a brief summary of the working directory state,
6883 including parents, branch, commit status, phase and available updates.
6881 including parents, branch, commit status, phase and available updates.
6884
6882
6885 With the --remote option, this will check the default paths for
6883 With the --remote option, this will check the default paths for
6886 incoming and outgoing changes. This can be time-consuming.
6884 incoming and outgoing changes. This can be time-consuming.
6887
6885
6888 Returns 0 on success.
6886 Returns 0 on success.
6889 """
6887 """
6890
6888
6891 opts = pycompat.byteskwargs(opts)
6889 opts = pycompat.byteskwargs(opts)
6892 ui.pager(b'summary')
6890 ui.pager(b'summary')
6893 ctx = repo[None]
6891 ctx = repo[None]
6894 parents = ctx.parents()
6892 parents = ctx.parents()
6895 pnode = parents[0].node()
6893 pnode = parents[0].node()
6896 marks = []
6894 marks = []
6897
6895
6898 try:
6896 try:
6899 ms = mergemod.mergestate.read(repo)
6897 ms = mergemod.mergestate.read(repo)
6900 except error.UnsupportedMergeRecords as e:
6898 except error.UnsupportedMergeRecords as e:
6901 s = b' '.join(e.recordtypes)
6899 s = b' '.join(e.recordtypes)
6902 ui.warn(
6900 ui.warn(
6903 _(b'warning: merge state has unsupported record types: %s\n') % s
6901 _(b'warning: merge state has unsupported record types: %s\n') % s
6904 )
6902 )
6905 unresolved = []
6903 unresolved = []
6906 else:
6904 else:
6907 unresolved = list(ms.unresolved())
6905 unresolved = list(ms.unresolved())
6908
6906
6909 for p in parents:
6907 for p in parents:
6910 # label with log.changeset (instead of log.parent) since this
6908 # label with log.changeset (instead of log.parent) since this
6911 # shows a working directory parent *changeset*:
6909 # shows a working directory parent *changeset*:
6912 # i18n: column positioning for "hg summary"
6910 # i18n: column positioning for "hg summary"
6913 ui.write(
6911 ui.write(
6914 _(b'parent: %d:%s ') % (p.rev(), p),
6912 _(b'parent: %d:%s ') % (p.rev(), p),
6915 label=logcmdutil.changesetlabels(p),
6913 label=logcmdutil.changesetlabels(p),
6916 )
6914 )
6917 ui.write(b' '.join(p.tags()), label=b'log.tag')
6915 ui.write(b' '.join(p.tags()), label=b'log.tag')
6918 if p.bookmarks():
6916 if p.bookmarks():
6919 marks.extend(p.bookmarks())
6917 marks.extend(p.bookmarks())
6920 if p.rev() == -1:
6918 if p.rev() == -1:
6921 if not len(repo):
6919 if not len(repo):
6922 ui.write(_(b' (empty repository)'))
6920 ui.write(_(b' (empty repository)'))
6923 else:
6921 else:
6924 ui.write(_(b' (no revision checked out)'))
6922 ui.write(_(b' (no revision checked out)'))
6925 if p.obsolete():
6923 if p.obsolete():
6926 ui.write(_(b' (obsolete)'))
6924 ui.write(_(b' (obsolete)'))
6927 if p.isunstable():
6925 if p.isunstable():
6928 instabilities = (
6926 instabilities = (
6929 ui.label(instability, b'trouble.%s' % instability)
6927 ui.label(instability, b'trouble.%s' % instability)
6930 for instability in p.instabilities()
6928 for instability in p.instabilities()
6931 )
6929 )
6932 ui.write(b' (' + b', '.join(instabilities) + b')')
6930 ui.write(b' (' + b', '.join(instabilities) + b')')
6933 ui.write(b'\n')
6931 ui.write(b'\n')
6934 if p.description():
6932 if p.description():
6935 ui.status(
6933 ui.status(
6936 b' ' + p.description().splitlines()[0].strip() + b'\n',
6934 b' ' + p.description().splitlines()[0].strip() + b'\n',
6937 label=b'log.summary',
6935 label=b'log.summary',
6938 )
6936 )
6939
6937
6940 branch = ctx.branch()
6938 branch = ctx.branch()
6941 bheads = repo.branchheads(branch)
6939 bheads = repo.branchheads(branch)
6942 # i18n: column positioning for "hg summary"
6940 # i18n: column positioning for "hg summary"
6943 m = _(b'branch: %s\n') % branch
6941 m = _(b'branch: %s\n') % branch
6944 if branch != b'default':
6942 if branch != b'default':
6945 ui.write(m, label=b'log.branch')
6943 ui.write(m, label=b'log.branch')
6946 else:
6944 else:
6947 ui.status(m, label=b'log.branch')
6945 ui.status(m, label=b'log.branch')
6948
6946
6949 if marks:
6947 if marks:
6950 active = repo._activebookmark
6948 active = repo._activebookmark
6951 # i18n: column positioning for "hg summary"
6949 # i18n: column positioning for "hg summary"
6952 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6950 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6953 if active is not None:
6951 if active is not None:
6954 if active in marks:
6952 if active in marks:
6955 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6953 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6956 marks.remove(active)
6954 marks.remove(active)
6957 else:
6955 else:
6958 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6956 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6959 for m in marks:
6957 for m in marks:
6960 ui.write(b' ' + m, label=b'log.bookmark')
6958 ui.write(b' ' + m, label=b'log.bookmark')
6961 ui.write(b'\n', label=b'log.bookmark')
6959 ui.write(b'\n', label=b'log.bookmark')
6962
6960
6963 status = repo.status(unknown=True)
6961 status = repo.status(unknown=True)
6964
6962
6965 c = repo.dirstate.copies()
6963 c = repo.dirstate.copies()
6966 copied, renamed = [], []
6964 copied, renamed = [], []
6967 for d, s in pycompat.iteritems(c):
6965 for d, s in pycompat.iteritems(c):
6968 if s in status.removed:
6966 if s in status.removed:
6969 status.removed.remove(s)
6967 status.removed.remove(s)
6970 renamed.append(d)
6968 renamed.append(d)
6971 else:
6969 else:
6972 copied.append(d)
6970 copied.append(d)
6973 if d in status.added:
6971 if d in status.added:
6974 status.added.remove(d)
6972 status.added.remove(d)
6975
6973
6976 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6974 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6977
6975
6978 labels = [
6976 labels = [
6979 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6977 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6980 (ui.label(_(b'%d added'), b'status.added'), status.added),
6978 (ui.label(_(b'%d added'), b'status.added'), status.added),
6981 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6979 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6982 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6980 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6983 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6981 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6984 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6982 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6985 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6983 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6986 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6984 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6987 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6985 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6988 ]
6986 ]
6989 t = []
6987 t = []
6990 for l, s in labels:
6988 for l, s in labels:
6991 if s:
6989 if s:
6992 t.append(l % len(s))
6990 t.append(l % len(s))
6993
6991
6994 t = b', '.join(t)
6992 t = b', '.join(t)
6995 cleanworkdir = False
6993 cleanworkdir = False
6996
6994
6997 if repo.vfs.exists(b'graftstate'):
6995 if repo.vfs.exists(b'graftstate'):
6998 t += _(b' (graft in progress)')
6996 t += _(b' (graft in progress)')
6999 if repo.vfs.exists(b'updatestate'):
6997 if repo.vfs.exists(b'updatestate'):
7000 t += _(b' (interrupted update)')
6998 t += _(b' (interrupted update)')
7001 elif len(parents) > 1:
6999 elif len(parents) > 1:
7002 t += _(b' (merge)')
7000 t += _(b' (merge)')
7003 elif branch != parents[0].branch():
7001 elif branch != parents[0].branch():
7004 t += _(b' (new branch)')
7002 t += _(b' (new branch)')
7005 elif parents[0].closesbranch() and pnode in repo.branchheads(
7003 elif parents[0].closesbranch() and pnode in repo.branchheads(
7006 branch, closed=True
7004 branch, closed=True
7007 ):
7005 ):
7008 t += _(b' (head closed)')
7006 t += _(b' (head closed)')
7009 elif not (
7007 elif not (
7010 status.modified
7008 status.modified
7011 or status.added
7009 or status.added
7012 or status.removed
7010 or status.removed
7013 or renamed
7011 or renamed
7014 or copied
7012 or copied
7015 or subs
7013 or subs
7016 ):
7014 ):
7017 t += _(b' (clean)')
7015 t += _(b' (clean)')
7018 cleanworkdir = True
7016 cleanworkdir = True
7019 elif pnode not in bheads:
7017 elif pnode not in bheads:
7020 t += _(b' (new branch head)')
7018 t += _(b' (new branch head)')
7021
7019
7022 if parents:
7020 if parents:
7023 pendingphase = max(p.phase() for p in parents)
7021 pendingphase = max(p.phase() for p in parents)
7024 else:
7022 else:
7025 pendingphase = phases.public
7023 pendingphase = phases.public
7026
7024
7027 if pendingphase > phases.newcommitphase(ui):
7025 if pendingphase > phases.newcommitphase(ui):
7028 t += b' (%s)' % phases.phasenames[pendingphase]
7026 t += b' (%s)' % phases.phasenames[pendingphase]
7029
7027
7030 if cleanworkdir:
7028 if cleanworkdir:
7031 # i18n: column positioning for "hg summary"
7029 # i18n: column positioning for "hg summary"
7032 ui.status(_(b'commit: %s\n') % t.strip())
7030 ui.status(_(b'commit: %s\n') % t.strip())
7033 else:
7031 else:
7034 # i18n: column positioning for "hg summary"
7032 # i18n: column positioning for "hg summary"
7035 ui.write(_(b'commit: %s\n') % t.strip())
7033 ui.write(_(b'commit: %s\n') % t.strip())
7036
7034
7037 # all ancestors of branch heads - all ancestors of parent = new csets
7035 # all ancestors of branch heads - all ancestors of parent = new csets
7038 new = len(
7036 new = len(
7039 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7037 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7040 )
7038 )
7041
7039
7042 if new == 0:
7040 if new == 0:
7043 # i18n: column positioning for "hg summary"
7041 # i18n: column positioning for "hg summary"
7044 ui.status(_(b'update: (current)\n'))
7042 ui.status(_(b'update: (current)\n'))
7045 elif pnode not in bheads:
7043 elif pnode not in bheads:
7046 # i18n: column positioning for "hg summary"
7044 # i18n: column positioning for "hg summary"
7047 ui.write(_(b'update: %d new changesets (update)\n') % new)
7045 ui.write(_(b'update: %d new changesets (update)\n') % new)
7048 else:
7046 else:
7049 # i18n: column positioning for "hg summary"
7047 # i18n: column positioning for "hg summary"
7050 ui.write(
7048 ui.write(
7051 _(b'update: %d new changesets, %d branch heads (merge)\n')
7049 _(b'update: %d new changesets, %d branch heads (merge)\n')
7052 % (new, len(bheads))
7050 % (new, len(bheads))
7053 )
7051 )
7054
7052
7055 t = []
7053 t = []
7056 draft = len(repo.revs(b'draft()'))
7054 draft = len(repo.revs(b'draft()'))
7057 if draft:
7055 if draft:
7058 t.append(_(b'%d draft') % draft)
7056 t.append(_(b'%d draft') % draft)
7059 secret = len(repo.revs(b'secret()'))
7057 secret = len(repo.revs(b'secret()'))
7060 if secret:
7058 if secret:
7061 t.append(_(b'%d secret') % secret)
7059 t.append(_(b'%d secret') % secret)
7062
7060
7063 if draft or secret:
7061 if draft or secret:
7064 ui.status(_(b'phases: %s\n') % b', '.join(t))
7062 ui.status(_(b'phases: %s\n') % b', '.join(t))
7065
7063
7066 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7064 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7067 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7065 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7068 numtrouble = len(repo.revs(trouble + b"()"))
7066 numtrouble = len(repo.revs(trouble + b"()"))
7069 # We write all the possibilities to ease translation
7067 # We write all the possibilities to ease translation
7070 troublemsg = {
7068 troublemsg = {
7071 b"orphan": _(b"orphan: %d changesets"),
7069 b"orphan": _(b"orphan: %d changesets"),
7072 b"contentdivergent": _(b"content-divergent: %d changesets"),
7070 b"contentdivergent": _(b"content-divergent: %d changesets"),
7073 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7071 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7074 }
7072 }
7075 if numtrouble > 0:
7073 if numtrouble > 0:
7076 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7074 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7077
7075
7078 cmdutil.summaryhooks(ui, repo)
7076 cmdutil.summaryhooks(ui, repo)
7079
7077
7080 if opts.get(b'remote'):
7078 if opts.get(b'remote'):
7081 needsincoming, needsoutgoing = True, True
7079 needsincoming, needsoutgoing = True, True
7082 else:
7080 else:
7083 needsincoming, needsoutgoing = False, False
7081 needsincoming, needsoutgoing = False, False
7084 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7082 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7085 if i:
7083 if i:
7086 needsincoming = True
7084 needsincoming = True
7087 if o:
7085 if o:
7088 needsoutgoing = True
7086 needsoutgoing = True
7089 if not needsincoming and not needsoutgoing:
7087 if not needsincoming and not needsoutgoing:
7090 return
7088 return
7091
7089
7092 def getincoming():
7090 def getincoming():
7093 source, branches = hg.parseurl(ui.expandpath(b'default'))
7091 source, branches = hg.parseurl(ui.expandpath(b'default'))
7094 sbranch = branches[0]
7092 sbranch = branches[0]
7095 try:
7093 try:
7096 other = hg.peer(repo, {}, source)
7094 other = hg.peer(repo, {}, source)
7097 except error.RepoError:
7095 except error.RepoError:
7098 if opts.get(b'remote'):
7096 if opts.get(b'remote'):
7099 raise
7097 raise
7100 return source, sbranch, None, None, None
7098 return source, sbranch, None, None, None
7101 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7099 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7102 if revs:
7100 if revs:
7103 revs = [other.lookup(rev) for rev in revs]
7101 revs = [other.lookup(rev) for rev in revs]
7104 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7102 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7105 repo.ui.pushbuffer()
7103 repo.ui.pushbuffer()
7106 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7104 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7107 repo.ui.popbuffer()
7105 repo.ui.popbuffer()
7108 return source, sbranch, other, commoninc, commoninc[1]
7106 return source, sbranch, other, commoninc, commoninc[1]
7109
7107
7110 if needsincoming:
7108 if needsincoming:
7111 source, sbranch, sother, commoninc, incoming = getincoming()
7109 source, sbranch, sother, commoninc, incoming = getincoming()
7112 else:
7110 else:
7113 source = sbranch = sother = commoninc = incoming = None
7111 source = sbranch = sother = commoninc = incoming = None
7114
7112
7115 def getoutgoing():
7113 def getoutgoing():
7116 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7114 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7117 dbranch = branches[0]
7115 dbranch = branches[0]
7118 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7116 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7119 if source != dest:
7117 if source != dest:
7120 try:
7118 try:
7121 dother = hg.peer(repo, {}, dest)
7119 dother = hg.peer(repo, {}, dest)
7122 except error.RepoError:
7120 except error.RepoError:
7123 if opts.get(b'remote'):
7121 if opts.get(b'remote'):
7124 raise
7122 raise
7125 return dest, dbranch, None, None
7123 return dest, dbranch, None, None
7126 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7124 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7127 elif sother is None:
7125 elif sother is None:
7128 # there is no explicit destination peer, but source one is invalid
7126 # there is no explicit destination peer, but source one is invalid
7129 return dest, dbranch, None, None
7127 return dest, dbranch, None, None
7130 else:
7128 else:
7131 dother = sother
7129 dother = sother
7132 if source != dest or (sbranch is not None and sbranch != dbranch):
7130 if source != dest or (sbranch is not None and sbranch != dbranch):
7133 common = None
7131 common = None
7134 else:
7132 else:
7135 common = commoninc
7133 common = commoninc
7136 if revs:
7134 if revs:
7137 revs = [repo.lookup(rev) for rev in revs]
7135 revs = [repo.lookup(rev) for rev in revs]
7138 repo.ui.pushbuffer()
7136 repo.ui.pushbuffer()
7139 outgoing = discovery.findcommonoutgoing(
7137 outgoing = discovery.findcommonoutgoing(
7140 repo, dother, onlyheads=revs, commoninc=common
7138 repo, dother, onlyheads=revs, commoninc=common
7141 )
7139 )
7142 repo.ui.popbuffer()
7140 repo.ui.popbuffer()
7143 return dest, dbranch, dother, outgoing
7141 return dest, dbranch, dother, outgoing
7144
7142
7145 if needsoutgoing:
7143 if needsoutgoing:
7146 dest, dbranch, dother, outgoing = getoutgoing()
7144 dest, dbranch, dother, outgoing = getoutgoing()
7147 else:
7145 else:
7148 dest = dbranch = dother = outgoing = None
7146 dest = dbranch = dother = outgoing = None
7149
7147
7150 if opts.get(b'remote'):
7148 if opts.get(b'remote'):
7151 t = []
7149 t = []
7152 if incoming:
7150 if incoming:
7153 t.append(_(b'1 or more incoming'))
7151 t.append(_(b'1 or more incoming'))
7154 o = outgoing.missing
7152 o = outgoing.missing
7155 if o:
7153 if o:
7156 t.append(_(b'%d outgoing') % len(o))
7154 t.append(_(b'%d outgoing') % len(o))
7157 other = dother or sother
7155 other = dother or sother
7158 if b'bookmarks' in other.listkeys(b'namespaces'):
7156 if b'bookmarks' in other.listkeys(b'namespaces'):
7159 counts = bookmarks.summary(repo, other)
7157 counts = bookmarks.summary(repo, other)
7160 if counts[0] > 0:
7158 if counts[0] > 0:
7161 t.append(_(b'%d incoming bookmarks') % counts[0])
7159 t.append(_(b'%d incoming bookmarks') % counts[0])
7162 if counts[1] > 0:
7160 if counts[1] > 0:
7163 t.append(_(b'%d outgoing bookmarks') % counts[1])
7161 t.append(_(b'%d outgoing bookmarks') % counts[1])
7164
7162
7165 if t:
7163 if t:
7166 # i18n: column positioning for "hg summary"
7164 # i18n: column positioning for "hg summary"
7167 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7165 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7168 else:
7166 else:
7169 # i18n: column positioning for "hg summary"
7167 # i18n: column positioning for "hg summary"
7170 ui.status(_(b'remote: (synced)\n'))
7168 ui.status(_(b'remote: (synced)\n'))
7171
7169
7172 cmdutil.summaryremotehooks(
7170 cmdutil.summaryremotehooks(
7173 ui,
7171 ui,
7174 repo,
7172 repo,
7175 opts,
7173 opts,
7176 (
7174 (
7177 (source, sbranch, sother, commoninc),
7175 (source, sbranch, sother, commoninc),
7178 (dest, dbranch, dother, outgoing),
7176 (dest, dbranch, dother, outgoing),
7179 ),
7177 ),
7180 )
7178 )
7181
7179
7182
7180
7183 @command(
7181 @command(
7184 b'tag',
7182 b'tag',
7185 [
7183 [
7186 (b'f', b'force', None, _(b'force tag')),
7184 (b'f', b'force', None, _(b'force tag')),
7187 (b'l', b'local', None, _(b'make the tag local')),
7185 (b'l', b'local', None, _(b'make the tag local')),
7188 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7186 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7189 (b'', b'remove', None, _(b'remove a tag')),
7187 (b'', b'remove', None, _(b'remove a tag')),
7190 # -l/--local is already there, commitopts cannot be used
7188 # -l/--local is already there, commitopts cannot be used
7191 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7189 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7192 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7190 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7193 ]
7191 ]
7194 + commitopts2,
7192 + commitopts2,
7195 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7193 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7196 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7194 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7197 )
7195 )
7198 def tag(ui, repo, name1, *names, **opts):
7196 def tag(ui, repo, name1, *names, **opts):
7199 """add one or more tags for the current or given revision
7197 """add one or more tags for the current or given revision
7200
7198
7201 Name a particular revision using <name>.
7199 Name a particular revision using <name>.
7202
7200
7203 Tags are used to name particular revisions of the repository and are
7201 Tags are used to name particular revisions of the repository and are
7204 very useful to compare different revisions, to go back to significant
7202 very useful to compare different revisions, to go back to significant
7205 earlier versions or to mark branch points as releases, etc. Changing
7203 earlier versions or to mark branch points as releases, etc. Changing
7206 an existing tag is normally disallowed; use -f/--force to override.
7204 an existing tag is normally disallowed; use -f/--force to override.
7207
7205
7208 If no revision is given, the parent of the working directory is
7206 If no revision is given, the parent of the working directory is
7209 used.
7207 used.
7210
7208
7211 To facilitate version control, distribution, and merging of tags,
7209 To facilitate version control, distribution, and merging of tags,
7212 they are stored as a file named ".hgtags" which is managed similarly
7210 they are stored as a file named ".hgtags" which is managed similarly
7213 to other project files and can be hand-edited if necessary. This
7211 to other project files and can be hand-edited if necessary. This
7214 also means that tagging creates a new commit. The file
7212 also means that tagging creates a new commit. The file
7215 ".hg/localtags" is used for local tags (not shared among
7213 ".hg/localtags" is used for local tags (not shared among
7216 repositories).
7214 repositories).
7217
7215
7218 Tag commits are usually made at the head of a branch. If the parent
7216 Tag commits are usually made at the head of a branch. If the parent
7219 of the working directory is not a branch head, :hg:`tag` aborts; use
7217 of the working directory is not a branch head, :hg:`tag` aborts; use
7220 -f/--force to force the tag commit to be based on a non-head
7218 -f/--force to force the tag commit to be based on a non-head
7221 changeset.
7219 changeset.
7222
7220
7223 See :hg:`help dates` for a list of formats valid for -d/--date.
7221 See :hg:`help dates` for a list of formats valid for -d/--date.
7224
7222
7225 Since tag names have priority over branch names during revision
7223 Since tag names have priority over branch names during revision
7226 lookup, using an existing branch name as a tag name is discouraged.
7224 lookup, using an existing branch name as a tag name is discouraged.
7227
7225
7228 Returns 0 on success.
7226 Returns 0 on success.
7229 """
7227 """
7230 opts = pycompat.byteskwargs(opts)
7228 opts = pycompat.byteskwargs(opts)
7231 with repo.wlock(), repo.lock():
7229 with repo.wlock(), repo.lock():
7232 rev_ = b"."
7230 rev_ = b"."
7233 names = [t.strip() for t in (name1,) + names]
7231 names = [t.strip() for t in (name1,) + names]
7234 if len(names) != len(set(names)):
7232 if len(names) != len(set(names)):
7235 raise error.Abort(_(b'tag names must be unique'))
7233 raise error.Abort(_(b'tag names must be unique'))
7236 for n in names:
7234 for n in names:
7237 scmutil.checknewlabel(repo, n, b'tag')
7235 scmutil.checknewlabel(repo, n, b'tag')
7238 if not n:
7236 if not n:
7239 raise error.Abort(
7237 raise error.Abort(
7240 _(b'tag names cannot consist entirely of whitespace')
7238 _(b'tag names cannot consist entirely of whitespace')
7241 )
7239 )
7242 if opts.get(b'rev') and opts.get(b'remove'):
7240 if opts.get(b'rev') and opts.get(b'remove'):
7243 raise error.Abort(_(b"--rev and --remove are incompatible"))
7241 raise error.Abort(_(b"--rev and --remove are incompatible"))
7244 if opts.get(b'rev'):
7242 if opts.get(b'rev'):
7245 rev_ = opts[b'rev']
7243 rev_ = opts[b'rev']
7246 message = opts.get(b'message')
7244 message = opts.get(b'message')
7247 if opts.get(b'remove'):
7245 if opts.get(b'remove'):
7248 if opts.get(b'local'):
7246 if opts.get(b'local'):
7249 expectedtype = b'local'
7247 expectedtype = b'local'
7250 else:
7248 else:
7251 expectedtype = b'global'
7249 expectedtype = b'global'
7252
7250
7253 for n in names:
7251 for n in names:
7254 if repo.tagtype(n) == b'global':
7252 if repo.tagtype(n) == b'global':
7255 alltags = tagsmod.findglobaltags(ui, repo)
7253 alltags = tagsmod.findglobaltags(ui, repo)
7256 if alltags[n][0] == nullid:
7254 if alltags[n][0] == nullid:
7257 raise error.Abort(_(b"tag '%s' is already removed") % n)
7255 raise error.Abort(_(b"tag '%s' is already removed") % n)
7258 if not repo.tagtype(n):
7256 if not repo.tagtype(n):
7259 raise error.Abort(_(b"tag '%s' does not exist") % n)
7257 raise error.Abort(_(b"tag '%s' does not exist") % n)
7260 if repo.tagtype(n) != expectedtype:
7258 if repo.tagtype(n) != expectedtype:
7261 if expectedtype == b'global':
7259 if expectedtype == b'global':
7262 raise error.Abort(
7260 raise error.Abort(
7263 _(b"tag '%s' is not a global tag") % n
7261 _(b"tag '%s' is not a global tag") % n
7264 )
7262 )
7265 else:
7263 else:
7266 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7264 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7267 rev_ = b'null'
7265 rev_ = b'null'
7268 if not message:
7266 if not message:
7269 # we don't translate commit messages
7267 # we don't translate commit messages
7270 message = b'Removed tag %s' % b', '.join(names)
7268 message = b'Removed tag %s' % b', '.join(names)
7271 elif not opts.get(b'force'):
7269 elif not opts.get(b'force'):
7272 for n in names:
7270 for n in names:
7273 if n in repo.tags():
7271 if n in repo.tags():
7274 raise error.Abort(
7272 raise error.Abort(
7275 _(b"tag '%s' already exists (use -f to force)") % n
7273 _(b"tag '%s' already exists (use -f to force)") % n
7276 )
7274 )
7277 if not opts.get(b'local'):
7275 if not opts.get(b'local'):
7278 p1, p2 = repo.dirstate.parents()
7276 p1, p2 = repo.dirstate.parents()
7279 if p2 != nullid:
7277 if p2 != nullid:
7280 raise error.Abort(_(b'uncommitted merge'))
7278 raise error.Abort(_(b'uncommitted merge'))
7281 bheads = repo.branchheads()
7279 bheads = repo.branchheads()
7282 if not opts.get(b'force') and bheads and p1 not in bheads:
7280 if not opts.get(b'force') and bheads and p1 not in bheads:
7283 raise error.Abort(
7281 raise error.Abort(
7284 _(
7282 _(
7285 b'working directory is not at a branch head '
7283 b'working directory is not at a branch head '
7286 b'(use -f to force)'
7284 b'(use -f to force)'
7287 )
7285 )
7288 )
7286 )
7289 node = scmutil.revsingle(repo, rev_).node()
7287 node = scmutil.revsingle(repo, rev_).node()
7290
7288
7291 if not message:
7289 if not message:
7292 # we don't translate commit messages
7290 # we don't translate commit messages
7293 message = b'Added tag %s for changeset %s' % (
7291 message = b'Added tag %s for changeset %s' % (
7294 b', '.join(names),
7292 b', '.join(names),
7295 short(node),
7293 short(node),
7296 )
7294 )
7297
7295
7298 date = opts.get(b'date')
7296 date = opts.get(b'date')
7299 if date:
7297 if date:
7300 date = dateutil.parsedate(date)
7298 date = dateutil.parsedate(date)
7301
7299
7302 if opts.get(b'remove'):
7300 if opts.get(b'remove'):
7303 editform = b'tag.remove'
7301 editform = b'tag.remove'
7304 else:
7302 else:
7305 editform = b'tag.add'
7303 editform = b'tag.add'
7306 editor = cmdutil.getcommiteditor(
7304 editor = cmdutil.getcommiteditor(
7307 editform=editform, **pycompat.strkwargs(opts)
7305 editform=editform, **pycompat.strkwargs(opts)
7308 )
7306 )
7309
7307
7310 # don't allow tagging the null rev
7308 # don't allow tagging the null rev
7311 if (
7309 if (
7312 not opts.get(b'remove')
7310 not opts.get(b'remove')
7313 and scmutil.revsingle(repo, rev_).rev() == nullrev
7311 and scmutil.revsingle(repo, rev_).rev() == nullrev
7314 ):
7312 ):
7315 raise error.Abort(_(b"cannot tag null revision"))
7313 raise error.Abort(_(b"cannot tag null revision"))
7316
7314
7317 tagsmod.tag(
7315 tagsmod.tag(
7318 repo,
7316 repo,
7319 names,
7317 names,
7320 node,
7318 node,
7321 message,
7319 message,
7322 opts.get(b'local'),
7320 opts.get(b'local'),
7323 opts.get(b'user'),
7321 opts.get(b'user'),
7324 date,
7322 date,
7325 editor=editor,
7323 editor=editor,
7326 )
7324 )
7327
7325
7328
7326
7329 @command(
7327 @command(
7330 b'tags',
7328 b'tags',
7331 formatteropts,
7329 formatteropts,
7332 b'',
7330 b'',
7333 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7331 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7334 intents={INTENT_READONLY},
7332 intents={INTENT_READONLY},
7335 )
7333 )
7336 def tags(ui, repo, **opts):
7334 def tags(ui, repo, **opts):
7337 """list repository tags
7335 """list repository tags
7338
7336
7339 This lists both regular and local tags. When the -v/--verbose
7337 This lists both regular and local tags. When the -v/--verbose
7340 switch is used, a third column "local" is printed for local tags.
7338 switch is used, a third column "local" is printed for local tags.
7341 When the -q/--quiet switch is used, only the tag name is printed.
7339 When the -q/--quiet switch is used, only the tag name is printed.
7342
7340
7343 .. container:: verbose
7341 .. container:: verbose
7344
7342
7345 Template:
7343 Template:
7346
7344
7347 The following keywords are supported in addition to the common template
7345 The following keywords are supported in addition to the common template
7348 keywords and functions such as ``{tag}``. See also
7346 keywords and functions such as ``{tag}``. See also
7349 :hg:`help templates`.
7347 :hg:`help templates`.
7350
7348
7351 :type: String. ``local`` for local tags.
7349 :type: String. ``local`` for local tags.
7352
7350
7353 Returns 0 on success.
7351 Returns 0 on success.
7354 """
7352 """
7355
7353
7356 opts = pycompat.byteskwargs(opts)
7354 opts = pycompat.byteskwargs(opts)
7357 ui.pager(b'tags')
7355 ui.pager(b'tags')
7358 fm = ui.formatter(b'tags', opts)
7356 fm = ui.formatter(b'tags', opts)
7359 hexfunc = fm.hexfunc
7357 hexfunc = fm.hexfunc
7360
7358
7361 for t, n in reversed(repo.tagslist()):
7359 for t, n in reversed(repo.tagslist()):
7362 hn = hexfunc(n)
7360 hn = hexfunc(n)
7363 label = b'tags.normal'
7361 label = b'tags.normal'
7364 tagtype = b''
7362 tagtype = b''
7365 if repo.tagtype(t) == b'local':
7363 if repo.tagtype(t) == b'local':
7366 label = b'tags.local'
7364 label = b'tags.local'
7367 tagtype = b'local'
7365 tagtype = b'local'
7368
7366
7369 fm.startitem()
7367 fm.startitem()
7370 fm.context(repo=repo)
7368 fm.context(repo=repo)
7371 fm.write(b'tag', b'%s', t, label=label)
7369 fm.write(b'tag', b'%s', t, label=label)
7372 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7370 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7373 fm.condwrite(
7371 fm.condwrite(
7374 not ui.quiet,
7372 not ui.quiet,
7375 b'rev node',
7373 b'rev node',
7376 fmt,
7374 fmt,
7377 repo.changelog.rev(n),
7375 repo.changelog.rev(n),
7378 hn,
7376 hn,
7379 label=label,
7377 label=label,
7380 )
7378 )
7381 fm.condwrite(
7379 fm.condwrite(
7382 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7380 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7383 )
7381 )
7384 fm.plain(b'\n')
7382 fm.plain(b'\n')
7385 fm.end()
7383 fm.end()
7386
7384
7387
7385
7388 @command(
7386 @command(
7389 b'tip',
7387 b'tip',
7390 [
7388 [
7391 (b'p', b'patch', None, _(b'show patch')),
7389 (b'p', b'patch', None, _(b'show patch')),
7392 (b'g', b'git', None, _(b'use git extended diff format')),
7390 (b'g', b'git', None, _(b'use git extended diff format')),
7393 ]
7391 ]
7394 + templateopts,
7392 + templateopts,
7395 _(b'[-p] [-g]'),
7393 _(b'[-p] [-g]'),
7396 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7394 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7397 )
7395 )
7398 def tip(ui, repo, **opts):
7396 def tip(ui, repo, **opts):
7399 """show the tip revision (DEPRECATED)
7397 """show the tip revision (DEPRECATED)
7400
7398
7401 The tip revision (usually just called the tip) is the changeset
7399 The tip revision (usually just called the tip) is the changeset
7402 most recently added to the repository (and therefore the most
7400 most recently added to the repository (and therefore the most
7403 recently changed head).
7401 recently changed head).
7404
7402
7405 If you have just made a commit, that commit will be the tip. If
7403 If you have just made a commit, that commit will be the tip. If
7406 you have just pulled changes from another repository, the tip of
7404 you have just pulled changes from another repository, the tip of
7407 that repository becomes the current tip. The "tip" tag is special
7405 that repository becomes the current tip. The "tip" tag is special
7408 and cannot be renamed or assigned to a different changeset.
7406 and cannot be renamed or assigned to a different changeset.
7409
7407
7410 This command is deprecated, please use :hg:`heads` instead.
7408 This command is deprecated, please use :hg:`heads` instead.
7411
7409
7412 Returns 0 on success.
7410 Returns 0 on success.
7413 """
7411 """
7414 opts = pycompat.byteskwargs(opts)
7412 opts = pycompat.byteskwargs(opts)
7415 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7413 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7416 displayer.show(repo[b'tip'])
7414 displayer.show(repo[b'tip'])
7417 displayer.close()
7415 displayer.close()
7418
7416
7419
7417
7420 @command(
7418 @command(
7421 b'unbundle',
7419 b'unbundle',
7422 [
7420 [
7423 (
7421 (
7424 b'u',
7422 b'u',
7425 b'update',
7423 b'update',
7426 None,
7424 None,
7427 _(b'update to new branch head if changesets were unbundled'),
7425 _(b'update to new branch head if changesets were unbundled'),
7428 )
7426 )
7429 ],
7427 ],
7430 _(b'[-u] FILE...'),
7428 _(b'[-u] FILE...'),
7431 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7429 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7432 )
7430 )
7433 def unbundle(ui, repo, fname1, *fnames, **opts):
7431 def unbundle(ui, repo, fname1, *fnames, **opts):
7434 """apply one or more bundle files
7432 """apply one or more bundle files
7435
7433
7436 Apply one or more bundle files generated by :hg:`bundle`.
7434 Apply one or more bundle files generated by :hg:`bundle`.
7437
7435
7438 Returns 0 on success, 1 if an update has unresolved files.
7436 Returns 0 on success, 1 if an update has unresolved files.
7439 """
7437 """
7440 fnames = (fname1,) + fnames
7438 fnames = (fname1,) + fnames
7441
7439
7442 with repo.lock():
7440 with repo.lock():
7443 for fname in fnames:
7441 for fname in fnames:
7444 f = hg.openpath(ui, fname)
7442 f = hg.openpath(ui, fname)
7445 gen = exchange.readbundle(ui, f, fname)
7443 gen = exchange.readbundle(ui, f, fname)
7446 if isinstance(gen, streamclone.streamcloneapplier):
7444 if isinstance(gen, streamclone.streamcloneapplier):
7447 raise error.Abort(
7445 raise error.Abort(
7448 _(
7446 _(
7449 b'packed bundles cannot be applied with '
7447 b'packed bundles cannot be applied with '
7450 b'"hg unbundle"'
7448 b'"hg unbundle"'
7451 ),
7449 ),
7452 hint=_(b'use "hg debugapplystreamclonebundle"'),
7450 hint=_(b'use "hg debugapplystreamclonebundle"'),
7453 )
7451 )
7454 url = b'bundle:' + fname
7452 url = b'bundle:' + fname
7455 try:
7453 try:
7456 txnname = b'unbundle'
7454 txnname = b'unbundle'
7457 if not isinstance(gen, bundle2.unbundle20):
7455 if not isinstance(gen, bundle2.unbundle20):
7458 txnname = b'unbundle\n%s' % util.hidepassword(url)
7456 txnname = b'unbundle\n%s' % util.hidepassword(url)
7459 with repo.transaction(txnname) as tr:
7457 with repo.transaction(txnname) as tr:
7460 op = bundle2.applybundle(
7458 op = bundle2.applybundle(
7461 repo, gen, tr, source=b'unbundle', url=url
7459 repo, gen, tr, source=b'unbundle', url=url
7462 )
7460 )
7463 except error.BundleUnknownFeatureError as exc:
7461 except error.BundleUnknownFeatureError as exc:
7464 raise error.Abort(
7462 raise error.Abort(
7465 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7463 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7466 hint=_(
7464 hint=_(
7467 b"see https://mercurial-scm.org/"
7465 b"see https://mercurial-scm.org/"
7468 b"wiki/BundleFeature for more "
7466 b"wiki/BundleFeature for more "
7469 b"information"
7467 b"information"
7470 ),
7468 ),
7471 )
7469 )
7472 modheads = bundle2.combinechangegroupresults(op)
7470 modheads = bundle2.combinechangegroupresults(op)
7473
7471
7474 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
7472 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
7475
7473
7476
7474
7477 @command(
7475 @command(
7478 b'unshelve',
7476 b'unshelve',
7479 [
7477 [
7480 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7478 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7481 (
7479 (
7482 b'c',
7480 b'c',
7483 b'continue',
7481 b'continue',
7484 None,
7482 None,
7485 _(b'continue an incomplete unshelve operation'),
7483 _(b'continue an incomplete unshelve operation'),
7486 ),
7484 ),
7487 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7485 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7488 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7486 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7489 (
7487 (
7490 b'n',
7488 b'n',
7491 b'name',
7489 b'name',
7492 b'',
7490 b'',
7493 _(b'restore shelved change with given name'),
7491 _(b'restore shelved change with given name'),
7494 _(b'NAME'),
7492 _(b'NAME'),
7495 ),
7493 ),
7496 (b't', b'tool', b'', _(b'specify merge tool')),
7494 (b't', b'tool', b'', _(b'specify merge tool')),
7497 (
7495 (
7498 b'',
7496 b'',
7499 b'date',
7497 b'date',
7500 b'',
7498 b'',
7501 _(b'set date for temporary commits (DEPRECATED)'),
7499 _(b'set date for temporary commits (DEPRECATED)'),
7502 _(b'DATE'),
7500 _(b'DATE'),
7503 ),
7501 ),
7504 ],
7502 ],
7505 _(b'hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
7503 _(b'hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
7506 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7504 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7507 )
7505 )
7508 def unshelve(ui, repo, *shelved, **opts):
7506 def unshelve(ui, repo, *shelved, **opts):
7509 """restore a shelved change to the working directory
7507 """restore a shelved change to the working directory
7510
7508
7511 This command accepts an optional name of a shelved change to
7509 This command accepts an optional name of a shelved change to
7512 restore. If none is given, the most recent shelved change is used.
7510 restore. If none is given, the most recent shelved change is used.
7513
7511
7514 If a shelved change is applied successfully, the bundle that
7512 If a shelved change is applied successfully, the bundle that
7515 contains the shelved changes is moved to a backup location
7513 contains the shelved changes is moved to a backup location
7516 (.hg/shelve-backup).
7514 (.hg/shelve-backup).
7517
7515
7518 Since you can restore a shelved change on top of an arbitrary
7516 Since you can restore a shelved change on top of an arbitrary
7519 commit, it is possible that unshelving will result in a conflict
7517 commit, it is possible that unshelving will result in a conflict
7520 between your changes and the commits you are unshelving onto. If
7518 between your changes and the commits you are unshelving onto. If
7521 this occurs, you must resolve the conflict, then use
7519 this occurs, you must resolve the conflict, then use
7522 ``--continue`` to complete the unshelve operation. (The bundle
7520 ``--continue`` to complete the unshelve operation. (The bundle
7523 will not be moved until you successfully complete the unshelve.)
7521 will not be moved until you successfully complete the unshelve.)
7524
7522
7525 (Alternatively, you can use ``--abort`` to abandon an unshelve
7523 (Alternatively, you can use ``--abort`` to abandon an unshelve
7526 that causes a conflict. This reverts the unshelved changes, and
7524 that causes a conflict. This reverts the unshelved changes, and
7527 leaves the bundle in place.)
7525 leaves the bundle in place.)
7528
7526
7529 If bare shelved change (when no files are specified, without interactive,
7527 If bare shelved change (when no files are specified, without interactive,
7530 include and exclude option) was done on newly created branch it would
7528 include and exclude option) was done on newly created branch it would
7531 restore branch information to the working directory.
7529 restore branch information to the working directory.
7532
7530
7533 After a successful unshelve, the shelved changes are stored in a
7531 After a successful unshelve, the shelved changes are stored in a
7534 backup directory. Only the N most recent backups are kept. N
7532 backup directory. Only the N most recent backups are kept. N
7535 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7533 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7536 configuration option.
7534 configuration option.
7537
7535
7538 .. container:: verbose
7536 .. container:: verbose
7539
7537
7540 Timestamp in seconds is used to decide order of backups. More
7538 Timestamp in seconds is used to decide order of backups. More
7541 than ``maxbackups`` backups are kept, if same timestamp
7539 than ``maxbackups`` backups are kept, if same timestamp
7542 prevents from deciding exact order of them, for safety.
7540 prevents from deciding exact order of them, for safety.
7543
7541
7544 Selected changes can be unshelved with ``--interactive`` flag.
7542 Selected changes can be unshelved with ``--interactive`` flag.
7545 The working directory is updated with the selected changes, and
7543 The working directory is updated with the selected changes, and
7546 only the unselected changes remain shelved.
7544 only the unselected changes remain shelved.
7547 Note: The whole shelve is applied to working directory first before
7545 Note: The whole shelve is applied to working directory first before
7548 running interactively. So, this will bring up all the conflicts between
7546 running interactively. So, this will bring up all the conflicts between
7549 working directory and the shelve, irrespective of which changes will be
7547 working directory and the shelve, irrespective of which changes will be
7550 unshelved.
7548 unshelved.
7551 """
7549 """
7552 with repo.wlock():
7550 with repo.wlock():
7553 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7551 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7554
7552
7555
7553
7556 statemod.addunfinished(
7554 statemod.addunfinished(
7557 b'unshelve',
7555 b'unshelve',
7558 fname=b'shelvedstate',
7556 fname=b'shelvedstate',
7559 continueflag=True,
7557 continueflag=True,
7560 abortfunc=shelvemod.hgabortunshelve,
7558 abortfunc=shelvemod.hgabortunshelve,
7561 continuefunc=shelvemod.hgcontinueunshelve,
7559 continuefunc=shelvemod.hgcontinueunshelve,
7562 cmdmsg=_(b'unshelve already in progress'),
7560 cmdmsg=_(b'unshelve already in progress'),
7563 )
7561 )
7564
7562
7565
7563
7566 @command(
7564 @command(
7567 b'update|up|checkout|co',
7565 b'update|up|checkout|co',
7568 [
7566 [
7569 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7567 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7570 (b'c', b'check', None, _(b'require clean working directory')),
7568 (b'c', b'check', None, _(b'require clean working directory')),
7571 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7569 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7572 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7570 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7573 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7571 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7574 ]
7572 ]
7575 + mergetoolopts,
7573 + mergetoolopts,
7576 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7574 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7577 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7575 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7578 helpbasic=True,
7576 helpbasic=True,
7579 )
7577 )
7580 def update(ui, repo, node=None, **opts):
7578 def update(ui, repo, node=None, **opts):
7581 """update working directory (or switch revisions)
7579 """update working directory (or switch revisions)
7582
7580
7583 Update the repository's working directory to the specified
7581 Update the repository's working directory to the specified
7584 changeset. If no changeset is specified, update to the tip of the
7582 changeset. If no changeset is specified, update to the tip of the
7585 current named branch and move the active bookmark (see :hg:`help
7583 current named branch and move the active bookmark (see :hg:`help
7586 bookmarks`).
7584 bookmarks`).
7587
7585
7588 Update sets the working directory's parent revision to the specified
7586 Update sets the working directory's parent revision to the specified
7589 changeset (see :hg:`help parents`).
7587 changeset (see :hg:`help parents`).
7590
7588
7591 If the changeset is not a descendant or ancestor of the working
7589 If the changeset is not a descendant or ancestor of the working
7592 directory's parent and there are uncommitted changes, the update is
7590 directory's parent and there are uncommitted changes, the update is
7593 aborted. With the -c/--check option, the working directory is checked
7591 aborted. With the -c/--check option, the working directory is checked
7594 for uncommitted changes; if none are found, the working directory is
7592 for uncommitted changes; if none are found, the working directory is
7595 updated to the specified changeset.
7593 updated to the specified changeset.
7596
7594
7597 .. container:: verbose
7595 .. container:: verbose
7598
7596
7599 The -C/--clean, -c/--check, and -m/--merge options control what
7597 The -C/--clean, -c/--check, and -m/--merge options control what
7600 happens if the working directory contains uncommitted changes.
7598 happens if the working directory contains uncommitted changes.
7601 At most of one of them can be specified.
7599 At most of one of them can be specified.
7602
7600
7603 1. If no option is specified, and if
7601 1. If no option is specified, and if
7604 the requested changeset is an ancestor or descendant of
7602 the requested changeset is an ancestor or descendant of
7605 the working directory's parent, the uncommitted changes
7603 the working directory's parent, the uncommitted changes
7606 are merged into the requested changeset and the merged
7604 are merged into the requested changeset and the merged
7607 result is left uncommitted. If the requested changeset is
7605 result is left uncommitted. If the requested changeset is
7608 not an ancestor or descendant (that is, it is on another
7606 not an ancestor or descendant (that is, it is on another
7609 branch), the update is aborted and the uncommitted changes
7607 branch), the update is aborted and the uncommitted changes
7610 are preserved.
7608 are preserved.
7611
7609
7612 2. With the -m/--merge option, the update is allowed even if the
7610 2. With the -m/--merge option, the update is allowed even if the
7613 requested changeset is not an ancestor or descendant of
7611 requested changeset is not an ancestor or descendant of
7614 the working directory's parent.
7612 the working directory's parent.
7615
7613
7616 3. With the -c/--check option, the update is aborted and the
7614 3. With the -c/--check option, the update is aborted and the
7617 uncommitted changes are preserved.
7615 uncommitted changes are preserved.
7618
7616
7619 4. With the -C/--clean option, uncommitted changes are discarded and
7617 4. With the -C/--clean option, uncommitted changes are discarded and
7620 the working directory is updated to the requested changeset.
7618 the working directory is updated to the requested changeset.
7621
7619
7622 To cancel an uncommitted merge (and lose your changes), use
7620 To cancel an uncommitted merge (and lose your changes), use
7623 :hg:`merge --abort`.
7621 :hg:`merge --abort`.
7624
7622
7625 Use null as the changeset to remove the working directory (like
7623 Use null as the changeset to remove the working directory (like
7626 :hg:`clone -U`).
7624 :hg:`clone -U`).
7627
7625
7628 If you want to revert just one file to an older revision, use
7626 If you want to revert just one file to an older revision, use
7629 :hg:`revert [-r REV] NAME`.
7627 :hg:`revert [-r REV] NAME`.
7630
7628
7631 See :hg:`help dates` for a list of formats valid for -d/--date.
7629 See :hg:`help dates` for a list of formats valid for -d/--date.
7632
7630
7633 Returns 0 on success, 1 if there are unresolved files.
7631 Returns 0 on success, 1 if there are unresolved files.
7634 """
7632 """
7635 rev = opts.get(r'rev')
7633 rev = opts.get(r'rev')
7636 date = opts.get(r'date')
7634 date = opts.get(r'date')
7637 clean = opts.get(r'clean')
7635 clean = opts.get(r'clean')
7638 check = opts.get(r'check')
7636 check = opts.get(r'check')
7639 merge = opts.get(r'merge')
7637 merge = opts.get(r'merge')
7640 if rev and node:
7638 if rev and node:
7641 raise error.Abort(_(b"please specify just one revision"))
7639 raise error.Abort(_(b"please specify just one revision"))
7642
7640
7643 if ui.configbool(b'commands', b'update.requiredest'):
7641 if ui.configbool(b'commands', b'update.requiredest'):
7644 if not node and not rev and not date:
7642 if not node and not rev and not date:
7645 raise error.Abort(
7643 raise error.Abort(
7646 _(b'you must specify a destination'),
7644 _(b'you must specify a destination'),
7647 hint=_(b'for example: hg update ".::"'),
7645 hint=_(b'for example: hg update ".::"'),
7648 )
7646 )
7649
7647
7650 if rev is None or rev == b'':
7648 if rev is None or rev == b'':
7651 rev = node
7649 rev = node
7652
7650
7653 if date and rev is not None:
7651 if date and rev is not None:
7654 raise error.Abort(_(b"you can't specify a revision and a date"))
7652 raise error.Abort(_(b"you can't specify a revision and a date"))
7655
7653
7656 if len([x for x in (clean, check, merge) if x]) > 1:
7654 if len([x for x in (clean, check, merge) if x]) > 1:
7657 raise error.Abort(
7655 raise error.Abort(
7658 _(
7656 _(
7659 b"can only specify one of -C/--clean, -c/--check, "
7657 b"can only specify one of -C/--clean, -c/--check, "
7660 b"or -m/--merge"
7658 b"or -m/--merge"
7661 )
7659 )
7662 )
7660 )
7663
7661
7664 updatecheck = None
7662 updatecheck = None
7665 if check:
7663 if check:
7666 updatecheck = b'abort'
7664 updatecheck = b'abort'
7667 elif merge:
7665 elif merge:
7668 updatecheck = b'none'
7666 updatecheck = b'none'
7669
7667
7670 with repo.wlock():
7668 with repo.wlock():
7671 cmdutil.clearunfinished(repo)
7669 cmdutil.clearunfinished(repo)
7672 if date:
7670 if date:
7673 rev = cmdutil.finddate(ui, repo, date)
7671 rev = cmdutil.finddate(ui, repo, date)
7674
7672
7675 # if we defined a bookmark, we have to remember the original name
7673 # if we defined a bookmark, we have to remember the original name
7676 brev = rev
7674 brev = rev
7677 if rev:
7675 if rev:
7678 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7676 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7679 ctx = scmutil.revsingle(repo, rev, default=None)
7677 ctx = scmutil.revsingle(repo, rev, default=None)
7680 rev = ctx.rev()
7678 rev = ctx.rev()
7681 hidden = ctx.hidden()
7679 hidden = ctx.hidden()
7682 overrides = {(b'ui', b'forcemerge'): opts.get(r'tool', b'')}
7680 overrides = {(b'ui', b'forcemerge'): opts.get(r'tool', b'')}
7683 with ui.configoverride(overrides, b'update'):
7681 with ui.configoverride(overrides, b'update'):
7684 ret = hg.updatetotally(
7682 ret = hg.updatetotally(
7685 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7683 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7686 )
7684 )
7687 if hidden:
7685 if hidden:
7688 ctxstr = ctx.hex()[:12]
7686 ctxstr = ctx.hex()[:12]
7689 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7687 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7690
7688
7691 if ctx.obsolete():
7689 if ctx.obsolete():
7692 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7690 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7693 ui.warn(b"(%s)\n" % obsfatemsg)
7691 ui.warn(b"(%s)\n" % obsfatemsg)
7694 return ret
7692 return ret
7695
7693
7696
7694
7697 @command(
7695 @command(
7698 b'verify',
7696 b'verify',
7699 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7697 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7700 helpcategory=command.CATEGORY_MAINTENANCE,
7698 helpcategory=command.CATEGORY_MAINTENANCE,
7701 )
7699 )
7702 def verify(ui, repo, **opts):
7700 def verify(ui, repo, **opts):
7703 """verify the integrity of the repository
7701 """verify the integrity of the repository
7704
7702
7705 Verify the integrity of the current repository.
7703 Verify the integrity of the current repository.
7706
7704
7707 This will perform an extensive check of the repository's
7705 This will perform an extensive check of the repository's
7708 integrity, validating the hashes and checksums of each entry in
7706 integrity, validating the hashes and checksums of each entry in
7709 the changelog, manifest, and tracked files, as well as the
7707 the changelog, manifest, and tracked files, as well as the
7710 integrity of their crosslinks and indices.
7708 integrity of their crosslinks and indices.
7711
7709
7712 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7710 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7713 for more information about recovery from corruption of the
7711 for more information about recovery from corruption of the
7714 repository.
7712 repository.
7715
7713
7716 Returns 0 on success, 1 if errors are encountered.
7714 Returns 0 on success, 1 if errors are encountered.
7717 """
7715 """
7718 opts = pycompat.byteskwargs(opts)
7716 opts = pycompat.byteskwargs(opts)
7719
7717
7720 level = None
7718 level = None
7721 if opts[b'full']:
7719 if opts[b'full']:
7722 level = verifymod.VERIFY_FULL
7720 level = verifymod.VERIFY_FULL
7723 return hg.verify(repo, level)
7721 return hg.verify(repo, level)
7724
7722
7725
7723
7726 @command(
7724 @command(
7727 b'version',
7725 b'version',
7728 [] + formatteropts,
7726 [] + formatteropts,
7729 helpcategory=command.CATEGORY_HELP,
7727 helpcategory=command.CATEGORY_HELP,
7730 norepo=True,
7728 norepo=True,
7731 intents={INTENT_READONLY},
7729 intents={INTENT_READONLY},
7732 )
7730 )
7733 def version_(ui, **opts):
7731 def version_(ui, **opts):
7734 """output version and copyright information
7732 """output version and copyright information
7735
7733
7736 .. container:: verbose
7734 .. container:: verbose
7737
7735
7738 Template:
7736 Template:
7739
7737
7740 The following keywords are supported. See also :hg:`help templates`.
7738 The following keywords are supported. See also :hg:`help templates`.
7741
7739
7742 :extensions: List of extensions.
7740 :extensions: List of extensions.
7743 :ver: String. Version number.
7741 :ver: String. Version number.
7744
7742
7745 And each entry of ``{extensions}`` provides the following sub-keywords
7743 And each entry of ``{extensions}`` provides the following sub-keywords
7746 in addition to ``{ver}``.
7744 in addition to ``{ver}``.
7747
7745
7748 :bundled: Boolean. True if included in the release.
7746 :bundled: Boolean. True if included in the release.
7749 :name: String. Extension name.
7747 :name: String. Extension name.
7750 """
7748 """
7751 opts = pycompat.byteskwargs(opts)
7749 opts = pycompat.byteskwargs(opts)
7752 if ui.verbose:
7750 if ui.verbose:
7753 ui.pager(b'version')
7751 ui.pager(b'version')
7754 fm = ui.formatter(b"version", opts)
7752 fm = ui.formatter(b"version", opts)
7755 fm.startitem()
7753 fm.startitem()
7756 fm.write(
7754 fm.write(
7757 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7755 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7758 )
7756 )
7759 license = _(
7757 license = _(
7760 b"(see https://mercurial-scm.org for more information)\n"
7758 b"(see https://mercurial-scm.org for more information)\n"
7761 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7759 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7762 b"This is free software; see the source for copying conditions. "
7760 b"This is free software; see the source for copying conditions. "
7763 b"There is NO\nwarranty; "
7761 b"There is NO\nwarranty; "
7764 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7762 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7765 )
7763 )
7766 if not ui.quiet:
7764 if not ui.quiet:
7767 fm.plain(license)
7765 fm.plain(license)
7768
7766
7769 if ui.verbose:
7767 if ui.verbose:
7770 fm.plain(_(b"\nEnabled extensions:\n\n"))
7768 fm.plain(_(b"\nEnabled extensions:\n\n"))
7771 # format names and versions into columns
7769 # format names and versions into columns
7772 names = []
7770 names = []
7773 vers = []
7771 vers = []
7774 isinternals = []
7772 isinternals = []
7775 for name, module in extensions.extensions():
7773 for name, module in extensions.extensions():
7776 names.append(name)
7774 names.append(name)
7777 vers.append(extensions.moduleversion(module) or None)
7775 vers.append(extensions.moduleversion(module) or None)
7778 isinternals.append(extensions.ismoduleinternal(module))
7776 isinternals.append(extensions.ismoduleinternal(module))
7779 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7777 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7780 if names:
7778 if names:
7781 namefmt = b" %%-%ds " % max(len(n) for n in names)
7779 namefmt = b" %%-%ds " % max(len(n) for n in names)
7782 places = [_(b"external"), _(b"internal")]
7780 places = [_(b"external"), _(b"internal")]
7783 for n, v, p in zip(names, vers, isinternals):
7781 for n, v, p in zip(names, vers, isinternals):
7784 fn.startitem()
7782 fn.startitem()
7785 fn.condwrite(ui.verbose, b"name", namefmt, n)
7783 fn.condwrite(ui.verbose, b"name", namefmt, n)
7786 if ui.verbose:
7784 if ui.verbose:
7787 fn.plain(b"%s " % places[p])
7785 fn.plain(b"%s " % places[p])
7788 fn.data(bundled=p)
7786 fn.data(bundled=p)
7789 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7787 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7790 if ui.verbose:
7788 if ui.verbose:
7791 fn.plain(b"\n")
7789 fn.plain(b"\n")
7792 fn.end()
7790 fn.end()
7793 fm.end()
7791 fm.end()
7794
7792
7795
7793
7796 def loadcmdtable(ui, name, cmdtable):
7794 def loadcmdtable(ui, name, cmdtable):
7797 """Load command functions from specified cmdtable
7795 """Load command functions from specified cmdtable
7798 """
7796 """
7799 overrides = [cmd for cmd in cmdtable if cmd in table]
7797 overrides = [cmd for cmd in cmdtable if cmd in table]
7800 if overrides:
7798 if overrides:
7801 ui.warn(
7799 ui.warn(
7802 _(b"extension '%s' overrides commands: %s\n")
7800 _(b"extension '%s' overrides commands: %s\n")
7803 % (name, b" ".join(overrides))
7801 % (name, b" ".join(overrides))
7804 )
7802 )
7805 table.update(cmdtable)
7803 table.update(cmdtable)
@@ -1,533 +1,735 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ echo import > port
3 $ echo import > port
4 $ hg add port
4 $ hg add port
5 $ hg commit -m 0 -u spam -d '0 0'
5 $ hg commit -m 0 -u spam -d '0 0'
6 $ echo export >> port
6 $ echo export >> port
7 $ hg commit -m 1 -u eggs -d '1 0'
7 $ hg commit -m 1 -u eggs -d '1 0'
8 $ echo export > port
8 $ echo export > port
9 $ echo vaportight >> port
9 $ echo vaportight >> port
10 $ echo 'import/export' >> port
10 $ echo 'import/export' >> port
11 $ hg commit -m 2 -u spam -d '2 0'
11 $ hg commit -m 2 -u spam -d '2 0'
12 $ echo 'import/export' >> port
12 $ echo 'import/export' >> port
13 $ hg commit -m 3 -u eggs -d '3 0'
13 $ hg commit -m 3 -u eggs -d '3 0'
14 $ head -n 3 port > port1
14 $ head -n 3 port > port1
15 $ mv port1 port
15 $ mv port1 port
16 $ hg commit -m 4 -u spam -d '4 0'
16 $ hg commit -m 4 -u spam -d '4 0'
17
17
18 pattern error
18 pattern error
19
19
20 $ hg grep '**test**'
20 $ hg grep '**test**'
21 grep: invalid match pattern: nothing to repeat* (glob)
21 grep: invalid match pattern: nothing to repeat* (glob)
22 [1]
22 [1]
23
23
24 simple
24 simple
25
25
26 $ hg grep -r tip:0 '.*'
26 $ hg grep -r tip:0 '.*'
27 port:4:export
27 port:4:export
28 port:4:vaportight
28 port:4:vaportight
29 port:4:import/export
29 port:4:import/export
30 port:3:export
31 port:3:vaportight
32 port:3:import/export
33 port:3:import/export
34 port:2:export
35 port:2:vaportight
36 port:2:import/export
37 port:1:import
38 port:1:export
39 port:0:import
30 $ hg grep -r tip:0 port port
40 $ hg grep -r tip:0 port port
31 port:4:export
41 port:4:export
32 port:4:vaportight
42 port:4:vaportight
33 port:4:import/export
43 port:4:import/export
44 port:3:export
45 port:3:vaportight
46 port:3:import/export
47 port:3:import/export
48 port:2:export
49 port:2:vaportight
50 port:2:import/export
51 port:1:import
52 port:1:export
53 port:0:import
34
54
35 simple from subdirectory
55 simple from subdirectory
36
56
37 $ mkdir dir
57 $ mkdir dir
38 $ cd dir
58 $ cd dir
39 $ hg grep -r tip:0 port
59 $ hg grep -r tip:0 port
40 port:4:export
60 port:4:export
41 port:4:vaportight
61 port:4:vaportight
42 port:4:import/export
62 port:4:import/export
63 port:3:export
64 port:3:vaportight
65 port:3:import/export
66 port:3:import/export
67 port:2:export
68 port:2:vaportight
69 port:2:import/export
70 port:1:import
71 port:1:export
72 port:0:import
43 $ hg grep -r tip:0 port --config ui.relative-paths=yes
73 $ hg grep -r tip:0 port --config ui.relative-paths=yes
44 ../port:4:export
74 ../port:4:export
45 ../port:4:vaportight
75 ../port:4:vaportight
46 ../port:4:import/export
76 ../port:4:import/export
77 ../port:3:export
78 ../port:3:vaportight
79 ../port:3:import/export
80 ../port:3:import/export
81 ../port:2:export
82 ../port:2:vaportight
83 ../port:2:import/export
84 ../port:1:import
85 ../port:1:export
86 ../port:0:import
47 $ cd ..
87 $ cd ..
48
88
49 simple with color
89 simple with color
50
90
51 $ hg --config extensions.color= grep --config color.mode=ansi \
91 $ hg --config extensions.color= grep --config color.mode=ansi \
52 > --color=always port port -r tip:0
92 > --color=always port port -r tip:0
53 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
93 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
54 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
94 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
55 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
95 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
96 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
97 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
98 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
99 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
100 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
101 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
102 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc)
103 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
104 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
105 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m0\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m (esc)
56
106
57 simple templated
107 simple templated
58
108
59 $ hg grep port -r tip:0 \
109 $ hg grep port -r tip:0 \
60 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
110 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
61 port:4:914fa752cdea:exPORT
111 port:4:914fa752cdea:exPORT
62 port:4:914fa752cdea:vaPORTight
112 port:4:914fa752cdea:vaPORTight
63 port:4:914fa752cdea:imPORT/exPORT
113 port:4:914fa752cdea:imPORT/exPORT
114 port:3:95040cfd017d:exPORT
115 port:3:95040cfd017d:vaPORTight
116 port:3:95040cfd017d:imPORT/exPORT
117 port:3:95040cfd017d:imPORT/exPORT
118 port:2:3b325e3481a1:exPORT
119 port:2:3b325e3481a1:vaPORTight
120 port:2:3b325e3481a1:imPORT/exPORT
121 port:1:8b20f75c1585:imPORT
122 port:1:8b20f75c1585:exPORT
123 port:0:f31323c92170:imPORT
64
124
65 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
125 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
66 port:4:export
126 port:4:export
67 port:4:vaportight
127 port:4:vaportight
68 port:4:import/export
128 port:4:import/export
129 port:3:export
130 port:3:vaportight
131 port:3:import/export
132 port:3:import/export
133 port:2:export
134 port:2:vaportight
135 port:2:import/export
136 port:1:import
137 port:1:export
138 port:0:import
69
139
70 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
140 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
71 port:tip:export
141 port:tip:export
72 port:tip:vaportight
142 port:tip:vaportight
73 port:tip:import/export
143 port:tip:import/export
144 port::export
145 port::vaportight
146 port::import/export
147 port::import/export
148 port::export
149 port::vaportight
150 port::import/export
151 port::import
152 port::export
153 port::import
74
154
75 simple JSON (no "change" field)
155 simple JSON (no "change" field)
76
156
77 $ hg grep -r tip:0 -Tjson port
157 $ hg grep -r tip:0 -Tjson port
78 [
158 [
79 {
159 {
80 "date": [4, 0],
160 "date": [4, 0],
81 "lineno": 1,
161 "lineno": 1,
82 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
162 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
83 "path": "port",
163 "path": "port",
84 "rev": 4,
164 "rev": 4,
85 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
165 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
86 "user": "spam"
166 "user": "spam"
87 },
167 },
88 {
168 {
89 "date": [4, 0],
169 "date": [4, 0],
90 "lineno": 2,
170 "lineno": 2,
91 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
171 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
92 "path": "port",
172 "path": "port",
93 "rev": 4,
173 "rev": 4,
94 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
174 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
95 "user": "spam"
175 "user": "spam"
96 },
176 },
97 {
177 {
98 "date": [4, 0],
178 "date": [4, 0],
99 "lineno": 3,
179 "lineno": 3,
100 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
180 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
101 "path": "port",
181 "path": "port",
102 "rev": 4,
182 "rev": 4,
103 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
183 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
104 "user": "spam"
184 "user": "spam"
185 },
186 {
187 "date": [3, 0],
188 "lineno": 1,
189 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
190 "path": "port",
191 "rev": 3,
192 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
193 "user": "eggs"
194 },
195 {
196 "date": [3, 0],
197 "lineno": 2,
198 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
199 "path": "port",
200 "rev": 3,
201 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
202 "user": "eggs"
203 },
204 {
205 "date": [3, 0],
206 "lineno": 3,
207 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
208 "path": "port",
209 "rev": 3,
210 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
211 "user": "eggs"
212 },
213 {
214 "date": [3, 0],
215 "lineno": 4,
216 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
217 "path": "port",
218 "rev": 3,
219 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
220 "user": "eggs"
221 },
222 {
223 "date": [2, 0],
224 "lineno": 1,
225 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
226 "path": "port",
227 "rev": 2,
228 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
229 "user": "spam"
230 },
231 {
232 "date": [2, 0],
233 "lineno": 2,
234 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
235 "path": "port",
236 "rev": 2,
237 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
238 "user": "spam"
239 },
240 {
241 "date": [2, 0],
242 "lineno": 3,
243 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
244 "path": "port",
245 "rev": 2,
246 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
247 "user": "spam"
248 },
249 {
250 "date": [1, 0],
251 "lineno": 1,
252 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
253 "path": "port",
254 "rev": 1,
255 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
256 "user": "eggs"
257 },
258 {
259 "date": [1, 0],
260 "lineno": 2,
261 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
262 "path": "port",
263 "rev": 1,
264 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
265 "user": "eggs"
266 },
267 {
268 "date": [0, 0],
269 "lineno": 1,
270 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
271 "path": "port",
272 "rev": 0,
273 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
274 "user": "spam"
105 }
275 }
106 ]
276 ]
107
277
108 simple JSON without matching lines
278 simple JSON without matching lines
109
279
110 $ hg grep -r tip:0 -Tjson -l port
280 $ hg grep -r tip:0 -Tjson -l port
111 [
281 [
112 {
282 {
113 "date": [4, 0],
283 "date": [4, 0],
114 "lineno": 1,
284 "lineno": 1,
115 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
285 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
116 "path": "port",
286 "path": "port",
117 "rev": 4,
287 "rev": 4,
118 "user": "spam"
288 "user": "spam"
289 },
290 {
291 "date": [3, 0],
292 "lineno": 1,
293 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
294 "path": "port",
295 "rev": 3,
296 "user": "eggs"
297 },
298 {
299 "date": [2, 0],
300 "lineno": 1,
301 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
302 "path": "port",
303 "rev": 2,
304 "user": "spam"
305 },
306 {
307 "date": [1, 0],
308 "lineno": 1,
309 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
310 "path": "port",
311 "rev": 1,
312 "user": "eggs"
313 },
314 {
315 "date": [0, 0],
316 "lineno": 1,
317 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
318 "path": "port",
319 "rev": 0,
320 "user": "spam"
119 }
321 }
120 ]
322 ]
121
323
122 all
324 all
123
325
124 $ hg grep --traceback --all -nu port port
326 $ hg grep --traceback --all -nu port port
125 port:4:4:-:spam:import/export
327 port:4:4:-:spam:import/export
126 port:3:4:+:eggs:import/export
328 port:3:4:+:eggs:import/export
127 port:2:1:-:spam:import
329 port:2:1:-:spam:import
128 port:2:2:-:spam:export
330 port:2:2:-:spam:export
129 port:2:1:+:spam:export
331 port:2:1:+:spam:export
130 port:2:2:+:spam:vaportight
332 port:2:2:+:spam:vaportight
131 port:2:3:+:spam:import/export
333 port:2:3:+:spam:import/export
132 port:1:2:+:eggs:export
334 port:1:2:+:eggs:export
133 port:0:1:+:spam:import
335 port:0:1:+:spam:import
134
336
135 all JSON
337 all JSON
136
338
137 $ hg grep --all -Tjson port port
339 $ hg grep --all -Tjson port port
138 [
340 [
139 {
341 {
140 "change": "-",
342 "change": "-",
141 "date": [4, 0],
343 "date": [4, 0],
142 "lineno": 4,
344 "lineno": 4,
143 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
345 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
144 "path": "port",
346 "path": "port",
145 "rev": 4,
347 "rev": 4,
146 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
348 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
147 "user": "spam"
349 "user": "spam"
148 },
350 },
149 {
351 {
150 "change": "+",
352 "change": "+",
151 "date": [3, 0],
353 "date": [3, 0],
152 "lineno": 4,
354 "lineno": 4,
153 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
355 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
154 "path": "port",
356 "path": "port",
155 "rev": 3,
357 "rev": 3,
156 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
358 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
157 "user": "eggs"
359 "user": "eggs"
158 },
360 },
159 {
361 {
160 "change": "-",
362 "change": "-",
161 "date": [2, 0],
363 "date": [2, 0],
162 "lineno": 1,
364 "lineno": 1,
163 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
365 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
164 "path": "port",
366 "path": "port",
165 "rev": 2,
367 "rev": 2,
166 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
368 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
167 "user": "spam"
369 "user": "spam"
168 },
370 },
169 {
371 {
170 "change": "-",
372 "change": "-",
171 "date": [2, 0],
373 "date": [2, 0],
172 "lineno": 2,
374 "lineno": 2,
173 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
375 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
174 "path": "port",
376 "path": "port",
175 "rev": 2,
377 "rev": 2,
176 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
378 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
177 "user": "spam"
379 "user": "spam"
178 },
380 },
179 {
381 {
180 "change": "+",
382 "change": "+",
181 "date": [2, 0],
383 "date": [2, 0],
182 "lineno": 1,
384 "lineno": 1,
183 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
385 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
184 "path": "port",
386 "path": "port",
185 "rev": 2,
387 "rev": 2,
186 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
388 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
187 "user": "spam"
389 "user": "spam"
188 },
390 },
189 {
391 {
190 "change": "+",
392 "change": "+",
191 "date": [2, 0],
393 "date": [2, 0],
192 "lineno": 2,
394 "lineno": 2,
193 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
395 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
194 "path": "port",
396 "path": "port",
195 "rev": 2,
397 "rev": 2,
196 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
398 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
197 "user": "spam"
399 "user": "spam"
198 },
400 },
199 {
401 {
200 "change": "+",
402 "change": "+",
201 "date": [2, 0],
403 "date": [2, 0],
202 "lineno": 3,
404 "lineno": 3,
203 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
405 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
204 "path": "port",
406 "path": "port",
205 "rev": 2,
407 "rev": 2,
206 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
408 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
207 "user": "spam"
409 "user": "spam"
208 },
410 },
209 {
411 {
210 "change": "+",
412 "change": "+",
211 "date": [1, 0],
413 "date": [1, 0],
212 "lineno": 2,
414 "lineno": 2,
213 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
415 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
214 "path": "port",
416 "path": "port",
215 "rev": 1,
417 "rev": 1,
216 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
418 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
217 "user": "eggs"
419 "user": "eggs"
218 },
420 },
219 {
421 {
220 "change": "+",
422 "change": "+",
221 "date": [0, 0],
423 "date": [0, 0],
222 "lineno": 1,
424 "lineno": 1,
223 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
425 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
224 "path": "port",
426 "path": "port",
225 "rev": 0,
427 "rev": 0,
226 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
428 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
227 "user": "spam"
429 "user": "spam"
228 }
430 }
229 ]
431 ]
230
432
231 other
433 other
232
434
233 $ hg grep -r tip:0 -l port port
435 $ hg grep -r tip:0 -l port port
234 port:4
436 port:4
437 port:3
438 port:2
439 port:1
440 port:0
235 $ hg grep -r tip:0 import port
441 $ hg grep -r tip:0 import port
236 port:4:import/export
442 port:4:import/export
443 port:3:import/export
444 port:3:import/export
445 port:2:import/export
446 port:1:import
447 port:0:import
237
448
238 $ hg cp port port2
449 $ hg cp port port2
239 $ hg commit -m 4 -u spam -d '5 0'
450 $ hg commit -m 4 -u spam -d '5 0'
240
451
241 follow
452 follow
242
453
243 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
454 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
244 port:0:import
455 [1]
245
246 $ echo deport >> port2
456 $ echo deport >> port2
247 $ hg commit -m 5 -u eggs -d '6 0'
457 $ hg commit -m 5 -u eggs -d '6 0'
248 $ hg grep -f --all -nu port port2
458 $ hg grep -f --all -nu port port2
249 port2:6:4:+:eggs:deport
459 port2:6:4:+:eggs:deport
250 port:4:4:-:spam:import/export
460 port:4:4:-:spam:import/export
251 port:3:4:+:eggs:import/export
461 port:3:4:+:eggs:import/export
252 port:2:1:-:spam:import
462 port:2:1:-:spam:import
253 port:2:2:-:spam:export
463 port:2:2:-:spam:export
254 port:2:1:+:spam:export
464 port:2:1:+:spam:export
255 port:2:2:+:spam:vaportight
465 port:2:2:+:spam:vaportight
256 port:2:3:+:spam:import/export
466 port:2:3:+:spam:import/export
257 port:1:2:+:eggs:export
467 port:1:2:+:eggs:export
258 port:0:1:+:spam:import
468 port:0:1:+:spam:import
259
469
260 $ hg up -q null
470 $ hg up -q null
261 $ hg grep -r 'reverse(:.)' -f port
471 $ hg grep -r 'reverse(:.)' -f port
262 port:0:import
472 port:0:import
263
473
264 Test wdir
474 Test wdir
265 (at least, this shouldn't crash)
475 (at least, this shouldn't crash)
266
476
267 $ hg up -q
477 $ hg up -q
268 $ echo wport >> port2
478 $ echo wport >> port2
269 $ hg stat
479 $ hg stat
270 M port2
480 M port2
271 $ hg grep -r 'wdir()' port
481 $ hg grep -r 'wdir()' port
482 port:2147483647:export
483 port:2147483647:vaportight
484 port:2147483647:import/export
272 port2:2147483647:export
485 port2:2147483647:export
273 port2:2147483647:vaportight
486 port2:2147483647:vaportight
274 port2:2147483647:import/export
487 port2:2147483647:import/export
275 port2:2147483647:deport
488 port2:2147483647:deport
276 port2:2147483647:wport
489 port2:2147483647:wport
277
490
278 $ cd ..
491 $ cd ..
279 $ hg init t2
492 $ hg init t2
280 $ cd t2
493 $ cd t2
281 $ hg grep -r tip:0 foobar foo
494 $ hg grep -r tip:0 foobar foo
282 [1]
495 [1]
283 $ hg grep -r tip:0 foobar
496 $ hg grep -r tip:0 foobar
284 [1]
497 [1]
285 $ echo blue >> color
498 $ echo blue >> color
286 $ echo black >> color
499 $ echo black >> color
287 $ hg add color
500 $ hg add color
288 $ hg ci -m 0
501 $ hg ci -m 0
289 $ echo orange >> color
502 $ echo orange >> color
290 $ hg ci -m 1
503 $ hg ci -m 1
291 $ echo black > color
504 $ echo black > color
292 $ hg ci -m 2
505 $ hg ci -m 2
293 $ echo orange >> color
506 $ echo orange >> color
294 $ echo blue >> color
507 $ echo blue >> color
295 $ hg ci -m 3
508 $ hg ci -m 3
296 $ hg grep -r tip:0 orange
509 $ hg grep -r tip:0 orange
297 color:3:orange
510 color:3:orange
511 color:1:orange
298 $ hg grep --all orange
512 $ hg grep --all orange
299 color:3:+:orange
513 color:3:+:orange
300 color:2:-:orange
514 color:2:-:orange
301 color:1:+:orange
515 color:1:+:orange
302 $ hg grep --diff orange --color=debug
516 $ hg grep --diff orange --color=debug
303 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
517 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
304 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
518 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
305 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
519 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
306
520
307 $ hg grep --diff orange --color=yes
521 $ hg grep --diff orange --color=yes
308 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
522 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m3\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
309 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
523 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m2\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1m-\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
310 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
524 \x1b[0;35mcolor\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;34m1\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32;1m+\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;31;1morange\x1b[0m (esc)
311
525
312 $ hg grep --diff orange
526 $ hg grep --diff orange
313 color:3:+:orange
527 color:3:+:orange
314 color:2:-:orange
528 color:2:-:orange
315 color:1:+:orange
529 color:1:+:orange
316
530
317 test substring match: '^' should only match at the beginning
531 test substring match: '^' should only match at the beginning
318
532
319 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
533 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
320 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
534 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
321 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
535 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
322 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
536 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
537 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.match|b]lack
538 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lue
539 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lack
540 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|o]range
541 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lue
542 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lack
323
543
324 match in last "line" without newline
544 match in last "line" without newline
325
545
326 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
546 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
327 $ hg ci -Amnoeol
547 $ hg ci -Amnoeol
328 adding noeol
548 adding noeol
329 $ hg grep -r tip:0 loop
549 $ hg grep -r tip:0 loop
330 noeol:4:no infinite loop
550 noeol:4:no infinite loop
331
551
332 $ cd ..
552 $ cd ..
333
553
334 Issue685: traceback in grep -r after rename
554 Issue685: traceback in grep -r after rename
335
555
336 Got a traceback when using grep on a single
556 Got a traceback when using grep on a single
337 revision with renamed files.
557 revision with renamed files.
338
558
339 $ hg init issue685
559 $ hg init issue685
340 $ cd issue685
560 $ cd issue685
341 $ echo octarine > color
561 $ echo octarine > color
342 $ hg ci -Amcolor
562 $ hg ci -Amcolor
343 adding color
563 adding color
344 $ hg rename color colour
564 $ hg rename color colour
345 $ hg ci -Am rename
565 $ hg ci -Am rename
346 $ hg grep -r tip:0 octarine
566 $ hg grep -r tip:0 octarine
347 colour:1:octarine
567 colour:1:octarine
348 color:0:octarine
568 color:0:octarine
349
569
350 Used to crash here
570 Used to crash here
351
571
352 $ hg grep -r 1 octarine
572 $ hg grep -r 1 octarine
353 colour:1:octarine
573 colour:1:octarine
354 $ cd ..
574 $ cd ..
355
575
356
576
357 Issue337: test that grep follows parent-child relationships instead
577 Issue337: test that grep follows parent-child relationships instead
358 of just using revision numbers.
578 of just using revision numbers.
359
579
360 $ hg init issue337
580 $ hg init issue337
361 $ cd issue337
581 $ cd issue337
362
582
363 $ echo white > color
583 $ echo white > color
364 $ hg commit -A -m "0 white"
584 $ hg commit -A -m "0 white"
365 adding color
585 adding color
366
586
367 $ echo red > color
587 $ echo red > color
368 $ hg commit -A -m "1 red"
588 $ hg commit -A -m "1 red"
369
589
370 $ hg update 0
590 $ hg update 0
371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
591 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 $ echo black > color
592 $ echo black > color
373 $ hg commit -A -m "2 black"
593 $ hg commit -A -m "2 black"
374 created new head
594 created new head
375
595
376 $ hg update --clean 1
596 $ hg update --clean 1
377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 $ echo blue > color
598 $ echo blue > color
379 $ hg commit -A -m "3 blue"
599 $ hg commit -A -m "3 blue"
380
600
381 $ hg grep --all red
601 $ hg grep --all red
382 color:3:-:red
602 color:3:-:red
383 color:1:+:red
603 color:1:+:red
384
604
385 $ hg grep --diff red
605 $ hg grep --diff red
386 color:3:-:red
606 color:3:-:red
387 color:1:+:red
607 color:1:+:red
388
608
389 Issue3885: test that changing revision order does not alter the
609 Issue3885: test that changing revision order does not alter the
390 revisions printed, just their order.
610 revisions printed, just their order.
391
611
392 $ hg grep --all red -r "all()"
612 $ hg grep --all red -r "all()"
393 color:1:+:red
613 color:1:+:red
394 color:3:-:red
614 color:3:-:red
395
615
396 $ hg grep --all red -r "reverse(all())"
616 $ hg grep --all red -r "reverse(all())"
397 color:3:-:red
617 color:3:-:red
398 color:1:+:red
618 color:1:+:red
399
619
400 $ hg grep --diff red -r "all()"
620 $ hg grep --diff red -r "all()"
401 color:1:+:red
621 color:1:+:red
402 color:3:-:red
622 color:3:-:red
403
623
404 $ hg grep --diff red -r "reverse(all())"
624 $ hg grep --diff red -r "reverse(all())"
405 color:3:-:red
625 color:3:-:red
406 color:1:+:red
626 color:1:+:red
407
627
408 $ cd ..
628 $ cd ..
409
629
410 $ hg init a
630 $ hg init a
411 $ cd a
631 $ cd a
412 $ cp "$TESTDIR/binfile.bin" .
632 $ cp "$TESTDIR/binfile.bin" .
413 $ hg add binfile.bin
633 $ hg add binfile.bin
414 $ hg ci -m 'add binfile.bin'
634 $ hg ci -m 'add binfile.bin'
415 $ hg grep "MaCam" --all
635 $ hg grep "MaCam" --all
416 binfile.bin:0:+: Binary file matches
636 binfile.bin:0:+: Binary file matches
417
637
418 $ hg grep "MaCam" --diff
638 $ hg grep "MaCam" --diff
419 binfile.bin:0:+: Binary file matches
639 binfile.bin:0:+: Binary file matches
420
640
421 $ cd ..
641 $ cd ..
422
642
423 Test for showing working of allfiles flag
643 Test for showing working of allfiles flag
424
644
425 $ hg init sng
645 $ hg init sng
426 $ cd sng
646 $ cd sng
427 $ echo "unmod" >> um
647 $ echo "unmod" >> um
428 $ hg ci -A -m "adds unmod to um"
648 $ hg ci -A -m "adds unmod to um"
429 adding um
649 adding um
430 $ echo "something else" >> new
650 $ echo "something else" >> new
431 $ hg ci -A -m "second commit"
651 $ hg ci -A -m "second commit"
432 adding new
652 adding new
433 $ hg grep -r "." "unmod"
653 $ hg grep -r "." "unmod"
434 [1]
435 $ hg grep -r "." "unmod" --all-files
436 um:1:unmod
654 um:1:unmod
437
655
438 With --all-files, the working directory is searched by default
656 Working directory is searched by default
439
657
440 $ echo modified >> new
658 $ echo modified >> new
441 $ hg grep --all-files mod
659 $ hg grep mod
442 new:modified
660 new:modified
443 um:unmod
661 um:unmod
444
662
445 which can be overridden by -rREV
663 which can be overridden by -rREV
446
664
447 $ hg grep --all-files -r. mod
665 $ hg grep -r. mod
448 um:1:unmod
666 um:1:unmod
449
667
450 commands.all-files can be negated by --no-all-files
668 $ hg grep --diff mod
451
452 $ hg grep --config commands.grep.all-files=True mod
453 new:modified
454 um:unmod
455 $ hg grep --config commands.grep.all-files=True --no-all-files mod
456 um:0:unmod
457
458 --diff --all-files makes no sense since --diff is the option to grep history
459
460 $ hg grep --diff --all-files um
461 abort: --diff and --all-files are mutually exclusive
462 [255]
463
464 but --diff should precede the commands.grep.all-files option
465
466 $ hg grep --config commands.grep.all-files=True --diff mod
467 um:0:+:unmod
669 um:0:+:unmod
468
670
469 $ cd ..
671 $ cd ..
470
672
471 Fix_Wdir(): test that passing wdir() t -r flag does greps on the
673 Fix_Wdir(): test that passing wdir() t -r flag does greps on the
472 files modified in the working directory
674 files modified in the working directory
473
675
474 $ cd a
676 $ cd a
475 $ echo "abracadara" >> a
677 $ echo "abracadara" >> a
476 $ hg add a
678 $ hg add a
477 $ hg grep -r "wdir()" "abra"
679 $ hg grep -r "wdir()" "abra"
478 a:2147483647:abracadara
680 a:2147483647:abracadara
479
681
480 $ cd ..
682 $ cd ..
481
683
482 Change Default of grep by ui.tweakdefaults, that is, the files not in current
684 Change Default of grep by ui.tweakdefaults, that is, the files not in current
483 working directory should not be grepp-ed on
685 working directory should not be grepp-ed on
484
686
485 $ hg init ab
687 $ hg init ab
486 $ cd ab
688 $ cd ab
487 $ cat <<'EOF' >> .hg/hgrc
689 $ cat <<'EOF' >> .hg/hgrc
488 > [ui]
690 > [ui]
489 > tweakdefaults = True
691 > tweakdefaults = True
490 > EOF
692 > EOF
491 $ echo "some text">>file1
693 $ echo "some text">>file1
492 $ hg add file1
694 $ hg add file1
493 $ hg commit -m "adds file1"
695 $ hg commit -m "adds file1"
494 $ hg mv file1 file2
696 $ hg mv file1 file2
495
697
496 wdir revision is hidden by default:
698 wdir revision is hidden by default:
497
699
498 $ hg grep "some"
700 $ hg grep "some"
499 file2:some text
701 file2:some text
500
702
501 but it should be available in template dict:
703 but it should be available in template dict:
502
704
503 $ hg grep "some" -Tjson
705 $ hg grep "some" -Tjson
504 [
706 [
505 {
707 {
506 "date": [0, 0],
708 "date": [0, 0],
507 "lineno": 1,
709 "lineno": 1,
508 "node": "ffffffffffffffffffffffffffffffffffffffff",
710 "node": "ffffffffffffffffffffffffffffffffffffffff",
509 "path": "file2",
711 "path": "file2",
510 "rev": 2147483647,
712 "rev": 2147483647,
511 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
713 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
512 "user": "test"
714 "user": "test"
513 }
715 }
514 ]
716 ]
515
717
516 $ cd ..
718 $ cd ..
517
719
518 test -rMULTIREV with --all-files
720 test -rMULTIREV
519
721
520 $ cd sng
722 $ cd sng
521 $ hg rm um
723 $ hg rm um
522 $ hg commit -m "deletes um"
724 $ hg commit -m "deletes um"
523 $ hg grep -r "0:2" "unmod" --all-files
725 $ hg grep -r "0:2" "unmod"
524 um:0:unmod
726 um:0:unmod
525 um:1:unmod
727 um:1:unmod
526 $ hg grep -r "0:2" "unmod" --all-files um
728 $ hg grep -r "0:2" "unmod" um
527 um:0:unmod
729 um:0:unmod
528 um:1:unmod
730 um:1:unmod
529 $ hg grep -r "0:2" "unmod" --all-files "glob:**/um" # Check that patterns also work
731 $ hg grep -r "0:2" "unmod" "glob:**/um" # Check that patterns also work
530 um:0:unmod
732 um:0:unmod
531 um:1:unmod
733 um:1:unmod
532 $ cd ..
734 $ cd ..
533
735
General Comments 0
You need to be logged in to leave comments. Login now