##// END OF EJS Templates
grep: restore usage of --include/--exclude options...
Jordi Gutiérrez Hermoso -
r52257:c6560ee5 stable
parent child Browse files
Show More
@@ -1,8057 +1,8057 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@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
8
9 import os
9 import os
10 import re
10 import re
11 import sys
11 import sys
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullid,
16 nullid,
17 nullrev,
17 nullrev,
18 short,
18 short,
19 wdirrev,
19 wdirrev,
20 )
20 )
21 from . import (
21 from . import (
22 admin_commands as admin_commands_mod,
22 admin_commands as admin_commands_mod,
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 bundlecaches,
26 bundlecaches,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 discovery,
32 discovery,
33 encoding,
33 encoding,
34 error,
34 error,
35 exchange,
35 exchange,
36 extensions,
36 extensions,
37 filemerge,
37 filemerge,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 grep as grepmod,
40 grep as grepmod,
41 hbisect,
41 hbisect,
42 help,
42 help,
43 hg,
43 hg,
44 logcmdutil,
44 logcmdutil,
45 merge as mergemod,
45 merge as mergemod,
46 mergestate as mergestatemod,
46 mergestate as mergestatemod,
47 narrowspec,
47 narrowspec,
48 obsolete,
48 obsolete,
49 obsutil,
49 obsutil,
50 patch,
50 patch,
51 phases,
51 phases,
52 pycompat,
52 pycompat,
53 rcutil,
53 rcutil,
54 registrar,
54 registrar,
55 requirements,
55 requirements,
56 revsetlang,
56 revsetlang,
57 rewriteutil,
57 rewriteutil,
58 scmutil,
58 scmutil,
59 server,
59 server,
60 shelve as shelvemod,
60 shelve as shelvemod,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
63 tags as tagsmod,
63 tags as tagsmod,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 verify as verifymod,
66 verify as verifymod,
67 vfs as vfsmod,
67 vfs as vfsmod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 procutil,
72 procutil,
73 stringutil,
73 stringutil,
74 urlutil,
74 urlutil,
75 )
75 )
76
76
77 table = {}
77 table = {}
78 table.update(debugcommandsmod.command._table)
78 table.update(debugcommandsmod.command._table)
79 table.update(admin_commands_mod.command._table)
79 table.update(admin_commands_mod.command._table)
80
80
81 command = registrar.command(table)
81 command = registrar.command(table)
82 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
83
83
84 # common command options
84 # common command options
85
85
86 globalopts = [
86 globalopts = [
87 (
87 (
88 b'R',
88 b'R',
89 b'repository',
89 b'repository',
90 b'',
90 b'',
91 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
92 _(b'REPO'),
92 _(b'REPO'),
93 ),
93 ),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (
95 (
96 b'y',
96 b'y',
97 b'noninteractive',
97 b'noninteractive',
98 None,
98 None,
99 _(
99 _(
100 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
101 ),
101 ),
102 ),
102 ),
103 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
105 (
105 (
106 b'',
106 b'',
107 b'color',
107 b'color',
108 b'',
108 b'',
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # and should not be translated
110 # and should not be translated
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b'TYPE'),
112 _(b'TYPE'),
113 ),
113 ),
114 (
114 (
115 b'',
115 b'',
116 b'config',
116 b'config',
117 [],
117 [],
118 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'CONFIG'),
119 _(b'CONFIG'),
120 ),
120 ),
121 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
123 (
123 (
124 b'',
124 b'',
125 b'encoding',
125 b'encoding',
126 encoding.encoding,
126 encoding.encoding,
127 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
128 _(b'ENCODE'),
128 _(b'ENCODE'),
129 ),
129 ),
130 (
130 (
131 b'',
131 b'',
132 b'encodingmode',
132 b'encodingmode',
133 encoding.encodingmode,
133 encoding.encodingmode,
134 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
135 _(b'MODE'),
135 _(b'MODE'),
136 ),
136 ),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (
143 (
144 b'',
144 b'',
145 b'pager',
145 b'pager',
146 b'auto',
146 b'auto',
147 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b'TYPE'),
148 _(b'TYPE'),
149 ),
149 ),
150 ]
150 ]
151
151
152 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
153 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
154 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
155 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
156 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
157 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
158 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
159 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
160 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
161 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
162 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
163 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
164 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
165 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
166 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
167 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
168
168
169 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
170
170
171
171
172 @command(
172 @command(
173 b'abort',
173 b'abort',
174 dryrunopts,
174 dryrunopts,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpbasic=True,
176 helpbasic=True,
177 )
177 )
178 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
179 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
180
180
181 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
182 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
183
183
184 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
185 """
185 """
186 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
187 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
188 if not abortstate:
188 if not abortstate:
189 raise error.StateError(_(b'no operation in progress'))
189 raise error.StateError(_(b'no operation in progress'))
190 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
191 raise error.InputError(
191 raise error.InputError(
192 (
192 (
193 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
194 % (abortstate._opname)
194 % (abortstate._opname)
195 ),
195 ),
196 hint=abortstate.hint(),
196 hint=abortstate.hint(),
197 )
197 )
198 if dryrun:
198 if dryrun:
199 ui.status(
199 ui.status(
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 )
201 )
202 return
202 return
203 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
204
204
205
205
206 @command(
206 @command(
207 b'add',
207 b'add',
208 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
209 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpbasic=True,
211 helpbasic=True,
212 inferrepo=True,
212 inferrepo=True,
213 )
213 )
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 with repo.wlock(), repo.dirstate.changing_files(repo):
257 with repo.wlock(), repo.dirstate.changing_files(repo):
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 with repo.wlock(), repo.dirstate.changing_files(repo):
336 with repo.wlock(), repo.dirstate.changing_files(repo):
337 matcher = scmutil.match(repo[None], pats, opts)
337 matcher = scmutil.match(repo[None], pats, opts)
338 relative = scmutil.anypats(pats, opts)
338 relative = scmutil.anypats(pats, opts)
339 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
340 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
341
341
342
342
343 @command(
343 @command(
344 b'annotate|blame',
344 b'annotate|blame',
345 [
345 [
346 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
347 (
347 (
348 b'',
348 b'',
349 b'follow',
349 b'follow',
350 None,
350 None,
351 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 _(b'follow copies/renames and list the filename (DEPRECATED)'),
352 ),
352 ),
353 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
354 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'a', b'text', None, _(b'treat all files as text')),
355 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'u', b'user', None, _(b'list the author (long with -v)')),
356 (b'f', b'file', None, _(b'list the filename')),
356 (b'f', b'file', None, _(b'list the filename')),
357 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'd', b'date', None, _(b'list the date (short with -q)')),
358 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'n', b'number', None, _(b'list the revision number (default)')),
359 (b'c', b'changeset', None, _(b'list the changeset')),
359 (b'c', b'changeset', None, _(b'list the changeset')),
360 (
360 (
361 b'l',
361 b'l',
362 b'line-number',
362 b'line-number',
363 None,
363 None,
364 _(b'show line number at the first appearance'),
364 _(b'show line number at the first appearance'),
365 ),
365 ),
366 (
366 (
367 b'',
367 b'',
368 b'skip',
368 b'skip',
369 [],
369 [],
370 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'revset to not display (EXPERIMENTAL)'),
371 _(b'REV'),
371 _(b'REV'),
372 ),
372 ),
373 ]
373 ]
374 + diffwsopts
374 + diffwsopts
375 + walkopts
375 + walkopts
376 + formatteropts,
376 + formatteropts,
377 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
378 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpcategory=command.CATEGORY_FILE_CONTENTS,
379 helpbasic=True,
379 helpbasic=True,
380 inferrepo=True,
380 inferrepo=True,
381 )
381 )
382 def annotate(ui, repo, *pats, **opts):
382 def annotate(ui, repo, *pats, **opts):
383 """show changeset information by line for each file
383 """show changeset information by line for each file
384
384
385 List changes in files, showing the revision id responsible for
385 List changes in files, showing the revision id responsible for
386 each line.
386 each line.
387
387
388 This command is useful for discovering when a change was made and
388 This command is useful for discovering when a change was made and
389 by whom.
389 by whom.
390
390
391 If you include --file, --user, or --date, the revision number is
391 If you include --file, --user, or --date, the revision number is
392 suppressed unless you also include --number.
392 suppressed unless you also include --number.
393
393
394 Without the -a/--text option, annotate will avoid processing files
394 Without the -a/--text option, annotate will avoid processing files
395 it detects as binary. With -a, annotate will annotate the file
395 it detects as binary. With -a, annotate will annotate the file
396 anyway, although the results will probably be neither useful
396 anyway, although the results will probably be neither useful
397 nor desirable.
397 nor desirable.
398
398
399 .. container:: verbose
399 .. container:: verbose
400
400
401 Template:
401 Template:
402
402
403 The following keywords are supported in addition to the common template
403 The following keywords are supported in addition to the common template
404 keywords and functions. See also :hg:`help templates`.
404 keywords and functions. See also :hg:`help templates`.
405
405
406 :lines: List of lines with annotation data.
406 :lines: List of lines with annotation data.
407 :path: String. Repository-absolute path of the specified file.
407 :path: String. Repository-absolute path of the specified file.
408
408
409 And each entry of ``{lines}`` provides the following sub-keywords in
409 And each entry of ``{lines}`` provides the following sub-keywords in
410 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
411
411
412 :line: String. Line content.
412 :line: String. Line content.
413 :lineno: Integer. Line number at that revision.
413 :lineno: Integer. Line number at that revision.
414 :path: String. Repository-absolute path of the file at that revision.
414 :path: String. Repository-absolute path of the file at that revision.
415
415
416 See :hg:`help templates.operators` for the list expansion syntax.
416 See :hg:`help templates.operators` for the list expansion syntax.
417
417
418 Returns 0 on success.
418 Returns 0 on success.
419 """
419 """
420 opts = pycompat.byteskwargs(opts)
420 opts = pycompat.byteskwargs(opts)
421 if not pats:
421 if not pats:
422 raise error.InputError(
422 raise error.InputError(
423 _(b'at least one filename or pattern is required')
423 _(b'at least one filename or pattern is required')
424 )
424 )
425
425
426 if opts.get(b'follow'):
426 if opts.get(b'follow'):
427 # --follow is deprecated and now just an alias for -f/--file
427 # --follow is deprecated and now just an alias for -f/--file
428 # to mimic the behavior of Mercurial before version 1.5
428 # to mimic the behavior of Mercurial before version 1.5
429 opts[b'file'] = True
429 opts[b'file'] = True
430
430
431 if (
431 if (
432 not opts.get(b'user')
432 not opts.get(b'user')
433 and not opts.get(b'changeset')
433 and not opts.get(b'changeset')
434 and not opts.get(b'date')
434 and not opts.get(b'date')
435 and not opts.get(b'file')
435 and not opts.get(b'file')
436 ):
436 ):
437 opts[b'number'] = True
437 opts[b'number'] = True
438
438
439 linenumber = opts.get(b'line_number') is not None
439 linenumber = opts.get(b'line_number') is not None
440 if (
440 if (
441 linenumber
441 linenumber
442 and (not opts.get(b'changeset'))
442 and (not opts.get(b'changeset'))
443 and (not opts.get(b'number'))
443 and (not opts.get(b'number'))
444 ):
444 ):
445 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
445 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
446
446
447 rev = opts.get(b'rev')
447 rev = opts.get(b'rev')
448 if rev:
448 if rev:
449 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
449 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
450 ctx = logcmdutil.revsingle(repo, rev)
450 ctx = logcmdutil.revsingle(repo, rev)
451
451
452 ui.pager(b'annotate')
452 ui.pager(b'annotate')
453 rootfm = ui.formatter(b'annotate', opts)
453 rootfm = ui.formatter(b'annotate', opts)
454 if ui.debugflag:
454 if ui.debugflag:
455 shorthex = pycompat.identity
455 shorthex = pycompat.identity
456 else:
456 else:
457
457
458 def shorthex(h):
458 def shorthex(h):
459 return h[:12]
459 return h[:12]
460
460
461 if ui.quiet:
461 if ui.quiet:
462 datefunc = dateutil.shortdate
462 datefunc = dateutil.shortdate
463 else:
463 else:
464 datefunc = dateutil.datestr
464 datefunc = dateutil.datestr
465 if ctx.rev() is None:
465 if ctx.rev() is None:
466 if opts.get(b'changeset'):
466 if opts.get(b'changeset'):
467 # omit "+" suffix which is appended to node hex
467 # omit "+" suffix which is appended to node hex
468 def formatrev(rev):
468 def formatrev(rev):
469 if rev == wdirrev:
469 if rev == wdirrev:
470 return b'%d' % ctx.p1().rev()
470 return b'%d' % ctx.p1().rev()
471 else:
471 else:
472 return b'%d' % rev
472 return b'%d' % rev
473
473
474 else:
474 else:
475
475
476 def formatrev(rev):
476 def formatrev(rev):
477 if rev == wdirrev:
477 if rev == wdirrev:
478 return b'%d+' % ctx.p1().rev()
478 return b'%d+' % ctx.p1().rev()
479 else:
479 else:
480 return b'%d ' % rev
480 return b'%d ' % rev
481
481
482 def formathex(h):
482 def formathex(h):
483 if h == repo.nodeconstants.wdirhex:
483 if h == repo.nodeconstants.wdirhex:
484 return b'%s+' % shorthex(hex(ctx.p1().node()))
484 return b'%s+' % shorthex(hex(ctx.p1().node()))
485 else:
485 else:
486 return b'%s ' % shorthex(h)
486 return b'%s ' % shorthex(h)
487
487
488 else:
488 else:
489 formatrev = b'%d'.__mod__
489 formatrev = b'%d'.__mod__
490 formathex = shorthex
490 formathex = shorthex
491
491
492 opmap = [
492 opmap = [
493 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
493 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
494 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
494 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
495 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
495 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
496 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
496 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
497 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
497 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
498 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
498 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
499 ]
499 ]
500 opnamemap = {
500 opnamemap = {
501 b'rev': b'number',
501 b'rev': b'number',
502 b'node': b'changeset',
502 b'node': b'changeset',
503 b'path': b'file',
503 b'path': b'file',
504 b'lineno': b'line_number',
504 b'lineno': b'line_number',
505 }
505 }
506
506
507 if rootfm.isplain():
507 if rootfm.isplain():
508
508
509 def makefunc(get, fmt):
509 def makefunc(get, fmt):
510 return lambda x: fmt(get(x))
510 return lambda x: fmt(get(x))
511
511
512 else:
512 else:
513
513
514 def makefunc(get, fmt):
514 def makefunc(get, fmt):
515 return get
515 return get
516
516
517 datahint = rootfm.datahint()
517 datahint = rootfm.datahint()
518 funcmap = [
518 funcmap = [
519 (makefunc(get, fmt), sep)
519 (makefunc(get, fmt), sep)
520 for fn, sep, get, fmt in opmap
520 for fn, sep, get, fmt in opmap
521 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
522 ]
522 ]
523 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
523 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
524 fields = b' '.join(
524 fields = b' '.join(
525 fn
525 fn
526 for fn, sep, get, fmt in opmap
526 for fn, sep, get, fmt in opmap
527 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
527 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
528 )
528 )
529
529
530 def bad(x, y):
530 def bad(x, y):
531 raise error.InputError(b"%s: %s" % (x, y))
531 raise error.InputError(b"%s: %s" % (x, y))
532
532
533 m = scmutil.match(ctx, pats, opts, badfn=bad)
533 m = scmutil.match(ctx, pats, opts, badfn=bad)
534
534
535 follow = not opts.get(b'no_follow')
535 follow = not opts.get(b'no_follow')
536 diffopts = patch.difffeatureopts(
536 diffopts = patch.difffeatureopts(
537 ui, opts, section=b'annotate', whitespace=True
537 ui, opts, section=b'annotate', whitespace=True
538 )
538 )
539 skiprevs = opts.get(b'skip')
539 skiprevs = opts.get(b'skip')
540 if skiprevs:
540 if skiprevs:
541 skiprevs = logcmdutil.revrange(repo, skiprevs)
541 skiprevs = logcmdutil.revrange(repo, skiprevs)
542
542
543 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
543 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
544 for abs in ctx.walk(m):
544 for abs in ctx.walk(m):
545 fctx = ctx[abs]
545 fctx = ctx[abs]
546 rootfm.startitem()
546 rootfm.startitem()
547 rootfm.data(path=abs)
547 rootfm.data(path=abs)
548 if not opts.get(b'text') and fctx.isbinary():
548 if not opts.get(b'text') and fctx.isbinary():
549 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
549 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
550 continue
550 continue
551
551
552 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
552 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
553 lines = fctx.annotate(
553 lines = fctx.annotate(
554 follow=follow, skiprevs=skiprevs, diffopts=diffopts
554 follow=follow, skiprevs=skiprevs, diffopts=diffopts
555 )
555 )
556 if not lines:
556 if not lines:
557 fm.end()
557 fm.end()
558 continue
558 continue
559 formats = []
559 formats = []
560 pieces = []
560 pieces = []
561
561
562 for f, sep in funcmap:
562 for f, sep in funcmap:
563 l = [f(n) for n in lines]
563 l = [f(n) for n in lines]
564 if fm.isplain():
564 if fm.isplain():
565 sizes = [encoding.colwidth(x) for x in l]
565 sizes = [encoding.colwidth(x) for x in l]
566 ml = max(sizes)
566 ml = max(sizes)
567 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
567 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
568 else:
568 else:
569 formats.append([b'%s'] * len(l))
569 formats.append([b'%s'] * len(l))
570 pieces.append(l)
570 pieces.append(l)
571
571
572 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
572 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
573 fm.startitem()
573 fm.startitem()
574 fm.context(fctx=n.fctx)
574 fm.context(fctx=n.fctx)
575 fm.write(fields, b"".join(f), *p)
575 fm.write(fields, b"".join(f), *p)
576 if n.skip:
576 if n.skip:
577 fmt = b"* %s"
577 fmt = b"* %s"
578 else:
578 else:
579 fmt = b": %s"
579 fmt = b": %s"
580 fm.write(b'line', fmt, n.text)
580 fm.write(b'line', fmt, n.text)
581
581
582 if not lines[-1].text.endswith(b'\n'):
582 if not lines[-1].text.endswith(b'\n'):
583 fm.plain(b'\n')
583 fm.plain(b'\n')
584 fm.end()
584 fm.end()
585
585
586 rootfm.end()
586 rootfm.end()
587
587
588
588
589 @command(
589 @command(
590 b'archive',
590 b'archive',
591 [
591 [
592 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
592 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
593 (
593 (
594 b'p',
594 b'p',
595 b'prefix',
595 b'prefix',
596 b'',
596 b'',
597 _(b'directory prefix for files in archive'),
597 _(b'directory prefix for files in archive'),
598 _(b'PREFIX'),
598 _(b'PREFIX'),
599 ),
599 ),
600 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
600 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
601 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
601 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
602 ]
602 ]
603 + subrepoopts
603 + subrepoopts
604 + walkopts,
604 + walkopts,
605 _(b'[OPTION]... DEST'),
605 _(b'[OPTION]... DEST'),
606 helpcategory=command.CATEGORY_IMPORT_EXPORT,
606 helpcategory=command.CATEGORY_IMPORT_EXPORT,
607 )
607 )
608 def archive(ui, repo, dest, **opts):
608 def archive(ui, repo, dest, **opts):
609 """create an unversioned archive of a repository revision
609 """create an unversioned archive of a repository revision
610
610
611 By default, the revision used is the parent of the working
611 By default, the revision used is the parent of the working
612 directory; use -r/--rev to specify a different revision.
612 directory; use -r/--rev to specify a different revision.
613
613
614 The archive type is automatically detected based on file
614 The archive type is automatically detected based on file
615 extension (to override, use -t/--type).
615 extension (to override, use -t/--type).
616
616
617 .. container:: verbose
617 .. container:: verbose
618
618
619 Examples:
619 Examples:
620
620
621 - create a zip file containing the 1.0 release::
621 - create a zip file containing the 1.0 release::
622
622
623 hg archive -r 1.0 project-1.0.zip
623 hg archive -r 1.0 project-1.0.zip
624
624
625 - create a tarball excluding .hg files::
625 - create a tarball excluding .hg files::
626
626
627 hg archive project.tar.gz -X ".hg*"
627 hg archive project.tar.gz -X ".hg*"
628
628
629 Valid types are:
629 Valid types are:
630
630
631 :``files``: a directory full of files (default)
631 :``files``: a directory full of files (default)
632 :``tar``: tar archive, uncompressed
632 :``tar``: tar archive, uncompressed
633 :``tbz2``: tar archive, compressed using bzip2
633 :``tbz2``: tar archive, compressed using bzip2
634 :``tgz``: tar archive, compressed using gzip
634 :``tgz``: tar archive, compressed using gzip
635 :``txz``: tar archive, compressed using lzma (only in Python 3)
635 :``txz``: tar archive, compressed using lzma (only in Python 3)
636 :``uzip``: zip archive, uncompressed
636 :``uzip``: zip archive, uncompressed
637 :``zip``: zip archive, compressed using deflate
637 :``zip``: zip archive, compressed using deflate
638
638
639 The exact name of the destination archive or directory is given
639 The exact name of the destination archive or directory is given
640 using a format string; see :hg:`help export` for details.
640 using a format string; see :hg:`help export` for details.
641
641
642 Each member added to an archive file has a directory prefix
642 Each member added to an archive file has a directory prefix
643 prepended. Use -p/--prefix to specify a format string for the
643 prepended. Use -p/--prefix to specify a format string for the
644 prefix. The default is the basename of the archive, with suffixes
644 prefix. The default is the basename of the archive, with suffixes
645 removed.
645 removed.
646
646
647 Returns 0 on success.
647 Returns 0 on success.
648 """
648 """
649
649
650 rev = opts.get('rev')
650 rev = opts.get('rev')
651 if rev:
651 if rev:
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
653 ctx = logcmdutil.revsingle(repo, rev)
653 ctx = logcmdutil.revsingle(repo, rev)
654 if not ctx:
654 if not ctx:
655 raise error.InputError(
655 raise error.InputError(
656 _(b'no working directory: please specify a revision')
656 _(b'no working directory: please specify a revision')
657 )
657 )
658 node = ctx.node()
658 node = ctx.node()
659 dest = cmdutil.makefilename(ctx, dest)
659 dest = cmdutil.makefilename(ctx, dest)
660 if os.path.realpath(dest) == repo.root:
660 if os.path.realpath(dest) == repo.root:
661 raise error.InputError(_(b'repository root cannot be destination'))
661 raise error.InputError(_(b'repository root cannot be destination'))
662
662
663 kind = opts.get('type') or archival.guesskind(dest) or b'files'
663 kind = opts.get('type') or archival.guesskind(dest) or b'files'
664 prefix = opts.get('prefix')
664 prefix = opts.get('prefix')
665
665
666 if dest == b'-':
666 if dest == b'-':
667 if kind == b'files':
667 if kind == b'files':
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
669 dest = cmdutil.makefileobj(ctx, dest)
669 dest = cmdutil.makefileobj(ctx, dest)
670 if not prefix:
670 if not prefix:
671 prefix = os.path.basename(repo.root) + b'-%h'
671 prefix = os.path.basename(repo.root) + b'-%h'
672
672
673 prefix = cmdutil.makefilename(ctx, prefix)
673 prefix = cmdutil.makefilename(ctx, prefix)
674 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
674 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
675 archival.archive(
675 archival.archive(
676 repo,
676 repo,
677 dest,
677 dest,
678 node,
678 node,
679 kind,
679 kind,
680 not opts.get('no_decode'),
680 not opts.get('no_decode'),
681 match,
681 match,
682 prefix,
682 prefix,
683 subrepos=opts.get('subrepos'),
683 subrepos=opts.get('subrepos'),
684 )
684 )
685
685
686
686
687 @command(
687 @command(
688 b'backout',
688 b'backout',
689 [
689 [
690 (
690 (
691 b'',
691 b'',
692 b'merge',
692 b'merge',
693 None,
693 None,
694 _(b'merge with old dirstate parent after backout'),
694 _(b'merge with old dirstate parent after backout'),
695 ),
695 ),
696 (
696 (
697 b'',
697 b'',
698 b'commit',
698 b'commit',
699 None,
699 None,
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
701 ),
701 ),
702 (b'', b'no-commit', None, _(b'do not commit')),
702 (b'', b'no-commit', None, _(b'do not commit')),
703 (
703 (
704 b'',
704 b'',
705 b'parent',
705 b'parent',
706 b'',
706 b'',
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
708 _(b'REV'),
708 _(b'REV'),
709 ),
709 ),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
712 ]
712 ]
713 + mergetoolopts
713 + mergetoolopts
714 + walkopts
714 + walkopts
715 + commitopts
715 + commitopts
716 + commitopts2,
716 + commitopts2,
717 _(b'[OPTION]... [-r] REV'),
717 _(b'[OPTION]... [-r] REV'),
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
719 )
719 )
720 def backout(ui, repo, node=None, rev=None, **opts):
720 def backout(ui, repo, node=None, rev=None, **opts):
721 """reverse effect of earlier changeset
721 """reverse effect of earlier changeset
722
722
723 Prepare a new changeset with the effect of REV undone in the
723 Prepare a new changeset with the effect of REV undone in the
724 current working directory. If no conflicts were encountered,
724 current working directory. If no conflicts were encountered,
725 it will be committed immediately.
725 it will be committed immediately.
726
726
727 If REV is the parent of the working directory, then this new changeset
727 If REV is the parent of the working directory, then this new changeset
728 is committed automatically (unless --no-commit is specified).
728 is committed automatically (unless --no-commit is specified).
729
729
730 .. note::
730 .. note::
731
731
732 :hg:`backout` cannot be used to fix either an unwanted or
732 :hg:`backout` cannot be used to fix either an unwanted or
733 incorrect merge.
733 incorrect merge.
734
734
735 .. container:: verbose
735 .. container:: verbose
736
736
737 Examples:
737 Examples:
738
738
739 - Reverse the effect of the parent of the working directory.
739 - Reverse the effect of the parent of the working directory.
740 This backout will be committed immediately::
740 This backout will be committed immediately::
741
741
742 hg backout -r .
742 hg backout -r .
743
743
744 - Reverse the effect of previous bad revision 23::
744 - Reverse the effect of previous bad revision 23::
745
745
746 hg backout -r 23
746 hg backout -r 23
747
747
748 - Reverse the effect of previous bad revision 23 and
748 - Reverse the effect of previous bad revision 23 and
749 leave changes uncommitted::
749 leave changes uncommitted::
750
750
751 hg backout -r 23 --no-commit
751 hg backout -r 23 --no-commit
752 hg commit -m "Backout revision 23"
752 hg commit -m "Backout revision 23"
753
753
754 By default, the pending changeset will have one parent,
754 By default, the pending changeset will have one parent,
755 maintaining a linear history. With --merge, the pending
755 maintaining a linear history. With --merge, the pending
756 changeset will instead have two parents: the old parent of the
756 changeset will instead have two parents: the old parent of the
757 working directory and a new child of REV that simply undoes REV.
757 working directory and a new child of REV that simply undoes REV.
758
758
759 Before version 1.7, the behavior without --merge was equivalent
759 Before version 1.7, the behavior without --merge was equivalent
760 to specifying --merge followed by :hg:`update --clean .` to
760 to specifying --merge followed by :hg:`update --clean .` to
761 cancel the merge and leave the child of REV as a head to be
761 cancel the merge and leave the child of REV as a head to be
762 merged separately.
762 merged separately.
763
763
764 See :hg:`help dates` for a list of formats valid for -d/--date.
764 See :hg:`help dates` for a list of formats valid for -d/--date.
765
765
766 See :hg:`help revert` for a way to restore files to the state
766 See :hg:`help revert` for a way to restore files to the state
767 of another revision.
767 of another revision.
768
768
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
770 files.
770 files.
771 """
771 """
772 with repo.wlock(), repo.lock():
772 with repo.wlock(), repo.lock():
773 return _dobackout(ui, repo, node, rev, **opts)
773 return _dobackout(ui, repo, node, rev, **opts)
774
774
775
775
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
778
778
779 if rev and node:
779 if rev and node:
780 raise error.InputError(_(b"please specify just one revision"))
780 raise error.InputError(_(b"please specify just one revision"))
781
781
782 if not rev:
782 if not rev:
783 rev = node
783 rev = node
784
784
785 if not rev:
785 if not rev:
786 raise error.InputError(_(b"please specify a revision to backout"))
786 raise error.InputError(_(b"please specify a revision to backout"))
787
787
788 date = opts.get('date')
788 date = opts.get('date')
789 if date:
789 if date:
790 opts['date'] = dateutil.parsedate(date)
790 opts['date'] = dateutil.parsedate(date)
791
791
792 cmdutil.checkunfinished(repo)
792 cmdutil.checkunfinished(repo)
793 cmdutil.bailifchanged(repo)
793 cmdutil.bailifchanged(repo)
794 ctx = logcmdutil.revsingle(repo, rev)
794 ctx = logcmdutil.revsingle(repo, rev)
795 node = ctx.node()
795 node = ctx.node()
796
796
797 op1, op2 = repo.dirstate.parents()
797 op1, op2 = repo.dirstate.parents()
798 if not repo.changelog.isancestor(node, op1):
798 if not repo.changelog.isancestor(node, op1):
799 raise error.InputError(
799 raise error.InputError(
800 _(b'cannot backout change that is not an ancestor')
800 _(b'cannot backout change that is not an ancestor')
801 )
801 )
802
802
803 p1, p2 = repo.changelog.parents(node)
803 p1, p2 = repo.changelog.parents(node)
804 if p1 == repo.nullid:
804 if p1 == repo.nullid:
805 raise error.InputError(_(b'cannot backout a change with no parents'))
805 raise error.InputError(_(b'cannot backout a change with no parents'))
806 if p2 != repo.nullid:
806 if p2 != repo.nullid:
807 if not opts.get('parent'):
807 if not opts.get('parent'):
808 raise error.InputError(_(b'cannot backout a merge changeset'))
808 raise error.InputError(_(b'cannot backout a merge changeset'))
809 p = repo.lookup(opts['parent'])
809 p = repo.lookup(opts['parent'])
810 if p not in (p1, p2):
810 if p not in (p1, p2):
811 raise error.InputError(
811 raise error.InputError(
812 _(b'%s is not a parent of %s') % (short(p), short(node))
812 _(b'%s is not a parent of %s') % (short(p), short(node))
813 )
813 )
814 parent = p
814 parent = p
815 else:
815 else:
816 if opts.get('parent'):
816 if opts.get('parent'):
817 raise error.InputError(
817 raise error.InputError(
818 _(b'cannot use --parent on non-merge changeset')
818 _(b'cannot use --parent on non-merge changeset')
819 )
819 )
820 parent = p1
820 parent = p1
821
821
822 # the backout should appear on the same branch
822 # the backout should appear on the same branch
823 branch = repo.dirstate.branch()
823 branch = repo.dirstate.branch()
824 bheads = repo.branchheads(branch)
824 bheads = repo.branchheads(branch)
825 rctx = scmutil.revsingle(repo, hex(parent))
825 rctx = scmutil.revsingle(repo, hex(parent))
826 if not opts.get('merge') and op1 != node:
826 if not opts.get('merge') and op1 != node:
827 with repo.transaction(b"backout"):
827 with repo.transaction(b"backout"):
828 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
828 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
829 with ui.configoverride(overrides, b'backout'):
829 with ui.configoverride(overrides, b'backout'):
830 stats = mergemod.back_out(ctx, parent=repo[parent])
830 stats = mergemod.back_out(ctx, parent=repo[parent])
831 repo.setparents(op1, op2)
831 repo.setparents(op1, op2)
832 hg._showstats(repo, stats)
832 hg._showstats(repo, stats)
833 if stats.unresolvedcount:
833 if stats.unresolvedcount:
834 repo.ui.status(
834 repo.ui.status(
835 _(b"use 'hg resolve' to retry unresolved file merges\n")
835 _(b"use 'hg resolve' to retry unresolved file merges\n")
836 )
836 )
837 return 1
837 return 1
838 else:
838 else:
839 hg.clean(repo, node, show_stats=False)
839 hg.clean(repo, node, show_stats=False)
840 repo.dirstate.setbranch(branch, repo.currenttransaction())
840 repo.dirstate.setbranch(branch, repo.currenttransaction())
841 cmdutil.revert(ui, repo, rctx)
841 cmdutil.revert(ui, repo, rctx)
842
842
843 if opts.get('no_commit'):
843 if opts.get('no_commit'):
844 msg = _(b"changeset %s backed out, don't forget to commit.\n")
844 msg = _(b"changeset %s backed out, don't forget to commit.\n")
845 ui.status(msg % short(node))
845 ui.status(msg % short(node))
846 return 0
846 return 0
847
847
848 def commitfunc(ui, repo, message, match, opts):
848 def commitfunc(ui, repo, message, match, opts):
849 editform = b'backout'
849 editform = b'backout'
850 e = cmdutil.getcommiteditor(
850 e = cmdutil.getcommiteditor(
851 editform=editform, **pycompat.strkwargs(opts)
851 editform=editform, **pycompat.strkwargs(opts)
852 )
852 )
853 if not message:
853 if not message:
854 # we don't translate commit messages
854 # we don't translate commit messages
855 message = b"Backed out changeset %s" % short(node)
855 message = b"Backed out changeset %s" % short(node)
856 e = cmdutil.getcommiteditor(edit=True, editform=editform)
856 e = cmdutil.getcommiteditor(edit=True, editform=editform)
857 return repo.commit(
857 return repo.commit(
858 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
858 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
859 )
859 )
860
860
861 # save to detect changes
861 # save to detect changes
862 tip = repo.changelog.tip()
862 tip = repo.changelog.tip()
863
863
864 newnode = cmdutil.commit(
864 newnode = cmdutil.commit(
865 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
865 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
866 )
866 )
867 if not newnode:
867 if not newnode:
868 ui.status(_(b"nothing changed\n"))
868 ui.status(_(b"nothing changed\n"))
869 return 1
869 return 1
870 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
870 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
871
871
872 def nice(node):
872 def nice(node):
873 return b'%d:%s' % (repo.changelog.rev(node), short(node))
873 return b'%d:%s' % (repo.changelog.rev(node), short(node))
874
874
875 ui.status(
875 ui.status(
876 _(b'changeset %s backs out changeset %s\n')
876 _(b'changeset %s backs out changeset %s\n')
877 % (nice(newnode), nice(node))
877 % (nice(newnode), nice(node))
878 )
878 )
879 if opts.get('merge') and op1 != node:
879 if opts.get('merge') and op1 != node:
880 hg.clean(repo, op1, show_stats=False)
880 hg.clean(repo, op1, show_stats=False)
881 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
881 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
882 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
882 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
883 with ui.configoverride(overrides, b'backout'):
883 with ui.configoverride(overrides, b'backout'):
884 return hg.merge(repo[b'tip'])
884 return hg.merge(repo[b'tip'])
885 return 0
885 return 0
886
886
887
887
888 @command(
888 @command(
889 b'bisect',
889 b'bisect',
890 [
890 [
891 (b'r', b'reset', False, _(b'reset bisect state')),
891 (b'r', b'reset', False, _(b'reset bisect state')),
892 (b'g', b'good', False, _(b'mark changeset good')),
892 (b'g', b'good', False, _(b'mark changeset good')),
893 (b'b', b'bad', False, _(b'mark changeset bad')),
893 (b'b', b'bad', False, _(b'mark changeset bad')),
894 (b's', b'skip', False, _(b'skip testing changeset')),
894 (b's', b'skip', False, _(b'skip testing changeset')),
895 (b'e', b'extend', False, _(b'extend the bisect range')),
895 (b'e', b'extend', False, _(b'extend the bisect range')),
896 (
896 (
897 b'c',
897 b'c',
898 b'command',
898 b'command',
899 b'',
899 b'',
900 _(b'use command to check changeset state'),
900 _(b'use command to check changeset state'),
901 _(b'CMD'),
901 _(b'CMD'),
902 ),
902 ),
903 (b'U', b'noupdate', False, _(b'do not update to target')),
903 (b'U', b'noupdate', False, _(b'do not update to target')),
904 ],
904 ],
905 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
905 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
906 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
906 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
907 )
907 )
908 def bisect(
908 def bisect(
909 ui,
909 ui,
910 repo,
910 repo,
911 positional_1=None,
911 positional_1=None,
912 positional_2=None,
912 positional_2=None,
913 command=None,
913 command=None,
914 reset=None,
914 reset=None,
915 good=None,
915 good=None,
916 bad=None,
916 bad=None,
917 skip=None,
917 skip=None,
918 extend=None,
918 extend=None,
919 noupdate=None,
919 noupdate=None,
920 ):
920 ):
921 """subdivision search of changesets
921 """subdivision search of changesets
922
922
923 This command helps to find changesets which introduce problems. To
923 This command helps to find changesets which introduce problems. To
924 use, mark the earliest changeset you know exhibits the problem as
924 use, mark the earliest changeset you know exhibits the problem as
925 bad, then mark the latest changeset which is free from the problem
925 bad, then mark the latest changeset which is free from the problem
926 as good. Bisect will update your working directory to a revision
926 as good. Bisect will update your working directory to a revision
927 for testing (unless the -U/--noupdate option is specified). Once
927 for testing (unless the -U/--noupdate option is specified). Once
928 you have performed tests, mark the working directory as good or
928 you have performed tests, mark the working directory as good or
929 bad, and bisect will either update to another candidate changeset
929 bad, and bisect will either update to another candidate changeset
930 or announce that it has found the bad revision.
930 or announce that it has found the bad revision.
931
931
932 As a shortcut, you can also use the revision argument to mark a
932 As a shortcut, you can also use the revision argument to mark a
933 revision as good or bad without checking it out first.
933 revision as good or bad without checking it out first.
934
934
935 If you supply a command, it will be used for automatic bisection.
935 If you supply a command, it will be used for automatic bisection.
936 The environment variable HG_NODE will contain the ID of the
936 The environment variable HG_NODE will contain the ID of the
937 changeset being tested. The exit status of the command will be
937 changeset being tested. The exit status of the command will be
938 used to mark revisions as good or bad: status 0 means good, 125
938 used to mark revisions as good or bad: status 0 means good, 125
939 means to skip the revision, 127 (command not found) will abort the
939 means to skip the revision, 127 (command not found) will abort the
940 bisection, and any other non-zero exit status means the revision
940 bisection, and any other non-zero exit status means the revision
941 is bad.
941 is bad.
942
942
943 .. container:: verbose
943 .. container:: verbose
944
944
945 Some examples:
945 Some examples:
946
946
947 - start a bisection with known bad revision 34, and good revision 12::
947 - start a bisection with known bad revision 34, and good revision 12::
948
948
949 hg bisect --bad 34
949 hg bisect --bad 34
950 hg bisect --good 12
950 hg bisect --good 12
951
951
952 - advance the current bisection by marking current revision as good or
952 - advance the current bisection by marking current revision as good or
953 bad::
953 bad::
954
954
955 hg bisect --good
955 hg bisect --good
956 hg bisect --bad
956 hg bisect --bad
957
957
958 - mark the current revision, or a known revision, to be skipped (e.g. if
958 - mark the current revision, or a known revision, to be skipped (e.g. if
959 that revision is not usable because of another issue)::
959 that revision is not usable because of another issue)::
960
960
961 hg bisect --skip
961 hg bisect --skip
962 hg bisect --skip 23
962 hg bisect --skip 23
963
963
964 - skip all revisions that do not touch directories ``foo`` or ``bar``::
964 - skip all revisions that do not touch directories ``foo`` or ``bar``::
965
965
966 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
966 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
967
967
968 - forget the current bisection::
968 - forget the current bisection::
969
969
970 hg bisect --reset
970 hg bisect --reset
971
971
972 - use 'make && make tests' to automatically find the first broken
972 - use 'make && make tests' to automatically find the first broken
973 revision::
973 revision::
974
974
975 hg bisect --reset
975 hg bisect --reset
976 hg bisect --bad 34
976 hg bisect --bad 34
977 hg bisect --good 12
977 hg bisect --good 12
978 hg bisect --command "make && make tests"
978 hg bisect --command "make && make tests"
979
979
980 - see all changesets whose states are already known in the current
980 - see all changesets whose states are already known in the current
981 bisection::
981 bisection::
982
982
983 hg log -r "bisect(pruned)"
983 hg log -r "bisect(pruned)"
984
984
985 - see the changeset currently being bisected (especially useful
985 - see the changeset currently being bisected (especially useful
986 if running with -U/--noupdate)::
986 if running with -U/--noupdate)::
987
987
988 hg log -r "bisect(current)"
988 hg log -r "bisect(current)"
989
989
990 - see all changesets that took part in the current bisection::
990 - see all changesets that took part in the current bisection::
991
991
992 hg log -r "bisect(range)"
992 hg log -r "bisect(range)"
993
993
994 - you can even get a nice graph::
994 - you can even get a nice graph::
995
995
996 hg log --graph -r "bisect(range)"
996 hg log --graph -r "bisect(range)"
997
997
998 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
998 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
999
999
1000 Returns 0 on success.
1000 Returns 0 on success.
1001 """
1001 """
1002 rev = []
1002 rev = []
1003 # backward compatibility
1003 # backward compatibility
1004 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1004 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1005 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1005 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1006 cmd = positional_1
1006 cmd = positional_1
1007 rev.append(positional_2)
1007 rev.append(positional_2)
1008 if cmd == b"good":
1008 if cmd == b"good":
1009 good = True
1009 good = True
1010 elif cmd == b"bad":
1010 elif cmd == b"bad":
1011 bad = True
1011 bad = True
1012 else:
1012 else:
1013 reset = True
1013 reset = True
1014 elif positional_2:
1014 elif positional_2:
1015 raise error.InputError(_(b'incompatible arguments'))
1015 raise error.InputError(_(b'incompatible arguments'))
1016 elif positional_1 is not None:
1016 elif positional_1 is not None:
1017 rev.append(positional_1)
1017 rev.append(positional_1)
1018
1018
1019 incompatibles = {
1019 incompatibles = {
1020 b'--bad': bad,
1020 b'--bad': bad,
1021 b'--command': bool(command),
1021 b'--command': bool(command),
1022 b'--extend': extend,
1022 b'--extend': extend,
1023 b'--good': good,
1023 b'--good': good,
1024 b'--reset': reset,
1024 b'--reset': reset,
1025 b'--skip': skip,
1025 b'--skip': skip,
1026 }
1026 }
1027
1027
1028 enabled = [x for x in incompatibles if incompatibles[x]]
1028 enabled = [x for x in incompatibles if incompatibles[x]]
1029
1029
1030 if len(enabled) > 1:
1030 if len(enabled) > 1:
1031 raise error.InputError(
1031 raise error.InputError(
1032 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1032 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1033 )
1033 )
1034
1034
1035 if reset:
1035 if reset:
1036 hbisect.resetstate(repo)
1036 hbisect.resetstate(repo)
1037 return
1037 return
1038
1038
1039 state = hbisect.load_state(repo)
1039 state = hbisect.load_state(repo)
1040
1040
1041 if rev:
1041 if rev:
1042 revs = logcmdutil.revrange(repo, rev)
1042 revs = logcmdutil.revrange(repo, rev)
1043 goodnodes = state[b'good']
1043 goodnodes = state[b'good']
1044 badnodes = state[b'bad']
1044 badnodes = state[b'bad']
1045 if goodnodes and badnodes:
1045 if goodnodes and badnodes:
1046 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1046 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1047 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1047 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1048 revs = candidates & revs
1048 revs = candidates & revs
1049 nodes = [repo.changelog.node(i) for i in revs]
1049 nodes = [repo.changelog.node(i) for i in revs]
1050 else:
1050 else:
1051 nodes = [repo.lookup(b'.')]
1051 nodes = [repo.lookup(b'.')]
1052
1052
1053 # update state
1053 # update state
1054 if good or bad or skip:
1054 if good or bad or skip:
1055 if good:
1055 if good:
1056 state[b'good'] += nodes
1056 state[b'good'] += nodes
1057 elif bad:
1057 elif bad:
1058 state[b'bad'] += nodes
1058 state[b'bad'] += nodes
1059 elif skip:
1059 elif skip:
1060 state[b'skip'] += nodes
1060 state[b'skip'] += nodes
1061 hbisect.save_state(repo, state)
1061 hbisect.save_state(repo, state)
1062 if not (state[b'good'] and state[b'bad']):
1062 if not (state[b'good'] and state[b'bad']):
1063 return
1063 return
1064
1064
1065 def mayupdate(repo, node, show_stats=True):
1065 def mayupdate(repo, node, show_stats=True):
1066 """common used update sequence"""
1066 """common used update sequence"""
1067 if noupdate:
1067 if noupdate:
1068 return
1068 return
1069 cmdutil.checkunfinished(repo)
1069 cmdutil.checkunfinished(repo)
1070 cmdutil.bailifchanged(repo)
1070 cmdutil.bailifchanged(repo)
1071 return hg.clean(repo, node, show_stats=show_stats)
1071 return hg.clean(repo, node, show_stats=show_stats)
1072
1072
1073 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1073 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1074
1074
1075 if command:
1075 if command:
1076 changesets = 1
1076 changesets = 1
1077 if noupdate:
1077 if noupdate:
1078 try:
1078 try:
1079 node = state[b'current'][0]
1079 node = state[b'current'][0]
1080 except LookupError:
1080 except LookupError:
1081 raise error.StateError(
1081 raise error.StateError(
1082 _(
1082 _(
1083 b'current bisect revision is unknown - '
1083 b'current bisect revision is unknown - '
1084 b'start a new bisect to fix'
1084 b'start a new bisect to fix'
1085 )
1085 )
1086 )
1086 )
1087 else:
1087 else:
1088 node, p2 = repo.dirstate.parents()
1088 node, p2 = repo.dirstate.parents()
1089 if p2 != repo.nullid:
1089 if p2 != repo.nullid:
1090 raise error.StateError(_(b'current bisect revision is a merge'))
1090 raise error.StateError(_(b'current bisect revision is a merge'))
1091 if rev:
1091 if rev:
1092 if not nodes:
1092 if not nodes:
1093 raise error.InputError(_(b'empty revision set'))
1093 raise error.InputError(_(b'empty revision set'))
1094 node = repo[nodes[-1]].node()
1094 node = repo[nodes[-1]].node()
1095 with hbisect.restore_state(repo, state, node):
1095 with hbisect.restore_state(repo, state, node):
1096 while changesets:
1096 while changesets:
1097 # update state
1097 # update state
1098 state[b'current'] = [node]
1098 state[b'current'] = [node]
1099 hbisect.save_state(repo, state)
1099 hbisect.save_state(repo, state)
1100 status = ui.system(
1100 status = ui.system(
1101 command,
1101 command,
1102 environ={b'HG_NODE': hex(node)},
1102 environ={b'HG_NODE': hex(node)},
1103 blockedtag=b'bisect_check',
1103 blockedtag=b'bisect_check',
1104 )
1104 )
1105 if status == 125:
1105 if status == 125:
1106 transition = b"skip"
1106 transition = b"skip"
1107 elif status == 0:
1107 elif status == 0:
1108 transition = b"good"
1108 transition = b"good"
1109 # status < 0 means process was killed
1109 # status < 0 means process was killed
1110 elif status == 127:
1110 elif status == 127:
1111 raise error.Abort(_(b"failed to execute %s") % command)
1111 raise error.Abort(_(b"failed to execute %s") % command)
1112 elif status < 0:
1112 elif status < 0:
1113 raise error.Abort(_(b"%s killed") % command)
1113 raise error.Abort(_(b"%s killed") % command)
1114 else:
1114 else:
1115 transition = b"bad"
1115 transition = b"bad"
1116 state[transition].append(node)
1116 state[transition].append(node)
1117 ctx = repo[node]
1117 ctx = repo[node]
1118 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1118 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1119 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1119 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1120 hbisect.checkstate(state)
1120 hbisect.checkstate(state)
1121 # bisect
1121 # bisect
1122 nodes, changesets, bgood = hbisect.bisect(repo, state)
1122 nodes, changesets, bgood = hbisect.bisect(repo, state)
1123 # update to next check
1123 # update to next check
1124 node = nodes[0]
1124 node = nodes[0]
1125 mayupdate(repo, node, show_stats=False)
1125 mayupdate(repo, node, show_stats=False)
1126 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1126 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1127 return
1127 return
1128
1128
1129 hbisect.checkstate(state)
1129 hbisect.checkstate(state)
1130
1130
1131 # actually bisect
1131 # actually bisect
1132 nodes, changesets, good = hbisect.bisect(repo, state)
1132 nodes, changesets, good = hbisect.bisect(repo, state)
1133 if extend:
1133 if extend:
1134 if not changesets:
1134 if not changesets:
1135 extendctx = hbisect.extendrange(repo, state, nodes, good)
1135 extendctx = hbisect.extendrange(repo, state, nodes, good)
1136 if extendctx is not None:
1136 if extendctx is not None:
1137 ui.write(
1137 ui.write(
1138 _(b"Extending search to changeset %s\n")
1138 _(b"Extending search to changeset %s\n")
1139 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1139 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1140 )
1140 )
1141 state[b'current'] = [extendctx.node()]
1141 state[b'current'] = [extendctx.node()]
1142 hbisect.save_state(repo, state)
1142 hbisect.save_state(repo, state)
1143 return mayupdate(repo, extendctx.node())
1143 return mayupdate(repo, extendctx.node())
1144 raise error.StateError(_(b"nothing to extend"))
1144 raise error.StateError(_(b"nothing to extend"))
1145
1145
1146 if changesets == 0:
1146 if changesets == 0:
1147 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1147 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1148 else:
1148 else:
1149 assert len(nodes) == 1 # only a single node can be tested next
1149 assert len(nodes) == 1 # only a single node can be tested next
1150 node = nodes[0]
1150 node = nodes[0]
1151 # compute the approximate number of remaining tests
1151 # compute the approximate number of remaining tests
1152 tests, size = 0, 2
1152 tests, size = 0, 2
1153 while size <= changesets:
1153 while size <= changesets:
1154 tests, size = tests + 1, size * 2
1154 tests, size = tests + 1, size * 2
1155 rev = repo.changelog.rev(node)
1155 rev = repo.changelog.rev(node)
1156 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1156 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1157 ui.write(
1157 ui.write(
1158 _(
1158 _(
1159 b"Testing changeset %s "
1159 b"Testing changeset %s "
1160 b"(%d changesets remaining, ~%d tests)\n"
1160 b"(%d changesets remaining, ~%d tests)\n"
1161 )
1161 )
1162 % (summary, changesets, tests)
1162 % (summary, changesets, tests)
1163 )
1163 )
1164 state[b'current'] = [node]
1164 state[b'current'] = [node]
1165 hbisect.save_state(repo, state)
1165 hbisect.save_state(repo, state)
1166 return mayupdate(repo, node)
1166 return mayupdate(repo, node)
1167
1167
1168
1168
1169 @command(
1169 @command(
1170 b'bookmarks|bookmark',
1170 b'bookmarks|bookmark',
1171 [
1171 [
1172 (b'f', b'force', False, _(b'force')),
1172 (b'f', b'force', False, _(b'force')),
1173 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1173 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1174 (b'd', b'delete', False, _(b'delete a given bookmark')),
1174 (b'd', b'delete', False, _(b'delete a given bookmark')),
1175 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1175 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1176 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1176 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1177 (b'l', b'list', False, _(b'list existing bookmarks')),
1177 (b'l', b'list', False, _(b'list existing bookmarks')),
1178 ]
1178 ]
1179 + formatteropts,
1179 + formatteropts,
1180 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1180 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1181 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1181 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1182 )
1182 )
1183 def bookmark(ui, repo, *names, **opts):
1183 def bookmark(ui, repo, *names, **opts):
1184 """create a new bookmark or list existing bookmarks
1184 """create a new bookmark or list existing bookmarks
1185
1185
1186 Bookmarks are labels on changesets to help track lines of development.
1186 Bookmarks are labels on changesets to help track lines of development.
1187 Bookmarks are unversioned and can be moved, renamed and deleted.
1187 Bookmarks are unversioned and can be moved, renamed and deleted.
1188 Deleting or moving a bookmark has no effect on the associated changesets.
1188 Deleting or moving a bookmark has no effect on the associated changesets.
1189
1189
1190 Creating or updating to a bookmark causes it to be marked as 'active'.
1190 Creating or updating to a bookmark causes it to be marked as 'active'.
1191 The active bookmark is indicated with a '*'.
1191 The active bookmark is indicated with a '*'.
1192 When a commit is made, the active bookmark will advance to the new commit.
1192 When a commit is made, the active bookmark will advance to the new commit.
1193 A plain :hg:`update` will also advance an active bookmark, if possible.
1193 A plain :hg:`update` will also advance an active bookmark, if possible.
1194 Updating away from a bookmark will cause it to be deactivated.
1194 Updating away from a bookmark will cause it to be deactivated.
1195
1195
1196 Bookmarks can be pushed and pulled between repositories (see
1196 Bookmarks can be pushed and pulled between repositories (see
1197 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1197 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1198 diverged, a new 'divergent bookmark' of the form 'name@path' will
1198 diverged, a new 'divergent bookmark' of the form 'name@path' will
1199 be created. Using :hg:`merge` will resolve the divergence.
1199 be created. Using :hg:`merge` will resolve the divergence.
1200
1200
1201 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1201 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1202 the active bookmark's name.
1202 the active bookmark's name.
1203
1203
1204 A bookmark named '@' has the special property that :hg:`clone` will
1204 A bookmark named '@' has the special property that :hg:`clone` will
1205 check it out by default if it exists.
1205 check it out by default if it exists.
1206
1206
1207 .. container:: verbose
1207 .. container:: verbose
1208
1208
1209 Template:
1209 Template:
1210
1210
1211 The following keywords are supported in addition to the common template
1211 The following keywords are supported in addition to the common template
1212 keywords and functions such as ``{bookmark}``. See also
1212 keywords and functions such as ``{bookmark}``. See also
1213 :hg:`help templates`.
1213 :hg:`help templates`.
1214
1214
1215 :active: Boolean. True if the bookmark is active.
1215 :active: Boolean. True if the bookmark is active.
1216
1216
1217 Examples:
1217 Examples:
1218
1218
1219 - create an active bookmark for a new line of development::
1219 - create an active bookmark for a new line of development::
1220
1220
1221 hg book new-feature
1221 hg book new-feature
1222
1222
1223 - create an inactive bookmark as a place marker::
1223 - create an inactive bookmark as a place marker::
1224
1224
1225 hg book -i reviewed
1225 hg book -i reviewed
1226
1226
1227 - create an inactive bookmark on another changeset::
1227 - create an inactive bookmark on another changeset::
1228
1228
1229 hg book -r .^ tested
1229 hg book -r .^ tested
1230
1230
1231 - rename bookmark turkey to dinner::
1231 - rename bookmark turkey to dinner::
1232
1232
1233 hg book -m turkey dinner
1233 hg book -m turkey dinner
1234
1234
1235 - move the '@' bookmark from another branch::
1235 - move the '@' bookmark from another branch::
1236
1236
1237 hg book -f @
1237 hg book -f @
1238
1238
1239 - print only the active bookmark name::
1239 - print only the active bookmark name::
1240
1240
1241 hg book -ql .
1241 hg book -ql .
1242 """
1242 """
1243 force = opts.get('force')
1243 force = opts.get('force')
1244 rev = opts.get('rev')
1244 rev = opts.get('rev')
1245 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1245 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1246
1246
1247 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1247 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1248 if action:
1248 if action:
1249 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1249 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1250 elif names or rev:
1250 elif names or rev:
1251 action = 'add'
1251 action = 'add'
1252 elif inactive:
1252 elif inactive:
1253 action = 'inactive' # meaning deactivate
1253 action = 'inactive' # meaning deactivate
1254 else:
1254 else:
1255 action = 'list'
1255 action = 'list'
1256
1256
1257 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1257 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1258 if not names and action in {'add', 'delete'}:
1258 if not names and action in {'add', 'delete'}:
1259 raise error.InputError(_(b"bookmark name required"))
1259 raise error.InputError(_(b"bookmark name required"))
1260
1260
1261 if action in {'add', 'delete', 'rename', 'inactive'}:
1261 if action in {'add', 'delete', 'rename', 'inactive'}:
1262 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1262 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1263 if action == 'delete':
1263 if action == 'delete':
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 bookmarks.delete(repo, tr, names)
1265 bookmarks.delete(repo, tr, names)
1266 elif action == 'rename':
1266 elif action == 'rename':
1267 if not names:
1267 if not names:
1268 raise error.InputError(_(b"new bookmark name required"))
1268 raise error.InputError(_(b"new bookmark name required"))
1269 elif len(names) > 1:
1269 elif len(names) > 1:
1270 raise error.InputError(
1270 raise error.InputError(
1271 _(b"only one new bookmark name allowed")
1271 _(b"only one new bookmark name allowed")
1272 )
1272 )
1273 oldname = repo._bookmarks.expandname(opts['rename'])
1273 oldname = repo._bookmarks.expandname(opts['rename'])
1274 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1274 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1275 elif action == 'add':
1275 elif action == 'add':
1276 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1276 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1277 elif action == 'inactive':
1277 elif action == 'inactive':
1278 if len(repo._bookmarks) == 0:
1278 if len(repo._bookmarks) == 0:
1279 ui.status(_(b"no bookmarks set\n"))
1279 ui.status(_(b"no bookmarks set\n"))
1280 elif not repo._activebookmark:
1280 elif not repo._activebookmark:
1281 ui.status(_(b"no active bookmark\n"))
1281 ui.status(_(b"no active bookmark\n"))
1282 else:
1282 else:
1283 bookmarks.deactivate(repo)
1283 bookmarks.deactivate(repo)
1284 elif action == 'list':
1284 elif action == 'list':
1285 names = pycompat.maplist(repo._bookmarks.expandname, names)
1285 names = pycompat.maplist(repo._bookmarks.expandname, names)
1286 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1286 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1287 bookmarks.printbookmarks(ui, repo, fm, names)
1287 bookmarks.printbookmarks(ui, repo, fm, names)
1288 else:
1288 else:
1289 raise error.ProgrammingError(
1289 raise error.ProgrammingError(
1290 b'invalid action: %s' % pycompat.sysbytes(action)
1290 b'invalid action: %s' % pycompat.sysbytes(action)
1291 )
1291 )
1292
1292
1293
1293
1294 @command(
1294 @command(
1295 b'branch',
1295 b'branch',
1296 [
1296 [
1297 (
1297 (
1298 b'f',
1298 b'f',
1299 b'force',
1299 b'force',
1300 None,
1300 None,
1301 _(b'set branch name even if it shadows an existing branch'),
1301 _(b'set branch name even if it shadows an existing branch'),
1302 ),
1302 ),
1303 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1303 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1304 (
1304 (
1305 b'r',
1305 b'r',
1306 b'rev',
1306 b'rev',
1307 [],
1307 [],
1308 _(b'change branches of the given revs (EXPERIMENTAL)'),
1308 _(b'change branches of the given revs (EXPERIMENTAL)'),
1309 ),
1309 ),
1310 ],
1310 ],
1311 _(b'[-fC] [NAME]'),
1311 _(b'[-fC] [NAME]'),
1312 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1312 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1313 )
1313 )
1314 def branch(ui, repo, label=None, **opts):
1314 def branch(ui, repo, label=None, **opts):
1315 """set or show the current branch name
1315 """set or show the current branch name
1316
1316
1317 .. note::
1317 .. note::
1318
1318
1319 Branch names are permanent and global. Use :hg:`bookmark` to create a
1319 Branch names are permanent and global. Use :hg:`bookmark` to create a
1320 light-weight bookmark instead. See :hg:`help glossary` for more
1320 light-weight bookmark instead. See :hg:`help glossary` for more
1321 information about named branches and bookmarks.
1321 information about named branches and bookmarks.
1322
1322
1323 With no argument, show the current branch name. With one argument,
1323 With no argument, show the current branch name. With one argument,
1324 set the working directory branch name (the branch will not exist
1324 set the working directory branch name (the branch will not exist
1325 in the repository until the next commit). Standard practice
1325 in the repository until the next commit). Standard practice
1326 recommends that primary development take place on the 'default'
1326 recommends that primary development take place on the 'default'
1327 branch.
1327 branch.
1328
1328
1329 Unless -f/--force is specified, branch will not let you set a
1329 Unless -f/--force is specified, branch will not let you set a
1330 branch name that already exists.
1330 branch name that already exists.
1331
1331
1332 Use -C/--clean to reset the working directory branch to that of
1332 Use -C/--clean to reset the working directory branch to that of
1333 the parent of the working directory, negating a previous branch
1333 the parent of the working directory, negating a previous branch
1334 change.
1334 change.
1335
1335
1336 Use the command :hg:`update` to switch to an existing branch. Use
1336 Use the command :hg:`update` to switch to an existing branch. Use
1337 :hg:`commit --close-branch` to mark this branch head as closed.
1337 :hg:`commit --close-branch` to mark this branch head as closed.
1338 When all heads of a branch are closed, the branch will be
1338 When all heads of a branch are closed, the branch will be
1339 considered closed.
1339 considered closed.
1340
1340
1341 Returns 0 on success.
1341 Returns 0 on success.
1342 """
1342 """
1343 revs = opts.get('rev')
1343 revs = opts.get('rev')
1344 if label:
1344 if label:
1345 label = label.strip()
1345 label = label.strip()
1346
1346
1347 if not opts.get('clean') and not label:
1347 if not opts.get('clean') and not label:
1348 if revs:
1348 if revs:
1349 raise error.InputError(
1349 raise error.InputError(
1350 _(b"no branch name specified for the revisions")
1350 _(b"no branch name specified for the revisions")
1351 )
1351 )
1352 ui.write(b"%s\n" % repo.dirstate.branch())
1352 ui.write(b"%s\n" % repo.dirstate.branch())
1353 return
1353 return
1354
1354
1355 with repo.wlock():
1355 with repo.wlock():
1356 if opts.get('clean'):
1356 if opts.get('clean'):
1357 label = repo[b'.'].branch()
1357 label = repo[b'.'].branch()
1358 repo.dirstate.setbranch(label, repo.currenttransaction())
1358 repo.dirstate.setbranch(label, repo.currenttransaction())
1359 ui.status(_(b'reset working directory to branch %s\n') % label)
1359 ui.status(_(b'reset working directory to branch %s\n') % label)
1360 elif label:
1360 elif label:
1361
1361
1362 scmutil.checknewlabel(repo, label, b'branch')
1362 scmutil.checknewlabel(repo, label, b'branch')
1363 if revs:
1363 if revs:
1364 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1364 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1365
1365
1366 if not opts.get('force') and label in repo.branchmap():
1366 if not opts.get('force') and label in repo.branchmap():
1367 if label not in [p.branch() for p in repo[None].parents()]:
1367 if label not in [p.branch() for p in repo[None].parents()]:
1368 raise error.InputError(
1368 raise error.InputError(
1369 _(b'a branch of the same name already exists'),
1369 _(b'a branch of the same name already exists'),
1370 # i18n: "it" refers to an existing branch
1370 # i18n: "it" refers to an existing branch
1371 hint=_(b"use 'hg update' to switch to it"),
1371 hint=_(b"use 'hg update' to switch to it"),
1372 )
1372 )
1373
1373
1374 repo.dirstate.setbranch(label, repo.currenttransaction())
1374 repo.dirstate.setbranch(label, repo.currenttransaction())
1375 ui.status(_(b'marked working directory as branch %s\n') % label)
1375 ui.status(_(b'marked working directory as branch %s\n') % label)
1376
1376
1377 # find any open named branches aside from default
1377 # find any open named branches aside from default
1378 for n, h, t, c in repo.branchmap().iterbranches():
1378 for n, h, t, c in repo.branchmap().iterbranches():
1379 if n != b"default" and not c:
1379 if n != b"default" and not c:
1380 return 0
1380 return 0
1381 ui.status(
1381 ui.status(
1382 _(
1382 _(
1383 b'(branches are permanent and global, '
1383 b'(branches are permanent and global, '
1384 b'did you want a bookmark?)\n'
1384 b'did you want a bookmark?)\n'
1385 )
1385 )
1386 )
1386 )
1387
1387
1388
1388
1389 @command(
1389 @command(
1390 b'branches',
1390 b'branches',
1391 [
1391 [
1392 (
1392 (
1393 b'a',
1393 b'a',
1394 b'active',
1394 b'active',
1395 False,
1395 False,
1396 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1396 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1397 ),
1397 ),
1398 (b'c', b'closed', False, _(b'show normal and closed branches')),
1398 (b'c', b'closed', False, _(b'show normal and closed branches')),
1399 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1399 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1400 ]
1400 ]
1401 + formatteropts,
1401 + formatteropts,
1402 _(b'[-c]'),
1402 _(b'[-c]'),
1403 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1403 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1404 intents={INTENT_READONLY},
1404 intents={INTENT_READONLY},
1405 )
1405 )
1406 def branches(ui, repo, active=False, closed=False, **opts):
1406 def branches(ui, repo, active=False, closed=False, **opts):
1407 """list repository named branches
1407 """list repository named branches
1408
1408
1409 List the repository's named branches, indicating which ones are
1409 List the repository's named branches, indicating which ones are
1410 inactive. If -c/--closed is specified, also list branches which have
1410 inactive. If -c/--closed is specified, also list branches which have
1411 been marked closed (see :hg:`commit --close-branch`).
1411 been marked closed (see :hg:`commit --close-branch`).
1412
1412
1413 Use the command :hg:`update` to switch to an existing branch.
1413 Use the command :hg:`update` to switch to an existing branch.
1414
1414
1415 .. container:: verbose
1415 .. container:: verbose
1416
1416
1417 Template:
1417 Template:
1418
1418
1419 The following keywords are supported in addition to the common template
1419 The following keywords are supported in addition to the common template
1420 keywords and functions such as ``{branch}``. See also
1420 keywords and functions such as ``{branch}``. See also
1421 :hg:`help templates`.
1421 :hg:`help templates`.
1422
1422
1423 :active: Boolean. True if the branch is active.
1423 :active: Boolean. True if the branch is active.
1424 :closed: Boolean. True if the branch is closed.
1424 :closed: Boolean. True if the branch is closed.
1425 :current: Boolean. True if it is the current branch.
1425 :current: Boolean. True if it is the current branch.
1426
1426
1427 Returns 0.
1427 Returns 0.
1428 """
1428 """
1429
1429
1430 revs = opts.get('rev')
1430 revs = opts.get('rev')
1431 selectedbranches = None
1431 selectedbranches = None
1432 if revs:
1432 if revs:
1433 revs = logcmdutil.revrange(repo, revs)
1433 revs = logcmdutil.revrange(repo, revs)
1434 getbi = repo.revbranchcache().branchinfo
1434 getbi = repo.revbranchcache().branchinfo
1435 selectedbranches = {getbi(r)[0] for r in revs}
1435 selectedbranches = {getbi(r)[0] for r in revs}
1436
1436
1437 ui.pager(b'branches')
1437 ui.pager(b'branches')
1438 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1438 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1439 hexfunc = fm.hexfunc
1439 hexfunc = fm.hexfunc
1440
1440
1441 allheads = set(repo.heads())
1441 allheads = set(repo.heads())
1442 branches = []
1442 branches = []
1443 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1443 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1444 if selectedbranches is not None and tag not in selectedbranches:
1444 if selectedbranches is not None and tag not in selectedbranches:
1445 continue
1445 continue
1446 isactive = False
1446 isactive = False
1447 if not isclosed:
1447 if not isclosed:
1448 openheads = set(repo.branchmap().iteropen(heads))
1448 openheads = set(repo.branchmap().iteropen(heads))
1449 isactive = bool(openheads & allheads)
1449 isactive = bool(openheads & allheads)
1450 branches.append((tag, repo[tip], isactive, not isclosed))
1450 branches.append((tag, repo[tip], isactive, not isclosed))
1451 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1451 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1452
1452
1453 for tag, ctx, isactive, isopen in branches:
1453 for tag, ctx, isactive, isopen in branches:
1454 if active and not isactive:
1454 if active and not isactive:
1455 continue
1455 continue
1456 if isactive:
1456 if isactive:
1457 label = b'branches.active'
1457 label = b'branches.active'
1458 notice = b''
1458 notice = b''
1459 elif not isopen:
1459 elif not isopen:
1460 if not closed:
1460 if not closed:
1461 continue
1461 continue
1462 label = b'branches.closed'
1462 label = b'branches.closed'
1463 notice = _(b' (closed)')
1463 notice = _(b' (closed)')
1464 else:
1464 else:
1465 label = b'branches.inactive'
1465 label = b'branches.inactive'
1466 notice = _(b' (inactive)')
1466 notice = _(b' (inactive)')
1467 current = tag == repo.dirstate.branch()
1467 current = tag == repo.dirstate.branch()
1468 if current:
1468 if current:
1469 label = b'branches.current'
1469 label = b'branches.current'
1470
1470
1471 fm.startitem()
1471 fm.startitem()
1472 fm.write(b'branch', b'%s', tag, label=label)
1472 fm.write(b'branch', b'%s', tag, label=label)
1473 rev = ctx.rev()
1473 rev = ctx.rev()
1474 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1474 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1475 fmt = b' ' * padsize + b' %d:%s'
1475 fmt = b' ' * padsize + b' %d:%s'
1476 fm.condwrite(
1476 fm.condwrite(
1477 not ui.quiet,
1477 not ui.quiet,
1478 b'rev node',
1478 b'rev node',
1479 fmt,
1479 fmt,
1480 rev,
1480 rev,
1481 hexfunc(ctx.node()),
1481 hexfunc(ctx.node()),
1482 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1482 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1483 )
1483 )
1484 fm.context(ctx=ctx)
1484 fm.context(ctx=ctx)
1485 fm.data(active=isactive, closed=not isopen, current=current)
1485 fm.data(active=isactive, closed=not isopen, current=current)
1486 if not ui.quiet:
1486 if not ui.quiet:
1487 fm.plain(notice)
1487 fm.plain(notice)
1488 fm.plain(b'\n')
1488 fm.plain(b'\n')
1489 fm.end()
1489 fm.end()
1490
1490
1491
1491
1492 @command(
1492 @command(
1493 b'bundle',
1493 b'bundle',
1494 [
1494 [
1495 (
1495 (
1496 b'',
1496 b'',
1497 b'exact',
1497 b'exact',
1498 None,
1498 None,
1499 _(b'compute the base from the revision specified'),
1499 _(b'compute the base from the revision specified'),
1500 ),
1500 ),
1501 (
1501 (
1502 b'f',
1502 b'f',
1503 b'force',
1503 b'force',
1504 None,
1504 None,
1505 _(b'run even when the destination is unrelated'),
1505 _(b'run even when the destination is unrelated'),
1506 ),
1506 ),
1507 (
1507 (
1508 b'r',
1508 b'r',
1509 b'rev',
1509 b'rev',
1510 [],
1510 [],
1511 _(b'a changeset intended to be added to the destination'),
1511 _(b'a changeset intended to be added to the destination'),
1512 _(b'REV'),
1512 _(b'REV'),
1513 ),
1513 ),
1514 (
1514 (
1515 b'b',
1515 b'b',
1516 b'branch',
1516 b'branch',
1517 [],
1517 [],
1518 _(b'a specific branch you would like to bundle'),
1518 _(b'a specific branch you would like to bundle'),
1519 _(b'BRANCH'),
1519 _(b'BRANCH'),
1520 ),
1520 ),
1521 (
1521 (
1522 b'',
1522 b'',
1523 b'base',
1523 b'base',
1524 [],
1524 [],
1525 _(b'a base changeset assumed to be available at the destination'),
1525 _(b'a base changeset assumed to be available at the destination'),
1526 _(b'REV'),
1526 _(b'REV'),
1527 ),
1527 ),
1528 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1528 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1529 (
1529 (
1530 b't',
1530 b't',
1531 b'type',
1531 b'type',
1532 b'bzip2',
1532 b'bzip2',
1533 _(b'bundle compression type to use'),
1533 _(b'bundle compression type to use'),
1534 _(b'TYPE'),
1534 _(b'TYPE'),
1535 ),
1535 ),
1536 ]
1536 ]
1537 + remoteopts,
1537 + remoteopts,
1538 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1538 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1539 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1539 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1540 )
1540 )
1541 def bundle(ui, repo, fname, *dests, **opts):
1541 def bundle(ui, repo, fname, *dests, **opts):
1542 """create a bundle file
1542 """create a bundle file
1543
1543
1544 Generate a bundle file containing data to be transferred to another
1544 Generate a bundle file containing data to be transferred to another
1545 repository.
1545 repository.
1546
1546
1547 To create a bundle containing all changesets, use -a/--all
1547 To create a bundle containing all changesets, use -a/--all
1548 (or --base null). Otherwise, hg assumes the destination will have
1548 (or --base null). Otherwise, hg assumes the destination will have
1549 all the nodes you specify with --base parameters. Otherwise, hg
1549 all the nodes you specify with --base parameters. Otherwise, hg
1550 will assume the repository has all the nodes in destination, or
1550 will assume the repository has all the nodes in destination, or
1551 default-push/default if no destination is specified, where destination
1551 default-push/default if no destination is specified, where destination
1552 is the repositories you provide through DEST option.
1552 is the repositories you provide through DEST option.
1553
1553
1554 You can change bundle format with the -t/--type option. See
1554 You can change bundle format with the -t/--type option. See
1555 :hg:`help bundlespec` for documentation on this format. By default,
1555 :hg:`help bundlespec` for documentation on this format. By default,
1556 the most appropriate format is used and compression defaults to
1556 the most appropriate format is used and compression defaults to
1557 bzip2.
1557 bzip2.
1558
1558
1559 The bundle file can then be transferred using conventional means
1559 The bundle file can then be transferred using conventional means
1560 and applied to another repository with the unbundle or pull
1560 and applied to another repository with the unbundle or pull
1561 command. This is useful when direct push and pull are not
1561 command. This is useful when direct push and pull are not
1562 available or when exporting an entire repository is undesirable.
1562 available or when exporting an entire repository is undesirable.
1563
1563
1564 Applying bundles preserves all changeset contents including
1564 Applying bundles preserves all changeset contents including
1565 permissions, copy/rename information, and revision history.
1565 permissions, copy/rename information, and revision history.
1566
1566
1567 Returns 0 on success, 1 if no changes found.
1567 Returns 0 on success, 1 if no changes found.
1568 """
1568 """
1569
1569
1570 revs = None
1570 revs = None
1571 if 'rev' in opts:
1571 if 'rev' in opts:
1572 revstrings = opts['rev']
1572 revstrings = opts['rev']
1573 revs = logcmdutil.revrange(repo, revstrings)
1573 revs = logcmdutil.revrange(repo, revstrings)
1574 if revstrings and not revs:
1574 if revstrings and not revs:
1575 raise error.InputError(_(b'no commits to bundle'))
1575 raise error.InputError(_(b'no commits to bundle'))
1576
1576
1577 bundletype = opts.get('type', b'bzip2').lower()
1577 bundletype = opts.get('type', b'bzip2').lower()
1578 try:
1578 try:
1579 bundlespec = bundlecaches.parsebundlespec(
1579 bundlespec = bundlecaches.parsebundlespec(
1580 repo, bundletype, strict=False
1580 repo, bundletype, strict=False
1581 )
1581 )
1582 except error.UnsupportedBundleSpecification as e:
1582 except error.UnsupportedBundleSpecification as e:
1583 raise error.InputError(
1583 raise error.InputError(
1584 pycompat.bytestr(e),
1584 pycompat.bytestr(e),
1585 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1585 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1586 )
1586 )
1587 cgversion = bundlespec.params[b"cg.version"]
1587 cgversion = bundlespec.params[b"cg.version"]
1588
1588
1589 # Packed bundles are a pseudo bundle format for now.
1589 # Packed bundles are a pseudo bundle format for now.
1590 if cgversion == b's1':
1590 if cgversion == b's1':
1591 raise error.InputError(
1591 raise error.InputError(
1592 _(b'packed bundles cannot be produced by "hg bundle"'),
1592 _(b'packed bundles cannot be produced by "hg bundle"'),
1593 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1593 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1594 )
1594 )
1595 base_opt = opts.get('base')
1595 base_opt = opts.get('base')
1596 if opts.get('all'):
1596 if opts.get('all'):
1597 if dests:
1597 if dests:
1598 raise error.InputError(
1598 raise error.InputError(
1599 _(b"--all is incompatible with specifying destinations")
1599 _(b"--all is incompatible with specifying destinations")
1600 )
1600 )
1601 if base_opt:
1601 if base_opt:
1602 ui.warn(_(b"ignoring --base because --all was specified\n"))
1602 ui.warn(_(b"ignoring --base because --all was specified\n"))
1603 if opts.get('exact'):
1603 if opts.get('exact'):
1604 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1604 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1605 base = [nullrev]
1605 base = [nullrev]
1606 elif opts.get('exact'):
1606 elif opts.get('exact'):
1607 if dests:
1607 if dests:
1608 raise error.InputError(
1608 raise error.InputError(
1609 _(b"--exact is incompatible with specifying destinations")
1609 _(b"--exact is incompatible with specifying destinations")
1610 )
1610 )
1611 if base_opt:
1611 if base_opt:
1612 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1612 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1613 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1613 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1614 if not base:
1614 if not base:
1615 base = [nullrev]
1615 base = [nullrev]
1616 elif base_opt:
1616 elif base_opt:
1617 base = logcmdutil.revrange(repo, base_opt)
1617 base = logcmdutil.revrange(repo, base_opt)
1618 if not base:
1618 if not base:
1619 # base specified, but nothing was selected
1619 # base specified, but nothing was selected
1620 base = [nullrev]
1620 base = [nullrev]
1621 else:
1621 else:
1622 base = None
1622 base = None
1623 if cgversion not in changegroup.supportedoutgoingversions(repo):
1623 if cgversion not in changegroup.supportedoutgoingversions(repo):
1624 raise error.Abort(
1624 raise error.Abort(
1625 _(b"repository does not support bundle version %s") % cgversion
1625 _(b"repository does not support bundle version %s") % cgversion
1626 )
1626 )
1627
1627
1628 if base is not None:
1628 if base is not None:
1629 if dests:
1629 if dests:
1630 raise error.InputError(
1630 raise error.InputError(
1631 _(b"--base is incompatible with specifying destinations")
1631 _(b"--base is incompatible with specifying destinations")
1632 )
1632 )
1633 cl = repo.changelog
1633 cl = repo.changelog
1634 common = [cl.node(rev) for rev in base]
1634 common = [cl.node(rev) for rev in base]
1635 heads = [cl.node(r) for r in revs] if revs else None
1635 heads = [cl.node(r) for r in revs] if revs else None
1636 outgoing = discovery.outgoing(repo, common, heads)
1636 outgoing = discovery.outgoing(repo, common, heads)
1637 missing = outgoing.missing
1637 missing = outgoing.missing
1638 excluded = outgoing.excluded
1638 excluded = outgoing.excluded
1639 else:
1639 else:
1640 missing = set()
1640 missing = set()
1641 excluded = set()
1641 excluded = set()
1642 for path in urlutil.get_push_paths(repo, ui, dests):
1642 for path in urlutil.get_push_paths(repo, ui, dests):
1643 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1643 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1644 if revs is not None:
1644 if revs is not None:
1645 hex_revs = [repo[r].hex() for r in revs]
1645 hex_revs = [repo[r].hex() for r in revs]
1646 else:
1646 else:
1647 hex_revs = None
1647 hex_revs = None
1648 branches = (path.branch, [])
1648 branches = (path.branch, [])
1649 head_revs, checkout = hg.addbranchrevs(
1649 head_revs, checkout = hg.addbranchrevs(
1650 repo, repo, branches, hex_revs
1650 repo, repo, branches, hex_revs
1651 )
1651 )
1652 heads = (
1652 heads = (
1653 head_revs
1653 head_revs
1654 and pycompat.maplist(repo.lookup, head_revs)
1654 and pycompat.maplist(repo.lookup, head_revs)
1655 or head_revs
1655 or head_revs
1656 )
1656 )
1657 outgoing = discovery.findcommonoutgoing(
1657 outgoing = discovery.findcommonoutgoing(
1658 repo,
1658 repo,
1659 other,
1659 other,
1660 onlyheads=heads,
1660 onlyheads=heads,
1661 force=opts.get('force'),
1661 force=opts.get('force'),
1662 portable=True,
1662 portable=True,
1663 )
1663 )
1664 missing.update(outgoing.missing)
1664 missing.update(outgoing.missing)
1665 excluded.update(outgoing.excluded)
1665 excluded.update(outgoing.excluded)
1666
1666
1667 if not missing:
1667 if not missing:
1668 scmutil.nochangesfound(ui, repo, not base and excluded)
1668 scmutil.nochangesfound(ui, repo, not base and excluded)
1669 return 1
1669 return 1
1670
1670
1671 # internal changeset are internal implementation details that should not
1671 # internal changeset are internal implementation details that should not
1672 # leave the repository. Bundling with `hg bundle` create such risk.
1672 # leave the repository. Bundling with `hg bundle` create such risk.
1673 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1673 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1674 if bundled_internal:
1674 if bundled_internal:
1675 msg = _(b"cannot bundle internal changesets")
1675 msg = _(b"cannot bundle internal changesets")
1676 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1676 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1677 raise error.Abort(msg, hint=hint)
1677 raise error.Abort(msg, hint=hint)
1678
1678
1679 if heads:
1679 if heads:
1680 outgoing = discovery.outgoing(
1680 outgoing = discovery.outgoing(
1681 repo, missingroots=missing, ancestorsof=heads
1681 repo, missingroots=missing, ancestorsof=heads
1682 )
1682 )
1683 else:
1683 else:
1684 outgoing = discovery.outgoing(repo, missingroots=missing)
1684 outgoing = discovery.outgoing(repo, missingroots=missing)
1685 outgoing.excluded = sorted(excluded)
1685 outgoing.excluded = sorted(excluded)
1686
1686
1687 if cgversion == b'01': # bundle1
1687 if cgversion == b'01': # bundle1
1688 bversion = b'HG10' + bundlespec.wirecompression
1688 bversion = b'HG10' + bundlespec.wirecompression
1689 bcompression = None
1689 bcompression = None
1690 elif cgversion in (b'02', b'03'):
1690 elif cgversion in (b'02', b'03'):
1691 bversion = b'HG20'
1691 bversion = b'HG20'
1692 bcompression = bundlespec.wirecompression
1692 bcompression = bundlespec.wirecompression
1693 else:
1693 else:
1694 raise error.ProgrammingError(
1694 raise error.ProgrammingError(
1695 b'bundle: unexpected changegroup version %s' % cgversion
1695 b'bundle: unexpected changegroup version %s' % cgversion
1696 )
1696 )
1697
1697
1698 # TODO compression options should be derived from bundlespec parsing.
1698 # TODO compression options should be derived from bundlespec parsing.
1699 # This is a temporary hack to allow adjusting bundle compression
1699 # This is a temporary hack to allow adjusting bundle compression
1700 # level without a) formalizing the bundlespec changes to declare it
1700 # level without a) formalizing the bundlespec changes to declare it
1701 # b) introducing a command flag.
1701 # b) introducing a command flag.
1702 compopts = {}
1702 compopts = {}
1703 complevel = ui.configint(
1703 complevel = ui.configint(
1704 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1704 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1705 )
1705 )
1706 if complevel is None:
1706 if complevel is None:
1707 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1707 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1708 if complevel is not None:
1708 if complevel is not None:
1709 compopts[b'level'] = complevel
1709 compopts[b'level'] = complevel
1710
1710
1711 compthreads = ui.configint(
1711 compthreads = ui.configint(
1712 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1712 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1713 )
1713 )
1714 if compthreads is None:
1714 if compthreads is None:
1715 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1715 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1716 if compthreads is not None:
1716 if compthreads is not None:
1717 compopts[b'threads'] = compthreads
1717 compopts[b'threads'] = compthreads
1718
1718
1719 # Bundling of obsmarker and phases is optional as not all clients
1719 # Bundling of obsmarker and phases is optional as not all clients
1720 # support the necessary features.
1720 # support the necessary features.
1721 cfg = ui.configbool
1721 cfg = ui.configbool
1722 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1722 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1723 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1723 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1724 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1724 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1725 bundlespec.set_param(
1725 bundlespec.set_param(
1726 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1726 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1727 )
1727 )
1728 if not bundlespec.params.get(b'phases', False):
1728 if not bundlespec.params.get(b'phases', False):
1729 phases_cfg = cfg(b'experimental', b'bundle-phases')
1729 phases_cfg = cfg(b'experimental', b'bundle-phases')
1730 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1730 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1731
1731
1732 bundle2.writenewbundle(
1732 bundle2.writenewbundle(
1733 ui,
1733 ui,
1734 repo,
1734 repo,
1735 b'bundle',
1735 b'bundle',
1736 fname,
1736 fname,
1737 bversion,
1737 bversion,
1738 outgoing,
1738 outgoing,
1739 bundlespec.params,
1739 bundlespec.params,
1740 compression=bcompression,
1740 compression=bcompression,
1741 compopts=compopts,
1741 compopts=compopts,
1742 )
1742 )
1743
1743
1744
1744
1745 @command(
1745 @command(
1746 b'cat',
1746 b'cat',
1747 [
1747 [
1748 (
1748 (
1749 b'o',
1749 b'o',
1750 b'output',
1750 b'output',
1751 b'',
1751 b'',
1752 _(b'print output to file with formatted name'),
1752 _(b'print output to file with formatted name'),
1753 _(b'FORMAT'),
1753 _(b'FORMAT'),
1754 ),
1754 ),
1755 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1755 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1756 (b'', b'decode', None, _(b'apply any matching decode filter')),
1756 (b'', b'decode', None, _(b'apply any matching decode filter')),
1757 ]
1757 ]
1758 + walkopts
1758 + walkopts
1759 + formatteropts,
1759 + formatteropts,
1760 _(b'[OPTION]... FILE...'),
1760 _(b'[OPTION]... FILE...'),
1761 helpcategory=command.CATEGORY_FILE_CONTENTS,
1761 helpcategory=command.CATEGORY_FILE_CONTENTS,
1762 inferrepo=True,
1762 inferrepo=True,
1763 intents={INTENT_READONLY},
1763 intents={INTENT_READONLY},
1764 )
1764 )
1765 def cat(ui, repo, file1, *pats, **opts):
1765 def cat(ui, repo, file1, *pats, **opts):
1766 """output the current or given revision of files
1766 """output the current or given revision of files
1767
1767
1768 Print the specified files as they were at the given revision. If
1768 Print the specified files as they were at the given revision. If
1769 no revision is given, the parent of the working directory is used.
1769 no revision is given, the parent of the working directory is used.
1770
1770
1771 Output may be to a file, in which case the name of the file is
1771 Output may be to a file, in which case the name of the file is
1772 given using a template string. See :hg:`help templates`. In addition
1772 given using a template string. See :hg:`help templates`. In addition
1773 to the common template keywords, the following formatting rules are
1773 to the common template keywords, the following formatting rules are
1774 supported:
1774 supported:
1775
1775
1776 :``%%``: literal "%" character
1776 :``%%``: literal "%" character
1777 :``%s``: basename of file being printed
1777 :``%s``: basename of file being printed
1778 :``%d``: dirname of file being printed, or '.' if in repository root
1778 :``%d``: dirname of file being printed, or '.' if in repository root
1779 :``%p``: root-relative path name of file being printed
1779 :``%p``: root-relative path name of file being printed
1780 :``%H``: changeset hash (40 hexadecimal digits)
1780 :``%H``: changeset hash (40 hexadecimal digits)
1781 :``%R``: changeset revision number
1781 :``%R``: changeset revision number
1782 :``%h``: short-form changeset hash (12 hexadecimal digits)
1782 :``%h``: short-form changeset hash (12 hexadecimal digits)
1783 :``%r``: zero-padded changeset revision number
1783 :``%r``: zero-padded changeset revision number
1784 :``%b``: basename of the exporting repository
1784 :``%b``: basename of the exporting repository
1785 :``\\``: literal "\\" character
1785 :``\\``: literal "\\" character
1786
1786
1787 .. container:: verbose
1787 .. container:: verbose
1788
1788
1789 Template:
1789 Template:
1790
1790
1791 The following keywords are supported in addition to the common template
1791 The following keywords are supported in addition to the common template
1792 keywords and functions. See also :hg:`help templates`.
1792 keywords and functions. See also :hg:`help templates`.
1793
1793
1794 :data: String. File content.
1794 :data: String. File content.
1795 :path: String. Repository-absolute path of the file.
1795 :path: String. Repository-absolute path of the file.
1796
1796
1797 Returns 0 on success.
1797 Returns 0 on success.
1798 """
1798 """
1799 rev = opts.get('rev')
1799 rev = opts.get('rev')
1800 if rev:
1800 if rev:
1801 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1801 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1802 ctx = logcmdutil.revsingle(repo, rev)
1802 ctx = logcmdutil.revsingle(repo, rev)
1803 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1803 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1804 fntemplate = opts.pop('output', b'')
1804 fntemplate = opts.pop('output', b'')
1805 if cmdutil.isstdiofilename(fntemplate):
1805 if cmdutil.isstdiofilename(fntemplate):
1806 fntemplate = b''
1806 fntemplate = b''
1807
1807
1808 if fntemplate:
1808 if fntemplate:
1809 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1809 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1810 else:
1810 else:
1811 ui.pager(b'cat')
1811 ui.pager(b'cat')
1812 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1812 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1813 with fm:
1813 with fm:
1814 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1814 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1815
1815
1816
1816
1817 @command(
1817 @command(
1818 b'clone',
1818 b'clone',
1819 [
1819 [
1820 (
1820 (
1821 b'U',
1821 b'U',
1822 b'noupdate',
1822 b'noupdate',
1823 None,
1823 None,
1824 _(
1824 _(
1825 b'the clone will include an empty working '
1825 b'the clone will include an empty working '
1826 b'directory (only a repository)'
1826 b'directory (only a repository)'
1827 ),
1827 ),
1828 ),
1828 ),
1829 (
1829 (
1830 b'u',
1830 b'u',
1831 b'updaterev',
1831 b'updaterev',
1832 b'',
1832 b'',
1833 _(b'revision, tag, or branch to check out'),
1833 _(b'revision, tag, or branch to check out'),
1834 _(b'REV'),
1834 _(b'REV'),
1835 ),
1835 ),
1836 (
1836 (
1837 b'r',
1837 b'r',
1838 b'rev',
1838 b'rev',
1839 [],
1839 [],
1840 _(
1840 _(
1841 b'do not clone everything, but include this changeset'
1841 b'do not clone everything, but include this changeset'
1842 b' and its ancestors'
1842 b' and its ancestors'
1843 ),
1843 ),
1844 _(b'REV'),
1844 _(b'REV'),
1845 ),
1845 ),
1846 (
1846 (
1847 b'b',
1847 b'b',
1848 b'branch',
1848 b'branch',
1849 [],
1849 [],
1850 _(
1850 _(
1851 b'do not clone everything, but include this branch\'s'
1851 b'do not clone everything, but include this branch\'s'
1852 b' changesets and their ancestors'
1852 b' changesets and their ancestors'
1853 ),
1853 ),
1854 _(b'BRANCH'),
1854 _(b'BRANCH'),
1855 ),
1855 ),
1856 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1856 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1857 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1857 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1858 (b'', b'stream', None, _(b'clone with minimal data processing')),
1858 (b'', b'stream', None, _(b'clone with minimal data processing')),
1859 ]
1859 ]
1860 + remoteopts,
1860 + remoteopts,
1861 _(b'[OPTION]... SOURCE [DEST]'),
1861 _(b'[OPTION]... SOURCE [DEST]'),
1862 helpcategory=command.CATEGORY_REPO_CREATION,
1862 helpcategory=command.CATEGORY_REPO_CREATION,
1863 helpbasic=True,
1863 helpbasic=True,
1864 norepo=True,
1864 norepo=True,
1865 )
1865 )
1866 def clone(ui, source, dest=None, **opts):
1866 def clone(ui, source, dest=None, **opts):
1867 """make a copy of an existing repository
1867 """make a copy of an existing repository
1868
1868
1869 Create a copy of an existing repository in a new directory.
1869 Create a copy of an existing repository in a new directory.
1870
1870
1871 If no destination directory name is specified, it defaults to the
1871 If no destination directory name is specified, it defaults to the
1872 basename of the source.
1872 basename of the source.
1873
1873
1874 The location of the source is added to the new repository's
1874 The location of the source is added to the new repository's
1875 ``.hg/hgrc`` file, as the default to be used for future pulls.
1875 ``.hg/hgrc`` file, as the default to be used for future pulls.
1876
1876
1877 Only local paths and ``ssh://`` URLs are supported as
1877 Only local paths and ``ssh://`` URLs are supported as
1878 destinations. For ``ssh://`` destinations, no working directory or
1878 destinations. For ``ssh://`` destinations, no working directory or
1879 ``.hg/hgrc`` will be created on the remote side.
1879 ``.hg/hgrc`` will be created on the remote side.
1880
1880
1881 If the source repository has a bookmark called '@' set, that
1881 If the source repository has a bookmark called '@' set, that
1882 revision will be checked out in the new repository by default.
1882 revision will be checked out in the new repository by default.
1883
1883
1884 To check out a particular version, use -u/--update, or
1884 To check out a particular version, use -u/--update, or
1885 -U/--noupdate to create a clone with no working directory.
1885 -U/--noupdate to create a clone with no working directory.
1886
1886
1887 To pull only a subset of changesets, specify one or more revisions
1887 To pull only a subset of changesets, specify one or more revisions
1888 identifiers with -r/--rev or branches with -b/--branch. The
1888 identifiers with -r/--rev or branches with -b/--branch. The
1889 resulting clone will contain only the specified changesets and
1889 resulting clone will contain only the specified changesets and
1890 their ancestors. These options (or 'clone src#rev dest') imply
1890 their ancestors. These options (or 'clone src#rev dest') imply
1891 --pull, even for local source repositories.
1891 --pull, even for local source repositories.
1892
1892
1893 In normal clone mode, the remote normalizes repository data into a common
1893 In normal clone mode, the remote normalizes repository data into a common
1894 exchange format and the receiving end translates this data into its local
1894 exchange format and the receiving end translates this data into its local
1895 storage format. --stream activates a different clone mode that essentially
1895 storage format. --stream activates a different clone mode that essentially
1896 copies repository files from the remote with minimal data processing. This
1896 copies repository files from the remote with minimal data processing. This
1897 significantly reduces the CPU cost of a clone both remotely and locally.
1897 significantly reduces the CPU cost of a clone both remotely and locally.
1898 However, it often increases the transferred data size by 30-40%. This can
1898 However, it often increases the transferred data size by 30-40%. This can
1899 result in substantially faster clones where I/O throughput is plentiful,
1899 result in substantially faster clones where I/O throughput is plentiful,
1900 especially for larger repositories. A side-effect of --stream clones is
1900 especially for larger repositories. A side-effect of --stream clones is
1901 that storage settings and requirements on the remote are applied locally:
1901 that storage settings and requirements on the remote are applied locally:
1902 a modern client may inherit legacy or inefficient storage used by the
1902 a modern client may inherit legacy or inefficient storage used by the
1903 remote or a legacy Mercurial client may not be able to clone from a
1903 remote or a legacy Mercurial client may not be able to clone from a
1904 modern Mercurial remote.
1904 modern Mercurial remote.
1905
1905
1906 .. note::
1906 .. note::
1907
1907
1908 Specifying a tag will include the tagged changeset but not the
1908 Specifying a tag will include the tagged changeset but not the
1909 changeset containing the tag.
1909 changeset containing the tag.
1910
1910
1911 .. container:: verbose
1911 .. container:: verbose
1912
1912
1913 For efficiency, hardlinks are used for cloning whenever the
1913 For efficiency, hardlinks are used for cloning whenever the
1914 source and destination are on the same filesystem (note this
1914 source and destination are on the same filesystem (note this
1915 applies only to the repository data, not to the working
1915 applies only to the repository data, not to the working
1916 directory). Some filesystems, such as AFS, implement hardlinking
1916 directory). Some filesystems, such as AFS, implement hardlinking
1917 incorrectly, but do not report errors. In these cases, use the
1917 incorrectly, but do not report errors. In these cases, use the
1918 --pull option to avoid hardlinking.
1918 --pull option to avoid hardlinking.
1919
1919
1920 Mercurial will update the working directory to the first applicable
1920 Mercurial will update the working directory to the first applicable
1921 revision from this list:
1921 revision from this list:
1922
1922
1923 a) null if -U or the source repository has no changesets
1923 a) null if -U or the source repository has no changesets
1924 b) if -u . and the source repository is local, the first parent of
1924 b) if -u . and the source repository is local, the first parent of
1925 the source repository's working directory
1925 the source repository's working directory
1926 c) the changeset specified with -u (if a branch name, this means the
1926 c) the changeset specified with -u (if a branch name, this means the
1927 latest head of that branch)
1927 latest head of that branch)
1928 d) the changeset specified with -r
1928 d) the changeset specified with -r
1929 e) the tipmost head specified with -b
1929 e) the tipmost head specified with -b
1930 f) the tipmost head specified with the url#branch source syntax
1930 f) the tipmost head specified with the url#branch source syntax
1931 g) the revision marked with the '@' bookmark, if present
1931 g) the revision marked with the '@' bookmark, if present
1932 h) the tipmost head of the default branch
1932 h) the tipmost head of the default branch
1933 i) tip
1933 i) tip
1934
1934
1935 When cloning from servers that support it, Mercurial may fetch
1935 When cloning from servers that support it, Mercurial may fetch
1936 pre-generated data from a server-advertised URL or inline from the
1936 pre-generated data from a server-advertised URL or inline from the
1937 same stream. When this is done, hooks operating on incoming changesets
1937 same stream. When this is done, hooks operating on incoming changesets
1938 and changegroups may fire more than once, once for each pre-generated
1938 and changegroups may fire more than once, once for each pre-generated
1939 bundle and as well as for any additional remaining data. In addition,
1939 bundle and as well as for any additional remaining data. In addition,
1940 if an error occurs, the repository may be rolled back to a partial
1940 if an error occurs, the repository may be rolled back to a partial
1941 clone. This behavior may change in future releases.
1941 clone. This behavior may change in future releases.
1942 See :hg:`help -e clonebundles` for more.
1942 See :hg:`help -e clonebundles` for more.
1943
1943
1944 Examples:
1944 Examples:
1945
1945
1946 - clone a remote repository to a new directory named hg/::
1946 - clone a remote repository to a new directory named hg/::
1947
1947
1948 hg clone https://www.mercurial-scm.org/repo/hg/
1948 hg clone https://www.mercurial-scm.org/repo/hg/
1949
1949
1950 - create a lightweight local clone::
1950 - create a lightweight local clone::
1951
1951
1952 hg clone project/ project-feature/
1952 hg clone project/ project-feature/
1953
1953
1954 - clone from an absolute path on an ssh server (note double-slash)::
1954 - clone from an absolute path on an ssh server (note double-slash)::
1955
1955
1956 hg clone ssh://user@server//home/projects/alpha/
1956 hg clone ssh://user@server//home/projects/alpha/
1957
1957
1958 - do a streaming clone while checking out a specified version::
1958 - do a streaming clone while checking out a specified version::
1959
1959
1960 hg clone --stream http://server/repo -u 1.5
1960 hg clone --stream http://server/repo -u 1.5
1961
1961
1962 - create a repository without changesets after a particular revision::
1962 - create a repository without changesets after a particular revision::
1963
1963
1964 hg clone -r 04e544 experimental/ good/
1964 hg clone -r 04e544 experimental/ good/
1965
1965
1966 - clone (and track) a particular named branch::
1966 - clone (and track) a particular named branch::
1967
1967
1968 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1968 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1969
1969
1970 See :hg:`help urls` for details on specifying URLs.
1970 See :hg:`help urls` for details on specifying URLs.
1971
1971
1972 Returns 0 on success.
1972 Returns 0 on success.
1973 """
1973 """
1974 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
1974 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
1975
1975
1976 # --include/--exclude can come from narrow or sparse.
1976 # --include/--exclude can come from narrow or sparse.
1977 includepats, excludepats = None, None
1977 includepats, excludepats = None, None
1978
1978
1979 # hg.clone() differentiates between None and an empty set. So make sure
1979 # hg.clone() differentiates between None and an empty set. So make sure
1980 # patterns are sets if narrow is requested without patterns.
1980 # patterns are sets if narrow is requested without patterns.
1981 if opts.get('narrow'):
1981 if opts.get('narrow'):
1982 includepats = set()
1982 includepats = set()
1983 excludepats = set()
1983 excludepats = set()
1984
1984
1985 if opts.get('include'):
1985 if opts.get('include'):
1986 includepats = narrowspec.parsepatterns(opts.get('include'))
1986 includepats = narrowspec.parsepatterns(opts.get('include'))
1987 if opts.get('exclude'):
1987 if opts.get('exclude'):
1988 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1988 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1989
1989
1990 r = hg.clone(
1990 r = hg.clone(
1991 ui,
1991 ui,
1992 pycompat.byteskwargs(opts),
1992 pycompat.byteskwargs(opts),
1993 source,
1993 source,
1994 dest,
1994 dest,
1995 pull=opts.get('pull'),
1995 pull=opts.get('pull'),
1996 stream=opts.get('stream') or opts.get('uncompressed'),
1996 stream=opts.get('stream') or opts.get('uncompressed'),
1997 revs=opts.get('rev'),
1997 revs=opts.get('rev'),
1998 update=opts.get('updaterev') or not opts.get('noupdate'),
1998 update=opts.get('updaterev') or not opts.get('noupdate'),
1999 branch=opts.get('branch'),
1999 branch=opts.get('branch'),
2000 shareopts=opts.get('shareopts'),
2000 shareopts=opts.get('shareopts'),
2001 storeincludepats=includepats,
2001 storeincludepats=includepats,
2002 storeexcludepats=excludepats,
2002 storeexcludepats=excludepats,
2003 depth=opts.get('depth') or None,
2003 depth=opts.get('depth') or None,
2004 )
2004 )
2005
2005
2006 return r is None
2006 return r is None
2007
2007
2008
2008
2009 @command(
2009 @command(
2010 b'commit|ci',
2010 b'commit|ci',
2011 [
2011 [
2012 (
2012 (
2013 b'A',
2013 b'A',
2014 b'addremove',
2014 b'addremove',
2015 None,
2015 None,
2016 _(b'mark new/missing files as added/removed before committing'),
2016 _(b'mark new/missing files as added/removed before committing'),
2017 ),
2017 ),
2018 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2018 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2019 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2019 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2020 (b's', b'secret', None, _(b'use the secret phase for committing')),
2020 (b's', b'secret', None, _(b'use the secret phase for committing')),
2021 (b'', b'draft', None, _(b'use the draft phase for committing')),
2021 (b'', b'draft', None, _(b'use the draft phase for committing')),
2022 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2022 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2023 (
2023 (
2024 b'',
2024 b'',
2025 b'force-close-branch',
2025 b'force-close-branch',
2026 None,
2026 None,
2027 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2027 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2028 ),
2028 ),
2029 (b'i', b'interactive', None, _(b'use interactive mode')),
2029 (b'i', b'interactive', None, _(b'use interactive mode')),
2030 ]
2030 ]
2031 + walkopts
2031 + walkopts
2032 + commitopts
2032 + commitopts
2033 + commitopts2
2033 + commitopts2
2034 + subrepoopts,
2034 + subrepoopts,
2035 _(b'[OPTION]... [FILE]...'),
2035 _(b'[OPTION]... [FILE]...'),
2036 helpcategory=command.CATEGORY_COMMITTING,
2036 helpcategory=command.CATEGORY_COMMITTING,
2037 helpbasic=True,
2037 helpbasic=True,
2038 inferrepo=True,
2038 inferrepo=True,
2039 )
2039 )
2040 def commit(ui, repo, *pats, **opts):
2040 def commit(ui, repo, *pats, **opts):
2041 """commit the specified files or all outstanding changes
2041 """commit the specified files or all outstanding changes
2042
2042
2043 Commit changes to the given files into the repository. Unlike a
2043 Commit changes to the given files into the repository. Unlike a
2044 centralized SCM, this operation is a local operation. See
2044 centralized SCM, this operation is a local operation. See
2045 :hg:`push` for a way to actively distribute your changes.
2045 :hg:`push` for a way to actively distribute your changes.
2046
2046
2047 If a list of files is omitted, all changes reported by :hg:`status`
2047 If a list of files is omitted, all changes reported by :hg:`status`
2048 will be committed.
2048 will be committed.
2049
2049
2050 If you are committing the result of a merge, do not provide any
2050 If you are committing the result of a merge, do not provide any
2051 filenames or -I/-X filters.
2051 filenames or -I/-X filters.
2052
2052
2053 If no commit message is specified, Mercurial starts your
2053 If no commit message is specified, Mercurial starts your
2054 configured editor where you can enter a message. In case your
2054 configured editor where you can enter a message. In case your
2055 commit fails, you will find a backup of your message in
2055 commit fails, you will find a backup of your message in
2056 ``.hg/last-message.txt``.
2056 ``.hg/last-message.txt``.
2057
2057
2058 The --close-branch flag can be used to mark the current branch
2058 The --close-branch flag can be used to mark the current branch
2059 head closed. When all heads of a branch are closed, the branch
2059 head closed. When all heads of a branch are closed, the branch
2060 will be considered closed and no longer listed.
2060 will be considered closed and no longer listed.
2061
2061
2062 The --amend flag can be used to amend the parent of the
2062 The --amend flag can be used to amend the parent of the
2063 working directory with a new commit that contains the changes
2063 working directory with a new commit that contains the changes
2064 in the parent in addition to those currently reported by :hg:`status`,
2064 in the parent in addition to those currently reported by :hg:`status`,
2065 if there are any. The old commit is stored in a backup bundle in
2065 if there are any. The old commit is stored in a backup bundle in
2066 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2066 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2067 on how to restore it).
2067 on how to restore it).
2068
2068
2069 Message, user and date are taken from the amended commit unless
2069 Message, user and date are taken from the amended commit unless
2070 specified. When a message isn't specified on the command line,
2070 specified. When a message isn't specified on the command line,
2071 the editor will open with the message of the amended commit.
2071 the editor will open with the message of the amended commit.
2072
2072
2073 It is not possible to amend public changesets (see :hg:`help phases`)
2073 It is not possible to amend public changesets (see :hg:`help phases`)
2074 or changesets that have children.
2074 or changesets that have children.
2075
2075
2076 See :hg:`help dates` for a list of formats valid for -d/--date.
2076 See :hg:`help dates` for a list of formats valid for -d/--date.
2077
2077
2078 Returns 0 on success, 1 if nothing changed.
2078 Returns 0 on success, 1 if nothing changed.
2079
2079
2080 .. container:: verbose
2080 .. container:: verbose
2081
2081
2082 Examples:
2082 Examples:
2083
2083
2084 - commit all files ending in .py::
2084 - commit all files ending in .py::
2085
2085
2086 hg commit --include "set:**.py"
2086 hg commit --include "set:**.py"
2087
2087
2088 - commit all non-binary files::
2088 - commit all non-binary files::
2089
2089
2090 hg commit --exclude "set:binary()"
2090 hg commit --exclude "set:binary()"
2091
2091
2092 - amend the current commit and set the date to now::
2092 - amend the current commit and set the date to now::
2093
2093
2094 hg commit --amend --date now
2094 hg commit --amend --date now
2095 """
2095 """
2096 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2096 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2097 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2097 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2098 with repo.wlock(), repo.lock():
2098 with repo.wlock(), repo.lock():
2099 return _docommit(ui, repo, *pats, **opts)
2099 return _docommit(ui, repo, *pats, **opts)
2100
2100
2101
2101
2102 def _docommit(ui, repo, *pats, **opts):
2102 def _docommit(ui, repo, *pats, **opts):
2103 if opts.get('interactive'):
2103 if opts.get('interactive'):
2104 opts.pop('interactive')
2104 opts.pop('interactive')
2105 ret = cmdutil.dorecord(
2105 ret = cmdutil.dorecord(
2106 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2106 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2107 )
2107 )
2108 # ret can be 0 (no changes to record) or the value returned by
2108 # ret can be 0 (no changes to record) or the value returned by
2109 # commit(), 1 if nothing changed or None on success.
2109 # commit(), 1 if nothing changed or None on success.
2110 return 1 if ret == 0 else ret
2110 return 1 if ret == 0 else ret
2111
2111
2112 if opts.get('subrepos'):
2112 if opts.get('subrepos'):
2113 # Let --subrepos on the command line override config setting.
2113 # Let --subrepos on the command line override config setting.
2114 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2114 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2115
2115
2116 cmdutil.checkunfinished(repo, commit=True)
2116 cmdutil.checkunfinished(repo, commit=True)
2117
2117
2118 branch = repo[None].branch()
2118 branch = repo[None].branch()
2119 bheads = repo.branchheads(branch)
2119 bheads = repo.branchheads(branch)
2120 tip = repo.changelog.tip()
2120 tip = repo.changelog.tip()
2121
2121
2122 extra = {}
2122 extra = {}
2123 if opts.get('close_branch') or opts.get('force_close_branch'):
2123 if opts.get('close_branch') or opts.get('force_close_branch'):
2124 extra[b'close'] = b'1'
2124 extra[b'close'] = b'1'
2125
2125
2126 if repo[b'.'].closesbranch():
2126 if repo[b'.'].closesbranch():
2127 # Not ideal, but let us do an extra status early to prevent early
2127 # Not ideal, but let us do an extra status early to prevent early
2128 # bail out.
2128 # bail out.
2129 matcher = scmutil.match(
2129 matcher = scmutil.match(
2130 repo[None], pats, pycompat.byteskwargs(opts)
2130 repo[None], pats, pycompat.byteskwargs(opts)
2131 )
2131 )
2132 s = repo.status(match=matcher)
2132 s = repo.status(match=matcher)
2133 if s.modified or s.added or s.removed:
2133 if s.modified or s.added or s.removed:
2134 bheads = repo.branchheads(branch, closed=True)
2134 bheads = repo.branchheads(branch, closed=True)
2135 else:
2135 else:
2136 msg = _(b'current revision is already a branch closing head')
2136 msg = _(b'current revision is already a branch closing head')
2137 raise error.InputError(msg)
2137 raise error.InputError(msg)
2138
2138
2139 if not bheads:
2139 if not bheads:
2140 raise error.InputError(
2140 raise error.InputError(
2141 _(b'branch "%s" has no heads to close') % branch
2141 _(b'branch "%s" has no heads to close') % branch
2142 )
2142 )
2143 elif (
2143 elif (
2144 branch == repo[b'.'].branch()
2144 branch == repo[b'.'].branch()
2145 and repo[b'.'].node() not in bheads
2145 and repo[b'.'].node() not in bheads
2146 and not opts.get('force_close_branch')
2146 and not opts.get('force_close_branch')
2147 ):
2147 ):
2148 hint = _(
2148 hint = _(
2149 b'use --force-close-branch to close branch from a non-head'
2149 b'use --force-close-branch to close branch from a non-head'
2150 b' changeset'
2150 b' changeset'
2151 )
2151 )
2152 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2152 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2153 elif opts.get('amend'):
2153 elif opts.get('amend'):
2154 if (
2154 if (
2155 repo[b'.'].p1().branch() != branch
2155 repo[b'.'].p1().branch() != branch
2156 and repo[b'.'].p2().branch() != branch
2156 and repo[b'.'].p2().branch() != branch
2157 ):
2157 ):
2158 raise error.InputError(_(b'can only close branch heads'))
2158 raise error.InputError(_(b'can only close branch heads'))
2159
2159
2160 if opts.get('amend'):
2160 if opts.get('amend'):
2161 if ui.configbool(b'ui', b'commitsubrepos'):
2161 if ui.configbool(b'ui', b'commitsubrepos'):
2162 raise error.InputError(
2162 raise error.InputError(
2163 _(b'cannot amend with ui.commitsubrepos enabled')
2163 _(b'cannot amend with ui.commitsubrepos enabled')
2164 )
2164 )
2165
2165
2166 old = repo[b'.']
2166 old = repo[b'.']
2167 rewriteutil.precheck(repo, [old.rev()], b'amend')
2167 rewriteutil.precheck(repo, [old.rev()], b'amend')
2168
2168
2169 # Currently histedit gets confused if an amend happens while histedit
2169 # Currently histedit gets confused if an amend happens while histedit
2170 # is in progress. Since we have a checkunfinished command, we are
2170 # is in progress. Since we have a checkunfinished command, we are
2171 # temporarily honoring it.
2171 # temporarily honoring it.
2172 #
2172 #
2173 # Note: eventually this guard will be removed. Please do not expect
2173 # Note: eventually this guard will be removed. Please do not expect
2174 # this behavior to remain.
2174 # this behavior to remain.
2175 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2175 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2176 cmdutil.checkunfinished(repo)
2176 cmdutil.checkunfinished(repo)
2177
2177
2178 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2178 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2179 if node == old.node():
2179 if node == old.node():
2180 ui.status(_(b"nothing changed\n"))
2180 ui.status(_(b"nothing changed\n"))
2181 return 1
2181 return 1
2182 else:
2182 else:
2183
2183
2184 def commitfunc(ui, repo, message, match, opts):
2184 def commitfunc(ui, repo, message, match, opts):
2185 overrides = {}
2185 overrides = {}
2186 if opts.get(b'secret'):
2186 if opts.get(b'secret'):
2187 overrides[(b'phases', b'new-commit')] = b'secret'
2187 overrides[(b'phases', b'new-commit')] = b'secret'
2188 elif opts.get(b'draft'):
2188 elif opts.get(b'draft'):
2189 overrides[(b'phases', b'new-commit')] = b'draft'
2189 overrides[(b'phases', b'new-commit')] = b'draft'
2190
2190
2191 baseui = repo.baseui
2191 baseui = repo.baseui
2192 with baseui.configoverride(overrides, b'commit'):
2192 with baseui.configoverride(overrides, b'commit'):
2193 with ui.configoverride(overrides, b'commit'):
2193 with ui.configoverride(overrides, b'commit'):
2194 editform = cmdutil.mergeeditform(
2194 editform = cmdutil.mergeeditform(
2195 repo[None], b'commit.normal'
2195 repo[None], b'commit.normal'
2196 )
2196 )
2197 editor = cmdutil.getcommiteditor(
2197 editor = cmdutil.getcommiteditor(
2198 editform=editform, **pycompat.strkwargs(opts)
2198 editform=editform, **pycompat.strkwargs(opts)
2199 )
2199 )
2200 return repo.commit(
2200 return repo.commit(
2201 message,
2201 message,
2202 opts.get(b'user'),
2202 opts.get(b'user'),
2203 opts.get(b'date'),
2203 opts.get(b'date'),
2204 match,
2204 match,
2205 editor=editor,
2205 editor=editor,
2206 extra=extra,
2206 extra=extra,
2207 )
2207 )
2208
2208
2209 node = cmdutil.commit(
2209 node = cmdutil.commit(
2210 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2210 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2211 )
2211 )
2212
2212
2213 if not node:
2213 if not node:
2214 stat = cmdutil.postcommitstatus(
2214 stat = cmdutil.postcommitstatus(
2215 repo, pats, pycompat.byteskwargs(opts)
2215 repo, pats, pycompat.byteskwargs(opts)
2216 )
2216 )
2217 if stat.deleted:
2217 if stat.deleted:
2218 ui.status(
2218 ui.status(
2219 _(
2219 _(
2220 b"nothing changed (%d missing files, see "
2220 b"nothing changed (%d missing files, see "
2221 b"'hg status')\n"
2221 b"'hg status')\n"
2222 )
2222 )
2223 % len(stat.deleted)
2223 % len(stat.deleted)
2224 )
2224 )
2225 else:
2225 else:
2226 ui.status(_(b"nothing changed\n"))
2226 ui.status(_(b"nothing changed\n"))
2227 return 1
2227 return 1
2228
2228
2229 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2229 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2230
2230
2231 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2231 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2232 status(
2232 status(
2233 ui,
2233 ui,
2234 repo,
2234 repo,
2235 modified=True,
2235 modified=True,
2236 added=True,
2236 added=True,
2237 removed=True,
2237 removed=True,
2238 deleted=True,
2238 deleted=True,
2239 unknown=True,
2239 unknown=True,
2240 subrepos=opts.get('subrepos'),
2240 subrepos=opts.get('subrepos'),
2241 )
2241 )
2242
2242
2243
2243
2244 @command(
2244 @command(
2245 b'config|showconfig|debugconfig',
2245 b'config|showconfig|debugconfig',
2246 [
2246 [
2247 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2247 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2248 # This is experimental because we need
2248 # This is experimental because we need
2249 # * reasonable behavior around aliases,
2249 # * reasonable behavior around aliases,
2250 # * decide if we display [debug] [experimental] and [devel] section par
2250 # * decide if we display [debug] [experimental] and [devel] section par
2251 # default
2251 # default
2252 # * some way to display "generic" config entry (the one matching
2252 # * some way to display "generic" config entry (the one matching
2253 # regexp,
2253 # regexp,
2254 # * proper display of the different value type
2254 # * proper display of the different value type
2255 # * a better way to handle <DYNAMIC> values (and variable types),
2255 # * a better way to handle <DYNAMIC> values (and variable types),
2256 # * maybe some type information ?
2256 # * maybe some type information ?
2257 (
2257 (
2258 b'',
2258 b'',
2259 b'exp-all-known',
2259 b'exp-all-known',
2260 None,
2260 None,
2261 _(b'show all known config option (EXPERIMENTAL)'),
2261 _(b'show all known config option (EXPERIMENTAL)'),
2262 ),
2262 ),
2263 (b'e', b'edit', None, _(b'edit user config')),
2263 (b'e', b'edit', None, _(b'edit user config')),
2264 (b'l', b'local', None, _(b'edit repository config')),
2264 (b'l', b'local', None, _(b'edit repository config')),
2265 (b'', b'source', None, _(b'show source of configuration value')),
2265 (b'', b'source', None, _(b'show source of configuration value')),
2266 (
2266 (
2267 b'',
2267 b'',
2268 b'shared',
2268 b'shared',
2269 None,
2269 None,
2270 _(b'edit shared source repository config (EXPERIMENTAL)'),
2270 _(b'edit shared source repository config (EXPERIMENTAL)'),
2271 ),
2271 ),
2272 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2272 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2273 (b'g', b'global', None, _(b'edit global config')),
2273 (b'g', b'global', None, _(b'edit global config')),
2274 ]
2274 ]
2275 + formatteropts,
2275 + formatteropts,
2276 _(b'[-u] [NAME]...'),
2276 _(b'[-u] [NAME]...'),
2277 helpcategory=command.CATEGORY_HELP,
2277 helpcategory=command.CATEGORY_HELP,
2278 optionalrepo=True,
2278 optionalrepo=True,
2279 intents={INTENT_READONLY},
2279 intents={INTENT_READONLY},
2280 )
2280 )
2281 def config(ui, repo, *values, **opts):
2281 def config(ui, repo, *values, **opts):
2282 """show combined config settings from all hgrc files
2282 """show combined config settings from all hgrc files
2283
2283
2284 With no arguments, print names and values of all config items.
2284 With no arguments, print names and values of all config items.
2285
2285
2286 With one argument of the form section.name, print just the value
2286 With one argument of the form section.name, print just the value
2287 of that config item.
2287 of that config item.
2288
2288
2289 With multiple arguments, print names and values of all config
2289 With multiple arguments, print names and values of all config
2290 items with matching section names or section.names.
2290 items with matching section names or section.names.
2291
2291
2292 With --edit, start an editor on the user-level config file. With
2292 With --edit, start an editor on the user-level config file. With
2293 --global, edit the system-wide config file. With --local, edit the
2293 --global, edit the system-wide config file. With --local, edit the
2294 repository-level config file.
2294 repository-level config file.
2295
2295
2296 With --source, the source (filename and line number) is printed
2296 With --source, the source (filename and line number) is printed
2297 for each config item.
2297 for each config item.
2298
2298
2299 See :hg:`help config` for more information about config files.
2299 See :hg:`help config` for more information about config files.
2300
2300
2301 .. container:: verbose
2301 .. container:: verbose
2302
2302
2303 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2303 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2304 This file is not shared across shares when in share-safe mode.
2304 This file is not shared across shares when in share-safe mode.
2305
2305
2306 Template:
2306 Template:
2307
2307
2308 The following keywords are supported. See also :hg:`help templates`.
2308 The following keywords are supported. See also :hg:`help templates`.
2309
2309
2310 :name: String. Config name.
2310 :name: String. Config name.
2311 :source: String. Filename and line number where the item is defined.
2311 :source: String. Filename and line number where the item is defined.
2312 :value: String. Config value.
2312 :value: String. Config value.
2313
2313
2314 The --shared flag can be used to edit the config file of shared source
2314 The --shared flag can be used to edit the config file of shared source
2315 repository. It only works when you have shared using the experimental
2315 repository. It only works when you have shared using the experimental
2316 share safe feature.
2316 share safe feature.
2317
2317
2318 Returns 0 on success, 1 if NAME does not exist.
2318 Returns 0 on success, 1 if NAME does not exist.
2319
2319
2320 """
2320 """
2321
2321
2322 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2322 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2323 if any(opts.get(o) for o in editopts):
2323 if any(opts.get(o) for o in editopts):
2324 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2324 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2325 if opts.get('local'):
2325 if opts.get('local'):
2326 if not repo:
2326 if not repo:
2327 raise error.InputError(
2327 raise error.InputError(
2328 _(b"can't use --local outside a repository")
2328 _(b"can't use --local outside a repository")
2329 )
2329 )
2330 paths = [repo.vfs.join(b'hgrc')]
2330 paths = [repo.vfs.join(b'hgrc')]
2331 elif opts.get('global'):
2331 elif opts.get('global'):
2332 paths = rcutil.systemrcpath()
2332 paths = rcutil.systemrcpath()
2333 elif opts.get('shared'):
2333 elif opts.get('shared'):
2334 if not repo.shared():
2334 if not repo.shared():
2335 raise error.InputError(
2335 raise error.InputError(
2336 _(b"repository is not shared; can't use --shared")
2336 _(b"repository is not shared; can't use --shared")
2337 )
2337 )
2338 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2338 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2339 raise error.InputError(
2339 raise error.InputError(
2340 _(
2340 _(
2341 b"share safe feature not enabled; "
2341 b"share safe feature not enabled; "
2342 b"unable to edit shared source repository config"
2342 b"unable to edit shared source repository config"
2343 )
2343 )
2344 )
2344 )
2345 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2345 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2346 elif opts.get('non_shared'):
2346 elif opts.get('non_shared'):
2347 paths = [repo.vfs.join(b'hgrc-not-shared')]
2347 paths = [repo.vfs.join(b'hgrc-not-shared')]
2348 else:
2348 else:
2349 paths = rcutil.userrcpath()
2349 paths = rcutil.userrcpath()
2350
2350
2351 for f in paths:
2351 for f in paths:
2352 if os.path.exists(f):
2352 if os.path.exists(f):
2353 break
2353 break
2354 else:
2354 else:
2355 if opts.get('global'):
2355 if opts.get('global'):
2356 samplehgrc = uimod.samplehgrcs[b'global']
2356 samplehgrc = uimod.samplehgrcs[b'global']
2357 elif opts.get('local'):
2357 elif opts.get('local'):
2358 samplehgrc = uimod.samplehgrcs[b'local']
2358 samplehgrc = uimod.samplehgrcs[b'local']
2359 else:
2359 else:
2360 samplehgrc = uimod.samplehgrcs[b'user']
2360 samplehgrc = uimod.samplehgrcs[b'user']
2361
2361
2362 f = paths[0]
2362 f = paths[0]
2363 util.writefile(f, util.tonativeeol(samplehgrc))
2363 util.writefile(f, util.tonativeeol(samplehgrc))
2364
2364
2365 editor = ui.geteditor()
2365 editor = ui.geteditor()
2366 ui.system(
2366 ui.system(
2367 b"%s \"%s\"" % (editor, f),
2367 b"%s \"%s\"" % (editor, f),
2368 onerr=error.InputError,
2368 onerr=error.InputError,
2369 errprefix=_(b"edit failed"),
2369 errprefix=_(b"edit failed"),
2370 blockedtag=b'config_edit',
2370 blockedtag=b'config_edit',
2371 )
2371 )
2372 return
2372 return
2373 ui.pager(b'config')
2373 ui.pager(b'config')
2374 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2374 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2375 for t, f in rcutil.rccomponents():
2375 for t, f in rcutil.rccomponents():
2376 if t == b'path':
2376 if t == b'path':
2377 ui.debug(b'read config from: %s\n' % f)
2377 ui.debug(b'read config from: %s\n' % f)
2378 elif t == b'resource':
2378 elif t == b'resource':
2379 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2379 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2380 elif t == b'items':
2380 elif t == b'items':
2381 # Don't print anything for 'items'.
2381 # Don't print anything for 'items'.
2382 pass
2382 pass
2383 else:
2383 else:
2384 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2384 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2385 untrusted = bool(opts.get('untrusted'))
2385 untrusted = bool(opts.get('untrusted'))
2386
2386
2387 selsections = selentries = []
2387 selsections = selentries = []
2388 if values:
2388 if values:
2389 selsections = [v for v in values if b'.' not in v]
2389 selsections = [v for v in values if b'.' not in v]
2390 selentries = [v for v in values if b'.' in v]
2390 selentries = [v for v in values if b'.' in v]
2391 uniquesel = len(selentries) == 1 and not selsections
2391 uniquesel = len(selentries) == 1 and not selsections
2392 selsections = set(selsections)
2392 selsections = set(selsections)
2393 selentries = set(selentries)
2393 selentries = set(selentries)
2394
2394
2395 matched = False
2395 matched = False
2396 all_known = opts['exp_all_known']
2396 all_known = opts['exp_all_known']
2397 show_source = ui.debugflag or opts.get('source')
2397 show_source = ui.debugflag or opts.get('source')
2398 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2398 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2399 for section, name, value in entries:
2399 for section, name, value in entries:
2400 source = ui.configsource(section, name, untrusted)
2400 source = ui.configsource(section, name, untrusted)
2401 value = pycompat.bytestr(value)
2401 value = pycompat.bytestr(value)
2402 defaultvalue = ui.configdefault(section, name)
2402 defaultvalue = ui.configdefault(section, name)
2403 if fm.isplain():
2403 if fm.isplain():
2404 source = source or b'none'
2404 source = source or b'none'
2405 value = value.replace(b'\n', b'\\n')
2405 value = value.replace(b'\n', b'\\n')
2406 entryname = section + b'.' + name
2406 entryname = section + b'.' + name
2407 if values and not (section in selsections or entryname in selentries):
2407 if values and not (section in selsections or entryname in selentries):
2408 continue
2408 continue
2409 fm.startitem()
2409 fm.startitem()
2410 fm.condwrite(show_source, b'source', b'%s: ', source)
2410 fm.condwrite(show_source, b'source', b'%s: ', source)
2411 if uniquesel:
2411 if uniquesel:
2412 fm.data(name=entryname)
2412 fm.data(name=entryname)
2413 fm.write(b'value', b'%s\n', value)
2413 fm.write(b'value', b'%s\n', value)
2414 else:
2414 else:
2415 fm.write(b'name value', b'%s=%s\n', entryname, value)
2415 fm.write(b'name value', b'%s=%s\n', entryname, value)
2416 if formatter.isprintable(defaultvalue):
2416 if formatter.isprintable(defaultvalue):
2417 fm.data(defaultvalue=defaultvalue)
2417 fm.data(defaultvalue=defaultvalue)
2418 elif isinstance(defaultvalue, list) and all(
2418 elif isinstance(defaultvalue, list) and all(
2419 formatter.isprintable(e) for e in defaultvalue
2419 formatter.isprintable(e) for e in defaultvalue
2420 ):
2420 ):
2421 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2421 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2422 # TODO: no idea how to process unsupported defaultvalue types
2422 # TODO: no idea how to process unsupported defaultvalue types
2423 matched = True
2423 matched = True
2424 fm.end()
2424 fm.end()
2425 if matched:
2425 if matched:
2426 return 0
2426 return 0
2427 return 1
2427 return 1
2428
2428
2429
2429
2430 @command(
2430 @command(
2431 b'continue',
2431 b'continue',
2432 dryrunopts,
2432 dryrunopts,
2433 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2433 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2434 helpbasic=True,
2434 helpbasic=True,
2435 )
2435 )
2436 def continuecmd(ui, repo, **opts):
2436 def continuecmd(ui, repo, **opts):
2437 """resumes an interrupted operation (EXPERIMENTAL)
2437 """resumes an interrupted operation (EXPERIMENTAL)
2438
2438
2439 Finishes a multistep operation like graft, histedit, rebase, merge,
2439 Finishes a multistep operation like graft, histedit, rebase, merge,
2440 and unshelve if they are in an interrupted state.
2440 and unshelve if they are in an interrupted state.
2441
2441
2442 use --dry-run/-n to dry run the command.
2442 use --dry-run/-n to dry run the command.
2443 """
2443 """
2444 dryrun = opts.get('dry_run')
2444 dryrun = opts.get('dry_run')
2445 contstate = cmdutil.getunfinishedstate(repo)
2445 contstate = cmdutil.getunfinishedstate(repo)
2446 if not contstate:
2446 if not contstate:
2447 raise error.StateError(_(b'no operation in progress'))
2447 raise error.StateError(_(b'no operation in progress'))
2448 if not contstate.continuefunc:
2448 if not contstate.continuefunc:
2449 raise error.StateError(
2449 raise error.StateError(
2450 (
2450 (
2451 _(b"%s in progress but does not support 'hg continue'")
2451 _(b"%s in progress but does not support 'hg continue'")
2452 % (contstate._opname)
2452 % (contstate._opname)
2453 ),
2453 ),
2454 hint=contstate.continuemsg(),
2454 hint=contstate.continuemsg(),
2455 )
2455 )
2456 if dryrun:
2456 if dryrun:
2457 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2457 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2458 return
2458 return
2459 return contstate.continuefunc(ui, repo)
2459 return contstate.continuefunc(ui, repo)
2460
2460
2461
2461
2462 @command(
2462 @command(
2463 b'copy|cp',
2463 b'copy|cp',
2464 [
2464 [
2465 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2465 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2466 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2466 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2467 (
2467 (
2468 b'',
2468 b'',
2469 b'at-rev',
2469 b'at-rev',
2470 b'',
2470 b'',
2471 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2471 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2472 _(b'REV'),
2472 _(b'REV'),
2473 ),
2473 ),
2474 (
2474 (
2475 b'f',
2475 b'f',
2476 b'force',
2476 b'force',
2477 None,
2477 None,
2478 _(b'forcibly copy over an existing managed file'),
2478 _(b'forcibly copy over an existing managed file'),
2479 ),
2479 ),
2480 ]
2480 ]
2481 + walkopts
2481 + walkopts
2482 + dryrunopts,
2482 + dryrunopts,
2483 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2483 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2484 helpcategory=command.CATEGORY_FILE_CONTENTS,
2484 helpcategory=command.CATEGORY_FILE_CONTENTS,
2485 )
2485 )
2486 def copy(ui, repo, *pats, **opts):
2486 def copy(ui, repo, *pats, **opts):
2487 """mark files as copied for the next commit
2487 """mark files as copied for the next commit
2488
2488
2489 Mark dest as having copies of source files. If dest is a
2489 Mark dest as having copies of source files. If dest is a
2490 directory, copies are put in that directory. If dest is a file,
2490 directory, copies are put in that directory. If dest is a file,
2491 the source must be a single file.
2491 the source must be a single file.
2492
2492
2493 By default, this command copies the contents of files as they
2493 By default, this command copies the contents of files as they
2494 exist in the working directory. If invoked with -A/--after, the
2494 exist in the working directory. If invoked with -A/--after, the
2495 operation is recorded, but no copying is performed.
2495 operation is recorded, but no copying is performed.
2496
2496
2497 To undo marking a destination file as copied, use --forget. With that
2497 To undo marking a destination file as copied, use --forget. With that
2498 option, all given (positional) arguments are unmarked as copies. The
2498 option, all given (positional) arguments are unmarked as copies. The
2499 destination file(s) will be left in place (still tracked). Note that
2499 destination file(s) will be left in place (still tracked). Note that
2500 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2500 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2501
2501
2502 This command takes effect with the next commit by default.
2502 This command takes effect with the next commit by default.
2503
2503
2504 Returns 0 on success, 1 if errors are encountered.
2504 Returns 0 on success, 1 if errors are encountered.
2505 """
2505 """
2506
2506
2507 context = lambda repo: repo.dirstate.changing_files(repo)
2507 context = lambda repo: repo.dirstate.changing_files(repo)
2508 rev = opts.get('at_rev')
2508 rev = opts.get('at_rev')
2509
2509
2510 if rev:
2510 if rev:
2511 ctx = logcmdutil.revsingle(repo, rev)
2511 ctx = logcmdutil.revsingle(repo, rev)
2512 if ctx.rev() is not None:
2512 if ctx.rev() is not None:
2513
2513
2514 def context(repo):
2514 def context(repo):
2515 return util.nullcontextmanager()
2515 return util.nullcontextmanager()
2516
2516
2517 opts['at_rev'] = ctx.rev()
2517 opts['at_rev'] = ctx.rev()
2518 with repo.wlock(), context(repo):
2518 with repo.wlock(), context(repo):
2519 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2519 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2520
2520
2521
2521
2522 @command(
2522 @command(
2523 b'debugcommands',
2523 b'debugcommands',
2524 [],
2524 [],
2525 _(b'[COMMAND]'),
2525 _(b'[COMMAND]'),
2526 helpcategory=command.CATEGORY_HELP,
2526 helpcategory=command.CATEGORY_HELP,
2527 norepo=True,
2527 norepo=True,
2528 )
2528 )
2529 def debugcommands(ui, cmd=b'', *args):
2529 def debugcommands(ui, cmd=b'', *args):
2530 """list all available commands and options"""
2530 """list all available commands and options"""
2531 for cmd, vals in sorted(table.items()):
2531 for cmd, vals in sorted(table.items()):
2532 cmd = cmd.split(b'|')[0]
2532 cmd = cmd.split(b'|')[0]
2533 opts = b', '.join([i[1] for i in vals[1]])
2533 opts = b', '.join([i[1] for i in vals[1]])
2534 ui.write(b'%s: %s\n' % (cmd, opts))
2534 ui.write(b'%s: %s\n' % (cmd, opts))
2535
2535
2536
2536
2537 @command(
2537 @command(
2538 b'debugcomplete',
2538 b'debugcomplete',
2539 [(b'o', b'options', None, _(b'show the command options'))],
2539 [(b'o', b'options', None, _(b'show the command options'))],
2540 _(b'[-o] CMD'),
2540 _(b'[-o] CMD'),
2541 helpcategory=command.CATEGORY_HELP,
2541 helpcategory=command.CATEGORY_HELP,
2542 norepo=True,
2542 norepo=True,
2543 )
2543 )
2544 def debugcomplete(ui, cmd=b'', **opts):
2544 def debugcomplete(ui, cmd=b'', **opts):
2545 """returns the completion list associated with the given command"""
2545 """returns the completion list associated with the given command"""
2546
2546
2547 if opts.get('options'):
2547 if opts.get('options'):
2548 options = []
2548 options = []
2549 otables = [globalopts]
2549 otables = [globalopts]
2550 if cmd:
2550 if cmd:
2551 aliases, entry = cmdutil.findcmd(cmd, table, False)
2551 aliases, entry = cmdutil.findcmd(cmd, table, False)
2552 otables.append(entry[1])
2552 otables.append(entry[1])
2553 for t in otables:
2553 for t in otables:
2554 for o in t:
2554 for o in t:
2555 if b"(DEPRECATED)" in o[3]:
2555 if b"(DEPRECATED)" in o[3]:
2556 continue
2556 continue
2557 if o[0]:
2557 if o[0]:
2558 options.append(b'-%s' % o[0])
2558 options.append(b'-%s' % o[0])
2559 options.append(b'--%s' % o[1])
2559 options.append(b'--%s' % o[1])
2560 ui.write(b"%s\n" % b"\n".join(options))
2560 ui.write(b"%s\n" % b"\n".join(options))
2561 return
2561 return
2562
2562
2563 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2563 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2564 if ui.verbose:
2564 if ui.verbose:
2565 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2565 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2566 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2566 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2567
2567
2568
2568
2569 @command(
2569 @command(
2570 b'diff',
2570 b'diff',
2571 [
2571 [
2572 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2572 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2573 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2573 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2574 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2574 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2575 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2575 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2576 ]
2576 ]
2577 + diffopts
2577 + diffopts
2578 + diffopts2
2578 + diffopts2
2579 + walkopts
2579 + walkopts
2580 + subrepoopts,
2580 + subrepoopts,
2581 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2581 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2582 helpcategory=command.CATEGORY_FILE_CONTENTS,
2582 helpcategory=command.CATEGORY_FILE_CONTENTS,
2583 helpbasic=True,
2583 helpbasic=True,
2584 inferrepo=True,
2584 inferrepo=True,
2585 intents={INTENT_READONLY},
2585 intents={INTENT_READONLY},
2586 )
2586 )
2587 def diff(ui, repo, *pats, **opts):
2587 def diff(ui, repo, *pats, **opts):
2588 """diff repository (or selected files)
2588 """diff repository (or selected files)
2589
2589
2590 Show differences between revisions for the specified files.
2590 Show differences between revisions for the specified files.
2591
2591
2592 Differences between files are shown using the unified diff format.
2592 Differences between files are shown using the unified diff format.
2593
2593
2594 .. note::
2594 .. note::
2595
2595
2596 :hg:`diff` may generate unexpected results for merges, as it will
2596 :hg:`diff` may generate unexpected results for merges, as it will
2597 default to comparing against the working directory's first
2597 default to comparing against the working directory's first
2598 parent changeset if no revisions are specified. To diff against the
2598 parent changeset if no revisions are specified. To diff against the
2599 conflict regions, you can use `--config diff.merge=yes`.
2599 conflict regions, you can use `--config diff.merge=yes`.
2600
2600
2601 By default, the working directory files are compared to its first parent. To
2601 By default, the working directory files are compared to its first parent. To
2602 see the differences from another revision, use --from. To see the difference
2602 see the differences from another revision, use --from. To see the difference
2603 to another revision, use --to. For example, :hg:`diff --from .^` will show
2603 to another revision, use --to. For example, :hg:`diff --from .^` will show
2604 the differences from the working copy's grandparent to the working copy,
2604 the differences from the working copy's grandparent to the working copy,
2605 :hg:`diff --to .` will show the diff from the working copy to its parent
2605 :hg:`diff --to .` will show the diff from the working copy to its parent
2606 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2606 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2607 show the diff between those two revisions.
2607 show the diff between those two revisions.
2608
2608
2609 Alternatively you can specify -c/--change with a revision to see the changes
2609 Alternatively you can specify -c/--change with a revision to see the changes
2610 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2610 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2611 equivalent to :hg:`diff --from 42^ --to 42`)
2611 equivalent to :hg:`diff --from 42^ --to 42`)
2612
2612
2613 Without the -a/--text option, diff will avoid generating diffs of
2613 Without the -a/--text option, diff will avoid generating diffs of
2614 files it detects as binary. With -a, diff will generate a diff
2614 files it detects as binary. With -a, diff will generate a diff
2615 anyway, probably with undesirable results.
2615 anyway, probably with undesirable results.
2616
2616
2617 Use the -g/--git option to generate diffs in the git extended diff
2617 Use the -g/--git option to generate diffs in the git extended diff
2618 format. For more information, read :hg:`help diffs`.
2618 format. For more information, read :hg:`help diffs`.
2619
2619
2620 .. container:: verbose
2620 .. container:: verbose
2621
2621
2622 Examples:
2622 Examples:
2623
2623
2624 - compare a file in the current working directory to its parent::
2624 - compare a file in the current working directory to its parent::
2625
2625
2626 hg diff foo.c
2626 hg diff foo.c
2627
2627
2628 - compare two historical versions of a directory, with rename info::
2628 - compare two historical versions of a directory, with rename info::
2629
2629
2630 hg diff --git --from 1.0 --to 1.2 lib/
2630 hg diff --git --from 1.0 --to 1.2 lib/
2631
2631
2632 - get change stats relative to the last change on some date::
2632 - get change stats relative to the last change on some date::
2633
2633
2634 hg diff --stat --from "date('may 2')"
2634 hg diff --stat --from "date('may 2')"
2635
2635
2636 - diff all newly-added files that contain a keyword::
2636 - diff all newly-added files that contain a keyword::
2637
2637
2638 hg diff "set:added() and grep(GNU)"
2638 hg diff "set:added() and grep(GNU)"
2639
2639
2640 - compare a revision and its parents::
2640 - compare a revision and its parents::
2641
2641
2642 hg diff -c 9353 # compare against first parent
2642 hg diff -c 9353 # compare against first parent
2643 hg diff --from 9353^ --to 9353 # same using revset syntax
2643 hg diff --from 9353^ --to 9353 # same using revset syntax
2644 hg diff --from 9353^2 --to 9353 # compare against the second parent
2644 hg diff --from 9353^2 --to 9353 # compare against the second parent
2645
2645
2646 Returns 0 on success.
2646 Returns 0 on success.
2647 """
2647 """
2648
2648
2649 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2649 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2650 opts = pycompat.byteskwargs(opts)
2650 opts = pycompat.byteskwargs(opts)
2651 revs = opts.get(b'rev')
2651 revs = opts.get(b'rev')
2652 change = opts.get(b'change')
2652 change = opts.get(b'change')
2653 from_rev = opts.get(b'from')
2653 from_rev = opts.get(b'from')
2654 to_rev = opts.get(b'to')
2654 to_rev = opts.get(b'to')
2655 stat = opts.get(b'stat')
2655 stat = opts.get(b'stat')
2656 reverse = opts.get(b'reverse')
2656 reverse = opts.get(b'reverse')
2657
2657
2658 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2658 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2659 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2659 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2660 if change:
2660 if change:
2661 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2661 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2662 ctx2 = logcmdutil.revsingle(repo, change, None)
2662 ctx2 = logcmdutil.revsingle(repo, change, None)
2663 ctx1 = logcmdutil.diff_parent(ctx2)
2663 ctx1 = logcmdutil.diff_parent(ctx2)
2664 elif from_rev or to_rev:
2664 elif from_rev or to_rev:
2665 repo = scmutil.unhidehashlikerevs(
2665 repo = scmutil.unhidehashlikerevs(
2666 repo, [from_rev] + [to_rev], b'nowarn'
2666 repo, [from_rev] + [to_rev], b'nowarn'
2667 )
2667 )
2668 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2668 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2669 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2669 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2670 else:
2670 else:
2671 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2671 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2672 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2672 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2673
2673
2674 if reverse:
2674 if reverse:
2675 ctxleft = ctx2
2675 ctxleft = ctx2
2676 ctxright = ctx1
2676 ctxright = ctx1
2677 else:
2677 else:
2678 ctxleft = ctx1
2678 ctxleft = ctx1
2679 ctxright = ctx2
2679 ctxright = ctx2
2680
2680
2681 diffopts = patch.diffallopts(ui, opts)
2681 diffopts = patch.diffallopts(ui, opts)
2682 m = scmutil.match(ctx2, pats, opts)
2682 m = scmutil.match(ctx2, pats, opts)
2683 m = repo.narrowmatch(m)
2683 m = repo.narrowmatch(m)
2684 ui.pager(b'diff')
2684 ui.pager(b'diff')
2685 logcmdutil.diffordiffstat(
2685 logcmdutil.diffordiffstat(
2686 ui,
2686 ui,
2687 repo,
2687 repo,
2688 diffopts,
2688 diffopts,
2689 ctxleft,
2689 ctxleft,
2690 ctxright,
2690 ctxright,
2691 m,
2691 m,
2692 stat=stat,
2692 stat=stat,
2693 listsubrepos=opts.get(b'subrepos'),
2693 listsubrepos=opts.get(b'subrepos'),
2694 root=opts.get(b'root'),
2694 root=opts.get(b'root'),
2695 )
2695 )
2696
2696
2697
2697
2698 @command(
2698 @command(
2699 b'export',
2699 b'export',
2700 [
2700 [
2701 (
2701 (
2702 b'B',
2702 b'B',
2703 b'bookmark',
2703 b'bookmark',
2704 b'',
2704 b'',
2705 _(b'export changes only reachable by given bookmark'),
2705 _(b'export changes only reachable by given bookmark'),
2706 _(b'BOOKMARK'),
2706 _(b'BOOKMARK'),
2707 ),
2707 ),
2708 (
2708 (
2709 b'o',
2709 b'o',
2710 b'output',
2710 b'output',
2711 b'',
2711 b'',
2712 _(b'print output to file with formatted name'),
2712 _(b'print output to file with formatted name'),
2713 _(b'FORMAT'),
2713 _(b'FORMAT'),
2714 ),
2714 ),
2715 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2715 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2716 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2716 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2717 ]
2717 ]
2718 + diffopts
2718 + diffopts
2719 + formatteropts,
2719 + formatteropts,
2720 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2720 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2721 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2721 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2722 helpbasic=True,
2722 helpbasic=True,
2723 intents={INTENT_READONLY},
2723 intents={INTENT_READONLY},
2724 )
2724 )
2725 def export(ui, repo, *changesets, **opts):
2725 def export(ui, repo, *changesets, **opts):
2726 """dump the header and diffs for one or more changesets
2726 """dump the header and diffs for one or more changesets
2727
2727
2728 Print the changeset header and diffs for one or more revisions.
2728 Print the changeset header and diffs for one or more revisions.
2729 If no revision is given, the parent of the working directory is used.
2729 If no revision is given, the parent of the working directory is used.
2730
2730
2731 The information shown in the changeset header is: author, date,
2731 The information shown in the changeset header is: author, date,
2732 branch name (if non-default), changeset hash, parent(s) and commit
2732 branch name (if non-default), changeset hash, parent(s) and commit
2733 comment.
2733 comment.
2734
2734
2735 .. note::
2735 .. note::
2736
2736
2737 :hg:`export` may generate unexpected diff output for merge
2737 :hg:`export` may generate unexpected diff output for merge
2738 changesets, as it will compare the merge changeset against its
2738 changesets, as it will compare the merge changeset against its
2739 first parent only.
2739 first parent only.
2740
2740
2741 Output may be to a file, in which case the name of the file is
2741 Output may be to a file, in which case the name of the file is
2742 given using a template string. See :hg:`help templates`. In addition
2742 given using a template string. See :hg:`help templates`. In addition
2743 to the common template keywords, the following formatting rules are
2743 to the common template keywords, the following formatting rules are
2744 supported:
2744 supported:
2745
2745
2746 :``%%``: literal "%" character
2746 :``%%``: literal "%" character
2747 :``%H``: changeset hash (40 hexadecimal digits)
2747 :``%H``: changeset hash (40 hexadecimal digits)
2748 :``%N``: number of patches being generated
2748 :``%N``: number of patches being generated
2749 :``%R``: changeset revision number
2749 :``%R``: changeset revision number
2750 :``%b``: basename of the exporting repository
2750 :``%b``: basename of the exporting repository
2751 :``%h``: short-form changeset hash (12 hexadecimal digits)
2751 :``%h``: short-form changeset hash (12 hexadecimal digits)
2752 :``%m``: first line of the commit message (only alphanumeric characters)
2752 :``%m``: first line of the commit message (only alphanumeric characters)
2753 :``%n``: zero-padded sequence number, starting at 1
2753 :``%n``: zero-padded sequence number, starting at 1
2754 :``%r``: zero-padded changeset revision number
2754 :``%r``: zero-padded changeset revision number
2755 :``\\``: literal "\\" character
2755 :``\\``: literal "\\" character
2756
2756
2757 Without the -a/--text option, export will avoid generating diffs
2757 Without the -a/--text option, export will avoid generating diffs
2758 of files it detects as binary. With -a, export will generate a
2758 of files it detects as binary. With -a, export will generate a
2759 diff anyway, probably with undesirable results.
2759 diff anyway, probably with undesirable results.
2760
2760
2761 With -B/--bookmark changesets reachable by the given bookmark are
2761 With -B/--bookmark changesets reachable by the given bookmark are
2762 selected.
2762 selected.
2763
2763
2764 Use the -g/--git option to generate diffs in the git extended diff
2764 Use the -g/--git option to generate diffs in the git extended diff
2765 format. See :hg:`help diffs` for more information.
2765 format. See :hg:`help diffs` for more information.
2766
2766
2767 With the --switch-parent option, the diff will be against the
2767 With the --switch-parent option, the diff will be against the
2768 second parent. It can be useful to review a merge.
2768 second parent. It can be useful to review a merge.
2769
2769
2770 .. container:: verbose
2770 .. container:: verbose
2771
2771
2772 Template:
2772 Template:
2773
2773
2774 The following keywords are supported in addition to the common template
2774 The following keywords are supported in addition to the common template
2775 keywords and functions. See also :hg:`help templates`.
2775 keywords and functions. See also :hg:`help templates`.
2776
2776
2777 :diff: String. Diff content.
2777 :diff: String. Diff content.
2778 :parents: List of strings. Parent nodes of the changeset.
2778 :parents: List of strings. Parent nodes of the changeset.
2779
2779
2780 Examples:
2780 Examples:
2781
2781
2782 - use export and import to transplant a bugfix to the current
2782 - use export and import to transplant a bugfix to the current
2783 branch::
2783 branch::
2784
2784
2785 hg export -r 9353 | hg import -
2785 hg export -r 9353 | hg import -
2786
2786
2787 - export all the changesets between two revisions to a file with
2787 - export all the changesets between two revisions to a file with
2788 rename information::
2788 rename information::
2789
2789
2790 hg export --git -r 123:150 > changes.txt
2790 hg export --git -r 123:150 > changes.txt
2791
2791
2792 - split outgoing changes into a series of patches with
2792 - split outgoing changes into a series of patches with
2793 descriptive names::
2793 descriptive names::
2794
2794
2795 hg export -r "outgoing()" -o "%n-%m.patch"
2795 hg export -r "outgoing()" -o "%n-%m.patch"
2796
2796
2797 Returns 0 on success.
2797 Returns 0 on success.
2798 """
2798 """
2799 opts = pycompat.byteskwargs(opts)
2799 opts = pycompat.byteskwargs(opts)
2800 bookmark = opts.get(b'bookmark')
2800 bookmark = opts.get(b'bookmark')
2801 changesets += tuple(opts.get(b'rev', []))
2801 changesets += tuple(opts.get(b'rev', []))
2802
2802
2803 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2803 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2804
2804
2805 if bookmark:
2805 if bookmark:
2806 if bookmark not in repo._bookmarks:
2806 if bookmark not in repo._bookmarks:
2807 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2807 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2808
2808
2809 revs = scmutil.bookmarkrevs(repo, bookmark)
2809 revs = scmutil.bookmarkrevs(repo, bookmark)
2810 else:
2810 else:
2811 if not changesets:
2811 if not changesets:
2812 changesets = [b'.']
2812 changesets = [b'.']
2813
2813
2814 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2814 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2815 revs = logcmdutil.revrange(repo, changesets)
2815 revs = logcmdutil.revrange(repo, changesets)
2816
2816
2817 if not revs:
2817 if not revs:
2818 raise error.InputError(_(b"export requires at least one changeset"))
2818 raise error.InputError(_(b"export requires at least one changeset"))
2819 if len(revs) > 1:
2819 if len(revs) > 1:
2820 ui.note(_(b'exporting patches:\n'))
2820 ui.note(_(b'exporting patches:\n'))
2821 else:
2821 else:
2822 ui.note(_(b'exporting patch:\n'))
2822 ui.note(_(b'exporting patch:\n'))
2823
2823
2824 fntemplate = opts.get(b'output')
2824 fntemplate = opts.get(b'output')
2825 if cmdutil.isstdiofilename(fntemplate):
2825 if cmdutil.isstdiofilename(fntemplate):
2826 fntemplate = b''
2826 fntemplate = b''
2827
2827
2828 if fntemplate:
2828 if fntemplate:
2829 fm = formatter.nullformatter(ui, b'export', opts)
2829 fm = formatter.nullformatter(ui, b'export', opts)
2830 else:
2830 else:
2831 ui.pager(b'export')
2831 ui.pager(b'export')
2832 fm = ui.formatter(b'export', opts)
2832 fm = ui.formatter(b'export', opts)
2833 with fm:
2833 with fm:
2834 cmdutil.export(
2834 cmdutil.export(
2835 repo,
2835 repo,
2836 revs,
2836 revs,
2837 fm,
2837 fm,
2838 fntemplate=fntemplate,
2838 fntemplate=fntemplate,
2839 switch_parent=opts.get(b'switch_parent'),
2839 switch_parent=opts.get(b'switch_parent'),
2840 opts=patch.diffallopts(ui, opts),
2840 opts=patch.diffallopts(ui, opts),
2841 )
2841 )
2842
2842
2843
2843
2844 @command(
2844 @command(
2845 b'files',
2845 b'files',
2846 [
2846 [
2847 (
2847 (
2848 b'r',
2848 b'r',
2849 b'rev',
2849 b'rev',
2850 b'',
2850 b'',
2851 _(b'search the repository as it is in REV'),
2851 _(b'search the repository as it is in REV'),
2852 _(b'REV'),
2852 _(b'REV'),
2853 ),
2853 ),
2854 (
2854 (
2855 b'0',
2855 b'0',
2856 b'print0',
2856 b'print0',
2857 None,
2857 None,
2858 _(b'end filenames with NUL, for use with xargs'),
2858 _(b'end filenames with NUL, for use with xargs'),
2859 ),
2859 ),
2860 ]
2860 ]
2861 + walkopts
2861 + walkopts
2862 + formatteropts
2862 + formatteropts
2863 + subrepoopts,
2863 + subrepoopts,
2864 _(b'[OPTION]... [FILE]...'),
2864 _(b'[OPTION]... [FILE]...'),
2865 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2865 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2866 intents={INTENT_READONLY},
2866 intents={INTENT_READONLY},
2867 )
2867 )
2868 def files(ui, repo, *pats, **opts):
2868 def files(ui, repo, *pats, **opts):
2869 """list tracked files
2869 """list tracked files
2870
2870
2871 Print files under Mercurial control in the working directory or
2871 Print files under Mercurial control in the working directory or
2872 specified revision for given files (excluding removed files).
2872 specified revision for given files (excluding removed files).
2873 Files can be specified as filenames or filesets.
2873 Files can be specified as filenames or filesets.
2874
2874
2875 If no files are given to match, this command prints the names
2875 If no files are given to match, this command prints the names
2876 of all files under Mercurial control.
2876 of all files under Mercurial control.
2877
2877
2878 .. container:: verbose
2878 .. container:: verbose
2879
2879
2880 Template:
2880 Template:
2881
2881
2882 The following keywords are supported in addition to the common template
2882 The following keywords are supported in addition to the common template
2883 keywords and functions. See also :hg:`help templates`.
2883 keywords and functions. See also :hg:`help templates`.
2884
2884
2885 :flags: String. Character denoting file's symlink and executable bits.
2885 :flags: String. Character denoting file's symlink and executable bits.
2886 :path: String. Repository-absolute path of the file.
2886 :path: String. Repository-absolute path of the file.
2887 :size: Integer. Size of the file in bytes.
2887 :size: Integer. Size of the file in bytes.
2888
2888
2889 Examples:
2889 Examples:
2890
2890
2891 - list all files under the current directory::
2891 - list all files under the current directory::
2892
2892
2893 hg files .
2893 hg files .
2894
2894
2895 - shows sizes and flags for current revision::
2895 - shows sizes and flags for current revision::
2896
2896
2897 hg files -vr .
2897 hg files -vr .
2898
2898
2899 - list all files named README::
2899 - list all files named README::
2900
2900
2901 hg files -I "**/README"
2901 hg files -I "**/README"
2902
2902
2903 - list all binary files::
2903 - list all binary files::
2904
2904
2905 hg files "set:binary()"
2905 hg files "set:binary()"
2906
2906
2907 - find files containing a regular expression::
2907 - find files containing a regular expression::
2908
2908
2909 hg files "set:grep('bob')"
2909 hg files "set:grep('bob')"
2910
2910
2911 - search tracked file contents with xargs and grep::
2911 - search tracked file contents with xargs and grep::
2912
2912
2913 hg files -0 | xargs -0 grep foo
2913 hg files -0 | xargs -0 grep foo
2914
2914
2915 See :hg:`help patterns` and :hg:`help filesets` for more information
2915 See :hg:`help patterns` and :hg:`help filesets` for more information
2916 on specifying file patterns.
2916 on specifying file patterns.
2917
2917
2918 Returns 0 if a match is found, 1 otherwise.
2918 Returns 0 if a match is found, 1 otherwise.
2919
2919
2920 """
2920 """
2921
2921
2922 opts = pycompat.byteskwargs(opts)
2922 opts = pycompat.byteskwargs(opts)
2923 rev = opts.get(b'rev')
2923 rev = opts.get(b'rev')
2924 if rev:
2924 if rev:
2925 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2925 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2926 ctx = logcmdutil.revsingle(repo, rev, None)
2926 ctx = logcmdutil.revsingle(repo, rev, None)
2927
2927
2928 end = b'\n'
2928 end = b'\n'
2929 if opts.get(b'print0'):
2929 if opts.get(b'print0'):
2930 end = b'\0'
2930 end = b'\0'
2931 fmt = b'%s' + end
2931 fmt = b'%s' + end
2932
2932
2933 m = scmutil.match(ctx, pats, opts)
2933 m = scmutil.match(ctx, pats, opts)
2934 ui.pager(b'files')
2934 ui.pager(b'files')
2935 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2935 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2936 with ui.formatter(b'files', opts) as fm:
2936 with ui.formatter(b'files', opts) as fm:
2937 return cmdutil.files(
2937 return cmdutil.files(
2938 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2938 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2939 )
2939 )
2940
2940
2941
2941
2942 @command(
2942 @command(
2943 b'forget',
2943 b'forget',
2944 [
2944 [
2945 (b'i', b'interactive', None, _(b'use interactive mode')),
2945 (b'i', b'interactive', None, _(b'use interactive mode')),
2946 ]
2946 ]
2947 + walkopts
2947 + walkopts
2948 + dryrunopts,
2948 + dryrunopts,
2949 _(b'[OPTION]... FILE...'),
2949 _(b'[OPTION]... FILE...'),
2950 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2950 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2951 helpbasic=True,
2951 helpbasic=True,
2952 inferrepo=True,
2952 inferrepo=True,
2953 )
2953 )
2954 def forget(ui, repo, *pats, **opts):
2954 def forget(ui, repo, *pats, **opts):
2955 """forget the specified files on the next commit
2955 """forget the specified files on the next commit
2956
2956
2957 Mark the specified files so they will no longer be tracked
2957 Mark the specified files so they will no longer be tracked
2958 after the next commit.
2958 after the next commit.
2959
2959
2960 This only removes files from the current branch, not from the
2960 This only removes files from the current branch, not from the
2961 entire project history, and it does not delete them from the
2961 entire project history, and it does not delete them from the
2962 working directory.
2962 working directory.
2963
2963
2964 To delete the file from the working directory, see :hg:`remove`.
2964 To delete the file from the working directory, see :hg:`remove`.
2965
2965
2966 To undo a forget before the next commit, see :hg:`add`.
2966 To undo a forget before the next commit, see :hg:`add`.
2967
2967
2968 .. container:: verbose
2968 .. container:: verbose
2969
2969
2970 Examples:
2970 Examples:
2971
2971
2972 - forget newly-added binary files::
2972 - forget newly-added binary files::
2973
2973
2974 hg forget "set:added() and binary()"
2974 hg forget "set:added() and binary()"
2975
2975
2976 - forget files that would be excluded by .hgignore::
2976 - forget files that would be excluded by .hgignore::
2977
2977
2978 hg forget "set:hgignore()"
2978 hg forget "set:hgignore()"
2979
2979
2980 Returns 0 on success.
2980 Returns 0 on success.
2981 """
2981 """
2982
2982
2983 if not pats:
2983 if not pats:
2984 raise error.InputError(_(b'no files specified'))
2984 raise error.InputError(_(b'no files specified'))
2985
2985
2986 with repo.wlock(), repo.dirstate.changing_files(repo):
2986 with repo.wlock(), repo.dirstate.changing_files(repo):
2987 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2987 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2988 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2988 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2989 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2989 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2990 rejected = cmdutil.forget(
2990 rejected = cmdutil.forget(
2991 ui,
2991 ui,
2992 repo,
2992 repo,
2993 m,
2993 m,
2994 prefix=b"",
2994 prefix=b"",
2995 uipathfn=uipathfn,
2995 uipathfn=uipathfn,
2996 explicitonly=False,
2996 explicitonly=False,
2997 dryrun=dryrun,
2997 dryrun=dryrun,
2998 interactive=interactive,
2998 interactive=interactive,
2999 )[0]
2999 )[0]
3000 return rejected and 1 or 0
3000 return rejected and 1 or 0
3001
3001
3002
3002
3003 @command(
3003 @command(
3004 b'graft',
3004 b'graft',
3005 [
3005 [
3006 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3006 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3007 (
3007 (
3008 b'',
3008 b'',
3009 b'base',
3009 b'base',
3010 b'',
3010 b'',
3011 _(b'base revision when doing the graft merge (ADVANCED)'),
3011 _(b'base revision when doing the graft merge (ADVANCED)'),
3012 _(b'REV'),
3012 _(b'REV'),
3013 ),
3013 ),
3014 (b'c', b'continue', False, _(b'resume interrupted graft')),
3014 (b'c', b'continue', False, _(b'resume interrupted graft')),
3015 (b'', b'stop', False, _(b'stop interrupted graft')),
3015 (b'', b'stop', False, _(b'stop interrupted graft')),
3016 (b'', b'abort', False, _(b'abort interrupted graft')),
3016 (b'', b'abort', False, _(b'abort interrupted graft')),
3017 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3017 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3018 (b'', b'log', None, _(b'append graft info to log message')),
3018 (b'', b'log', None, _(b'append graft info to log message')),
3019 (
3019 (
3020 b'',
3020 b'',
3021 b'no-commit',
3021 b'no-commit',
3022 None,
3022 None,
3023 _(b"don't commit, just apply the changes in working directory"),
3023 _(b"don't commit, just apply the changes in working directory"),
3024 ),
3024 ),
3025 (b'f', b'force', False, _(b'force graft')),
3025 (b'f', b'force', False, _(b'force graft')),
3026 (
3026 (
3027 b'D',
3027 b'D',
3028 b'currentdate',
3028 b'currentdate',
3029 False,
3029 False,
3030 _(b'record the current date as commit date'),
3030 _(b'record the current date as commit date'),
3031 ),
3031 ),
3032 (
3032 (
3033 b'U',
3033 b'U',
3034 b'currentuser',
3034 b'currentuser',
3035 False,
3035 False,
3036 _(b'record the current user as committer'),
3036 _(b'record the current user as committer'),
3037 ),
3037 ),
3038 ]
3038 ]
3039 + commitopts2
3039 + commitopts2
3040 + mergetoolopts
3040 + mergetoolopts
3041 + dryrunopts,
3041 + dryrunopts,
3042 _(b'[OPTION]... [-r REV]... REV...'),
3042 _(b'[OPTION]... [-r REV]... REV...'),
3043 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3043 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3044 )
3044 )
3045 def graft(ui, repo, *revs, **opts):
3045 def graft(ui, repo, *revs, **opts):
3046 """copy changes from other branches onto the current branch
3046 """copy changes from other branches onto the current branch
3047
3047
3048 This command uses Mercurial's merge logic to copy individual
3048 This command uses Mercurial's merge logic to copy individual
3049 changes from other branches without merging branches in the
3049 changes from other branches without merging branches in the
3050 history graph. This is sometimes known as 'backporting' or
3050 history graph. This is sometimes known as 'backporting' or
3051 'cherry-picking'. By default, graft will copy user, date, and
3051 'cherry-picking'. By default, graft will copy user, date, and
3052 description from the source changesets.
3052 description from the source changesets.
3053
3053
3054 Changesets that are ancestors of the current revision, that have
3054 Changesets that are ancestors of the current revision, that have
3055 already been grafted, or that are merges will be skipped.
3055 already been grafted, or that are merges will be skipped.
3056
3056
3057 If --log is specified, log messages will have a comment appended
3057 If --log is specified, log messages will have a comment appended
3058 of the form::
3058 of the form::
3059
3059
3060 (grafted from CHANGESETHASH)
3060 (grafted from CHANGESETHASH)
3061
3061
3062 If --force is specified, revisions will be grafted even if they
3062 If --force is specified, revisions will be grafted even if they
3063 are already ancestors of, or have been grafted to, the destination.
3063 are already ancestors of, or have been grafted to, the destination.
3064 This is useful when the revisions have since been backed out.
3064 This is useful when the revisions have since been backed out.
3065
3065
3066 If a graft merge results in conflicts, the graft process is
3066 If a graft merge results in conflicts, the graft process is
3067 interrupted so that the current merge can be manually resolved.
3067 interrupted so that the current merge can be manually resolved.
3068 Once all conflicts are addressed, the graft process can be
3068 Once all conflicts are addressed, the graft process can be
3069 continued with the -c/--continue option.
3069 continued with the -c/--continue option.
3070
3070
3071 The -c/--continue option reapplies all the earlier options.
3071 The -c/--continue option reapplies all the earlier options.
3072
3072
3073 .. container:: verbose
3073 .. container:: verbose
3074
3074
3075 The --base option exposes more of how graft internally uses merge with a
3075 The --base option exposes more of how graft internally uses merge with a
3076 custom base revision. --base can be used to specify another ancestor than
3076 custom base revision. --base can be used to specify another ancestor than
3077 the first and only parent.
3077 the first and only parent.
3078
3078
3079 The command::
3079 The command::
3080
3080
3081 hg graft -r 345 --base 234
3081 hg graft -r 345 --base 234
3082
3082
3083 is thus pretty much the same as::
3083 is thus pretty much the same as::
3084
3084
3085 hg diff --from 234 --to 345 | hg import
3085 hg diff --from 234 --to 345 | hg import
3086
3086
3087 but using merge to resolve conflicts and track moved files.
3087 but using merge to resolve conflicts and track moved files.
3088
3088
3089 The result of a merge can thus be backported as a single commit by
3089 The result of a merge can thus be backported as a single commit by
3090 specifying one of the merge parents as base, and thus effectively
3090 specifying one of the merge parents as base, and thus effectively
3091 grafting the changes from the other side.
3091 grafting the changes from the other side.
3092
3092
3093 It is also possible to collapse multiple changesets and clean up history
3093 It is also possible to collapse multiple changesets and clean up history
3094 by specifying another ancestor as base, much like rebase --collapse
3094 by specifying another ancestor as base, much like rebase --collapse
3095 --keep.
3095 --keep.
3096
3096
3097 The commit message can be tweaked after the fact using commit --amend .
3097 The commit message can be tweaked after the fact using commit --amend .
3098
3098
3099 For using non-ancestors as the base to backout changes, see the backout
3099 For using non-ancestors as the base to backout changes, see the backout
3100 command and the hidden --parent option.
3100 command and the hidden --parent option.
3101
3101
3102 .. container:: verbose
3102 .. container:: verbose
3103
3103
3104 Examples:
3104 Examples:
3105
3105
3106 - copy a single change to the stable branch and edit its description::
3106 - copy a single change to the stable branch and edit its description::
3107
3107
3108 hg update stable
3108 hg update stable
3109 hg graft --edit 9393
3109 hg graft --edit 9393
3110
3110
3111 - graft a range of changesets with one exception, updating dates::
3111 - graft a range of changesets with one exception, updating dates::
3112
3112
3113 hg graft -D "2085::2093 and not 2091"
3113 hg graft -D "2085::2093 and not 2091"
3114
3114
3115 - continue a graft after resolving conflicts::
3115 - continue a graft after resolving conflicts::
3116
3116
3117 hg graft -c
3117 hg graft -c
3118
3118
3119 - show the source of a grafted changeset::
3119 - show the source of a grafted changeset::
3120
3120
3121 hg log --debug -r .
3121 hg log --debug -r .
3122
3122
3123 - show revisions sorted by date::
3123 - show revisions sorted by date::
3124
3124
3125 hg log -r "sort(all(), date)"
3125 hg log -r "sort(all(), date)"
3126
3126
3127 - backport the result of a merge as a single commit::
3127 - backport the result of a merge as a single commit::
3128
3128
3129 hg graft -r 123 --base 123^
3129 hg graft -r 123 --base 123^
3130
3130
3131 - land a feature branch as one changeset::
3131 - land a feature branch as one changeset::
3132
3132
3133 hg up -cr default
3133 hg up -cr default
3134 hg graft -r featureX --base "ancestor('featureX', 'default')"
3134 hg graft -r featureX --base "ancestor('featureX', 'default')"
3135
3135
3136 See :hg:`help revisions` for more about specifying revisions.
3136 See :hg:`help revisions` for more about specifying revisions.
3137
3137
3138 Returns 0 on successful completion, 1 if there are unresolved files.
3138 Returns 0 on successful completion, 1 if there are unresolved files.
3139 """
3139 """
3140 with repo.wlock():
3140 with repo.wlock():
3141 return _dograft(ui, repo, *revs, **opts)
3141 return _dograft(ui, repo, *revs, **opts)
3142
3142
3143
3143
3144 def _dograft(ui, repo, *revs, **opts):
3144 def _dograft(ui, repo, *revs, **opts):
3145 if revs and opts.get('rev'):
3145 if revs and opts.get('rev'):
3146 ui.warn(
3146 ui.warn(
3147 _(
3147 _(
3148 b'warning: inconsistent use of --rev might give unexpected '
3148 b'warning: inconsistent use of --rev might give unexpected '
3149 b'revision ordering!\n'
3149 b'revision ordering!\n'
3150 )
3150 )
3151 )
3151 )
3152
3152
3153 revs = list(revs)
3153 revs = list(revs)
3154 revs.extend(opts.get('rev'))
3154 revs.extend(opts.get('rev'))
3155 # a dict of data to be stored in state file
3155 # a dict of data to be stored in state file
3156 statedata = {}
3156 statedata = {}
3157 # list of new nodes created by ongoing graft
3157 # list of new nodes created by ongoing graft
3158 statedata[b'newnodes'] = []
3158 statedata[b'newnodes'] = []
3159
3159
3160 cmdutil.resolve_commit_options(ui, opts)
3160 cmdutil.resolve_commit_options(ui, opts)
3161
3161
3162 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3162 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3163
3163
3164 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3164 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3165
3165
3166 cont = False
3166 cont = False
3167 if opts.get('no_commit'):
3167 if opts.get('no_commit'):
3168 cmdutil.check_incompatible_arguments(
3168 cmdutil.check_incompatible_arguments(
3169 opts,
3169 opts,
3170 'no_commit',
3170 'no_commit',
3171 ['edit', 'currentuser', 'currentdate', 'log'],
3171 ['edit', 'currentuser', 'currentdate', 'log'],
3172 )
3172 )
3173
3173
3174 graftstate = statemod.cmdstate(repo, b'graftstate')
3174 graftstate = statemod.cmdstate(repo, b'graftstate')
3175
3175
3176 if opts.get('stop'):
3176 if opts.get('stop'):
3177 cmdutil.check_incompatible_arguments(
3177 cmdutil.check_incompatible_arguments(
3178 opts,
3178 opts,
3179 'stop',
3179 'stop',
3180 [
3180 [
3181 'edit',
3181 'edit',
3182 'log',
3182 'log',
3183 'user',
3183 'user',
3184 'date',
3184 'date',
3185 'currentdate',
3185 'currentdate',
3186 'currentuser',
3186 'currentuser',
3187 'rev',
3187 'rev',
3188 ],
3188 ],
3189 )
3189 )
3190 return _stopgraft(ui, repo, graftstate)
3190 return _stopgraft(ui, repo, graftstate)
3191 elif opts.get('abort'):
3191 elif opts.get('abort'):
3192 cmdutil.check_incompatible_arguments(
3192 cmdutil.check_incompatible_arguments(
3193 opts,
3193 opts,
3194 'abort',
3194 'abort',
3195 [
3195 [
3196 'edit',
3196 'edit',
3197 'log',
3197 'log',
3198 'user',
3198 'user',
3199 'date',
3199 'date',
3200 'currentdate',
3200 'currentdate',
3201 'currentuser',
3201 'currentuser',
3202 'rev',
3202 'rev',
3203 ],
3203 ],
3204 )
3204 )
3205 return cmdutil.abortgraft(ui, repo, graftstate)
3205 return cmdutil.abortgraft(ui, repo, graftstate)
3206 elif opts.get('continue'):
3206 elif opts.get('continue'):
3207 cont = True
3207 cont = True
3208 if revs:
3208 if revs:
3209 raise error.InputError(_(b"can't specify --continue and revisions"))
3209 raise error.InputError(_(b"can't specify --continue and revisions"))
3210 # read in unfinished revisions
3210 # read in unfinished revisions
3211 if graftstate.exists():
3211 if graftstate.exists():
3212 statedata = cmdutil.readgraftstate(repo, graftstate)
3212 statedata = cmdutil.readgraftstate(repo, graftstate)
3213 if statedata.get(b'date'):
3213 if statedata.get(b'date'):
3214 opts['date'] = statedata[b'date']
3214 opts['date'] = statedata[b'date']
3215 if statedata.get(b'user'):
3215 if statedata.get(b'user'):
3216 opts['user'] = statedata[b'user']
3216 opts['user'] = statedata[b'user']
3217 if statedata.get(b'log'):
3217 if statedata.get(b'log'):
3218 opts['log'] = True
3218 opts['log'] = True
3219 if statedata.get(b'no_commit'):
3219 if statedata.get(b'no_commit'):
3220 opts['no_commit'] = statedata.get(b'no_commit')
3220 opts['no_commit'] = statedata.get(b'no_commit')
3221 if statedata.get(b'base'):
3221 if statedata.get(b'base'):
3222 opts['base'] = statedata.get(b'base')
3222 opts['base'] = statedata.get(b'base')
3223 nodes = statedata[b'nodes']
3223 nodes = statedata[b'nodes']
3224 revs = [repo[node].rev() for node in nodes]
3224 revs = [repo[node].rev() for node in nodes]
3225 else:
3225 else:
3226 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3226 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3227 else:
3227 else:
3228 if not revs:
3228 if not revs:
3229 raise error.InputError(_(b'no revisions specified'))
3229 raise error.InputError(_(b'no revisions specified'))
3230 cmdutil.checkunfinished(repo)
3230 cmdutil.checkunfinished(repo)
3231 cmdutil.bailifchanged(repo)
3231 cmdutil.bailifchanged(repo)
3232 revs = logcmdutil.revrange(repo, revs)
3232 revs = logcmdutil.revrange(repo, revs)
3233
3233
3234 skipped = set()
3234 skipped = set()
3235 basectx = None
3235 basectx = None
3236 if opts.get('base'):
3236 if opts.get('base'):
3237 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3237 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3238 if basectx is None:
3238 if basectx is None:
3239 # check for merges
3239 # check for merges
3240 for rev in repo.revs(b'%ld and merge()', revs):
3240 for rev in repo.revs(b'%ld and merge()', revs):
3241 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3241 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3242 skipped.add(rev)
3242 skipped.add(rev)
3243 revs = [r for r in revs if r not in skipped]
3243 revs = [r for r in revs if r not in skipped]
3244 if not revs:
3244 if not revs:
3245 return -1
3245 return -1
3246 if basectx is not None and len(revs) != 1:
3246 if basectx is not None and len(revs) != 1:
3247 raise error.InputError(_(b'only one revision allowed with --base '))
3247 raise error.InputError(_(b'only one revision allowed with --base '))
3248
3248
3249 # Don't check in the --continue case, in effect retaining --force across
3249 # Don't check in the --continue case, in effect retaining --force across
3250 # --continues. That's because without --force, any revisions we decided to
3250 # --continues. That's because without --force, any revisions we decided to
3251 # skip would have been filtered out here, so they wouldn't have made their
3251 # skip would have been filtered out here, so they wouldn't have made their
3252 # way to the graftstate. With --force, any revisions we would have otherwise
3252 # way to the graftstate. With --force, any revisions we would have otherwise
3253 # skipped would not have been filtered out, and if they hadn't been applied
3253 # skipped would not have been filtered out, and if they hadn't been applied
3254 # already, they'd have been in the graftstate.
3254 # already, they'd have been in the graftstate.
3255 if not (cont or opts.get('force')) and basectx is None:
3255 if not (cont or opts.get('force')) and basectx is None:
3256 # check for ancestors of dest branch
3256 # check for ancestors of dest branch
3257 ancestors = repo.revs(b'%ld & (::.)', revs)
3257 ancestors = repo.revs(b'%ld & (::.)', revs)
3258 for rev in ancestors:
3258 for rev in ancestors:
3259 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3259 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3260
3260
3261 revs = [r for r in revs if r not in ancestors]
3261 revs = [r for r in revs if r not in ancestors]
3262
3262
3263 if not revs:
3263 if not revs:
3264 return -1
3264 return -1
3265
3265
3266 # analyze revs for earlier grafts
3266 # analyze revs for earlier grafts
3267 ids = {}
3267 ids = {}
3268 for ctx in repo.set(b"%ld", revs):
3268 for ctx in repo.set(b"%ld", revs):
3269 ids[ctx.hex()] = ctx.rev()
3269 ids[ctx.hex()] = ctx.rev()
3270 n = ctx.extra().get(b'source')
3270 n = ctx.extra().get(b'source')
3271 if n:
3271 if n:
3272 ids[n] = ctx.rev()
3272 ids[n] = ctx.rev()
3273
3273
3274 # check ancestors for earlier grafts
3274 # check ancestors for earlier grafts
3275 ui.debug(b'scanning for duplicate grafts\n')
3275 ui.debug(b'scanning for duplicate grafts\n')
3276
3276
3277 # The only changesets we can be sure doesn't contain grafts of any
3277 # The only changesets we can be sure doesn't contain grafts of any
3278 # revs, are the ones that are common ancestors of *all* revs:
3278 # revs, are the ones that are common ancestors of *all* revs:
3279 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3279 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3280 ctx = repo[rev]
3280 ctx = repo[rev]
3281 n = ctx.extra().get(b'source')
3281 n = ctx.extra().get(b'source')
3282 if n in ids:
3282 if n in ids:
3283 try:
3283 try:
3284 r = repo[n].rev()
3284 r = repo[n].rev()
3285 except error.RepoLookupError:
3285 except error.RepoLookupError:
3286 r = None
3286 r = None
3287 if r in revs:
3287 if r in revs:
3288 ui.warn(
3288 ui.warn(
3289 _(
3289 _(
3290 b'skipping revision %d:%s '
3290 b'skipping revision %d:%s '
3291 b'(already grafted to %d:%s)\n'
3291 b'(already grafted to %d:%s)\n'
3292 )
3292 )
3293 % (r, repo[r], rev, ctx)
3293 % (r, repo[r], rev, ctx)
3294 )
3294 )
3295 revs.remove(r)
3295 revs.remove(r)
3296 elif ids[n] in revs:
3296 elif ids[n] in revs:
3297 if r is None:
3297 if r is None:
3298 ui.warn(
3298 ui.warn(
3299 _(
3299 _(
3300 b'skipping already grafted revision %d:%s '
3300 b'skipping already grafted revision %d:%s '
3301 b'(%d:%s also has unknown origin %s)\n'
3301 b'(%d:%s also has unknown origin %s)\n'
3302 )
3302 )
3303 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3303 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3304 )
3304 )
3305 else:
3305 else:
3306 ui.warn(
3306 ui.warn(
3307 _(
3307 _(
3308 b'skipping already grafted revision %d:%s '
3308 b'skipping already grafted revision %d:%s '
3309 b'(%d:%s also has origin %d:%s)\n'
3309 b'(%d:%s also has origin %d:%s)\n'
3310 )
3310 )
3311 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3311 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3312 )
3312 )
3313 revs.remove(ids[n])
3313 revs.remove(ids[n])
3314 elif ctx.hex() in ids:
3314 elif ctx.hex() in ids:
3315 r = ids[ctx.hex()]
3315 r = ids[ctx.hex()]
3316 if r in revs:
3316 if r in revs:
3317 ui.warn(
3317 ui.warn(
3318 _(
3318 _(
3319 b'skipping already grafted revision %d:%s '
3319 b'skipping already grafted revision %d:%s '
3320 b'(was grafted from %d:%s)\n'
3320 b'(was grafted from %d:%s)\n'
3321 )
3321 )
3322 % (r, repo[r], rev, ctx)
3322 % (r, repo[r], rev, ctx)
3323 )
3323 )
3324 revs.remove(r)
3324 revs.remove(r)
3325 if not revs:
3325 if not revs:
3326 return -1
3326 return -1
3327
3327
3328 if opts.get('no_commit'):
3328 if opts.get('no_commit'):
3329 statedata[b'no_commit'] = True
3329 statedata[b'no_commit'] = True
3330 if opts.get('base'):
3330 if opts.get('base'):
3331 statedata[b'base'] = opts['base']
3331 statedata[b'base'] = opts['base']
3332 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3332 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3333 desc = b'%d:%s "%s"' % (
3333 desc = b'%d:%s "%s"' % (
3334 ctx.rev(),
3334 ctx.rev(),
3335 ctx,
3335 ctx,
3336 ctx.description().split(b'\n', 1)[0],
3336 ctx.description().split(b'\n', 1)[0],
3337 )
3337 )
3338 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3338 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3339 if names:
3339 if names:
3340 desc += b' (%s)' % b' '.join(names)
3340 desc += b' (%s)' % b' '.join(names)
3341 ui.status(_(b'grafting %s\n') % desc)
3341 ui.status(_(b'grafting %s\n') % desc)
3342 if opts.get('dry_run'):
3342 if opts.get('dry_run'):
3343 continue
3343 continue
3344
3344
3345 source = ctx.extra().get(b'source')
3345 source = ctx.extra().get(b'source')
3346 extra = {}
3346 extra = {}
3347 if source:
3347 if source:
3348 extra[b'source'] = source
3348 extra[b'source'] = source
3349 extra[b'intermediate-source'] = ctx.hex()
3349 extra[b'intermediate-source'] = ctx.hex()
3350 else:
3350 else:
3351 extra[b'source'] = ctx.hex()
3351 extra[b'source'] = ctx.hex()
3352 user = ctx.user()
3352 user = ctx.user()
3353 if opts.get('user'):
3353 if opts.get('user'):
3354 user = opts['user']
3354 user = opts['user']
3355 statedata[b'user'] = user
3355 statedata[b'user'] = user
3356 date = ctx.date()
3356 date = ctx.date()
3357 if opts.get('date'):
3357 if opts.get('date'):
3358 date = opts['date']
3358 date = opts['date']
3359 statedata[b'date'] = date
3359 statedata[b'date'] = date
3360 message = ctx.description()
3360 message = ctx.description()
3361 if opts.get('log'):
3361 if opts.get('log'):
3362 message += b'\n(grafted from %s)' % ctx.hex()
3362 message += b'\n(grafted from %s)' % ctx.hex()
3363 statedata[b'log'] = True
3363 statedata[b'log'] = True
3364
3364
3365 # we don't merge the first commit when continuing
3365 # we don't merge the first commit when continuing
3366 if not cont:
3366 if not cont:
3367 # perform the graft merge with p1(rev) as 'ancestor'
3367 # perform the graft merge with p1(rev) as 'ancestor'
3368 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3368 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3369 base = ctx.p1() if basectx is None else basectx
3369 base = ctx.p1() if basectx is None else basectx
3370 with ui.configoverride(overrides, b'graft'):
3370 with ui.configoverride(overrides, b'graft'):
3371 stats = mergemod.graft(
3371 stats = mergemod.graft(
3372 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3372 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3373 )
3373 )
3374 # report any conflicts
3374 # report any conflicts
3375 if stats.unresolvedcount > 0:
3375 if stats.unresolvedcount > 0:
3376 # write out state for --continue
3376 # write out state for --continue
3377 nodes = [repo[rev].hex() for rev in revs[pos:]]
3377 nodes = [repo[rev].hex() for rev in revs[pos:]]
3378 statedata[b'nodes'] = nodes
3378 statedata[b'nodes'] = nodes
3379 stateversion = 1
3379 stateversion = 1
3380 graftstate.save(stateversion, statedata)
3380 graftstate.save(stateversion, statedata)
3381 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3381 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3382 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3382 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3383 return 1
3383 return 1
3384 else:
3384 else:
3385 cont = False
3385 cont = False
3386
3386
3387 # commit if --no-commit is false
3387 # commit if --no-commit is false
3388 if not opts.get('no_commit'):
3388 if not opts.get('no_commit'):
3389 node = repo.commit(
3389 node = repo.commit(
3390 text=message, user=user, date=date, extra=extra, editor=editor
3390 text=message, user=user, date=date, extra=extra, editor=editor
3391 )
3391 )
3392 if node is None:
3392 if node is None:
3393 ui.warn(
3393 ui.warn(
3394 _(b'note: graft of %d:%s created no changes to commit\n')
3394 _(b'note: graft of %d:%s created no changes to commit\n')
3395 % (ctx.rev(), ctx)
3395 % (ctx.rev(), ctx)
3396 )
3396 )
3397 # checking that newnodes exist because old state files won't have it
3397 # checking that newnodes exist because old state files won't have it
3398 elif statedata.get(b'newnodes') is not None:
3398 elif statedata.get(b'newnodes') is not None:
3399 nn = statedata[b'newnodes']
3399 nn = statedata[b'newnodes']
3400 assert isinstance(nn, list) # list of bytes
3400 assert isinstance(nn, list) # list of bytes
3401 nn.append(node)
3401 nn.append(node)
3402
3402
3403 # remove state when we complete successfully
3403 # remove state when we complete successfully
3404 if not opts.get('dry_run'):
3404 if not opts.get('dry_run'):
3405 graftstate.delete()
3405 graftstate.delete()
3406
3406
3407 return 0
3407 return 0
3408
3408
3409
3409
3410 def _stopgraft(ui, repo, graftstate):
3410 def _stopgraft(ui, repo, graftstate):
3411 """stop the interrupted graft"""
3411 """stop the interrupted graft"""
3412 if not graftstate.exists():
3412 if not graftstate.exists():
3413 raise error.StateError(_(b"no interrupted graft found"))
3413 raise error.StateError(_(b"no interrupted graft found"))
3414 pctx = repo[b'.']
3414 pctx = repo[b'.']
3415 mergemod.clean_update(pctx)
3415 mergemod.clean_update(pctx)
3416 graftstate.delete()
3416 graftstate.delete()
3417 ui.status(_(b"stopped the interrupted graft\n"))
3417 ui.status(_(b"stopped the interrupted graft\n"))
3418 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3418 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3419 return 0
3419 return 0
3420
3420
3421
3421
3422 statemod.addunfinished(
3422 statemod.addunfinished(
3423 b'graft',
3423 b'graft',
3424 fname=b'graftstate',
3424 fname=b'graftstate',
3425 clearable=True,
3425 clearable=True,
3426 stopflag=True,
3426 stopflag=True,
3427 continueflag=True,
3427 continueflag=True,
3428 abortfunc=cmdutil.hgabortgraft,
3428 abortfunc=cmdutil.hgabortgraft,
3429 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3429 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3430 )
3430 )
3431
3431
3432
3432
3433 @command(
3433 @command(
3434 b'grep',
3434 b'grep',
3435 [
3435 [
3436 (b'0', b'print0', None, _(b'end fields with NUL')),
3436 (b'0', b'print0', None, _(b'end fields with NUL')),
3437 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3437 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3438 (
3438 (
3439 b'',
3439 b'',
3440 b'diff',
3440 b'diff',
3441 None,
3441 None,
3442 _(
3442 _(
3443 b'search revision differences for when the pattern was added '
3443 b'search revision differences for when the pattern was added '
3444 b'or removed'
3444 b'or removed'
3445 ),
3445 ),
3446 ),
3446 ),
3447 (b'a', b'text', None, _(b'treat all files as text')),
3447 (b'a', b'text', None, _(b'treat all files as text')),
3448 (
3448 (
3449 b'f',
3449 b'f',
3450 b'follow',
3450 b'follow',
3451 None,
3451 None,
3452 _(
3452 _(
3453 b'follow changeset history,'
3453 b'follow changeset history,'
3454 b' or file history across copies and renames'
3454 b' or file history across copies and renames'
3455 ),
3455 ),
3456 ),
3456 ),
3457 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3457 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3458 (
3458 (
3459 b'l',
3459 b'l',
3460 b'files-with-matches',
3460 b'files-with-matches',
3461 None,
3461 None,
3462 _(b'print only filenames and revisions that match'),
3462 _(b'print only filenames and revisions that match'),
3463 ),
3463 ),
3464 (b'n', b'line-number', None, _(b'print matching line numbers')),
3464 (b'n', b'line-number', None, _(b'print matching line numbers')),
3465 (
3465 (
3466 b'r',
3466 b'r',
3467 b'rev',
3467 b'rev',
3468 [],
3468 [],
3469 _(b'search files changed within revision range'),
3469 _(b'search files changed within revision range'),
3470 _(b'REV'),
3470 _(b'REV'),
3471 ),
3471 ),
3472 (
3472 (
3473 b'',
3473 b'',
3474 b'all-files',
3474 b'all-files',
3475 None,
3475 None,
3476 _(
3476 _(
3477 b'include all files in the changeset while grepping (DEPRECATED)'
3477 b'include all files in the changeset while grepping (DEPRECATED)'
3478 ),
3478 ),
3479 ),
3479 ),
3480 (b'u', b'user', None, _(b'list the author (long with -v)')),
3480 (b'u', b'user', None, _(b'list the author (long with -v)')),
3481 (b'd', b'date', None, _(b'list the date (short with -q)')),
3481 (b'd', b'date', None, _(b'list the date (short with -q)')),
3482 ]
3482 ]
3483 + formatteropts
3483 + formatteropts
3484 + walkopts,
3484 + walkopts,
3485 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3485 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3486 helpcategory=command.CATEGORY_FILE_CONTENTS,
3486 helpcategory=command.CATEGORY_FILE_CONTENTS,
3487 inferrepo=True,
3487 inferrepo=True,
3488 intents={INTENT_READONLY},
3488 intents={INTENT_READONLY},
3489 )
3489 )
3490 def grep(ui, repo, pattern, *pats, **opts):
3490 def grep(ui, repo, pattern, *pats, **opts):
3491 """search for a pattern in specified files
3491 """search for a pattern in specified files
3492
3492
3493 Search the working directory or revision history for a regular
3493 Search the working directory or revision history for a regular
3494 expression in the specified files for the entire repository.
3494 expression in the specified files for the entire repository.
3495
3495
3496 By default, grep searches the repository files in the working
3496 By default, grep searches the repository files in the working
3497 directory and prints the files where it finds a match. To specify
3497 directory and prints the files where it finds a match. To specify
3498 historical revisions instead of the working directory, use the
3498 historical revisions instead of the working directory, use the
3499 --rev flag.
3499 --rev flag.
3500
3500
3501 To search instead historical revision differences that contains a
3501 To search instead historical revision differences that contains a
3502 change in match status ("-" for a match that becomes a non-match,
3502 change in match status ("-" for a match that becomes a non-match,
3503 or "+" for a non-match that becomes a match), use the --diff flag.
3503 or "+" for a non-match that becomes a match), use the --diff flag.
3504
3504
3505 PATTERN can be any Python (roughly Perl-compatible) regular
3505 PATTERN can be any Python (roughly Perl-compatible) regular
3506 expression.
3506 expression.
3507
3507
3508 If no FILEs are specified and the --rev flag isn't supplied, all
3508 If no FILEs are specified and the --rev flag isn't supplied, all
3509 files in the working directory are searched. When using the --rev
3509 files in the working directory are searched. When using the --rev
3510 flag and specifying FILEs, use the --follow argument to also
3510 flag and specifying FILEs, use the --follow argument to also
3511 follow the specified FILEs across renames and copies.
3511 follow the specified FILEs across renames and copies.
3512
3512
3513 .. container:: verbose
3513 .. container:: verbose
3514
3514
3515 Template:
3515 Template:
3516
3516
3517 The following keywords are supported in addition to the common template
3517 The following keywords are supported in addition to the common template
3518 keywords and functions. See also :hg:`help templates`.
3518 keywords and functions. See also :hg:`help templates`.
3519
3519
3520 :change: String. Character denoting insertion ``+`` or removal ``-``.
3520 :change: String. Character denoting insertion ``+`` or removal ``-``.
3521 Available if ``--diff`` is specified.
3521 Available if ``--diff`` is specified.
3522 :lineno: Integer. Line number of the match.
3522 :lineno: Integer. Line number of the match.
3523 :path: String. Repository-absolute path of the file.
3523 :path: String. Repository-absolute path of the file.
3524 :texts: List of text chunks.
3524 :texts: List of text chunks.
3525
3525
3526 And each entry of ``{texts}`` provides the following sub-keywords.
3526 And each entry of ``{texts}`` provides the following sub-keywords.
3527
3527
3528 :matched: Boolean. True if the chunk matches the specified pattern.
3528 :matched: Boolean. True if the chunk matches the specified pattern.
3529 :text: String. Chunk content.
3529 :text: String. Chunk content.
3530
3530
3531 See :hg:`help templates.operators` for the list expansion syntax.
3531 See :hg:`help templates.operators` for the list expansion syntax.
3532
3532
3533 Returns 0 if a match is found, 1 otherwise.
3533 Returns 0 if a match is found, 1 otherwise.
3534
3534
3535 """
3535 """
3536 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3536 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3537
3537
3538 diff = opts.get('all') or opts.get('diff')
3538 diff = opts.get('all') or opts.get('diff')
3539 follow = opts.get('follow')
3539 follow = opts.get('follow')
3540 if opts.get('all_files') is None and not diff:
3540 if opts.get('all_files') is None and not diff:
3541 opts['all_files'] = True
3541 opts['all_files'] = True
3542 plaingrep = (
3542 plaingrep = (
3543 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3543 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3544 )
3544 )
3545 all_files = opts.get('all_files')
3545 all_files = opts.get('all_files')
3546 if plaingrep:
3546 if plaingrep:
3547 opts['rev'] = [b'wdir()']
3547 opts['rev'] = [b'wdir()']
3548
3548
3549 reflags = re.M
3549 reflags = re.M
3550 if opts.get('ignore_case'):
3550 if opts.get('ignore_case'):
3551 reflags |= re.I
3551 reflags |= re.I
3552 try:
3552 try:
3553 regexp = util.re.compile(pattern, reflags)
3553 regexp = util.re.compile(pattern, reflags)
3554 except re.error as inst:
3554 except re.error as inst:
3555 ui.warn(
3555 ui.warn(
3556 _(b"grep: invalid match pattern: %s\n")
3556 _(b"grep: invalid match pattern: %s\n")
3557 % stringutil.forcebytestr(inst)
3557 % stringutil.forcebytestr(inst)
3558 )
3558 )
3559 return 1
3559 return 1
3560 sep, eol = b':', b'\n'
3560 sep, eol = b':', b'\n'
3561 if opts.get('print0'):
3561 if opts.get('print0'):
3562 sep = eol = b'\0'
3562 sep = eol = b'\0'
3563
3563
3564 searcher = grepmod.grepsearcher(
3564 searcher = grepmod.grepsearcher(
3565 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3565 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3566 )
3566 )
3567
3567
3568 getfile = searcher._getfile
3568 getfile = searcher._getfile
3569
3569
3570 uipathfn = scmutil.getuipathfn(repo)
3570 uipathfn = scmutil.getuipathfn(repo)
3571
3571
3572 def display(fm, fn, ctx, pstates, states):
3572 def display(fm, fn, ctx, pstates, states):
3573 rev = scmutil.intrev(ctx)
3573 rev = scmutil.intrev(ctx)
3574 if fm.isplain():
3574 if fm.isplain():
3575 formatuser = ui.shortuser
3575 formatuser = ui.shortuser
3576 else:
3576 else:
3577 formatuser = pycompat.bytestr
3577 formatuser = pycompat.bytestr
3578 if ui.quiet:
3578 if ui.quiet:
3579 datefmt = b'%Y-%m-%d'
3579 datefmt = b'%Y-%m-%d'
3580 else:
3580 else:
3581 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3581 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3582 found = False
3582 found = False
3583
3583
3584 @util.cachefunc
3584 @util.cachefunc
3585 def binary():
3585 def binary():
3586 flog = getfile(fn)
3586 flog = getfile(fn)
3587 try:
3587 try:
3588 return stringutil.binary(flog.read(ctx.filenode(fn)))
3588 return stringutil.binary(flog.read(ctx.filenode(fn)))
3589 except error.WdirUnsupported:
3589 except error.WdirUnsupported:
3590 return ctx[fn].isbinary()
3590 return ctx[fn].isbinary()
3591
3591
3592 fieldnamemap = {b'linenumber': b'lineno'}
3592 fieldnamemap = {b'linenumber': b'lineno'}
3593 if diff:
3593 if diff:
3594 iter = grepmod.difflinestates(pstates, states)
3594 iter = grepmod.difflinestates(pstates, states)
3595 else:
3595 else:
3596 iter = [(b'', l) for l in states]
3596 iter = [(b'', l) for l in states]
3597 for change, l in iter:
3597 for change, l in iter:
3598 fm.startitem()
3598 fm.startitem()
3599 fm.context(ctx=ctx)
3599 fm.context(ctx=ctx)
3600 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3600 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3601 fm.plain(uipathfn(fn), label=b'grep.filename')
3601 fm.plain(uipathfn(fn), label=b'grep.filename')
3602
3602
3603 cols = [
3603 cols = [
3604 (b'rev', b'%d', rev, not plaingrep, b''),
3604 (b'rev', b'%d', rev, not plaingrep, b''),
3605 (
3605 (
3606 b'linenumber',
3606 b'linenumber',
3607 b'%d',
3607 b'%d',
3608 l.linenum,
3608 l.linenum,
3609 opts.get('line_number'),
3609 opts.get('line_number'),
3610 b'',
3610 b'',
3611 ),
3611 ),
3612 ]
3612 ]
3613 if diff:
3613 if diff:
3614 cols.append(
3614 cols.append(
3615 (
3615 (
3616 b'change',
3616 b'change',
3617 b'%s',
3617 b'%s',
3618 change,
3618 change,
3619 True,
3619 True,
3620 b'grep.inserted '
3620 b'grep.inserted '
3621 if change == b'+'
3621 if change == b'+'
3622 else b'grep.deleted ',
3622 else b'grep.deleted ',
3623 )
3623 )
3624 )
3624 )
3625 cols.extend(
3625 cols.extend(
3626 [
3626 [
3627 (
3627 (
3628 b'user',
3628 b'user',
3629 b'%s',
3629 b'%s',
3630 formatuser(ctx.user()),
3630 formatuser(ctx.user()),
3631 opts.get('user'),
3631 opts.get('user'),
3632 b'',
3632 b'',
3633 ),
3633 ),
3634 (
3634 (
3635 b'date',
3635 b'date',
3636 b'%s',
3636 b'%s',
3637 fm.formatdate(ctx.date(), datefmt),
3637 fm.formatdate(ctx.date(), datefmt),
3638 opts.get('date'),
3638 opts.get('date'),
3639 b'',
3639 b'',
3640 ),
3640 ),
3641 ]
3641 ]
3642 )
3642 )
3643 for name, fmt, data, cond, extra_label in cols:
3643 for name, fmt, data, cond, extra_label in cols:
3644 if cond:
3644 if cond:
3645 fm.plain(sep, label=b'grep.sep')
3645 fm.plain(sep, label=b'grep.sep')
3646 field = fieldnamemap.get(name, name)
3646 field = fieldnamemap.get(name, name)
3647 label = extra_label + (b'grep.%s' % name)
3647 label = extra_label + (b'grep.%s' % name)
3648 fm.condwrite(cond, field, fmt, data, label=label)
3648 fm.condwrite(cond, field, fmt, data, label=label)
3649 if not opts.get('files_with_matches'):
3649 if not opts.get('files_with_matches'):
3650 fm.plain(sep, label=b'grep.sep')
3650 fm.plain(sep, label=b'grep.sep')
3651 if not opts.get('text') and binary():
3651 if not opts.get('text') and binary():
3652 fm.plain(_(b" Binary file matches"))
3652 fm.plain(_(b" Binary file matches"))
3653 else:
3653 else:
3654 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3654 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3655 fm.plain(eol)
3655 fm.plain(eol)
3656 found = True
3656 found = True
3657 if opts.get('files_with_matches'):
3657 if opts.get('files_with_matches'):
3658 break
3658 break
3659 return found
3659 return found
3660
3660
3661 def displaymatches(fm, l):
3661 def displaymatches(fm, l):
3662 p = 0
3662 p = 0
3663 for s, e in l.findpos(regexp):
3663 for s, e in l.findpos(regexp):
3664 if p < s:
3664 if p < s:
3665 fm.startitem()
3665 fm.startitem()
3666 fm.write(b'text', b'%s', l.line[p:s])
3666 fm.write(b'text', b'%s', l.line[p:s])
3667 fm.data(matched=False)
3667 fm.data(matched=False)
3668 fm.startitem()
3668 fm.startitem()
3669 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3669 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3670 fm.data(matched=True)
3670 fm.data(matched=True)
3671 p = e
3671 p = e
3672 if p < len(l.line):
3672 if p < len(l.line):
3673 fm.startitem()
3673 fm.startitem()
3674 fm.write(b'text', b'%s', l.line[p:])
3674 fm.write(b'text', b'%s', l.line[p:])
3675 fm.data(matched=False)
3675 fm.data(matched=False)
3676 fm.end()
3676 fm.end()
3677
3677
3678 found = False
3678 found = False
3679
3679
3680 wopts = logcmdutil.walkopts(
3680 wopts = logcmdutil.walkopts(
3681 pats=pats,
3681 pats=pats,
3682 opts=opts,
3682 opts=pycompat.byteskwargs(opts),
3683 revspec=opts['rev'],
3683 revspec=opts['rev'],
3684 include_pats=opts['include'],
3684 include_pats=opts['include'],
3685 exclude_pats=opts['exclude'],
3685 exclude_pats=opts['exclude'],
3686 follow=follow,
3686 follow=follow,
3687 force_changelog_traversal=all_files,
3687 force_changelog_traversal=all_files,
3688 filter_revisions_by_pats=not all_files,
3688 filter_revisions_by_pats=not all_files,
3689 )
3689 )
3690 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3690 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3691
3691
3692 ui.pager(b'grep')
3692 ui.pager(b'grep')
3693 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3693 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3694 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3694 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3695 r = display(fm, fn, ctx, pstates, states)
3695 r = display(fm, fn, ctx, pstates, states)
3696 found = found or r
3696 found = found or r
3697 if r and not diff and not all_files:
3697 if r and not diff and not all_files:
3698 searcher.skipfile(fn, ctx.rev())
3698 searcher.skipfile(fn, ctx.rev())
3699 fm.end()
3699 fm.end()
3700
3700
3701 return not found
3701 return not found
3702
3702
3703
3703
3704 @command(
3704 @command(
3705 b'heads',
3705 b'heads',
3706 [
3706 [
3707 (
3707 (
3708 b'r',
3708 b'r',
3709 b'rev',
3709 b'rev',
3710 b'',
3710 b'',
3711 _(b'show only heads which are descendants of STARTREV'),
3711 _(b'show only heads which are descendants of STARTREV'),
3712 _(b'STARTREV'),
3712 _(b'STARTREV'),
3713 ),
3713 ),
3714 (b't', b'topo', False, _(b'show topological heads only')),
3714 (b't', b'topo', False, _(b'show topological heads only')),
3715 (
3715 (
3716 b'a',
3716 b'a',
3717 b'active',
3717 b'active',
3718 False,
3718 False,
3719 _(b'show active branchheads only (DEPRECATED)'),
3719 _(b'show active branchheads only (DEPRECATED)'),
3720 ),
3720 ),
3721 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3721 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3722 ]
3722 ]
3723 + templateopts,
3723 + templateopts,
3724 _(b'[-ct] [-r STARTREV] [REV]...'),
3724 _(b'[-ct] [-r STARTREV] [REV]...'),
3725 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3725 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3726 intents={INTENT_READONLY},
3726 intents={INTENT_READONLY},
3727 )
3727 )
3728 def heads(ui, repo, *branchrevs, **opts):
3728 def heads(ui, repo, *branchrevs, **opts):
3729 """show branch heads
3729 """show branch heads
3730
3730
3731 With no arguments, show all open branch heads in the repository.
3731 With no arguments, show all open branch heads in the repository.
3732 Branch heads are changesets that have no descendants on the
3732 Branch heads are changesets that have no descendants on the
3733 same branch. They are where development generally takes place and
3733 same branch. They are where development generally takes place and
3734 are the usual targets for update and merge operations.
3734 are the usual targets for update and merge operations.
3735
3735
3736 If one or more REVs are given, only open branch heads on the
3736 If one or more REVs are given, only open branch heads on the
3737 branches associated with the specified changesets are shown. This
3737 branches associated with the specified changesets are shown. This
3738 means that you can use :hg:`heads .` to see the heads on the
3738 means that you can use :hg:`heads .` to see the heads on the
3739 currently checked-out branch.
3739 currently checked-out branch.
3740
3740
3741 If -c/--closed is specified, also show branch heads marked closed
3741 If -c/--closed is specified, also show branch heads marked closed
3742 (see :hg:`commit --close-branch`).
3742 (see :hg:`commit --close-branch`).
3743
3743
3744 If STARTREV is specified, only those heads that are descendants of
3744 If STARTREV is specified, only those heads that are descendants of
3745 STARTREV will be displayed.
3745 STARTREV will be displayed.
3746
3746
3747 If -t/--topo is specified, named branch mechanics will be ignored and only
3747 If -t/--topo is specified, named branch mechanics will be ignored and only
3748 topological heads (changesets with no children) will be shown.
3748 topological heads (changesets with no children) will be shown.
3749
3749
3750 Returns 0 if matching heads are found, 1 if not.
3750 Returns 0 if matching heads are found, 1 if not.
3751 """
3751 """
3752
3752
3753 start = None
3753 start = None
3754 rev = opts.get('rev')
3754 rev = opts.get('rev')
3755 if rev:
3755 if rev:
3756 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3756 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3757 start = logcmdutil.revsingle(repo, rev, None).node()
3757 start = logcmdutil.revsingle(repo, rev, None).node()
3758
3758
3759 if opts.get('topo'):
3759 if opts.get('topo'):
3760 heads = [repo[h] for h in repo.heads(start)]
3760 heads = [repo[h] for h in repo.heads(start)]
3761 else:
3761 else:
3762 heads = []
3762 heads = []
3763 for branch in repo.branchmap():
3763 for branch in repo.branchmap():
3764 heads += repo.branchheads(branch, start, opts.get('closed'))
3764 heads += repo.branchheads(branch, start, opts.get('closed'))
3765 heads = [repo[h] for h in heads]
3765 heads = [repo[h] for h in heads]
3766
3766
3767 if branchrevs:
3767 if branchrevs:
3768 branches = {
3768 branches = {
3769 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3769 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3770 }
3770 }
3771 heads = [h for h in heads if h.branch() in branches]
3771 heads = [h for h in heads if h.branch() in branches]
3772
3772
3773 if opts.get('active') and branchrevs:
3773 if opts.get('active') and branchrevs:
3774 dagheads = repo.heads(start)
3774 dagheads = repo.heads(start)
3775 heads = [h for h in heads if h.node() in dagheads]
3775 heads = [h for h in heads if h.node() in dagheads]
3776
3776
3777 if branchrevs:
3777 if branchrevs:
3778 haveheads = {h.branch() for h in heads}
3778 haveheads = {h.branch() for h in heads}
3779 if branches - haveheads:
3779 if branches - haveheads:
3780 headless = b', '.join(b for b in branches - haveheads)
3780 headless = b', '.join(b for b in branches - haveheads)
3781 msg = _(b'no open branch heads found on branches %s')
3781 msg = _(b'no open branch heads found on branches %s')
3782 if opts.get('rev'):
3782 if opts.get('rev'):
3783 msg += _(b' (started at %s)') % opts['rev']
3783 msg += _(b' (started at %s)') % opts['rev']
3784 ui.warn((msg + b'\n') % headless)
3784 ui.warn((msg + b'\n') % headless)
3785
3785
3786 if not heads:
3786 if not heads:
3787 return 1
3787 return 1
3788
3788
3789 ui.pager(b'heads')
3789 ui.pager(b'heads')
3790 heads = sorted(heads, key=lambda x: -(x.rev()))
3790 heads = sorted(heads, key=lambda x: -(x.rev()))
3791 displayer = logcmdutil.changesetdisplayer(
3791 displayer = logcmdutil.changesetdisplayer(
3792 ui, repo, pycompat.byteskwargs(opts)
3792 ui, repo, pycompat.byteskwargs(opts)
3793 )
3793 )
3794 for ctx in heads:
3794 for ctx in heads:
3795 displayer.show(ctx)
3795 displayer.show(ctx)
3796 displayer.close()
3796 displayer.close()
3797
3797
3798
3798
3799 @command(
3799 @command(
3800 b'help',
3800 b'help',
3801 [
3801 [
3802 (b'e', b'extension', None, _(b'show only help for extensions')),
3802 (b'e', b'extension', None, _(b'show only help for extensions')),
3803 (b'c', b'command', None, _(b'show only help for commands')),
3803 (b'c', b'command', None, _(b'show only help for commands')),
3804 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3804 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3805 (
3805 (
3806 b's',
3806 b's',
3807 b'system',
3807 b'system',
3808 [],
3808 [],
3809 _(b'show help for specific platform(s)'),
3809 _(b'show help for specific platform(s)'),
3810 _(b'PLATFORM'),
3810 _(b'PLATFORM'),
3811 ),
3811 ),
3812 ],
3812 ],
3813 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3813 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3814 helpcategory=command.CATEGORY_HELP,
3814 helpcategory=command.CATEGORY_HELP,
3815 norepo=True,
3815 norepo=True,
3816 intents={INTENT_READONLY},
3816 intents={INTENT_READONLY},
3817 )
3817 )
3818 def help_(ui, name=None, **opts):
3818 def help_(ui, name=None, **opts):
3819 """show help for a given topic or a help overview
3819 """show help for a given topic or a help overview
3820
3820
3821 With no arguments, print a list of commands with short help messages.
3821 With no arguments, print a list of commands with short help messages.
3822
3822
3823 Given a topic, extension, or command name, print help for that
3823 Given a topic, extension, or command name, print help for that
3824 topic.
3824 topic.
3825
3825
3826 Returns 0 if successful.
3826 Returns 0 if successful.
3827 """
3827 """
3828
3828
3829 keep = opts.get('system') or []
3829 keep = opts.get('system') or []
3830 if len(keep) == 0:
3830 if len(keep) == 0:
3831 if pycompat.sysplatform.startswith(b'win'):
3831 if pycompat.sysplatform.startswith(b'win'):
3832 keep.append(b'windows')
3832 keep.append(b'windows')
3833 elif pycompat.sysplatform == b'OpenVMS':
3833 elif pycompat.sysplatform == b'OpenVMS':
3834 keep.append(b'vms')
3834 keep.append(b'vms')
3835 elif pycompat.sysplatform == b'plan9':
3835 elif pycompat.sysplatform == b'plan9':
3836 keep.append(b'plan9')
3836 keep.append(b'plan9')
3837 else:
3837 else:
3838 keep.append(b'unix')
3838 keep.append(b'unix')
3839 keep.append(pycompat.sysplatform.lower())
3839 keep.append(pycompat.sysplatform.lower())
3840 if ui.verbose:
3840 if ui.verbose:
3841 keep.append(b'verbose')
3841 keep.append(b'verbose')
3842
3842
3843 commands = sys.modules[__name__]
3843 commands = sys.modules[__name__]
3844 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3844 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3845 ui.pager(b'help')
3845 ui.pager(b'help')
3846 ui.write(formatted)
3846 ui.write(formatted)
3847
3847
3848
3848
3849 @command(
3849 @command(
3850 b'identify|id',
3850 b'identify|id',
3851 [
3851 [
3852 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3852 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3853 (b'n', b'num', None, _(b'show local revision number')),
3853 (b'n', b'num', None, _(b'show local revision number')),
3854 (b'i', b'id', None, _(b'show global revision id')),
3854 (b'i', b'id', None, _(b'show global revision id')),
3855 (b'b', b'branch', None, _(b'show branch')),
3855 (b'b', b'branch', None, _(b'show branch')),
3856 (b't', b'tags', None, _(b'show tags')),
3856 (b't', b'tags', None, _(b'show tags')),
3857 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3857 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3858 ]
3858 ]
3859 + remoteopts
3859 + remoteopts
3860 + formatteropts,
3860 + formatteropts,
3861 _(b'[-nibtB] [-r REV] [SOURCE]'),
3861 _(b'[-nibtB] [-r REV] [SOURCE]'),
3862 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3862 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3863 optionalrepo=True,
3863 optionalrepo=True,
3864 intents={INTENT_READONLY},
3864 intents={INTENT_READONLY},
3865 )
3865 )
3866 def identify(
3866 def identify(
3867 ui,
3867 ui,
3868 repo,
3868 repo,
3869 source=None,
3869 source=None,
3870 rev=None,
3870 rev=None,
3871 num=None,
3871 num=None,
3872 id=None,
3872 id=None,
3873 branch=None,
3873 branch=None,
3874 tags=None,
3874 tags=None,
3875 bookmarks=None,
3875 bookmarks=None,
3876 **opts
3876 **opts
3877 ):
3877 ):
3878 """identify the working directory or specified revision
3878 """identify the working directory or specified revision
3879
3879
3880 Print a summary identifying the repository state at REV using one or
3880 Print a summary identifying the repository state at REV using one or
3881 two parent hash identifiers, followed by a "+" if the working
3881 two parent hash identifiers, followed by a "+" if the working
3882 directory has uncommitted changes, the branch name (if not default),
3882 directory has uncommitted changes, the branch name (if not default),
3883 a list of tags, and a list of bookmarks.
3883 a list of tags, and a list of bookmarks.
3884
3884
3885 When REV is not given, print a summary of the current state of the
3885 When REV is not given, print a summary of the current state of the
3886 repository including the working directory. Specify -r. to get information
3886 repository including the working directory. Specify -r. to get information
3887 of the working directory parent without scanning uncommitted changes.
3887 of the working directory parent without scanning uncommitted changes.
3888
3888
3889 Specifying a path to a repository root or Mercurial bundle will
3889 Specifying a path to a repository root or Mercurial bundle will
3890 cause lookup to operate on that repository/bundle.
3890 cause lookup to operate on that repository/bundle.
3891
3891
3892 .. container:: verbose
3892 .. container:: verbose
3893
3893
3894 Template:
3894 Template:
3895
3895
3896 The following keywords are supported in addition to the common template
3896 The following keywords are supported in addition to the common template
3897 keywords and functions. See also :hg:`help templates`.
3897 keywords and functions. See also :hg:`help templates`.
3898
3898
3899 :dirty: String. Character ``+`` denoting if the working directory has
3899 :dirty: String. Character ``+`` denoting if the working directory has
3900 uncommitted changes.
3900 uncommitted changes.
3901 :id: String. One or two nodes, optionally followed by ``+``.
3901 :id: String. One or two nodes, optionally followed by ``+``.
3902 :parents: List of strings. Parent nodes of the changeset.
3902 :parents: List of strings. Parent nodes of the changeset.
3903
3903
3904 Examples:
3904 Examples:
3905
3905
3906 - generate a build identifier for the working directory::
3906 - generate a build identifier for the working directory::
3907
3907
3908 hg id --id > build-id.dat
3908 hg id --id > build-id.dat
3909
3909
3910 - find the revision corresponding to a tag::
3910 - find the revision corresponding to a tag::
3911
3911
3912 hg id -n -r 1.3
3912 hg id -n -r 1.3
3913
3913
3914 - check the most recent revision of a remote repository::
3914 - check the most recent revision of a remote repository::
3915
3915
3916 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3916 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3917
3917
3918 See :hg:`log` for generating more information about specific revisions,
3918 See :hg:`log` for generating more information about specific revisions,
3919 including full hash identifiers.
3919 including full hash identifiers.
3920
3920
3921 Returns 0 if successful.
3921 Returns 0 if successful.
3922 """
3922 """
3923
3923
3924 opts = pycompat.byteskwargs(opts)
3924 opts = pycompat.byteskwargs(opts)
3925 if not repo and not source:
3925 if not repo and not source:
3926 raise error.InputError(
3926 raise error.InputError(
3927 _(b"there is no Mercurial repository here (.hg not found)")
3927 _(b"there is no Mercurial repository here (.hg not found)")
3928 )
3928 )
3929
3929
3930 default = not (num or id or branch or tags or bookmarks)
3930 default = not (num or id or branch or tags or bookmarks)
3931 output = []
3931 output = []
3932 revs = []
3932 revs = []
3933
3933
3934 peer = None
3934 peer = None
3935 try:
3935 try:
3936 if source:
3936 if source:
3937 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3937 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3938 # only pass ui when no repo
3938 # only pass ui when no repo
3939 peer = hg.peer(repo or ui, opts, path)
3939 peer = hg.peer(repo or ui, opts, path)
3940 repo = peer.local()
3940 repo = peer.local()
3941 branches = (path.branch, [])
3941 branches = (path.branch, [])
3942 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3942 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3943
3943
3944 fm = ui.formatter(b'identify', opts)
3944 fm = ui.formatter(b'identify', opts)
3945 fm.startitem()
3945 fm.startitem()
3946
3946
3947 if not repo:
3947 if not repo:
3948 if num or branch or tags:
3948 if num or branch or tags:
3949 raise error.InputError(
3949 raise error.InputError(
3950 _(b"can't query remote revision number, branch, or tags")
3950 _(b"can't query remote revision number, branch, or tags")
3951 )
3951 )
3952 if not rev and revs:
3952 if not rev and revs:
3953 rev = revs[0]
3953 rev = revs[0]
3954 if not rev:
3954 if not rev:
3955 rev = b"tip"
3955 rev = b"tip"
3956
3956
3957 remoterev = peer.lookup(rev)
3957 remoterev = peer.lookup(rev)
3958 hexrev = fm.hexfunc(remoterev)
3958 hexrev = fm.hexfunc(remoterev)
3959 if default or id:
3959 if default or id:
3960 output = [hexrev]
3960 output = [hexrev]
3961 fm.data(id=hexrev)
3961 fm.data(id=hexrev)
3962
3962
3963 @util.cachefunc
3963 @util.cachefunc
3964 def getbms():
3964 def getbms():
3965 bms = []
3965 bms = []
3966
3966
3967 if b'bookmarks' in peer.listkeys(b'namespaces'):
3967 if b'bookmarks' in peer.listkeys(b'namespaces'):
3968 hexremoterev = hex(remoterev)
3968 hexremoterev = hex(remoterev)
3969 bms = [
3969 bms = [
3970 bm
3970 bm
3971 for bm, bmr in peer.listkeys(b'bookmarks').items()
3971 for bm, bmr in peer.listkeys(b'bookmarks').items()
3972 if bmr == hexremoterev
3972 if bmr == hexremoterev
3973 ]
3973 ]
3974
3974
3975 return sorted(bms)
3975 return sorted(bms)
3976
3976
3977 if fm.isplain():
3977 if fm.isplain():
3978 if bookmarks:
3978 if bookmarks:
3979 output.extend(getbms())
3979 output.extend(getbms())
3980 elif default and not ui.quiet:
3980 elif default and not ui.quiet:
3981 # multiple bookmarks for a single parent separated by '/'
3981 # multiple bookmarks for a single parent separated by '/'
3982 bm = b'/'.join(getbms())
3982 bm = b'/'.join(getbms())
3983 if bm:
3983 if bm:
3984 output.append(bm)
3984 output.append(bm)
3985 else:
3985 else:
3986 fm.data(node=hex(remoterev))
3986 fm.data(node=hex(remoterev))
3987 if bookmarks or b'bookmarks' in fm.datahint():
3987 if bookmarks or b'bookmarks' in fm.datahint():
3988 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3988 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3989 else:
3989 else:
3990 if rev:
3990 if rev:
3991 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3991 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3992 ctx = logcmdutil.revsingle(repo, rev, None)
3992 ctx = logcmdutil.revsingle(repo, rev, None)
3993
3993
3994 if ctx.rev() is None:
3994 if ctx.rev() is None:
3995 ctx = repo[None]
3995 ctx = repo[None]
3996 parents = ctx.parents()
3996 parents = ctx.parents()
3997 taglist = []
3997 taglist = []
3998 for p in parents:
3998 for p in parents:
3999 taglist.extend(p.tags())
3999 taglist.extend(p.tags())
4000
4000
4001 dirty = b""
4001 dirty = b""
4002 if ctx.dirty(missing=True, merge=False, branch=False):
4002 if ctx.dirty(missing=True, merge=False, branch=False):
4003 dirty = b'+'
4003 dirty = b'+'
4004 fm.data(dirty=dirty)
4004 fm.data(dirty=dirty)
4005
4005
4006 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4006 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4007 if default or id:
4007 if default or id:
4008 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4008 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4009 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4009 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4010
4010
4011 if num:
4011 if num:
4012 numoutput = [b"%d" % p.rev() for p in parents]
4012 numoutput = [b"%d" % p.rev() for p in parents]
4013 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4013 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4014
4014
4015 fm.data(
4015 fm.data(
4016 parents=fm.formatlist(
4016 parents=fm.formatlist(
4017 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4017 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4018 )
4018 )
4019 )
4019 )
4020 else:
4020 else:
4021 hexoutput = fm.hexfunc(ctx.node())
4021 hexoutput = fm.hexfunc(ctx.node())
4022 if default or id:
4022 if default or id:
4023 output = [hexoutput]
4023 output = [hexoutput]
4024 fm.data(id=hexoutput)
4024 fm.data(id=hexoutput)
4025
4025
4026 if num:
4026 if num:
4027 output.append(pycompat.bytestr(ctx.rev()))
4027 output.append(pycompat.bytestr(ctx.rev()))
4028 taglist = ctx.tags()
4028 taglist = ctx.tags()
4029
4029
4030 if default and not ui.quiet:
4030 if default and not ui.quiet:
4031 b = ctx.branch()
4031 b = ctx.branch()
4032 if b != b'default':
4032 if b != b'default':
4033 output.append(b"(%s)" % b)
4033 output.append(b"(%s)" % b)
4034
4034
4035 # multiple tags for a single parent separated by '/'
4035 # multiple tags for a single parent separated by '/'
4036 t = b'/'.join(taglist)
4036 t = b'/'.join(taglist)
4037 if t:
4037 if t:
4038 output.append(t)
4038 output.append(t)
4039
4039
4040 # multiple bookmarks for a single parent separated by '/'
4040 # multiple bookmarks for a single parent separated by '/'
4041 bm = b'/'.join(ctx.bookmarks())
4041 bm = b'/'.join(ctx.bookmarks())
4042 if bm:
4042 if bm:
4043 output.append(bm)
4043 output.append(bm)
4044 else:
4044 else:
4045 if branch:
4045 if branch:
4046 output.append(ctx.branch())
4046 output.append(ctx.branch())
4047
4047
4048 if tags:
4048 if tags:
4049 output.extend(taglist)
4049 output.extend(taglist)
4050
4050
4051 if bookmarks:
4051 if bookmarks:
4052 output.extend(ctx.bookmarks())
4052 output.extend(ctx.bookmarks())
4053
4053
4054 fm.data(node=ctx.hex())
4054 fm.data(node=ctx.hex())
4055 fm.data(branch=ctx.branch())
4055 fm.data(branch=ctx.branch())
4056 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4056 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4057 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4057 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4058 fm.context(ctx=ctx)
4058 fm.context(ctx=ctx)
4059
4059
4060 fm.plain(b"%s\n" % b' '.join(output))
4060 fm.plain(b"%s\n" % b' '.join(output))
4061 fm.end()
4061 fm.end()
4062 finally:
4062 finally:
4063 if peer:
4063 if peer:
4064 peer.close()
4064 peer.close()
4065
4065
4066
4066
4067 @command(
4067 @command(
4068 b'import|patch',
4068 b'import|patch',
4069 [
4069 [
4070 (
4070 (
4071 b'p',
4071 b'p',
4072 b'strip',
4072 b'strip',
4073 1,
4073 1,
4074 _(
4074 _(
4075 b'directory strip option for patch. This has the same '
4075 b'directory strip option for patch. This has the same '
4076 b'meaning as the corresponding patch option'
4076 b'meaning as the corresponding patch option'
4077 ),
4077 ),
4078 _(b'NUM'),
4078 _(b'NUM'),
4079 ),
4079 ),
4080 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4080 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4081 (b'', b'secret', None, _(b'use the secret phase for committing')),
4081 (b'', b'secret', None, _(b'use the secret phase for committing')),
4082 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4082 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4083 (
4083 (
4084 b'f',
4084 b'f',
4085 b'force',
4085 b'force',
4086 None,
4086 None,
4087 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4087 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4088 ),
4088 ),
4089 (
4089 (
4090 b'',
4090 b'',
4091 b'no-commit',
4091 b'no-commit',
4092 None,
4092 None,
4093 _(b"don't commit, just update the working directory"),
4093 _(b"don't commit, just update the working directory"),
4094 ),
4094 ),
4095 (
4095 (
4096 b'',
4096 b'',
4097 b'bypass',
4097 b'bypass',
4098 None,
4098 None,
4099 _(b"apply patch without touching the working directory"),
4099 _(b"apply patch without touching the working directory"),
4100 ),
4100 ),
4101 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4101 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4102 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4102 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4103 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4103 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4104 (
4104 (
4105 b'',
4105 b'',
4106 b'import-branch',
4106 b'import-branch',
4107 None,
4107 None,
4108 _(b'use any branch information in patch (implied by --exact)'),
4108 _(b'use any branch information in patch (implied by --exact)'),
4109 ),
4109 ),
4110 ]
4110 ]
4111 + commitopts
4111 + commitopts
4112 + commitopts2
4112 + commitopts2
4113 + similarityopts,
4113 + similarityopts,
4114 _(b'[OPTION]... PATCH...'),
4114 _(b'[OPTION]... PATCH...'),
4115 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4115 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4116 )
4116 )
4117 def import_(ui, repo, patch1=None, *patches, **opts):
4117 def import_(ui, repo, patch1=None, *patches, **opts):
4118 """import an ordered set of patches
4118 """import an ordered set of patches
4119
4119
4120 Import a list of patches and commit them individually (unless
4120 Import a list of patches and commit them individually (unless
4121 --no-commit is specified).
4121 --no-commit is specified).
4122
4122
4123 To read a patch from standard input (stdin), use "-" as the patch
4123 To read a patch from standard input (stdin), use "-" as the patch
4124 name. If a URL is specified, the patch will be downloaded from
4124 name. If a URL is specified, the patch will be downloaded from
4125 there.
4125 there.
4126
4126
4127 Import first applies changes to the working directory (unless
4127 Import first applies changes to the working directory (unless
4128 --bypass is specified), import will abort if there are outstanding
4128 --bypass is specified), import will abort if there are outstanding
4129 changes.
4129 changes.
4130
4130
4131 Use --bypass to apply and commit patches directly to the
4131 Use --bypass to apply and commit patches directly to the
4132 repository, without affecting the working directory. Without
4132 repository, without affecting the working directory. Without
4133 --exact, patches will be applied on top of the working directory
4133 --exact, patches will be applied on top of the working directory
4134 parent revision.
4134 parent revision.
4135
4135
4136 You can import a patch straight from a mail message. Even patches
4136 You can import a patch straight from a mail message. Even patches
4137 as attachments work (to use the body part, it must have type
4137 as attachments work (to use the body part, it must have type
4138 text/plain or text/x-patch). From and Subject headers of email
4138 text/plain or text/x-patch). From and Subject headers of email
4139 message are used as default committer and commit message. All
4139 message are used as default committer and commit message. All
4140 text/plain body parts before first diff are added to the commit
4140 text/plain body parts before first diff are added to the commit
4141 message.
4141 message.
4142
4142
4143 If the imported patch was generated by :hg:`export`, user and
4143 If the imported patch was generated by :hg:`export`, user and
4144 description from patch override values from message headers and
4144 description from patch override values from message headers and
4145 body. Values given on command line with -m/--message and -u/--user
4145 body. Values given on command line with -m/--message and -u/--user
4146 override these.
4146 override these.
4147
4147
4148 If --exact is specified, import will set the working directory to
4148 If --exact is specified, import will set the working directory to
4149 the parent of each patch before applying it, and will abort if the
4149 the parent of each patch before applying it, and will abort if the
4150 resulting changeset has a different ID than the one recorded in
4150 resulting changeset has a different ID than the one recorded in
4151 the patch. This will guard against various ways that portable
4151 the patch. This will guard against various ways that portable
4152 patch formats and mail systems might fail to transfer Mercurial
4152 patch formats and mail systems might fail to transfer Mercurial
4153 data or metadata. See :hg:`bundle` for lossless transmission.
4153 data or metadata. See :hg:`bundle` for lossless transmission.
4154
4154
4155 Use --partial to ensure a changeset will be created from the patch
4155 Use --partial to ensure a changeset will be created from the patch
4156 even if some hunks fail to apply. Hunks that fail to apply will be
4156 even if some hunks fail to apply. Hunks that fail to apply will be
4157 written to a <target-file>.rej file. Conflicts can then be resolved
4157 written to a <target-file>.rej file. Conflicts can then be resolved
4158 by hand before :hg:`commit --amend` is run to update the created
4158 by hand before :hg:`commit --amend` is run to update the created
4159 changeset. This flag exists to let people import patches that
4159 changeset. This flag exists to let people import patches that
4160 partially apply without losing the associated metadata (author,
4160 partially apply without losing the associated metadata (author,
4161 date, description, ...).
4161 date, description, ...).
4162
4162
4163 .. note::
4163 .. note::
4164
4164
4165 When no hunks apply cleanly, :hg:`import --partial` will create
4165 When no hunks apply cleanly, :hg:`import --partial` will create
4166 an empty changeset, importing only the patch metadata.
4166 an empty changeset, importing only the patch metadata.
4167
4167
4168 With -s/--similarity, hg will attempt to discover renames and
4168 With -s/--similarity, hg will attempt to discover renames and
4169 copies in the patch in the same way as :hg:`addremove`.
4169 copies in the patch in the same way as :hg:`addremove`.
4170
4170
4171 It is possible to use external patch programs to perform the patch
4171 It is possible to use external patch programs to perform the patch
4172 by setting the ``ui.patch`` configuration option. For the default
4172 by setting the ``ui.patch`` configuration option. For the default
4173 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4173 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4174 See :hg:`help config` for more information about configuration
4174 See :hg:`help config` for more information about configuration
4175 files and how to use these options.
4175 files and how to use these options.
4176
4176
4177 See :hg:`help dates` for a list of formats valid for -d/--date.
4177 See :hg:`help dates` for a list of formats valid for -d/--date.
4178
4178
4179 .. container:: verbose
4179 .. container:: verbose
4180
4180
4181 Examples:
4181 Examples:
4182
4182
4183 - import a traditional patch from a website and detect renames::
4183 - import a traditional patch from a website and detect renames::
4184
4184
4185 hg import -s 80 http://example.com/bugfix.patch
4185 hg import -s 80 http://example.com/bugfix.patch
4186
4186
4187 - import a changeset from an hgweb server::
4187 - import a changeset from an hgweb server::
4188
4188
4189 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4189 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4190
4190
4191 - import all the patches in an Unix-style mbox::
4191 - import all the patches in an Unix-style mbox::
4192
4192
4193 hg import incoming-patches.mbox
4193 hg import incoming-patches.mbox
4194
4194
4195 - import patches from stdin::
4195 - import patches from stdin::
4196
4196
4197 hg import -
4197 hg import -
4198
4198
4199 - attempt to exactly restore an exported changeset (not always
4199 - attempt to exactly restore an exported changeset (not always
4200 possible)::
4200 possible)::
4201
4201
4202 hg import --exact proposed-fix.patch
4202 hg import --exact proposed-fix.patch
4203
4203
4204 - use an external tool to apply a patch which is too fuzzy for
4204 - use an external tool to apply a patch which is too fuzzy for
4205 the default internal tool.
4205 the default internal tool.
4206
4206
4207 hg import --config ui.patch="patch --merge" fuzzy.patch
4207 hg import --config ui.patch="patch --merge" fuzzy.patch
4208
4208
4209 - change the default fuzzing from 2 to a less strict 7
4209 - change the default fuzzing from 2 to a less strict 7
4210
4210
4211 hg import --config ui.fuzz=7 fuzz.patch
4211 hg import --config ui.fuzz=7 fuzz.patch
4212
4212
4213 Returns 0 on success, 1 on partial success (see --partial).
4213 Returns 0 on success, 1 on partial success (see --partial).
4214 """
4214 """
4215
4215
4216 cmdutil.check_incompatible_arguments(
4216 cmdutil.check_incompatible_arguments(
4217 opts, 'no_commit', ['bypass', 'secret']
4217 opts, 'no_commit', ['bypass', 'secret']
4218 )
4218 )
4219 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4219 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4220
4220
4221 if not patch1:
4221 if not patch1:
4222 raise error.InputError(_(b'need at least one patch to import'))
4222 raise error.InputError(_(b'need at least one patch to import'))
4223
4223
4224 patches = (patch1,) + patches
4224 patches = (patch1,) + patches
4225
4225
4226 date = opts.get('date')
4226 date = opts.get('date')
4227 if date:
4227 if date:
4228 opts['date'] = dateutil.parsedate(date)
4228 opts['date'] = dateutil.parsedate(date)
4229
4229
4230 exact = opts.get('exact')
4230 exact = opts.get('exact')
4231 update = not opts.get('bypass')
4231 update = not opts.get('bypass')
4232 try:
4232 try:
4233 sim = float(opts.get('similarity') or 0)
4233 sim = float(opts.get('similarity') or 0)
4234 except ValueError:
4234 except ValueError:
4235 raise error.InputError(_(b'similarity must be a number'))
4235 raise error.InputError(_(b'similarity must be a number'))
4236 if sim < 0 or sim > 100:
4236 if sim < 0 or sim > 100:
4237 raise error.InputError(_(b'similarity must be between 0 and 100'))
4237 raise error.InputError(_(b'similarity must be between 0 and 100'))
4238 if sim and not update:
4238 if sim and not update:
4239 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4239 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4240
4240
4241 base = opts["base"]
4241 base = opts["base"]
4242 msgs = []
4242 msgs = []
4243 ret = 0
4243 ret = 0
4244
4244
4245 with repo.wlock():
4245 with repo.wlock():
4246 if update:
4246 if update:
4247 cmdutil.checkunfinished(repo)
4247 cmdutil.checkunfinished(repo)
4248 if exact or not opts.get('force'):
4248 if exact or not opts.get('force'):
4249 cmdutil.bailifchanged(repo)
4249 cmdutil.bailifchanged(repo)
4250
4250
4251 if not opts.get('no_commit'):
4251 if not opts.get('no_commit'):
4252 lock = repo.lock
4252 lock = repo.lock
4253 tr = lambda: repo.transaction(b'import')
4253 tr = lambda: repo.transaction(b'import')
4254 else:
4254 else:
4255 lock = util.nullcontextmanager
4255 lock = util.nullcontextmanager
4256 tr = util.nullcontextmanager
4256 tr = util.nullcontextmanager
4257 with lock(), tr():
4257 with lock(), tr():
4258 parents = repo[None].parents()
4258 parents = repo[None].parents()
4259 for patchurl in patches:
4259 for patchurl in patches:
4260 if patchurl == b'-':
4260 if patchurl == b'-':
4261 ui.status(_(b'applying patch from stdin\n'))
4261 ui.status(_(b'applying patch from stdin\n'))
4262 patchfile = ui.fin
4262 patchfile = ui.fin
4263 patchurl = b'stdin' # for error message
4263 patchurl = b'stdin' # for error message
4264 else:
4264 else:
4265 patchurl = os.path.join(base, patchurl)
4265 patchurl = os.path.join(base, patchurl)
4266 ui.status(_(b'applying %s\n') % patchurl)
4266 ui.status(_(b'applying %s\n') % patchurl)
4267 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4267 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4268
4268
4269 haspatch = False
4269 haspatch = False
4270 for hunk in patch.split(patchfile):
4270 for hunk in patch.split(patchfile):
4271 with patch.extract(ui, hunk) as patchdata:
4271 with patch.extract(ui, hunk) as patchdata:
4272 msg, node, rej = cmdutil.tryimportone(
4272 msg, node, rej = cmdutil.tryimportone(
4273 ui,
4273 ui,
4274 repo,
4274 repo,
4275 patchdata,
4275 patchdata,
4276 parents,
4276 parents,
4277 pycompat.byteskwargs(opts),
4277 pycompat.byteskwargs(opts),
4278 msgs,
4278 msgs,
4279 hg.clean,
4279 hg.clean,
4280 )
4280 )
4281 if msg:
4281 if msg:
4282 haspatch = True
4282 haspatch = True
4283 ui.note(msg + b'\n')
4283 ui.note(msg + b'\n')
4284 if update or exact:
4284 if update or exact:
4285 parents = repo[None].parents()
4285 parents = repo[None].parents()
4286 else:
4286 else:
4287 parents = [repo[node]]
4287 parents = [repo[node]]
4288 if rej:
4288 if rej:
4289 ui.write_err(_(b"patch applied partially\n"))
4289 ui.write_err(_(b"patch applied partially\n"))
4290 ui.write_err(
4290 ui.write_err(
4291 _(
4291 _(
4292 b"(fix the .rej files and run "
4292 b"(fix the .rej files and run "
4293 b"`hg commit --amend`)\n"
4293 b"`hg commit --amend`)\n"
4294 )
4294 )
4295 )
4295 )
4296 ret = 1
4296 ret = 1
4297 break
4297 break
4298
4298
4299 if not haspatch:
4299 if not haspatch:
4300 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4300 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4301
4301
4302 if msgs:
4302 if msgs:
4303 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4303 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4304 return ret
4304 return ret
4305
4305
4306
4306
4307 @command(
4307 @command(
4308 b'incoming|in',
4308 b'incoming|in',
4309 [
4309 [
4310 (
4310 (
4311 b'f',
4311 b'f',
4312 b'force',
4312 b'force',
4313 None,
4313 None,
4314 _(b'run even if remote repository is unrelated'),
4314 _(b'run even if remote repository is unrelated'),
4315 ),
4315 ),
4316 (b'n', b'newest-first', None, _(b'show newest record first')),
4316 (b'n', b'newest-first', None, _(b'show newest record first')),
4317 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4317 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4318 (
4318 (
4319 b'r',
4319 b'r',
4320 b'rev',
4320 b'rev',
4321 [],
4321 [],
4322 _(b'a remote changeset intended to be added'),
4322 _(b'a remote changeset intended to be added'),
4323 _(b'REV'),
4323 _(b'REV'),
4324 ),
4324 ),
4325 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4325 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4326 (
4326 (
4327 b'b',
4327 b'b',
4328 b'branch',
4328 b'branch',
4329 [],
4329 [],
4330 _(b'a specific branch you would like to pull'),
4330 _(b'a specific branch you would like to pull'),
4331 _(b'BRANCH'),
4331 _(b'BRANCH'),
4332 ),
4332 ),
4333 ]
4333 ]
4334 + logopts
4334 + logopts
4335 + remoteopts
4335 + remoteopts
4336 + subrepoopts,
4336 + subrepoopts,
4337 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4337 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4338 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4338 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4339 )
4339 )
4340 def incoming(ui, repo, source=b"default", **opts):
4340 def incoming(ui, repo, source=b"default", **opts):
4341 """show new changesets found in source
4341 """show new changesets found in source
4342
4342
4343 Show new changesets found in the specified path/URL or the default
4343 Show new changesets found in the specified path/URL or the default
4344 pull location. These are the changesets that would have been pulled
4344 pull location. These are the changesets that would have been pulled
4345 by :hg:`pull` at the time you issued this command.
4345 by :hg:`pull` at the time you issued this command.
4346
4346
4347 See pull for valid source format details.
4347 See pull for valid source format details.
4348
4348
4349 .. container:: verbose
4349 .. container:: verbose
4350
4350
4351 With -B/--bookmarks, the result of bookmark comparison between
4351 With -B/--bookmarks, the result of bookmark comparison between
4352 local and remote repositories is displayed. With -v/--verbose,
4352 local and remote repositories is displayed. With -v/--verbose,
4353 status is also displayed for each bookmark like below::
4353 status is also displayed for each bookmark like below::
4354
4354
4355 BM1 01234567890a added
4355 BM1 01234567890a added
4356 BM2 1234567890ab advanced
4356 BM2 1234567890ab advanced
4357 BM3 234567890abc diverged
4357 BM3 234567890abc diverged
4358 BM4 34567890abcd changed
4358 BM4 34567890abcd changed
4359
4359
4360 The action taken locally when pulling depends on the
4360 The action taken locally when pulling depends on the
4361 status of each bookmark:
4361 status of each bookmark:
4362
4362
4363 :``added``: pull will create it
4363 :``added``: pull will create it
4364 :``advanced``: pull will update it
4364 :``advanced``: pull will update it
4365 :``diverged``: pull will create a divergent bookmark
4365 :``diverged``: pull will create a divergent bookmark
4366 :``changed``: result depends on remote changesets
4366 :``changed``: result depends on remote changesets
4367
4367
4368 From the point of view of pulling behavior, bookmark
4368 From the point of view of pulling behavior, bookmark
4369 existing only in the remote repository are treated as ``added``,
4369 existing only in the remote repository are treated as ``added``,
4370 even if it is in fact locally deleted.
4370 even if it is in fact locally deleted.
4371
4371
4372 .. container:: verbose
4372 .. container:: verbose
4373
4373
4374 For remote repository, using --bundle avoids downloading the
4374 For remote repository, using --bundle avoids downloading the
4375 changesets twice if the incoming is followed by a pull.
4375 changesets twice if the incoming is followed by a pull.
4376
4376
4377 Examples:
4377 Examples:
4378
4378
4379 - show incoming changes with patches and full description::
4379 - show incoming changes with patches and full description::
4380
4380
4381 hg incoming -vp
4381 hg incoming -vp
4382
4382
4383 - show incoming changes excluding merges, store a bundle::
4383 - show incoming changes excluding merges, store a bundle::
4384
4384
4385 hg in -vpM --bundle incoming.hg
4385 hg in -vpM --bundle incoming.hg
4386 hg pull incoming.hg
4386 hg pull incoming.hg
4387
4387
4388 - briefly list changes inside a bundle::
4388 - briefly list changes inside a bundle::
4389
4389
4390 hg in changes.hg -T "{desc|firstline}\\n"
4390 hg in changes.hg -T "{desc|firstline}\\n"
4391
4391
4392 Returns 0 if there are incoming changes, 1 otherwise.
4392 Returns 0 if there are incoming changes, 1 otherwise.
4393 """
4393 """
4394 opts = pycompat.byteskwargs(opts)
4394 opts = pycompat.byteskwargs(opts)
4395 if opts.get(b'graph'):
4395 if opts.get(b'graph'):
4396 logcmdutil.checkunsupportedgraphflags([], opts)
4396 logcmdutil.checkunsupportedgraphflags([], opts)
4397
4397
4398 def display(other, chlist, displayer):
4398 def display(other, chlist, displayer):
4399 revdag = logcmdutil.graphrevs(other, chlist, opts)
4399 revdag = logcmdutil.graphrevs(other, chlist, opts)
4400 logcmdutil.displaygraph(
4400 logcmdutil.displaygraph(
4401 ui, repo, revdag, displayer, graphmod.asciiedges
4401 ui, repo, revdag, displayer, graphmod.asciiedges
4402 )
4402 )
4403
4403
4404 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4404 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4405 return 0
4405 return 0
4406
4406
4407 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4407 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4408
4408
4409 if opts.get(b'bookmarks'):
4409 if opts.get(b'bookmarks'):
4410 srcs = urlutil.get_pull_paths(repo, ui, [source])
4410 srcs = urlutil.get_pull_paths(repo, ui, [source])
4411 for path in srcs:
4411 for path in srcs:
4412 # XXX the "branches" options are not used. Should it be used?
4412 # XXX the "branches" options are not used. Should it be used?
4413 other = hg.peer(repo, opts, path)
4413 other = hg.peer(repo, opts, path)
4414 try:
4414 try:
4415 if b'bookmarks' not in other.listkeys(b'namespaces'):
4415 if b'bookmarks' not in other.listkeys(b'namespaces'):
4416 ui.warn(_(b"remote doesn't support bookmarks\n"))
4416 ui.warn(_(b"remote doesn't support bookmarks\n"))
4417 return 0
4417 return 0
4418 ui.pager(b'incoming')
4418 ui.pager(b'incoming')
4419 ui.status(
4419 ui.status(
4420 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4420 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4421 )
4421 )
4422 return bookmarks.incoming(
4422 return bookmarks.incoming(
4423 ui, repo, other, mode=path.bookmarks_mode
4423 ui, repo, other, mode=path.bookmarks_mode
4424 )
4424 )
4425 finally:
4425 finally:
4426 other.close()
4426 other.close()
4427
4427
4428 return hg.incoming(ui, repo, source, opts)
4428 return hg.incoming(ui, repo, source, opts)
4429
4429
4430
4430
4431 @command(
4431 @command(
4432 b'init',
4432 b'init',
4433 remoteopts,
4433 remoteopts,
4434 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4434 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4435 helpcategory=command.CATEGORY_REPO_CREATION,
4435 helpcategory=command.CATEGORY_REPO_CREATION,
4436 helpbasic=True,
4436 helpbasic=True,
4437 norepo=True,
4437 norepo=True,
4438 )
4438 )
4439 def init(ui, dest=b".", **opts):
4439 def init(ui, dest=b".", **opts):
4440 """create a new repository in the given directory
4440 """create a new repository in the given directory
4441
4441
4442 Initialize a new repository in the given directory. If the given
4442 Initialize a new repository in the given directory. If the given
4443 directory does not exist, it will be created.
4443 directory does not exist, it will be created.
4444
4444
4445 If no directory is given, the current directory is used.
4445 If no directory is given, the current directory is used.
4446
4446
4447 It is possible to specify an ``ssh://`` URL as the destination.
4447 It is possible to specify an ``ssh://`` URL as the destination.
4448 See :hg:`help urls` for more information.
4448 See :hg:`help urls` for more information.
4449
4449
4450 Returns 0 on success.
4450 Returns 0 on success.
4451 """
4451 """
4452 opts = pycompat.byteskwargs(opts)
4452 opts = pycompat.byteskwargs(opts)
4453 path = urlutil.get_clone_path_obj(ui, dest)
4453 path = urlutil.get_clone_path_obj(ui, dest)
4454 peer = hg.peer(ui, opts, path, create=True)
4454 peer = hg.peer(ui, opts, path, create=True)
4455 peer.close()
4455 peer.close()
4456
4456
4457
4457
4458 @command(
4458 @command(
4459 b'locate',
4459 b'locate',
4460 [
4460 [
4461 (
4461 (
4462 b'r',
4462 b'r',
4463 b'rev',
4463 b'rev',
4464 b'',
4464 b'',
4465 _(b'search the repository as it is in REV'),
4465 _(b'search the repository as it is in REV'),
4466 _(b'REV'),
4466 _(b'REV'),
4467 ),
4467 ),
4468 (
4468 (
4469 b'0',
4469 b'0',
4470 b'print0',
4470 b'print0',
4471 None,
4471 None,
4472 _(b'end filenames with NUL, for use with xargs'),
4472 _(b'end filenames with NUL, for use with xargs'),
4473 ),
4473 ),
4474 (
4474 (
4475 b'f',
4475 b'f',
4476 b'fullpath',
4476 b'fullpath',
4477 None,
4477 None,
4478 _(b'print complete paths from the filesystem root'),
4478 _(b'print complete paths from the filesystem root'),
4479 ),
4479 ),
4480 ]
4480 ]
4481 + walkopts,
4481 + walkopts,
4482 _(b'[OPTION]... [PATTERN]...'),
4482 _(b'[OPTION]... [PATTERN]...'),
4483 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4483 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4484 )
4484 )
4485 def locate(ui, repo, *pats, **opts):
4485 def locate(ui, repo, *pats, **opts):
4486 """locate files matching specific patterns (DEPRECATED)
4486 """locate files matching specific patterns (DEPRECATED)
4487
4487
4488 Print files under Mercurial control in the working directory whose
4488 Print files under Mercurial control in the working directory whose
4489 names match the given patterns.
4489 names match the given patterns.
4490
4490
4491 By default, this command searches all directories in the working
4491 By default, this command searches all directories in the working
4492 directory. To search just the current directory and its
4492 directory. To search just the current directory and its
4493 subdirectories, use "--include .".
4493 subdirectories, use "--include .".
4494
4494
4495 If no patterns are given to match, this command prints the names
4495 If no patterns are given to match, this command prints the names
4496 of all files under Mercurial control in the working directory.
4496 of all files under Mercurial control in the working directory.
4497
4497
4498 If you want to feed the output of this command into the "xargs"
4498 If you want to feed the output of this command into the "xargs"
4499 command, use the -0 option to both this command and "xargs". This
4499 command, use the -0 option to both this command and "xargs". This
4500 will avoid the problem of "xargs" treating single filenames that
4500 will avoid the problem of "xargs" treating single filenames that
4501 contain whitespace as multiple filenames.
4501 contain whitespace as multiple filenames.
4502
4502
4503 See :hg:`help files` for a more versatile command.
4503 See :hg:`help files` for a more versatile command.
4504
4504
4505 Returns 0 if a match is found, 1 otherwise.
4505 Returns 0 if a match is found, 1 otherwise.
4506 """
4506 """
4507 if opts.get('print0'):
4507 if opts.get('print0'):
4508 end = b'\0'
4508 end = b'\0'
4509 else:
4509 else:
4510 end = b'\n'
4510 end = b'\n'
4511 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4511 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4512
4512
4513 ret = 1
4513 ret = 1
4514 m = scmutil.match(
4514 m = scmutil.match(
4515 ctx,
4515 ctx,
4516 pats,
4516 pats,
4517 pycompat.byteskwargs(opts),
4517 pycompat.byteskwargs(opts),
4518 default=b'relglob',
4518 default=b'relglob',
4519 badfn=lambda x, y: False,
4519 badfn=lambda x, y: False,
4520 )
4520 )
4521
4521
4522 ui.pager(b'locate')
4522 ui.pager(b'locate')
4523 if ctx.rev() is None:
4523 if ctx.rev() is None:
4524 # When run on the working copy, "locate" includes removed files, so
4524 # When run on the working copy, "locate" includes removed files, so
4525 # we get the list of files from the dirstate.
4525 # we get the list of files from the dirstate.
4526 filesgen = sorted(repo.dirstate.matches(m))
4526 filesgen = sorted(repo.dirstate.matches(m))
4527 else:
4527 else:
4528 filesgen = ctx.matches(m)
4528 filesgen = ctx.matches(m)
4529 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4529 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4530 for abs in filesgen:
4530 for abs in filesgen:
4531 if opts.get('fullpath'):
4531 if opts.get('fullpath'):
4532 ui.write(repo.wjoin(abs), end)
4532 ui.write(repo.wjoin(abs), end)
4533 else:
4533 else:
4534 ui.write(uipathfn(abs), end)
4534 ui.write(uipathfn(abs), end)
4535 ret = 0
4535 ret = 0
4536
4536
4537 return ret
4537 return ret
4538
4538
4539
4539
4540 @command(
4540 @command(
4541 b'log|history',
4541 b'log|history',
4542 [
4542 [
4543 (
4543 (
4544 b'f',
4544 b'f',
4545 b'follow',
4545 b'follow',
4546 None,
4546 None,
4547 _(
4547 _(
4548 b'follow changeset history, or file history across copies and renames'
4548 b'follow changeset history, or file history across copies and renames'
4549 ),
4549 ),
4550 ),
4550 ),
4551 (
4551 (
4552 b'',
4552 b'',
4553 b'follow-first',
4553 b'follow-first',
4554 None,
4554 None,
4555 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4555 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4556 ),
4556 ),
4557 (
4557 (
4558 b'd',
4558 b'd',
4559 b'date',
4559 b'date',
4560 b'',
4560 b'',
4561 _(b'show revisions matching date spec'),
4561 _(b'show revisions matching date spec'),
4562 _(b'DATE'),
4562 _(b'DATE'),
4563 ),
4563 ),
4564 (b'C', b'copies', None, _(b'show copied files')),
4564 (b'C', b'copies', None, _(b'show copied files')),
4565 (
4565 (
4566 b'k',
4566 b'k',
4567 b'keyword',
4567 b'keyword',
4568 [],
4568 [],
4569 _(b'do case-insensitive search for a given text'),
4569 _(b'do case-insensitive search for a given text'),
4570 _(b'TEXT'),
4570 _(b'TEXT'),
4571 ),
4571 ),
4572 (
4572 (
4573 b'r',
4573 b'r',
4574 b'rev',
4574 b'rev',
4575 [],
4575 [],
4576 _(b'revisions to select or follow from'),
4576 _(b'revisions to select or follow from'),
4577 _(b'REV'),
4577 _(b'REV'),
4578 ),
4578 ),
4579 (
4579 (
4580 b'L',
4580 b'L',
4581 b'line-range',
4581 b'line-range',
4582 [],
4582 [],
4583 _(b'follow line range of specified file (EXPERIMENTAL)'),
4583 _(b'follow line range of specified file (EXPERIMENTAL)'),
4584 _(b'FILE,RANGE'),
4584 _(b'FILE,RANGE'),
4585 ),
4585 ),
4586 (
4586 (
4587 b'',
4587 b'',
4588 b'removed',
4588 b'removed',
4589 None,
4589 None,
4590 _(b'include revisions where files were removed'),
4590 _(b'include revisions where files were removed'),
4591 ),
4591 ),
4592 (
4592 (
4593 b'm',
4593 b'm',
4594 b'only-merges',
4594 b'only-merges',
4595 None,
4595 None,
4596 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4596 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4597 ),
4597 ),
4598 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4598 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4599 (
4599 (
4600 b'',
4600 b'',
4601 b'only-branch',
4601 b'only-branch',
4602 [],
4602 [],
4603 _(
4603 _(
4604 b'show only changesets within the given named branch (DEPRECATED)'
4604 b'show only changesets within the given named branch (DEPRECATED)'
4605 ),
4605 ),
4606 _(b'BRANCH'),
4606 _(b'BRANCH'),
4607 ),
4607 ),
4608 (
4608 (
4609 b'b',
4609 b'b',
4610 b'branch',
4610 b'branch',
4611 [],
4611 [],
4612 _(b'show changesets within the given named branch'),
4612 _(b'show changesets within the given named branch'),
4613 _(b'BRANCH'),
4613 _(b'BRANCH'),
4614 ),
4614 ),
4615 (
4615 (
4616 b'B',
4616 b'B',
4617 b'bookmark',
4617 b'bookmark',
4618 [],
4618 [],
4619 _(b"show changesets within the given bookmark"),
4619 _(b"show changesets within the given bookmark"),
4620 _(b'BOOKMARK'),
4620 _(b'BOOKMARK'),
4621 ),
4621 ),
4622 (
4622 (
4623 b'P',
4623 b'P',
4624 b'prune',
4624 b'prune',
4625 [],
4625 [],
4626 _(b'do not display revision or any of its ancestors'),
4626 _(b'do not display revision or any of its ancestors'),
4627 _(b'REV'),
4627 _(b'REV'),
4628 ),
4628 ),
4629 ]
4629 ]
4630 + logopts
4630 + logopts
4631 + walkopts,
4631 + walkopts,
4632 _(b'[OPTION]... [FILE]'),
4632 _(b'[OPTION]... [FILE]'),
4633 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4633 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4634 helpbasic=True,
4634 helpbasic=True,
4635 inferrepo=True,
4635 inferrepo=True,
4636 intents={INTENT_READONLY},
4636 intents={INTENT_READONLY},
4637 )
4637 )
4638 def log(ui, repo, *pats, **opts):
4638 def log(ui, repo, *pats, **opts):
4639 """show revision history of entire repository or files
4639 """show revision history of entire repository or files
4640
4640
4641 Print the revision history of the specified files or the entire
4641 Print the revision history of the specified files or the entire
4642 project.
4642 project.
4643
4643
4644 If no revision range is specified, the default is ``tip:0`` unless
4644 If no revision range is specified, the default is ``tip:0`` unless
4645 --follow is set.
4645 --follow is set.
4646
4646
4647 File history is shown without following rename or copy history of
4647 File history is shown without following rename or copy history of
4648 files. Use -f/--follow with a filename to follow history across
4648 files. Use -f/--follow with a filename to follow history across
4649 renames and copies. --follow without a filename will only show
4649 renames and copies. --follow without a filename will only show
4650 ancestors of the starting revisions. The starting revisions can be
4650 ancestors of the starting revisions. The starting revisions can be
4651 specified by -r/--rev, which default to the working directory parent.
4651 specified by -r/--rev, which default to the working directory parent.
4652
4652
4653 By default this command prints revision number and changeset id,
4653 By default this command prints revision number and changeset id,
4654 tags, non-trivial parents, user, date and time, and a summary for
4654 tags, non-trivial parents, user, date and time, and a summary for
4655 each commit. When the -v/--verbose switch is used, the list of
4655 each commit. When the -v/--verbose switch is used, the list of
4656 changed files and full commit message are shown.
4656 changed files and full commit message are shown.
4657
4657
4658 With --graph the revisions are shown as an ASCII art DAG with the most
4658 With --graph the revisions are shown as an ASCII art DAG with the most
4659 recent changeset at the top.
4659 recent changeset at the top.
4660 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4660 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4661 involved in an unresolved merge conflict, '_' closes a branch,
4661 involved in an unresolved merge conflict, '_' closes a branch,
4662 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4662 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4663 changeset from the lines below is a parent of the 'o' merge on the same
4663 changeset from the lines below is a parent of the 'o' merge on the same
4664 line.
4664 line.
4665 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4665 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4666 of a '|' indicates one or more revisions in a path are omitted.
4666 of a '|' indicates one or more revisions in a path are omitted.
4667
4667
4668 .. container:: verbose
4668 .. container:: verbose
4669
4669
4670 Use -L/--line-range FILE,M:N options to follow the history of lines
4670 Use -L/--line-range FILE,M:N options to follow the history of lines
4671 from M to N in FILE. With -p/--patch only diff hunks affecting
4671 from M to N in FILE. With -p/--patch only diff hunks affecting
4672 specified line range will be shown. This option requires --follow;
4672 specified line range will be shown. This option requires --follow;
4673 it can be specified multiple times. Currently, this option is not
4673 it can be specified multiple times. Currently, this option is not
4674 compatible with --graph. This option is experimental.
4674 compatible with --graph. This option is experimental.
4675
4675
4676 .. note::
4676 .. note::
4677
4677
4678 :hg:`log --patch` may generate unexpected diff output for merge
4678 :hg:`log --patch` may generate unexpected diff output for merge
4679 changesets, as it will only compare the merge changeset against
4679 changesets, as it will only compare the merge changeset against
4680 its first parent. Also, only files different from BOTH parents
4680 its first parent. Also, only files different from BOTH parents
4681 will appear in files:.
4681 will appear in files:.
4682
4682
4683 .. note::
4683 .. note::
4684
4684
4685 For performance reasons, :hg:`log FILE` may omit duplicate changes
4685 For performance reasons, :hg:`log FILE` may omit duplicate changes
4686 made on branches and will not show removals or mode changes. To
4686 made on branches and will not show removals or mode changes. To
4687 see all such changes, use the --removed switch.
4687 see all such changes, use the --removed switch.
4688
4688
4689 .. container:: verbose
4689 .. container:: verbose
4690
4690
4691 .. note::
4691 .. note::
4692
4692
4693 The history resulting from -L/--line-range options depends on diff
4693 The history resulting from -L/--line-range options depends on diff
4694 options; for instance if white-spaces are ignored, respective changes
4694 options; for instance if white-spaces are ignored, respective changes
4695 with only white-spaces in specified line range will not be listed.
4695 with only white-spaces in specified line range will not be listed.
4696
4696
4697 .. container:: verbose
4697 .. container:: verbose
4698
4698
4699 Some examples:
4699 Some examples:
4700
4700
4701 - changesets with full descriptions and file lists::
4701 - changesets with full descriptions and file lists::
4702
4702
4703 hg log -v
4703 hg log -v
4704
4704
4705 - changesets ancestral to the working directory::
4705 - changesets ancestral to the working directory::
4706
4706
4707 hg log -f
4707 hg log -f
4708
4708
4709 - last 10 commits on the current branch::
4709 - last 10 commits on the current branch::
4710
4710
4711 hg log -l 10 -b .
4711 hg log -l 10 -b .
4712
4712
4713 - changesets showing all modifications of a file, including removals::
4713 - changesets showing all modifications of a file, including removals::
4714
4714
4715 hg log --removed file.c
4715 hg log --removed file.c
4716
4716
4717 - all changesets that touch a directory, with diffs, excluding merges::
4717 - all changesets that touch a directory, with diffs, excluding merges::
4718
4718
4719 hg log -Mp lib/
4719 hg log -Mp lib/
4720
4720
4721 - all revision numbers that match a keyword::
4721 - all revision numbers that match a keyword::
4722
4722
4723 hg log -k bug --template "{rev}\\n"
4723 hg log -k bug --template "{rev}\\n"
4724
4724
4725 - the full hash identifier of the working directory parent::
4725 - the full hash identifier of the working directory parent::
4726
4726
4727 hg log -r . --template "{node}\\n"
4727 hg log -r . --template "{node}\\n"
4728
4728
4729 - list available log templates::
4729 - list available log templates::
4730
4730
4731 hg log -T list
4731 hg log -T list
4732
4732
4733 - check if a given changeset is included in a tagged release::
4733 - check if a given changeset is included in a tagged release::
4734
4734
4735 hg log -r "a21ccf and ancestor(1.9)"
4735 hg log -r "a21ccf and ancestor(1.9)"
4736
4736
4737 - find all changesets by some user in a date range::
4737 - find all changesets by some user in a date range::
4738
4738
4739 hg log -k alice -d "may 2008 to jul 2008"
4739 hg log -k alice -d "may 2008 to jul 2008"
4740
4740
4741 - summary of all changesets after the last tag::
4741 - summary of all changesets after the last tag::
4742
4742
4743 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4743 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4744
4744
4745 - changesets touching lines 13 to 23 for file.c::
4745 - changesets touching lines 13 to 23 for file.c::
4746
4746
4747 hg log -L file.c,13:23
4747 hg log -L file.c,13:23
4748
4748
4749 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4749 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4750 main.c with patch::
4750 main.c with patch::
4751
4751
4752 hg log -L file.c,13:23 -L main.c,2:6 -p
4752 hg log -L file.c,13:23 -L main.c,2:6 -p
4753
4753
4754 See :hg:`help dates` for a list of formats valid for -d/--date.
4754 See :hg:`help dates` for a list of formats valid for -d/--date.
4755
4755
4756 See :hg:`help revisions` for more about specifying and ordering
4756 See :hg:`help revisions` for more about specifying and ordering
4757 revisions.
4757 revisions.
4758
4758
4759 See :hg:`help templates` for more about pre-packaged styles and
4759 See :hg:`help templates` for more about pre-packaged styles and
4760 specifying custom templates. The default template used by the log
4760 specifying custom templates. The default template used by the log
4761 command can be customized via the ``command-templates.log`` configuration
4761 command can be customized via the ``command-templates.log`` configuration
4762 setting.
4762 setting.
4763
4763
4764 Returns 0 on success.
4764 Returns 0 on success.
4765
4765
4766 """
4766 """
4767 opts = pycompat.byteskwargs(opts)
4767 opts = pycompat.byteskwargs(opts)
4768 linerange = opts.get(b'line_range')
4768 linerange = opts.get(b'line_range')
4769
4769
4770 if linerange and not opts.get(b'follow'):
4770 if linerange and not opts.get(b'follow'):
4771 raise error.InputError(_(b'--line-range requires --follow'))
4771 raise error.InputError(_(b'--line-range requires --follow'))
4772
4772
4773 if linerange and pats:
4773 if linerange and pats:
4774 # TODO: take pats as patterns with no line-range filter
4774 # TODO: take pats as patterns with no line-range filter
4775 raise error.InputError(
4775 raise error.InputError(
4776 _(b'FILE arguments are not compatible with --line-range option')
4776 _(b'FILE arguments are not compatible with --line-range option')
4777 )
4777 )
4778
4778
4779 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4779 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4780 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4780 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4781 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4781 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4782 if linerange:
4782 if linerange:
4783 # TODO: should follow file history from logcmdutil._initialrevs(),
4783 # TODO: should follow file history from logcmdutil._initialrevs(),
4784 # then filter the result by logcmdutil._makerevset() and --limit
4784 # then filter the result by logcmdutil._makerevset() and --limit
4785 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4785 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4786
4786
4787 getcopies = None
4787 getcopies = None
4788 if opts.get(b'copies'):
4788 if opts.get(b'copies'):
4789 endrev = None
4789 endrev = None
4790 if revs:
4790 if revs:
4791 endrev = revs.max() + 1
4791 endrev = revs.max() + 1
4792 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4792 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4793
4793
4794 ui.pager(b'log')
4794 ui.pager(b'log')
4795 displayer = logcmdutil.changesetdisplayer(
4795 displayer = logcmdutil.changesetdisplayer(
4796 ui, repo, opts, differ, buffered=True
4796 ui, repo, opts, differ, buffered=True
4797 )
4797 )
4798 if opts.get(b'graph'):
4798 if opts.get(b'graph'):
4799 displayfn = logcmdutil.displaygraphrevs
4799 displayfn = logcmdutil.displaygraphrevs
4800 else:
4800 else:
4801 displayfn = logcmdutil.displayrevs
4801 displayfn = logcmdutil.displayrevs
4802 displayfn(ui, repo, revs, displayer, getcopies)
4802 displayfn(ui, repo, revs, displayer, getcopies)
4803
4803
4804
4804
4805 @command(
4805 @command(
4806 b'manifest',
4806 b'manifest',
4807 [
4807 [
4808 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4808 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4809 (b'', b'all', False, _(b"list files from all revisions")),
4809 (b'', b'all', False, _(b"list files from all revisions")),
4810 ]
4810 ]
4811 + formatteropts,
4811 + formatteropts,
4812 _(b'[-r REV]'),
4812 _(b'[-r REV]'),
4813 helpcategory=command.CATEGORY_MAINTENANCE,
4813 helpcategory=command.CATEGORY_MAINTENANCE,
4814 intents={INTENT_READONLY},
4814 intents={INTENT_READONLY},
4815 )
4815 )
4816 def manifest(ui, repo, node=None, rev=None, **opts):
4816 def manifest(ui, repo, node=None, rev=None, **opts):
4817 """output the current or given revision of the project manifest
4817 """output the current or given revision of the project manifest
4818
4818
4819 Print a list of version controlled files for the given revision.
4819 Print a list of version controlled files for the given revision.
4820 If no revision is given, the first parent of the working directory
4820 If no revision is given, the first parent of the working directory
4821 is used, or the null revision if no revision is checked out.
4821 is used, or the null revision if no revision is checked out.
4822
4822
4823 With -v, print file permissions, symlink and executable bits.
4823 With -v, print file permissions, symlink and executable bits.
4824 With --debug, print file revision hashes.
4824 With --debug, print file revision hashes.
4825
4825
4826 If option --all is specified, the list of all files from all revisions
4826 If option --all is specified, the list of all files from all revisions
4827 is printed. This includes deleted and renamed files.
4827 is printed. This includes deleted and renamed files.
4828
4828
4829 Returns 0 on success.
4829 Returns 0 on success.
4830 """
4830 """
4831 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4831 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4832
4832
4833 if opts.get('all'):
4833 if opts.get('all'):
4834 if rev or node:
4834 if rev or node:
4835 raise error.InputError(_(b"can't specify a revision with --all"))
4835 raise error.InputError(_(b"can't specify a revision with --all"))
4836
4836
4837 res = set()
4837 res = set()
4838 for rev in repo:
4838 for rev in repo:
4839 ctx = repo[rev]
4839 ctx = repo[rev]
4840 res |= set(ctx.files())
4840 res |= set(ctx.files())
4841
4841
4842 ui.pager(b'manifest')
4842 ui.pager(b'manifest')
4843 for f in sorted(res):
4843 for f in sorted(res):
4844 fm.startitem()
4844 fm.startitem()
4845 fm.write(b"path", b'%s\n', f)
4845 fm.write(b"path", b'%s\n', f)
4846 fm.end()
4846 fm.end()
4847 return
4847 return
4848
4848
4849 if rev and node:
4849 if rev and node:
4850 raise error.InputError(_(b"please specify just one revision"))
4850 raise error.InputError(_(b"please specify just one revision"))
4851
4851
4852 if not node:
4852 if not node:
4853 node = rev
4853 node = rev
4854
4854
4855 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4855 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4856 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4856 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4857 if node:
4857 if node:
4858 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4858 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4859 ctx = logcmdutil.revsingle(repo, node)
4859 ctx = logcmdutil.revsingle(repo, node)
4860 mf = ctx.manifest()
4860 mf = ctx.manifest()
4861 ui.pager(b'manifest')
4861 ui.pager(b'manifest')
4862 for f in ctx:
4862 for f in ctx:
4863 fm.startitem()
4863 fm.startitem()
4864 fm.context(ctx=ctx)
4864 fm.context(ctx=ctx)
4865 fl = ctx[f].flags()
4865 fl = ctx[f].flags()
4866 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4866 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4867 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4867 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4868 fm.write(b'path', b'%s\n', f)
4868 fm.write(b'path', b'%s\n', f)
4869 fm.end()
4869 fm.end()
4870
4870
4871
4871
4872 @command(
4872 @command(
4873 b'merge',
4873 b'merge',
4874 [
4874 [
4875 (
4875 (
4876 b'f',
4876 b'f',
4877 b'force',
4877 b'force',
4878 None,
4878 None,
4879 _(b'force a merge including outstanding changes (DEPRECATED)'),
4879 _(b'force a merge including outstanding changes (DEPRECATED)'),
4880 ),
4880 ),
4881 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4881 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4882 (
4882 (
4883 b'P',
4883 b'P',
4884 b'preview',
4884 b'preview',
4885 None,
4885 None,
4886 _(b'review revisions to merge (no merge is performed)'),
4886 _(b'review revisions to merge (no merge is performed)'),
4887 ),
4887 ),
4888 (b'', b'abort', None, _(b'abort the ongoing merge')),
4888 (b'', b'abort', None, _(b'abort the ongoing merge')),
4889 ]
4889 ]
4890 + mergetoolopts,
4890 + mergetoolopts,
4891 _(b'[-P] [[-r] REV]'),
4891 _(b'[-P] [[-r] REV]'),
4892 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4892 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4893 helpbasic=True,
4893 helpbasic=True,
4894 )
4894 )
4895 def merge(ui, repo, node=None, **opts):
4895 def merge(ui, repo, node=None, **opts):
4896 """merge another revision into working directory
4896 """merge another revision into working directory
4897
4897
4898 The current working directory is updated with all changes made in
4898 The current working directory is updated with all changes made in
4899 the requested revision since the last common predecessor revision.
4899 the requested revision since the last common predecessor revision.
4900
4900
4901 Files that changed between either parent are marked as changed for
4901 Files that changed between either parent are marked as changed for
4902 the next commit and a commit must be performed before any further
4902 the next commit and a commit must be performed before any further
4903 updates to the repository are allowed. The next commit will have
4903 updates to the repository are allowed. The next commit will have
4904 two parents.
4904 two parents.
4905
4905
4906 ``--tool`` can be used to specify the merge tool used for file
4906 ``--tool`` can be used to specify the merge tool used for file
4907 merges. It overrides the HGMERGE environment variable and your
4907 merges. It overrides the HGMERGE environment variable and your
4908 configuration files. See :hg:`help merge-tools` for options.
4908 configuration files. See :hg:`help merge-tools` for options.
4909
4909
4910 If no revision is specified, the working directory's parent is a
4910 If no revision is specified, the working directory's parent is a
4911 head revision, and the current branch contains exactly one other
4911 head revision, and the current branch contains exactly one other
4912 head, the other head is merged with by default. Otherwise, an
4912 head, the other head is merged with by default. Otherwise, an
4913 explicit revision with which to merge must be provided.
4913 explicit revision with which to merge must be provided.
4914
4914
4915 See :hg:`help resolve` for information on handling file conflicts.
4915 See :hg:`help resolve` for information on handling file conflicts.
4916
4916
4917 To undo an uncommitted merge, use :hg:`merge --abort` which
4917 To undo an uncommitted merge, use :hg:`merge --abort` which
4918 will check out a clean copy of the original merge parent, losing
4918 will check out a clean copy of the original merge parent, losing
4919 all changes.
4919 all changes.
4920
4920
4921 Returns 0 on success, 1 if there are unresolved files.
4921 Returns 0 on success, 1 if there are unresolved files.
4922 """
4922 """
4923
4923
4924 abort = opts.get('abort')
4924 abort = opts.get('abort')
4925 if abort and repo.dirstate.p2() == repo.nullid:
4925 if abort and repo.dirstate.p2() == repo.nullid:
4926 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4926 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4927 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4927 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4928 if abort:
4928 if abort:
4929 state = cmdutil.getunfinishedstate(repo)
4929 state = cmdutil.getunfinishedstate(repo)
4930 if state and state._opname != b'merge':
4930 if state and state._opname != b'merge':
4931 raise error.StateError(
4931 raise error.StateError(
4932 _(b'cannot abort merge with %s in progress') % (state._opname),
4932 _(b'cannot abort merge with %s in progress') % (state._opname),
4933 hint=state.hint(),
4933 hint=state.hint(),
4934 )
4934 )
4935 if node:
4935 if node:
4936 raise error.InputError(_(b"cannot specify a node with --abort"))
4936 raise error.InputError(_(b"cannot specify a node with --abort"))
4937 return hg.abortmerge(repo.ui, repo)
4937 return hg.abortmerge(repo.ui, repo)
4938
4938
4939 if opts.get('rev') and node:
4939 if opts.get('rev') and node:
4940 raise error.InputError(_(b"please specify just one revision"))
4940 raise error.InputError(_(b"please specify just one revision"))
4941 if not node:
4941 if not node:
4942 node = opts.get('rev')
4942 node = opts.get('rev')
4943
4943
4944 if node:
4944 if node:
4945 ctx = logcmdutil.revsingle(repo, node)
4945 ctx = logcmdutil.revsingle(repo, node)
4946 else:
4946 else:
4947 if ui.configbool(b'commands', b'merge.require-rev'):
4947 if ui.configbool(b'commands', b'merge.require-rev'):
4948 raise error.InputError(
4948 raise error.InputError(
4949 _(
4949 _(
4950 b'configuration requires specifying revision to merge '
4950 b'configuration requires specifying revision to merge '
4951 b'with'
4951 b'with'
4952 )
4952 )
4953 )
4953 )
4954 ctx = repo[destutil.destmerge(repo)]
4954 ctx = repo[destutil.destmerge(repo)]
4955
4955
4956 if ctx.node() is None:
4956 if ctx.node() is None:
4957 raise error.InputError(
4957 raise error.InputError(
4958 _(b'merging with the working copy has no effect')
4958 _(b'merging with the working copy has no effect')
4959 )
4959 )
4960
4960
4961 if opts.get('preview'):
4961 if opts.get('preview'):
4962 # find nodes that are ancestors of p2 but not of p1
4962 # find nodes that are ancestors of p2 but not of p1
4963 p1 = repo[b'.'].node()
4963 p1 = repo[b'.'].node()
4964 p2 = ctx.node()
4964 p2 = ctx.node()
4965 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4965 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4966
4966
4967 displayer = logcmdutil.changesetdisplayer(
4967 displayer = logcmdutil.changesetdisplayer(
4968 ui, repo, pycompat.byteskwargs(opts)
4968 ui, repo, pycompat.byteskwargs(opts)
4969 )
4969 )
4970 for node in nodes:
4970 for node in nodes:
4971 displayer.show(repo[node])
4971 displayer.show(repo[node])
4972 displayer.close()
4972 displayer.close()
4973 return 0
4973 return 0
4974
4974
4975 # ui.forcemerge is an internal variable, do not document
4975 # ui.forcemerge is an internal variable, do not document
4976 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4976 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4977 with ui.configoverride(overrides, b'merge'):
4977 with ui.configoverride(overrides, b'merge'):
4978 force = opts.get('force')
4978 force = opts.get('force')
4979 labels = [b'working copy', b'merge rev', b'common ancestor']
4979 labels = [b'working copy', b'merge rev', b'common ancestor']
4980 return hg.merge(ctx, force=force, labels=labels)
4980 return hg.merge(ctx, force=force, labels=labels)
4981
4981
4982
4982
4983 statemod.addunfinished(
4983 statemod.addunfinished(
4984 b'merge',
4984 b'merge',
4985 fname=None,
4985 fname=None,
4986 clearable=True,
4986 clearable=True,
4987 allowcommit=True,
4987 allowcommit=True,
4988 cmdmsg=_(b'outstanding uncommitted merge'),
4988 cmdmsg=_(b'outstanding uncommitted merge'),
4989 abortfunc=hg.abortmerge,
4989 abortfunc=hg.abortmerge,
4990 statushint=_(
4990 statushint=_(
4991 b'To continue: hg commit\nTo abort: hg merge --abort'
4991 b'To continue: hg commit\nTo abort: hg merge --abort'
4992 ),
4992 ),
4993 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4993 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4994 )
4994 )
4995
4995
4996
4996
4997 @command(
4997 @command(
4998 b'outgoing|out',
4998 b'outgoing|out',
4999 [
4999 [
5000 (
5000 (
5001 b'f',
5001 b'f',
5002 b'force',
5002 b'force',
5003 None,
5003 None,
5004 _(b'run even when the destination is unrelated'),
5004 _(b'run even when the destination is unrelated'),
5005 ),
5005 ),
5006 (
5006 (
5007 b'r',
5007 b'r',
5008 b'rev',
5008 b'rev',
5009 [],
5009 [],
5010 _(b'a changeset intended to be included in the destination'),
5010 _(b'a changeset intended to be included in the destination'),
5011 _(b'REV'),
5011 _(b'REV'),
5012 ),
5012 ),
5013 (b'n', b'newest-first', None, _(b'show newest record first')),
5013 (b'n', b'newest-first', None, _(b'show newest record first')),
5014 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5014 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5015 (
5015 (
5016 b'b',
5016 b'b',
5017 b'branch',
5017 b'branch',
5018 [],
5018 [],
5019 _(b'a specific branch you would like to push'),
5019 _(b'a specific branch you would like to push'),
5020 _(b'BRANCH'),
5020 _(b'BRANCH'),
5021 ),
5021 ),
5022 ]
5022 ]
5023 + logopts
5023 + logopts
5024 + remoteopts
5024 + remoteopts
5025 + subrepoopts,
5025 + subrepoopts,
5026 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5026 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5027 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5027 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5028 )
5028 )
5029 def outgoing(ui, repo, *dests, **opts):
5029 def outgoing(ui, repo, *dests, **opts):
5030 """show changesets not found in the destination
5030 """show changesets not found in the destination
5031
5031
5032 Show changesets not found in the specified destination repository
5032 Show changesets not found in the specified destination repository
5033 or the default push location. These are the changesets that would
5033 or the default push location. These are the changesets that would
5034 be pushed if a push was requested.
5034 be pushed if a push was requested.
5035
5035
5036 See pull for details of valid destination formats.
5036 See pull for details of valid destination formats.
5037
5037
5038 .. container:: verbose
5038 .. container:: verbose
5039
5039
5040 With -B/--bookmarks, the result of bookmark comparison between
5040 With -B/--bookmarks, the result of bookmark comparison between
5041 local and remote repositories is displayed. With -v/--verbose,
5041 local and remote repositories is displayed. With -v/--verbose,
5042 status is also displayed for each bookmark like below::
5042 status is also displayed for each bookmark like below::
5043
5043
5044 BM1 01234567890a added
5044 BM1 01234567890a added
5045 BM2 deleted
5045 BM2 deleted
5046 BM3 234567890abc advanced
5046 BM3 234567890abc advanced
5047 BM4 34567890abcd diverged
5047 BM4 34567890abcd diverged
5048 BM5 4567890abcde changed
5048 BM5 4567890abcde changed
5049
5049
5050 The action taken when pushing depends on the
5050 The action taken when pushing depends on the
5051 status of each bookmark:
5051 status of each bookmark:
5052
5052
5053 :``added``: push with ``-B`` will create it
5053 :``added``: push with ``-B`` will create it
5054 :``deleted``: push with ``-B`` will delete it
5054 :``deleted``: push with ``-B`` will delete it
5055 :``advanced``: push will update it
5055 :``advanced``: push will update it
5056 :``diverged``: push with ``-B`` will update it
5056 :``diverged``: push with ``-B`` will update it
5057 :``changed``: push with ``-B`` will update it
5057 :``changed``: push with ``-B`` will update it
5058
5058
5059 From the point of view of pushing behavior, bookmarks
5059 From the point of view of pushing behavior, bookmarks
5060 existing only in the remote repository are treated as
5060 existing only in the remote repository are treated as
5061 ``deleted``, even if it is in fact added remotely.
5061 ``deleted``, even if it is in fact added remotely.
5062
5062
5063 Returns 0 if there are outgoing changes, 1 otherwise.
5063 Returns 0 if there are outgoing changes, 1 otherwise.
5064 """
5064 """
5065 opts = pycompat.byteskwargs(opts)
5065 opts = pycompat.byteskwargs(opts)
5066 if opts.get(b'bookmarks'):
5066 if opts.get(b'bookmarks'):
5067 for path in urlutil.get_push_paths(repo, ui, dests):
5067 for path in urlutil.get_push_paths(repo, ui, dests):
5068 other = hg.peer(repo, opts, path)
5068 other = hg.peer(repo, opts, path)
5069 try:
5069 try:
5070 if b'bookmarks' not in other.listkeys(b'namespaces'):
5070 if b'bookmarks' not in other.listkeys(b'namespaces'):
5071 ui.warn(_(b"remote doesn't support bookmarks\n"))
5071 ui.warn(_(b"remote doesn't support bookmarks\n"))
5072 return 0
5072 return 0
5073 ui.status(
5073 ui.status(
5074 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5074 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5075 )
5075 )
5076 ui.pager(b'outgoing')
5076 ui.pager(b'outgoing')
5077 return bookmarks.outgoing(ui, repo, other)
5077 return bookmarks.outgoing(ui, repo, other)
5078 finally:
5078 finally:
5079 other.close()
5079 other.close()
5080
5080
5081 return hg.outgoing(ui, repo, dests, opts)
5081 return hg.outgoing(ui, repo, dests, opts)
5082
5082
5083
5083
5084 @command(
5084 @command(
5085 b'parents',
5085 b'parents',
5086 [
5086 [
5087 (
5087 (
5088 b'r',
5088 b'r',
5089 b'rev',
5089 b'rev',
5090 b'',
5090 b'',
5091 _(b'show parents of the specified revision'),
5091 _(b'show parents of the specified revision'),
5092 _(b'REV'),
5092 _(b'REV'),
5093 ),
5093 ),
5094 ]
5094 ]
5095 + templateopts,
5095 + templateopts,
5096 _(b'[-r REV] [FILE]'),
5096 _(b'[-r REV] [FILE]'),
5097 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5097 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5098 inferrepo=True,
5098 inferrepo=True,
5099 )
5099 )
5100 def parents(ui, repo, file_=None, **opts):
5100 def parents(ui, repo, file_=None, **opts):
5101 """show the parents of the working directory or revision (DEPRECATED)
5101 """show the parents of the working directory or revision (DEPRECATED)
5102
5102
5103 Print the working directory's parent revisions. If a revision is
5103 Print the working directory's parent revisions. If a revision is
5104 given via -r/--rev, the parent of that revision will be printed.
5104 given via -r/--rev, the parent of that revision will be printed.
5105 If a file argument is given, the revision in which the file was
5105 If a file argument is given, the revision in which the file was
5106 last changed (before the working directory revision or the
5106 last changed (before the working directory revision or the
5107 argument to --rev if given) is printed.
5107 argument to --rev if given) is printed.
5108
5108
5109 This command is equivalent to::
5109 This command is equivalent to::
5110
5110
5111 hg log -r "p1()+p2()" or
5111 hg log -r "p1()+p2()" or
5112 hg log -r "p1(REV)+p2(REV)" or
5112 hg log -r "p1(REV)+p2(REV)" or
5113 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5113 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5114 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5114 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5115
5115
5116 See :hg:`summary` and :hg:`help revsets` for related information.
5116 See :hg:`summary` and :hg:`help revsets` for related information.
5117
5117
5118 Returns 0 on success.
5118 Returns 0 on success.
5119 """
5119 """
5120
5120
5121 opts = pycompat.byteskwargs(opts)
5121 opts = pycompat.byteskwargs(opts)
5122 rev = opts.get(b'rev')
5122 rev = opts.get(b'rev')
5123 if rev:
5123 if rev:
5124 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5124 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5125 ctx = logcmdutil.revsingle(repo, rev, None)
5125 ctx = logcmdutil.revsingle(repo, rev, None)
5126
5126
5127 if file_:
5127 if file_:
5128 m = scmutil.match(ctx, (file_,), opts)
5128 m = scmutil.match(ctx, (file_,), opts)
5129 if m.anypats() or len(m.files()) != 1:
5129 if m.anypats() or len(m.files()) != 1:
5130 raise error.InputError(_(b'can only specify an explicit filename'))
5130 raise error.InputError(_(b'can only specify an explicit filename'))
5131 file_ = m.files()[0]
5131 file_ = m.files()[0]
5132 filenodes = []
5132 filenodes = []
5133 for cp in ctx.parents():
5133 for cp in ctx.parents():
5134 if not cp:
5134 if not cp:
5135 continue
5135 continue
5136 try:
5136 try:
5137 filenodes.append(cp.filenode(file_))
5137 filenodes.append(cp.filenode(file_))
5138 except error.LookupError:
5138 except error.LookupError:
5139 pass
5139 pass
5140 if not filenodes:
5140 if not filenodes:
5141 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5141 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5142 p = []
5142 p = []
5143 for fn in filenodes:
5143 for fn in filenodes:
5144 fctx = repo.filectx(file_, fileid=fn)
5144 fctx = repo.filectx(file_, fileid=fn)
5145 p.append(fctx.node())
5145 p.append(fctx.node())
5146 else:
5146 else:
5147 p = [cp.node() for cp in ctx.parents()]
5147 p = [cp.node() for cp in ctx.parents()]
5148
5148
5149 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5149 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5150 for n in p:
5150 for n in p:
5151 if n != repo.nullid:
5151 if n != repo.nullid:
5152 displayer.show(repo[n])
5152 displayer.show(repo[n])
5153 displayer.close()
5153 displayer.close()
5154
5154
5155
5155
5156 @command(
5156 @command(
5157 b'paths',
5157 b'paths',
5158 formatteropts,
5158 formatteropts,
5159 _(b'[NAME]'),
5159 _(b'[NAME]'),
5160 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5160 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5161 optionalrepo=True,
5161 optionalrepo=True,
5162 intents={INTENT_READONLY},
5162 intents={INTENT_READONLY},
5163 )
5163 )
5164 def paths(ui, repo, search=None, **opts):
5164 def paths(ui, repo, search=None, **opts):
5165 """show aliases for remote repositories
5165 """show aliases for remote repositories
5166
5166
5167 Show definition of symbolic path name NAME. If no name is given,
5167 Show definition of symbolic path name NAME. If no name is given,
5168 show definition of all available names.
5168 show definition of all available names.
5169
5169
5170 Option -q/--quiet suppresses all output when searching for NAME
5170 Option -q/--quiet suppresses all output when searching for NAME
5171 and shows only the path names when listing all definitions.
5171 and shows only the path names when listing all definitions.
5172
5172
5173 Path names are defined in the [paths] section of your
5173 Path names are defined in the [paths] section of your
5174 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5174 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5175 repository, ``.hg/hgrc`` is used, too.
5175 repository, ``.hg/hgrc`` is used, too.
5176
5176
5177 The path names ``default`` and ``default-push`` have a special
5177 The path names ``default`` and ``default-push`` have a special
5178 meaning. When performing a push or pull operation, they are used
5178 meaning. When performing a push or pull operation, they are used
5179 as fallbacks if no location is specified on the command-line.
5179 as fallbacks if no location is specified on the command-line.
5180 When ``default-push`` is set, it will be used for push and
5180 When ``default-push`` is set, it will be used for push and
5181 ``default`` will be used for pull; otherwise ``default`` is used
5181 ``default`` will be used for pull; otherwise ``default`` is used
5182 as the fallback for both. When cloning a repository, the clone
5182 as the fallback for both. When cloning a repository, the clone
5183 source is written as ``default`` in ``.hg/hgrc``.
5183 source is written as ``default`` in ``.hg/hgrc``.
5184
5184
5185 .. note::
5185 .. note::
5186
5186
5187 ``default`` and ``default-push`` apply to all inbound (e.g.
5187 ``default`` and ``default-push`` apply to all inbound (e.g.
5188 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5188 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5189 and :hg:`bundle`) operations.
5189 and :hg:`bundle`) operations.
5190
5190
5191 See :hg:`help urls` for more information.
5191 See :hg:`help urls` for more information.
5192
5192
5193 .. container:: verbose
5193 .. container:: verbose
5194
5194
5195 Template:
5195 Template:
5196
5196
5197 The following keywords are supported. See also :hg:`help templates`.
5197 The following keywords are supported. See also :hg:`help templates`.
5198
5198
5199 :name: String. Symbolic name of the path alias.
5199 :name: String. Symbolic name of the path alias.
5200 :pushurl: String. URL for push operations.
5200 :pushurl: String. URL for push operations.
5201 :url: String. URL or directory path for the other operations.
5201 :url: String. URL or directory path for the other operations.
5202
5202
5203 Returns 0 on success.
5203 Returns 0 on success.
5204 """
5204 """
5205
5205
5206 pathitems = urlutil.list_paths(ui, search)
5206 pathitems = urlutil.list_paths(ui, search)
5207 ui.pager(b'paths')
5207 ui.pager(b'paths')
5208
5208
5209 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5209 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5210 if fm.isplain():
5210 if fm.isplain():
5211 hidepassword = urlutil.hidepassword
5211 hidepassword = urlutil.hidepassword
5212 else:
5212 else:
5213 hidepassword = bytes
5213 hidepassword = bytes
5214 if ui.quiet:
5214 if ui.quiet:
5215 namefmt = b'%s\n'
5215 namefmt = b'%s\n'
5216 else:
5216 else:
5217 namefmt = b'%s = '
5217 namefmt = b'%s = '
5218 showsubopts = not search and not ui.quiet
5218 showsubopts = not search and not ui.quiet
5219
5219
5220 for name, path in pathitems:
5220 for name, path in pathitems:
5221 fm.startitem()
5221 fm.startitem()
5222 fm.condwrite(not search, b'name', namefmt, name)
5222 fm.condwrite(not search, b'name', namefmt, name)
5223 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5223 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5224 for subopt, value in sorted(path.suboptions.items()):
5224 for subopt, value in sorted(path.suboptions.items()):
5225 assert subopt not in (b'name', b'url')
5225 assert subopt not in (b'name', b'url')
5226 if showsubopts:
5226 if showsubopts:
5227 fm.plain(b'%s:%s = ' % (name, subopt))
5227 fm.plain(b'%s:%s = ' % (name, subopt))
5228 display = urlutil.path_suboptions_display[subopt]
5228 display = urlutil.path_suboptions_display[subopt]
5229 value = display(value)
5229 value = display(value)
5230 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5230 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5231
5231
5232 fm.end()
5232 fm.end()
5233
5233
5234 if search and not pathitems:
5234 if search and not pathitems:
5235 if not ui.quiet:
5235 if not ui.quiet:
5236 ui.warn(_(b"not found!\n"))
5236 ui.warn(_(b"not found!\n"))
5237 return 1
5237 return 1
5238 else:
5238 else:
5239 return 0
5239 return 0
5240
5240
5241
5241
5242 @command(
5242 @command(
5243 b'phase',
5243 b'phase',
5244 [
5244 [
5245 (b'p', b'public', False, _(b'set changeset phase to public')),
5245 (b'p', b'public', False, _(b'set changeset phase to public')),
5246 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5246 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5247 (b's', b'secret', False, _(b'set changeset phase to secret')),
5247 (b's', b'secret', False, _(b'set changeset phase to secret')),
5248 (b'f', b'force', False, _(b'allow to move boundary backward')),
5248 (b'f', b'force', False, _(b'allow to move boundary backward')),
5249 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5249 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5250 ],
5250 ],
5251 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5251 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5252 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5252 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5253 )
5253 )
5254 def phase(ui, repo, *revs, **opts):
5254 def phase(ui, repo, *revs, **opts):
5255 """set or show the current phase name
5255 """set or show the current phase name
5256
5256
5257 With no argument, show the phase name of the current revision(s).
5257 With no argument, show the phase name of the current revision(s).
5258
5258
5259 With one of -p/--public, -d/--draft or -s/--secret, change the
5259 With one of -p/--public, -d/--draft or -s/--secret, change the
5260 phase value of the specified revisions.
5260 phase value of the specified revisions.
5261
5261
5262 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5262 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5263 lower phase to a higher phase. Phases are ordered as follows::
5263 lower phase to a higher phase. Phases are ordered as follows::
5264
5264
5265 public < draft < secret
5265 public < draft < secret
5266
5266
5267 Returns 0 on success, 1 if some phases could not be changed.
5267 Returns 0 on success, 1 if some phases could not be changed.
5268
5268
5269 (For more information about the phases concept, see :hg:`help phases`.)
5269 (For more information about the phases concept, see :hg:`help phases`.)
5270 """
5270 """
5271 opts = pycompat.byteskwargs(opts)
5271 opts = pycompat.byteskwargs(opts)
5272 # search for a unique phase argument
5272 # search for a unique phase argument
5273 targetphase = None
5273 targetphase = None
5274 for idx, name in enumerate(phases.cmdphasenames):
5274 for idx, name in enumerate(phases.cmdphasenames):
5275 if opts[name]:
5275 if opts[name]:
5276 if targetphase is not None:
5276 if targetphase is not None:
5277 raise error.InputError(_(b'only one phase can be specified'))
5277 raise error.InputError(_(b'only one phase can be specified'))
5278 targetphase = idx
5278 targetphase = idx
5279
5279
5280 # look for specified revision
5280 # look for specified revision
5281 revs = list(revs)
5281 revs = list(revs)
5282 revs.extend(opts[b'rev'])
5282 revs.extend(opts[b'rev'])
5283 if revs:
5283 if revs:
5284 revs = logcmdutil.revrange(repo, revs)
5284 revs = logcmdutil.revrange(repo, revs)
5285 else:
5285 else:
5286 # display both parents as the second parent phase can influence
5286 # display both parents as the second parent phase can influence
5287 # the phase of a merge commit
5287 # the phase of a merge commit
5288 revs = [c.rev() for c in repo[None].parents()]
5288 revs = [c.rev() for c in repo[None].parents()]
5289
5289
5290 ret = 0
5290 ret = 0
5291 if targetphase is None:
5291 if targetphase is None:
5292 # display
5292 # display
5293 for r in revs:
5293 for r in revs:
5294 ctx = repo[r]
5294 ctx = repo[r]
5295 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5295 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5296 else:
5296 else:
5297 with repo.lock(), repo.transaction(b"phase") as tr:
5297 with repo.lock(), repo.transaction(b"phase") as tr:
5298 # set phase
5298 # set phase
5299 if not revs:
5299 if not revs:
5300 raise error.InputError(_(b'empty revision set'))
5300 raise error.InputError(_(b'empty revision set'))
5301 nodes = [repo[r].node() for r in revs]
5301 nodes = [repo[r].node() for r in revs]
5302 # moving revision from public to draft may hide them
5302 # moving revision from public to draft may hide them
5303 # We have to check result on an unfiltered repository
5303 # We have to check result on an unfiltered repository
5304 unfi = repo.unfiltered()
5304 unfi = repo.unfiltered()
5305 getphase = unfi._phasecache.phase
5305 getphase = unfi._phasecache.phase
5306 olddata = [getphase(unfi, r) for r in unfi]
5306 olddata = [getphase(unfi, r) for r in unfi]
5307 phases.advanceboundary(repo, tr, targetphase, nodes)
5307 phases.advanceboundary(repo, tr, targetphase, nodes)
5308 if opts[b'force']:
5308 if opts[b'force']:
5309 phases.retractboundary(repo, tr, targetphase, nodes)
5309 phases.retractboundary(repo, tr, targetphase, nodes)
5310 getphase = unfi._phasecache.phase
5310 getphase = unfi._phasecache.phase
5311 newdata = [getphase(unfi, r) for r in unfi]
5311 newdata = [getphase(unfi, r) for r in unfi]
5312 changes = sum(newdata[r] != olddata[r] for r in unfi)
5312 changes = sum(newdata[r] != olddata[r] for r in unfi)
5313 cl = unfi.changelog
5313 cl = unfi.changelog
5314 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5314 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5315 if rejected:
5315 if rejected:
5316 ui.warn(
5316 ui.warn(
5317 _(
5317 _(
5318 b'cannot move %i changesets to a higher '
5318 b'cannot move %i changesets to a higher '
5319 b'phase, use --force\n'
5319 b'phase, use --force\n'
5320 )
5320 )
5321 % len(rejected)
5321 % len(rejected)
5322 )
5322 )
5323 ret = 1
5323 ret = 1
5324 if changes:
5324 if changes:
5325 msg = _(b'phase changed for %i changesets\n') % changes
5325 msg = _(b'phase changed for %i changesets\n') % changes
5326 if ret:
5326 if ret:
5327 ui.status(msg)
5327 ui.status(msg)
5328 else:
5328 else:
5329 ui.note(msg)
5329 ui.note(msg)
5330 else:
5330 else:
5331 ui.warn(_(b'no phases changed\n'))
5331 ui.warn(_(b'no phases changed\n'))
5332 return ret
5332 return ret
5333
5333
5334
5334
5335 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5335 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5336 """Run after a changegroup has been added via pull/unbundle
5336 """Run after a changegroup has been added via pull/unbundle
5337
5337
5338 This takes arguments below:
5338 This takes arguments below:
5339
5339
5340 :modheads: change of heads by pull/unbundle
5340 :modheads: change of heads by pull/unbundle
5341 :optupdate: updating working directory is needed or not
5341 :optupdate: updating working directory is needed or not
5342 :checkout: update destination revision (or None to default destination)
5342 :checkout: update destination revision (or None to default destination)
5343 :brev: a name, which might be a bookmark to be activated after updating
5343 :brev: a name, which might be a bookmark to be activated after updating
5344
5344
5345 return True if update raise any conflict, False otherwise.
5345 return True if update raise any conflict, False otherwise.
5346 """
5346 """
5347 if modheads == 0:
5347 if modheads == 0:
5348 return False
5348 return False
5349 if optupdate:
5349 if optupdate:
5350 try:
5350 try:
5351 return hg.updatetotally(ui, repo, checkout, brev)
5351 return hg.updatetotally(ui, repo, checkout, brev)
5352 except error.UpdateAbort as inst:
5352 except error.UpdateAbort as inst:
5353 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5353 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5354 hint = inst.hint
5354 hint = inst.hint
5355 raise error.UpdateAbort(msg, hint=hint)
5355 raise error.UpdateAbort(msg, hint=hint)
5356 if modheads is not None and modheads > 1:
5356 if modheads is not None and modheads > 1:
5357 currentbranchheads = len(repo.branchheads())
5357 currentbranchheads = len(repo.branchheads())
5358 if currentbranchheads == modheads:
5358 if currentbranchheads == modheads:
5359 ui.status(
5359 ui.status(
5360 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5360 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5361 )
5361 )
5362 elif currentbranchheads > 1:
5362 elif currentbranchheads > 1:
5363 ui.status(
5363 ui.status(
5364 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5364 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5365 )
5365 )
5366 else:
5366 else:
5367 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5367 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5368 elif not ui.configbool(b'commands', b'update.requiredest'):
5368 elif not ui.configbool(b'commands', b'update.requiredest'):
5369 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5369 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5370 return False
5370 return False
5371
5371
5372
5372
5373 @command(
5373 @command(
5374 b'pull',
5374 b'pull',
5375 [
5375 [
5376 (
5376 (
5377 b'u',
5377 b'u',
5378 b'update',
5378 b'update',
5379 None,
5379 None,
5380 _(b'update to new branch head if new descendants were pulled'),
5380 _(b'update to new branch head if new descendants were pulled'),
5381 ),
5381 ),
5382 (
5382 (
5383 b'f',
5383 b'f',
5384 b'force',
5384 b'force',
5385 None,
5385 None,
5386 _(b'run even when remote repository is unrelated'),
5386 _(b'run even when remote repository is unrelated'),
5387 ),
5387 ),
5388 (
5388 (
5389 b'',
5389 b'',
5390 b'confirm',
5390 b'confirm',
5391 None,
5391 None,
5392 _(b'confirm pull before applying changes'),
5392 _(b'confirm pull before applying changes'),
5393 ),
5393 ),
5394 (
5394 (
5395 b'r',
5395 b'r',
5396 b'rev',
5396 b'rev',
5397 [],
5397 [],
5398 _(b'a remote changeset intended to be added'),
5398 _(b'a remote changeset intended to be added'),
5399 _(b'REV'),
5399 _(b'REV'),
5400 ),
5400 ),
5401 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5401 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5402 (
5402 (
5403 b'b',
5403 b'b',
5404 b'branch',
5404 b'branch',
5405 [],
5405 [],
5406 _(b'a specific branch you would like to pull'),
5406 _(b'a specific branch you would like to pull'),
5407 _(b'BRANCH'),
5407 _(b'BRANCH'),
5408 ),
5408 ),
5409 (
5409 (
5410 b'',
5410 b'',
5411 b'remote-hidden',
5411 b'remote-hidden',
5412 False,
5412 False,
5413 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5413 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5414 ),
5414 ),
5415 ]
5415 ]
5416 + remoteopts,
5416 + remoteopts,
5417 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5417 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5418 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5418 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5419 helpbasic=True,
5419 helpbasic=True,
5420 )
5420 )
5421 def pull(ui, repo, *sources, **opts):
5421 def pull(ui, repo, *sources, **opts):
5422 """pull changes from the specified source
5422 """pull changes from the specified source
5423
5423
5424 Pull changes from a remote repository to a local one.
5424 Pull changes from a remote repository to a local one.
5425
5425
5426 This finds all changes from the repository at the specified path
5426 This finds all changes from the repository at the specified path
5427 or URL and adds them to a local repository (the current one unless
5427 or URL and adds them to a local repository (the current one unless
5428 -R is specified). By default, this does not update the copy of the
5428 -R is specified). By default, this does not update the copy of the
5429 project in the working directory.
5429 project in the working directory.
5430
5430
5431 When cloning from servers that support it, Mercurial may fetch
5431 When cloning from servers that support it, Mercurial may fetch
5432 pre-generated data. When this is done, hooks operating on incoming
5432 pre-generated data. When this is done, hooks operating on incoming
5433 changesets and changegroups may fire more than once, once for each
5433 changesets and changegroups may fire more than once, once for each
5434 pre-generated bundle and as well as for any additional remaining
5434 pre-generated bundle and as well as for any additional remaining
5435 data. See :hg:`help -e clonebundles` for more.
5435 data. See :hg:`help -e clonebundles` for more.
5436
5436
5437 Use :hg:`incoming` if you want to see what would have been added
5437 Use :hg:`incoming` if you want to see what would have been added
5438 by a pull at the time you issued this command. If you then decide
5438 by a pull at the time you issued this command. If you then decide
5439 to add those changes to the repository, you should use :hg:`pull
5439 to add those changes to the repository, you should use :hg:`pull
5440 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5440 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5441
5441
5442 If SOURCE is omitted, the 'default' path will be used.
5442 If SOURCE is omitted, the 'default' path will be used.
5443 See :hg:`help urls` for more information.
5443 See :hg:`help urls` for more information.
5444
5444
5445 If multiple sources are specified, they will be pulled sequentially as if
5445 If multiple sources are specified, they will be pulled sequentially as if
5446 the command was run multiple time. If --update is specify and the command
5446 the command was run multiple time. If --update is specify and the command
5447 will stop at the first failed --update.
5447 will stop at the first failed --update.
5448
5448
5449 Specifying bookmark as ``.`` is equivalent to specifying the active
5449 Specifying bookmark as ``.`` is equivalent to specifying the active
5450 bookmark's name.
5450 bookmark's name.
5451
5451
5452 .. container:: verbose
5452 .. container:: verbose
5453
5453
5454 One can use the `--remote-hidden` flag to pull changesets
5454 One can use the `--remote-hidden` flag to pull changesets
5455 hidden on the remote. This flag is "best effort", and will only
5455 hidden on the remote. This flag is "best effort", and will only
5456 work if the server supports the feature and is configured to
5456 work if the server supports the feature and is configured to
5457 allow the user to access hidden changesets. This option is
5457 allow the user to access hidden changesets. This option is
5458 experimental and backwards compatibility is not garanteed.
5458 experimental and backwards compatibility is not garanteed.
5459
5459
5460 Returns 0 on success, 1 if an update had unresolved files.
5460 Returns 0 on success, 1 if an update had unresolved files.
5461 """
5461 """
5462
5462
5463 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5463 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5464 msg = _(b'update destination required by configuration')
5464 msg = _(b'update destination required by configuration')
5465 hint = _(b'use hg pull followed by hg update DEST')
5465 hint = _(b'use hg pull followed by hg update DEST')
5466 raise error.InputError(msg, hint=hint)
5466 raise error.InputError(msg, hint=hint)
5467
5467
5468 update_conflict = None
5468 update_conflict = None
5469
5469
5470 for path in urlutil.get_pull_paths(repo, ui, sources):
5470 for path in urlutil.get_pull_paths(repo, ui, sources):
5471 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5471 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5472 ui.flush()
5472 ui.flush()
5473 other = hg.peer(
5473 other = hg.peer(
5474 repo,
5474 repo,
5475 pycompat.byteskwargs(opts),
5475 pycompat.byteskwargs(opts),
5476 path,
5476 path,
5477 remotehidden=opts['remote_hidden'],
5477 remotehidden=opts['remote_hidden'],
5478 )
5478 )
5479 update_conflict = None
5479 update_conflict = None
5480 try:
5480 try:
5481 branches = (path.branch, opts.get('branch', []))
5481 branches = (path.branch, opts.get('branch', []))
5482 revs, checkout = hg.addbranchrevs(
5482 revs, checkout = hg.addbranchrevs(
5483 repo,
5483 repo,
5484 other,
5484 other,
5485 branches,
5485 branches,
5486 opts.get('rev'),
5486 opts.get('rev'),
5487 remotehidden=opts['remote_hidden'],
5487 remotehidden=opts['remote_hidden'],
5488 )
5488 )
5489
5489
5490 pullopargs = {}
5490 pullopargs = {}
5491
5491
5492 nodes = None
5492 nodes = None
5493 if opts.get('bookmark') or revs:
5493 if opts.get('bookmark') or revs:
5494 # The list of bookmark used here is the same used to actually update
5494 # The list of bookmark used here is the same used to actually update
5495 # the bookmark names, to avoid the race from issue 4689 and we do
5495 # the bookmark names, to avoid the race from issue 4689 and we do
5496 # all lookup and bookmark queries in one go so they see the same
5496 # all lookup and bookmark queries in one go so they see the same
5497 # version of the server state (issue 4700).
5497 # version of the server state (issue 4700).
5498 nodes = []
5498 nodes = []
5499 fnodes = []
5499 fnodes = []
5500 revs = revs or []
5500 revs = revs or []
5501 if revs and not other.capable(b'lookup'):
5501 if revs and not other.capable(b'lookup'):
5502 err = _(
5502 err = _(
5503 b"other repository doesn't support revision lookup, "
5503 b"other repository doesn't support revision lookup, "
5504 b"so a rev cannot be specified."
5504 b"so a rev cannot be specified."
5505 )
5505 )
5506 raise error.Abort(err)
5506 raise error.Abort(err)
5507 with other.commandexecutor() as e:
5507 with other.commandexecutor() as e:
5508 fremotebookmarks = e.callcommand(
5508 fremotebookmarks = e.callcommand(
5509 b'listkeys', {b'namespace': b'bookmarks'}
5509 b'listkeys', {b'namespace': b'bookmarks'}
5510 )
5510 )
5511 for r in revs:
5511 for r in revs:
5512 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5512 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5513 remotebookmarks = fremotebookmarks.result()
5513 remotebookmarks = fremotebookmarks.result()
5514 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5514 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5515 pullopargs[b'remotebookmarks'] = remotebookmarks
5515 pullopargs[b'remotebookmarks'] = remotebookmarks
5516 for b in opts.get('bookmark', []):
5516 for b in opts.get('bookmark', []):
5517 b = repo._bookmarks.expandname(b)
5517 b = repo._bookmarks.expandname(b)
5518 if b not in remotebookmarks:
5518 if b not in remotebookmarks:
5519 raise error.InputError(
5519 raise error.InputError(
5520 _(b'remote bookmark %s not found!') % b
5520 _(b'remote bookmark %s not found!') % b
5521 )
5521 )
5522 nodes.append(remotebookmarks[b])
5522 nodes.append(remotebookmarks[b])
5523 for i, rev in enumerate(revs):
5523 for i, rev in enumerate(revs):
5524 node = fnodes[i].result()
5524 node = fnodes[i].result()
5525 nodes.append(node)
5525 nodes.append(node)
5526 if rev == checkout:
5526 if rev == checkout:
5527 checkout = node
5527 checkout = node
5528
5528
5529 wlock = util.nullcontextmanager()
5529 wlock = util.nullcontextmanager()
5530 if opts.get('update'):
5530 if opts.get('update'):
5531 wlock = repo.wlock()
5531 wlock = repo.wlock()
5532 with wlock:
5532 with wlock:
5533 pullopargs.update(opts.get('opargs', {}))
5533 pullopargs.update(opts.get('opargs', {}))
5534 modheads = exchange.pull(
5534 modheads = exchange.pull(
5535 repo,
5535 repo,
5536 other,
5536 other,
5537 path=path,
5537 path=path,
5538 heads=nodes,
5538 heads=nodes,
5539 force=opts.get('force'),
5539 force=opts.get('force'),
5540 bookmarks=opts.get('bookmark', ()),
5540 bookmarks=opts.get('bookmark', ()),
5541 opargs=pullopargs,
5541 opargs=pullopargs,
5542 confirm=opts.get('confirm'),
5542 confirm=opts.get('confirm'),
5543 ).cgresult
5543 ).cgresult
5544
5544
5545 # brev is a name, which might be a bookmark to be activated at
5545 # brev is a name, which might be a bookmark to be activated at
5546 # the end of the update. In other words, it is an explicit
5546 # the end of the update. In other words, it is an explicit
5547 # destination of the update
5547 # destination of the update
5548 brev = None
5548 brev = None
5549
5549
5550 if checkout:
5550 if checkout:
5551 checkout = repo.unfiltered().changelog.rev(checkout)
5551 checkout = repo.unfiltered().changelog.rev(checkout)
5552
5552
5553 # order below depends on implementation of
5553 # order below depends on implementation of
5554 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5554 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5555 # because 'checkout' is determined without it.
5555 # because 'checkout' is determined without it.
5556 if opts.get('rev'):
5556 if opts.get('rev'):
5557 brev = opts['rev'][0]
5557 brev = opts['rev'][0]
5558 elif opts.get('branch'):
5558 elif opts.get('branch'):
5559 brev = opts['branch'][0]
5559 brev = opts['branch'][0]
5560 else:
5560 else:
5561 brev = path.branch
5561 brev = path.branch
5562
5562
5563 # XXX path: we are losing the `path` object here. Keeping it
5563 # XXX path: we are losing the `path` object here. Keeping it
5564 # would be valuable. For example as a "variant" as we do
5564 # would be valuable. For example as a "variant" as we do
5565 # for pushes.
5565 # for pushes.
5566 repo._subtoppath = path.loc
5566 repo._subtoppath = path.loc
5567 try:
5567 try:
5568 update_conflict = postincoming(
5568 update_conflict = postincoming(
5569 ui, repo, modheads, opts.get('update'), checkout, brev
5569 ui, repo, modheads, opts.get('update'), checkout, brev
5570 )
5570 )
5571 except error.FilteredRepoLookupError as exc:
5571 except error.FilteredRepoLookupError as exc:
5572 msg = _(b'cannot update to target: %s') % exc.args[0]
5572 msg = _(b'cannot update to target: %s') % exc.args[0]
5573 exc.args = (msg,) + exc.args[1:]
5573 exc.args = (msg,) + exc.args[1:]
5574 raise
5574 raise
5575 finally:
5575 finally:
5576 del repo._subtoppath
5576 del repo._subtoppath
5577
5577
5578 finally:
5578 finally:
5579 other.close()
5579 other.close()
5580 # skip the remaining pull source if they are some conflict.
5580 # skip the remaining pull source if they are some conflict.
5581 if update_conflict:
5581 if update_conflict:
5582 break
5582 break
5583 if update_conflict:
5583 if update_conflict:
5584 return 1
5584 return 1
5585 else:
5585 else:
5586 return 0
5586 return 0
5587
5587
5588
5588
5589 @command(
5589 @command(
5590 b'purge|clean',
5590 b'purge|clean',
5591 [
5591 [
5592 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5592 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5593 (b'', b'all', None, _(b'purge ignored files too')),
5593 (b'', b'all', None, _(b'purge ignored files too')),
5594 (b'i', b'ignored', None, _(b'purge only ignored files')),
5594 (b'i', b'ignored', None, _(b'purge only ignored files')),
5595 (b'', b'dirs', None, _(b'purge empty directories')),
5595 (b'', b'dirs', None, _(b'purge empty directories')),
5596 (b'', b'files', None, _(b'purge files')),
5596 (b'', b'files', None, _(b'purge files')),
5597 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5597 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5598 (
5598 (
5599 b'0',
5599 b'0',
5600 b'print0',
5600 b'print0',
5601 None,
5601 None,
5602 _(
5602 _(
5603 b'end filenames with NUL, for use with xargs'
5603 b'end filenames with NUL, for use with xargs'
5604 b' (implies -p/--print)'
5604 b' (implies -p/--print)'
5605 ),
5605 ),
5606 ),
5606 ),
5607 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5607 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5608 ]
5608 ]
5609 + cmdutil.walkopts,
5609 + cmdutil.walkopts,
5610 _(b'hg purge [OPTION]... [DIR]...'),
5610 _(b'hg purge [OPTION]... [DIR]...'),
5611 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5611 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5612 )
5612 )
5613 def purge(ui, repo, *dirs, **opts):
5613 def purge(ui, repo, *dirs, **opts):
5614 """removes files not tracked by Mercurial
5614 """removes files not tracked by Mercurial
5615
5615
5616 Delete files not known to Mercurial. This is useful to test local
5616 Delete files not known to Mercurial. This is useful to test local
5617 and uncommitted changes in an otherwise-clean source tree.
5617 and uncommitted changes in an otherwise-clean source tree.
5618
5618
5619 This means that purge will delete the following by default:
5619 This means that purge will delete the following by default:
5620
5620
5621 - Unknown files: files marked with "?" by :hg:`status`
5621 - Unknown files: files marked with "?" by :hg:`status`
5622 - Empty directories: in fact Mercurial ignores directories unless
5622 - Empty directories: in fact Mercurial ignores directories unless
5623 they contain files under source control management
5623 they contain files under source control management
5624
5624
5625 But it will leave untouched:
5625 But it will leave untouched:
5626
5626
5627 - Modified and unmodified tracked files
5627 - Modified and unmodified tracked files
5628 - Ignored files (unless -i or --all is specified)
5628 - Ignored files (unless -i or --all is specified)
5629 - New files added to the repository (with :hg:`add`)
5629 - New files added to the repository (with :hg:`add`)
5630
5630
5631 The --files and --dirs options can be used to direct purge to delete
5631 The --files and --dirs options can be used to direct purge to delete
5632 only files, only directories, or both. If neither option is given,
5632 only files, only directories, or both. If neither option is given,
5633 both will be deleted.
5633 both will be deleted.
5634
5634
5635 If directories are given on the command line, only files in these
5635 If directories are given on the command line, only files in these
5636 directories are considered.
5636 directories are considered.
5637
5637
5638 Be careful with purge, as you could irreversibly delete some files
5638 Be careful with purge, as you could irreversibly delete some files
5639 you forgot to add to the repository. If you only want to print the
5639 you forgot to add to the repository. If you only want to print the
5640 list of files that this program would delete, use the --print
5640 list of files that this program would delete, use the --print
5641 option.
5641 option.
5642 """
5642 """
5643 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5643 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5644
5644
5645 act = not opts.get('print')
5645 act = not opts.get('print')
5646 eol = b'\n'
5646 eol = b'\n'
5647 if opts.get('print0'):
5647 if opts.get('print0'):
5648 eol = b'\0'
5648 eol = b'\0'
5649 act = False # --print0 implies --print
5649 act = False # --print0 implies --print
5650 if opts.get('all', False):
5650 if opts.get('all', False):
5651 ignored = True
5651 ignored = True
5652 unknown = True
5652 unknown = True
5653 else:
5653 else:
5654 ignored = opts.get('ignored', False)
5654 ignored = opts.get('ignored', False)
5655 unknown = not ignored
5655 unknown = not ignored
5656
5656
5657 removefiles = opts.get('files')
5657 removefiles = opts.get('files')
5658 removedirs = opts.get('dirs')
5658 removedirs = opts.get('dirs')
5659 confirm = opts.get('confirm')
5659 confirm = opts.get('confirm')
5660 if confirm is None:
5660 if confirm is None:
5661 try:
5661 try:
5662 extensions.find(b'purge')
5662 extensions.find(b'purge')
5663 confirm = False
5663 confirm = False
5664 except KeyError:
5664 except KeyError:
5665 confirm = True
5665 confirm = True
5666
5666
5667 if not removefiles and not removedirs:
5667 if not removefiles and not removedirs:
5668 removefiles = True
5668 removefiles = True
5669 removedirs = True
5669 removedirs = True
5670
5670
5671 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5671 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5672
5672
5673 paths = mergemod.purge(
5673 paths = mergemod.purge(
5674 repo,
5674 repo,
5675 match,
5675 match,
5676 unknown=unknown,
5676 unknown=unknown,
5677 ignored=ignored,
5677 ignored=ignored,
5678 removeemptydirs=removedirs,
5678 removeemptydirs=removedirs,
5679 removefiles=removefiles,
5679 removefiles=removefiles,
5680 abortonerror=opts.get('abort_on_err'),
5680 abortonerror=opts.get('abort_on_err'),
5681 noop=not act,
5681 noop=not act,
5682 confirm=confirm,
5682 confirm=confirm,
5683 )
5683 )
5684
5684
5685 for path in paths:
5685 for path in paths:
5686 if not act:
5686 if not act:
5687 ui.write(b'%s%s' % (path, eol))
5687 ui.write(b'%s%s' % (path, eol))
5688
5688
5689
5689
5690 @command(
5690 @command(
5691 b'push',
5691 b'push',
5692 [
5692 [
5693 (b'f', b'force', None, _(b'force push')),
5693 (b'f', b'force', None, _(b'force push')),
5694 (
5694 (
5695 b'r',
5695 b'r',
5696 b'rev',
5696 b'rev',
5697 [],
5697 [],
5698 _(b'a changeset intended to be included in the destination'),
5698 _(b'a changeset intended to be included in the destination'),
5699 _(b'REV'),
5699 _(b'REV'),
5700 ),
5700 ),
5701 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5701 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5702 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5702 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5703 (
5703 (
5704 b'b',
5704 b'b',
5705 b'branch',
5705 b'branch',
5706 [],
5706 [],
5707 _(b'a specific branch you would like to push'),
5707 _(b'a specific branch you would like to push'),
5708 _(b'BRANCH'),
5708 _(b'BRANCH'),
5709 ),
5709 ),
5710 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5710 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5711 (
5711 (
5712 b'',
5712 b'',
5713 b'pushvars',
5713 b'pushvars',
5714 [],
5714 [],
5715 _(b'variables that can be sent to server (ADVANCED)'),
5715 _(b'variables that can be sent to server (ADVANCED)'),
5716 ),
5716 ),
5717 (
5717 (
5718 b'',
5718 b'',
5719 b'publish',
5719 b'publish',
5720 False,
5720 False,
5721 _(b'push the changeset as public (EXPERIMENTAL)'),
5721 _(b'push the changeset as public (EXPERIMENTAL)'),
5722 ),
5722 ),
5723 ]
5723 ]
5724 + remoteopts,
5724 + remoteopts,
5725 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5725 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5726 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5726 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5727 helpbasic=True,
5727 helpbasic=True,
5728 )
5728 )
5729 def push(ui, repo, *dests, **opts):
5729 def push(ui, repo, *dests, **opts):
5730 """push changes to the specified destination
5730 """push changes to the specified destination
5731
5731
5732 Push changesets from the local repository to the specified
5732 Push changesets from the local repository to the specified
5733 destination.
5733 destination.
5734
5734
5735 This operation is symmetrical to pull: it is identical to a pull
5735 This operation is symmetrical to pull: it is identical to a pull
5736 in the destination repository from the current one.
5736 in the destination repository from the current one.
5737
5737
5738 By default, push will not allow creation of new heads at the
5738 By default, push will not allow creation of new heads at the
5739 destination, since multiple heads would make it unclear which head
5739 destination, since multiple heads would make it unclear which head
5740 to use. In this situation, it is recommended to pull and merge
5740 to use. In this situation, it is recommended to pull and merge
5741 before pushing.
5741 before pushing.
5742
5742
5743 Use --new-branch if you want to allow push to create a new named
5743 Use --new-branch if you want to allow push to create a new named
5744 branch that is not present at the destination. This allows you to
5744 branch that is not present at the destination. This allows you to
5745 only create a new branch without forcing other changes.
5745 only create a new branch without forcing other changes.
5746
5746
5747 .. note::
5747 .. note::
5748
5748
5749 Extra care should be taken with the -f/--force option,
5749 Extra care should be taken with the -f/--force option,
5750 which will push all new heads on all branches, an action which will
5750 which will push all new heads on all branches, an action which will
5751 almost always cause confusion for collaborators.
5751 almost always cause confusion for collaborators.
5752
5752
5753 If -r/--rev is used, the specified revision and all its ancestors
5753 If -r/--rev is used, the specified revision and all its ancestors
5754 will be pushed to the remote repository.
5754 will be pushed to the remote repository.
5755
5755
5756 If -B/--bookmark is used, the specified bookmarked revision, its
5756 If -B/--bookmark is used, the specified bookmarked revision, its
5757 ancestors, and the bookmark will be pushed to the remote
5757 ancestors, and the bookmark will be pushed to the remote
5758 repository. Specifying ``.`` is equivalent to specifying the active
5758 repository. Specifying ``.`` is equivalent to specifying the active
5759 bookmark's name. Use the --all-bookmarks option for pushing all
5759 bookmark's name. Use the --all-bookmarks option for pushing all
5760 current bookmarks.
5760 current bookmarks.
5761
5761
5762 Please see :hg:`help urls` for important details about ``ssh://``
5762 Please see :hg:`help urls` for important details about ``ssh://``
5763 URLs. If DESTINATION is omitted, a default path will be used.
5763 URLs. If DESTINATION is omitted, a default path will be used.
5764
5764
5765 When passed multiple destinations, push will process them one after the
5765 When passed multiple destinations, push will process them one after the
5766 other, but stop should an error occur.
5766 other, but stop should an error occur.
5767
5767
5768 .. container:: verbose
5768 .. container:: verbose
5769
5769
5770 The --pushvars option sends strings to the server that become
5770 The --pushvars option sends strings to the server that become
5771 environment variables prepended with ``HG_USERVAR_``. For example,
5771 environment variables prepended with ``HG_USERVAR_``. For example,
5772 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5772 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5773 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5773 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5774
5774
5775 pushvars can provide for user-overridable hooks as well as set debug
5775 pushvars can provide for user-overridable hooks as well as set debug
5776 levels. One example is having a hook that blocks commits containing
5776 levels. One example is having a hook that blocks commits containing
5777 conflict markers, but enables the user to override the hook if the file
5777 conflict markers, but enables the user to override the hook if the file
5778 is using conflict markers for testing purposes or the file format has
5778 is using conflict markers for testing purposes or the file format has
5779 strings that look like conflict markers.
5779 strings that look like conflict markers.
5780
5780
5781 By default, servers will ignore `--pushvars`. To enable it add the
5781 By default, servers will ignore `--pushvars`. To enable it add the
5782 following to your configuration file::
5782 following to your configuration file::
5783
5783
5784 [push]
5784 [push]
5785 pushvars.server = true
5785 pushvars.server = true
5786
5786
5787 Returns 0 if push was successful, 1 if nothing to push.
5787 Returns 0 if push was successful, 1 if nothing to push.
5788 """
5788 """
5789
5789
5790 opts = pycompat.byteskwargs(opts)
5790 opts = pycompat.byteskwargs(opts)
5791
5791
5792 if opts.get(b'all_bookmarks'):
5792 if opts.get(b'all_bookmarks'):
5793 cmdutil.check_incompatible_arguments(
5793 cmdutil.check_incompatible_arguments(
5794 opts,
5794 opts,
5795 b'all_bookmarks',
5795 b'all_bookmarks',
5796 [b'bookmark', b'rev'],
5796 [b'bookmark', b'rev'],
5797 )
5797 )
5798 opts[b'bookmark'] = list(repo._bookmarks)
5798 opts[b'bookmark'] = list(repo._bookmarks)
5799
5799
5800 if opts.get(b'bookmark'):
5800 if opts.get(b'bookmark'):
5801 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5801 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5802 for b in opts[b'bookmark']:
5802 for b in opts[b'bookmark']:
5803 # translate -B options to -r so changesets get pushed
5803 # translate -B options to -r so changesets get pushed
5804 b = repo._bookmarks.expandname(b)
5804 b = repo._bookmarks.expandname(b)
5805 if b in repo._bookmarks:
5805 if b in repo._bookmarks:
5806 opts.setdefault(b'rev', []).append(b)
5806 opts.setdefault(b'rev', []).append(b)
5807 else:
5807 else:
5808 # if we try to push a deleted bookmark, translate it to null
5808 # if we try to push a deleted bookmark, translate it to null
5809 # this lets simultaneous -r, -b options continue working
5809 # this lets simultaneous -r, -b options continue working
5810 opts.setdefault(b'rev', []).append(b"null")
5810 opts.setdefault(b'rev', []).append(b"null")
5811
5811
5812 some_pushed = False
5812 some_pushed = False
5813 result = 0
5813 result = 0
5814 for path in urlutil.get_push_paths(repo, ui, dests):
5814 for path in urlutil.get_push_paths(repo, ui, dests):
5815 dest = path.loc
5815 dest = path.loc
5816 branches = (path.branch, opts.get(b'branch') or [])
5816 branches = (path.branch, opts.get(b'branch') or [])
5817 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5817 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5818 revs, checkout = hg.addbranchrevs(
5818 revs, checkout = hg.addbranchrevs(
5819 repo, repo, branches, opts.get(b'rev')
5819 repo, repo, branches, opts.get(b'rev')
5820 )
5820 )
5821 other = hg.peer(repo, opts, dest)
5821 other = hg.peer(repo, opts, dest)
5822
5822
5823 try:
5823 try:
5824 if revs:
5824 if revs:
5825 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5825 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5826 if not revs:
5826 if not revs:
5827 raise error.InputError(
5827 raise error.InputError(
5828 _(b"specified revisions evaluate to an empty set"),
5828 _(b"specified revisions evaluate to an empty set"),
5829 hint=_(b"use different revision arguments"),
5829 hint=_(b"use different revision arguments"),
5830 )
5830 )
5831 elif path.pushrev:
5831 elif path.pushrev:
5832 # It doesn't make any sense to specify ancestor revisions. So limit
5832 # It doesn't make any sense to specify ancestor revisions. So limit
5833 # to DAG heads to make discovery simpler.
5833 # to DAG heads to make discovery simpler.
5834 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5834 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5835 revs = scmutil.revrange(repo, [expr])
5835 revs = scmutil.revrange(repo, [expr])
5836 revs = [repo[rev].node() for rev in revs]
5836 revs = [repo[rev].node() for rev in revs]
5837 if not revs:
5837 if not revs:
5838 raise error.InputError(
5838 raise error.InputError(
5839 _(
5839 _(
5840 b'default push revset for path evaluates to an empty set'
5840 b'default push revset for path evaluates to an empty set'
5841 )
5841 )
5842 )
5842 )
5843 elif ui.configbool(b'commands', b'push.require-revs'):
5843 elif ui.configbool(b'commands', b'push.require-revs'):
5844 raise error.InputError(
5844 raise error.InputError(
5845 _(b'no revisions specified to push'),
5845 _(b'no revisions specified to push'),
5846 hint=_(b'did you mean "hg push -r ."?'),
5846 hint=_(b'did you mean "hg push -r ."?'),
5847 )
5847 )
5848
5848
5849 repo._subtoppath = dest
5849 repo._subtoppath = dest
5850 try:
5850 try:
5851 # push subrepos depth-first for coherent ordering
5851 # push subrepos depth-first for coherent ordering
5852 c = repo[b'.']
5852 c = repo[b'.']
5853 subs = c.substate # only repos that are committed
5853 subs = c.substate # only repos that are committed
5854 for s in sorted(subs):
5854 for s in sorted(subs):
5855 sub_result = c.sub(s).push(opts)
5855 sub_result = c.sub(s).push(opts)
5856 if sub_result == 0:
5856 if sub_result == 0:
5857 return 1
5857 return 1
5858 finally:
5858 finally:
5859 del repo._subtoppath
5859 del repo._subtoppath
5860
5860
5861 opargs = dict(
5861 opargs = dict(
5862 opts.get(b'opargs', {})
5862 opts.get(b'opargs', {})
5863 ) # copy opargs since we may mutate it
5863 ) # copy opargs since we may mutate it
5864 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5864 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5865
5865
5866 pushop = exchange.push(
5866 pushop = exchange.push(
5867 repo,
5867 repo,
5868 other,
5868 other,
5869 opts.get(b'force'),
5869 opts.get(b'force'),
5870 revs=revs,
5870 revs=revs,
5871 newbranch=opts.get(b'new_branch'),
5871 newbranch=opts.get(b'new_branch'),
5872 bookmarks=opts.get(b'bookmark', ()),
5872 bookmarks=opts.get(b'bookmark', ()),
5873 publish=opts.get(b'publish'),
5873 publish=opts.get(b'publish'),
5874 opargs=opargs,
5874 opargs=opargs,
5875 )
5875 )
5876
5876
5877 if pushop.cgresult == 0:
5877 if pushop.cgresult == 0:
5878 result = 1
5878 result = 1
5879 elif pushop.cgresult is not None:
5879 elif pushop.cgresult is not None:
5880 some_pushed = True
5880 some_pushed = True
5881
5881
5882 if pushop.bkresult is not None:
5882 if pushop.bkresult is not None:
5883 if pushop.bkresult == 2:
5883 if pushop.bkresult == 2:
5884 result = 2
5884 result = 2
5885 elif not result and pushop.bkresult:
5885 elif not result and pushop.bkresult:
5886 result = 2
5886 result = 2
5887
5887
5888 if result:
5888 if result:
5889 break
5889 break
5890
5890
5891 finally:
5891 finally:
5892 other.close()
5892 other.close()
5893 if result == 0 and not some_pushed:
5893 if result == 0 and not some_pushed:
5894 result = 1
5894 result = 1
5895 return result
5895 return result
5896
5896
5897
5897
5898 @command(
5898 @command(
5899 b'recover',
5899 b'recover',
5900 [
5900 [
5901 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5901 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5902 ],
5902 ],
5903 helpcategory=command.CATEGORY_MAINTENANCE,
5903 helpcategory=command.CATEGORY_MAINTENANCE,
5904 )
5904 )
5905 def recover(ui, repo, **opts):
5905 def recover(ui, repo, **opts):
5906 """roll back an interrupted transaction
5906 """roll back an interrupted transaction
5907
5907
5908 Recover from an interrupted commit or pull.
5908 Recover from an interrupted commit or pull.
5909
5909
5910 This command tries to fix the repository status after an
5910 This command tries to fix the repository status after an
5911 interrupted operation. It should only be necessary when Mercurial
5911 interrupted operation. It should only be necessary when Mercurial
5912 suggests it.
5912 suggests it.
5913
5913
5914 Returns 0 if successful, 1 if nothing to recover or verify fails.
5914 Returns 0 if successful, 1 if nothing to recover or verify fails.
5915 """
5915 """
5916 ret = repo.recover()
5916 ret = repo.recover()
5917 if ret:
5917 if ret:
5918 if opts['verify']:
5918 if opts['verify']:
5919 return hg.verify(repo)
5919 return hg.verify(repo)
5920 else:
5920 else:
5921 msg = _(
5921 msg = _(
5922 b"(verify step skipped, run `hg verify` to check your "
5922 b"(verify step skipped, run `hg verify` to check your "
5923 b"repository content)\n"
5923 b"repository content)\n"
5924 )
5924 )
5925 ui.warn(msg)
5925 ui.warn(msg)
5926 return 0
5926 return 0
5927 return 1
5927 return 1
5928
5928
5929
5929
5930 @command(
5930 @command(
5931 b'remove|rm',
5931 b'remove|rm',
5932 [
5932 [
5933 (b'A', b'after', None, _(b'record delete for missing files')),
5933 (b'A', b'after', None, _(b'record delete for missing files')),
5934 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5934 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5935 ]
5935 ]
5936 + subrepoopts
5936 + subrepoopts
5937 + walkopts
5937 + walkopts
5938 + dryrunopts,
5938 + dryrunopts,
5939 _(b'[OPTION]... FILE...'),
5939 _(b'[OPTION]... FILE...'),
5940 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5940 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5941 helpbasic=True,
5941 helpbasic=True,
5942 inferrepo=True,
5942 inferrepo=True,
5943 )
5943 )
5944 def remove(ui, repo, *pats, **opts):
5944 def remove(ui, repo, *pats, **opts):
5945 """remove the specified files on the next commit
5945 """remove the specified files on the next commit
5946
5946
5947 Schedule the indicated files for removal from the current branch.
5947 Schedule the indicated files for removal from the current branch.
5948
5948
5949 This command schedules the files to be removed at the next commit.
5949 This command schedules the files to be removed at the next commit.
5950 To undo a remove before that, see :hg:`revert`. To undo added
5950 To undo a remove before that, see :hg:`revert`. To undo added
5951 files, see :hg:`forget`.
5951 files, see :hg:`forget`.
5952
5952
5953 .. container:: verbose
5953 .. container:: verbose
5954
5954
5955 -A/--after can be used to remove only files that have already
5955 -A/--after can be used to remove only files that have already
5956 been deleted, -f/--force can be used to force deletion, and -Af
5956 been deleted, -f/--force can be used to force deletion, and -Af
5957 can be used to remove files from the next revision without
5957 can be used to remove files from the next revision without
5958 deleting them from the working directory.
5958 deleting them from the working directory.
5959
5959
5960 The following table details the behavior of remove for different
5960 The following table details the behavior of remove for different
5961 file states (columns) and option combinations (rows). The file
5961 file states (columns) and option combinations (rows). The file
5962 states are Added [A], Clean [C], Modified [M] and Missing [!]
5962 states are Added [A], Clean [C], Modified [M] and Missing [!]
5963 (as reported by :hg:`status`). The actions are Warn, Remove
5963 (as reported by :hg:`status`). The actions are Warn, Remove
5964 (from branch) and Delete (from disk):
5964 (from branch) and Delete (from disk):
5965
5965
5966 ========= == == == ==
5966 ========= == == == ==
5967 opt/state A C M !
5967 opt/state A C M !
5968 ========= == == == ==
5968 ========= == == == ==
5969 none W RD W R
5969 none W RD W R
5970 -f R RD RD R
5970 -f R RD RD R
5971 -A W W W R
5971 -A W W W R
5972 -Af R R R R
5972 -Af R R R R
5973 ========= == == == ==
5973 ========= == == == ==
5974
5974
5975 .. note::
5975 .. note::
5976
5976
5977 :hg:`remove` never deletes files in Added [A] state from the
5977 :hg:`remove` never deletes files in Added [A] state from the
5978 working directory, not even if ``--force`` is specified.
5978 working directory, not even if ``--force`` is specified.
5979
5979
5980 Returns 0 on success, 1 if any warnings encountered.
5980 Returns 0 on success, 1 if any warnings encountered.
5981 """
5981 """
5982
5982
5983 after, force = opts.get('after'), opts.get('force')
5983 after, force = opts.get('after'), opts.get('force')
5984 dryrun = opts.get('dry_run')
5984 dryrun = opts.get('dry_run')
5985 if not pats and not after:
5985 if not pats and not after:
5986 raise error.InputError(_(b'no files specified'))
5986 raise error.InputError(_(b'no files specified'))
5987
5987
5988 with repo.wlock(), repo.dirstate.changing_files(repo):
5988 with repo.wlock(), repo.dirstate.changing_files(repo):
5989 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5989 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5990 subrepos = opts.get('subrepos')
5990 subrepos = opts.get('subrepos')
5991 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5991 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5992 return cmdutil.remove(
5992 return cmdutil.remove(
5993 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5993 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5994 )
5994 )
5995
5995
5996
5996
5997 @command(
5997 @command(
5998 b'rename|move|mv',
5998 b'rename|move|mv',
5999 [
5999 [
6000 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6000 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6001 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6001 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6002 (
6002 (
6003 b'',
6003 b'',
6004 b'at-rev',
6004 b'at-rev',
6005 b'',
6005 b'',
6006 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6006 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6007 _(b'REV'),
6007 _(b'REV'),
6008 ),
6008 ),
6009 (
6009 (
6010 b'f',
6010 b'f',
6011 b'force',
6011 b'force',
6012 None,
6012 None,
6013 _(b'forcibly move over an existing managed file'),
6013 _(b'forcibly move over an existing managed file'),
6014 ),
6014 ),
6015 ]
6015 ]
6016 + walkopts
6016 + walkopts
6017 + dryrunopts,
6017 + dryrunopts,
6018 _(b'[OPTION]... SOURCE... DEST'),
6018 _(b'[OPTION]... SOURCE... DEST'),
6019 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6019 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6020 )
6020 )
6021 def rename(ui, repo, *pats, **opts):
6021 def rename(ui, repo, *pats, **opts):
6022 """rename files; equivalent of copy + remove
6022 """rename files; equivalent of copy + remove
6023
6023
6024 Mark dest as copies of sources; mark sources for deletion. If dest
6024 Mark dest as copies of sources; mark sources for deletion. If dest
6025 is a directory, copies are put in that directory. If dest is a
6025 is a directory, copies are put in that directory. If dest is a
6026 file, there can only be one source.
6026 file, there can only be one source.
6027
6027
6028 By default, this command copies the contents of files as they
6028 By default, this command copies the contents of files as they
6029 exist in the working directory. If invoked with -A/--after, the
6029 exist in the working directory. If invoked with -A/--after, the
6030 operation is recorded, but no copying is performed.
6030 operation is recorded, but no copying is performed.
6031
6031
6032 To undo marking a destination file as renamed, use --forget. With that
6032 To undo marking a destination file as renamed, use --forget. With that
6033 option, all given (positional) arguments are unmarked as renames. The
6033 option, all given (positional) arguments are unmarked as renames. The
6034 destination file(s) will be left in place (still tracked). The source
6034 destination file(s) will be left in place (still tracked). The source
6035 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6035 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6036 the same way as :hg:`copy --forget`.
6036 the same way as :hg:`copy --forget`.
6037
6037
6038 This command takes effect with the next commit by default.
6038 This command takes effect with the next commit by default.
6039
6039
6040 Returns 0 on success, 1 if errors are encountered.
6040 Returns 0 on success, 1 if errors are encountered.
6041 """
6041 """
6042 context = lambda repo: repo.dirstate.changing_files(repo)
6042 context = lambda repo: repo.dirstate.changing_files(repo)
6043 rev = opts.get('at_rev')
6043 rev = opts.get('at_rev')
6044
6044
6045 if rev:
6045 if rev:
6046 ctx = logcmdutil.revsingle(repo, rev)
6046 ctx = logcmdutil.revsingle(repo, rev)
6047 if ctx.rev() is not None:
6047 if ctx.rev() is not None:
6048
6048
6049 def context(repo):
6049 def context(repo):
6050 return util.nullcontextmanager()
6050 return util.nullcontextmanager()
6051
6051
6052 opts['at_rev'] = ctx.rev()
6052 opts['at_rev'] = ctx.rev()
6053 with repo.wlock(), context(repo):
6053 with repo.wlock(), context(repo):
6054 return cmdutil.copy(
6054 return cmdutil.copy(
6055 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6055 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6056 )
6056 )
6057
6057
6058
6058
6059 @command(
6059 @command(
6060 b'resolve',
6060 b'resolve',
6061 [
6061 [
6062 (b'a', b'all', None, _(b'select all unresolved files')),
6062 (b'a', b'all', None, _(b'select all unresolved files')),
6063 (b'l', b'list', None, _(b'list state of files needing merge')),
6063 (b'l', b'list', None, _(b'list state of files needing merge')),
6064 (b'm', b'mark', None, _(b'mark files as resolved')),
6064 (b'm', b'mark', None, _(b'mark files as resolved')),
6065 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6065 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6066 (b'n', b'no-status', None, _(b'hide status prefix')),
6066 (b'n', b'no-status', None, _(b'hide status prefix')),
6067 (b'', b're-merge', None, _(b're-merge files')),
6067 (b'', b're-merge', None, _(b're-merge files')),
6068 ]
6068 ]
6069 + mergetoolopts
6069 + mergetoolopts
6070 + walkopts
6070 + walkopts
6071 + formatteropts,
6071 + formatteropts,
6072 _(b'[OPTION]... [FILE]...'),
6072 _(b'[OPTION]... [FILE]...'),
6073 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6073 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6074 inferrepo=True,
6074 inferrepo=True,
6075 )
6075 )
6076 def resolve(ui, repo, *pats, **opts):
6076 def resolve(ui, repo, *pats, **opts):
6077 """redo merges or set/view the merge status of files
6077 """redo merges or set/view the merge status of files
6078
6078
6079 Merges with unresolved conflicts are often the result of
6079 Merges with unresolved conflicts are often the result of
6080 non-interactive merging using the ``internal:merge`` configuration
6080 non-interactive merging using the ``internal:merge`` configuration
6081 setting, or a command-line merge tool like ``diff3``. The resolve
6081 setting, or a command-line merge tool like ``diff3``. The resolve
6082 command is used to manage the files involved in a merge, after
6082 command is used to manage the files involved in a merge, after
6083 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6083 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6084 working directory must have two parents). See :hg:`help
6084 working directory must have two parents). See :hg:`help
6085 merge-tools` for information on configuring merge tools.
6085 merge-tools` for information on configuring merge tools.
6086
6086
6087 The resolve command can be used in the following ways:
6087 The resolve command can be used in the following ways:
6088
6088
6089 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6089 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6090 the specified files, discarding any previous merge attempts. Re-merging
6090 the specified files, discarding any previous merge attempts. Re-merging
6091 is not performed for files already marked as resolved. Use ``--all/-a``
6091 is not performed for files already marked as resolved. Use ``--all/-a``
6092 to select all unresolved files. ``--tool`` can be used to specify
6092 to select all unresolved files. ``--tool`` can be used to specify
6093 the merge tool used for the given files. It overrides the HGMERGE
6093 the merge tool used for the given files. It overrides the HGMERGE
6094 environment variable and your configuration files. Previous file
6094 environment variable and your configuration files. Previous file
6095 contents are saved with a ``.orig`` suffix.
6095 contents are saved with a ``.orig`` suffix.
6096
6096
6097 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6097 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6098 (e.g. after having manually fixed-up the files). The default is
6098 (e.g. after having manually fixed-up the files). The default is
6099 to mark all unresolved files.
6099 to mark all unresolved files.
6100
6100
6101 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6101 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6102 default is to mark all resolved files.
6102 default is to mark all resolved files.
6103
6103
6104 - :hg:`resolve -l`: list files which had or still have conflicts.
6104 - :hg:`resolve -l`: list files which had or still have conflicts.
6105 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6105 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6106 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6106 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6107 the list. See :hg:`help filesets` for details.
6107 the list. See :hg:`help filesets` for details.
6108
6108
6109 .. note::
6109 .. note::
6110
6110
6111 Mercurial will not let you commit files with unresolved merge
6111 Mercurial will not let you commit files with unresolved merge
6112 conflicts. You must use :hg:`resolve -m ...` before you can
6112 conflicts. You must use :hg:`resolve -m ...` before you can
6113 commit after a conflicting merge.
6113 commit after a conflicting merge.
6114
6114
6115 .. container:: verbose
6115 .. container:: verbose
6116
6116
6117 Template:
6117 Template:
6118
6118
6119 The following keywords are supported in addition to the common template
6119 The following keywords are supported in addition to the common template
6120 keywords and functions. See also :hg:`help templates`.
6120 keywords and functions. See also :hg:`help templates`.
6121
6121
6122 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6122 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6123 :path: String. Repository-absolute path of the file.
6123 :path: String. Repository-absolute path of the file.
6124
6124
6125 Returns 0 on success, 1 if any files fail a resolve attempt.
6125 Returns 0 on success, 1 if any files fail a resolve attempt.
6126 """
6126 """
6127
6127
6128 opts = pycompat.byteskwargs(opts)
6128 opts = pycompat.byteskwargs(opts)
6129 confirm = ui.configbool(b'commands', b'resolve.confirm')
6129 confirm = ui.configbool(b'commands', b'resolve.confirm')
6130 flaglist = b'all mark unmark list no_status re_merge'.split()
6130 flaglist = b'all mark unmark list no_status re_merge'.split()
6131 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6131 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6132
6132
6133 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6133 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6134 if actioncount > 1:
6134 if actioncount > 1:
6135 raise error.InputError(_(b"too many actions specified"))
6135 raise error.InputError(_(b"too many actions specified"))
6136 elif actioncount == 0 and ui.configbool(
6136 elif actioncount == 0 and ui.configbool(
6137 b'commands', b'resolve.explicit-re-merge'
6137 b'commands', b'resolve.explicit-re-merge'
6138 ):
6138 ):
6139 hint = _(b'use --mark, --unmark, --list or --re-merge')
6139 hint = _(b'use --mark, --unmark, --list or --re-merge')
6140 raise error.InputError(_(b'no action specified'), hint=hint)
6140 raise error.InputError(_(b'no action specified'), hint=hint)
6141 if pats and all:
6141 if pats and all:
6142 raise error.InputError(_(b"can't specify --all and patterns"))
6142 raise error.InputError(_(b"can't specify --all and patterns"))
6143 if not (all or pats or show or mark or unmark):
6143 if not (all or pats or show or mark or unmark):
6144 raise error.InputError(
6144 raise error.InputError(
6145 _(b'no files or directories specified'),
6145 _(b'no files or directories specified'),
6146 hint=b'use --all to re-merge all unresolved files',
6146 hint=b'use --all to re-merge all unresolved files',
6147 )
6147 )
6148
6148
6149 if confirm:
6149 if confirm:
6150 if all:
6150 if all:
6151 if ui.promptchoice(
6151 if ui.promptchoice(
6152 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6152 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6153 ):
6153 ):
6154 raise error.CanceledError(_(b'user quit'))
6154 raise error.CanceledError(_(b'user quit'))
6155 if mark and not pats:
6155 if mark and not pats:
6156 if ui.promptchoice(
6156 if ui.promptchoice(
6157 _(
6157 _(
6158 b'mark all unresolved files as resolved (yn)?'
6158 b'mark all unresolved files as resolved (yn)?'
6159 b'$$ &Yes $$ &No'
6159 b'$$ &Yes $$ &No'
6160 )
6160 )
6161 ):
6161 ):
6162 raise error.CanceledError(_(b'user quit'))
6162 raise error.CanceledError(_(b'user quit'))
6163 if unmark and not pats:
6163 if unmark and not pats:
6164 if ui.promptchoice(
6164 if ui.promptchoice(
6165 _(
6165 _(
6166 b'mark all resolved files as unresolved (yn)?'
6166 b'mark all resolved files as unresolved (yn)?'
6167 b'$$ &Yes $$ &No'
6167 b'$$ &Yes $$ &No'
6168 )
6168 )
6169 ):
6169 ):
6170 raise error.CanceledError(_(b'user quit'))
6170 raise error.CanceledError(_(b'user quit'))
6171
6171
6172 uipathfn = scmutil.getuipathfn(repo)
6172 uipathfn = scmutil.getuipathfn(repo)
6173
6173
6174 if show:
6174 if show:
6175 ui.pager(b'resolve')
6175 ui.pager(b'resolve')
6176 fm = ui.formatter(b'resolve', opts)
6176 fm = ui.formatter(b'resolve', opts)
6177 ms = mergestatemod.mergestate.read(repo)
6177 ms = mergestatemod.mergestate.read(repo)
6178 wctx = repo[None]
6178 wctx = repo[None]
6179 m = scmutil.match(wctx, pats, opts)
6179 m = scmutil.match(wctx, pats, opts)
6180
6180
6181 # Labels and keys based on merge state. Unresolved path conflicts show
6181 # Labels and keys based on merge state. Unresolved path conflicts show
6182 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6182 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6183 # resolved conflicts.
6183 # resolved conflicts.
6184 mergestateinfo = {
6184 mergestateinfo = {
6185 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6185 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6186 b'resolve.unresolved',
6186 b'resolve.unresolved',
6187 b'U',
6187 b'U',
6188 ),
6188 ),
6189 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6189 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6190 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6190 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6191 b'resolve.unresolved',
6191 b'resolve.unresolved',
6192 b'P',
6192 b'P',
6193 ),
6193 ),
6194 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6194 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6195 b'resolve.resolved',
6195 b'resolve.resolved',
6196 b'R',
6196 b'R',
6197 ),
6197 ),
6198 }
6198 }
6199
6199
6200 for f in ms:
6200 for f in ms:
6201 if not m(f):
6201 if not m(f):
6202 continue
6202 continue
6203
6203
6204 label, key = mergestateinfo[ms[f]]
6204 label, key = mergestateinfo[ms[f]]
6205 fm.startitem()
6205 fm.startitem()
6206 fm.context(ctx=wctx)
6206 fm.context(ctx=wctx)
6207 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6207 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6208 fm.data(path=f)
6208 fm.data(path=f)
6209 fm.plain(b'%s\n' % uipathfn(f), label=label)
6209 fm.plain(b'%s\n' % uipathfn(f), label=label)
6210 fm.end()
6210 fm.end()
6211 return 0
6211 return 0
6212
6212
6213 with repo.wlock():
6213 with repo.wlock():
6214 ms = mergestatemod.mergestate.read(repo)
6214 ms = mergestatemod.mergestate.read(repo)
6215
6215
6216 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6216 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6217 raise error.StateError(
6217 raise error.StateError(
6218 _(b'resolve command not applicable when not merging')
6218 _(b'resolve command not applicable when not merging')
6219 )
6219 )
6220
6220
6221 wctx = repo[None]
6221 wctx = repo[None]
6222 m = scmutil.match(wctx, pats, opts)
6222 m = scmutil.match(wctx, pats, opts)
6223 ret = 0
6223 ret = 0
6224 didwork = False
6224 didwork = False
6225
6225
6226 hasconflictmarkers = []
6226 hasconflictmarkers = []
6227 if mark:
6227 if mark:
6228 markcheck = ui.config(b'commands', b'resolve.mark-check')
6228 markcheck = ui.config(b'commands', b'resolve.mark-check')
6229 if markcheck not in [b'warn', b'abort']:
6229 if markcheck not in [b'warn', b'abort']:
6230 # Treat all invalid / unrecognized values as 'none'.
6230 # Treat all invalid / unrecognized values as 'none'.
6231 markcheck = False
6231 markcheck = False
6232 for f in ms:
6232 for f in ms:
6233 if not m(f):
6233 if not m(f):
6234 continue
6234 continue
6235
6235
6236 didwork = True
6236 didwork = True
6237
6237
6238 # path conflicts must be resolved manually
6238 # path conflicts must be resolved manually
6239 if ms[f] in (
6239 if ms[f] in (
6240 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6240 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6241 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6241 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6242 ):
6242 ):
6243 if mark:
6243 if mark:
6244 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6244 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6245 elif unmark:
6245 elif unmark:
6246 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6246 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6247 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6247 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6248 ui.warn(
6248 ui.warn(
6249 _(b'%s: path conflict must be resolved manually\n')
6249 _(b'%s: path conflict must be resolved manually\n')
6250 % uipathfn(f)
6250 % uipathfn(f)
6251 )
6251 )
6252 continue
6252 continue
6253
6253
6254 if mark:
6254 if mark:
6255 if markcheck:
6255 if markcheck:
6256 fdata = repo.wvfs.tryread(f)
6256 fdata = repo.wvfs.tryread(f)
6257 if (
6257 if (
6258 filemerge.hasconflictmarkers(fdata)
6258 filemerge.hasconflictmarkers(fdata)
6259 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6259 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6260 ):
6260 ):
6261 hasconflictmarkers.append(f)
6261 hasconflictmarkers.append(f)
6262 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6262 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6263 elif unmark:
6263 elif unmark:
6264 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6264 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6265 else:
6265 else:
6266 # backup pre-resolve (merge uses .orig for its own purposes)
6266 # backup pre-resolve (merge uses .orig for its own purposes)
6267 a = repo.wjoin(f)
6267 a = repo.wjoin(f)
6268 try:
6268 try:
6269 util.copyfile(a, a + b".resolve")
6269 util.copyfile(a, a + b".resolve")
6270 except FileNotFoundError:
6270 except FileNotFoundError:
6271 pass
6271 pass
6272
6272
6273 try:
6273 try:
6274 # preresolve file
6274 # preresolve file
6275 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6275 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6276 with ui.configoverride(overrides, b'resolve'):
6276 with ui.configoverride(overrides, b'resolve'):
6277 r = ms.resolve(f, wctx)
6277 r = ms.resolve(f, wctx)
6278 if r:
6278 if r:
6279 ret = 1
6279 ret = 1
6280 finally:
6280 finally:
6281 ms.commit()
6281 ms.commit()
6282
6282
6283 # replace filemerge's .orig file with our resolve file
6283 # replace filemerge's .orig file with our resolve file
6284 try:
6284 try:
6285 util.rename(
6285 util.rename(
6286 a + b".resolve", scmutil.backuppath(ui, repo, f)
6286 a + b".resolve", scmutil.backuppath(ui, repo, f)
6287 )
6287 )
6288 except FileNotFoundError:
6288 except FileNotFoundError:
6289 pass
6289 pass
6290
6290
6291 if hasconflictmarkers:
6291 if hasconflictmarkers:
6292 ui.warn(
6292 ui.warn(
6293 _(
6293 _(
6294 b'warning: the following files still have conflict '
6294 b'warning: the following files still have conflict '
6295 b'markers:\n'
6295 b'markers:\n'
6296 )
6296 )
6297 + b''.join(
6297 + b''.join(
6298 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6298 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6299 )
6299 )
6300 )
6300 )
6301 if markcheck == b'abort' and not all and not pats:
6301 if markcheck == b'abort' and not all and not pats:
6302 raise error.StateError(
6302 raise error.StateError(
6303 _(b'conflict markers detected'),
6303 _(b'conflict markers detected'),
6304 hint=_(b'use --all to mark anyway'),
6304 hint=_(b'use --all to mark anyway'),
6305 )
6305 )
6306
6306
6307 ms.commit()
6307 ms.commit()
6308 branchmerge = repo.dirstate.p2() != repo.nullid
6308 branchmerge = repo.dirstate.p2() != repo.nullid
6309 # resolve is not doing a parent change here, however, `record updates`
6309 # resolve is not doing a parent change here, however, `record updates`
6310 # will call some dirstate API that at intended for parent changes call.
6310 # will call some dirstate API that at intended for parent changes call.
6311 # Ideally we would not need this and could implement a lighter version
6311 # Ideally we would not need this and could implement a lighter version
6312 # of the recordupdateslogic that will not have to deal with the part
6312 # of the recordupdateslogic that will not have to deal with the part
6313 # related to parent changes. However this would requires that:
6313 # related to parent changes. However this would requires that:
6314 # - we are sure we passed around enough information at update/merge
6314 # - we are sure we passed around enough information at update/merge
6315 # time to no longer needs it at `hg resolve time`
6315 # time to no longer needs it at `hg resolve time`
6316 # - we are sure we store that information well enough to be able to reuse it
6316 # - we are sure we store that information well enough to be able to reuse it
6317 # - we are the necessary logic to reuse it right.
6317 # - we are the necessary logic to reuse it right.
6318 #
6318 #
6319 # All this should eventually happens, but in the mean time, we use this
6319 # All this should eventually happens, but in the mean time, we use this
6320 # context manager slightly out of the context it should be.
6320 # context manager slightly out of the context it should be.
6321 with repo.dirstate.changing_parents(repo):
6321 with repo.dirstate.changing_parents(repo):
6322 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6322 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6323
6323
6324 if not didwork and pats:
6324 if not didwork and pats:
6325 hint = None
6325 hint = None
6326 if not any([p for p in pats if p.find(b':') >= 0]):
6326 if not any([p for p in pats if p.find(b':') >= 0]):
6327 pats = [b'path:%s' % p for p in pats]
6327 pats = [b'path:%s' % p for p in pats]
6328 m = scmutil.match(wctx, pats, opts)
6328 m = scmutil.match(wctx, pats, opts)
6329 for f in ms:
6329 for f in ms:
6330 if not m(f):
6330 if not m(f):
6331 continue
6331 continue
6332
6332
6333 def flag(o):
6333 def flag(o):
6334 if o == b're_merge':
6334 if o == b're_merge':
6335 return b'--re-merge '
6335 return b'--re-merge '
6336 return b'-%s ' % o[0:1]
6336 return b'-%s ' % o[0:1]
6337
6337
6338 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6338 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6339 hint = _(b"(try: hg resolve %s%s)\n") % (
6339 hint = _(b"(try: hg resolve %s%s)\n") % (
6340 flags,
6340 flags,
6341 b' '.join(pats),
6341 b' '.join(pats),
6342 )
6342 )
6343 break
6343 break
6344 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6344 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6345 if hint:
6345 if hint:
6346 ui.warn(hint)
6346 ui.warn(hint)
6347
6347
6348 unresolvedf = ms.unresolvedcount()
6348 unresolvedf = ms.unresolvedcount()
6349 if not unresolvedf:
6349 if not unresolvedf:
6350 ui.status(_(b'(no more unresolved files)\n'))
6350 ui.status(_(b'(no more unresolved files)\n'))
6351 cmdutil.checkafterresolved(repo)
6351 cmdutil.checkafterresolved(repo)
6352
6352
6353 return ret
6353 return ret
6354
6354
6355
6355
6356 @command(
6356 @command(
6357 b'revert',
6357 b'revert',
6358 [
6358 [
6359 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6359 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6360 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6360 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6361 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6361 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6362 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6362 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6363 (b'i', b'interactive', None, _(b'interactively select the changes')),
6363 (b'i', b'interactive', None, _(b'interactively select the changes')),
6364 ]
6364 ]
6365 + walkopts
6365 + walkopts
6366 + dryrunopts,
6366 + dryrunopts,
6367 _(b'[OPTION]... [-r REV] [NAME]...'),
6367 _(b'[OPTION]... [-r REV] [NAME]...'),
6368 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6368 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6369 )
6369 )
6370 def revert(ui, repo, *pats, **opts):
6370 def revert(ui, repo, *pats, **opts):
6371 """restore files to their checkout state
6371 """restore files to their checkout state
6372
6372
6373 .. note::
6373 .. note::
6374
6374
6375 To check out earlier revisions, you should use :hg:`update REV`.
6375 To check out earlier revisions, you should use :hg:`update REV`.
6376 To cancel an uncommitted merge (and lose your changes),
6376 To cancel an uncommitted merge (and lose your changes),
6377 use :hg:`merge --abort`.
6377 use :hg:`merge --abort`.
6378
6378
6379 With no revision specified, revert the specified files or directories
6379 With no revision specified, revert the specified files or directories
6380 to the contents they had in the parent of the working directory.
6380 to the contents they had in the parent of the working directory.
6381 This restores the contents of files to an unmodified
6381 This restores the contents of files to an unmodified
6382 state and unschedules adds, removes, copies, and renames. If the
6382 state and unschedules adds, removes, copies, and renames. If the
6383 working directory has two parents, you must explicitly specify a
6383 working directory has two parents, you must explicitly specify a
6384 revision.
6384 revision.
6385
6385
6386 Using the -r/--rev or -d/--date options, revert the given files or
6386 Using the -r/--rev or -d/--date options, revert the given files or
6387 directories to their states as of a specific revision. Because
6387 directories to their states as of a specific revision. Because
6388 revert does not change the working directory parents, this will
6388 revert does not change the working directory parents, this will
6389 cause these files to appear modified. This can be helpful to "back
6389 cause these files to appear modified. This can be helpful to "back
6390 out" some or all of an earlier change. See :hg:`backout` for a
6390 out" some or all of an earlier change. See :hg:`backout` for a
6391 related method.
6391 related method.
6392
6392
6393 Modified files are saved with a .orig suffix before reverting.
6393 Modified files are saved with a .orig suffix before reverting.
6394 To disable these backups, use --no-backup. It is possible to store
6394 To disable these backups, use --no-backup. It is possible to store
6395 the backup files in a custom directory relative to the root of the
6395 the backup files in a custom directory relative to the root of the
6396 repository by setting the ``ui.origbackuppath`` configuration
6396 repository by setting the ``ui.origbackuppath`` configuration
6397 option.
6397 option.
6398
6398
6399 See :hg:`help dates` for a list of formats valid for -d/--date.
6399 See :hg:`help dates` for a list of formats valid for -d/--date.
6400
6400
6401 See :hg:`help backout` for a way to reverse the effect of an
6401 See :hg:`help backout` for a way to reverse the effect of an
6402 earlier changeset.
6402 earlier changeset.
6403
6403
6404 Returns 0 on success.
6404 Returns 0 on success.
6405 """
6405 """
6406
6406
6407 if opts.get("date"):
6407 if opts.get("date"):
6408 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6408 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6409 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6409 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6410
6410
6411 parent, p2 = repo.dirstate.parents()
6411 parent, p2 = repo.dirstate.parents()
6412 if not opts.get('rev') and p2 != repo.nullid:
6412 if not opts.get('rev') and p2 != repo.nullid:
6413 # revert after merge is a trap for new users (issue2915)
6413 # revert after merge is a trap for new users (issue2915)
6414 raise error.InputError(
6414 raise error.InputError(
6415 _(b'uncommitted merge with no revision specified'),
6415 _(b'uncommitted merge with no revision specified'),
6416 hint=_(b"use 'hg update' or see 'hg help revert'"),
6416 hint=_(b"use 'hg update' or see 'hg help revert'"),
6417 )
6417 )
6418
6418
6419 rev = opts.get('rev')
6419 rev = opts.get('rev')
6420 if rev:
6420 if rev:
6421 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6421 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6422 ctx = logcmdutil.revsingle(repo, rev)
6422 ctx = logcmdutil.revsingle(repo, rev)
6423
6423
6424 if not (
6424 if not (
6425 pats
6425 pats
6426 or opts.get('include')
6426 or opts.get('include')
6427 or opts.get('exclude')
6427 or opts.get('exclude')
6428 or opts.get('all')
6428 or opts.get('all')
6429 or opts.get('interactive')
6429 or opts.get('interactive')
6430 ):
6430 ):
6431 msg = _(b"no files or directories specified")
6431 msg = _(b"no files or directories specified")
6432 if p2 != repo.nullid:
6432 if p2 != repo.nullid:
6433 hint = _(
6433 hint = _(
6434 b"uncommitted merge, use --all to discard all changes,"
6434 b"uncommitted merge, use --all to discard all changes,"
6435 b" or 'hg update -C .' to abort the merge"
6435 b" or 'hg update -C .' to abort the merge"
6436 )
6436 )
6437 raise error.InputError(msg, hint=hint)
6437 raise error.InputError(msg, hint=hint)
6438 dirty = any(repo.status())
6438 dirty = any(repo.status())
6439 node = ctx.node()
6439 node = ctx.node()
6440 if node != parent:
6440 if node != parent:
6441 if dirty:
6441 if dirty:
6442 hint = (
6442 hint = (
6443 _(
6443 _(
6444 b"uncommitted changes, use --all to discard all"
6444 b"uncommitted changes, use --all to discard all"
6445 b" changes, or 'hg update %d' to update"
6445 b" changes, or 'hg update %d' to update"
6446 )
6446 )
6447 % ctx.rev()
6447 % ctx.rev()
6448 )
6448 )
6449 else:
6449 else:
6450 hint = (
6450 hint = (
6451 _(
6451 _(
6452 b"use --all to revert all files,"
6452 b"use --all to revert all files,"
6453 b" or 'hg update %d' to update"
6453 b" or 'hg update %d' to update"
6454 )
6454 )
6455 % ctx.rev()
6455 % ctx.rev()
6456 )
6456 )
6457 elif dirty:
6457 elif dirty:
6458 hint = _(b"uncommitted changes, use --all to discard all changes")
6458 hint = _(b"uncommitted changes, use --all to discard all changes")
6459 else:
6459 else:
6460 hint = _(b"use --all to revert all files")
6460 hint = _(b"use --all to revert all files")
6461 raise error.InputError(msg, hint=hint)
6461 raise error.InputError(msg, hint=hint)
6462
6462
6463 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6463 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6464
6464
6465
6465
6466 @command(
6466 @command(
6467 b'rollback',
6467 b'rollback',
6468 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6468 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6469 helpcategory=command.CATEGORY_MAINTENANCE,
6469 helpcategory=command.CATEGORY_MAINTENANCE,
6470 )
6470 )
6471 def rollback(ui, repo, **opts):
6471 def rollback(ui, repo, **opts):
6472 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6472 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6473
6473
6474 Please use :hg:`commit --amend` instead of rollback to correct
6474 Please use :hg:`commit --amend` instead of rollback to correct
6475 mistakes in the last commit.
6475 mistakes in the last commit.
6476
6476
6477 This command should be used with care. There is only one level of
6477 This command should be used with care. There is only one level of
6478 rollback, and there is no way to undo a rollback. It will also
6478 rollback, and there is no way to undo a rollback. It will also
6479 restore the dirstate at the time of the last transaction, losing
6479 restore the dirstate at the time of the last transaction, losing
6480 any dirstate changes since that time. This command does not alter
6480 any dirstate changes since that time. This command does not alter
6481 the working directory.
6481 the working directory.
6482
6482
6483 Transactions are used to encapsulate the effects of all commands
6483 Transactions are used to encapsulate the effects of all commands
6484 that create new changesets or propagate existing changesets into a
6484 that create new changesets or propagate existing changesets into a
6485 repository.
6485 repository.
6486
6486
6487 .. container:: verbose
6487 .. container:: verbose
6488
6488
6489 For example, the following commands are transactional, and their
6489 For example, the following commands are transactional, and their
6490 effects can be rolled back:
6490 effects can be rolled back:
6491
6491
6492 - commit
6492 - commit
6493 - import
6493 - import
6494 - pull
6494 - pull
6495 - push (with this repository as the destination)
6495 - push (with this repository as the destination)
6496 - unbundle
6496 - unbundle
6497
6497
6498 To avoid permanent data loss, rollback will refuse to rollback a
6498 To avoid permanent data loss, rollback will refuse to rollback a
6499 commit transaction if it isn't checked out. Use --force to
6499 commit transaction if it isn't checked out. Use --force to
6500 override this protection.
6500 override this protection.
6501
6501
6502 The rollback command can be entirely disabled by setting the
6502 The rollback command can be entirely disabled by setting the
6503 ``ui.rollback`` configuration setting to false. If you're here
6503 ``ui.rollback`` configuration setting to false. If you're here
6504 because you want to use rollback and it's disabled, you can
6504 because you want to use rollback and it's disabled, you can
6505 re-enable the command by setting ``ui.rollback`` to true.
6505 re-enable the command by setting ``ui.rollback`` to true.
6506
6506
6507 This command is not intended for use on public repositories. Once
6507 This command is not intended for use on public repositories. Once
6508 changes are visible for pull by other users, rolling a transaction
6508 changes are visible for pull by other users, rolling a transaction
6509 back locally is ineffective (someone else may already have pulled
6509 back locally is ineffective (someone else may already have pulled
6510 the changes). Furthermore, a race is possible with readers of the
6510 the changes). Furthermore, a race is possible with readers of the
6511 repository; for example an in-progress pull from the repository
6511 repository; for example an in-progress pull from the repository
6512 may fail if a rollback is performed.
6512 may fail if a rollback is performed.
6513
6513
6514 Returns 0 on success, 1 if no rollback data is available.
6514 Returns 0 on success, 1 if no rollback data is available.
6515 """
6515 """
6516 if not ui.configbool(b'ui', b'rollback'):
6516 if not ui.configbool(b'ui', b'rollback'):
6517 raise error.Abort(
6517 raise error.Abort(
6518 _(b'rollback is disabled because it is unsafe'),
6518 _(b'rollback is disabled because it is unsafe'),
6519 hint=b'see `hg help -v rollback` for information',
6519 hint=b'see `hg help -v rollback` for information',
6520 )
6520 )
6521 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6521 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6522
6522
6523
6523
6524 @command(
6524 @command(
6525 b'root',
6525 b'root',
6526 [] + formatteropts,
6526 [] + formatteropts,
6527 intents={INTENT_READONLY},
6527 intents={INTENT_READONLY},
6528 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6528 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6529 )
6529 )
6530 def root(ui, repo, **opts):
6530 def root(ui, repo, **opts):
6531 """print the root (top) of the current working directory
6531 """print the root (top) of the current working directory
6532
6532
6533 Print the root directory of the current repository.
6533 Print the root directory of the current repository.
6534
6534
6535 .. container:: verbose
6535 .. container:: verbose
6536
6536
6537 Template:
6537 Template:
6538
6538
6539 The following keywords are supported in addition to the common template
6539 The following keywords are supported in addition to the common template
6540 keywords and functions. See also :hg:`help templates`.
6540 keywords and functions. See also :hg:`help templates`.
6541
6541
6542 :hgpath: String. Path to the .hg directory.
6542 :hgpath: String. Path to the .hg directory.
6543 :storepath: String. Path to the directory holding versioned data.
6543 :storepath: String. Path to the directory holding versioned data.
6544
6544
6545 Returns 0 on success.
6545 Returns 0 on success.
6546 """
6546 """
6547 opts = pycompat.byteskwargs(opts)
6547 opts = pycompat.byteskwargs(opts)
6548 with ui.formatter(b'root', opts) as fm:
6548 with ui.formatter(b'root', opts) as fm:
6549 fm.startitem()
6549 fm.startitem()
6550 fm.write(b'reporoot', b'%s\n', repo.root)
6550 fm.write(b'reporoot', b'%s\n', repo.root)
6551 fm.data(hgpath=repo.path, storepath=repo.spath)
6551 fm.data(hgpath=repo.path, storepath=repo.spath)
6552
6552
6553
6553
6554 @command(
6554 @command(
6555 b'serve',
6555 b'serve',
6556 [
6556 [
6557 (
6557 (
6558 b'A',
6558 b'A',
6559 b'accesslog',
6559 b'accesslog',
6560 b'',
6560 b'',
6561 _(b'name of access log file to write to'),
6561 _(b'name of access log file to write to'),
6562 _(b'FILE'),
6562 _(b'FILE'),
6563 ),
6563 ),
6564 (b'd', b'daemon', None, _(b'run server in background')),
6564 (b'd', b'daemon', None, _(b'run server in background')),
6565 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6565 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6566 (
6566 (
6567 b'E',
6567 b'E',
6568 b'errorlog',
6568 b'errorlog',
6569 b'',
6569 b'',
6570 _(b'name of error log file to write to'),
6570 _(b'name of error log file to write to'),
6571 _(b'FILE'),
6571 _(b'FILE'),
6572 ),
6572 ),
6573 # use string type, then we can check if something was passed
6573 # use string type, then we can check if something was passed
6574 (
6574 (
6575 b'p',
6575 b'p',
6576 b'port',
6576 b'port',
6577 b'',
6577 b'',
6578 _(b'port to listen on (default: 8000)'),
6578 _(b'port to listen on (default: 8000)'),
6579 _(b'PORT'),
6579 _(b'PORT'),
6580 ),
6580 ),
6581 (
6581 (
6582 b'a',
6582 b'a',
6583 b'address',
6583 b'address',
6584 b'',
6584 b'',
6585 _(b'address to listen on (default: all interfaces)'),
6585 _(b'address to listen on (default: all interfaces)'),
6586 _(b'ADDR'),
6586 _(b'ADDR'),
6587 ),
6587 ),
6588 (
6588 (
6589 b'',
6589 b'',
6590 b'prefix',
6590 b'prefix',
6591 b'',
6591 b'',
6592 _(b'prefix path to serve from (default: server root)'),
6592 _(b'prefix path to serve from (default: server root)'),
6593 _(b'PREFIX'),
6593 _(b'PREFIX'),
6594 ),
6594 ),
6595 (
6595 (
6596 b'n',
6596 b'n',
6597 b'name',
6597 b'name',
6598 b'',
6598 b'',
6599 _(b'name to show in web pages (default: working directory)'),
6599 _(b'name to show in web pages (default: working directory)'),
6600 _(b'NAME'),
6600 _(b'NAME'),
6601 ),
6601 ),
6602 (
6602 (
6603 b'',
6603 b'',
6604 b'web-conf',
6604 b'web-conf',
6605 b'',
6605 b'',
6606 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6606 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6607 _(b'FILE'),
6607 _(b'FILE'),
6608 ),
6608 ),
6609 (
6609 (
6610 b'',
6610 b'',
6611 b'webdir-conf',
6611 b'webdir-conf',
6612 b'',
6612 b'',
6613 _(b'name of the hgweb config file (DEPRECATED)'),
6613 _(b'name of the hgweb config file (DEPRECATED)'),
6614 _(b'FILE'),
6614 _(b'FILE'),
6615 ),
6615 ),
6616 (
6616 (
6617 b'',
6617 b'',
6618 b'pid-file',
6618 b'pid-file',
6619 b'',
6619 b'',
6620 _(b'name of file to write process ID to'),
6620 _(b'name of file to write process ID to'),
6621 _(b'FILE'),
6621 _(b'FILE'),
6622 ),
6622 ),
6623 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6623 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6624 (
6624 (
6625 b'',
6625 b'',
6626 b'cmdserver',
6626 b'cmdserver',
6627 b'',
6627 b'',
6628 _(b'for remote clients (ADVANCED)'),
6628 _(b'for remote clients (ADVANCED)'),
6629 _(b'MODE'),
6629 _(b'MODE'),
6630 ),
6630 ),
6631 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6631 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6632 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6632 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6633 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6633 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6634 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6634 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6635 (b'', b'print-url', None, _(b'start and print only the URL')),
6635 (b'', b'print-url', None, _(b'start and print only the URL')),
6636 ]
6636 ]
6637 + subrepoopts,
6637 + subrepoopts,
6638 _(b'[OPTION]...'),
6638 _(b'[OPTION]...'),
6639 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6639 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6640 helpbasic=True,
6640 helpbasic=True,
6641 optionalrepo=True,
6641 optionalrepo=True,
6642 )
6642 )
6643 def serve(ui, repo, **opts):
6643 def serve(ui, repo, **opts):
6644 """start stand-alone webserver
6644 """start stand-alone webserver
6645
6645
6646 Start a local HTTP repository browser and pull server. You can use
6646 Start a local HTTP repository browser and pull server. You can use
6647 this for ad-hoc sharing and browsing of repositories. It is
6647 this for ad-hoc sharing and browsing of repositories. It is
6648 recommended to use a real web server to serve a repository for
6648 recommended to use a real web server to serve a repository for
6649 longer periods of time.
6649 longer periods of time.
6650
6650
6651 Please note that the server does not implement access control.
6651 Please note that the server does not implement access control.
6652 This means that, by default, anybody can read from the server and
6652 This means that, by default, anybody can read from the server and
6653 nobody can write to it by default. Set the ``web.allow-push``
6653 nobody can write to it by default. Set the ``web.allow-push``
6654 option to ``*`` to allow everybody to push to the server. You
6654 option to ``*`` to allow everybody to push to the server. You
6655 should use a real web server if you need to authenticate users.
6655 should use a real web server if you need to authenticate users.
6656
6656
6657 By default, the server logs accesses to stdout and errors to
6657 By default, the server logs accesses to stdout and errors to
6658 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6658 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6659 files.
6659 files.
6660
6660
6661 To have the server choose a free port number to listen on, specify
6661 To have the server choose a free port number to listen on, specify
6662 a port number of 0; in this case, the server will print the port
6662 a port number of 0; in this case, the server will print the port
6663 number it uses.
6663 number it uses.
6664
6664
6665 Returns 0 on success.
6665 Returns 0 on success.
6666 """
6666 """
6667
6667
6668 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6668 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6669 opts = pycompat.byteskwargs(opts)
6669 opts = pycompat.byteskwargs(opts)
6670 if opts[b"print_url"] and ui.verbose:
6670 if opts[b"print_url"] and ui.verbose:
6671 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6671 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6672
6672
6673 if opts[b"stdio"]:
6673 if opts[b"stdio"]:
6674 if repo is None:
6674 if repo is None:
6675 raise error.RepoError(
6675 raise error.RepoError(
6676 _(b"there is no Mercurial repository here (.hg not found)")
6676 _(b"there is no Mercurial repository here (.hg not found)")
6677 )
6677 )
6678 accesshidden = False
6678 accesshidden = False
6679 if repo.filtername is None:
6679 if repo.filtername is None:
6680 allow = ui.configlist(
6680 allow = ui.configlist(
6681 b'experimental', b'server.allow-hidden-access'
6681 b'experimental', b'server.allow-hidden-access'
6682 )
6682 )
6683 user = procutil.getuser()
6683 user = procutil.getuser()
6684 if allow and scmutil.ismember(ui, user, allow):
6684 if allow and scmutil.ismember(ui, user, allow):
6685 accesshidden = True
6685 accesshidden = True
6686 else:
6686 else:
6687 msg = (
6687 msg = (
6688 _(
6688 _(
6689 b'ignoring request to access hidden changeset by '
6689 b'ignoring request to access hidden changeset by '
6690 b'unauthorized user: %s\n'
6690 b'unauthorized user: %s\n'
6691 )
6691 )
6692 % user
6692 % user
6693 )
6693 )
6694 ui.warn(msg)
6694 ui.warn(msg)
6695
6695
6696 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6696 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6697 s.serve_forever()
6697 s.serve_forever()
6698 return
6698 return
6699
6699
6700 service = server.createservice(ui, repo, opts)
6700 service = server.createservice(ui, repo, opts)
6701 return server.runservice(opts, initfn=service.init, runfn=service.run)
6701 return server.runservice(opts, initfn=service.init, runfn=service.run)
6702
6702
6703
6703
6704 @command(
6704 @command(
6705 b'shelve',
6705 b'shelve',
6706 [
6706 [
6707 (
6707 (
6708 b'A',
6708 b'A',
6709 b'addremove',
6709 b'addremove',
6710 None,
6710 None,
6711 _(b'mark new/missing files as added/removed before shelving'),
6711 _(b'mark new/missing files as added/removed before shelving'),
6712 ),
6712 ),
6713 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6713 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6714 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6714 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6715 (
6715 (
6716 b'',
6716 b'',
6717 b'date',
6717 b'date',
6718 b'',
6718 b'',
6719 _(b'shelve with the specified commit date'),
6719 _(b'shelve with the specified commit date'),
6720 _(b'DATE'),
6720 _(b'DATE'),
6721 ),
6721 ),
6722 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6722 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6723 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6723 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6724 (
6724 (
6725 b'k',
6725 b'k',
6726 b'keep',
6726 b'keep',
6727 False,
6727 False,
6728 _(b'shelve, but keep changes in the working directory'),
6728 _(b'shelve, but keep changes in the working directory'),
6729 ),
6729 ),
6730 (b'l', b'list', None, _(b'list current shelves')),
6730 (b'l', b'list', None, _(b'list current shelves')),
6731 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6731 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6732 (
6732 (
6733 b'n',
6733 b'n',
6734 b'name',
6734 b'name',
6735 b'',
6735 b'',
6736 _(b'use the given name for the shelved commit'),
6736 _(b'use the given name for the shelved commit'),
6737 _(b'NAME'),
6737 _(b'NAME'),
6738 ),
6738 ),
6739 (
6739 (
6740 b'p',
6740 b'p',
6741 b'patch',
6741 b'patch',
6742 None,
6742 None,
6743 _(
6743 _(
6744 b'output patches for changes (provide the names of the shelved '
6744 b'output patches for changes (provide the names of the shelved '
6745 b'changes as positional arguments)'
6745 b'changes as positional arguments)'
6746 ),
6746 ),
6747 ),
6747 ),
6748 (b'i', b'interactive', None, _(b'interactive mode')),
6748 (b'i', b'interactive', None, _(b'interactive mode')),
6749 (
6749 (
6750 b'',
6750 b'',
6751 b'stat',
6751 b'stat',
6752 None,
6752 None,
6753 _(
6753 _(
6754 b'output diffstat-style summary of changes (provide the names of '
6754 b'output diffstat-style summary of changes (provide the names of '
6755 b'the shelved changes as positional arguments)'
6755 b'the shelved changes as positional arguments)'
6756 ),
6756 ),
6757 ),
6757 ),
6758 ]
6758 ]
6759 + cmdutil.walkopts,
6759 + cmdutil.walkopts,
6760 _(b'hg shelve [OPTION]... [FILE]...'),
6760 _(b'hg shelve [OPTION]... [FILE]...'),
6761 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6761 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6762 )
6762 )
6763 def shelve(ui, repo, *pats, **opts):
6763 def shelve(ui, repo, *pats, **opts):
6764 """save and set aside changes from the working directory
6764 """save and set aside changes from the working directory
6765
6765
6766 Shelving takes files that "hg status" reports as not clean, saves
6766 Shelving takes files that "hg status" reports as not clean, saves
6767 the modifications to a bundle (a shelved change), and reverts the
6767 the modifications to a bundle (a shelved change), and reverts the
6768 files so that their state in the working directory becomes clean.
6768 files so that their state in the working directory becomes clean.
6769
6769
6770 To restore these changes to the working directory, using "hg
6770 To restore these changes to the working directory, using "hg
6771 unshelve"; this will work even if you switch to a different
6771 unshelve"; this will work even if you switch to a different
6772 commit.
6772 commit.
6773
6773
6774 When no files are specified, "hg shelve" saves all not-clean
6774 When no files are specified, "hg shelve" saves all not-clean
6775 files. If specific files or directories are named, only changes to
6775 files. If specific files or directories are named, only changes to
6776 those files are shelved.
6776 those files are shelved.
6777
6777
6778 In bare shelve (when no files are specified, without interactive,
6778 In bare shelve (when no files are specified, without interactive,
6779 include and exclude option), shelving remembers information if the
6779 include and exclude option), shelving remembers information if the
6780 working directory was on newly created branch, in other words working
6780 working directory was on newly created branch, in other words working
6781 directory was on different branch than its first parent. In this
6781 directory was on different branch than its first parent. In this
6782 situation unshelving restores branch information to the working directory.
6782 situation unshelving restores branch information to the working directory.
6783
6783
6784 Each shelved change has a name that makes it easier to find later.
6784 Each shelved change has a name that makes it easier to find later.
6785 The name of a shelved change defaults to being based on the active
6785 The name of a shelved change defaults to being based on the active
6786 bookmark, or if there is no active bookmark, the current named
6786 bookmark, or if there is no active bookmark, the current named
6787 branch. To specify a different name, use ``--name``.
6787 branch. To specify a different name, use ``--name``.
6788
6788
6789 To see a list of existing shelved changes, use the ``--list``
6789 To see a list of existing shelved changes, use the ``--list``
6790 option. For each shelved change, this will print its name, age,
6790 option. For each shelved change, this will print its name, age,
6791 and description; use ``--patch`` or ``--stat`` for more details.
6791 and description; use ``--patch`` or ``--stat`` for more details.
6792
6792
6793 To delete specific shelved changes, use ``--delete``. To delete
6793 To delete specific shelved changes, use ``--delete``. To delete
6794 all shelved changes, use ``--cleanup``.
6794 all shelved changes, use ``--cleanup``.
6795 """
6795 """
6796 opts = pycompat.byteskwargs(opts)
6796 opts = pycompat.byteskwargs(opts)
6797 allowables = [
6797 allowables = [
6798 (b'addremove', {b'create'}), # 'create' is pseudo action
6798 (b'addremove', {b'create'}), # 'create' is pseudo action
6799 (b'unknown', {b'create'}),
6799 (b'unknown', {b'create'}),
6800 (b'cleanup', {b'cleanup'}),
6800 (b'cleanup', {b'cleanup'}),
6801 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6801 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6802 (b'delete', {b'delete'}),
6802 (b'delete', {b'delete'}),
6803 (b'edit', {b'create'}),
6803 (b'edit', {b'create'}),
6804 (b'keep', {b'create'}),
6804 (b'keep', {b'create'}),
6805 (b'list', {b'list'}),
6805 (b'list', {b'list'}),
6806 (b'message', {b'create'}),
6806 (b'message', {b'create'}),
6807 (b'name', {b'create'}),
6807 (b'name', {b'create'}),
6808 (b'patch', {b'patch', b'list'}),
6808 (b'patch', {b'patch', b'list'}),
6809 (b'stat', {b'stat', b'list'}),
6809 (b'stat', {b'stat', b'list'}),
6810 ]
6810 ]
6811
6811
6812 def checkopt(opt):
6812 def checkopt(opt):
6813 if opts.get(opt):
6813 if opts.get(opt):
6814 for i, allowable in allowables:
6814 for i, allowable in allowables:
6815 if opts[i] and opt not in allowable:
6815 if opts[i] and opt not in allowable:
6816 raise error.InputError(
6816 raise error.InputError(
6817 _(
6817 _(
6818 b"options '--%s' and '--%s' may not be "
6818 b"options '--%s' and '--%s' may not be "
6819 b"used together"
6819 b"used together"
6820 )
6820 )
6821 % (opt, i)
6821 % (opt, i)
6822 )
6822 )
6823 return True
6823 return True
6824
6824
6825 if checkopt(b'cleanup'):
6825 if checkopt(b'cleanup'):
6826 if pats:
6826 if pats:
6827 raise error.InputError(
6827 raise error.InputError(
6828 _(b"cannot specify names when using '--cleanup'")
6828 _(b"cannot specify names when using '--cleanup'")
6829 )
6829 )
6830 return shelvemod.cleanupcmd(ui, repo)
6830 return shelvemod.cleanupcmd(ui, repo)
6831 elif checkopt(b'delete'):
6831 elif checkopt(b'delete'):
6832 return shelvemod.deletecmd(ui, repo, pats)
6832 return shelvemod.deletecmd(ui, repo, pats)
6833 elif checkopt(b'list'):
6833 elif checkopt(b'list'):
6834 return shelvemod.listcmd(ui, repo, pats, opts)
6834 return shelvemod.listcmd(ui, repo, pats, opts)
6835 elif checkopt(b'patch') or checkopt(b'stat'):
6835 elif checkopt(b'patch') or checkopt(b'stat'):
6836 return shelvemod.patchcmds(ui, repo, pats, opts)
6836 return shelvemod.patchcmds(ui, repo, pats, opts)
6837 else:
6837 else:
6838 return shelvemod.createcmd(ui, repo, pats, opts)
6838 return shelvemod.createcmd(ui, repo, pats, opts)
6839
6839
6840
6840
6841 _NOTTERSE = b'nothing'
6841 _NOTTERSE = b'nothing'
6842
6842
6843
6843
6844 @command(
6844 @command(
6845 b'status|st',
6845 b'status|st',
6846 [
6846 [
6847 (b'A', b'all', None, _(b'show status of all files')),
6847 (b'A', b'all', None, _(b'show status of all files')),
6848 (b'm', b'modified', None, _(b'show only modified files')),
6848 (b'm', b'modified', None, _(b'show only modified files')),
6849 (b'a', b'added', None, _(b'show only added files')),
6849 (b'a', b'added', None, _(b'show only added files')),
6850 (b'r', b'removed', None, _(b'show only removed files')),
6850 (b'r', b'removed', None, _(b'show only removed files')),
6851 (b'd', b'deleted', None, _(b'show only missing files')),
6851 (b'd', b'deleted', None, _(b'show only missing files')),
6852 (b'c', b'clean', None, _(b'show only files without changes')),
6852 (b'c', b'clean', None, _(b'show only files without changes')),
6853 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6853 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6854 (b'i', b'ignored', None, _(b'show only ignored files')),
6854 (b'i', b'ignored', None, _(b'show only ignored files')),
6855 (b'n', b'no-status', None, _(b'hide status prefix')),
6855 (b'n', b'no-status', None, _(b'hide status prefix')),
6856 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6856 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6857 (
6857 (
6858 b'C',
6858 b'C',
6859 b'copies',
6859 b'copies',
6860 None,
6860 None,
6861 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6861 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6862 ),
6862 ),
6863 (
6863 (
6864 b'0',
6864 b'0',
6865 b'print0',
6865 b'print0',
6866 None,
6866 None,
6867 _(b'end filenames with NUL, for use with xargs'),
6867 _(b'end filenames with NUL, for use with xargs'),
6868 ),
6868 ),
6869 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6869 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6870 (
6870 (
6871 b'',
6871 b'',
6872 b'change',
6872 b'change',
6873 b'',
6873 b'',
6874 _(b'list the changed files of a revision'),
6874 _(b'list the changed files of a revision'),
6875 _(b'REV'),
6875 _(b'REV'),
6876 ),
6876 ),
6877 ]
6877 ]
6878 + walkopts
6878 + walkopts
6879 + subrepoopts
6879 + subrepoopts
6880 + formatteropts,
6880 + formatteropts,
6881 _(b'[OPTION]... [FILE]...'),
6881 _(b'[OPTION]... [FILE]...'),
6882 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6882 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6883 helpbasic=True,
6883 helpbasic=True,
6884 inferrepo=True,
6884 inferrepo=True,
6885 intents={INTENT_READONLY},
6885 intents={INTENT_READONLY},
6886 )
6886 )
6887 def status(ui, repo, *pats, **opts):
6887 def status(ui, repo, *pats, **opts):
6888 """show changed files in the working directory
6888 """show changed files in the working directory
6889
6889
6890 Show status of files in the repository. If names are given, only
6890 Show status of files in the repository. If names are given, only
6891 files that match are shown. Files that are clean or ignored or
6891 files that match are shown. Files that are clean or ignored or
6892 the source of a copy/move operation, are not listed unless
6892 the source of a copy/move operation, are not listed unless
6893 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6893 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6894 Unless options described with "show only ..." are given, the
6894 Unless options described with "show only ..." are given, the
6895 options -mardu are used.
6895 options -mardu are used.
6896
6896
6897 Option -q/--quiet hides untracked (unknown and ignored) files
6897 Option -q/--quiet hides untracked (unknown and ignored) files
6898 unless explicitly requested with -u/--unknown or -i/--ignored.
6898 unless explicitly requested with -u/--unknown or -i/--ignored.
6899
6899
6900 .. note::
6900 .. note::
6901
6901
6902 :hg:`status` may appear to disagree with diff if permissions have
6902 :hg:`status` may appear to disagree with diff if permissions have
6903 changed or a merge has occurred. The standard diff format does
6903 changed or a merge has occurred. The standard diff format does
6904 not report permission changes and diff only reports changes
6904 not report permission changes and diff only reports changes
6905 relative to one merge parent.
6905 relative to one merge parent.
6906
6906
6907 If one revision is given, it is used as the base revision.
6907 If one revision is given, it is used as the base revision.
6908 If two revisions are given, the differences between them are
6908 If two revisions are given, the differences between them are
6909 shown. The --change option can also be used as a shortcut to list
6909 shown. The --change option can also be used as a shortcut to list
6910 the changed files of a revision from its first parent.
6910 the changed files of a revision from its first parent.
6911
6911
6912 The codes used to show the status of files are::
6912 The codes used to show the status of files are::
6913
6913
6914 M = modified
6914 M = modified
6915 A = added
6915 A = added
6916 R = removed
6916 R = removed
6917 C = clean
6917 C = clean
6918 ! = missing (deleted by non-hg command, but still tracked)
6918 ! = missing (deleted by non-hg command, but still tracked)
6919 ? = not tracked
6919 ? = not tracked
6920 I = ignored
6920 I = ignored
6921 = origin of the previous file (with --copies)
6921 = origin of the previous file (with --copies)
6922
6922
6923 .. container:: verbose
6923 .. container:: verbose
6924
6924
6925 The -t/--terse option abbreviates the output by showing only the directory
6925 The -t/--terse option abbreviates the output by showing only the directory
6926 name if all the files in it share the same status. The option takes an
6926 name if all the files in it share the same status. The option takes an
6927 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6927 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6928 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6928 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6929 for 'ignored' and 'c' for clean.
6929 for 'ignored' and 'c' for clean.
6930
6930
6931 It abbreviates only those statuses which are passed. Note that clean and
6931 It abbreviates only those statuses which are passed. Note that clean and
6932 ignored files are not displayed with '--terse ic' unless the -c/--clean
6932 ignored files are not displayed with '--terse ic' unless the -c/--clean
6933 and -i/--ignored options are also used.
6933 and -i/--ignored options are also used.
6934
6934
6935 The -v/--verbose option shows information when the repository is in an
6935 The -v/--verbose option shows information when the repository is in an
6936 unfinished merge, shelve, rebase state etc. You can have this behavior
6936 unfinished merge, shelve, rebase state etc. You can have this behavior
6937 turned on by default by enabling the ``commands.status.verbose`` option.
6937 turned on by default by enabling the ``commands.status.verbose`` option.
6938
6938
6939 You can skip displaying some of these states by setting
6939 You can skip displaying some of these states by setting
6940 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6940 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6941 'histedit', 'merge', 'rebase', or 'unshelve'.
6941 'histedit', 'merge', 'rebase', or 'unshelve'.
6942
6942
6943 Template:
6943 Template:
6944
6944
6945 The following keywords are supported in addition to the common template
6945 The following keywords are supported in addition to the common template
6946 keywords and functions. See also :hg:`help templates`.
6946 keywords and functions. See also :hg:`help templates`.
6947
6947
6948 :path: String. Repository-absolute path of the file.
6948 :path: String. Repository-absolute path of the file.
6949 :source: String. Repository-absolute path of the file originated from.
6949 :source: String. Repository-absolute path of the file originated from.
6950 Available if ``--copies`` is specified.
6950 Available if ``--copies`` is specified.
6951 :status: String. Character denoting file's status.
6951 :status: String. Character denoting file's status.
6952
6952
6953 Examples:
6953 Examples:
6954
6954
6955 - show changes in the working directory relative to a
6955 - show changes in the working directory relative to a
6956 changeset::
6956 changeset::
6957
6957
6958 hg status --rev 9353
6958 hg status --rev 9353
6959
6959
6960 - show changes in the working directory relative to the
6960 - show changes in the working directory relative to the
6961 current directory (see :hg:`help patterns` for more information)::
6961 current directory (see :hg:`help patterns` for more information)::
6962
6962
6963 hg status re:
6963 hg status re:
6964
6964
6965 - show all changes including copies in an existing changeset::
6965 - show all changes including copies in an existing changeset::
6966
6966
6967 hg status --copies --change 9353
6967 hg status --copies --change 9353
6968
6968
6969 - get a NUL separated list of added files, suitable for xargs::
6969 - get a NUL separated list of added files, suitable for xargs::
6970
6970
6971 hg status -an0
6971 hg status -an0
6972
6972
6973 - show more information about the repository status, abbreviating
6973 - show more information about the repository status, abbreviating
6974 added, removed, modified, deleted, and untracked paths::
6974 added, removed, modified, deleted, and untracked paths::
6975
6975
6976 hg status -v -t mardu
6976 hg status -v -t mardu
6977
6977
6978 Returns 0 on success.
6978 Returns 0 on success.
6979
6979
6980 """
6980 """
6981
6981
6982 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6982 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6983 opts = pycompat.byteskwargs(opts)
6983 opts = pycompat.byteskwargs(opts)
6984 revs = opts.get(b'rev', [])
6984 revs = opts.get(b'rev', [])
6985 change = opts.get(b'change', b'')
6985 change = opts.get(b'change', b'')
6986 terse = opts.get(b'terse', _NOTTERSE)
6986 terse = opts.get(b'terse', _NOTTERSE)
6987 if terse is _NOTTERSE:
6987 if terse is _NOTTERSE:
6988 if revs:
6988 if revs:
6989 terse = b''
6989 terse = b''
6990 else:
6990 else:
6991 terse = ui.config(b'commands', b'status.terse')
6991 terse = ui.config(b'commands', b'status.terse')
6992
6992
6993 if revs and terse:
6993 if revs and terse:
6994 msg = _(b'cannot use --terse with --rev')
6994 msg = _(b'cannot use --terse with --rev')
6995 raise error.InputError(msg)
6995 raise error.InputError(msg)
6996 elif change:
6996 elif change:
6997 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6997 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6998 ctx2 = logcmdutil.revsingle(repo, change, None)
6998 ctx2 = logcmdutil.revsingle(repo, change, None)
6999 ctx1 = ctx2.p1()
6999 ctx1 = ctx2.p1()
7000 else:
7000 else:
7001 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7001 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7002 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7002 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7003
7003
7004 forcerelativevalue = None
7004 forcerelativevalue = None
7005 if ui.hasconfig(b'commands', b'status.relative'):
7005 if ui.hasconfig(b'commands', b'status.relative'):
7006 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7006 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7007 uipathfn = scmutil.getuipathfn(
7007 uipathfn = scmutil.getuipathfn(
7008 repo,
7008 repo,
7009 legacyrelativevalue=bool(pats),
7009 legacyrelativevalue=bool(pats),
7010 forcerelativevalue=forcerelativevalue,
7010 forcerelativevalue=forcerelativevalue,
7011 )
7011 )
7012
7012
7013 if opts.get(b'print0'):
7013 if opts.get(b'print0'):
7014 end = b'\0'
7014 end = b'\0'
7015 else:
7015 else:
7016 end = b'\n'
7016 end = b'\n'
7017 states = b'modified added removed deleted unknown ignored clean'.split()
7017 states = b'modified added removed deleted unknown ignored clean'.split()
7018 show = [k for k in states if opts.get(k)]
7018 show = [k for k in states if opts.get(k)]
7019 if opts.get(b'all'):
7019 if opts.get(b'all'):
7020 show += ui.quiet and (states[:4] + [b'clean']) or states
7020 show += ui.quiet and (states[:4] + [b'clean']) or states
7021
7021
7022 if not show:
7022 if not show:
7023 if ui.quiet:
7023 if ui.quiet:
7024 show = states[:4]
7024 show = states[:4]
7025 else:
7025 else:
7026 show = states[:5]
7026 show = states[:5]
7027
7027
7028 m = scmutil.match(ctx2, pats, opts)
7028 m = scmutil.match(ctx2, pats, opts)
7029 if terse:
7029 if terse:
7030 # we need to compute clean and unknown to terse
7030 # we need to compute clean and unknown to terse
7031 stat = repo.status(
7031 stat = repo.status(
7032 ctx1.node(),
7032 ctx1.node(),
7033 ctx2.node(),
7033 ctx2.node(),
7034 m,
7034 m,
7035 b'ignored' in show or b'i' in terse,
7035 b'ignored' in show or b'i' in terse,
7036 clean=True,
7036 clean=True,
7037 unknown=True,
7037 unknown=True,
7038 listsubrepos=opts.get(b'subrepos'),
7038 listsubrepos=opts.get(b'subrepos'),
7039 )
7039 )
7040
7040
7041 stat = cmdutil.tersedir(stat, terse)
7041 stat = cmdutil.tersedir(stat, terse)
7042 else:
7042 else:
7043 stat = repo.status(
7043 stat = repo.status(
7044 ctx1.node(),
7044 ctx1.node(),
7045 ctx2.node(),
7045 ctx2.node(),
7046 m,
7046 m,
7047 b'ignored' in show,
7047 b'ignored' in show,
7048 b'clean' in show,
7048 b'clean' in show,
7049 b'unknown' in show,
7049 b'unknown' in show,
7050 opts.get(b'subrepos'),
7050 opts.get(b'subrepos'),
7051 )
7051 )
7052
7052
7053 changestates = zip(
7053 changestates = zip(
7054 states,
7054 states,
7055 pycompat.iterbytestr(b'MAR!?IC'),
7055 pycompat.iterbytestr(b'MAR!?IC'),
7056 [getattr(stat, s.decode('utf8')) for s in states],
7056 [getattr(stat, s.decode('utf8')) for s in states],
7057 )
7057 )
7058
7058
7059 copy = {}
7059 copy = {}
7060 show_copies = ui.configbool(b'ui', b'statuscopies')
7060 show_copies = ui.configbool(b'ui', b'statuscopies')
7061 if opts.get(b'copies') is not None:
7061 if opts.get(b'copies') is not None:
7062 show_copies = opts.get(b'copies')
7062 show_copies = opts.get(b'copies')
7063 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7063 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7064 b'no_status'
7064 b'no_status'
7065 )
7065 )
7066 if show_copies:
7066 if show_copies:
7067 copy = copies.pathcopies(ctx1, ctx2, m)
7067 copy = copies.pathcopies(ctx1, ctx2, m)
7068
7068
7069 morestatus = None
7069 morestatus = None
7070 if (
7070 if (
7071 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7071 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7072 and not ui.plain()
7072 and not ui.plain()
7073 and not opts.get(b'print0')
7073 and not opts.get(b'print0')
7074 ):
7074 ):
7075 morestatus = cmdutil.readmorestatus(repo)
7075 morestatus = cmdutil.readmorestatus(repo)
7076
7076
7077 ui.pager(b'status')
7077 ui.pager(b'status')
7078 fm = ui.formatter(b'status', opts)
7078 fm = ui.formatter(b'status', opts)
7079 fmt = b'%s' + end
7079 fmt = b'%s' + end
7080 showchar = not opts.get(b'no_status')
7080 showchar = not opts.get(b'no_status')
7081
7081
7082 for state, char, files in changestates:
7082 for state, char, files in changestates:
7083 if state in show:
7083 if state in show:
7084 label = b'status.' + state
7084 label = b'status.' + state
7085 for f in files:
7085 for f in files:
7086 fm.startitem()
7086 fm.startitem()
7087 fm.context(ctx=ctx2)
7087 fm.context(ctx=ctx2)
7088 fm.data(itemtype=b'file', path=f)
7088 fm.data(itemtype=b'file', path=f)
7089 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7089 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7090 fm.plain(fmt % uipathfn(f), label=label)
7090 fm.plain(fmt % uipathfn(f), label=label)
7091 if f in copy:
7091 if f in copy:
7092 fm.data(source=copy[f])
7092 fm.data(source=copy[f])
7093 fm.plain(
7093 fm.plain(
7094 (b' %s' + end) % uipathfn(copy[f]),
7094 (b' %s' + end) % uipathfn(copy[f]),
7095 label=b'status.copied',
7095 label=b'status.copied',
7096 )
7096 )
7097 if morestatus:
7097 if morestatus:
7098 morestatus.formatfile(f, fm)
7098 morestatus.formatfile(f, fm)
7099
7099
7100 if morestatus:
7100 if morestatus:
7101 morestatus.formatfooter(fm)
7101 morestatus.formatfooter(fm)
7102 fm.end()
7102 fm.end()
7103
7103
7104
7104
7105 @command(
7105 @command(
7106 b'summary|sum',
7106 b'summary|sum',
7107 [(b'', b'remote', None, _(b'check for push and pull'))],
7107 [(b'', b'remote', None, _(b'check for push and pull'))],
7108 b'[--remote]',
7108 b'[--remote]',
7109 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7109 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7110 helpbasic=True,
7110 helpbasic=True,
7111 intents={INTENT_READONLY},
7111 intents={INTENT_READONLY},
7112 )
7112 )
7113 def summary(ui, repo, **opts):
7113 def summary(ui, repo, **opts):
7114 """summarize working directory state
7114 """summarize working directory state
7115
7115
7116 This generates a brief summary of the working directory state,
7116 This generates a brief summary of the working directory state,
7117 including parents, branch, commit status, phase and available updates.
7117 including parents, branch, commit status, phase and available updates.
7118
7118
7119 With the --remote option, this will check the default paths for
7119 With the --remote option, this will check the default paths for
7120 incoming and outgoing changes. This can be time-consuming.
7120 incoming and outgoing changes. This can be time-consuming.
7121
7121
7122 Returns 0 on success.
7122 Returns 0 on success.
7123 """
7123 """
7124
7124
7125 ui.pager(b'summary')
7125 ui.pager(b'summary')
7126 ctx = repo[None]
7126 ctx = repo[None]
7127 parents = ctx.parents()
7127 parents = ctx.parents()
7128 pnode = parents[0].node()
7128 pnode = parents[0].node()
7129 marks = []
7129 marks = []
7130
7130
7131 try:
7131 try:
7132 ms = mergestatemod.mergestate.read(repo)
7132 ms = mergestatemod.mergestate.read(repo)
7133 except error.UnsupportedMergeRecords as e:
7133 except error.UnsupportedMergeRecords as e:
7134 s = b' '.join(e.recordtypes)
7134 s = b' '.join(e.recordtypes)
7135 ui.warn(
7135 ui.warn(
7136 _(b'warning: merge state has unsupported record types: %s\n') % s
7136 _(b'warning: merge state has unsupported record types: %s\n') % s
7137 )
7137 )
7138 unresolved = []
7138 unresolved = []
7139 else:
7139 else:
7140 unresolved = list(ms.unresolved())
7140 unresolved = list(ms.unresolved())
7141
7141
7142 for p in parents:
7142 for p in parents:
7143 # label with log.changeset (instead of log.parent) since this
7143 # label with log.changeset (instead of log.parent) since this
7144 # shows a working directory parent *changeset*:
7144 # shows a working directory parent *changeset*:
7145 # i18n: column positioning for "hg summary"
7145 # i18n: column positioning for "hg summary"
7146 ui.write(
7146 ui.write(
7147 _(b'parent: %d:%s ') % (p.rev(), p),
7147 _(b'parent: %d:%s ') % (p.rev(), p),
7148 label=logcmdutil.changesetlabels(p),
7148 label=logcmdutil.changesetlabels(p),
7149 )
7149 )
7150 ui.write(b' '.join(p.tags()), label=b'log.tag')
7150 ui.write(b' '.join(p.tags()), label=b'log.tag')
7151 if p.bookmarks():
7151 if p.bookmarks():
7152 marks.extend(p.bookmarks())
7152 marks.extend(p.bookmarks())
7153 if p.rev() == -1:
7153 if p.rev() == -1:
7154 if not len(repo):
7154 if not len(repo):
7155 ui.write(_(b' (empty repository)'))
7155 ui.write(_(b' (empty repository)'))
7156 else:
7156 else:
7157 ui.write(_(b' (no revision checked out)'))
7157 ui.write(_(b' (no revision checked out)'))
7158 if p.obsolete():
7158 if p.obsolete():
7159 ui.write(_(b' (obsolete)'))
7159 ui.write(_(b' (obsolete)'))
7160 if p.isunstable():
7160 if p.isunstable():
7161 instabilities = (
7161 instabilities = (
7162 ui.label(instability, b'trouble.%s' % instability)
7162 ui.label(instability, b'trouble.%s' % instability)
7163 for instability in p.instabilities()
7163 for instability in p.instabilities()
7164 )
7164 )
7165 ui.write(b' (' + b', '.join(instabilities) + b')')
7165 ui.write(b' (' + b', '.join(instabilities) + b')')
7166 ui.write(b'\n')
7166 ui.write(b'\n')
7167 if p.description():
7167 if p.description():
7168 ui.status(
7168 ui.status(
7169 b' ' + p.description().splitlines()[0].strip() + b'\n',
7169 b' ' + p.description().splitlines()[0].strip() + b'\n',
7170 label=b'log.summary',
7170 label=b'log.summary',
7171 )
7171 )
7172
7172
7173 branch = ctx.branch()
7173 branch = ctx.branch()
7174 bheads = repo.branchheads(branch)
7174 bheads = repo.branchheads(branch)
7175 # i18n: column positioning for "hg summary"
7175 # i18n: column positioning for "hg summary"
7176 m = _(b'branch: %s\n') % branch
7176 m = _(b'branch: %s\n') % branch
7177 if branch != b'default':
7177 if branch != b'default':
7178 ui.write(m, label=b'log.branch')
7178 ui.write(m, label=b'log.branch')
7179 else:
7179 else:
7180 ui.status(m, label=b'log.branch')
7180 ui.status(m, label=b'log.branch')
7181
7181
7182 if marks:
7182 if marks:
7183 active = repo._activebookmark
7183 active = repo._activebookmark
7184 # i18n: column positioning for "hg summary"
7184 # i18n: column positioning for "hg summary"
7185 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7185 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7186 if active is not None:
7186 if active is not None:
7187 if active in marks:
7187 if active in marks:
7188 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7188 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7189 marks.remove(active)
7189 marks.remove(active)
7190 else:
7190 else:
7191 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7191 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7192 for m in marks:
7192 for m in marks:
7193 ui.write(b' ' + m, label=b'log.bookmark')
7193 ui.write(b' ' + m, label=b'log.bookmark')
7194 ui.write(b'\n', label=b'log.bookmark')
7194 ui.write(b'\n', label=b'log.bookmark')
7195
7195
7196 status = repo.status(unknown=True)
7196 status = repo.status(unknown=True)
7197
7197
7198 c = repo.dirstate.copies()
7198 c = repo.dirstate.copies()
7199 copied, renamed = [], []
7199 copied, renamed = [], []
7200 for d, s in c.items():
7200 for d, s in c.items():
7201 if s in status.removed:
7201 if s in status.removed:
7202 status.removed.remove(s)
7202 status.removed.remove(s)
7203 renamed.append(d)
7203 renamed.append(d)
7204 else:
7204 else:
7205 copied.append(d)
7205 copied.append(d)
7206 if d in status.added:
7206 if d in status.added:
7207 status.added.remove(d)
7207 status.added.remove(d)
7208
7208
7209 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7209 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7210
7210
7211 labels = [
7211 labels = [
7212 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7212 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7213 (ui.label(_(b'%d added'), b'status.added'), status.added),
7213 (ui.label(_(b'%d added'), b'status.added'), status.added),
7214 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7214 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7215 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7215 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7216 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7216 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7217 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7217 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7218 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7218 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7219 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7219 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7220 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7220 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7221 ]
7221 ]
7222 t = []
7222 t = []
7223 for l, s in labels:
7223 for l, s in labels:
7224 if s:
7224 if s:
7225 t.append(l % len(s))
7225 t.append(l % len(s))
7226
7226
7227 t = b', '.join(t)
7227 t = b', '.join(t)
7228 cleanworkdir = False
7228 cleanworkdir = False
7229
7229
7230 if repo.vfs.exists(b'graftstate'):
7230 if repo.vfs.exists(b'graftstate'):
7231 t += _(b' (graft in progress)')
7231 t += _(b' (graft in progress)')
7232 if repo.vfs.exists(b'updatestate'):
7232 if repo.vfs.exists(b'updatestate'):
7233 t += _(b' (interrupted update)')
7233 t += _(b' (interrupted update)')
7234 elif len(parents) > 1:
7234 elif len(parents) > 1:
7235 t += _(b' (merge)')
7235 t += _(b' (merge)')
7236 elif branch != parents[0].branch():
7236 elif branch != parents[0].branch():
7237 t += _(b' (new branch)')
7237 t += _(b' (new branch)')
7238 elif parents[0].closesbranch() and pnode in repo.branchheads(
7238 elif parents[0].closesbranch() and pnode in repo.branchheads(
7239 branch, closed=True
7239 branch, closed=True
7240 ):
7240 ):
7241 t += _(b' (head closed)')
7241 t += _(b' (head closed)')
7242 elif not (
7242 elif not (
7243 status.modified
7243 status.modified
7244 or status.added
7244 or status.added
7245 or status.removed
7245 or status.removed
7246 or renamed
7246 or renamed
7247 or copied
7247 or copied
7248 or subs
7248 or subs
7249 ):
7249 ):
7250 t += _(b' (clean)')
7250 t += _(b' (clean)')
7251 cleanworkdir = True
7251 cleanworkdir = True
7252 elif pnode not in bheads:
7252 elif pnode not in bheads:
7253 t += _(b' (new branch head)')
7253 t += _(b' (new branch head)')
7254
7254
7255 if parents:
7255 if parents:
7256 pendingphase = max(p.phase() for p in parents)
7256 pendingphase = max(p.phase() for p in parents)
7257 else:
7257 else:
7258 pendingphase = phases.public
7258 pendingphase = phases.public
7259
7259
7260 if pendingphase > phases.newcommitphase(ui):
7260 if pendingphase > phases.newcommitphase(ui):
7261 t += b' (%s)' % phases.phasenames[pendingphase]
7261 t += b' (%s)' % phases.phasenames[pendingphase]
7262
7262
7263 if cleanworkdir:
7263 if cleanworkdir:
7264 # i18n: column positioning for "hg summary"
7264 # i18n: column positioning for "hg summary"
7265 ui.status(_(b'commit: %s\n') % t.strip())
7265 ui.status(_(b'commit: %s\n') % t.strip())
7266 else:
7266 else:
7267 # i18n: column positioning for "hg summary"
7267 # i18n: column positioning for "hg summary"
7268 ui.write(_(b'commit: %s\n') % t.strip())
7268 ui.write(_(b'commit: %s\n') % t.strip())
7269
7269
7270 # all ancestors of branch heads - all ancestors of parent = new csets
7270 # all ancestors of branch heads - all ancestors of parent = new csets
7271 new = len(
7271 new = len(
7272 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7272 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7273 )
7273 )
7274
7274
7275 if new == 0:
7275 if new == 0:
7276 # i18n: column positioning for "hg summary"
7276 # i18n: column positioning for "hg summary"
7277 ui.status(_(b'update: (current)\n'))
7277 ui.status(_(b'update: (current)\n'))
7278 elif pnode not in bheads:
7278 elif pnode not in bheads:
7279 # i18n: column positioning for "hg summary"
7279 # i18n: column positioning for "hg summary"
7280 ui.write(_(b'update: %d new changesets (update)\n') % new)
7280 ui.write(_(b'update: %d new changesets (update)\n') % new)
7281 else:
7281 else:
7282 # i18n: column positioning for "hg summary"
7282 # i18n: column positioning for "hg summary"
7283 ui.write(
7283 ui.write(
7284 _(b'update: %d new changesets, %d branch heads (merge)\n')
7284 _(b'update: %d new changesets, %d branch heads (merge)\n')
7285 % (new, len(bheads))
7285 % (new, len(bheads))
7286 )
7286 )
7287
7287
7288 t = []
7288 t = []
7289 draft = len(repo.revs(b'draft()'))
7289 draft = len(repo.revs(b'draft()'))
7290 if draft:
7290 if draft:
7291 t.append(_(b'%d draft') % draft)
7291 t.append(_(b'%d draft') % draft)
7292 secret = len(repo.revs(b'secret()'))
7292 secret = len(repo.revs(b'secret()'))
7293 if secret:
7293 if secret:
7294 t.append(_(b'%d secret') % secret)
7294 t.append(_(b'%d secret') % secret)
7295
7295
7296 if draft or secret:
7296 if draft or secret:
7297 ui.status(_(b'phases: %s\n') % b', '.join(t))
7297 ui.status(_(b'phases: %s\n') % b', '.join(t))
7298
7298
7299 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7299 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7300 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7300 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7301 numtrouble = len(repo.revs(trouble + b"()"))
7301 numtrouble = len(repo.revs(trouble + b"()"))
7302 # We write all the possibilities to ease translation
7302 # We write all the possibilities to ease translation
7303 troublemsg = {
7303 troublemsg = {
7304 b"orphan": _(b"orphan: %d changesets"),
7304 b"orphan": _(b"orphan: %d changesets"),
7305 b"contentdivergent": _(b"content-divergent: %d changesets"),
7305 b"contentdivergent": _(b"content-divergent: %d changesets"),
7306 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7306 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7307 }
7307 }
7308 if numtrouble > 0:
7308 if numtrouble > 0:
7309 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7309 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7310
7310
7311 cmdutil.summaryhooks(ui, repo)
7311 cmdutil.summaryhooks(ui, repo)
7312
7312
7313 if opts.get('remote'):
7313 if opts.get('remote'):
7314 needsincoming, needsoutgoing = True, True
7314 needsincoming, needsoutgoing = True, True
7315 else:
7315 else:
7316 needsincoming, needsoutgoing = False, False
7316 needsincoming, needsoutgoing = False, False
7317 for i, o in cmdutil.summaryremotehooks(
7317 for i, o in cmdutil.summaryremotehooks(
7318 ui, repo, pycompat.byteskwargs(opts), None
7318 ui, repo, pycompat.byteskwargs(opts), None
7319 ):
7319 ):
7320 if i:
7320 if i:
7321 needsincoming = True
7321 needsincoming = True
7322 if o:
7322 if o:
7323 needsoutgoing = True
7323 needsoutgoing = True
7324 if not needsincoming and not needsoutgoing:
7324 if not needsincoming and not needsoutgoing:
7325 return
7325 return
7326
7326
7327 def getincoming():
7327 def getincoming():
7328 # XXX We should actually skip this if no default is specified, instead
7328 # XXX We should actually skip this if no default is specified, instead
7329 # of passing "default" which will resolve as "./default/" if no default
7329 # of passing "default" which will resolve as "./default/" if no default
7330 # path is defined.
7330 # path is defined.
7331 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7331 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7332 sbranch = path.branch
7332 sbranch = path.branch
7333 try:
7333 try:
7334 other = hg.peer(repo, {}, path)
7334 other = hg.peer(repo, {}, path)
7335 except error.RepoError:
7335 except error.RepoError:
7336 if opts.get('remote'):
7336 if opts.get('remote'):
7337 raise
7337 raise
7338 return path.loc, sbranch, None, None, None
7338 return path.loc, sbranch, None, None, None
7339 branches = (path.branch, [])
7339 branches = (path.branch, [])
7340 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7340 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7341 if revs:
7341 if revs:
7342 revs = [other.lookup(rev) for rev in revs]
7342 revs = [other.lookup(rev) for rev in revs]
7343 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7343 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7344 with repo.ui.silent():
7344 with repo.ui.silent():
7345 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7345 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7346 return path.loc, sbranch, other, commoninc, commoninc[1]
7346 return path.loc, sbranch, other, commoninc, commoninc[1]
7347
7347
7348 if needsincoming:
7348 if needsincoming:
7349 source, sbranch, sother, commoninc, incoming = getincoming()
7349 source, sbranch, sother, commoninc, incoming = getincoming()
7350 else:
7350 else:
7351 source = sbranch = sother = commoninc = incoming = None
7351 source = sbranch = sother = commoninc = incoming = None
7352
7352
7353 def getoutgoing():
7353 def getoutgoing():
7354 # XXX We should actually skip this if no default is specified, instead
7354 # XXX We should actually skip this if no default is specified, instead
7355 # of passing "default" which will resolve as "./default/" if no default
7355 # of passing "default" which will resolve as "./default/" if no default
7356 # path is defined.
7356 # path is defined.
7357 d = None
7357 d = None
7358 if b'default-push' in ui.paths:
7358 if b'default-push' in ui.paths:
7359 d = b'default-push'
7359 d = b'default-push'
7360 elif b'default' in ui.paths:
7360 elif b'default' in ui.paths:
7361 d = b'default'
7361 d = b'default'
7362 path = None
7362 path = None
7363 if d is not None:
7363 if d is not None:
7364 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7364 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7365 dest = path.loc
7365 dest = path.loc
7366 dbranch = path.branch
7366 dbranch = path.branch
7367 else:
7367 else:
7368 dest = b'default'
7368 dest = b'default'
7369 dbranch = None
7369 dbranch = None
7370 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7370 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7371 if source != dest:
7371 if source != dest:
7372 try:
7372 try:
7373 dother = hg.peer(repo, {}, path if path is not None else dest)
7373 dother = hg.peer(repo, {}, path if path is not None else dest)
7374 except error.RepoError:
7374 except error.RepoError:
7375 if opts.get('remote'):
7375 if opts.get('remote'):
7376 raise
7376 raise
7377 return dest, dbranch, None, None
7377 return dest, dbranch, None, None
7378 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7378 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7379 elif sother is None:
7379 elif sother is None:
7380 # there is no explicit destination peer, but source one is invalid
7380 # there is no explicit destination peer, but source one is invalid
7381 return dest, dbranch, None, None
7381 return dest, dbranch, None, None
7382 else:
7382 else:
7383 dother = sother
7383 dother = sother
7384 if source != dest or (sbranch is not None and sbranch != dbranch):
7384 if source != dest or (sbranch is not None and sbranch != dbranch):
7385 common = None
7385 common = None
7386 else:
7386 else:
7387 common = commoninc
7387 common = commoninc
7388 if revs:
7388 if revs:
7389 revs = [repo.lookup(rev) for rev in revs]
7389 revs = [repo.lookup(rev) for rev in revs]
7390 with repo.ui.silent():
7390 with repo.ui.silent():
7391 outgoing = discovery.findcommonoutgoing(
7391 outgoing = discovery.findcommonoutgoing(
7392 repo, dother, onlyheads=revs, commoninc=common
7392 repo, dother, onlyheads=revs, commoninc=common
7393 )
7393 )
7394 return dest, dbranch, dother, outgoing
7394 return dest, dbranch, dother, outgoing
7395
7395
7396 if needsoutgoing:
7396 if needsoutgoing:
7397 dest, dbranch, dother, outgoing = getoutgoing()
7397 dest, dbranch, dother, outgoing = getoutgoing()
7398 else:
7398 else:
7399 dest = dbranch = dother = outgoing = None
7399 dest = dbranch = dother = outgoing = None
7400
7400
7401 if opts.get('remote'):
7401 if opts.get('remote'):
7402 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7402 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7403 # The former always sets `sother` (or raises an exception if it can't);
7403 # The former always sets `sother` (or raises an exception if it can't);
7404 # the latter always sets `outgoing`.
7404 # the latter always sets `outgoing`.
7405 assert sother is not None
7405 assert sother is not None
7406 assert outgoing is not None
7406 assert outgoing is not None
7407
7407
7408 t = []
7408 t = []
7409 if incoming:
7409 if incoming:
7410 t.append(_(b'1 or more incoming'))
7410 t.append(_(b'1 or more incoming'))
7411 o = outgoing.missing
7411 o = outgoing.missing
7412 if o:
7412 if o:
7413 t.append(_(b'%d outgoing') % len(o))
7413 t.append(_(b'%d outgoing') % len(o))
7414 other = dother or sother
7414 other = dother or sother
7415 if b'bookmarks' in other.listkeys(b'namespaces'):
7415 if b'bookmarks' in other.listkeys(b'namespaces'):
7416 counts = bookmarks.summary(repo, other)
7416 counts = bookmarks.summary(repo, other)
7417 if counts[0] > 0:
7417 if counts[0] > 0:
7418 t.append(_(b'%d incoming bookmarks') % counts[0])
7418 t.append(_(b'%d incoming bookmarks') % counts[0])
7419 if counts[1] > 0:
7419 if counts[1] > 0:
7420 t.append(_(b'%d outgoing bookmarks') % counts[1])
7420 t.append(_(b'%d outgoing bookmarks') % counts[1])
7421
7421
7422 if t:
7422 if t:
7423 # i18n: column positioning for "hg summary"
7423 # i18n: column positioning for "hg summary"
7424 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7424 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7425 else:
7425 else:
7426 # i18n: column positioning for "hg summary"
7426 # i18n: column positioning for "hg summary"
7427 ui.status(_(b'remote: (synced)\n'))
7427 ui.status(_(b'remote: (synced)\n'))
7428
7428
7429 cmdutil.summaryremotehooks(
7429 cmdutil.summaryremotehooks(
7430 ui,
7430 ui,
7431 repo,
7431 repo,
7432 pycompat.byteskwargs(opts),
7432 pycompat.byteskwargs(opts),
7433 (
7433 (
7434 (source, sbranch, sother, commoninc),
7434 (source, sbranch, sother, commoninc),
7435 (dest, dbranch, dother, outgoing),
7435 (dest, dbranch, dother, outgoing),
7436 ),
7436 ),
7437 )
7437 )
7438
7438
7439
7439
7440 @command(
7440 @command(
7441 b'tag',
7441 b'tag',
7442 [
7442 [
7443 (b'f', b'force', None, _(b'force tag')),
7443 (b'f', b'force', None, _(b'force tag')),
7444 (b'l', b'local', None, _(b'make the tag local')),
7444 (b'l', b'local', None, _(b'make the tag local')),
7445 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7445 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7446 (b'', b'remove', None, _(b'remove a tag')),
7446 (b'', b'remove', None, _(b'remove a tag')),
7447 # -l/--local is already there, commitopts cannot be used
7447 # -l/--local is already there, commitopts cannot be used
7448 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7448 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7449 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7449 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7450 ]
7450 ]
7451 + commitopts2,
7451 + commitopts2,
7452 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7452 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7453 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7453 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7454 )
7454 )
7455 def tag(ui, repo, name1, *names, **opts):
7455 def tag(ui, repo, name1, *names, **opts):
7456 """add one or more tags for the current or given revision
7456 """add one or more tags for the current or given revision
7457
7457
7458 Name a particular revision using <name>.
7458 Name a particular revision using <name>.
7459
7459
7460 Tags are used to name particular revisions of the repository and are
7460 Tags are used to name particular revisions of the repository and are
7461 very useful to compare different revisions, to go back to significant
7461 very useful to compare different revisions, to go back to significant
7462 earlier versions or to mark branch points as releases, etc. Changing
7462 earlier versions or to mark branch points as releases, etc. Changing
7463 an existing tag is normally disallowed; use -f/--force to override.
7463 an existing tag is normally disallowed; use -f/--force to override.
7464
7464
7465 If no revision is given, the parent of the working directory is
7465 If no revision is given, the parent of the working directory is
7466 used.
7466 used.
7467
7467
7468 To facilitate version control, distribution, and merging of tags,
7468 To facilitate version control, distribution, and merging of tags,
7469 they are stored as a file named ".hgtags" which is managed similarly
7469 they are stored as a file named ".hgtags" which is managed similarly
7470 to other project files and can be hand-edited if necessary. This
7470 to other project files and can be hand-edited if necessary. This
7471 also means that tagging creates a new commit. The file
7471 also means that tagging creates a new commit. The file
7472 ".hg/localtags" is used for local tags (not shared among
7472 ".hg/localtags" is used for local tags (not shared among
7473 repositories).
7473 repositories).
7474
7474
7475 Tag commits are usually made at the head of a branch. If the parent
7475 Tag commits are usually made at the head of a branch. If the parent
7476 of the working directory is not a branch head, :hg:`tag` aborts; use
7476 of the working directory is not a branch head, :hg:`tag` aborts; use
7477 -f/--force to force the tag commit to be based on a non-head
7477 -f/--force to force the tag commit to be based on a non-head
7478 changeset.
7478 changeset.
7479
7479
7480 See :hg:`help dates` for a list of formats valid for -d/--date.
7480 See :hg:`help dates` for a list of formats valid for -d/--date.
7481
7481
7482 Since tag names have priority over branch names during revision
7482 Since tag names have priority over branch names during revision
7483 lookup, using an existing branch name as a tag name is discouraged.
7483 lookup, using an existing branch name as a tag name is discouraged.
7484
7484
7485 Returns 0 on success.
7485 Returns 0 on success.
7486 """
7486 """
7487 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7487 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7488
7488
7489 with repo.wlock(), repo.lock():
7489 with repo.wlock(), repo.lock():
7490 rev_ = b"."
7490 rev_ = b"."
7491 names = [t.strip() for t in (name1,) + names]
7491 names = [t.strip() for t in (name1,) + names]
7492 if len(names) != len(set(names)):
7492 if len(names) != len(set(names)):
7493 raise error.InputError(_(b'tag names must be unique'))
7493 raise error.InputError(_(b'tag names must be unique'))
7494 for n in names:
7494 for n in names:
7495 scmutil.checknewlabel(repo, n, b'tag')
7495 scmutil.checknewlabel(repo, n, b'tag')
7496 if not n:
7496 if not n:
7497 raise error.InputError(
7497 raise error.InputError(
7498 _(b'tag names cannot consist entirely of whitespace')
7498 _(b'tag names cannot consist entirely of whitespace')
7499 )
7499 )
7500 if opts.get('rev'):
7500 if opts.get('rev'):
7501 rev_ = opts['rev']
7501 rev_ = opts['rev']
7502 message = opts.get('message')
7502 message = opts.get('message')
7503 if opts.get('remove'):
7503 if opts.get('remove'):
7504 if opts.get('local'):
7504 if opts.get('local'):
7505 expectedtype = b'local'
7505 expectedtype = b'local'
7506 else:
7506 else:
7507 expectedtype = b'global'
7507 expectedtype = b'global'
7508
7508
7509 for n in names:
7509 for n in names:
7510 if repo.tagtype(n) == b'global':
7510 if repo.tagtype(n) == b'global':
7511 alltags = tagsmod.findglobaltags(ui, repo)
7511 alltags = tagsmod.findglobaltags(ui, repo)
7512 if alltags[n][0] == repo.nullid:
7512 if alltags[n][0] == repo.nullid:
7513 raise error.InputError(
7513 raise error.InputError(
7514 _(b"tag '%s' is already removed") % n
7514 _(b"tag '%s' is already removed") % n
7515 )
7515 )
7516 if not repo.tagtype(n):
7516 if not repo.tagtype(n):
7517 raise error.InputError(_(b"tag '%s' does not exist") % n)
7517 raise error.InputError(_(b"tag '%s' does not exist") % n)
7518 if repo.tagtype(n) != expectedtype:
7518 if repo.tagtype(n) != expectedtype:
7519 if expectedtype == b'global':
7519 if expectedtype == b'global':
7520 raise error.InputError(
7520 raise error.InputError(
7521 _(b"tag '%s' is not a global tag") % n
7521 _(b"tag '%s' is not a global tag") % n
7522 )
7522 )
7523 else:
7523 else:
7524 raise error.InputError(
7524 raise error.InputError(
7525 _(b"tag '%s' is not a local tag") % n
7525 _(b"tag '%s' is not a local tag") % n
7526 )
7526 )
7527 rev_ = b'null'
7527 rev_ = b'null'
7528 if not message:
7528 if not message:
7529 # we don't translate commit messages
7529 # we don't translate commit messages
7530 message = b'Removed tag %s' % b', '.join(names)
7530 message = b'Removed tag %s' % b', '.join(names)
7531 elif not opts.get('force'):
7531 elif not opts.get('force'):
7532 for n in names:
7532 for n in names:
7533 if n in repo.tags():
7533 if n in repo.tags():
7534 raise error.InputError(
7534 raise error.InputError(
7535 _(b"tag '%s' already exists (use -f to force)") % n
7535 _(b"tag '%s' already exists (use -f to force)") % n
7536 )
7536 )
7537 if not opts.get('local'):
7537 if not opts.get('local'):
7538 p1, p2 = repo.dirstate.parents()
7538 p1, p2 = repo.dirstate.parents()
7539 if p2 != repo.nullid:
7539 if p2 != repo.nullid:
7540 raise error.StateError(_(b'uncommitted merge'))
7540 raise error.StateError(_(b'uncommitted merge'))
7541 bheads = repo.branchheads()
7541 bheads = repo.branchheads()
7542 if not opts.get('force') and bheads and p1 not in bheads:
7542 if not opts.get('force') and bheads and p1 not in bheads:
7543 raise error.InputError(
7543 raise error.InputError(
7544 _(
7544 _(
7545 b'working directory is not at a branch head '
7545 b'working directory is not at a branch head '
7546 b'(use -f to force)'
7546 b'(use -f to force)'
7547 )
7547 )
7548 )
7548 )
7549 node = logcmdutil.revsingle(repo, rev_).node()
7549 node = logcmdutil.revsingle(repo, rev_).node()
7550
7550
7551 # don't allow tagging the null rev or the working directory
7551 # don't allow tagging the null rev or the working directory
7552 if node is None:
7552 if node is None:
7553 raise error.InputError(_(b"cannot tag working directory"))
7553 raise error.InputError(_(b"cannot tag working directory"))
7554 elif not opts.get('remove') and node == nullid:
7554 elif not opts.get('remove') and node == nullid:
7555 raise error.InputError(_(b"cannot tag null revision"))
7555 raise error.InputError(_(b"cannot tag null revision"))
7556
7556
7557 if not message:
7557 if not message:
7558 # we don't translate commit messages
7558 # we don't translate commit messages
7559 message = b'Added tag %s for changeset %s' % (
7559 message = b'Added tag %s for changeset %s' % (
7560 b', '.join(names),
7560 b', '.join(names),
7561 short(node),
7561 short(node),
7562 )
7562 )
7563
7563
7564 date = opts.get('date')
7564 date = opts.get('date')
7565 if date:
7565 if date:
7566 date = dateutil.parsedate(date)
7566 date = dateutil.parsedate(date)
7567
7567
7568 if opts.get('remove'):
7568 if opts.get('remove'):
7569 editform = b'tag.remove'
7569 editform = b'tag.remove'
7570 else:
7570 else:
7571 editform = b'tag.add'
7571 editform = b'tag.add'
7572 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7572 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7573
7573
7574 tagsmod.tag(
7574 tagsmod.tag(
7575 repo,
7575 repo,
7576 names,
7576 names,
7577 node,
7577 node,
7578 message,
7578 message,
7579 opts.get('local'),
7579 opts.get('local'),
7580 opts.get('user'),
7580 opts.get('user'),
7581 date,
7581 date,
7582 editor=editor,
7582 editor=editor,
7583 )
7583 )
7584
7584
7585
7585
7586 @command(
7586 @command(
7587 b'tags',
7587 b'tags',
7588 formatteropts,
7588 formatteropts,
7589 b'',
7589 b'',
7590 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7590 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7591 intents={INTENT_READONLY},
7591 intents={INTENT_READONLY},
7592 )
7592 )
7593 def tags(ui, repo, **opts):
7593 def tags(ui, repo, **opts):
7594 """list repository tags
7594 """list repository tags
7595
7595
7596 This lists both regular and local tags. When the -v/--verbose
7596 This lists both regular and local tags. When the -v/--verbose
7597 switch is used, a third column "local" is printed for local tags.
7597 switch is used, a third column "local" is printed for local tags.
7598 When the -q/--quiet switch is used, only the tag name is printed.
7598 When the -q/--quiet switch is used, only the tag name is printed.
7599
7599
7600 .. container:: verbose
7600 .. container:: verbose
7601
7601
7602 Template:
7602 Template:
7603
7603
7604 The following keywords are supported in addition to the common template
7604 The following keywords are supported in addition to the common template
7605 keywords and functions such as ``{tag}``. See also
7605 keywords and functions such as ``{tag}``. See also
7606 :hg:`help templates`.
7606 :hg:`help templates`.
7607
7607
7608 :type: String. ``local`` for local tags.
7608 :type: String. ``local`` for local tags.
7609
7609
7610 Returns 0 on success.
7610 Returns 0 on success.
7611 """
7611 """
7612
7612
7613 ui.pager(b'tags')
7613 ui.pager(b'tags')
7614 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7614 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7615 hexfunc = fm.hexfunc
7615 hexfunc = fm.hexfunc
7616
7616
7617 for t, n in reversed(repo.tagslist()):
7617 for t, n in reversed(repo.tagslist()):
7618 hn = hexfunc(n)
7618 hn = hexfunc(n)
7619 label = b'tags.normal'
7619 label = b'tags.normal'
7620 tagtype = repo.tagtype(t)
7620 tagtype = repo.tagtype(t)
7621 if not tagtype or tagtype == b'global':
7621 if not tagtype or tagtype == b'global':
7622 tagtype = b''
7622 tagtype = b''
7623 else:
7623 else:
7624 label = b'tags.' + tagtype
7624 label = b'tags.' + tagtype
7625
7625
7626 fm.startitem()
7626 fm.startitem()
7627 fm.context(repo=repo)
7627 fm.context(repo=repo)
7628 fm.write(b'tag', b'%s', t, label=label)
7628 fm.write(b'tag', b'%s', t, label=label)
7629 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7629 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7630 fm.condwrite(
7630 fm.condwrite(
7631 not ui.quiet,
7631 not ui.quiet,
7632 b'rev node',
7632 b'rev node',
7633 fmt,
7633 fmt,
7634 repo.changelog.rev(n),
7634 repo.changelog.rev(n),
7635 hn,
7635 hn,
7636 label=label,
7636 label=label,
7637 )
7637 )
7638 fm.condwrite(
7638 fm.condwrite(
7639 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7639 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7640 )
7640 )
7641 fm.plain(b'\n')
7641 fm.plain(b'\n')
7642 fm.end()
7642 fm.end()
7643
7643
7644
7644
7645 @command(
7645 @command(
7646 b'tip',
7646 b'tip',
7647 [
7647 [
7648 (b'p', b'patch', None, _(b'show patch')),
7648 (b'p', b'patch', None, _(b'show patch')),
7649 (b'g', b'git', None, _(b'use git extended diff format')),
7649 (b'g', b'git', None, _(b'use git extended diff format')),
7650 ]
7650 ]
7651 + templateopts,
7651 + templateopts,
7652 _(b'[-p] [-g]'),
7652 _(b'[-p] [-g]'),
7653 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7653 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7654 )
7654 )
7655 def tip(ui, repo, **opts):
7655 def tip(ui, repo, **opts):
7656 """show the tip revision (DEPRECATED)
7656 """show the tip revision (DEPRECATED)
7657
7657
7658 The tip revision (usually just called the tip) is the changeset
7658 The tip revision (usually just called the tip) is the changeset
7659 most recently added to the repository (and therefore the most
7659 most recently added to the repository (and therefore the most
7660 recently changed head).
7660 recently changed head).
7661
7661
7662 If you have just made a commit, that commit will be the tip. If
7662 If you have just made a commit, that commit will be the tip. If
7663 you have just pulled changes from another repository, the tip of
7663 you have just pulled changes from another repository, the tip of
7664 that repository becomes the current tip. The "tip" tag is special
7664 that repository becomes the current tip. The "tip" tag is special
7665 and cannot be renamed or assigned to a different changeset.
7665 and cannot be renamed or assigned to a different changeset.
7666
7666
7667 This command is deprecated, please use :hg:`heads` instead.
7667 This command is deprecated, please use :hg:`heads` instead.
7668
7668
7669 Returns 0 on success.
7669 Returns 0 on success.
7670 """
7670 """
7671 opts = pycompat.byteskwargs(opts)
7671 opts = pycompat.byteskwargs(opts)
7672 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7672 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7673 displayer.show(repo[b'tip'])
7673 displayer.show(repo[b'tip'])
7674 displayer.close()
7674 displayer.close()
7675
7675
7676
7676
7677 @command(
7677 @command(
7678 b'unbundle',
7678 b'unbundle',
7679 [
7679 [
7680 (
7680 (
7681 b'u',
7681 b'u',
7682 b'update',
7682 b'update',
7683 None,
7683 None,
7684 _(b'update to new branch head if changesets were unbundled'),
7684 _(b'update to new branch head if changesets were unbundled'),
7685 )
7685 )
7686 ],
7686 ],
7687 _(b'[-u] FILE...'),
7687 _(b'[-u] FILE...'),
7688 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7688 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7689 )
7689 )
7690 def unbundle(ui, repo, fname1, *fnames, **opts):
7690 def unbundle(ui, repo, fname1, *fnames, **opts):
7691 """apply one or more bundle files
7691 """apply one or more bundle files
7692
7692
7693 Apply one or more bundle files generated by :hg:`bundle`.
7693 Apply one or more bundle files generated by :hg:`bundle`.
7694
7694
7695 Returns 0 on success, 1 if an update has unresolved files.
7695 Returns 0 on success, 1 if an update has unresolved files.
7696 """
7696 """
7697 fnames = (fname1,) + fnames
7697 fnames = (fname1,) + fnames
7698
7698
7699 with repo.lock():
7699 with repo.lock():
7700 for fname in fnames:
7700 for fname in fnames:
7701 f = hg.openpath(ui, fname)
7701 f = hg.openpath(ui, fname)
7702 gen = exchange.readbundle(ui, f, fname)
7702 gen = exchange.readbundle(ui, f, fname)
7703 if isinstance(gen, streamclone.streamcloneapplier):
7703 if isinstance(gen, streamclone.streamcloneapplier):
7704 raise error.InputError(
7704 raise error.InputError(
7705 _(
7705 _(
7706 b'packed bundles cannot be applied with '
7706 b'packed bundles cannot be applied with '
7707 b'"hg unbundle"'
7707 b'"hg unbundle"'
7708 ),
7708 ),
7709 hint=_(b'use "hg debugapplystreamclonebundle"'),
7709 hint=_(b'use "hg debugapplystreamclonebundle"'),
7710 )
7710 )
7711 url = b'bundle:' + fname
7711 url = b'bundle:' + fname
7712 try:
7712 try:
7713 txnname = b'unbundle'
7713 txnname = b'unbundle'
7714 if not isinstance(gen, bundle2.unbundle20):
7714 if not isinstance(gen, bundle2.unbundle20):
7715 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7715 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7716 with repo.transaction(txnname) as tr:
7716 with repo.transaction(txnname) as tr:
7717 op = bundle2.applybundle(
7717 op = bundle2.applybundle(
7718 repo, gen, tr, source=b'unbundle', url=url
7718 repo, gen, tr, source=b'unbundle', url=url
7719 )
7719 )
7720 except error.BundleUnknownFeatureError as exc:
7720 except error.BundleUnknownFeatureError as exc:
7721 raise error.Abort(
7721 raise error.Abort(
7722 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7722 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7723 hint=_(
7723 hint=_(
7724 b"see https://mercurial-scm.org/"
7724 b"see https://mercurial-scm.org/"
7725 b"wiki/BundleFeature for more "
7725 b"wiki/BundleFeature for more "
7726 b"information"
7726 b"information"
7727 ),
7727 ),
7728 )
7728 )
7729 modheads = bundle2.combinechangegroupresults(op)
7729 modheads = bundle2.combinechangegroupresults(op)
7730
7730
7731 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7731 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7732 return 1
7732 return 1
7733 else:
7733 else:
7734 return 0
7734 return 0
7735
7735
7736
7736
7737 @command(
7737 @command(
7738 b'unshelve',
7738 b'unshelve',
7739 [
7739 [
7740 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7740 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7741 (
7741 (
7742 b'c',
7742 b'c',
7743 b'continue',
7743 b'continue',
7744 None,
7744 None,
7745 _(b'continue an incomplete unshelve operation'),
7745 _(b'continue an incomplete unshelve operation'),
7746 ),
7746 ),
7747 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7747 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7748 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7748 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7749 (
7749 (
7750 b'n',
7750 b'n',
7751 b'name',
7751 b'name',
7752 b'',
7752 b'',
7753 _(b'restore shelved change with given name'),
7753 _(b'restore shelved change with given name'),
7754 _(b'NAME'),
7754 _(b'NAME'),
7755 ),
7755 ),
7756 (b't', b'tool', b'', _(b'specify merge tool')),
7756 (b't', b'tool', b'', _(b'specify merge tool')),
7757 (
7757 (
7758 b'',
7758 b'',
7759 b'date',
7759 b'date',
7760 b'',
7760 b'',
7761 _(b'set date for temporary commits (DEPRECATED)'),
7761 _(b'set date for temporary commits (DEPRECATED)'),
7762 _(b'DATE'),
7762 _(b'DATE'),
7763 ),
7763 ),
7764 ],
7764 ],
7765 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7765 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7766 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7766 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7767 )
7767 )
7768 def unshelve(ui, repo, *shelved, **opts):
7768 def unshelve(ui, repo, *shelved, **opts):
7769 """restore a shelved change to the working directory
7769 """restore a shelved change to the working directory
7770
7770
7771 This command accepts an optional name of a shelved change to
7771 This command accepts an optional name of a shelved change to
7772 restore. If none is given, the most recent shelved change is used.
7772 restore. If none is given, the most recent shelved change is used.
7773
7773
7774 If a shelved change is applied successfully, the bundle that
7774 If a shelved change is applied successfully, the bundle that
7775 contains the shelved changes is moved to a backup location
7775 contains the shelved changes is moved to a backup location
7776 (.hg/shelve-backup).
7776 (.hg/shelve-backup).
7777
7777
7778 Since you can restore a shelved change on top of an arbitrary
7778 Since you can restore a shelved change on top of an arbitrary
7779 commit, it is possible that unshelving will result in a conflict
7779 commit, it is possible that unshelving will result in a conflict
7780 between your changes and the commits you are unshelving onto. If
7780 between your changes and the commits you are unshelving onto. If
7781 this occurs, you must resolve the conflict, then use
7781 this occurs, you must resolve the conflict, then use
7782 ``--continue`` to complete the unshelve operation. (The bundle
7782 ``--continue`` to complete the unshelve operation. (The bundle
7783 will not be moved until you successfully complete the unshelve.)
7783 will not be moved until you successfully complete the unshelve.)
7784
7784
7785 (Alternatively, you can use ``--abort`` to abandon an unshelve
7785 (Alternatively, you can use ``--abort`` to abandon an unshelve
7786 that causes a conflict. This reverts the unshelved changes, and
7786 that causes a conflict. This reverts the unshelved changes, and
7787 leaves the bundle in place.)
7787 leaves the bundle in place.)
7788
7788
7789 If bare shelved change (without interactive, include and exclude
7789 If bare shelved change (without interactive, include and exclude
7790 option) was done on newly created branch it would restore branch
7790 option) was done on newly created branch it would restore branch
7791 information to the working directory.
7791 information to the working directory.
7792
7792
7793 After a successful unshelve, the shelved changes are stored in a
7793 After a successful unshelve, the shelved changes are stored in a
7794 backup directory. Only the N most recent backups are kept. N
7794 backup directory. Only the N most recent backups are kept. N
7795 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7795 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7796 configuration option.
7796 configuration option.
7797
7797
7798 .. container:: verbose
7798 .. container:: verbose
7799
7799
7800 Timestamp in seconds is used to decide order of backups. More
7800 Timestamp in seconds is used to decide order of backups. More
7801 than ``maxbackups`` backups are kept, if same timestamp
7801 than ``maxbackups`` backups are kept, if same timestamp
7802 prevents from deciding exact order of them, for safety.
7802 prevents from deciding exact order of them, for safety.
7803
7803
7804 Selected changes can be unshelved with ``--interactive`` flag.
7804 Selected changes can be unshelved with ``--interactive`` flag.
7805 The working directory is updated with the selected changes, and
7805 The working directory is updated with the selected changes, and
7806 only the unselected changes remain shelved.
7806 only the unselected changes remain shelved.
7807 Note: The whole shelve is applied to working directory first before
7807 Note: The whole shelve is applied to working directory first before
7808 running interactively. So, this will bring up all the conflicts between
7808 running interactively. So, this will bring up all the conflicts between
7809 working directory and the shelve, irrespective of which changes will be
7809 working directory and the shelve, irrespective of which changes will be
7810 unshelved.
7810 unshelved.
7811 """
7811 """
7812 with repo.wlock():
7812 with repo.wlock():
7813 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7813 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7814
7814
7815
7815
7816 statemod.addunfinished(
7816 statemod.addunfinished(
7817 b'unshelve',
7817 b'unshelve',
7818 fname=b'shelvedstate',
7818 fname=b'shelvedstate',
7819 continueflag=True,
7819 continueflag=True,
7820 abortfunc=shelvemod.hgabortunshelve,
7820 abortfunc=shelvemod.hgabortunshelve,
7821 continuefunc=shelvemod.hgcontinueunshelve,
7821 continuefunc=shelvemod.hgcontinueunshelve,
7822 cmdmsg=_(b'unshelve already in progress'),
7822 cmdmsg=_(b'unshelve already in progress'),
7823 )
7823 )
7824
7824
7825
7825
7826 @command(
7826 @command(
7827 b'update|up|checkout|co',
7827 b'update|up|checkout|co',
7828 [
7828 [
7829 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7829 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7830 (b'c', b'check', None, _(b'require clean working directory')),
7830 (b'c', b'check', None, _(b'require clean working directory')),
7831 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7831 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7832 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7832 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7833 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7833 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7834 ]
7834 ]
7835 + mergetoolopts,
7835 + mergetoolopts,
7836 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7836 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7837 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7837 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7838 helpbasic=True,
7838 helpbasic=True,
7839 )
7839 )
7840 def update(ui, repo, node=None, **opts):
7840 def update(ui, repo, node=None, **opts):
7841 """update working directory (or switch revisions)
7841 """update working directory (or switch revisions)
7842
7842
7843 Update the repository's working directory to the specified
7843 Update the repository's working directory to the specified
7844 changeset. If no changeset is specified, update to the tip of the
7844 changeset. If no changeset is specified, update to the tip of the
7845 current named branch and move the active bookmark (see :hg:`help
7845 current named branch and move the active bookmark (see :hg:`help
7846 bookmarks`).
7846 bookmarks`).
7847
7847
7848 Update sets the working directory's parent revision to the specified
7848 Update sets the working directory's parent revision to the specified
7849 changeset (see :hg:`help parents`).
7849 changeset (see :hg:`help parents`).
7850
7850
7851 If the changeset is not a descendant or ancestor of the working
7851 If the changeset is not a descendant or ancestor of the working
7852 directory's parent and there are uncommitted changes, the update is
7852 directory's parent and there are uncommitted changes, the update is
7853 aborted. With the -c/--check option, the working directory is checked
7853 aborted. With the -c/--check option, the working directory is checked
7854 for uncommitted changes; if none are found, the working directory is
7854 for uncommitted changes; if none are found, the working directory is
7855 updated to the specified changeset.
7855 updated to the specified changeset.
7856
7856
7857 .. container:: verbose
7857 .. container:: verbose
7858
7858
7859 The -C/--clean, -c/--check, and -m/--merge options control what
7859 The -C/--clean, -c/--check, and -m/--merge options control what
7860 happens if the working directory contains uncommitted changes.
7860 happens if the working directory contains uncommitted changes.
7861 At most of one of them can be specified.
7861 At most of one of them can be specified.
7862
7862
7863 1. If no option is specified, and if
7863 1. If no option is specified, and if
7864 the requested changeset is an ancestor or descendant of
7864 the requested changeset is an ancestor or descendant of
7865 the working directory's parent, the uncommitted changes
7865 the working directory's parent, the uncommitted changes
7866 are merged into the requested changeset and the merged
7866 are merged into the requested changeset and the merged
7867 result is left uncommitted. If the requested changeset is
7867 result is left uncommitted. If the requested changeset is
7868 not an ancestor or descendant (that is, it is on another
7868 not an ancestor or descendant (that is, it is on another
7869 branch), the update is aborted and the uncommitted changes
7869 branch), the update is aborted and the uncommitted changes
7870 are preserved.
7870 are preserved.
7871
7871
7872 2. With the -m/--merge option, the update is allowed even if the
7872 2. With the -m/--merge option, the update is allowed even if the
7873 requested changeset is not an ancestor or descendant of
7873 requested changeset is not an ancestor or descendant of
7874 the working directory's parent.
7874 the working directory's parent.
7875
7875
7876 3. With the -c/--check option, the update is aborted and the
7876 3. With the -c/--check option, the update is aborted and the
7877 uncommitted changes are preserved.
7877 uncommitted changes are preserved.
7878
7878
7879 4. With the -C/--clean option, uncommitted changes are discarded and
7879 4. With the -C/--clean option, uncommitted changes are discarded and
7880 the working directory is updated to the requested changeset.
7880 the working directory is updated to the requested changeset.
7881
7881
7882 To cancel an uncommitted merge (and lose your changes), use
7882 To cancel an uncommitted merge (and lose your changes), use
7883 :hg:`merge --abort`.
7883 :hg:`merge --abort`.
7884
7884
7885 Use null as the changeset to remove the working directory (like
7885 Use null as the changeset to remove the working directory (like
7886 :hg:`clone -U`).
7886 :hg:`clone -U`).
7887
7887
7888 If you want to revert just one file to an older revision, use
7888 If you want to revert just one file to an older revision, use
7889 :hg:`revert [-r REV] NAME`.
7889 :hg:`revert [-r REV] NAME`.
7890
7890
7891 See :hg:`help dates` for a list of formats valid for -d/--date.
7891 See :hg:`help dates` for a list of formats valid for -d/--date.
7892
7892
7893 Returns 0 on success, 1 if there are unresolved files.
7893 Returns 0 on success, 1 if there are unresolved files.
7894 """
7894 """
7895 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7895 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7896 rev = opts.get('rev')
7896 rev = opts.get('rev')
7897 date = opts.get('date')
7897 date = opts.get('date')
7898 clean = opts.get('clean')
7898 clean = opts.get('clean')
7899 check = opts.get('check')
7899 check = opts.get('check')
7900 merge = opts.get('merge')
7900 merge = opts.get('merge')
7901 if rev and node:
7901 if rev and node:
7902 raise error.InputError(_(b"please specify just one revision"))
7902 raise error.InputError(_(b"please specify just one revision"))
7903
7903
7904 if ui.configbool(b'commands', b'update.requiredest'):
7904 if ui.configbool(b'commands', b'update.requiredest'):
7905 if not node and not rev and not date:
7905 if not node and not rev and not date:
7906 raise error.InputError(
7906 raise error.InputError(
7907 _(b'you must specify a destination'),
7907 _(b'you must specify a destination'),
7908 hint=_(b'for example: hg update ".::"'),
7908 hint=_(b'for example: hg update ".::"'),
7909 )
7909 )
7910
7910
7911 if rev is None or rev == b'':
7911 if rev is None or rev == b'':
7912 rev = node
7912 rev = node
7913
7913
7914 if date and rev is not None:
7914 if date and rev is not None:
7915 raise error.InputError(_(b"you can't specify a revision and a date"))
7915 raise error.InputError(_(b"you can't specify a revision and a date"))
7916
7916
7917 updatecheck = None
7917 updatecheck = None
7918 if check or merge is not None and not merge:
7918 if check or merge is not None and not merge:
7919 updatecheck = b'abort'
7919 updatecheck = b'abort'
7920 elif merge or check is not None and not check:
7920 elif merge or check is not None and not check:
7921 updatecheck = b'none'
7921 updatecheck = b'none'
7922
7922
7923 with repo.wlock():
7923 with repo.wlock():
7924 cmdutil.clearunfinished(repo)
7924 cmdutil.clearunfinished(repo)
7925 if date:
7925 if date:
7926 rev = cmdutil.finddate(ui, repo, date)
7926 rev = cmdutil.finddate(ui, repo, date)
7927
7927
7928 # if we defined a bookmark, we have to remember the original name
7928 # if we defined a bookmark, we have to remember the original name
7929 brev = rev
7929 brev = rev
7930 if rev:
7930 if rev:
7931 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7931 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7932 ctx = logcmdutil.revsingle(repo, rev, default=None)
7932 ctx = logcmdutil.revsingle(repo, rev, default=None)
7933 rev = ctx.rev()
7933 rev = ctx.rev()
7934 hidden = ctx.hidden()
7934 hidden = ctx.hidden()
7935 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7935 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7936 with ui.configoverride(overrides, b'update'):
7936 with ui.configoverride(overrides, b'update'):
7937 ret = hg.updatetotally(
7937 ret = hg.updatetotally(
7938 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7938 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7939 )
7939 )
7940 if hidden:
7940 if hidden:
7941 ctxstr = ctx.hex()[:12]
7941 ctxstr = ctx.hex()[:12]
7942 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7942 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7943
7943
7944 if ctx.obsolete():
7944 if ctx.obsolete():
7945 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7945 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7946 ui.warn(b"(%s)\n" % obsfatemsg)
7946 ui.warn(b"(%s)\n" % obsfatemsg)
7947 return ret
7947 return ret
7948
7948
7949
7949
7950 @command(
7950 @command(
7951 b'verify',
7951 b'verify',
7952 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7952 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7953 helpcategory=command.CATEGORY_MAINTENANCE,
7953 helpcategory=command.CATEGORY_MAINTENANCE,
7954 )
7954 )
7955 def verify(ui, repo, **opts):
7955 def verify(ui, repo, **opts):
7956 """verify the integrity of the repository
7956 """verify the integrity of the repository
7957
7957
7958 Verify the integrity of the current repository.
7958 Verify the integrity of the current repository.
7959
7959
7960 This will perform an extensive check of the repository's
7960 This will perform an extensive check of the repository's
7961 integrity, validating the hashes and checksums of each entry in
7961 integrity, validating the hashes and checksums of each entry in
7962 the changelog, manifest, and tracked files, as well as the
7962 the changelog, manifest, and tracked files, as well as the
7963 integrity of their crosslinks and indices.
7963 integrity of their crosslinks and indices.
7964
7964
7965 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7965 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7966 for more information about recovery from corruption of the
7966 for more information about recovery from corruption of the
7967 repository.
7967 repository.
7968
7968
7969 For an alternative UI with a lot more control over the verification
7969 For an alternative UI with a lot more control over the verification
7970 process and better error reporting, try `hg help admin::verify`.
7970 process and better error reporting, try `hg help admin::verify`.
7971
7971
7972 Returns 0 on success, 1 if errors are encountered.
7972 Returns 0 on success, 1 if errors are encountered.
7973 """
7973 """
7974 level = None
7974 level = None
7975 if opts['full']:
7975 if opts['full']:
7976 level = verifymod.VERIFY_FULL
7976 level = verifymod.VERIFY_FULL
7977 return hg.verify(repo, level)
7977 return hg.verify(repo, level)
7978
7978
7979
7979
7980 @command(
7980 @command(
7981 b'version',
7981 b'version',
7982 [] + formatteropts,
7982 [] + formatteropts,
7983 helpcategory=command.CATEGORY_HELP,
7983 helpcategory=command.CATEGORY_HELP,
7984 norepo=True,
7984 norepo=True,
7985 intents={INTENT_READONLY},
7985 intents={INTENT_READONLY},
7986 )
7986 )
7987 def version_(ui, **opts):
7987 def version_(ui, **opts):
7988 """output version and copyright information
7988 """output version and copyright information
7989
7989
7990 .. container:: verbose
7990 .. container:: verbose
7991
7991
7992 Template:
7992 Template:
7993
7993
7994 The following keywords are supported. See also :hg:`help templates`.
7994 The following keywords are supported. See also :hg:`help templates`.
7995
7995
7996 :extensions: List of extensions.
7996 :extensions: List of extensions.
7997 :ver: String. Version number.
7997 :ver: String. Version number.
7998
7998
7999 And each entry of ``{extensions}`` provides the following sub-keywords
7999 And each entry of ``{extensions}`` provides the following sub-keywords
8000 in addition to ``{ver}``.
8000 in addition to ``{ver}``.
8001
8001
8002 :bundled: Boolean. True if included in the release.
8002 :bundled: Boolean. True if included in the release.
8003 :name: String. Extension name.
8003 :name: String. Extension name.
8004 """
8004 """
8005 if ui.verbose:
8005 if ui.verbose:
8006 ui.pager(b'version')
8006 ui.pager(b'version')
8007 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
8007 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
8008 fm.startitem()
8008 fm.startitem()
8009 fm.write(
8009 fm.write(
8010 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
8010 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
8011 )
8011 )
8012 license = _(
8012 license = _(
8013 b"(see https://mercurial-scm.org for more information)\n"
8013 b"(see https://mercurial-scm.org for more information)\n"
8014 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
8014 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
8015 b"This is free software; see the source for copying conditions. "
8015 b"This is free software; see the source for copying conditions. "
8016 b"There is NO\nwarranty; "
8016 b"There is NO\nwarranty; "
8017 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
8017 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
8018 )
8018 )
8019 if not ui.quiet:
8019 if not ui.quiet:
8020 fm.plain(license)
8020 fm.plain(license)
8021
8021
8022 if ui.verbose:
8022 if ui.verbose:
8023 fm.plain(_(b"\nEnabled extensions:\n\n"))
8023 fm.plain(_(b"\nEnabled extensions:\n\n"))
8024 # format names and versions into columns
8024 # format names and versions into columns
8025 names = []
8025 names = []
8026 vers = []
8026 vers = []
8027 isinternals = []
8027 isinternals = []
8028 for name, module in sorted(extensions.extensions()):
8028 for name, module in sorted(extensions.extensions()):
8029 names.append(name)
8029 names.append(name)
8030 vers.append(extensions.moduleversion(module) or None)
8030 vers.append(extensions.moduleversion(module) or None)
8031 isinternals.append(extensions.ismoduleinternal(module))
8031 isinternals.append(extensions.ismoduleinternal(module))
8032 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8032 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8033 if names:
8033 if names:
8034 namefmt = b" %%-%ds " % max(len(n) for n in names)
8034 namefmt = b" %%-%ds " % max(len(n) for n in names)
8035 places = [_(b"external"), _(b"internal")]
8035 places = [_(b"external"), _(b"internal")]
8036 for n, v, p in zip(names, vers, isinternals):
8036 for n, v, p in zip(names, vers, isinternals):
8037 fn.startitem()
8037 fn.startitem()
8038 fn.condwrite(ui.verbose, b"name", namefmt, n)
8038 fn.condwrite(ui.verbose, b"name", namefmt, n)
8039 if ui.verbose:
8039 if ui.verbose:
8040 fn.plain(b"%s " % places[p])
8040 fn.plain(b"%s " % places[p])
8041 fn.data(bundled=p)
8041 fn.data(bundled=p)
8042 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8042 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8043 if ui.verbose:
8043 if ui.verbose:
8044 fn.plain(b"\n")
8044 fn.plain(b"\n")
8045 fn.end()
8045 fn.end()
8046 fm.end()
8046 fm.end()
8047
8047
8048
8048
8049 def loadcmdtable(ui, name, cmdtable):
8049 def loadcmdtable(ui, name, cmdtable):
8050 """Load command functions from specified cmdtable"""
8050 """Load command functions from specified cmdtable"""
8051 overrides = [cmd for cmd in cmdtable if cmd in table]
8051 overrides = [cmd for cmd in cmdtable if cmd in table]
8052 if overrides:
8052 if overrides:
8053 ui.warn(
8053 ui.warn(
8054 _(b"extension '%s' overrides commands: %s\n")
8054 _(b"extension '%s' overrides commands: %s\n")
8055 % (name, b" ".join(overrides))
8055 % (name, b" ".join(overrides))
8056 )
8056 )
8057 table.update(cmdtable)
8057 table.update(cmdtable)
@@ -1,1464 +1,1481 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 invalid revset syntax
24 invalid revset syntax
25
25
26 $ hg log -r 'diffcontains()'
26 $ hg log -r 'diffcontains()'
27 hg: parse error: diffcontains takes at least 1 argument
27 hg: parse error: diffcontains takes at least 1 argument
28 [10]
28 [10]
29 $ hg log -r 'diffcontains(:)'
29 $ hg log -r 'diffcontains(:)'
30 hg: parse error: diffcontains requires a string pattern
30 hg: parse error: diffcontains requires a string pattern
31 [10]
31 [10]
32 $ hg log -r 'diffcontains("re:**test**")'
32 $ hg log -r 'diffcontains("re:**test**")'
33 hg: parse error: invalid regular expression: nothing to repeat* (glob)
33 hg: parse error: invalid regular expression: nothing to repeat* (glob)
34 [10]
34 [10]
35
35
36 simple
36 simple
37
37
38 $ hg grep -r tip:0 '.*'
38 $ hg grep -r tip:0 '.*'
39 port:4:export
39 port:4:export
40 port:4:vaportight
40 port:4:vaportight
41 port:4:import/export
41 port:4:import/export
42 port:3:export
42 port:3:export
43 port:3:vaportight
43 port:3:vaportight
44 port:3:import/export
44 port:3:import/export
45 port:3:import/export
45 port:3:import/export
46 port:2:export
46 port:2:export
47 port:2:vaportight
47 port:2:vaportight
48 port:2:import/export
48 port:2:import/export
49 port:1:import
49 port:1:import
50 port:1:export
50 port:1:export
51 port:0:import
51 port:0:import
52 $ hg grep -r tip:0 port port
52 $ hg grep -r tip:0 port port
53 port:4:export
53 port:4:export
54 port:4:vaportight
54 port:4:vaportight
55 port:4:import/export
55 port:4:import/export
56 port:3:export
56 port:3:export
57 port:3:vaportight
57 port:3:vaportight
58 port:3:import/export
58 port:3:import/export
59 port:3:import/export
59 port:3:import/export
60 port:2:export
60 port:2:export
61 port:2:vaportight
61 port:2:vaportight
62 port:2:import/export
62 port:2:import/export
63 port:1:import
63 port:1:import
64 port:1:export
64 port:1:export
65 port:0:import
65 port:0:import
66
66
67 simple from subdirectory
67 simple from subdirectory
68
68
69 $ mkdir dir
69 $ mkdir dir
70 $ cd dir
70 $ cd dir
71 $ hg grep -r tip:0 port
71 $ hg grep -r tip:0 port
72 port:4:export
72 port:4:export
73 port:4:vaportight
73 port:4:vaportight
74 port:4:import/export
74 port:4:import/export
75 port:3:export
75 port:3:export
76 port:3:vaportight
76 port:3:vaportight
77 port:3:import/export
77 port:3:import/export
78 port:3:import/export
78 port:3:import/export
79 port:2:export
79 port:2:export
80 port:2:vaportight
80 port:2:vaportight
81 port:2:import/export
81 port:2:import/export
82 port:1:import
82 port:1:import
83 port:1:export
83 port:1:export
84 port:0:import
84 port:0:import
85 $ hg grep -r tip:0 port --config ui.relative-paths=yes
85 $ hg grep -r tip:0 port --config ui.relative-paths=yes
86 ../port:4:export
86 ../port:4:export
87 ../port:4:vaportight
87 ../port:4:vaportight
88 ../port:4:import/export
88 ../port:4:import/export
89 ../port:3:export
89 ../port:3:export
90 ../port:3:vaportight
90 ../port:3:vaportight
91 ../port:3:import/export
91 ../port:3:import/export
92 ../port:3:import/export
92 ../port:3:import/export
93 ../port:2:export
93 ../port:2:export
94 ../port:2:vaportight
94 ../port:2:vaportight
95 ../port:2:import/export
95 ../port:2:import/export
96 ../port:1:import
96 ../port:1:import
97 ../port:1:export
97 ../port:1:export
98 ../port:0:import
98 ../port:0:import
99 $ cd ..
99 $ cd ..
100
100
101 simple with color
101 simple with color
102
102
103 $ hg --config extensions.color= grep --config color.mode=ansi \
103 $ hg --config extensions.color= grep --config color.mode=ansi \
104 > --color=always port port -r tip:0
104 > --color=always port port -r tip:0
105 \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)
105 \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)
106 \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)
106 \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)
107 \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)
107 \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)
108 \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)
108 \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)
109 \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)
109 \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)
110 \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)
110 \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)
111 \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)
111 \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)
112 \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)
112 \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)
113 \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)
113 \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)
114 \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)
114 \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)
115 \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)
115 \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)
116 \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)
116 \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)
117 \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)
117 \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)
118
118
119 simple templated
119 simple templated
120
120
121 $ hg grep port -r tip:0 \
121 $ hg grep port -r tip:0 \
122 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
122 > -T '{path}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n'
123 port:4:914fa752cdea:exPORT
123 port:4:914fa752cdea:exPORT
124 port:4:914fa752cdea:vaPORTight
124 port:4:914fa752cdea:vaPORTight
125 port:4:914fa752cdea:imPORT/exPORT
125 port:4:914fa752cdea:imPORT/exPORT
126 port:3:95040cfd017d:exPORT
126 port:3:95040cfd017d:exPORT
127 port:3:95040cfd017d:vaPORTight
127 port:3:95040cfd017d:vaPORTight
128 port:3:95040cfd017d:imPORT/exPORT
128 port:3:95040cfd017d:imPORT/exPORT
129 port:3:95040cfd017d:imPORT/exPORT
129 port:3:95040cfd017d:imPORT/exPORT
130 port:2:3b325e3481a1:exPORT
130 port:2:3b325e3481a1:exPORT
131 port:2:3b325e3481a1:vaPORTight
131 port:2:3b325e3481a1:vaPORTight
132 port:2:3b325e3481a1:imPORT/exPORT
132 port:2:3b325e3481a1:imPORT/exPORT
133 port:1:8b20f75c1585:imPORT
133 port:1:8b20f75c1585:imPORT
134 port:1:8b20f75c1585:exPORT
134 port:1:8b20f75c1585:exPORT
135 port:0:f31323c92170:imPORT
135 port:0:f31323c92170:imPORT
136
136
137 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
137 $ hg grep port -r tip:0 -T '{path}:{rev}:{texts}\n'
138 port:4:export
138 port:4:export
139 port:4:vaportight
139 port:4:vaportight
140 port:4:import/export
140 port:4:import/export
141 port:3:export
141 port:3:export
142 port:3:vaportight
142 port:3:vaportight
143 port:3:import/export
143 port:3:import/export
144 port:3:import/export
144 port:3:import/export
145 port:2:export
145 port:2:export
146 port:2:vaportight
146 port:2:vaportight
147 port:2:import/export
147 port:2:import/export
148 port:1:import
148 port:1:import
149 port:1:export
149 port:1:export
150 port:0:import
150 port:0:import
151
151
152 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
152 $ hg grep port -r tip:0 -T '{path}:{tags}:{texts}\n'
153 port:tip:export
153 port:tip:export
154 port:tip:vaportight
154 port:tip:vaportight
155 port:tip:import/export
155 port:tip:import/export
156 port::export
156 port::export
157 port::vaportight
157 port::vaportight
158 port::import/export
158 port::import/export
159 port::import/export
159 port::import/export
160 port::export
160 port::export
161 port::vaportight
161 port::vaportight
162 port::import/export
162 port::import/export
163 port::import
163 port::import
164 port::export
164 port::export
165 port::import
165 port::import
166
166
167 simple JSON (no "change" field)
167 simple JSON (no "change" field)
168
168
169 $ hg grep -r tip:0 -Tjson port
169 $ hg grep -r tip:0 -Tjson port
170 [
170 [
171 {
171 {
172 "date": [4, 0],
172 "date": [4, 0],
173 "lineno": 1,
173 "lineno": 1,
174 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
174 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
175 "path": "port",
175 "path": "port",
176 "rev": 4,
176 "rev": 4,
177 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
177 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
178 "user": "spam"
178 "user": "spam"
179 },
179 },
180 {
180 {
181 "date": [4, 0],
181 "date": [4, 0],
182 "lineno": 2,
182 "lineno": 2,
183 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
183 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
184 "path": "port",
184 "path": "port",
185 "rev": 4,
185 "rev": 4,
186 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
186 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
187 "user": "spam"
187 "user": "spam"
188 },
188 },
189 {
189 {
190 "date": [4, 0],
190 "date": [4, 0],
191 "lineno": 3,
191 "lineno": 3,
192 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
192 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
193 "path": "port",
193 "path": "port",
194 "rev": 4,
194 "rev": 4,
195 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
195 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
196 "user": "spam"
196 "user": "spam"
197 },
197 },
198 {
198 {
199 "date": [3, 0],
199 "date": [3, 0],
200 "lineno": 1,
200 "lineno": 1,
201 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
201 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
202 "path": "port",
202 "path": "port",
203 "rev": 3,
203 "rev": 3,
204 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
204 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
205 "user": "eggs"
205 "user": "eggs"
206 },
206 },
207 {
207 {
208 "date": [3, 0],
208 "date": [3, 0],
209 "lineno": 2,
209 "lineno": 2,
210 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
210 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
211 "path": "port",
211 "path": "port",
212 "rev": 3,
212 "rev": 3,
213 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
213 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
214 "user": "eggs"
214 "user": "eggs"
215 },
215 },
216 {
216 {
217 "date": [3, 0],
217 "date": [3, 0],
218 "lineno": 3,
218 "lineno": 3,
219 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
219 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
220 "path": "port",
220 "path": "port",
221 "rev": 3,
221 "rev": 3,
222 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
222 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
223 "user": "eggs"
223 "user": "eggs"
224 },
224 },
225 {
225 {
226 "date": [3, 0],
226 "date": [3, 0],
227 "lineno": 4,
227 "lineno": 4,
228 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
228 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
229 "path": "port",
229 "path": "port",
230 "rev": 3,
230 "rev": 3,
231 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
231 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
232 "user": "eggs"
232 "user": "eggs"
233 },
233 },
234 {
234 {
235 "date": [2, 0],
235 "date": [2, 0],
236 "lineno": 1,
236 "lineno": 1,
237 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
237 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
238 "path": "port",
238 "path": "port",
239 "rev": 2,
239 "rev": 2,
240 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
240 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
241 "user": "spam"
241 "user": "spam"
242 },
242 },
243 {
243 {
244 "date": [2, 0],
244 "date": [2, 0],
245 "lineno": 2,
245 "lineno": 2,
246 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
246 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
247 "path": "port",
247 "path": "port",
248 "rev": 2,
248 "rev": 2,
249 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
249 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
250 "user": "spam"
250 "user": "spam"
251 },
251 },
252 {
252 {
253 "date": [2, 0],
253 "date": [2, 0],
254 "lineno": 3,
254 "lineno": 3,
255 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
255 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
256 "path": "port",
256 "path": "port",
257 "rev": 2,
257 "rev": 2,
258 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
258 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
259 "user": "spam"
259 "user": "spam"
260 },
260 },
261 {
261 {
262 "date": [1, 0],
262 "date": [1, 0],
263 "lineno": 1,
263 "lineno": 1,
264 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
264 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
265 "path": "port",
265 "path": "port",
266 "rev": 1,
266 "rev": 1,
267 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
267 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
268 "user": "eggs"
268 "user": "eggs"
269 },
269 },
270 {
270 {
271 "date": [1, 0],
271 "date": [1, 0],
272 "lineno": 2,
272 "lineno": 2,
273 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
273 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
274 "path": "port",
274 "path": "port",
275 "rev": 1,
275 "rev": 1,
276 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
276 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
277 "user": "eggs"
277 "user": "eggs"
278 },
278 },
279 {
279 {
280 "date": [0, 0],
280 "date": [0, 0],
281 "lineno": 1,
281 "lineno": 1,
282 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
282 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
283 "path": "port",
283 "path": "port",
284 "rev": 0,
284 "rev": 0,
285 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
285 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
286 "user": "spam"
286 "user": "spam"
287 }
287 }
288 ]
288 ]
289
289
290 simple JSON without matching lines
290 simple JSON without matching lines
291
291
292 $ hg grep -r tip:0 -Tjson -l port
292 $ hg grep -r tip:0 -Tjson -l port
293 [
293 [
294 {
294 {
295 "date": [4, 0],
295 "date": [4, 0],
296 "lineno": 1,
296 "lineno": 1,
297 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
297 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
298 "path": "port",
298 "path": "port",
299 "rev": 4,
299 "rev": 4,
300 "user": "spam"
300 "user": "spam"
301 },
301 },
302 {
302 {
303 "date": [3, 0],
303 "date": [3, 0],
304 "lineno": 1,
304 "lineno": 1,
305 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
305 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
306 "path": "port",
306 "path": "port",
307 "rev": 3,
307 "rev": 3,
308 "user": "eggs"
308 "user": "eggs"
309 },
309 },
310 {
310 {
311 "date": [2, 0],
311 "date": [2, 0],
312 "lineno": 1,
312 "lineno": 1,
313 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
313 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
314 "path": "port",
314 "path": "port",
315 "rev": 2,
315 "rev": 2,
316 "user": "spam"
316 "user": "spam"
317 },
317 },
318 {
318 {
319 "date": [1, 0],
319 "date": [1, 0],
320 "lineno": 1,
320 "lineno": 1,
321 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
321 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
322 "path": "port",
322 "path": "port",
323 "rev": 1,
323 "rev": 1,
324 "user": "eggs"
324 "user": "eggs"
325 },
325 },
326 {
326 {
327 "date": [0, 0],
327 "date": [0, 0],
328 "lineno": 1,
328 "lineno": 1,
329 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
329 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
330 "path": "port",
330 "path": "port",
331 "rev": 0,
331 "rev": 0,
332 "user": "spam"
332 "user": "spam"
333 }
333 }
334 ]
334 ]
335
335
336 diff of each revision for reference
336 diff of each revision for reference
337
337
338 $ hg log -p -T'== rev: {rev} ==\n'
338 $ hg log -p -T'== rev: {rev} ==\n'
339 == rev: 4 ==
339 == rev: 4 ==
340 diff -r 95040cfd017d -r 914fa752cdea port
340 diff -r 95040cfd017d -r 914fa752cdea port
341 --- a/port Thu Jan 01 00:00:03 1970 +0000
341 --- a/port Thu Jan 01 00:00:03 1970 +0000
342 +++ b/port Thu Jan 01 00:00:04 1970 +0000
342 +++ b/port Thu Jan 01 00:00:04 1970 +0000
343 @@ -1,4 +1,3 @@
343 @@ -1,4 +1,3 @@
344 export
344 export
345 vaportight
345 vaportight
346 import/export
346 import/export
347 -import/export
347 -import/export
348
348
349 == rev: 3 ==
349 == rev: 3 ==
350 diff -r 3b325e3481a1 -r 95040cfd017d port
350 diff -r 3b325e3481a1 -r 95040cfd017d port
351 --- a/port Thu Jan 01 00:00:02 1970 +0000
351 --- a/port Thu Jan 01 00:00:02 1970 +0000
352 +++ b/port Thu Jan 01 00:00:03 1970 +0000
352 +++ b/port Thu Jan 01 00:00:03 1970 +0000
353 @@ -1,3 +1,4 @@
353 @@ -1,3 +1,4 @@
354 export
354 export
355 vaportight
355 vaportight
356 import/export
356 import/export
357 +import/export
357 +import/export
358
358
359 == rev: 2 ==
359 == rev: 2 ==
360 diff -r 8b20f75c1585 -r 3b325e3481a1 port
360 diff -r 8b20f75c1585 -r 3b325e3481a1 port
361 --- a/port Thu Jan 01 00:00:01 1970 +0000
361 --- a/port Thu Jan 01 00:00:01 1970 +0000
362 +++ b/port Thu Jan 01 00:00:02 1970 +0000
362 +++ b/port Thu Jan 01 00:00:02 1970 +0000
363 @@ -1,2 +1,3 @@
363 @@ -1,2 +1,3 @@
364 -import
364 -import
365 export
365 export
366 +vaportight
366 +vaportight
367 +import/export
367 +import/export
368
368
369 == rev: 1 ==
369 == rev: 1 ==
370 diff -r f31323c92170 -r 8b20f75c1585 port
370 diff -r f31323c92170 -r 8b20f75c1585 port
371 --- a/port Thu Jan 01 00:00:00 1970 +0000
371 --- a/port Thu Jan 01 00:00:00 1970 +0000
372 +++ b/port Thu Jan 01 00:00:01 1970 +0000
372 +++ b/port Thu Jan 01 00:00:01 1970 +0000
373 @@ -1,1 +1,2 @@
373 @@ -1,1 +1,2 @@
374 import
374 import
375 +export
375 +export
376
376
377 == rev: 0 ==
377 == rev: 0 ==
378 diff -r 000000000000 -r f31323c92170 port
378 diff -r 000000000000 -r f31323c92170 port
379 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
379 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
380 +++ b/port Thu Jan 01 00:00:00 1970 +0000
380 +++ b/port Thu Jan 01 00:00:00 1970 +0000
381 @@ -0,0 +1,1 @@
381 @@ -0,0 +1,1 @@
382 +import
382 +import
383
383
384
384
385 all
385 all
386
386
387 $ hg grep --traceback --all -nu port port
387 $ hg grep --traceback --all -nu port port
388 port:4:4:-:spam:import/export
388 port:4:4:-:spam:import/export
389 port:3:4:+:eggs:import/export
389 port:3:4:+:eggs:import/export
390 port:2:1:-:spam:import
390 port:2:1:-:spam:import
391 port:2:2:+:spam:vaportight
391 port:2:2:+:spam:vaportight
392 port:2:3:+:spam:import/export
392 port:2:3:+:spam:import/export
393 port:1:2:+:eggs:export
393 port:1:2:+:eggs:export
394 port:0:1:+:spam:import
394 port:0:1:+:spam:import
395
395
396 all JSON
396 all JSON
397
397
398 $ hg grep --all -Tjson port port
398 $ hg grep --all -Tjson port port
399 [
399 [
400 {
400 {
401 "change": "-",
401 "change": "-",
402 "date": [4, 0],
402 "date": [4, 0],
403 "lineno": 4,
403 "lineno": 4,
404 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
404 "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c",
405 "path": "port",
405 "path": "port",
406 "rev": 4,
406 "rev": 4,
407 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
407 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
408 "user": "spam"
408 "user": "spam"
409 },
409 },
410 {
410 {
411 "change": "+",
411 "change": "+",
412 "date": [3, 0],
412 "date": [3, 0],
413 "lineno": 4,
413 "lineno": 4,
414 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
414 "node": "95040cfd017d658c536071c6290230a613c4c2a6",
415 "path": "port",
415 "path": "port",
416 "rev": 3,
416 "rev": 3,
417 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
417 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
418 "user": "eggs"
418 "user": "eggs"
419 },
419 },
420 {
420 {
421 "change": "-",
421 "change": "-",
422 "date": [2, 0],
422 "date": [2, 0],
423 "lineno": 1,
423 "lineno": 1,
424 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
424 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
425 "path": "port",
425 "path": "port",
426 "rev": 2,
426 "rev": 2,
427 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
427 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
428 "user": "spam"
428 "user": "spam"
429 },
429 },
430 {
430 {
431 "change": "+",
431 "change": "+",
432 "date": [2, 0],
432 "date": [2, 0],
433 "lineno": 2,
433 "lineno": 2,
434 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
434 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
435 "path": "port",
435 "path": "port",
436 "rev": 2,
436 "rev": 2,
437 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
437 "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}],
438 "user": "spam"
438 "user": "spam"
439 },
439 },
440 {
440 {
441 "change": "+",
441 "change": "+",
442 "date": [2, 0],
442 "date": [2, 0],
443 "lineno": 3,
443 "lineno": 3,
444 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
444 "node": "3b325e3481a1f07435d81dfdbfa434d9a0245b47",
445 "path": "port",
445 "path": "port",
446 "rev": 2,
446 "rev": 2,
447 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
447 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}],
448 "user": "spam"
448 "user": "spam"
449 },
449 },
450 {
450 {
451 "change": "+",
451 "change": "+",
452 "date": [1, 0],
452 "date": [1, 0],
453 "lineno": 2,
453 "lineno": 2,
454 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
454 "node": "8b20f75c158513ff5ac80bd0e5219bfb6f0eb587",
455 "path": "port",
455 "path": "port",
456 "rev": 1,
456 "rev": 1,
457 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
457 "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}],
458 "user": "eggs"
458 "user": "eggs"
459 },
459 },
460 {
460 {
461 "change": "+",
461 "change": "+",
462 "date": [0, 0],
462 "date": [0, 0],
463 "lineno": 1,
463 "lineno": 1,
464 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
464 "node": "f31323c9217050ba245ee8b537c713ec2e8ab226",
465 "path": "port",
465 "path": "port",
466 "rev": 0,
466 "rev": 0,
467 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
467 "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}],
468 "user": "spam"
468 "user": "spam"
469 }
469 }
470 ]
470 ]
471
471
472 other
472 other
473
473
474 $ hg grep -r tip:0 -l port port
474 $ hg grep -r tip:0 -l port port
475 port:4
475 port:4
476 port:3
476 port:3
477 port:2
477 port:2
478 port:1
478 port:1
479 port:0
479 port:0
480 $ hg grep -r tip:0 import port
480 $ hg grep -r tip:0 import port
481 port:4:import/export
481 port:4:import/export
482 port:3:import/export
482 port:3:import/export
483 port:3:import/export
483 port:3:import/export
484 port:2:import/export
484 port:2:import/export
485 port:1:import
485 port:1:import
486 port:0:import
486 port:0:import
487
487
488 $ hg cp port port2
488 $ hg cp port port2
489 $ hg commit -m 4 -u spam -d '5 0'
489 $ hg commit -m 4 -u spam -d '5 0'
490
490
491 follow
491 follow
492
492
493 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
493 $ hg grep -r tip:0 --traceback -f 'import\n\Z' port2
494 [1]
494 [1]
495 $ echo deport >> port2
495 $ echo deport >> port2
496 $ hg commit -m 5 -u eggs -d '6 0'
496 $ hg commit -m 5 -u eggs -d '6 0'
497 $ hg grep -f --all -nu port port2
497 $ hg grep -f --all -nu port port2
498 port2:6:4:+:eggs:deport
498 port2:6:4:+:eggs:deport
499 port:4:4:-:spam:import/export
499 port:4:4:-:spam:import/export
500 port:3:4:+:eggs:import/export
500 port:3:4:+:eggs:import/export
501 port:2:1:-:spam:import
501 port:2:1:-:spam:import
502 port:2:2:+:spam:vaportight
502 port:2:2:+:spam:vaportight
503 port:2:3:+:spam:import/export
503 port:2:3:+:spam:import/export
504 port:1:2:+:eggs:export
504 port:1:2:+:eggs:export
505 port:0:1:+:spam:import
505 port:0:1:+:spam:import
506
506
507 $ hg up -q null
507 $ hg up -q null
508 $ hg grep -r 'reverse(:.)' -f port
508 $ hg grep -r 'reverse(:.)' -f port
509 port:0:import
509 port:0:import
510
510
511 Test wdir
511 Test wdir
512 (at least, this shouldn't crash)
512 (at least, this shouldn't crash)
513
513
514 $ hg up -q
514 $ hg up -q
515 $ echo wport >> port2
515 $ echo wport >> port2
516 $ hg stat
516 $ hg stat
517 M port2
517 M port2
518 $ hg grep -r 'wdir()' port
518 $ hg grep -r 'wdir()' port
519 port:2147483647:export
519 port:2147483647:export
520 port:2147483647:vaportight
520 port:2147483647:vaportight
521 port:2147483647:import/export
521 port:2147483647:import/export
522 port2:2147483647:export
522 port2:2147483647:export
523 port2:2147483647:vaportight
523 port2:2147483647:vaportight
524 port2:2147483647:import/export
524 port2:2147483647:import/export
525 port2:2147483647:deport
525 port2:2147483647:deport
526 port2:2147483647:wport
526 port2:2147483647:wport
527
527
528 Testing include/exclude
529
530 $ hg cp port tort
531 $ hg grep port -X tort
532 port:export
533 port:vaportight
534 port:import/export
535 port2:export
536 port2:vaportight
537 port2:import/export
538 port2:deport
539 port2:wport
540 $ hg grep port -I tort
541 tort:export
542 tort:vaportight
543 tort:import/export
544
528 $ cd ..
545 $ cd ..
529 $ hg init t2
546 $ hg init t2
530 $ cd t2
547 $ cd t2
531 $ hg grep -r tip:0 foobar foo
548 $ hg grep -r tip:0 foobar foo
532 [1]
549 [1]
533 $ hg grep -r tip:0 foobar
550 $ hg grep -r tip:0 foobar
534 [1]
551 [1]
535 $ echo blue >> color
552 $ echo blue >> color
536 $ echo black >> color
553 $ echo black >> color
537 $ hg add color
554 $ hg add color
538 $ hg ci -m 0
555 $ hg ci -m 0
539 $ echo orange >> color
556 $ echo orange >> color
540 $ hg ci -m 1
557 $ hg ci -m 1
541 $ echo black > color
558 $ echo black > color
542 $ hg ci -m 2
559 $ hg ci -m 2
543 $ echo orange >> color
560 $ echo orange >> color
544 $ echo blue >> color
561 $ echo blue >> color
545 $ hg ci -m 3
562 $ hg ci -m 3
546 $ hg grep -r tip:0 orange
563 $ hg grep -r tip:0 orange
547 color:3:orange
564 color:3:orange
548 color:1:orange
565 color:1:orange
549 $ hg grep --all orange
566 $ hg grep --all orange
550 color:3:+:orange
567 color:3:+:orange
551 color:2:-:orange
568 color:2:-:orange
552 color:1:+:orange
569 color:1:+:orange
553 $ hg grep --diff orange --color=debug
570 $ hg grep --diff orange --color=debug
554 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
571 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
555 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
572 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.deleted grep.change|-][grep.sep|:][grep.match|orange]
556 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
573 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.inserted grep.change|+][grep.sep|:][grep.match|orange]
557
574
558 $ hg grep --diff orange --color=yes
575 $ hg grep --diff orange --color=yes
559 \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)
576 \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)
560 \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)
577 \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)
561 \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)
578 \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)
562
579
563 $ hg grep --diff orange
580 $ hg grep --diff orange
564 color:3:+:orange
581 color:3:+:orange
565 color:2:-:orange
582 color:2:-:orange
566 color:1:+:orange
583 color:1:+:orange
567
584
568 revset predicate for "grep --diff"
585 revset predicate for "grep --diff"
569
586
570 $ hg log -qr 'diffcontains("re:^bl...$")'
587 $ hg log -qr 'diffcontains("re:^bl...$")'
571 0:203191eb5e21
588 0:203191eb5e21
572 $ hg log -qr 'diffcontains("orange")'
589 $ hg log -qr 'diffcontains("orange")'
573 1:7c585a21e0d1
590 1:7c585a21e0d1
574 2:11bd8bc8d653
591 2:11bd8bc8d653
575 3:e0116d3829f8
592 3:e0116d3829f8
576 $ hg log -qr '2:0 & diffcontains("orange")'
593 $ hg log -qr '2:0 & diffcontains("orange")'
577 2:11bd8bc8d653
594 2:11bd8bc8d653
578 1:7c585a21e0d1
595 1:7c585a21e0d1
579
596
580 test substring match: '^' should only match at the beginning
597 test substring match: '^' should only match at the beginning
581
598
582 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
599 $ hg grep -r tip:0 '^.' --config extensions.color= --color debug
583 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
600 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack
584 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
601 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range
585 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
602 [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue
586 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.match|b]lack
603 [grep.filename|color][grep.sep|:][grep.rev|2][grep.sep|:][grep.match|b]lack
587 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lue
604 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lue
588 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lack
605 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|b]lack
589 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|o]range
606 [grep.filename|color][grep.sep|:][grep.rev|1][grep.sep|:][grep.match|o]range
590 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lue
607 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lue
591 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lack
608 [grep.filename|color][grep.sep|:][grep.rev|0][grep.sep|:][grep.match|b]lack
592
609
593 match in last "line" without newline
610 match in last "line" without newline
594
611
595 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
612 $ "$PYTHON" -c 'fp = open("noeol", "wb"); fp.write(b"no infinite loop"); fp.close();'
596 $ hg ci -Amnoeol
613 $ hg ci -Amnoeol
597 adding noeol
614 adding noeol
598 $ hg grep -r tip:0 loop
615 $ hg grep -r tip:0 loop
599 noeol:4:no infinite loop
616 noeol:4:no infinite loop
600
617
601 $ cd ..
618 $ cd ..
602
619
603 Issue685: traceback in grep -r after rename
620 Issue685: traceback in grep -r after rename
604
621
605 Got a traceback when using grep on a single
622 Got a traceback when using grep on a single
606 revision with renamed files.
623 revision with renamed files.
607
624
608 $ hg init issue685
625 $ hg init issue685
609 $ cd issue685
626 $ cd issue685
610 $ echo octarine > color
627 $ echo octarine > color
611 $ hg ci -Amcolor
628 $ hg ci -Amcolor
612 adding color
629 adding color
613 $ hg rename color colour
630 $ hg rename color colour
614 $ hg ci -Am rename
631 $ hg ci -Am rename
615 $ hg grep -r tip:0 octarine
632 $ hg grep -r tip:0 octarine
616 colour:1:octarine
633 colour:1:octarine
617 color:0:octarine
634 color:0:octarine
618
635
619 Used to crash here
636 Used to crash here
620
637
621 $ hg grep -r 1 octarine
638 $ hg grep -r 1 octarine
622 colour:1:octarine
639 colour:1:octarine
623 $ cd ..
640 $ cd ..
624
641
625
642
626 Issue337: test that grep follows parent-child relationships instead
643 Issue337: test that grep follows parent-child relationships instead
627 of just using revision numbers.
644 of just using revision numbers.
628
645
629 $ hg init issue337
646 $ hg init issue337
630 $ cd issue337
647 $ cd issue337
631
648
632 $ echo white > color
649 $ echo white > color
633 $ hg commit -A -m "0 white"
650 $ hg commit -A -m "0 white"
634 adding color
651 adding color
635
652
636 $ echo red > color
653 $ echo red > color
637 $ hg commit -A -m "1 red"
654 $ hg commit -A -m "1 red"
638
655
639 $ hg update 0
656 $ hg update 0
640 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
657 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
641 $ echo black > color
658 $ echo black > color
642 $ hg commit -A -m "2 black"
659 $ hg commit -A -m "2 black"
643 created new head
660 created new head
644
661
645 $ hg update --clean 1
662 $ hg update --clean 1
646 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
663 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 $ echo blue > color
664 $ echo blue > color
648 $ hg commit -A -m "3 blue"
665 $ hg commit -A -m "3 blue"
649
666
650 $ hg grep --all red
667 $ hg grep --all red
651 color:3:-:red
668 color:3:-:red
652 color:1:+:red
669 color:1:+:red
653
670
654 $ hg grep --diff red
671 $ hg grep --diff red
655 color:3:-:red
672 color:3:-:red
656 color:1:+:red
673 color:1:+:red
657
674
658 Issue3885: test that changing revision order does not alter the
675 Issue3885: test that changing revision order does not alter the
659 revisions printed, just their order.
676 revisions printed, just their order.
660
677
661 $ hg grep --all red -r "all()"
678 $ hg grep --all red -r "all()"
662 color:1:+:red
679 color:1:+:red
663 color:3:-:red
680 color:3:-:red
664
681
665 $ hg grep --all red -r "reverse(all())"
682 $ hg grep --all red -r "reverse(all())"
666 color:3:-:red
683 color:3:-:red
667 color:1:+:red
684 color:1:+:red
668
685
669 $ hg grep --diff red -r "all()"
686 $ hg grep --diff red -r "all()"
670 color:1:+:red
687 color:1:+:red
671 color:3:-:red
688 color:3:-:red
672
689
673 $ hg grep --diff red -r "reverse(all())"
690 $ hg grep --diff red -r "reverse(all())"
674 color:3:-:red
691 color:3:-:red
675 color:1:+:red
692 color:1:+:red
676
693
677 $ cd ..
694 $ cd ..
678
695
679 $ hg init a
696 $ hg init a
680 $ cd a
697 $ cd a
681 $ cp "$TESTDIR/binfile.bin" .
698 $ cp "$TESTDIR/binfile.bin" .
682 $ hg add binfile.bin
699 $ hg add binfile.bin
683 $ hg ci -m 'add binfile.bin'
700 $ hg ci -m 'add binfile.bin'
684 $ hg grep "MaCam" --all
701 $ hg grep "MaCam" --all
685 binfile.bin:0:+: Binary file matches
702 binfile.bin:0:+: Binary file matches
686
703
687 $ hg grep "MaCam" --diff
704 $ hg grep "MaCam" --diff
688 binfile.bin:0:+: Binary file matches
705 binfile.bin:0:+: Binary file matches
689
706
690 $ cd ..
707 $ cd ..
691
708
692 Moved line may not be collected by "grep --diff" since it first filters
709 Moved line may not be collected by "grep --diff" since it first filters
693 the contents to be diffed by the pattern. (i.e.
710 the contents to be diffed by the pattern. (i.e.
694 "diff <(grep pat a) <(grep pat b)", not "diff a b | grep pat".)
711 "diff <(grep pat a) <(grep pat b)", not "diff a b | grep pat".)
695 This is much faster than generating full diff per revision.
712 This is much faster than generating full diff per revision.
696
713
697 $ hg init moved-line
714 $ hg init moved-line
698 $ cd moved-line
715 $ cd moved-line
699 $ cat <<'EOF' > a
716 $ cat <<'EOF' > a
700 > foo
717 > foo
701 > bar
718 > bar
702 > baz
719 > baz
703 > EOF
720 > EOF
704 $ hg ci -Am initial
721 $ hg ci -Am initial
705 adding a
722 adding a
706 $ cat <<'EOF' > a
723 $ cat <<'EOF' > a
707 > bar
724 > bar
708 > baz
725 > baz
709 > foo
726 > foo
710 > EOF
727 > EOF
711 $ hg ci -m reorder
728 $ hg ci -m reorder
712
729
713 $ hg diff -c 1
730 $ hg diff -c 1
714 diff -r a593cc55e81b -r 69789a3b6e80 a
731 diff -r a593cc55e81b -r 69789a3b6e80 a
715 --- a/a Thu Jan 01 00:00:00 1970 +0000
732 --- a/a Thu Jan 01 00:00:00 1970 +0000
716 +++ b/a Thu Jan 01 00:00:00 1970 +0000
733 +++ b/a Thu Jan 01 00:00:00 1970 +0000
717 @@ -1,3 +1,3 @@
734 @@ -1,3 +1,3 @@
718 -foo
735 -foo
719 bar
736 bar
720 baz
737 baz
721 +foo
738 +foo
722
739
723 can't find the move of "foo" at the revision 1:
740 can't find the move of "foo" at the revision 1:
724
741
725 $ hg grep --diff foo -r1
742 $ hg grep --diff foo -r1
726 [1]
743 [1]
727
744
728 "bar" isn't moved at the revisoin 1:
745 "bar" isn't moved at the revisoin 1:
729
746
730 $ hg grep --diff bar -r1
747 $ hg grep --diff bar -r1
731 [1]
748 [1]
732
749
733 $ cd ..
750 $ cd ..
734
751
735 Test for showing working of allfiles flag
752 Test for showing working of allfiles flag
736
753
737 $ hg init sng
754 $ hg init sng
738 $ cd sng
755 $ cd sng
739 $ echo "unmod" >> um
756 $ echo "unmod" >> um
740 $ echo old > old
757 $ echo old > old
741 $ hg ci -q -A -m "adds unmod to um"
758 $ hg ci -q -A -m "adds unmod to um"
742 $ echo "something else" >> new
759 $ echo "something else" >> new
743 $ hg ci -A -m "second commit"
760 $ hg ci -A -m "second commit"
744 adding new
761 adding new
745 $ hg grep -r "." "unmod"
762 $ hg grep -r "." "unmod"
746 um:1:unmod
763 um:1:unmod
747
764
748 Existing tracked files in the working directory are searched by default
765 Existing tracked files in the working directory are searched by default
749
766
750 $ echo modified >> new
767 $ echo modified >> new
751 $ echo 'added' > added; hg add added
768 $ echo 'added' > added; hg add added
752 $ echo 'added, missing' > added-missing; hg add added-missing; rm added-missing
769 $ echo 'added, missing' > added-missing; hg add added-missing; rm added-missing
753 $ echo 'untracked' > untracked
770 $ echo 'untracked' > untracked
754 $ hg rm old
771 $ hg rm old
755 $ hg grep ''
772 $ hg grep ''
756 added:added
773 added:added
757 new:something else
774 new:something else
758 new:modified
775 new:modified
759 um:unmod
776 um:unmod
760
777
761 #if symlink
778 #if symlink
762 Grepping a symlink greps its destination
779 Grepping a symlink greps its destination
763
780
764 $ rm -f added; ln -s symlink-added added
781 $ rm -f added; ln -s symlink-added added
765 $ hg grep '' | grep added
782 $ hg grep '' | grep added
766 added:symlink-added
783 added:symlink-added
767
784
768 But we reject symlinks as directories components of a tracked file as
785 But we reject symlinks as directories components of a tracked file as
769 usual:
786 usual:
770
787
771 $ mkdir dir; touch dir/f; hg add dir/f
788 $ mkdir dir; touch dir/f; hg add dir/f
772 $ rm -rf dir; ln -s / dir
789 $ rm -rf dir; ln -s / dir
773 $ hg grep ''
790 $ hg grep ''
774 abort: path 'dir/f' traverses symbolic link 'dir'
791 abort: path 'dir/f' traverses symbolic link 'dir'
775 [255]
792 [255]
776 #endif
793 #endif
777
794
778 But we can search files from some other revision with -rREV
795 But we can search files from some other revision with -rREV
779
796
780 $ hg grep -r. mod
797 $ hg grep -r. mod
781 um:1:unmod
798 um:1:unmod
782
799
783 $ hg grep --diff mod
800 $ hg grep --diff mod
784 um:0:+:unmod
801 um:0:+:unmod
785
802
786 $ cd ..
803 $ cd ..
787
804
788 Change Default of grep by ui.tweakdefaults, that is, the files not in current
805 Change Default of grep by ui.tweakdefaults, that is, the files not in current
789 working directory should not be grepp-ed on
806 working directory should not be grepp-ed on
790
807
791 $ hg init ab
808 $ hg init ab
792 $ cd ab
809 $ cd ab
793 $ cat <<'EOF' >> .hg/hgrc
810 $ cat <<'EOF' >> .hg/hgrc
794 > [ui]
811 > [ui]
795 > tweakdefaults = True
812 > tweakdefaults = True
796 > EOF
813 > EOF
797 $ echo "some text">>file1
814 $ echo "some text">>file1
798 $ hg add file1
815 $ hg add file1
799 $ hg commit -m "adds file1"
816 $ hg commit -m "adds file1"
800 $ hg mv file1 file2
817 $ hg mv file1 file2
801
818
802 wdir revision is hidden by default:
819 wdir revision is hidden by default:
803
820
804 $ hg grep "some"
821 $ hg grep "some"
805 file2:some text
822 file2:some text
806
823
807 but it should be available in template dict:
824 but it should be available in template dict:
808
825
809 $ hg grep "some" -Tjson
826 $ hg grep "some" -Tjson
810 [
827 [
811 {
828 {
812 "date": [0, 0],
829 "date": [0, 0],
813 "lineno": 1,
830 "lineno": 1,
814 "node": "ffffffffffffffffffffffffffffffffffffffff",
831 "node": "ffffffffffffffffffffffffffffffffffffffff",
815 "path": "file2",
832 "path": "file2",
816 "rev": 2147483647,
833 "rev": 2147483647,
817 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
834 "texts": [{"matched": true, "text": "some"}, {"matched": false, "text": " text"}],
818 "user": "test"
835 "user": "test"
819 }
836 }
820 ]
837 ]
821
838
822 $ cd ..
839 $ cd ..
823
840
824 test -rMULTIREV
841 test -rMULTIREV
825
842
826 $ cd sng
843 $ cd sng
827 $ hg rm um
844 $ hg rm um
828 $ hg commit -m "deletes um"
845 $ hg commit -m "deletes um"
829 $ hg grep -r "0:2" "unmod"
846 $ hg grep -r "0:2" "unmod"
830 um:0:unmod
847 um:0:unmod
831 um:1:unmod
848 um:1:unmod
832 $ hg grep -r "0:2" "unmod" um
849 $ hg grep -r "0:2" "unmod" um
833 um:0:unmod
850 um:0:unmod
834 um:1:unmod
851 um:1:unmod
835 $ hg grep -r "0:2" "unmod" "glob:**/um" # Check that patterns also work
852 $ hg grep -r "0:2" "unmod" "glob:**/um" # Check that patterns also work
836 um:0:unmod
853 um:0:unmod
837 um:1:unmod
854 um:1:unmod
838 $ cd ..
855 $ cd ..
839
856
840 --follow with/without --diff and/or paths
857 --follow with/without --diff and/or paths
841 -----------------------------------------
858 -----------------------------------------
842
859
843 For each test case, we compare the history traversal of "hg log",
860 For each test case, we compare the history traversal of "hg log",
844 "hg grep --diff", and "hg grep" (--all-files).
861 "hg grep --diff", and "hg grep" (--all-files).
845
862
846 "hg grep --diff" should traverse the log in the same way as "hg log".
863 "hg grep --diff" should traverse the log in the same way as "hg log".
847 "hg grep" (--all-files) is slightly different in that it includes
864 "hg grep" (--all-files) is slightly different in that it includes
848 unmodified changes.
865 unmodified changes.
849
866
850 $ hg init follow
867 $ hg init follow
851 $ cd follow
868 $ cd follow
852
869
853 $ cat <<'EOF' >> .hg/hgrc
870 $ cat <<'EOF' >> .hg/hgrc
854 > [command-templates]
871 > [command-templates]
855 > log = '{rev}: {join(files % "{status} {path}", ", ")}\n'
872 > log = '{rev}: {join(files % "{status} {path}", ", ")}\n'
856 > EOF
873 > EOF
857
874
858 $ for f in add0 add0-mod1 add0-rm1 add0-mod2 add0-rm2 add0-mod3 add0-mod4 add0-rm4; do
875 $ for f in add0 add0-mod1 add0-rm1 add0-mod2 add0-rm2 add0-mod3 add0-mod4 add0-rm4; do
859 > echo data0 >> $f
876 > echo data0 >> $f
860 > done
877 > done
861 $ hg ci -qAm0
878 $ hg ci -qAm0
862
879
863 $ hg cp add0 add0-cp1
880 $ hg cp add0 add0-cp1
864 $ hg cp add0 add0-cp1-mod1
881 $ hg cp add0 add0-cp1-mod1
865 $ hg cp add0 add0-cp1-mod1-rm3
882 $ hg cp add0 add0-cp1-mod1-rm3
866 $ hg rm add0-rm1
883 $ hg rm add0-rm1
867 $ for f in *mod1*; do
884 $ for f in *mod1*; do
868 > echo data1 >> $f
885 > echo data1 >> $f
869 > done
886 > done
870 $ hg ci -qAm1
887 $ hg ci -qAm1
871
888
872 $ hg update -q 0
889 $ hg update -q 0
873 $ hg cp add0 add0-cp2
890 $ hg cp add0 add0-cp2
874 $ hg cp add0 add0-cp2-mod2
891 $ hg cp add0 add0-cp2-mod2
875 $ hg rm add0-rm2
892 $ hg rm add0-rm2
876 $ for f in *mod2*; do
893 $ for f in *mod2*; do
877 > echo data2 >> $f
894 > echo data2 >> $f
878 > done
895 > done
879 $ hg ci -qAm2
896 $ hg ci -qAm2
880
897
881 $ hg update -q 1
898 $ hg update -q 1
882 $ hg cp add0-cp1 add0-cp1-cp3
899 $ hg cp add0-cp1 add0-cp1-cp3
883 $ hg cp add0-cp1-mod1 add0-cp1-mod1-cp3-mod3
900 $ hg cp add0-cp1-mod1 add0-cp1-mod1-cp3-mod3
884 $ hg rm add0-cp1-mod1-rm3
901 $ hg rm add0-cp1-mod1-rm3
885 $ for f in *mod3*; do
902 $ for f in *mod3*; do
886 > echo data3 >> $f
903 > echo data3 >> $f
887 > done
904 > done
888 $ hg ci -qAm3
905 $ hg ci -qAm3
889
906
890 $ hg cp add0 add0-cp4
907 $ hg cp add0 add0-cp4
891 $ hg cp add0 add0-cp4-mod4
908 $ hg cp add0 add0-cp4-mod4
892 $ hg rm add0-rm4
909 $ hg rm add0-rm4
893 $ for f in *mod4*; do
910 $ for f in *mod4*; do
894 > echo data4 >> $f
911 > echo data4 >> $f
895 > done
912 > done
896
913
897 $ hg log -Gr':wdir()'
914 $ hg log -Gr':wdir()'
898 o 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
915 o 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
899 |
916 |
900 @ 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
917 @ 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
901 |
918 |
902 | o 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
919 | o 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
903 | |
920 | |
904 o | 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
921 o | 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
905 |/
922 |/
906 o 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
923 o 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
907
924
908
925
909 follow revision history from wdir parent:
926 follow revision history from wdir parent:
910
927
911 $ hg log -f
928 $ hg log -f
912 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
929 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
913 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
930 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
914 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
931 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
915
932
916 $ hg grep --diff -f data
933 $ hg grep --diff -f data
917 add0-cp1-mod1-cp3-mod3:3:+:data3
934 add0-cp1-mod1-cp3-mod3:3:+:data3
918 add0-mod3:3:+:data3
935 add0-mod3:3:+:data3
919 add0-cp1-mod1:1:+:data1
936 add0-cp1-mod1:1:+:data1
920 add0-cp1-mod1-rm3:1:+:data1
937 add0-cp1-mod1-rm3:1:+:data1
921 add0-mod1:1:+:data1
938 add0-mod1:1:+:data1
922 add0:0:+:data0
939 add0:0:+:data0
923 add0-mod1:0:+:data0
940 add0-mod1:0:+:data0
924 add0-mod2:0:+:data0
941 add0-mod2:0:+:data0
925 add0-mod3:0:+:data0
942 add0-mod3:0:+:data0
926 add0-mod4:0:+:data0
943 add0-mod4:0:+:data0
927 add0-rm1:0:+:data0
944 add0-rm1:0:+:data0
928 add0-rm2:0:+:data0
945 add0-rm2:0:+:data0
929 add0-rm4:0:+:data0
946 add0-rm4:0:+:data0
930
947
931 $ hg grep -f data
948 $ hg grep -f data
932 add0:3:data0
949 add0:3:data0
933 add0-cp1:3:data0
950 add0-cp1:3:data0
934 add0-cp1-cp3:3:data0
951 add0-cp1-cp3:3:data0
935 add0-cp1-mod1:3:data0
952 add0-cp1-mod1:3:data0
936 add0-cp1-mod1:3:data1
953 add0-cp1-mod1:3:data1
937 add0-cp1-mod1-cp3-mod3:3:data0
954 add0-cp1-mod1-cp3-mod3:3:data0
938 add0-cp1-mod1-cp3-mod3:3:data1
955 add0-cp1-mod1-cp3-mod3:3:data1
939 add0-cp1-mod1-cp3-mod3:3:data3
956 add0-cp1-mod1-cp3-mod3:3:data3
940 add0-mod1:3:data0
957 add0-mod1:3:data0
941 add0-mod1:3:data1
958 add0-mod1:3:data1
942 add0-mod2:3:data0
959 add0-mod2:3:data0
943 add0-mod3:3:data0
960 add0-mod3:3:data0
944 add0-mod3:3:data3
961 add0-mod3:3:data3
945 add0-mod4:3:data0
962 add0-mod4:3:data0
946 add0-rm2:3:data0
963 add0-rm2:3:data0
947 add0-rm4:3:data0
964 add0-rm4:3:data0
948 add0:1:data0
965 add0:1:data0
949 add0-cp1:1:data0
966 add0-cp1:1:data0
950 add0-cp1-mod1:1:data0
967 add0-cp1-mod1:1:data0
951 add0-cp1-mod1:1:data1
968 add0-cp1-mod1:1:data1
952 add0-cp1-mod1-rm3:1:data0
969 add0-cp1-mod1-rm3:1:data0
953 add0-cp1-mod1-rm3:1:data1
970 add0-cp1-mod1-rm3:1:data1
954 add0-mod1:1:data0
971 add0-mod1:1:data0
955 add0-mod1:1:data1
972 add0-mod1:1:data1
956 add0-mod2:1:data0
973 add0-mod2:1:data0
957 add0-mod3:1:data0
974 add0-mod3:1:data0
958 add0-mod4:1:data0
975 add0-mod4:1:data0
959 add0-rm2:1:data0
976 add0-rm2:1:data0
960 add0-rm4:1:data0
977 add0-rm4:1:data0
961 add0:0:data0
978 add0:0:data0
962 add0-mod1:0:data0
979 add0-mod1:0:data0
963 add0-mod2:0:data0
980 add0-mod2:0:data0
964 add0-mod3:0:data0
981 add0-mod3:0:data0
965 add0-mod4:0:data0
982 add0-mod4:0:data0
966 add0-rm1:0:data0
983 add0-rm1:0:data0
967 add0-rm2:0:data0
984 add0-rm2:0:data0
968 add0-rm4:0:data0
985 add0-rm4:0:data0
969
986
970 follow revision history from specified revision:
987 follow revision history from specified revision:
971
988
972 $ hg log -fr2
989 $ hg log -fr2
973 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
990 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
974 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
991 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
975
992
976 $ hg grep --diff -fr2 data
993 $ hg grep --diff -fr2 data
977 add0-cp2-mod2:2:+:data2
994 add0-cp2-mod2:2:+:data2
978 add0-mod2:2:+:data2
995 add0-mod2:2:+:data2
979 add0:0:+:data0
996 add0:0:+:data0
980 add0-mod1:0:+:data0
997 add0-mod1:0:+:data0
981 add0-mod2:0:+:data0
998 add0-mod2:0:+:data0
982 add0-mod3:0:+:data0
999 add0-mod3:0:+:data0
983 add0-mod4:0:+:data0
1000 add0-mod4:0:+:data0
984 add0-rm1:0:+:data0
1001 add0-rm1:0:+:data0
985 add0-rm2:0:+:data0
1002 add0-rm2:0:+:data0
986 add0-rm4:0:+:data0
1003 add0-rm4:0:+:data0
987
1004
988 $ hg grep -fr2 data
1005 $ hg grep -fr2 data
989 add0:2:data0
1006 add0:2:data0
990 add0-cp2:2:data0
1007 add0-cp2:2:data0
991 add0-cp2-mod2:2:data0
1008 add0-cp2-mod2:2:data0
992 add0-cp2-mod2:2:data2
1009 add0-cp2-mod2:2:data2
993 add0-mod1:2:data0
1010 add0-mod1:2:data0
994 add0-mod2:2:data0
1011 add0-mod2:2:data0
995 add0-mod2:2:data2
1012 add0-mod2:2:data2
996 add0-mod3:2:data0
1013 add0-mod3:2:data0
997 add0-mod4:2:data0
1014 add0-mod4:2:data0
998 add0-rm1:2:data0
1015 add0-rm1:2:data0
999 add0-rm4:2:data0
1016 add0-rm4:2:data0
1000 add0:0:data0
1017 add0:0:data0
1001 add0-mod1:0:data0
1018 add0-mod1:0:data0
1002 add0-mod2:0:data0
1019 add0-mod2:0:data0
1003 add0-mod3:0:data0
1020 add0-mod3:0:data0
1004 add0-mod4:0:data0
1021 add0-mod4:0:data0
1005 add0-rm1:0:data0
1022 add0-rm1:0:data0
1006 add0-rm2:0:data0
1023 add0-rm2:0:data0
1007 add0-rm4:0:data0
1024 add0-rm4:0:data0
1008
1025
1009 follow revision history from wdir:
1026 follow revision history from wdir:
1010
1027
1011 $ hg log -fr'wdir()'
1028 $ hg log -fr'wdir()'
1012 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1029 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1013 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1030 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1014 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1031 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1015 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1032 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1016
1033
1017 BROKEN: should not abort because of removed file
1034 BROKEN: should not abort because of removed file
1018 $ hg grep --diff -fr'wdir()' data
1035 $ hg grep --diff -fr'wdir()' data
1019 add0-cp4-mod4:2147483647:+:data4
1036 add0-cp4-mod4:2147483647:+:data4
1020 add0-mod4:2147483647:+:data4
1037 add0-mod4:2147483647:+:data4
1021 add0-rm4:2147483647:-:abort: add0-rm4@None: not found in manifest
1038 add0-rm4:2147483647:-:abort: add0-rm4@None: not found in manifest
1022 [50]
1039 [50]
1023
1040
1024 $ hg grep -fr'wdir()' data
1041 $ hg grep -fr'wdir()' data
1025 add0:2147483647:data0
1042 add0:2147483647:data0
1026 add0-cp1:2147483647:data0
1043 add0-cp1:2147483647:data0
1027 add0-cp1-cp3:2147483647:data0
1044 add0-cp1-cp3:2147483647:data0
1028 add0-cp1-mod1:2147483647:data0
1045 add0-cp1-mod1:2147483647:data0
1029 add0-cp1-mod1:2147483647:data1
1046 add0-cp1-mod1:2147483647:data1
1030 add0-cp1-mod1-cp3-mod3:2147483647:data0
1047 add0-cp1-mod1-cp3-mod3:2147483647:data0
1031 add0-cp1-mod1-cp3-mod3:2147483647:data1
1048 add0-cp1-mod1-cp3-mod3:2147483647:data1
1032 add0-cp1-mod1-cp3-mod3:2147483647:data3
1049 add0-cp1-mod1-cp3-mod3:2147483647:data3
1033 add0-cp4:2147483647:data0
1050 add0-cp4:2147483647:data0
1034 add0-cp4-mod4:2147483647:data0
1051 add0-cp4-mod4:2147483647:data0
1035 add0-cp4-mod4:2147483647:data4
1052 add0-cp4-mod4:2147483647:data4
1036 add0-mod1:2147483647:data0
1053 add0-mod1:2147483647:data0
1037 add0-mod1:2147483647:data1
1054 add0-mod1:2147483647:data1
1038 add0-mod2:2147483647:data0
1055 add0-mod2:2147483647:data0
1039 add0-mod3:2147483647:data0
1056 add0-mod3:2147483647:data0
1040 add0-mod3:2147483647:data3
1057 add0-mod3:2147483647:data3
1041 add0-mod4:2147483647:data0
1058 add0-mod4:2147483647:data0
1042 add0-mod4:2147483647:data4
1059 add0-mod4:2147483647:data4
1043 add0-rm2:2147483647:data0
1060 add0-rm2:2147483647:data0
1044 add0:3:data0
1061 add0:3:data0
1045 add0-cp1:3:data0
1062 add0-cp1:3:data0
1046 add0-cp1-cp3:3:data0
1063 add0-cp1-cp3:3:data0
1047 add0-cp1-mod1:3:data0
1064 add0-cp1-mod1:3:data0
1048 add0-cp1-mod1:3:data1
1065 add0-cp1-mod1:3:data1
1049 add0-cp1-mod1-cp3-mod3:3:data0
1066 add0-cp1-mod1-cp3-mod3:3:data0
1050 add0-cp1-mod1-cp3-mod3:3:data1
1067 add0-cp1-mod1-cp3-mod3:3:data1
1051 add0-cp1-mod1-cp3-mod3:3:data3
1068 add0-cp1-mod1-cp3-mod3:3:data3
1052 add0-mod1:3:data0
1069 add0-mod1:3:data0
1053 add0-mod1:3:data1
1070 add0-mod1:3:data1
1054 add0-mod2:3:data0
1071 add0-mod2:3:data0
1055 add0-mod3:3:data0
1072 add0-mod3:3:data0
1056 add0-mod3:3:data3
1073 add0-mod3:3:data3
1057 add0-mod4:3:data0
1074 add0-mod4:3:data0
1058 add0-rm2:3:data0
1075 add0-rm2:3:data0
1059 add0-rm4:3:data0
1076 add0-rm4:3:data0
1060 add0:1:data0
1077 add0:1:data0
1061 add0-cp1:1:data0
1078 add0-cp1:1:data0
1062 add0-cp1-mod1:1:data0
1079 add0-cp1-mod1:1:data0
1063 add0-cp1-mod1:1:data1
1080 add0-cp1-mod1:1:data1
1064 add0-cp1-mod1-rm3:1:data0
1081 add0-cp1-mod1-rm3:1:data0
1065 add0-cp1-mod1-rm3:1:data1
1082 add0-cp1-mod1-rm3:1:data1
1066 add0-mod1:1:data0
1083 add0-mod1:1:data0
1067 add0-mod1:1:data1
1084 add0-mod1:1:data1
1068 add0-mod2:1:data0
1085 add0-mod2:1:data0
1069 add0-mod3:1:data0
1086 add0-mod3:1:data0
1070 add0-mod4:1:data0
1087 add0-mod4:1:data0
1071 add0-rm2:1:data0
1088 add0-rm2:1:data0
1072 add0-rm4:1:data0
1089 add0-rm4:1:data0
1073 add0:0:data0
1090 add0:0:data0
1074 add0-mod1:0:data0
1091 add0-mod1:0:data0
1075 add0-mod2:0:data0
1092 add0-mod2:0:data0
1076 add0-mod3:0:data0
1093 add0-mod3:0:data0
1077 add0-mod4:0:data0
1094 add0-mod4:0:data0
1078 add0-rm1:0:data0
1095 add0-rm1:0:data0
1079 add0-rm2:0:data0
1096 add0-rm2:0:data0
1080 add0-rm4:0:data0
1097 add0-rm4:0:data0
1081
1098
1082 follow revision history from multiple revisions:
1099 follow revision history from multiple revisions:
1083
1100
1084 $ hg log -fr'1+2'
1101 $ hg log -fr'1+2'
1085 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1102 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1086 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1103 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1087 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1104 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1088
1105
1089 $ hg grep --diff -fr'1+2' data
1106 $ hg grep --diff -fr'1+2' data
1090 add0-cp2-mod2:2:+:data2
1107 add0-cp2-mod2:2:+:data2
1091 add0-mod2:2:+:data2
1108 add0-mod2:2:+:data2
1092 add0-cp1-mod1:1:+:data1
1109 add0-cp1-mod1:1:+:data1
1093 add0-cp1-mod1-rm3:1:+:data1
1110 add0-cp1-mod1-rm3:1:+:data1
1094 add0-mod1:1:+:data1
1111 add0-mod1:1:+:data1
1095 add0:0:+:data0
1112 add0:0:+:data0
1096 add0-mod1:0:+:data0
1113 add0-mod1:0:+:data0
1097 add0-mod2:0:+:data0
1114 add0-mod2:0:+:data0
1098 add0-mod3:0:+:data0
1115 add0-mod3:0:+:data0
1099 add0-mod4:0:+:data0
1116 add0-mod4:0:+:data0
1100 add0-rm1:0:+:data0
1117 add0-rm1:0:+:data0
1101 add0-rm2:0:+:data0
1118 add0-rm2:0:+:data0
1102 add0-rm4:0:+:data0
1119 add0-rm4:0:+:data0
1103
1120
1104 $ hg grep -fr'1+2' data
1121 $ hg grep -fr'1+2' data
1105 add0:2:data0
1122 add0:2:data0
1106 add0-cp2:2:data0
1123 add0-cp2:2:data0
1107 add0-cp2-mod2:2:data0
1124 add0-cp2-mod2:2:data0
1108 add0-cp2-mod2:2:data2
1125 add0-cp2-mod2:2:data2
1109 add0-mod1:2:data0
1126 add0-mod1:2:data0
1110 add0-mod2:2:data0
1127 add0-mod2:2:data0
1111 add0-mod2:2:data2
1128 add0-mod2:2:data2
1112 add0-mod3:2:data0
1129 add0-mod3:2:data0
1113 add0-mod4:2:data0
1130 add0-mod4:2:data0
1114 add0-rm1:2:data0
1131 add0-rm1:2:data0
1115 add0-rm4:2:data0
1132 add0-rm4:2:data0
1116 add0:1:data0
1133 add0:1:data0
1117 add0-cp1:1:data0
1134 add0-cp1:1:data0
1118 add0-cp1-mod1:1:data0
1135 add0-cp1-mod1:1:data0
1119 add0-cp1-mod1:1:data1
1136 add0-cp1-mod1:1:data1
1120 add0-cp1-mod1-rm3:1:data0
1137 add0-cp1-mod1-rm3:1:data0
1121 add0-cp1-mod1-rm3:1:data1
1138 add0-cp1-mod1-rm3:1:data1
1122 add0-mod1:1:data0
1139 add0-mod1:1:data0
1123 add0-mod1:1:data1
1140 add0-mod1:1:data1
1124 add0-mod2:1:data0
1141 add0-mod2:1:data0
1125 add0-mod3:1:data0
1142 add0-mod3:1:data0
1126 add0-mod4:1:data0
1143 add0-mod4:1:data0
1127 add0-rm2:1:data0
1144 add0-rm2:1:data0
1128 add0-rm4:1:data0
1145 add0-rm4:1:data0
1129 add0:0:data0
1146 add0:0:data0
1130 add0-mod1:0:data0
1147 add0-mod1:0:data0
1131 add0-mod2:0:data0
1148 add0-mod2:0:data0
1132 add0-mod3:0:data0
1149 add0-mod3:0:data0
1133 add0-mod4:0:data0
1150 add0-mod4:0:data0
1134 add0-rm1:0:data0
1151 add0-rm1:0:data0
1135 add0-rm2:0:data0
1152 add0-rm2:0:data0
1136 add0-rm4:0:data0
1153 add0-rm4:0:data0
1137
1154
1138 follow file history from wdir parent, unmodified in wdir:
1155 follow file history from wdir parent, unmodified in wdir:
1139
1156
1140 $ hg log -f add0-mod3
1157 $ hg log -f add0-mod3
1141 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1158 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1142 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1159 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1143
1160
1144 $ hg grep --diff -f data add0-mod3
1161 $ hg grep --diff -f data add0-mod3
1145 add0-mod3:3:+:data3
1162 add0-mod3:3:+:data3
1146 add0-mod3:0:+:data0
1163 add0-mod3:0:+:data0
1147
1164
1148 $ hg grep -f data add0-mod3
1165 $ hg grep -f data add0-mod3
1149 add0-mod3:3:data0
1166 add0-mod3:3:data0
1150 add0-mod3:3:data3
1167 add0-mod3:3:data3
1151 add0-mod3:1:data0
1168 add0-mod3:1:data0
1152 add0-mod3:0:data0
1169 add0-mod3:0:data0
1153
1170
1154 follow file history from wdir parent, modified in wdir:
1171 follow file history from wdir parent, modified in wdir:
1155
1172
1156 $ hg log -f add0-mod4
1173 $ hg log -f add0-mod4
1157 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1174 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1158
1175
1159 $ hg grep --diff -f data add0-mod4
1176 $ hg grep --diff -f data add0-mod4
1160 add0-mod4:0:+:data0
1177 add0-mod4:0:+:data0
1161
1178
1162 $ hg grep -f data add0-mod4
1179 $ hg grep -f data add0-mod4
1163 add0-mod4:3:data0
1180 add0-mod4:3:data0
1164 add0-mod4:1:data0
1181 add0-mod4:1:data0
1165 add0-mod4:0:data0
1182 add0-mod4:0:data0
1166
1183
1167 follow file history from wdir parent, copied but unmodified:
1184 follow file history from wdir parent, copied but unmodified:
1168
1185
1169 $ hg log -f add0-cp1-cp3
1186 $ hg log -f add0-cp1-cp3
1170 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1187 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1171 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1188 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1172 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1189 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1173
1190
1174 $ hg grep --diff -f data add0-cp1-cp3
1191 $ hg grep --diff -f data add0-cp1-cp3
1175 add0:0:+:data0
1192 add0:0:+:data0
1176
1193
1177 BROKEN: should follow history across renames
1194 BROKEN: should follow history across renames
1178 $ hg grep -f data add0-cp1-cp3
1195 $ hg grep -f data add0-cp1-cp3
1179 add0-cp1-cp3:3:data0
1196 add0-cp1-cp3:3:data0
1180
1197
1181 follow file history from wdir parent, copied and modified:
1198 follow file history from wdir parent, copied and modified:
1182
1199
1183 $ hg log -f add0-cp1-mod1-cp3-mod3
1200 $ hg log -f add0-cp1-mod1-cp3-mod3
1184 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1201 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1185 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1202 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1186 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1203 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1187
1204
1188 $ hg grep --diff -f data add0-cp1-mod1-cp3-mod3
1205 $ hg grep --diff -f data add0-cp1-mod1-cp3-mod3
1189 add0-cp1-mod1-cp3-mod3:3:+:data3
1206 add0-cp1-mod1-cp3-mod3:3:+:data3
1190 add0-cp1-mod1:1:+:data1
1207 add0-cp1-mod1:1:+:data1
1191 add0:0:+:data0
1208 add0:0:+:data0
1192
1209
1193 BROKEN: should follow history across renames
1210 BROKEN: should follow history across renames
1194 $ hg grep -f data add0-cp1-mod1-cp3-mod3
1211 $ hg grep -f data add0-cp1-mod1-cp3-mod3
1195 add0-cp1-mod1-cp3-mod3:3:data0
1212 add0-cp1-mod1-cp3-mod3:3:data0
1196 add0-cp1-mod1-cp3-mod3:3:data1
1213 add0-cp1-mod1-cp3-mod3:3:data1
1197 add0-cp1-mod1-cp3-mod3:3:data3
1214 add0-cp1-mod1-cp3-mod3:3:data3
1198
1215
1199 follow file history from wdir parent, copied in wdir:
1216 follow file history from wdir parent, copied in wdir:
1200
1217
1201 $ hg log -f add0-cp4
1218 $ hg log -f add0-cp4
1202 abort: cannot follow nonexistent file: "add0-cp4"
1219 abort: cannot follow nonexistent file: "add0-cp4"
1203 [20]
1220 [20]
1204
1221
1205 $ hg grep --diff -f data add0-cp4
1222 $ hg grep --diff -f data add0-cp4
1206 abort: cannot follow nonexistent file: "add0-cp4"
1223 abort: cannot follow nonexistent file: "add0-cp4"
1207 [20]
1224 [20]
1208
1225
1209 BROKEN: maybe better to abort
1226 BROKEN: maybe better to abort
1210 $ hg grep -f data add0-cp4
1227 $ hg grep -f data add0-cp4
1211 [1]
1228 [1]
1212
1229
1213 follow file history from wdir parent, removed:
1230 follow file history from wdir parent, removed:
1214
1231
1215 $ hg log -f add0-cp1-mod1-rm3
1232 $ hg log -f add0-cp1-mod1-rm3
1216 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1233 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1217 [20]
1234 [20]
1218
1235
1219 $ hg grep --diff -f data add0-cp1-mod1-rm3
1236 $ hg grep --diff -f data add0-cp1-mod1-rm3
1220 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1237 abort: cannot follow file not in parent revision: "add0-cp1-mod1-rm3"
1221 [20]
1238 [20]
1222
1239
1223 BROKEN: maybe better to abort
1240 BROKEN: maybe better to abort
1224 $ hg grep -f data add0-cp1-mod1-rm3
1241 $ hg grep -f data add0-cp1-mod1-rm3
1225 add0-cp1-mod1-rm3:1:data0
1242 add0-cp1-mod1-rm3:1:data0
1226 add0-cp1-mod1-rm3:1:data1
1243 add0-cp1-mod1-rm3:1:data1
1227
1244
1228 follow file history from wdir parent (explicit), removed:
1245 follow file history from wdir parent (explicit), removed:
1229
1246
1230 $ hg log -fr. add0-cp1-mod1-rm3
1247 $ hg log -fr. add0-cp1-mod1-rm3
1231 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1248 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1232 [20]
1249 [20]
1233
1250
1234 $ hg grep --diff -fr. data add0-cp1-mod1-rm3
1251 $ hg grep --diff -fr. data add0-cp1-mod1-rm3
1235 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1252 abort: cannot follow file not in any of the specified revisions: "add0-cp1-mod1-rm3"
1236 [20]
1253 [20]
1237
1254
1238 BROKEN: should abort
1255 BROKEN: should abort
1239 $ hg grep -fr. data add0-cp1-mod1-rm3
1256 $ hg grep -fr. data add0-cp1-mod1-rm3
1240 add0-cp1-mod1-rm3:1:data0
1257 add0-cp1-mod1-rm3:1:data0
1241 add0-cp1-mod1-rm3:1:data1
1258 add0-cp1-mod1-rm3:1:data1
1242
1259
1243 follow file history from wdir parent, removed in wdir:
1260 follow file history from wdir parent, removed in wdir:
1244
1261
1245 $ hg log -f add0-rm4
1262 $ hg log -f add0-rm4
1246 abort: cannot follow file not in parent revision: "add0-rm4"
1263 abort: cannot follow file not in parent revision: "add0-rm4"
1247 [20]
1264 [20]
1248
1265
1249 $ hg grep --diff -f data add0-rm4
1266 $ hg grep --diff -f data add0-rm4
1250 abort: cannot follow file not in parent revision: "add0-rm4"
1267 abort: cannot follow file not in parent revision: "add0-rm4"
1251 [20]
1268 [20]
1252
1269
1253 BROKEN: should abort
1270 BROKEN: should abort
1254 $ hg grep -f data add0-rm4
1271 $ hg grep -f data add0-rm4
1255 add0-rm4:3:data0
1272 add0-rm4:3:data0
1256 add0-rm4:1:data0
1273 add0-rm4:1:data0
1257 add0-rm4:0:data0
1274 add0-rm4:0:data0
1258
1275
1259 follow file history from wdir parent (explicit), removed in wdir:
1276 follow file history from wdir parent (explicit), removed in wdir:
1260
1277
1261 $ hg log -fr. add0-rm4
1278 $ hg log -fr. add0-rm4
1262 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1279 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1263
1280
1264 $ hg grep --diff -fr. data add0-rm4
1281 $ hg grep --diff -fr. data add0-rm4
1265 add0-rm4:0:+:data0
1282 add0-rm4:0:+:data0
1266
1283
1267 $ hg grep -fr. data add0-rm4
1284 $ hg grep -fr. data add0-rm4
1268 add0-rm4:3:data0
1285 add0-rm4:3:data0
1269 add0-rm4:1:data0
1286 add0-rm4:1:data0
1270 add0-rm4:0:data0
1287 add0-rm4:0:data0
1271
1288
1272 follow file history from wdir parent, multiple files:
1289 follow file history from wdir parent, multiple files:
1273
1290
1274 $ hg log -f add0-mod3 add0-cp1-mod1
1291 $ hg log -f add0-mod3 add0-cp1-mod1
1275 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1292 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1276 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1293 1: A add0-cp1, A add0-cp1-mod1, A add0-cp1-mod1-rm3, M add0-mod1, R add0-rm1
1277 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1294 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1278
1295
1279 $ hg grep --diff -f data add0-mod3 add0-cp1-mod1
1296 $ hg grep --diff -f data add0-mod3 add0-cp1-mod1
1280 add0-mod3:3:+:data3
1297 add0-mod3:3:+:data3
1281 add0-cp1-mod1:1:+:data1
1298 add0-cp1-mod1:1:+:data1
1282 add0:0:+:data0
1299 add0:0:+:data0
1283 add0-mod3:0:+:data0
1300 add0-mod3:0:+:data0
1284
1301
1285 BROKEN: should follow history across renames
1302 BROKEN: should follow history across renames
1286 $ hg grep -f data add0-mod3 add0-cp1-mod1
1303 $ hg grep -f data add0-mod3 add0-cp1-mod1
1287 add0-cp1-mod1:3:data0
1304 add0-cp1-mod1:3:data0
1288 add0-cp1-mod1:3:data1
1305 add0-cp1-mod1:3:data1
1289 add0-mod3:3:data0
1306 add0-mod3:3:data0
1290 add0-mod3:3:data3
1307 add0-mod3:3:data3
1291 add0-cp1-mod1:1:data0
1308 add0-cp1-mod1:1:data0
1292 add0-cp1-mod1:1:data1
1309 add0-cp1-mod1:1:data1
1293 add0-mod3:1:data0
1310 add0-mod3:1:data0
1294 add0-mod3:0:data0
1311 add0-mod3:0:data0
1295
1312
1296 follow file history from specified revision, modified:
1313 follow file history from specified revision, modified:
1297
1314
1298 $ hg log -fr2 add0-mod2
1315 $ hg log -fr2 add0-mod2
1299 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1316 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1300 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1317 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1301
1318
1302 $ hg grep --diff -fr2 data add0-mod2
1319 $ hg grep --diff -fr2 data add0-mod2
1303 add0-mod2:2:+:data2
1320 add0-mod2:2:+:data2
1304 add0-mod2:0:+:data0
1321 add0-mod2:0:+:data0
1305
1322
1306 $ hg grep -fr2 data add0-mod2
1323 $ hg grep -fr2 data add0-mod2
1307 add0-mod2:2:data0
1324 add0-mod2:2:data0
1308 add0-mod2:2:data2
1325 add0-mod2:2:data2
1309 add0-mod2:0:data0
1326 add0-mod2:0:data0
1310
1327
1311 follow file history from specified revision, copied but unmodified:
1328 follow file history from specified revision, copied but unmodified:
1312
1329
1313 $ hg log -fr2 add0-cp2
1330 $ hg log -fr2 add0-cp2
1314 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1331 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1315 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1332 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1316
1333
1317 $ hg grep --diff -fr2 data add0-cp2
1334 $ hg grep --diff -fr2 data add0-cp2
1318 add0:0:+:data0
1335 add0:0:+:data0
1319
1336
1320 BROKEN: should follow history across renames
1337 BROKEN: should follow history across renames
1321 $ hg grep -fr2 data add0-cp2
1338 $ hg grep -fr2 data add0-cp2
1322 add0-cp2:2:data0
1339 add0-cp2:2:data0
1323
1340
1324 follow file history from specified revision, copied and modified:
1341 follow file history from specified revision, copied and modified:
1325
1342
1326 $ hg log -fr2 add0-cp2-mod2
1343 $ hg log -fr2 add0-cp2-mod2
1327 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1344 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1328 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1345 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1329
1346
1330 $ hg grep --diff -fr2 data add0-cp2-mod2
1347 $ hg grep --diff -fr2 data add0-cp2-mod2
1331 add0-cp2-mod2:2:+:data2
1348 add0-cp2-mod2:2:+:data2
1332 add0:0:+:data0
1349 add0:0:+:data0
1333
1350
1334 BROKEN: should follow history across renames
1351 BROKEN: should follow history across renames
1335 $ hg grep -fr2 data add0-cp2-mod2
1352 $ hg grep -fr2 data add0-cp2-mod2
1336 add0-cp2-mod2:2:data0
1353 add0-cp2-mod2:2:data0
1337 add0-cp2-mod2:2:data2
1354 add0-cp2-mod2:2:data2
1338
1355
1339 follow file history from specified revision, removed:
1356 follow file history from specified revision, removed:
1340
1357
1341 $ hg log -fr2 add0-rm2
1358 $ hg log -fr2 add0-rm2
1342 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1359 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1343 [20]
1360 [20]
1344
1361
1345 $ hg grep --diff -fr2 data add0-rm2
1362 $ hg grep --diff -fr2 data add0-rm2
1346 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1363 abort: cannot follow file not in any of the specified revisions: "add0-rm2"
1347 [20]
1364 [20]
1348
1365
1349 BROKEN: should abort
1366 BROKEN: should abort
1350 $ hg grep -fr2 data add0-rm2
1367 $ hg grep -fr2 data add0-rm2
1351 add0-rm2:0:data0
1368 add0-rm2:0:data0
1352
1369
1353 follow file history from specified revision, multiple files:
1370 follow file history from specified revision, multiple files:
1354
1371
1355 $ hg log -fr2 add0-cp2 add0-mod2
1372 $ hg log -fr2 add0-cp2 add0-mod2
1356 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1373 2: A add0-cp2, A add0-cp2-mod2, M add0-mod2, R add0-rm2
1357 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1374 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1358
1375
1359 $ hg grep --diff -fr2 data add0-cp2 add0-mod2
1376 $ hg grep --diff -fr2 data add0-cp2 add0-mod2
1360 add0-mod2:2:+:data2
1377 add0-mod2:2:+:data2
1361 add0:0:+:data0
1378 add0:0:+:data0
1362 add0-mod2:0:+:data0
1379 add0-mod2:0:+:data0
1363
1380
1364 BROKEN: should follow history across renames
1381 BROKEN: should follow history across renames
1365 $ hg grep -fr2 data add0-cp2 add0-mod2
1382 $ hg grep -fr2 data add0-cp2 add0-mod2
1366 add0-cp2:2:data0
1383 add0-cp2:2:data0
1367 add0-mod2:2:data0
1384 add0-mod2:2:data0
1368 add0-mod2:2:data2
1385 add0-mod2:2:data2
1369 add0-mod2:0:data0
1386 add0-mod2:0:data0
1370
1387
1371 follow file history from wdir, unmodified:
1388 follow file history from wdir, unmodified:
1372
1389
1373 $ hg log -fr'wdir()' add0-mod3
1390 $ hg log -fr'wdir()' add0-mod3
1374 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1391 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1375 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1392 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1376 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1393 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1377
1394
1378 $ hg grep --diff -fr'wdir()' data add0-mod3
1395 $ hg grep --diff -fr'wdir()' data add0-mod3
1379 add0-mod3:3:+:data3
1396 add0-mod3:3:+:data3
1380 add0-mod3:0:+:data0
1397 add0-mod3:0:+:data0
1381
1398
1382 $ hg grep -fr'wdir()' data add0-mod3
1399 $ hg grep -fr'wdir()' data add0-mod3
1383 add0-mod3:2147483647:data0
1400 add0-mod3:2147483647:data0
1384 add0-mod3:2147483647:data3
1401 add0-mod3:2147483647:data3
1385 add0-mod3:3:data0
1402 add0-mod3:3:data0
1386 add0-mod3:3:data3
1403 add0-mod3:3:data3
1387 add0-mod3:1:data0
1404 add0-mod3:1:data0
1388 add0-mod3:0:data0
1405 add0-mod3:0:data0
1389
1406
1390 follow file history from wdir, modified:
1407 follow file history from wdir, modified:
1391
1408
1392 $ hg log -fr'wdir()' add0-mod4
1409 $ hg log -fr'wdir()' add0-mod4
1393 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1410 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1394 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1411 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1395
1412
1396 $ hg grep --diff -fr'wdir()' data add0-mod4
1413 $ hg grep --diff -fr'wdir()' data add0-mod4
1397 add0-mod4:2147483647:+:data4
1414 add0-mod4:2147483647:+:data4
1398 add0-mod4:0:+:data0
1415 add0-mod4:0:+:data0
1399
1416
1400 $ hg grep -fr'wdir()' data add0-mod4
1417 $ hg grep -fr'wdir()' data add0-mod4
1401 add0-mod4:2147483647:data0
1418 add0-mod4:2147483647:data0
1402 add0-mod4:2147483647:data4
1419 add0-mod4:2147483647:data4
1403 add0-mod4:3:data0
1420 add0-mod4:3:data0
1404 add0-mod4:1:data0
1421 add0-mod4:1:data0
1405 add0-mod4:0:data0
1422 add0-mod4:0:data0
1406
1423
1407 follow file history from wdir, copied but unmodified:
1424 follow file history from wdir, copied but unmodified:
1408
1425
1409 $ hg log -fr'wdir()' add0-cp4
1426 $ hg log -fr'wdir()' add0-cp4
1410 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1427 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1411 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1428 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1412
1429
1413 $ hg grep --diff -fr'wdir()' data add0-cp4
1430 $ hg grep --diff -fr'wdir()' data add0-cp4
1414 add0:0:+:data0
1431 add0:0:+:data0
1415
1432
1416 BROKEN: should follow history across renames
1433 BROKEN: should follow history across renames
1417 $ hg grep -fr'wdir()' data add0-cp4
1434 $ hg grep -fr'wdir()' data add0-cp4
1418 add0-cp4:2147483647:data0
1435 add0-cp4:2147483647:data0
1419
1436
1420 follow file history from wdir, copied and modified:
1437 follow file history from wdir, copied and modified:
1421
1438
1422 $ hg log -fr'wdir()' add0-cp4-mod4
1439 $ hg log -fr'wdir()' add0-cp4-mod4
1423 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1440 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1424 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1441 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1425
1442
1426 $ hg grep --diff -fr'wdir()' data add0-cp4-mod4
1443 $ hg grep --diff -fr'wdir()' data add0-cp4-mod4
1427 add0-cp4-mod4:2147483647:+:data4
1444 add0-cp4-mod4:2147483647:+:data4
1428 add0:0:+:data0
1445 add0:0:+:data0
1429
1446
1430 BROKEN: should follow history across renames
1447 BROKEN: should follow history across renames
1431 $ hg grep -fr'wdir()' data add0-cp4-mod4
1448 $ hg grep -fr'wdir()' data add0-cp4-mod4
1432 add0-cp4-mod4:2147483647:data0
1449 add0-cp4-mod4:2147483647:data0
1433 add0-cp4-mod4:2147483647:data4
1450 add0-cp4-mod4:2147483647:data4
1434
1451
1435 follow file history from wdir, multiple files:
1452 follow file history from wdir, multiple files:
1436
1453
1437 $ hg log -fr'wdir()' add0-cp4 add0-mod4 add0-mod3
1454 $ hg log -fr'wdir()' add0-cp4 add0-mod4 add0-mod3
1438 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1455 2147483647: A add0-cp4, A add0-cp4-mod4, M add0-mod4, R add0-rm4
1439 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1456 3: A add0-cp1-cp3, A add0-cp1-mod1-cp3-mod3, R add0-cp1-mod1-rm3, M add0-mod3
1440 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1457 0: A add0, A add0-mod1, A add0-mod2, A add0-mod3, A add0-mod4, A add0-rm1, A add0-rm2, A add0-rm4
1441
1458
1442 $ hg grep --diff -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1459 $ hg grep --diff -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1443 add0-mod4:2147483647:+:data4
1460 add0-mod4:2147483647:+:data4
1444 add0-mod3:3:+:data3
1461 add0-mod3:3:+:data3
1445 add0:0:+:data0
1462 add0:0:+:data0
1446 add0-mod3:0:+:data0
1463 add0-mod3:0:+:data0
1447 add0-mod4:0:+:data0
1464 add0-mod4:0:+:data0
1448
1465
1449 BROKEN: should follow history across renames
1466 BROKEN: should follow history across renames
1450 $ hg grep -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1467 $ hg grep -fr'wdir()' data add0-cp4 add0-mod4 add0-mod3
1451 add0-cp4:2147483647:data0
1468 add0-cp4:2147483647:data0
1452 add0-mod3:2147483647:data0
1469 add0-mod3:2147483647:data0
1453 add0-mod3:2147483647:data3
1470 add0-mod3:2147483647:data3
1454 add0-mod4:2147483647:data0
1471 add0-mod4:2147483647:data0
1455 add0-mod4:2147483647:data4
1472 add0-mod4:2147483647:data4
1456 add0-mod3:3:data0
1473 add0-mod3:3:data0
1457 add0-mod3:3:data3
1474 add0-mod3:3:data3
1458 add0-mod4:3:data0
1475 add0-mod4:3:data0
1459 add0-mod3:1:data0
1476 add0-mod3:1:data0
1460 add0-mod4:1:data0
1477 add0-mod4:1:data0
1461 add0-mod3:0:data0
1478 add0-mod3:0:data0
1462 add0-mod4:0:data0
1479 add0-mod4:0:data0
1463
1480
1464 $ cd ..
1481 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now